diff --git a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs index 18f138d3..06214f54 100644 --- a/test/Ocelot.AcceptanceTests/AuthenticationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthenticationTests.cs @@ -2,265 +2,214 @@ using System; using System.Collections.Generic; using System.IO; using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text.Encodings.Web; +using System.Security.Claims; using IdentityServer4.Models; using IdentityServer4.Services.InMemory; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; using Ocelot.Configuration.Yaml; -using Ocelot.ManualTest; -using Shouldly; using TestStack.BDDfy; using Xunit; -using YamlDotNet.Serialization; namespace Ocelot.AcceptanceTests { - using System.Security.Claims; - public class AuthenticationTests : IDisposable { - private TestServer _ocelotServer; - private HttpClient _ocelotClient; - private HttpResponseMessage _response; - private readonly string _configurationPath; - private StringContent _postContent; private IWebHost _servicebuilder; - - // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly - private double _netCoreAppVersion = 1.4; + private readonly Steps _steps; private BearerToken _token; private IWebHost _identityServerBuilder; + private string _identityServerRootUrl = "http://localhost:51888"; + private string _downstreamServiceRootUrl = "http://localhost:51876/"; public AuthenticationTests() { - _configurationPath = $"./bin/Debug/netcoreapp{_netCoreAppVersion}/configuration.yaml"; + _steps = new Steps(); } [Fact] public void should_return_401_using_identity_server_access_token() { - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 201, string.Empty)) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration - { - ReRoutes = new List + var yamlConfiguration = new YamlConfiguration + { + ReRoutes = new List { new YamlReRoute { - DownstreamTemplate = "http://localhost:51876/", + DownstreamTemplate = _downstreamServiceRootUrl, UpstreamTemplate = "/", UpstreamHttpMethod = "Post", AuthenticationOptions = new YamlAuthenticationOptions { AdditionalScopes = new List(), Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:51888", + ProviderRootUrl = _identityServerRootUrl, RequireHttps = false, ScopeName = "api", ScopeSecret = "secret" } } } - })) - .And(x => x.GivenTheApiGatewayIsRunning()) - .And(x => x.GivenThePostHasContent("postContent")) - .When(x => x.WhenIPostUrlOnTheApiGateway("/")) - .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) + }; + + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceRootUrl, 201, string.Empty)) + .And(x => _steps.GivenThereIsAConfiguration(yamlConfiguration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenThePostHasContent("postContent")) + .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) .BDDfy(); } [Fact] public void should_return_401_using_identity_server_reference_token() { - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Reference)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 201, string.Empty)) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration - { - ReRoutes = new List + var yamlConfiguration = new YamlConfiguration + { + ReRoutes = new List { new YamlReRoute { - DownstreamTemplate = "http://localhost:51876/", + DownstreamTemplate = _downstreamServiceRootUrl, UpstreamTemplate = "/", UpstreamHttpMethod = "Post", AuthenticationOptions = new YamlAuthenticationOptions { AdditionalScopes = new List(), Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:51888", + ProviderRootUrl = _identityServerRootUrl, RequireHttps = false, ScopeName = "api", ScopeSecret = "secret" } } } - })) - .And(x => x.GivenTheApiGatewayIsRunning()) - .And(x => x.GivenThePostHasContent("postContent")) - .When(x => x.WhenIPostUrlOnTheApiGateway("/")) - .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) + }; + + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Reference)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceRootUrl, 201, string.Empty)) + .And(x => _steps.GivenThereIsAConfiguration(yamlConfiguration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenThePostHasContent("postContent")) + .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) .BDDfy(); } [Fact] public void should_return_response_200_using_identity_server() { - - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) - .And(x => x.GivenIHaveAToken("http://localhost:51888")) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration - { - ReRoutes = new List + var yamlConfiguration = new YamlConfiguration + { + ReRoutes = new List { new YamlReRoute { - DownstreamTemplate = "http://localhost:51876/", + DownstreamTemplate = _downstreamServiceRootUrl, UpstreamTemplate = "/", UpstreamHttpMethod = "Get", AuthenticationOptions = new YamlAuthenticationOptions { AdditionalScopes = new List(), Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:51888", + ProviderRootUrl = _identityServerRootUrl, RequireHttps = false, ScopeName = "api", ScopeSecret = "secret" } } } - })) - .And(x => x.GivenTheApiGatewayIsRunning()) - .And(x => x.GivenIHaveAddedATokenToMyRequest()) - .When(x => x.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => x.ThenTheResponseBodyShouldBe("Hello from Laura")) + }; + + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceRootUrl, 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) + .And(x => _steps.GivenThereIsAConfiguration(yamlConfiguration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_201_using_identity_server_access_token() { - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 201, string.Empty)) - .And(x => x.GivenIHaveAToken("http://localhost:51888")) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration - { - ReRoutes = new List + var yamlConfiguration = new YamlConfiguration + { + ReRoutes = new List { new YamlReRoute { - DownstreamTemplate = "http://localhost:51876/", + DownstreamTemplate = _downstreamServiceRootUrl, UpstreamTemplate = "/", UpstreamHttpMethod = "Post", AuthenticationOptions = new YamlAuthenticationOptions { AdditionalScopes = new List(), Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:51888", + ProviderRootUrl = _identityServerRootUrl, RequireHttps = false, ScopeName = "api", ScopeSecret = "secret" } } } - })) - .And(x => x.GivenTheApiGatewayIsRunning()) - .And(x => x.GivenIHaveAddedATokenToMyRequest()) - .And(x => x.GivenThePostHasContent("postContent")) - .When(x => x.WhenIPostUrlOnTheApiGateway("/")) - .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) + }; + + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceRootUrl, 201, string.Empty)) + .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) + .And(x => _steps.GivenThereIsAConfiguration(yamlConfiguration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .And(x => _steps.GivenThePostHasContent("postContent")) + .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) .BDDfy(); } [Fact] public void should_return_201_using_identity_server_reference_token() { - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Reference)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 201, string.Empty)) - .And(x => x.GivenIHaveAToken("http://localhost:51888")) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration - { - ReRoutes = new List + var yamlConfiguration = new YamlConfiguration + { + ReRoutes = new List { new YamlReRoute { - DownstreamTemplate = "http://localhost:51876/", + DownstreamTemplate = _downstreamServiceRootUrl, UpstreamTemplate = "/", UpstreamHttpMethod = "Post", AuthenticationOptions = new YamlAuthenticationOptions { AdditionalScopes = new List(), Provider = "IdentityServer", - ProviderRootUrl = "http://localhost:51888", + ProviderRootUrl = _identityServerRootUrl, RequireHttps = false, ScopeName = "api", ScopeSecret = "secret" } } } - })) - .And(x => x.GivenTheApiGatewayIsRunning()) - .And(x => x.GivenIHaveAddedATokenToMyRequest()) - .And(x => x.GivenThePostHasContent("postContent")) - .When(x => x.WhenIPostUrlOnTheApiGateway("/")) - .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) + }; + + this.Given(x => x.GivenThereIsAnIdentityServerOn(_identityServerRootUrl, "api", AccessTokenType.Reference)) + .And(x => x.GivenThereIsAServiceRunningOn(_downstreamServiceRootUrl, 201, string.Empty)) + .And(x => _steps.GivenIHaveAToken(_identityServerRootUrl)) + .And(x => _steps.GivenThereIsAConfiguration(yamlConfiguration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .And(x => _steps.GivenThePostHasContent("postContent")) + .When(x => _steps.WhenIPostUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Created)) .BDDfy(); } - private void WhenIGetUrlOnTheApiGateway(string url) - { - _response = _ocelotClient.GetAsync(url).Result; - } - - private void WhenIPostUrlOnTheApiGateway(string url) - { - _response = _ocelotClient.PostAsync(url, _postContent).Result; - } - - private void ThenTheResponseBodyShouldBe(string expectedBody) - { - _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody); - } - - private void GivenThePostHasContent(string postcontent) - { - _postContent = new StringContent(postcontent); - } - - /// - /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. - /// - private void GivenTheApiGatewayIsRunning() - { - _ocelotServer = new TestServer(new WebHostBuilder() - .UseStartup()); - - _ocelotClient = _ocelotServer.CreateClient(); - } - - private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) - { - var serializer = new Serializer(); - - if (File.Exists(_configurationPath)) - { - File.Delete(_configurationPath); - } - - using (TextWriter writer = File.CreateText(_configurationPath)) - { - serializer.Serialize(writer, yamlConfiguration); - } - } - private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { _servicebuilder = new WebHostBuilder() @@ -351,71 +300,14 @@ namespace Ocelot.AcceptanceTests _identityServerBuilder.Start(); - VerifyIdentiryServerStarted(url); - - } - - private void VerifyIdentiryServerStarted(string url) - { - using (var httpClient = new HttpClient()) - { - var response = httpClient.GetAsync($"{url}/.well-known/openid-configuration").Result; - response.EnsureSuccessStatusCode(); - } - } - - private void GivenIHaveAToken(string url) - { - var tokenUrl = $"{url}/connect/token"; - var formData = new List> - { - new KeyValuePair("client_id", "client"), - new KeyValuePair("client_secret", "secret"), - new KeyValuePair("scope", "api"), - new KeyValuePair("username", "test"), - new KeyValuePair("password", "test"), - new KeyValuePair("grant_type", "password") - }; - var content = new FormUrlEncodedContent(formData); - - using (var httpClient = new HttpClient()) - { - var response = httpClient.PostAsync(tokenUrl, content).Result; - response.EnsureSuccessStatusCode(); - var responseContent = response.Content.ReadAsStringAsync().Result; - _token = JsonConvert.DeserializeObject(responseContent); - } - } - - private void GivenIHaveAddedATokenToMyRequest() - { - _ocelotClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken); - } - - private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) - { - _response.StatusCode.ShouldBe(expectedHttpStatusCode); + _steps.VerifyIdentiryServerStarted(url); } public void Dispose() { _servicebuilder?.Dispose(); - _ocelotClient?.Dispose(); - _ocelotServer?.Dispose(); + _steps.Dispose(); _identityServerBuilder?.Dispose(); } - - // ReSharper disable once ClassNeverInstantiated.Local - class BearerToken - { - [JsonProperty("access_token")] - public string AccessToken { get; set; } - - [JsonProperty("expires_in")] - public int ExpiresIn { get; set; } - - [JsonProperty("token_type")] - public string TokenType { get; set; } - } } } diff --git a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs index 2bb3a908..bd2a9cab 100644 --- a/test/Ocelot.AcceptanceTests/AuthorisationTests.cs +++ b/test/Ocelot.AcceptanceTests/AuthorisationTests.cs @@ -2,56 +2,36 @@ using System; using System.Collections.Generic; using System.IO; using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Text.Encodings.Web; +using System.Security.Claims; using IdentityServer4.Models; using IdentityServer4.Services.InMemory; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; using Ocelot.Configuration.Yaml; -using Ocelot.ManualTest; -using Shouldly; using TestStack.BDDfy; using Xunit; -using YamlDotNet.Serialization; namespace Ocelot.AcceptanceTests { - using System.Security.Claims; - public class AuthorisationTests : IDisposable { - private TestServer _ocelotServer; - private HttpClient _ocelotClient; - private HttpResponseMessage _response; - private readonly string _configurationPath; - private StringContent _postContent; private IWebHost _servicebuilder; - - // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly - private double _netCoreAppVersion = 1.4; - private BearerToken _token; private IWebHost _identityServerBuilder; + private readonly Steps _steps; public AuthorisationTests() { - _configurationPath = $"./bin/Debug/netcoreapp{_netCoreAppVersion}/configuration.yaml"; + _steps = new Steps(); } [Fact] public void should_return_response_200_authorising_route() { - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) - .And(x => x.GivenIHaveAToken("http://localhost:51888")) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration - { - ReRoutes = new List + var yamlConfiguration = new YamlConfiguration + { + ReRoutes = new List { new YamlReRoute { @@ -74,7 +54,7 @@ namespace Ocelot.AcceptanceTests {"UserType", "Claims[sub] > value[0] > |"}, {"UserId", "Claims[sub] > value[1] > |"} }, - AddClaimsToRequest = + AddClaimsToRequest = { {"CustomerId", "Claims[CustomerId] > value"}, {"UserType", "Claims[sub] > value[0] > |"}, @@ -86,24 +66,26 @@ namespace Ocelot.AcceptanceTests } } } - })) - .And(x => x.GivenTheApiGatewayIsRunning()) - .And(x => x.GivenIHaveAddedATokenToMyRequest()) - .When(x => x.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => x.ThenTheResponseBodyShouldBe("Hello from Laura")) + }; + + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveAToken("http://localhost:51888")) + .And(x => _steps.GivenThereIsAConfiguration(yamlConfiguration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura")) .BDDfy(); } [Fact] public void should_return_response_403_authorising_route() { - this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) - .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) - .And(x => x.GivenIHaveAToken("http://localhost:51888")) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration - { - ReRoutes = new List + var yamlConfiguration = new YamlConfiguration + { + ReRoutes = new List { new YamlReRoute { @@ -137,50 +119,19 @@ namespace Ocelot.AcceptanceTests } } } - })) - .And(x => x.GivenTheApiGatewayIsRunning()) - .And(x => x.GivenIHaveAddedATokenToMyRequest()) - .When(x => x.WhenIGetUrlOnTheApiGateway("/")) - .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) + }; + + this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:51888", "api", AccessTokenType.Jwt)) + .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51876", 200, "Hello from Laura")) + .And(x => _steps.GivenIHaveAToken("http://localhost:51888")) + .And(x => _steps.GivenThereIsAConfiguration(yamlConfiguration)) + .And(x => _steps.GivenOcelotIsRunning()) + .And(x => _steps.GivenIHaveAddedATokenToMyRequest()) + .When(x => _steps.WhenIGetUrlOnTheApiGateway("/")) + .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.Forbidden)) .BDDfy(); } - private void WhenIGetUrlOnTheApiGateway(string url) - { - _response = _ocelotClient.GetAsync(url).Result; - } - - private void ThenTheResponseBodyShouldBe(string expectedBody) - { - _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody); - } - - /// - /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. - /// - private void GivenTheApiGatewayIsRunning() - { - _ocelotServer = new TestServer(new WebHostBuilder() - .UseStartup()); - - _ocelotClient = _ocelotServer.CreateClient(); - } - - private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) - { - var serializer = new Serializer(); - - if (File.Exists(_configurationPath)) - { - File.Delete(_configurationPath); - } - - using (TextWriter writer = File.CreateText(_configurationPath)) - { - serializer.Serialize(writer, yamlConfiguration); - } - } - private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { _servicebuilder = new WebHostBuilder() @@ -272,71 +223,15 @@ namespace Ocelot.AcceptanceTests _identityServerBuilder.Start(); - VerifyIdentiryServerStarted(url); + _steps.VerifyIdentiryServerStarted(url); } - private void VerifyIdentiryServerStarted(string url) - { - using (var httpClient = new HttpClient()) - { - var response = httpClient.GetAsync($"{url}/.well-known/openid-configuration").Result; - response.EnsureSuccessStatusCode(); - } - } - - private void GivenIHaveAToken(string url) - { - var tokenUrl = $"{url}/connect/token"; - var formData = new List> - { - new KeyValuePair("client_id", "client"), - new KeyValuePair("client_secret", "secret"), - new KeyValuePair("scope", "api"), - new KeyValuePair("username", "test"), - new KeyValuePair("password", "test"), - new KeyValuePair("grant_type", "password") - }; - var content = new FormUrlEncodedContent(formData); - - using (var httpClient = new HttpClient()) - { - var response = httpClient.PostAsync(tokenUrl, content).Result; - response.EnsureSuccessStatusCode(); - var responseContent = response.Content.ReadAsStringAsync().Result; - _token = JsonConvert.DeserializeObject(responseContent); - } - } - - private void GivenIHaveAddedATokenToMyRequest() - { - _ocelotClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken); - } - - private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) - { - _response.StatusCode.ShouldBe(expectedHttpStatusCode); - } - public void Dispose() { _servicebuilder?.Dispose(); - _ocelotClient?.Dispose(); - _ocelotServer?.Dispose(); + _steps.Dispose(); _identityServerBuilder?.Dispose(); } - - // ReSharper disable once ClassNeverInstantiated.Local - class BearerToken - { - [JsonProperty("access_token")] - public string AccessToken { get; set; } - - [JsonProperty("expires_in")] - public int ExpiresIn { get; set; } - - [JsonProperty("token_type")] - public string TokenType { get; set; } - } } } diff --git a/test/Ocelot.AcceptanceTests/BearerToken.cs b/test/Ocelot.AcceptanceTests/BearerToken.cs new file mode 100644 index 00000000..26fd8d3f --- /dev/null +++ b/test/Ocelot.AcceptanceTests/BearerToken.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Ocelot.AcceptanceTests +{ + class BearerToken + { + [JsonProperty("access_token")] + public string AccessToken { get; set; } + + [JsonProperty("expires_in")] + public int ExpiresIn { get; set; } + + [JsonProperty("token_type")] + public string TokenType { get; set; } + } +} \ No newline at end of file diff --git a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs index aea7ec07..3a9fb040 100644 --- a/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs +++ b/test/Ocelot.AcceptanceTests/ClaimsToHeadersForwardingTests.cs @@ -19,7 +19,6 @@ using Ocelot.ManualTest; using Shouldly; using TestStack.BDDfy; using Xunit; -using YamlDotNet.Serialization; [assembly: CollectionBehavior(DisableTestParallelization = true)] namespace Ocelot.AcceptanceTests @@ -29,17 +28,14 @@ namespace Ocelot.AcceptanceTests private TestServer _ocelotServer; private HttpClient _ocelotClient; private HttpResponseMessage _response; - private readonly string _configurationPath; private IWebHost _servicebuilder; - - // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly - private double _netCoreAppVersion = 1.4; private BearerToken _token; private IWebHost _identityServerBuilder; + private readonly Steps _steps; public ClaimsToHeadersForwardingTests() { - _configurationPath = $"./bin/Debug/netcoreapp{_netCoreAppVersion}/configuration.yaml"; + _steps = new Steps(); } [Fact] @@ -61,7 +57,7 @@ namespace Ocelot.AcceptanceTests this.Given(x => x.GivenThereIsAnIdentityServerOn("http://localhost:52888", "api", AccessTokenType.Jwt, user)) .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:52876", 200)) .And(x => x.GivenIHaveAToken("http://localhost:52888")) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + .And(x => _steps.GivenThereIsAConfiguration(new YamlConfiguration { ReRoutes = new List { @@ -121,21 +117,6 @@ namespace Ocelot.AcceptanceTests _ocelotClient = _ocelotServer.CreateClient(); } - private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) - { - var serializer = new Serializer(); - - if (File.Exists(_configurationPath)) - { - File.Delete(_configurationPath); - } - - using (TextWriter writer = File.CreateText(_configurationPath)) - { - serializer.Serialize(writer, yamlConfiguration); - } - } - private void GivenThereIsAServiceRunningOn(string url, int statusCode) { _servicebuilder = new WebHostBuilder() diff --git a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs index d7b680a5..ce11d346 100644 --- a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs +++ b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs @@ -7,38 +7,31 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Ocelot.Configuration.Yaml; +using Ocelot.DependencyInjection; +using Ocelot.Middleware; +using Ocelot.ScopedData; using Shouldly; using TestStack.BDDfy; using Xunit; -using YamlDotNet.Serialization; namespace Ocelot.AcceptanceTests { - using System.Linq; - using System.Threading.Tasks; - using DependencyInjection; - using Microsoft.Extensions.Configuration; - using Microsoft.Extensions.DependencyInjection; - using Microsoft.Extensions.Logging; - using Microsoft.Extensions.Primitives; - using Middleware; - using ScopedData; - public class CustomMiddlewareTests : IDisposable { private TestServer _server; private HttpClient _client; private HttpResponseMessage _response; private readonly string _configurationPath; - private StringContent _postContent; private IWebHost _builder; - - // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly - private double _netCoreAppVersion = 1.4; + private readonly Steps _steps; public CustomMiddlewareTests() { + _steps = new Steps();; _configurationPath = $"configuration.yaml"; } @@ -54,7 +47,7 @@ namespace Ocelot.AcceptanceTests }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41879", 200)) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + .And(x => _steps.GivenThereIsAConfiguration(new YamlConfiguration { ReRoutes = new List { @@ -65,8 +58,8 @@ namespace Ocelot.AcceptanceTests UpstreamHttpMethod = "Get", } } - })) - .And(x => x.GivenTheApiGatewayIsRunning(configuration)) + }, _configurationPath)) + .And(x => x.GivenOcelotIsRunning(configuration)) .When(x => x.WhenIGetUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => x.ThenTheResponseBodyShouldBe("PreHttpResponderMiddleware")) @@ -81,13 +74,12 @@ namespace Ocelot.AcceptanceTests PreHttpRequesterMiddleware = async (ctx, next) => { var service = ctx.RequestServices.GetService(); - service.Add("Response", - new HttpResponseMessage {Content = new StringContent("PreHttpRequesterMiddleware")}); + service.Add("Response", new HttpResponseMessage {Content = new StringContent("PreHttpRequesterMiddleware")}); } }; this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41879", 200)) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + .And(x => _steps.GivenThereIsAConfiguration(new YamlConfiguration { ReRoutes = new List { @@ -98,8 +90,8 @@ namespace Ocelot.AcceptanceTests UpstreamHttpMethod = "Get", } } - })) - .And(x => x.GivenTheApiGatewayIsRunning(configuration)) + }, _configurationPath)) + .And(x => x.GivenOcelotIsRunning(configuration)) .When(x => x.WhenIGetUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) .And(x => x.ThenTheResponseBodyShouldBe("PreHttpRequesterMiddleware")) @@ -111,7 +103,7 @@ namespace Ocelot.AcceptanceTests /// /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. /// - private void GivenTheApiGatewayIsRunning(OcelotMiddlewareConfiguration ocelotMiddlewareConfig) + private void GivenOcelotIsRunning(OcelotMiddlewareConfiguration ocelotMiddlewareConfig) { var builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) @@ -141,21 +133,6 @@ namespace Ocelot.AcceptanceTests _client = _server.CreateClient(); } - private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) - { - var serializer = new Serializer(); - - if (File.Exists(_configurationPath)) - { - File.Delete(_configurationPath); - } - - using (TextWriter writer = File.CreateText(_configurationPath)) - { - serializer.Serialize(writer, yamlConfiguration); - } - } - private void GivenThereIsAServiceRunningOn(string url, int statusCode) { _builder = new WebHostBuilder() diff --git a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs index c358e884..1b61281a 100644 --- a/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs +++ b/test/Ocelot.AcceptanceTests/ReturnsErrorTests.cs @@ -11,7 +11,6 @@ using Ocelot.ManualTest; using Shouldly; using TestStack.BDDfy; using Xunit; -using YamlDotNet.Serialization; namespace Ocelot.AcceptanceTests { @@ -20,22 +19,19 @@ namespace Ocelot.AcceptanceTests private TestServer _ocelotServer; private HttpClient _ocelotClient; private HttpResponseMessage _response; - private readonly string _configurationPath; private IWebHost _servicebuilder; - - // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly - private double _netCoreAppVersion = 1.4; + private readonly Steps _steps; public ReturnsErrorTests() { - _configurationPath = $"./bin/Debug/netcoreapp{_netCoreAppVersion}/configuration.yaml"; + _steps = new Steps(); } [Fact] public void should_return_response_200_and_foward_claim_as_header() { this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:53876")) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + .And(x => _steps.GivenThereIsAConfiguration(new YamlConfiguration { ReRoutes = new List { @@ -74,21 +70,6 @@ namespace Ocelot.AcceptanceTests _ocelotClient = _ocelotServer.CreateClient(); } - private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) - { - var serializer = new Serializer(); - - if (File.Exists(_configurationPath)) - { - File.Delete(_configurationPath); - } - - using (TextWriter writer = File.CreateText(_configurationPath)) - { - serializer.Serialize(writer, yamlConfiguration); - } - } - private void GivenThereIsAServiceRunningOn(string url) { _servicebuilder = new WebHostBuilder() diff --git a/test/Ocelot.AcceptanceTests/RoutingTests.cs b/test/Ocelot.AcceptanceTests/RoutingTests.cs index bef6e1b7..19b3c54a 100644 --- a/test/Ocelot.AcceptanceTests/RoutingTests.cs +++ b/test/Ocelot.AcceptanceTests/RoutingTests.cs @@ -12,7 +12,6 @@ using Ocelot.ManualTest; using Shouldly; using TestStack.BDDfy; using Xunit; -using YamlDotNet.Serialization; namespace Ocelot.AcceptanceTests { @@ -21,22 +20,19 @@ namespace Ocelot.AcceptanceTests private TestServer _server; private HttpClient _client; private HttpResponseMessage _response; - private readonly string _configurationPath; private StringContent _postContent; private IWebHost _builder; - - // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly - private double _netCoreAppVersion = 1.4; + private readonly Steps _steps; public RoutingTests() { - _configurationPath = $"./bin/Debug/netcoreapp{_netCoreAppVersion}/configuration.yaml"; + _steps = new Steps(); } [Fact] public void should_return_response_404_when_no_configuration_at_all() { - this.Given(x => x.GivenThereIsAConfiguration(new YamlConfiguration())) + this.Given(x => _steps.GivenThereIsAConfiguration(new YamlConfiguration())) .And(x => x.GivenTheApiGatewayIsRunning()) .When(x => x.WhenIGetUrlOnTheApiGateway("/")) .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) @@ -47,7 +43,7 @@ namespace Ocelot.AcceptanceTests public void should_return_response_200_with_simple_url() { this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", 200, "Hello from Laura")) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + .And(x => _steps.GivenThereIsAConfiguration(new YamlConfiguration { ReRoutes = new List { @@ -70,7 +66,7 @@ namespace Ocelot.AcceptanceTests public void should_return_response_200_with_complex_url() { this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/api/products/1", 200, "Some Product")) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + .And(x => _steps.GivenThereIsAConfiguration(new YamlConfiguration { ReRoutes = new List { @@ -93,7 +89,7 @@ namespace Ocelot.AcceptanceTests public void should_return_response_201_with_simple_url() { this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", 201, string.Empty)) - .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration + .And(x => _steps.GivenThereIsAConfiguration(new YamlConfiguration { ReRoutes = new List { @@ -128,21 +124,6 @@ namespace Ocelot.AcceptanceTests _client = _server.CreateClient(); } - private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) - { - var serializer = new Serializer(); - - if (File.Exists(_configurationPath)) - { - File.Delete(_configurationPath); - } - - using (TextWriter writer = File.CreateText(_configurationPath)) - { - serializer.Serialize(writer, yamlConfiguration); - } - } - private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody) { _builder = new WebHostBuilder() diff --git a/test/Ocelot.AcceptanceTests/Steps.cs b/test/Ocelot.AcceptanceTests/Steps.cs new file mode 100644 index 00000000..7b90630f --- /dev/null +++ b/test/Ocelot.AcceptanceTests/Steps.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; +using Newtonsoft.Json; +using Ocelot.Configuration.Yaml; +using Ocelot.ManualTest; +using Shouldly; +using YamlDotNet.Serialization; + +namespace Ocelot.AcceptanceTests +{ + public class Steps : IDisposable + { + private TestServer _ocelotServer; + private HttpClient _ocelotClient; + private HttpResponseMessage _response; + private HttpContent _postContent; + private BearerToken _token; + + public HttpClient OcelotClient => _ocelotClient; + + public void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration) + { + var configurationPath = TestConfiguration.ConfigurationPath; + + var serializer = new Serializer(); + + if (File.Exists(configurationPath)) + { + File.Delete(configurationPath); + } + + using (TextWriter writer = File.CreateText(configurationPath)) + { + serializer.Serialize(writer, yamlConfiguration); + } + } + + public void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration, string configurationPath) + { + var serializer = new Serializer(); + + if (File.Exists(configurationPath)) + { + File.Delete(configurationPath); + } + + using (TextWriter writer = File.CreateText(configurationPath)) + { + serializer.Serialize(writer, yamlConfiguration); + } + } + + /// + /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step. + /// + public void GivenOcelotIsRunning() + { + _ocelotServer = new TestServer(new WebHostBuilder() + .UseStartup()); + + _ocelotClient = _ocelotServer.CreateClient(); + } + + public void GivenIHaveAddedATokenToMyRequest() + { + _ocelotClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken); + } + + public void GivenIHaveAToken(string url) + { + var tokenUrl = $"{url}/connect/token"; + var formData = new List> + { + new KeyValuePair("client_id", "client"), + new KeyValuePair("client_secret", "secret"), + new KeyValuePair("scope", "api"), + new KeyValuePair("username", "test"), + new KeyValuePair("password", "test"), + new KeyValuePair("grant_type", "password") + }; + var content = new FormUrlEncodedContent(formData); + + using (var httpClient = new HttpClient()) + { + var response = httpClient.PostAsync(tokenUrl, content).Result; + response.EnsureSuccessStatusCode(); + var responseContent = response.Content.ReadAsStringAsync().Result; + _token = JsonConvert.DeserializeObject(responseContent); + } + } + + public void WhenIGetUrlOnTheApiGateway(string url) + { + _response = _ocelotClient.GetAsync(url).Result; + } + + public void WhenIPostUrlOnTheApiGateway(string url) + { + _response = _ocelotClient.PostAsync(url, _postContent).Result; + } + + public void GivenThePostHasContent(string postcontent) + { + _postContent = new StringContent(postcontent); + } + + public void ThenTheResponseBodyShouldBe(string expectedBody) + { + _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody); + } + + public void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) + { + _response.StatusCode.ShouldBe(expectedHttpStatusCode); + } + + public void Dispose() + { + _ocelotClient?.Dispose(); + _ocelotServer?.Dispose(); + } + } +} diff --git a/test/Ocelot.AcceptanceTests/TestConfiguration.cs b/test/Ocelot.AcceptanceTests/TestConfiguration.cs new file mode 100644 index 00000000..59547854 --- /dev/null +++ b/test/Ocelot.AcceptanceTests/TestConfiguration.cs @@ -0,0 +1,8 @@ +namespace Ocelot.AcceptanceTests +{ + public static class TestConfiguration + { + public static double Version => 1.4; + public static string ConfigurationPath => $"./bin/Debug/netcoreapp{Version}/configuration.yaml"; + } +} diff --git a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs index 8c1cce52..8f7af24e 100644 --- a/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs +++ b/test/Ocelot.UnitTests/Configuration/InMemoryConfigurationRepositoryTests.cs @@ -42,29 +42,6 @@ namespace Ocelot.UnitTests.Configuration .BDDfy(); } - /// - /// long runnnig unit test to make sure repo thread safeok on - /// - [Fact] - public void repo_is_thread_safe() - { - var tasks = new Task[100000]; - for (int i = 0; i < tasks.Length; i++) - { - tasks[i] = Fire(); - } - - Task.WaitAll(tasks); - } - - private async Task Fire() - { - var taskGuid = Guid.NewGuid().ToString(); - _repo.AddOrReplace(new FakeConfig(taskGuid)); - var configuration = _repo.Get(); - configuration.Data.ReRoutes[0].DownstreamTemplate.ShouldBe(taskGuid); - } - private void ThenTheConfigurationIsReturned() { _getResult.Data.ReRoutes[0].DownstreamTemplate.ShouldBe("initial");