mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 14:50:49 +08:00 
			
		
		
		
	@@ -1,137 +0,0 @@
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using CacheManager.Core.Internal;
 | 
			
		||||
using CacheManager.Core.Logging;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using static CacheManager.Core.Utility.Guard;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.AcceptanceTests.Caching
 | 
			
		||||
{
 | 
			
		||||
    public class InMemoryJsonHandle<TCacheValue> : BaseCacheHandle<TCacheValue>
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ICacheSerializer _serializer;
 | 
			
		||||
        private readonly ConcurrentDictionary<string, Tuple<Type, byte[]>> _cache;
 | 
			
		||||
 | 
			
		||||
        public InMemoryJsonHandle(
 | 
			
		||||
            ICacheManagerConfiguration managerConfiguration,
 | 
			
		||||
            CacheHandleConfiguration configuration,
 | 
			
		||||
            ICacheSerializer serializer,
 | 
			
		||||
            ILoggerFactory loggerFactory) : base(managerConfiguration, configuration)
 | 
			
		||||
        {
 | 
			
		||||
            _cache = new ConcurrentDictionary<string, Tuple<Type, byte[]>>();
 | 
			
		||||
            _serializer = serializer;
 | 
			
		||||
            Logger = loggerFactory.CreateLogger(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int Count => _cache.Count;
 | 
			
		||||
 | 
			
		||||
        protected override ILogger Logger { get; }
 | 
			
		||||
 | 
			
		||||
        public override void Clear() => _cache.Clear();
 | 
			
		||||
 | 
			
		||||
        public override void ClearRegion(string region)
 | 
			
		||||
        {
 | 
			
		||||
            NotNullOrWhiteSpace(region, nameof(region));
 | 
			
		||||
 | 
			
		||||
            var key = string.Concat(region, ":");
 | 
			
		||||
            foreach (var item in _cache.Where(p => p.Key.StartsWith(key, StringComparison.OrdinalIgnoreCase)))
 | 
			
		||||
            {
 | 
			
		||||
                _cache.TryRemove(item.Key, out Tuple<Type, byte[]> val);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Exists(string key)
 | 
			
		||||
        {
 | 
			
		||||
            NotNullOrWhiteSpace(key, nameof(key));
 | 
			
		||||
 | 
			
		||||
            return _cache.ContainsKey(key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Exists(string key, string region)
 | 
			
		||||
        {
 | 
			
		||||
            NotNullOrWhiteSpace(region, nameof(region));
 | 
			
		||||
            var fullKey = GetKey(key, region);
 | 
			
		||||
            return _cache.ContainsKey(fullKey);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override bool AddInternalPrepared(CacheItem<TCacheValue> item)
 | 
			
		||||
        {
 | 
			
		||||
            NotNull(item, nameof(item));
 | 
			
		||||
 | 
			
		||||
            var key = GetKey(item.Key, item.Region);
 | 
			
		||||
 | 
			
		||||
            var serializedItem = _serializer.SerializeCacheItem(item);
 | 
			
		||||
 | 
			
		||||
            return _cache.TryAdd(key, new Tuple<Type, byte[]>(item.Value.GetType(), serializedItem));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override CacheItem<TCacheValue> GetCacheItemInternal(string key) => GetCacheItemInternal(key, null);
 | 
			
		||||
 | 
			
		||||
        protected override CacheItem<TCacheValue> GetCacheItemInternal(string key, string region)
 | 
			
		||||
        {
 | 
			
		||||
            var fullKey = GetKey(key, region);
 | 
			
		||||
 | 
			
		||||
            CacheItem<TCacheValue> deserializedResult = null;
 | 
			
		||||
 | 
			
		||||
            if (_cache.TryGetValue(fullKey, out Tuple<Type, byte[]> result))
 | 
			
		||||
            {
 | 
			
		||||
                deserializedResult = _serializer.DeserializeCacheItem<TCacheValue>(result.Item2, result.Item1);
 | 
			
		||||
 | 
			
		||||
                if (deserializedResult.ExpirationMode != ExpirationMode.None && IsExpired(deserializedResult, DateTime.UtcNow))
 | 
			
		||||
                {
 | 
			
		||||
                    _cache.TryRemove(fullKey, out Tuple<Type, byte[]> removeResult);
 | 
			
		||||
                    TriggerCacheSpecificRemove(key, region, CacheItemRemovedReason.Expired, deserializedResult.Value);
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return deserializedResult;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void PutInternalPrepared(CacheItem<TCacheValue> item)
 | 
			
		||||
        {
 | 
			
		||||
            NotNull(item, nameof(item));
 | 
			
		||||
 | 
			
		||||
            var serializedItem = _serializer.SerializeCacheItem<TCacheValue>(item);
 | 
			
		||||
 | 
			
		||||
            _cache[GetKey(item.Key, item.Region)] = new Tuple<Type, byte[]>(item.Value.GetType(), serializedItem);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override bool RemoveInternal(string key) => RemoveInternal(key, null);
 | 
			
		||||
 | 
			
		||||
        protected override bool RemoveInternal(string key, string region)
 | 
			
		||||
        {
 | 
			
		||||
            var fullKey = GetKey(key, region);
 | 
			
		||||
            return _cache.TryRemove(fullKey, out Tuple<Type, byte[]> val);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static string GetKey(string key, string region)
 | 
			
		||||
        {
 | 
			
		||||
            NotNullOrWhiteSpace(key, nameof(key));
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(region))
 | 
			
		||||
            {
 | 
			
		||||
                return key;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return string.Concat(region, ":", key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool IsExpired(CacheItem<TCacheValue> item, DateTime now)
 | 
			
		||||
        {
 | 
			
		||||
            if (item.ExpirationMode == ExpirationMode.Absolute
 | 
			
		||||
                && item.CreatedUtc.Add(item.ExpirationTimeout) < now)
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            else if (item.ExpirationMode == ExpirationMode.Sliding
 | 
			
		||||
                && item.LastAccessedUtc.Add(item.ExpirationTimeout) < now)
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,225 +0,0 @@
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Threading;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class CachingTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private readonly ServiceHandler _serviceHandler;
 | 
			
		||||
 | 
			
		||||
        public CachingTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler = new ServiceHandler();
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_cached_response()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51899,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura", null, null))
 | 
			
		||||
                .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"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:51899", 200, "Hello from Tom"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.ThenTheContentLengthIs(16))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_cached_response_with_expires_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 52839,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:52839", 200, "Hello from Laura", "Expires", "-1"))
 | 
			
		||||
                .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"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:52839", 200, "Hello from Tom"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.ThenTheContentLengthIs(16))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyHeaderIs("Expires", "-1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_cached_response_when_using_jsonserialized_cache()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51899,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura", null, null))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningUsingJsonSerializedCache())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:51899", 200, "Hello from Tom"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_return_cached_response_as_ttl_expires()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51899,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 1
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura", null, null))
 | 
			
		||||
                .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"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:51899", 200, "Hello from Tom"))
 | 
			
		||||
                .And(x => x.GivenTheCacheExpires())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheCacheExpires()
 | 
			
		||||
        {
 | 
			
		||||
            Thread.Sleep(1000);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheServiceNowReturns(string url, int statusCode, string responseBody)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.Dispose();
 | 
			
		||||
            GivenThereIsAServiceRunningOn(url, statusCode, responseBody, null, null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody, string key, string value)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(key))
 | 
			
		||||
                {
 | 
			
		||||
                    context.Response.Headers.Add(key, value);
 | 
			
		||||
                }
 | 
			
		||||
                context.Response.StatusCode = statusCode;
 | 
			
		||||
                await context.Response.WriteAsync(responseBody);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -17,6 +17,8 @@ using static Ocelot.Infrastructure.Wait;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Cache;
 | 
			
		||||
 | 
			
		||||
    public class ConfigurationInConsulTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private IWebHost _builder;
 | 
			
		||||
@@ -76,51 +78,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_response_200_with_simple_url_when_using_jsonserialized_cache()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51779,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                GlobalConfiguration = new FileGlobalConfiguration()
 | 
			
		||||
                {
 | 
			
		||||
                    ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
 | 
			
		||||
                    {
 | 
			
		||||
                        Host = "localhost",
 | 
			
		||||
                        Port = 9502
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var fakeConsulServiceDiscoveryUrl = "http://localhost:9502";
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, ""))
 | 
			
		||||
                .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_load_configuration_out_of_consul()
 | 
			
		||||
        {
 | 
			
		||||
@@ -485,5 +442,28 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
            _builder?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        class FakeCache : IOcelotCache<FileConfiguration>
 | 
			
		||||
        {
 | 
			
		||||
            public void Add(string key, FileConfiguration value, TimeSpan ttl, string region)
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void AddAndDelete(string key, FileConfiguration value, TimeSpan ttl, string region)
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public FileConfiguration Get(string key, string region)
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void ClearRegion(string region)
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,6 @@
 | 
			
		||||
    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="CacheManager.Serialization.Json" Version="1.1.2" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.1.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
 | 
			
		||||
 
 | 
			
		||||
@@ -1,40 +1,35 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Net.Http.Headers;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using IdentityServer4.AccessTokenValidation;
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Microsoft.AspNetCore.TestHost;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.DependencyInjection;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
 | 
			
		||||
using Ocelot.AcceptanceTests.Caching;
 | 
			
		||||
using System.IO.Compression;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using static Ocelot.AcceptanceTests.HttpDelegatingHandlersTests;
 | 
			
		||||
using Ocelot.Requester;
 | 
			
		||||
using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
using static Ocelot.Infrastructure.Wait;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Butterfly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.IO;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Net.Http.Headers;
 | 
			
		||||
    using System.Threading;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using IdentityServer4.AccessTokenValidation;
 | 
			
		||||
    using Microsoft.AspNetCore.Builder;
 | 
			
		||||
    using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
    using Microsoft.AspNetCore.TestHost;
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Microsoft.Extensions.Logging;
 | 
			
		||||
    using Newtonsoft.Json;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
 | 
			
		||||
    using System.IO.Compression;
 | 
			
		||||
    using System.Text;
 | 
			
		||||
    using static Ocelot.AcceptanceTests.HttpDelegatingHandlersTests;
 | 
			
		||||
    using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
    using static Ocelot.Infrastructure.Wait;
 | 
			
		||||
    using Configuration.Repository;
 | 
			
		||||
    using Microsoft.Net.Http.Headers;
 | 
			
		||||
    using Ocelot.Configuration.Creator;
 | 
			
		||||
    using CookieHeaderValue = System.Net.Http.Headers.CookieHeaderValue;
 | 
			
		||||
    using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue;
 | 
			
		||||
 | 
			
		||||
    public class Steps : IDisposable
 | 
			
		||||
@@ -44,7 +39,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
        private HttpResponseMessage _response;
 | 
			
		||||
        private HttpContent _postContent;
 | 
			
		||||
        private BearerToken _token;
 | 
			
		||||
        public HttpClient OcelotClient => _ocelotClient;
 | 
			
		||||
        public string RequestIdKey = "OcRequestId";
 | 
			
		||||
        private readonly Random _random;
 | 
			
		||||
        private IWebHostBuilder _webHostBuilder;
 | 
			
		||||
@@ -428,55 +422,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
            header.First().ShouldBe(value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ThenTheResponseBodyHeaderIs(string key, string value)
 | 
			
		||||
        {
 | 
			
		||||
            var header = _response.Content.Headers.GetValues(key);
 | 
			
		||||
            header.First().ShouldBe(value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ThenTheTraceHeaderIsSet(string key)
 | 
			
		||||
        {
 | 
			
		||||
            var header = _response.Headers.GetValues(key);
 | 
			
		||||
            header.First().ShouldNotBeNullOrEmpty();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenOcelotIsRunningUsingJsonSerializedCache()
 | 
			
		||||
        {
 | 
			
		||||
            _webHostBuilder = new WebHostBuilder();
 | 
			
		||||
 | 
			
		||||
            _webHostBuilder
 | 
			
		||||
                .ConfigureAppConfiguration((hostingContext, config) =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
 | 
			
		||||
                    var env = hostingContext.HostingEnvironment;
 | 
			
		||||
                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
 | 
			
		||||
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
 | 
			
		||||
                    config.AddJsonFile("ocelot.json", false, false);
 | 
			
		||||
                    config.AddEnvironmentVariables();
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureServices(s =>
 | 
			
		||||
                {
 | 
			
		||||
                    s.AddOcelot()
 | 
			
		||||
                        .AddCacheManager((x) =>
 | 
			
		||||
                        {
 | 
			
		||||
                            x.WithMicrosoftLogging(log =>
 | 
			
		||||
                                {
 | 
			
		||||
                                    log.AddConsole(LogLevel.Debug);
 | 
			
		||||
                                })
 | 
			
		||||
                                .WithJsonSerializer()
 | 
			
		||||
                                .WithHandle(typeof(InMemoryJsonHandle<>));
 | 
			
		||||
                        });
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.UseOcelot().Wait();
 | 
			
		||||
                }); 
 | 
			
		||||
 | 
			
		||||
            _ocelotServer = new TestServer(_webHostBuilder);
 | 
			
		||||
 | 
			
		||||
            _ocelotClient = _ocelotServer.CreateClient();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenOcelotIsRunningUsingConsulToStoreConfig()
 | 
			
		||||
        {
 | 
			
		||||
            _webHostBuilder = new WebHostBuilder();
 | 
			
		||||
@@ -505,69 +450,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
            _ocelotClient = _ocelotServer.CreateClient();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache()
 | 
			
		||||
        {
 | 
			
		||||
            _webHostBuilder = new WebHostBuilder();
 | 
			
		||||
 | 
			
		||||
            _webHostBuilder
 | 
			
		||||
                .ConfigureAppConfiguration((hostingContext, config) =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
 | 
			
		||||
                    var env = hostingContext.HostingEnvironment;
 | 
			
		||||
                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
 | 
			
		||||
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
 | 
			
		||||
                    config.AddJsonFile("ocelot.json", optional: true, reloadOnChange: false);
 | 
			
		||||
                    config.AddEnvironmentVariables();
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureServices(s =>
 | 
			
		||||
                {
 | 
			
		||||
                    s.AddOcelot()
 | 
			
		||||
                        .AddCacheManager((x) =>
 | 
			
		||||
                        {
 | 
			
		||||
                            x.WithMicrosoftLogging(log =>
 | 
			
		||||
                                {
 | 
			
		||||
                                    log.AddConsole(LogLevel.Debug);
 | 
			
		||||
                                })
 | 
			
		||||
                                .WithJsonSerializer()
 | 
			
		||||
                                .WithHandle(typeof(InMemoryJsonHandle<>));
 | 
			
		||||
                        })
 | 
			
		||||
                        .AddStoreOcelotConfigurationInConsul();
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.UseOcelot().Wait();
 | 
			
		||||
                }); 
 | 
			
		||||
 | 
			
		||||
            _ocelotServer = new TestServer(_webHostBuilder);
 | 
			
		||||
 | 
			
		||||
            _ocelotClient = _ocelotServer.CreateClient();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal void ThenTheResponseShouldBe(FileConfiguration expecteds)
 | 
			
		||||
        {
 | 
			
		||||
            var response = JsonConvert.DeserializeObject<FileConfiguration>(_response.Content.ReadAsStringAsync().Result);
 | 
			
		||||
 | 
			
		||||
            response.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey);
 | 
			
		||||
            response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Host);
 | 
			
		||||
            response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Port);
 | 
			
		||||
 | 
			
		||||
            for (var i = 0; i < response.ReRoutes.Count; i++)
 | 
			
		||||
            {
 | 
			
		||||
                for (var j = 0; j < response.ReRoutes[i].DownstreamHostAndPorts.Count; j++)
 | 
			
		||||
                {
 | 
			
		||||
                    var result = response.ReRoutes[i].DownstreamHostAndPorts[j];
 | 
			
		||||
                    var expected = expecteds.ReRoutes[i].DownstreamHostAndPorts[j];
 | 
			
		||||
                    result.Host.ShouldBe(expected.Host);
 | 
			
		||||
                    result.Port.ShouldBe(expected.Port);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                response.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].DownstreamPathTemplate);
 | 
			
		||||
                response.ReRoutes[i].DownstreamScheme.ShouldBe(expecteds.ReRoutes[i].DownstreamScheme);
 | 
			
		||||
                response.ReRoutes[i].UpstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].UpstreamPathTemplate);
 | 
			
		||||
                response.ReRoutes[i].UpstreamHttpMethod.ShouldBe(expecteds.ReRoutes[i].UpstreamHttpMethod);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@@ -590,15 +472,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                .UseConfiguration(configuration)
 | 
			
		||||
                .ConfigureServices(s =>
 | 
			
		||||
                {
 | 
			
		||||
                    Action<ConfigurationBuilderCachePart> settings = (x) =>
 | 
			
		||||
                    {
 | 
			
		||||
                        x.WithMicrosoftLogging(log =>
 | 
			
		||||
                        {
 | 
			
		||||
                            log.AddConsole(LogLevel.Debug);
 | 
			
		||||
                        })
 | 
			
		||||
                        .WithDictionaryHandle();
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    s.AddOcelot(configuration);
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureLogging(l =>
 | 
			
		||||
@@ -688,26 +561,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenIHaveAnOcelotToken(string adminPath)
 | 
			
		||||
        {
 | 
			
		||||
            var tokenUrl = $"{adminPath}/connect/token";
 | 
			
		||||
            var formData = new List<KeyValuePair<string, string>>
 | 
			
		||||
            {
 | 
			
		||||
                new KeyValuePair<string, string>("client_id", "admin"),
 | 
			
		||||
                new KeyValuePair<string, string>("client_secret", "secret"),
 | 
			
		||||
                new KeyValuePair<string, string>("scope", "admin"),
 | 
			
		||||
                new KeyValuePair<string, string>("username", "admin"),
 | 
			
		||||
                new KeyValuePair<string, string>("password", "admin"),
 | 
			
		||||
                new KeyValuePair<string, string>("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<BearerToken>(responseContent);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void VerifyIdentiryServerStarted(string url)
 | 
			
		||||
        {
 | 
			
		||||
            using (var httpClient = new HttpClient())
 | 
			
		||||
@@ -883,11 +736,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
            _response.Headers.GetValues(RequestIdKey).First().ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ThenTheContentLengthIs(int expected)
 | 
			
		||||
        {
 | 
			
		||||
            _response.Content.Headers.ContentLength.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void WhenIMakeLotsOfDifferentRequestsToTheApiGateway()
 | 
			
		||||
        {
 | 
			
		||||
            int numberOfRequests = 100;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user