From f1947232305aecc00829f0452a0dc42c8cee5534 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Mon, 23 Jun 2014 11:12:32 -0700 Subject: [PATCH] Adding tests for convention-based routing --- Mvc.sln | 15 +- ...Microsoft.AspNet.Mvc.FunctionalTests.kproj | 3 +- .../RoutingTests.cs | 151 ++++++++++++++++++ .../project.json | 1 + .../Areas/Travel/FlightController.cs | 28 ++++ .../Controllers/HomeController.cs | 28 ++++ .../RoutingWebSite/RoutingWebSite.kproj | 40 +++++ test/WebSites/RoutingWebSite/Startup.cs | 33 ++++ .../RoutingWebSite/TestResponseGenerator.cs | 37 +++++ test/WebSites/RoutingWebSite/project.json | 11 ++ 10 files changed, 345 insertions(+), 2 deletions(-) create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/RoutingTests.cs create mode 100644 test/WebSites/RoutingWebSite/Areas/Travel/FlightController.cs create mode 100644 test/WebSites/RoutingWebSite/Controllers/HomeController.cs create mode 100644 test/WebSites/RoutingWebSite/RoutingWebSite.kproj create mode 100644 test/WebSites/RoutingWebSite/Startup.cs create mode 100644 test/WebSites/RoutingWebSite/TestResponseGenerator.cs create mode 100644 test/WebSites/RoutingWebSite/project.json diff --git a/Mvc.sln b/Mvc.sln index e5781ed5c3..502a66526f 100644 --- a/Mvc.sln +++ b/Mvc.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.21806.0 +VisualStudioVersion = 14.0.21727.3 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}" EndProject @@ -45,6 +45,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "AutofacWebSite", "test\WebS EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TestConfiguration", "test\WebSites\Microsoft.AspNet.Mvc.TestConfiguration\Microsoft.AspNet.Mvc.TestConfiguration.kproj", "{680D75ED-601F-4D86-B01B-1072D0C31B8C}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RoutingWebSite", "test\WebSites\RoutingWebSite\RoutingWebSite.kproj", "{42CDBF4A-E238-4C0F-A416-44588363EB4C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -225,6 +227,16 @@ Global {680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|Mixed Platforms.Build.0 = Release|Any CPU {680D75ED-601F-4D86-B01B-1072D0C31B8C}.Release|x86.ActiveCfg = Release|Any CPU + {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Debug|x86.ActiveCfg = Debug|Any CPU + {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Any CPU.Build.0 = Release|Any CPU + {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {42CDBF4A-E238-4C0F-A416-44588363EB4C}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -248,5 +260,6 @@ Global {EA34877F-1AC1-42B7-B4E6-15A093F40CAE} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {07C0E921-FCBB-458C-AC11-3D01CE68B16B} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {680D75ED-601F-4D86-B01B-1072D0C31B8C} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} + {42CDBF4A-E238-4C0F-A416-44588363EB4C} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} EndGlobalSection EndGlobal diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj b/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj index d5a62515f4..c2b262acd3 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj @@ -33,6 +33,7 @@ + @@ -42,4 +43,4 @@ - \ No newline at end of file + diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/RoutingTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/RoutingTests.cs new file mode 100644 index 0000000000..0281dbc520 --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/RoutingTests.cs @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.TestHost; +using Xunit; + +namespace Microsoft.AspNet.Mvc.FunctionalTests +{ + public class RoutingTests + { + private readonly IServiceProvider _services; + private readonly Action _app = new RoutingWebSite.Startup().Configure; + + public RoutingTests() + { + _services = TestHelper.CreateServices("RoutingWebSite"); + } + + [Fact] + public async Task ConventionRoutedController_ActionIsReachable() + { + // Arrange + var server = TestServer.Create(_services, _app); + var client = server.Handler; + + // Act + var response = await client.GetAsync("http://localhost/Home/Index"); + + // Assert + Assert.Equal(200, response.StatusCode); + + var body = await response.ReadBodyAsStringAsync(); + var result = JsonConvert.DeserializeObject(body); + + Assert.Contains("/Home/Index", result.ExpectedUrls); + Assert.Equal("Home", result.Controller); + Assert.Equal("Index", result.Action); + Assert.Equal( + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { "controller", "Home" }, + { "action", "Index" }, + }, + result.RouteValues); + } + + [Fact] + public async Task ConventionRoutedController_ActionIsReachable_WithDefaults() + { + // Arrange + var server = TestServer.Create(_services, _app); + var client = server.Handler; + + // Act + var response = await client.GetAsync("http://localhost/"); + + // Assert + Assert.Equal(200, response.StatusCode); + + var body = await response.ReadBodyAsStringAsync(); + var result = JsonConvert.DeserializeObject(body); + + Assert.Contains("/", result.ExpectedUrls); + Assert.Equal("Home", result.Controller); + Assert.Equal("Index", result.Action); + Assert.Equal( + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { "controller", "Home" }, + { "action", "Index" }, + }, + result.RouteValues); + } + + [Fact] + public async Task ConventionRoutedController_NonActionIsNotReachable() + { + // Arrange + var server = TestServer.Create(_services, _app); + var client = server.Handler; + + // Act + var response = await client.GetAsync("http://localhost/Home/NotAnAction"); + + // Assert + Assert.Equal(404, response.StatusCode); + } + + [Fact] + public async Task ConventionRoutedController_InArea_ActionIsReachable() + { + // Arrange + var server = TestServer.Create(_services, _app); + var client = server.Handler; + + // Act + var response = await client.GetAsync("http://localhost/Travel/Flight/Index"); + + // Assert + Assert.Equal(200, response.StatusCode); + + var body = await response.ReadBodyAsStringAsync(); + var result = JsonConvert.DeserializeObject(body); + + Assert.Contains("/Travel/Flight/Index", result.ExpectedUrls); + Assert.Equal("Flight", result.Controller); + Assert.Equal("Index", result.Action); + Assert.Equal( + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { "area", "Travel" }, + { "controller", "Flight" }, + { "action", "Index" }, + }, + result.RouteValues); + } + + [Fact] + public async Task ConventionRoutedController_InArea_ActionBlockedByHttpMethod() + { + // Arrange + var server = TestServer.Create(_services, _app); + var client = server.Handler; + + // Act + var response = await client.GetAsync("http://localhost/Travel/Flight/BuyTickets"); + + // Assert + Assert.Equal(404, response.StatusCode); + } + + // See TestResponseGenerator in RoutingWebSite for the code that generates this data. + private class RoutingResult + { + public string[] ExpectedUrls { get; set; } + + public string ActualUrl { get; set; } + + public Dictionary RouteValues { get; set; } + + public string Action { get; set; } + + public string Controller { get; set; } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json b/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json index 98d04a030f..4f78736822 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json @@ -12,6 +12,7 @@ "Microsoft.Framework.ConfigurationModel.Json": "1.0.0-*", "Microsoft.Framework.DependencyInjection": "1.0.0-*", "Microsoft.Framework.Runtime.Interfaces": "1.0.0-*", + "RoutingWebSite": "", "Xunit.KRunner": "1.0.0-*" }, "commands": { diff --git a/test/WebSites/RoutingWebSite/Areas/Travel/FlightController.cs b/test/WebSites/RoutingWebSite/Areas/Travel/FlightController.cs new file mode 100644 index 0000000000..ae5730e9a0 --- /dev/null +++ b/test/WebSites/RoutingWebSite/Areas/Travel/FlightController.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNet.Mvc; +using System; + +namespace RoutingWebSite +{ + // This controller is reachable via traditional routing. + [Area("Travel")] + public class FlightController + { + private readonly TestResponseGenerator _generator; + + public FlightController(TestResponseGenerator generator) + { + _generator = generator; + } + + public IActionResult Index() + { + return _generator.Generate("/Travel/Flight", "/Travel/Flight/Index"); + } + + [HttpPost] + public IActionResult BuyTickets() + { + return _generator.Generate("/Travel/Flight/BuyTickets"); + } + } +} \ No newline at end of file diff --git a/test/WebSites/RoutingWebSite/Controllers/HomeController.cs b/test/WebSites/RoutingWebSite/Controllers/HomeController.cs new file mode 100644 index 0000000000..ba4a876f7c --- /dev/null +++ b/test/WebSites/RoutingWebSite/Controllers/HomeController.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNet.Mvc; + +namespace RoutingWebSite +{ + // This controller is reachable via traditional routing. + public class HomeController : Controller + { + private readonly TestResponseGenerator _generator; + + public HomeController(TestResponseGenerator generator) + { + _generator = generator; + } + + public IActionResult Index() + { + return _generator.Generate("/", "/Home", "/Home/Index"); + } + + public IActionResult About() + { + return _generator.Generate(); + } + } +} \ No newline at end of file diff --git a/test/WebSites/RoutingWebSite/RoutingWebSite.kproj b/test/WebSites/RoutingWebSite/RoutingWebSite.kproj new file mode 100644 index 0000000000..6aceb03b05 --- /dev/null +++ b/test/WebSites/RoutingWebSite/RoutingWebSite.kproj @@ -0,0 +1,40 @@ + + + + 12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + Debug + AnyCPU + + + + 42cdbf4a-e238-4c0f-a416-44588363eb4c + Web + + + ConsoleDebugger + + + WebDebugger + + + + + 2.0 + + + 11178 + + + + + + + + + + + + \ No newline at end of file diff --git a/test/WebSites/RoutingWebSite/Startup.cs b/test/WebSites/RoutingWebSite/Startup.cs new file mode 100644 index 0000000000..eb11249f9c --- /dev/null +++ b/test/WebSites/RoutingWebSite/Startup.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Mvc; +using Microsoft.AspNet.Routing; +using Microsoft.Framework.ConfigurationModel; +using Microsoft.Framework.DependencyInjection; + +namespace RoutingWebSite +{ + public class Startup + { + public void Configure(IBuilder app) + { + var configuration = app.GetTestConfiguration(); + + app.UseServices(services => + { + services.AddMvc(configuration); + + services.AddScoped(); + }); + + app.UseMvc(routes => + { + routes.MapRoute("areaRoute", + "{area:exists}/{controller}/{action}", + new { controller = "Home", action = "Index" }); + + routes.MapRoute("ActionAsMethod", "{controller}/{action}", + defaults: new { controller = "Home", action = "Index" }); + }); + } + } +} diff --git a/test/WebSites/RoutingWebSite/TestResponseGenerator.cs b/test/WebSites/RoutingWebSite/TestResponseGenerator.cs new file mode 100644 index 0000000000..53b9a8abcf --- /dev/null +++ b/test/WebSites/RoutingWebSite/TestResponseGenerator.cs @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNet.Mvc; +using Microsoft.Framework.DependencyInjection; + +namespace RoutingWebSite +{ + // Generates a response based on the expected URL and action context + public class TestResponseGenerator + { + private readonly ActionContext _actionContext; + + public TestResponseGenerator(IContextAccessor contextAccessor) + { + _actionContext = contextAccessor.Value; + if (_actionContext == null) + { + throw new InvalidOperationException("ActionContext should not be null here."); + } + } + + public JsonResult Generate(params string[] expectedUrls) + { + return new JsonResult(new + { + expectedUrls = expectedUrls, + actualUrl = _actionContext.HttpContext.Request.Path.Value, + routeValues = _actionContext.RouteData.Values, + + action = _actionContext.ActionDescriptor.Name, + controller = ((ReflectedActionDescriptor)_actionContext.ActionDescriptor).ControllerDescriptor.Name, + }); + } + } +} \ No newline at end of file diff --git a/test/WebSites/RoutingWebSite/project.json b/test/WebSites/RoutingWebSite/project.json new file mode 100644 index 0000000000..465e43af98 --- /dev/null +++ b/test/WebSites/RoutingWebSite/project.json @@ -0,0 +1,11 @@ +{ + "dependencies": { + "Helios": "1.0.0-*", + "Microsoft.AspNet.Mvc": "", + "Microsoft.AspNet.Mvc.TestConfiguration": "" + }, + "configurations": { + "net45": { }, + "k10": { } + } +}