namespace Ocelot.AcceptanceTests { using Microsoft.AspNetCore.Http; using Ocelot.Configuration.File; using Shouldly; using System; using System.Collections.Generic; using System.Net; using TestStack.BDDfy; using Xunit; public class RoutingTests : IDisposable { private readonly Steps _steps; private string _downstreamPath; private readonly ServiceHandler _serviceHandler; public RoutingTests() { _serviceHandler = new ServiceHandler(); _steps = new Steps(); } [Fact] public void should_not_match_forward_slash_in_pattern_before_next_forward_slash() { var port = 31879; var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/v{apiVersion}/cards", DownstreamScheme = "http", UpstreamPathTemplate = "/api/v{apiVersion}/cards", UpstreamHttpMethod = new List { "Get" }, DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = port, } }, Priority = 1 } } }; this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/api/v1/aaaaaaaaa/cards", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/api/v1/aaaaaaaaa/cards")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) .BDDfy(); } [Fact] public void should_return_response_404_when_no_configuration_at_all() { this.Given(x => _steps.GivenThereIsAConfiguration(new FileConfiguration())) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) .BDDfy(); } [Fact] public void should_return_response_200_with_forward_slash_and_placeholder_only() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/{url}", DownstreamScheme = "http", UpstreamPathTemplate = "/{url}", UpstreamHttpMethod = new List { "Get" }, DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 57873, } } } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:57873/", "/", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_response_200_favouring_forward_slash_with_path_route() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/{url}", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 51880, } }, UpstreamPathTemplate = "/{url}", UpstreamHttpMethod = new List { "Get" }, }, new FileReRoute { DownstreamPathTemplate = "/", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 50810, } }, UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51880/", "/test", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/test")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_response_200_favouring_forward_slash() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/{url}", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 51880, } }, UpstreamPathTemplate = "/{url}", UpstreamHttpMethod = new List { "Get" }, }, new FileReRoute { DownstreamPathTemplate = "/", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 50810, } }, UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:50810/", "/", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_response_200_favouring_forward_slash_route_because_it_is_first() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 51880, } }, UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, }, new FileReRoute { DownstreamPathTemplate = "/{url}", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 51879, } }, UpstreamPathTemplate = "/{url}", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51880/", "/", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_response_200_with_nothing_and_placeholder_only() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/{url}", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 51005, } }, UpstreamPathTemplate = "/{url}", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51005", "/", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_response_200_with_simple_url() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 58589, } }, UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:58589", "/", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void bug() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/v1/vacancy", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 51874, } }, UpstreamPathTemplate = "/vacancy/", UpstreamHttpMethod = new List { "Options", "Put", "Get", "Post", "Delete" }, LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" } }, new FileReRoute { DownstreamPathTemplate = "/api/v1/vacancy/{vacancyId}", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 51874, } }, UpstreamPathTemplate = "/vacancy/{vacancyId}", UpstreamHttpMethod = new List { "Options", "Put", "Get", "Post", "Delete" }, LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" } } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51874", "/api/v1/vacancy/1", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/vacancy/1")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_response_200_when_path_missing_forward_slash_as_first_char() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/products", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 51206, } }, UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51206", "/api/products", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_response_200_when_host_has_trailing_slash() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/products", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 51990, } }, UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51990", "/api/products", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_ok_when_upstream_url_ends_with_forward_slash_but_template_does_not() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/products", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 58804, } }, UpstreamPathTemplate = "/products/", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:58804", "/products", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/products")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_not_found_when_upstream_url_ends_with_forward_slash_but_template_does_not() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/products", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 54015, } }, UpstreamPathTemplate = "/products", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:54015", "/products", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) .BDDfy(); } [Fact] public void should_return_not_found() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/products", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 54072, } }, UpstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = new List { "Get" } } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:54072", "/products", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) .BDDfy(); } [Fact] public void should_return_response_200_with_complex_url() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/products/{productId}", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 55961, } }, UpstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:55961", "/api/products/1", 200, "Some Product")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/1")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Some Product")) .BDDfy(); } [Fact] public void should_return_response_200_with_complex_url_that_starts_with_placeholder() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/{variantId}/products/{productId}", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 51116, } }, UpstreamPathTemplate = "/{variantId}/products/{productId}", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51116", "/api/23/products/1", 200, "Some Product")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("23/products/1")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Some Product")) .BDDfy(); } [Fact] public void should_not_add_trailing_slash_to_downstream_url() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/products/{productId}", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 51809, } }, UpstreamPathTemplate = "/products/{productId}", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => GivenThereIsAServiceRunningOn("http://localhost:51809", "/api/products/1", 200, "Some Product")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/1")) .Then(x => ThenTheDownstreamUrlPathShouldBe("/api/products/1")) .BDDfy(); } [Fact] public void should_return_response_201_with_simple_url() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 56615, } }, DownstreamScheme = "http", UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Post" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:56615", "/", 201, string.Empty)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenThePostHasContent("postContent")) .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) .BDDfy(); } [Fact] public void should_return_response_201_with_complex_query_string() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/newThing", UpstreamPathTemplate = "/newThing", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 57771, } }, UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:57771", "/newThing", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/newThing?DeviceType=IphoneApp&Browser=moonpigIphone&BrowserString=-&CountryCode=123&DeviceName=iPhone 5 (GSM+CDMA)&OperatingSystem=iPhone OS 7.1.2&BrowserVersion=3708AdHoc&ipAddress=-")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_response_200_with_placeholder_for_final_url_path() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/{urlPath}", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 55609, } }, UpstreamPathTemplate = "/myApp1Name/api/{urlPath}", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:55609", "/api/products/1", 200, "Some Product")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/myApp1Name/api/products/1")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Some Product")) .BDDfy(); } [Fact] public void should_return_response_201_with_simple_url_and_multiple_upstream_http_method() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 59911, } }, DownstreamScheme = "http", UpstreamPathTemplate = "/", UpstreamHttpMethod = new List { "Get", "Post" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:59911", "", 201, string.Empty)) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .And(x => _steps.GivenThePostHasContent("postContent")) .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) .BDDfy(); } [Fact] public void should_return_response_200_with_simple_url_and_any_upstream_http_method() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 50187, } }, DownstreamScheme = "http", UpstreamPathTemplate = "/", UpstreamHttpMethod = new List(), } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:50187", "/", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_404_when_calling_upstream_route_with_no_matching_downstream_re_route_github_issue_134() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/v1/vacancy", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 54079, } }, UpstreamPathTemplate = "/vacancy/", UpstreamHttpMethod = new List { "Options", "Put", "Get", "Post", "Delete" }, LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" } }, new FileReRoute { DownstreamPathTemplate = "/api/v1/vacancy/{vacancyId}", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 54079, } }, UpstreamPathTemplate = "/vacancy/{vacancyId}", UpstreamHttpMethod = new List { "Options", "Put", "Get", "Post", "Delete" }, LoadBalancerOptions = new FileLoadBalancerOptions { Type = "LeastConnection" } } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:54079", "/api/v1/vacancy/1", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("api/vacancy/1")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) .BDDfy(); } [Fact] public void should_not_set_trailing_slash_on_url_template() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/{url}", DownstreamScheme = "http", DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 51899, } }, UpstreamPathTemplate = "/platform/{url}", UpstreamHttpMethod = new List { "Get" }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", "/api/swagger/lib/backbone-min.js", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/platform/swagger/lib/backbone-min.js")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .And(x => ThenTheDownstreamUrlPathShouldBe("/api/swagger/lib/backbone-min.js")) .BDDfy(); } [Fact] public void should_use_priority() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/goods/{url}", DownstreamScheme = "http", UpstreamPathTemplate = "/goods/{url}", UpstreamHttpMethod = new List { "Get" }, DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 53879, } }, Priority = 0 }, new FileReRoute { DownstreamPathTemplate = "/goods/delete", DownstreamScheme = "http", UpstreamPathTemplate = "/goods/delete", UpstreamHttpMethod = new List { "Get" }, DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 52879, } }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:52879/", "/goods/delete", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/goods/delete")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_match_multiple_paths_with_catch_all() { var port = 61999; var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/{everything}", DownstreamScheme = "http", UpstreamPathTemplate = "/{everything}", UpstreamHttpMethod = new List { "Get" }, DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = port, } }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn($"http://localhost:{port}/", "/test/toot", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/test/toot")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_fix_issue_271() { var configuration = new FileConfiguration { ReRoutes = new List { new FileReRoute { DownstreamPathTemplate = "/api/v1/{everything}", DownstreamScheme = "http", UpstreamPathTemplate = "/api/v1/{everything}", UpstreamHttpMethod = new List { "Get", "Put", "Post" }, DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 54879, } }, }, new FileReRoute { DownstreamPathTemplate = "/connect/token", DownstreamScheme = "http", UpstreamPathTemplate = "/connect/token", UpstreamHttpMethod = new List { "Post" }, DownstreamHostAndPorts = new List { new FileHostAndPort { Host = "localhost", Port = 5001, } }, } } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:54879/", "/api/v1/modules/Test", 200, "Hello from Laura")) .And(x => _steps.GivenThereIsAConfiguration(configuration)) .And(x => _steps.GivenOcelotIsRunning()) .When(x => _steps.WhenIGetUrlOnTheApiGateway("/api/v1/modules/Test")) .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody) { _serviceHandler.GivenThereIsAServiceRunningOn(baseUrl, basePath, async context => { _downstreamPath = !string.IsNullOrEmpty(context.Request.PathBase.Value) ? context.Request.PathBase.Value : context.Request.Path.Value; if (_downstreamPath != basePath) { context.Response.StatusCode = statusCode; await context.Response.WriteAsync("downstream path didnt match base path"); } else { context.Response.StatusCode = statusCode; await context.Response.WriteAsync(responseBody); } }); } internal void ThenTheDownstreamUrlPathShouldBe(string expectedDownstreamPath) { _downstreamPath.ShouldBe(expectedDownstreamPath); } public void Dispose() { _serviceHandler.Dispose(); _steps.Dispose(); } } }