public async Task Tries_to_access_cache_on_failure_but_returns_error_if_not_in_cache(HttpMethod method)
        {
            // setup
            var testMessageHandler = new TestMessageHandler(HttpStatusCode.InternalServerError);
            var cache     = new Mock <IDistributedCache>(MockBehavior.Strict);
            var cacheTime = TimeSpan.FromSeconds(123);

            cache.Setup(c => c.GetAsync(method + url)).ReturnsAsync(default(byte[]));
            var client = new HttpClient(new RedisCacheFallbackHandler(testMessageHandler, TimeSpan.FromDays(1), cacheTime, cache.Object));

            // execute
            var result = await client.SendAsync(new HttpRequestMessage(method, url));

            // validate
            result.StatusCode.Should().Be(HttpStatusCode.InternalServerError);
        }
        public async Task Only_caches_get_results()
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var client = new HttpClient(new RedisCacheHandler(testMessageHandler, new Dictionary<HttpStatusCode, TimeSpan>(), (IDistributedCache) null));

            // execute twice for different methods
            await client.PostAsync("http://unittest", new StringContent(string.Empty));
            await client.PostAsync("http://unittest", new StringContent(string.Empty));
            await client.PutAsync("http://unittest", new StringContent(string.Empty));
            await client.PutAsync("http://unittest", new StringContent(string.Empty));
            await client.DeleteAsync("http://unittest");
            await client.DeleteAsync("http://unittest");

            // validate
            testMessageHandler.NumberOfCalls.Should().Be(6);
        }
        public async Task Caches_per_url()
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache = new Mock<IDistributedCache>(MockBehavior.Strict);
            cache.Setup(c => c.GetAsync(It.IsAny<string>())).ReturnsAsync(null);
            cache.Setup(c => c.SetAsync(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<DistributedCacheEntryOptions>())).Returns(Task.FromResult(true));
            var client = new HttpClient(new RedisCacheHandler(testMessageHandler, new Dictionary<HttpStatusCode, TimeSpan>(), cache.Object));

            // execute for different URLs
            await client.GetAsync("http://unittest1");
            await client.GetAsync("http://unittest2");

            // validate
            testMessageHandler.NumberOfCalls.Should().Be(2);
            cache.Verify(c => c.SetAsync(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<DistributedCacheEntryOptions>()), Times.Exactly(2));
        }
        public async Task Gets_the_data_again_after_entry_is_gone_from_cache()
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache = new Mock<IDistributedCache>(MockBehavior.Strict);
            cache.Setup(c => c.GetAsync("http://unittest/")).ReturnsAsync(null);
            cache.Setup(c => c.SetAsync("http://unittest/", It.IsAny<byte[]>(), It.IsAny<DistributedCacheEntryOptions>())).Returns(Task.FromResult(true));
            var client = new HttpClient(new RedisCacheHandler(testMessageHandler, new Dictionary<HttpStatusCode, TimeSpan>(), cache.Object));

            // execute twice
            await client.GetAsync("http://unittest");
            await client.GetAsync("http://unittest");

            // validate
            testMessageHandler.NumberOfCalls.Should().Be(2);
            cache.Verify(c => c.GetAsync("http://unittest/"), Times.Exactly(2));
        }
        public async Task Never_updates_the_cache_on_failure(HttpMethod method)
        {
            // setup
            var testMessageHandler = new TestMessageHandler(HttpStatusCode.InternalServerError);
            var cache     = new Mock <IDistributedCache>(MockBehavior.Strict);
            var cacheTime = TimeSpan.FromSeconds(123);

            cache.Setup(c => c.SetAsync(It.IsAny <string>(), It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>())).Returns(Task.FromResult(true));
            cache.Setup(c => c.GetAsync(method + url)).ReturnsAsync(default(byte[]));
            var client = new HttpClient(new RedisCacheFallbackHandler(testMessageHandler, TimeSpan.FromDays(1), cacheTime, cache.Object));

            // execute
            await client.SendAsync(new HttpRequestMessage(method, url));

            // validate
            cache.Verify(c => c.SetAsync(It.IsAny <string>(), It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>()), Times.Never);
        }
        public async Task Always_calls_the_http_handler(HttpMethod method)
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache = new Mock <IDistributedCache>(MockBehavior.Strict);

            cache.Setup(c => c.SetAsync(RedisCacheFallbackHandler.CacheFallbackKeyPrefix + method + url, It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>())).Returns(Task.FromResult(true));
            var client = new HttpClient(new RedisCacheFallbackHandler(testMessageHandler, TimeSpan.FromDays(1), TimeSpan.FromDays(1), cache.Object));

            // execute twice
            await client.SendAsync(new HttpRequestMessage(method, url));

            cache.Verify(c => c.SetAsync(RedisCacheFallbackHandler.CacheFallbackKeyPrefix + method + url, It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>()), Times.Once); // ensure it's cached before the 2nd call
            await client.SendAsync(new HttpRequestMessage(method, url));

            // validate
            testMessageHandler.NumberOfCalls.Should().Be(2);
        }
        public void Ignores_set_cache_exceptions()
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache = new Mock<IDistributedCache>(MockBehavior.Strict);
            cache.Setup(c => c.GetAsync("http://unittest/")).ReturnsAsync(null);
            cache.Setup(c => c.SetAsync("http://unittest/", It.IsAny<byte[]>(), It.IsAny<DistributedCacheEntryOptions>())).Throws<Exception>();
            var client = new HttpClient(new RedisCacheHandler(testMessageHandler, new Dictionary<HttpStatusCode, TimeSpan>(), cache.Object));

            // execute twice
            Func<Task<HttpResponseMessage>> func = async () => await client.GetAsync("http://unittest");
            func.ShouldNotThrow();

            // validate
            testMessageHandler.NumberOfCalls.Should().Be(1);
            cache.Verify(c => c.GetAsync("http://unittest/"), Times.Once);
            cache.Verify(c => c.SetAsync("http://unittest/", It.IsAny<byte[]>(), It.IsAny<DistributedCacheEntryOptions>()), Times.Once);
        }
        public async Task Always_updates_the_cache_on_success(HttpMethod method)
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache     = new Mock <IDistributedCache>(MockBehavior.Strict);
            var cacheTime = TimeSpan.FromSeconds(123);

            cache.Setup(c => c.SetAsync(method + url, It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>())).Returns(Task.FromResult(true));
            var client = new HttpClient(new RedisCacheFallbackHandler(testMessageHandler, TimeSpan.FromDays(1), cacheTime, cache.Object));

            // execute twice, validate cache is called each time
            await client.SendAsync(new HttpRequestMessage(method, url));

            cache.Verify(c => c.SetAsync(RedisCacheFallbackHandler.CacheFallbackKeyPrefix + method + url, It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>()), Times.Once);
            await client.SendAsync(new HttpRequestMessage(method, url));

            cache.Verify(c => c.SetAsync(RedisCacheFallbackHandler.CacheFallbackKeyPrefix + method + url, It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>()), Times.Exactly(2));
        }
예제 #9
0
        public async Task Caches_per_url_and_method(HttpMethod method)
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache = new Mock <IDistributedCache>(MockBehavior.Strict);

            cache.Setup(c => c.GetAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())).ReturnsAsync(default(byte[]));
            cache.Setup(c => c.SetAsync(It.IsAny <string>(), It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(true));
            var client = new HttpClient(new RedisCacheHandler(testMessageHandler, new Dictionary <HttpStatusCode, TimeSpan>(), cache.Object));

            // execute for different URLs
            await client.SendAsync(new HttpRequestMessage(method, "http://unittest1"));

            await client.SendAsync(new HttpRequestMessage(method, "http://unittest2"));

            // validate
            testMessageHandler.NumberOfCalls.Should().Be(2);
            cache.Verify(c => c.SetAsync(It.IsAny <string>(), It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
        }
예제 #10
0
        public async Task Gets_the_data_again_after_entry_is_gone_from_cache(HttpMethod method)
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache = new Mock <IDistributedCache>(MockBehavior.Strict);

            cache.Setup(c => c.GetAsync("http://unittest/", It.IsAny <CancellationToken>())).ReturnsAsync(default(byte[]));
            cache.Setup(c => c.SetAsync("http://unittest/", It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>(), It.IsAny <CancellationToken>())).Returns(Task.CompletedTask);
            var client = new HttpClient(new RedisCacheHandler(testMessageHandler, new Dictionary <HttpStatusCode, TimeSpan>(), cache.Object));

            // execute twice
            await client.SendAsync(new HttpRequestMessage(method, "http://unittest"));

            await client.SendAsync(new HttpRequestMessage(method, "http://unittest"));

            // validate
            testMessageHandler.NumberOfCalls.Should().Be(2);
            cache.Verify(c => c.GetAsync(method + "http://unittest/", It.IsAny <CancellationToken>()), Times.Exactly(2));
        }
        public async Task Caches_the_result()
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache = new Mock<IDistributedCache>(MockBehavior.Strict);
            cache.Setup(c => c.GetAsync("http://unittest/")).ReturnsAsync(null);
            cache.Setup(c => c.SetAsync("http://unittest/", It.IsAny<byte[]>(), It.IsAny<DistributedCacheEntryOptions>())).Returns(Task.FromResult(true));
            var client = new HttpClient(new RedisCacheHandler(testMessageHandler, new Dictionary<HttpStatusCode, TimeSpan>(), cache.Object));

            // execute twice
            await client.GetAsync("http://unittest");
            cache.Setup(c => c.GetAsync("http://unittest/")).ReturnsAsync(new SerializableCacheData(new byte[0], new HttpResponseMessage(HttpStatusCode.OK)).Serialize());
            await client.GetAsync("http://unittest");

            // validate
            testMessageHandler.NumberOfCalls.Should().Be(1);
            cache.Verify(c => c.GetAsync("http://unittest/"), Times.Exactly(2));
            cache.Verify(c => c.SetAsync("http://unittest/", It.IsAny<byte[]>(), It.IsAny<DistributedCacheEntryOptions>()), Times.Once);
        }
예제 #12
0
        public void Gets_the_underlying_data_on_get_error()
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache = new Mock <IDistributedCache>(MockBehavior.Strict);

            cache.Setup(c => c.GetAsync(HttpMethod.Get + "http://unittest/")).ThrowsAsync(new Exception("unittest"));
            cache.Setup(c => c.SetAsync(HttpMethod.Get + "http://unittest/", It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>())).Returns(Task.FromResult(true));
            var client = new HttpClient(new RedisCacheHandler(testMessageHandler, new Dictionary <HttpStatusCode, TimeSpan>(), cache.Object));

            // execute
            Func <Task <HttpResponseMessage> > func = async() => await client.GetAsync("http://unittest");

            func.ShouldNotThrow();

            // validate
            testMessageHandler.NumberOfCalls.Should().Be(1);
            cache.Verify(c => c.GetAsync(HttpMethod.Get + "http://unittest/"), Times.Once);
            cache.Verify(c => c.SetAsync(HttpMethod.Get + "http://unittest/", It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>()), Times.Once);
        }
        public void Ignores_set_cache_exceptions()
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache = new Mock <IDistributedCache>(MockBehavior.Strict);

            cache.Setup(c => c.GetAsync(HttpMethod.Get + "http://unittest/", default(CancellationToken))).ReturnsAsync(default(byte[]));
            cache.Setup(c => c.SetAsync(HttpMethod.Get + "http://unittest/", It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>(), It.IsAny <CancellationToken>())).Throws <Exception>();
            var client = new HttpClient(new RedisCacheHandler(testMessageHandler, new Dictionary <HttpStatusCode, TimeSpan>(), cache.Object));

            // execute twice
            Func <Task <HttpResponseMessage> > func = async() => await client.GetAsync("http://unittest");

            func.ShouldNotThrow();

            // validate
            testMessageHandler.NumberOfCalls.Should().Be(1);
            cache.Verify(c => c.GetAsync(HttpMethod.Get + "http://unittest/", It.IsAny <CancellationToken>()), Times.Once);
            cache.Verify(c => c.SetAsync(HttpMethod.Get + "http://unittest/", It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>(), It.IsAny <CancellationToken>()), Times.Once);
        }
예제 #14
0
        public async Task Caches_the_result(HttpMethod method)
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache = new Mock <IDistributedCache>(MockBehavior.Strict);

            cache.Setup(c => c.GetAsync(method + "http://unittest/", It.IsAny <CancellationToken>())).ReturnsAsync(default(byte[]));
            cache.Setup(c => c.SetAsync(method + "http://unittest/", It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>(), It.IsAny <CancellationToken>())).Returns(Task.CompletedTask);
            var client = new HttpClient(new RedisCacheHandler(testMessageHandler, new Dictionary <HttpStatusCode, TimeSpan>(), cache.Object));

            // execute twice
            await client.SendAsync(new HttpRequestMessage(method, "http://unittest"));

            cache.Setup(c => c.GetAsync(method + "http://unittest/", It.IsAny <CancellationToken>())).ReturnsAsync(() => new CacheData(new byte[0], new HttpResponseMessage(HttpStatusCode.OK), null, null).Serialize());
            await client.SendAsync(new HttpRequestMessage(method, "http://unittest"));

            // validate
            testMessageHandler.NumberOfCalls.Should().Be(1);
            cache.Verify(c => c.GetAsync(method + "http://unittest/", It.IsAny <CancellationToken>()), Times.Exactly(2));
            cache.Verify(c => c.SetAsync(method + "http://unittest/", It.IsAny <byte[]>(), It.IsAny <DistributedCacheEntryOptions>(), It.IsAny <CancellationToken>()), Times.Once);
        }
예제 #15
0
        public async Task Only_caches_get_and_head_results()
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var client             = new HttpClient(new RedisCacheHandler(testMessageHandler, new Dictionary <HttpStatusCode, TimeSpan>(), (IDistributedCache)null));

            // execute twice for different methods
            await client.PostAsync("http://unittest", new StringContent(string.Empty));

            await client.PostAsync("http://unittest", new StringContent(string.Empty));

            await client.PutAsync("http://unittest", new StringContent(string.Empty));

            await client.PutAsync("http://unittest", new StringContent(string.Empty));

            await client.DeleteAsync("http://unittest");

            await client.DeleteAsync("http://unittest");

            // validate
            testMessageHandler.NumberOfCalls.Should().Be(6);
        }
예제 #16
0
        public void Invalidates_cache_per_method()
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache   = new Mock <IDistributedCache>(MockBehavior.Strict);
            var url     = "http://unittest/";
            var getKey  = HttpMethod.Get + url;
            var headKey = HttpMethod.Head + url;

            cache.Setup(c => c.RemoveAsync(headKey, default(CancellationToken))).Returns(Task.FromResult(true));
            cache.Setup(c => c.RemoveAsync(getKey, default(CancellationToken))).Throws <Exception>();

            var cacheExpirationPerStatusCode = new Dictionary <HttpStatusCode, TimeSpan> {
                { (HttpStatusCode)200, TimeSpan.FromHours(1) }
            };
            var handler = new RedisCacheHandler(testMessageHandler, cacheExpirationPerStatusCode, cache.Object);

            // execute
            Func <Task> func = async() => await handler.InvalidateCache(new Uri(url), HttpMethod.Head);

            // validate
            func.ShouldNotThrow();
            cache.Verify(c => c.RemoveAsync(headKey, default(CancellationToken)), Times.Once);
        }
        public async Task Data_from_call_matches_data_from_cache()
        {
            // setup
            var testMessageHandler = new TestMessageHandler();
            var cache = new Mock<IDistributedCache>(MockBehavior.Strict);
            cache.Setup(c => c.GetAsync(It.IsAny<string>())).ReturnsAsync(new SerializableCacheData(Encoding.UTF8.GetBytes(TestMessageHandler.DefaultContent), new HttpResponseMessage(HttpStatusCode.OK)).Serialize());
            cache.Setup(c => c.SetAsync(It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<DistributedCacheEntryOptions>())).Returns(Task.FromResult(true));
            var client = new HttpClient(new RedisCacheHandler(testMessageHandler, new Dictionary<HttpStatusCode, TimeSpan>(), cache.Object));

            // execute twice for different methods
            var originalResult = await client.GetAsync("http://unittest");
            var cachedResult = await client.GetAsync("http://unittest");
            var originalResultString = await originalResult.Content.ReadAsStringAsync();
            var cachedResultString = await cachedResult.Content.ReadAsStringAsync();

            // validate
            originalResultString.ShouldBeEquivalentTo(cachedResultString);
            originalResultString.ShouldBeEquivalentTo(TestMessageHandler.DefaultContent);
        }