From d548a86327d2c4fd8ffbb09a660f5c52f7463788 Mon Sep 17 00:00:00 2001 From: TomPallister Date: Sun, 19 Feb 2017 15:29:32 +0000 Subject: [PATCH] Added integration test project as acceptance style doesnt work when running the new admin area because identityserver needs to use proper networking --- Ocelot.sln | 9 +- build.cake | 23 +- .../FileConfigurationController.cs | 3 +- .../ServiceCollectionExtensions.cs | 4 +- .../Middleware/OcelotMiddlewareExtensions.cs | 4 +- .../AdministrationTests.cs | 82 ------- test/Ocelot.AcceptanceTests/Steps.cs | 22 +- .../AdministrationTests.cs | 209 ++++++++++++++++++ test/Ocelot.IntegrationTests/BearerToken.cs | 16 ++ .../Ocelot.IntegrationTests.xproj | 22 ++ .../Properties/AssemblyInfo.cs | 19 ++ test/Ocelot.IntegrationTests/appsettings.json | 10 + .../configuration.json | 1 + test/Ocelot.IntegrationTests/project.json | 50 +++++ 14 files changed, 384 insertions(+), 90 deletions(-) delete mode 100644 test/Ocelot.AcceptanceTests/AdministrationTests.cs create mode 100644 test/Ocelot.IntegrationTests/AdministrationTests.cs create mode 100644 test/Ocelot.IntegrationTests/BearerToken.cs create mode 100644 test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.xproj create mode 100644 test/Ocelot.IntegrationTests/Properties/AssemblyInfo.cs create mode 100644 test/Ocelot.IntegrationTests/appsettings.json create mode 100644 test/Ocelot.IntegrationTests/configuration.json create mode 100644 test/Ocelot.IntegrationTests/project.json diff --git a/Ocelot.sln b/Ocelot.sln index 6c0006b0..d88020d3 100644 --- a/Ocelot.sln +++ b/Ocelot.sln @@ -8,7 +8,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3FA7C349-DBE8-4904-A2CE-015B8869CE6C}" ProjectSection(SolutionItems) = preProject .gitignore = .gitignore - appveyor.yml = appveyor.yml build-and-release-unstable.ps1 = build-and-release-unstable.ps1 build-and-run-tests.ps1 = build-and-run-tests.ps1 build.cake = build.cake @@ -19,7 +18,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution GitVersion.yml = GitVersion.yml global.json = global.json LICENSE.md = LICENSE.md - Ocelot.nuspec = Ocelot.nuspec README.md = README.md release.ps1 = release.ps1 ReleaseNotes.md = ReleaseNotes.md @@ -41,6 +39,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot.ManualTest", "test\O EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot.Benchmarks", "test\Ocelot.Benchmarks\Ocelot.Benchmarks.xproj", "{106B49E6-95F6-4A7B-B81C-96BFA74AF035}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Ocelot.IntegrationTests", "test\Ocelot.IntegrationTests\Ocelot.IntegrationTests.xproj", "{D4575572-99CA-4530-8737-C296EDA326F8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -67,6 +67,10 @@ Global {106B49E6-95F6-4A7B-B81C-96BFA74AF035}.Debug|Any CPU.Build.0 = Debug|Any CPU {106B49E6-95F6-4A7B-B81C-96BFA74AF035}.Release|Any CPU.ActiveCfg = Release|Any CPU {106B49E6-95F6-4A7B-B81C-96BFA74AF035}.Release|Any CPU.Build.0 = Release|Any CPU + {D4575572-99CA-4530-8737-C296EDA326F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4575572-99CA-4530-8737-C296EDA326F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4575572-99CA-4530-8737-C296EDA326F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4575572-99CA-4530-8737-C296EDA326F8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -77,5 +81,6 @@ Global {F8C224FE-36BE-45F5-9B0E-666D8F4A9B52} = {5B401523-36DA-4491-B73A-7590A26E420B} {02BBF4C5-517E-4157-8D21-4B8B9E118B7A} = {5B401523-36DA-4491-B73A-7590A26E420B} {106B49E6-95F6-4A7B-B81C-96BFA74AF035} = {5B401523-36DA-4491-B73A-7590A26E420B} + {D4575572-99CA-4530-8737-C296EDA326F8} = {5B401523-36DA-4491-B73A-7590A26E420B} EndGlobalSection EndGlobal diff --git a/build.cake b/build.cake index 579f4e82..d3aee78f 100644 --- a/build.cake +++ b/build.cake @@ -18,7 +18,9 @@ var unitTestAssemblies = @"./test/Ocelot.UnitTests"; // acceptance testing var artifactsForAcceptanceTestsDir = artifactsDir + Directory("AcceptanceTests"); -var acceptanceTestAssemblies = @"./test/Ocelot.AcceptanceTests"; + +// integration testing +var artifactsForIntegrationTestsDir = artifactsDir + Directory("IntegrationTests"); // benchmark testing var artifactsForBenchmarkTestsDir = artifactsDir + Directory("BenchmarkTests"); @@ -129,6 +131,24 @@ Task("RunAcceptanceTests") }); + Task("RunIntegrationTests") + .IsDependentOn("Restore") + .Does(() => + { + var buildSettings = new DotNetCoreTestSettings + { + Configuration = "Debug", //int test config is hard-coded for debug + }; + + EnsureDirectoryExists(artifactsForIntegrationTestsDir); + + DoInDirectory("test/Ocelot.IntegrationTests", () => + { + DotNetCoreTest(".", buildSettings); + }); + + }); + Task("RunBenchmarkTests") .IsDependentOn("Restore") .Does(() => @@ -149,6 +169,7 @@ Task("RunBenchmarkTests") Task("RunTests") .IsDependentOn("RunUnitTests") .IsDependentOn("RunAcceptanceTests") + .IsDependentOn("RunIntegrationTests") .Does(() => { }); diff --git a/src/Ocelot/Controllers/FileConfigurationController.cs b/src/Ocelot/Controllers/FileConfigurationController.cs index 3589bdb5..3dc22303 100644 --- a/src/Ocelot/Controllers/FileConfigurationController.cs +++ b/src/Ocelot/Controllers/FileConfigurationController.cs @@ -4,7 +4,7 @@ using Ocelot.Services; namespace Ocelot.Controllers { - [Authorize(Roles = "Admin")] + [Authorize] [Route("configuration")] public class FileConfigurationController : Controller { @@ -18,7 +18,6 @@ namespace Ocelot.Controllers [HttpGet] public IActionResult Get() { - var user = this.HttpContext.User; return new OkObjectResult(_getFileConfig.Invoke().Data); } } diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index c06d965b..c213aa6b 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -112,7 +112,9 @@ namespace Ocelot.DependencyInjection SubjectId = "admin", } }); - services.AddMvcCore().AddJsonFormatters(); + services.AddMvcCore() + .AddAuthorization() + .AddJsonFormatters(); services.AddLogging(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs index ab51e8da..fa113771 100644 --- a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs +++ b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs @@ -148,9 +148,11 @@ namespace Ocelot.Middleware { builder.Map(configuration.AdministrationPath, app => { + var identityServerUrl = $"http://localhost:5000/{configuration.AdministrationPath.Remove(0,1)}"; + app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions { - Authority = "http://localhost:5000/admin", + Authority = identityServerUrl, ApiName = "admin", RequireHttpsMetadata = false, AllowedScopes = new List(), diff --git a/test/Ocelot.AcceptanceTests/AdministrationTests.cs b/test/Ocelot.AcceptanceTests/AdministrationTests.cs deleted file mode 100644 index 93c4a8b9..00000000 --- a/test/Ocelot.AcceptanceTests/AdministrationTests.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using Ocelot.Configuration.File; -using TestStack.BDDfy; -using Xunit; - -namespace Ocelot.AcceptanceTests -{ - public class AdministrationTests : IDisposable - { - private readonly Steps _steps; - - public AdministrationTests() - { - _steps = new Steps(); - } - - [Fact] - public void should_return_response_200_with_call_re_routes_controller() - { - var configuration = new FileConfiguration - { - GlobalConfiguration = new FileGlobalConfiguration - { - AdministrationPath = "/administration" - } - }; - - this.Given(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/administration/configuration")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .BDDfy(); - } - - [Fact] - public void should_return_file_configuration() - { - var configuration = new FileConfiguration - { - GlobalConfiguration = new FileGlobalConfiguration - { - AdministrationPath = "/administration" - }, - ReRoutes = new List() - { - new FileReRoute() - { - DownstreamHost = "localhost", - DownstreamPort = 80, - DownstreamScheme = "https", - DownstreamPathTemplate = "/", - UpstreamHttpMethod = "get", - UpstreamPathTemplate = "/" - }, - new FileReRoute() - { - DownstreamHost = "localhost", - DownstreamPort = 80, - DownstreamScheme = "https", - DownstreamPathTemplate = "/", - UpstreamHttpMethod = "get", - UpstreamPathTemplate = "/test" - } - } - }; - - this.Given(x => _steps.GivenThereIsAConfiguration(configuration)) - .And(x => _steps.GivenOcelotIsRunning()) - .When(x => _steps.WhenIGetUrlOnTheApiGateway("/administration/configuration")) - .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) - .And(x => _steps.ThenTheResponseShouldBe(configuration)) - .BDDfy(); - } - - public void Dispose() - { - _steps.Dispose(); - } - } -} diff --git a/test/Ocelot.AcceptanceTests/Steps.cs b/test/Ocelot.AcceptanceTests/Steps.cs index 4a946947..1f4a8da1 100644 --- a/test/Ocelot.AcceptanceTests/Steps.cs +++ b/test/Ocelot.AcceptanceTests/Steps.cs @@ -133,7 +133,7 @@ namespace Ocelot.AcceptanceTests }) .Configure(a => { - a.UseOcelot(ocelotMiddlewareConfig); + a.UseOcelot(ocelotMiddlewareConfig).Wait(); })); _ocelotClient = _ocelotServer.CreateClient(); @@ -167,6 +167,26 @@ namespace Ocelot.AcceptanceTests } } + public void GivenIHaveAnOcelotToken(string adminPath) + { + var tokenUrl = $"{adminPath}/connect/token"; + var formData = new List> + { + new KeyValuePair("client_id", "admin"), + new KeyValuePair("client_secret", "secret"), + new KeyValuePair("scope", "admin"), + new KeyValuePair("username", "admin"), + new KeyValuePair("password", "admin"), + new KeyValuePair("grant_type", "password") + }; + var content = new FormUrlEncodedContent(formData); + + var response = _ocelotClient.PostAsync(tokenUrl, content).Result; + var responseContent = response.Content.ReadAsStringAsync().Result; + response.EnsureSuccessStatusCode(); + _token = JsonConvert.DeserializeObject(responseContent); + } + public void VerifyIdentiryServerStarted(string url) { using (var httpClient = new HttpClient()) diff --git a/test/Ocelot.IntegrationTests/AdministrationTests.cs b/test/Ocelot.IntegrationTests/AdministrationTests.cs new file mode 100644 index 00000000..6ea1aa32 --- /dev/null +++ b/test/Ocelot.IntegrationTests/AdministrationTests.cs @@ -0,0 +1,209 @@ +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 Newtonsoft.Json; +using Ocelot.Configuration.File; +using Ocelot.ManualTest; +using Shouldly; +using TestStack.BDDfy; +using Xunit; + +namespace Ocelot.IntegrationTests +{ + public class AdministrationTests : IDisposable + { + private readonly HttpClient _httpClient; + private HttpResponseMessage _response; + private IWebHost _builder; + private readonly string _ocelotBaseUrl; + private BearerToken _token; + + public AdministrationTests() + { + _httpClient = new HttpClient(); + _ocelotBaseUrl = "http://localhost:5000"; + _httpClient.BaseAddress = new Uri(_ocelotBaseUrl); + } + + [Fact] + public void should_return_response_401_with_call_re_routes_controller() + { + var configuration = new FileConfiguration + { + GlobalConfiguration = new FileGlobalConfiguration + { + AdministrationPath = "/administration" + } + }; + + this.Given(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .When(x => WhenIGetUrlOnTheApiGateway("/administration/configuration")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.Unauthorized)) + .BDDfy(); + } + + [Fact] + public void should_return_response_200_with_call_re_routes_controller() + { + var configuration = new FileConfiguration + { + GlobalConfiguration = new FileGlobalConfiguration + { + AdministrationPath = "/administration" + } + }; + + this.Given(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .And(x => GivenIHaveAnOcelotToken("/administration")) + .And(x => GivenIHaveAddedATokenToMyRequest()) + .When(x => WhenIGetUrlOnTheApiGateway("/administration/configuration")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .BDDfy(); + } + + [Fact] + public void should_return_file_configuration() + { + var configuration = new FileConfiguration + { + GlobalConfiguration = new FileGlobalConfiguration + { + AdministrationPath = "/administration" + }, + ReRoutes = new List() + { + new FileReRoute() + { + DownstreamHost = "localhost", + DownstreamPort = 80, + DownstreamScheme = "https", + DownstreamPathTemplate = "/", + UpstreamHttpMethod = "get", + UpstreamPathTemplate = "/" + }, + new FileReRoute() + { + DownstreamHost = "localhost", + DownstreamPort = 80, + DownstreamScheme = "https", + DownstreamPathTemplate = "/", + UpstreamHttpMethod = "get", + UpstreamPathTemplate = "/test" + } + } + }; + + this.Given(x => GivenThereIsAConfiguration(configuration)) + .And(x => GivenOcelotIsRunning()) + .And(x => GivenIHaveAnOcelotToken("/administration")) + .And(x => GivenIHaveAddedATokenToMyRequest()) + .When(x => WhenIGetUrlOnTheApiGateway("/administration/configuration")) + .Then(x => ThenTheStatusCodeShouldBe(HttpStatusCode.OK)) + .And(x => ThenTheResponseShouldBe(configuration)) + .BDDfy(); + } + + private void ThenTheResponseShouldBe(FileConfiguration expected) + { + var response = JsonConvert.DeserializeObject(_response.Content.ReadAsStringAsync().Result); + + response.GlobalConfiguration.AdministrationPath.ShouldBe(expected.GlobalConfiguration.AdministrationPath); + response.GlobalConfiguration.RequestIdKey.ShouldBe(expected.GlobalConfiguration.RequestIdKey); + response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Host); + response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Port); + response.GlobalConfiguration.ServiceDiscoveryProvider.Provider.ShouldBe(expected.GlobalConfiguration.ServiceDiscoveryProvider.Provider); + + for (var i = 0; i < response.ReRoutes.Count; i++) + { + response.ReRoutes[i].DownstreamHost.ShouldBe(expected.ReRoutes[i].DownstreamHost); + response.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expected.ReRoutes[i].DownstreamPathTemplate); + response.ReRoutes[i].DownstreamPort.ShouldBe(expected.ReRoutes[i].DownstreamPort); + response.ReRoutes[i].DownstreamScheme.ShouldBe(expected.ReRoutes[i].DownstreamScheme); + response.ReRoutes[i].UpstreamPathTemplate.ShouldBe(expected.ReRoutes[i].UpstreamPathTemplate); + response.ReRoutes[i].UpstreamHttpMethod.ShouldBe(expected.ReRoutes[i].UpstreamHttpMethod); + } + } + + private void GivenIHaveAddedATokenToMyRequest() + { + _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token.AccessToken); + } + + private void GivenIHaveAnOcelotToken(string adminPath) + { + var tokenUrl = $"{adminPath}/connect/token"; + var formData = new List> + { + new KeyValuePair("client_id", "admin"), + new KeyValuePair("client_secret", "secret"), + new KeyValuePair("scope", "admin"), + new KeyValuePair("username", "admin"), + new KeyValuePair("password", "admin"), + new KeyValuePair("grant_type", "password") + }; + var content = new FormUrlEncodedContent(formData); + + var response = _httpClient.PostAsync(tokenUrl, content).Result; + var responseContent = response.Content.ReadAsStringAsync().Result; + response.EnsureSuccessStatusCode(); + _token = JsonConvert.DeserializeObject(responseContent); + } + + private void GivenOcelotIsRunning() + { + _builder = new WebHostBuilder() + .UseUrls(_ocelotBaseUrl) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseStartup() + .Build(); + + _builder.Start(); + } + + private void GivenThereIsAConfiguration(FileConfiguration fileConfiguration) + { + var configurationPath = $"{Directory.GetCurrentDirectory()}/configuration.json"; + + var jsonConfiguration = JsonConvert.SerializeObject(fileConfiguration); + + if (File.Exists(configurationPath)) + { + File.Delete(configurationPath); + } + + File.WriteAllText(configurationPath, jsonConfiguration); + + configurationPath = $"{AppContext.BaseDirectory}/configuration.json"; + + if (File.Exists(configurationPath)) + { + File.Delete(configurationPath); + } + + File.WriteAllText(configurationPath, jsonConfiguration); + } + + private void WhenIGetUrlOnTheApiGateway(string url) + { + _response = _httpClient.GetAsync(url).Result; + } + + private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode) + { + _response.StatusCode.ShouldBe(expectedHttpStatusCode); + } + + public void Dispose() + { + _builder?.Dispose(); + _httpClient?.Dispose(); + } + } +} diff --git a/test/Ocelot.IntegrationTests/BearerToken.cs b/test/Ocelot.IntegrationTests/BearerToken.cs new file mode 100644 index 00000000..efd35c33 --- /dev/null +++ b/test/Ocelot.IntegrationTests/BearerToken.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Ocelot.IntegrationTests +{ + 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.IntegrationTests/Ocelot.IntegrationTests.xproj b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.xproj new file mode 100644 index 00000000..ece2b3b5 --- /dev/null +++ b/test/Ocelot.IntegrationTests/Ocelot.IntegrationTests.xproj @@ -0,0 +1,22 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + d4575572-99ca-4530-8737-c296eda326f8 + Ocelot.IntegrationTests + .\obj + .\bin\ + v4.6.1 + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/Ocelot.IntegrationTests/Properties/AssemblyInfo.cs b/test/Ocelot.IntegrationTests/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..5535cd70 --- /dev/null +++ b/test/Ocelot.IntegrationTests/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Ocelot.IntegrationTests")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d4575572-99ca-4530-8737-c296eda326f8")] diff --git a/test/Ocelot.IntegrationTests/appsettings.json b/test/Ocelot.IntegrationTests/appsettings.json new file mode 100644 index 00000000..d73b7dcb --- /dev/null +++ b/test/Ocelot.IntegrationTests/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "IncludeScopes": true, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + } +} diff --git a/test/Ocelot.IntegrationTests/configuration.json b/test/Ocelot.IntegrationTests/configuration.json new file mode 100644 index 00000000..3f39532c --- /dev/null +++ b/test/Ocelot.IntegrationTests/configuration.json @@ -0,0 +1 @@ +{"ReRoutes":[],"GlobalConfiguration":{"RequestIdKey":null,"ServiceDiscoveryProvider":{"Provider":null,"Host":null,"Port":0},"AdministrationPath":"/administration"}} \ No newline at end of file diff --git a/test/Ocelot.IntegrationTests/project.json b/test/Ocelot.IntegrationTests/project.json new file mode 100644 index 00000000..7454b3a0 --- /dev/null +++ b/test/Ocelot.IntegrationTests/project.json @@ -0,0 +1,50 @@ +{ + "version": "0.0.0-dev", + + "buildOptions": { + "copyToOutput": { + "include": [ + "configuration.json", + "appsettings.json" + ] + } + }, + + "testRunner": "xunit", + + "dependencies": { + "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0", + "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0", + "Microsoft.Extensions.Configuration.Json": "1.1.0", + "Microsoft.Extensions.Logging": "1.1.0", + "Microsoft.Extensions.Logging.Console": "1.1.0", + "Microsoft.Extensions.Logging.Debug": "1.1.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0", + "Microsoft.AspNetCore.Http": "1.1.0", + "Microsoft.DotNet.InternalAbstractions": "1.0.0", + "Ocelot": "0.0.0-dev", + "xunit": "2.2.0-beta2-build3300", + "dotnet-test-xunit": "2.2.0-preview2-build1029", + "Ocelot.ManualTest": "0.0.0-dev", + "Microsoft.AspNetCore.TestHost": "1.1.0", + "IdentityServer4": "1.0.1", + "Microsoft.AspNetCore.Mvc": "1.1.0", + "Microsoft.AspNetCore.Server.Kestrel": "1.1.0", + "Microsoft.NETCore.App": "1.1.0", + "Shouldly": "2.8.2", + "TestStack.BDDfy": "4.3.2", + "Consul": "0.7.2.1" + }, + "runtimes": { + "win10-x64": {}, + "osx.10.11-x64": {}, + "win7-x64": {} + }, + "frameworks": { + "netcoreapp1.1": { + "imports": [ + ] + } + } +}