From 8105a272d2e79ca70119fadd01dd3b1c4160aa79 Mon Sep 17 00:00:00 2001 From: Chris R Date: Thu, 1 Sep 2016 10:17:42 -0700 Subject: [PATCH] #210 Re-enable caching tests --- .../ResponseCachingTests.cs | 26 ++++-- .../ResponseCachingTests.cs | 81 +++++++++++++------ 2 files changed, 73 insertions(+), 34 deletions(-) diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs index 0075622980..6c63806476 100644 --- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs @@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests { httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -27,7 +28,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_JustPublic_NotCached() { var requestCount = 1; @@ -37,6 +38,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public"; + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -45,7 +47,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_MaxAge_Cached() { var requestCount = 1; @@ -55,6 +57,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, max-age=10"; + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -63,7 +66,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SMaxAge_Cached() { var requestCount = 1; @@ -73,6 +76,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, s-maxage=10"; + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -81,7 +85,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SMaxAgeAndMaxAge_SMaxAgePreferredCached() { var requestCount = 1; @@ -91,6 +95,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, max-age=0, s-maxage=10"; + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -99,7 +104,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_Expires_Cached() { var requestCount = 1; @@ -110,6 +115,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public"; httpContext.Response.Headers["Expires"] = (DateTime.UtcNow + TimeSpan.FromSeconds(10)).ToString("r"); + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -118,7 +124,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Theory(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Theory] [InlineData("Set-cookie")] [InlineData("vary")] [InlineData("pragma")] @@ -132,6 +138,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, max-age=10"; httpContext.Response.Headers[headerName] = "headerValue"; + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -153,6 +160,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public"; httpContext.Response.Headers["Expires"] = expiresValue; + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -161,7 +169,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_ExpiresWithoutPublic_NotCached() { var requestCount = 1; @@ -171,6 +179,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.ContentType = "some/thing"; // Http.Sys requires content-type for caching httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Expires"] = (DateTime.UtcNow + TimeSpan.FromSeconds(10)).ToString("r"); + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { @@ -179,7 +188,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_MaxAgeAndExpires_MaxAgePreferred() { var requestCount = 1; @@ -190,6 +199,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests httpContext.Response.Headers["x-request-count"] = (requestCount++).ToString(); httpContext.Response.Headers["Cache-Control"] = "public, max-age=10"; httpContext.Response.Headers["Expires"] = (DateTime.UtcNow - TimeSpan.FromSeconds(10)).ToString("r"); // In the past + httpContext.Response.ContentLength = 10; return httpContext.Response.Body.WriteAsync(new byte[10], 0, 10); })) { diff --git a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs index 63bf4e3537..5a062f878d 100644 --- a/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs +++ b/test/Microsoft.Net.Http.Server.FunctionalTests/ResponseCachingTests.cs @@ -56,7 +56,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SetTtlWithContentType_Cached() { string address; @@ -83,7 +83,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] // Http.Sys does not set the optional Age header for cached content. // http://tools.ietf.org/html/rfc7234#section-5.1 public async Task Caching_CheckAge_NotSentWithCachedContent() @@ -114,7 +114,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] // Http.Sys does not update the optional Age header for cached content. // http://tools.ietf.org/html/rfc7234#section-5.1 public async Task Caching_SetAge_AgeHeaderCachedAndNotUpdated() @@ -250,7 +250,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SetTtlHuge_Cached() { string address; @@ -277,7 +277,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SetTtlAndWriteBody_Cached() { string address; @@ -288,21 +288,50 @@ namespace Microsoft.Net.Http.Server var context = await server.AcceptAsync(); context.Response.Headers["x-request-count"] = "1"; context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.ContentLength = 10; context.Response.CacheTtl = TimeSpan.FromSeconds(10); context.Response.Body.Write(new byte[10], 0, 10); + context.Dispose(); + + var response = await responseTask; + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + + // Send a second request and make sure we get the same response (without listening for one on the server). + response = await SendRequestAsync(address); + Assert.Equal(200, (int)response.StatusCode); + Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); + } + } + + [Fact] + public async Task Caching_SetTtlAndWriteAsyncBody_Cached() + { + string address; + using (var server = Utilities.CreateHttpServer(out address)) + { + var responseTask = SendRequestAsync(address); + + var context = await server.AcceptAsync(); + context.Response.Headers["x-request-count"] = "1"; + context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache + context.Response.ContentLength = 10; + context.Response.CacheTtl = TimeSpan.FromSeconds(10); await context.Response.Body.WriteAsync(new byte[10], 0, 10); context.Dispose(); var response = await responseTask; Assert.Equal(200, (int)response.StatusCode); Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); - Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); // Send a second request and make sure we get the same response (without listening for one on the server). response = await SendRequestAsync(address); Assert.Equal(200, (int)response.StatusCode); Assert.Equal("1", response.Headers.GetValues("x-request-count").FirstOrDefault()); - Assert.Equal(new byte[20], await response.Content.ReadAsByteArrayAsync()); + Assert.Equal(new byte[10], await response.Content.ReadAsByteArrayAsync()); } } @@ -373,7 +402,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_WriteFullContentLength_Cached() { string address; @@ -435,7 +464,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SendFileWithFullContentLength_Cached() { string address; @@ -464,19 +493,20 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SetTtlAndStatusCode_Cached() { string address; using (var server = Utilities.CreateHttpServer(out address)) { - // Http.Sys will cache any status code. + // Http.Sys will cache almost any status code. for (int status = 200; status < 600; status++) { - // 407 (Proxy Authentication Required) makes CoreCLR's HttpClient throw - if (status == 407) + switch (status) { - continue; + case 206: // 206 (Partial Content) is not cached + case 407: // 407 (Proxy Authentication Required) makes CoreCLR's HttpClient throw + continue; } var responseTask = SendRequestAsync(address + status); @@ -561,7 +591,7 @@ namespace Microsoft.Net.Http.Server // RFC violation. http://tools.ietf.org/html/rfc7234#section-4.4 // "A cache MUST invalidate the effective Request URI ... when a non-error status code // is received in response to an unsafe request method." - [Theory(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Theory] // See HTTP_VERB for known verbs [InlineData("HEAD")] [InlineData("UNKNOWN")] @@ -628,7 +658,7 @@ namespace Microsoft.Net.Http.Server // RFC violation / implementation limiation, Vary is not respected. // http://tools.ietf.org/html/rfc7234#section-4.1 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_SetVary_NotRespected() { string address; @@ -729,7 +759,7 @@ namespace Microsoft.Net.Http.Server // Responses can be cached for requests with Pragma: no-cache. // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestPragmaNoCache_Cached() { string address; @@ -758,7 +788,7 @@ namespace Microsoft.Net.Http.Server // RFC violation, Requests with Pragma: no-cache should not be served from cache. // http://tools.ietf.org/html/rfc7234#section-5.4 // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestPragmaNoCache_NotRespectedAndServedFromCache() { string address; @@ -786,7 +816,7 @@ namespace Microsoft.Net.Http.Server // Responses can be cached for requests with cache-control: no-cache. // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestCacheControlNoCache_Cached() { string address; @@ -814,7 +844,7 @@ namespace Microsoft.Net.Http.Server // RFC violation, Requests with Cache-Control: no-cache should not be served from cache. // http://tools.ietf.org/html/rfc7234#section-5.2.1.4 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestCacheControlNoCache_NotRespectedAndServedFromCache() { string address; @@ -842,7 +872,7 @@ namespace Microsoft.Net.Http.Server // RFC violation // http://tools.ietf.org/html/rfc7234#section-5.2.1.1 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestCacheControlMaxAgeZero_NotRespectedAndServedFromCache() { string address; @@ -870,7 +900,7 @@ namespace Microsoft.Net.Http.Server // RFC violation // http://tools.ietf.org/html/rfc7234#section-5.2.1.3 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestCacheControlMinFreshOutOfRange_NotRespectedAndServedFromCache() { string address; @@ -941,8 +971,7 @@ namespace Microsoft.Net.Http.Server } // http://tools.ietf.org/html/rfc7233#section-4.1 - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR, SkipReason = "Cached response contains duplicate Content-Length headers (#167).")] + [Fact] public async Task Caching_RequestRangeFromCache_RangeServedFromCache() { string address; @@ -972,7 +1001,7 @@ namespace Microsoft.Net.Http.Server } // http://tools.ietf.org/html/rfc7233#section-4.1 - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestMultipleRangesFromCache_RangesServedFromCache() { string address; @@ -1032,7 +1061,7 @@ namespace Microsoft.Net.Http.Server } } - [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")] + [Fact] public async Task Caching_RequestMultipleRangesFromCachedFile_ServedFromCache() { string address;