Skip to content

Commit d432f02

Browse files
authored
Network tests refactor (#1031)
* Some progress * More progress * Some compression code * Feature complete * Set Content-Length * CodeFactor
1 parent a11fa94 commit d432f02

14 files changed

+456
-179
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using System.IO;
3+
using System.IO.Compression;
4+
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.Http;
6+
7+
namespace PuppeteerSharp.TestServer
8+
{
9+
internal class SimpleCompressionMiddleware
10+
{
11+
private readonly RequestDelegate _next;
12+
private readonly SimpleServer _server;
13+
14+
public SimpleCompressionMiddleware(RequestDelegate next, SimpleServer server)
15+
{
16+
_next = next;
17+
_server = server;
18+
}
19+
20+
public async Task Invoke(HttpContext context)
21+
{
22+
if (!_server.GzipRoutes.Contains(context.Request.Path))
23+
{
24+
await _next(context);
25+
}
26+
27+
var response = context.Response.Body;
28+
var bodyWrapperStream = new MemoryStream();
29+
context.Response.Body = bodyWrapperStream;
30+
31+
await _next(context);
32+
using (var stream = new MemoryStream())
33+
{
34+
using (var compressionStream = new GZipStream(stream, CompressionMode.Compress, true))
35+
{
36+
bodyWrapperStream.Position = 0;
37+
bodyWrapperStream.CopyTo(compressionStream);
38+
}
39+
40+
context.Response.Headers["Content-Encoding"] = "gzip";
41+
context.Response.Headers["Content-Length"] = stream.Length.ToString();
42+
stream.Position = 0;
43+
stream.CopyTo(response);
44+
context.Response.Body = response;
45+
}
46+
}
47+
}
48+
}

lib/PuppeteerSharp.TestServer/SimpleServer.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public class SimpleServer
2020
private readonly IDictionary<string, string> _csp;
2121
private readonly IWebHost _webHost;
2222

23+
internal IList<string> GzipRoutes { get; }
2324
public static SimpleServer Create(int port, string contentRoot) => new SimpleServer(port, contentRoot, isHttps: false);
2425
public static SimpleServer CreateHttps(int port, string contentRoot) => new SimpleServer(port, contentRoot, isHttps: true);
2526

@@ -29,6 +30,8 @@ public SimpleServer(int port, string contentRoot, bool isHttps)
2930
_routes = new ConcurrentDictionary<string, RequestDelegate>();
3031
_auths = new ConcurrentDictionary<string, (string username, string password)>();
3132
_csp = new ConcurrentDictionary<string, string>();
33+
GzipRoutes = new List<string>();
34+
3235
_webHost = new WebHostBuilder()
3336
.ConfigureAppConfiguration((context, builder) => builder
3437
.SetBasePath(context.HostingEnvironment.ContentRootPath)
@@ -50,13 +53,15 @@ public SimpleServer(int port, string contentRoot, bool isHttps)
5053
{
5154
return handler(context);
5255
}
56+
5357
return next();
5458
})
59+
.UseMiddleware<SimpleCompressionMiddleware>(this)
5560
.UseStaticFiles(new StaticFileOptions
5661
{
5762
OnPrepareResponse = fileResponseContext =>
5863
{
59-
if(_csp.TryGetValue(fileResponseContext.Context.Request.Path, out var csp))
64+
if (_csp.TryGetValue(fileResponseContext.Context.Request.Path, out var csp))
6065
{
6166
fileResponseContext.Context.Response.Headers["Content-Security-Policy"] = csp;
6267
}
@@ -95,13 +100,16 @@ public void Reset()
95100
_routes.Clear();
96101
_auths.Clear();
97102
_csp.Clear();
103+
GzipRoutes.Clear();
98104
foreach (var subscriber in _requestSubscribers.Values)
99105
{
100106
subscriber(null);
101107
}
102108
_requestSubscribers.Clear();
103109
}
104110

111+
public void EnableGzip(string path) => GzipRoutes.Add(path);
112+
105113
public void SetRoute(string path, RequestDelegate handler) => _routes.Add(path, handler);
106114

107115
public void SetRedirect(string from, string to) => SetRoute(from, context =>

lib/PuppeteerSharp.Tests/NetworkTests/NetworkEventTests.cs

Lines changed: 0 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -52,125 +52,6 @@ public async Task PageEventsResponse()
5252
Assert.Equal(TestConstants.Port, remoteAddress.Port);
5353
}
5454

55-
[Fact]
56-
public async Task ResponseStatusText()
57-
{
58-
Server.SetRoute("/cool", (context) =>
59-
{
60-
context.Response.StatusCode = 200;
61-
//There are some debates about this on these issues
62-
//https://github.com/aspnet/HttpAbstractions/issues/395
63-
//https://github.com/aspnet/HttpAbstractions/issues/486
64-
//https://github.com/aspnet/HttpAbstractions/issues/794
65-
context.Features.Get<IHttpResponseFeature>().ReasonPhrase = "cool!";
66-
return Task.CompletedTask;
67-
});
68-
var response = await Page.GoToAsync(TestConstants.ServerUrl + "/cool");
69-
Assert.Equal("cool!", response.StatusText);
70-
}
71-
72-
[Fact]
73-
public async Task ResponseFromCache()
74-
{
75-
var responses = new Dictionary<string, Response>();
76-
Page.Response += (sender, e) => responses[e.Response.Url.Split('/').Last()] = e.Response;
77-
await Page.GoToAsync(TestConstants.ServerUrl + "/cached/one-style.html");
78-
await Page.ReloadAsync();
79-
80-
Assert.Equal(2, responses.Count);
81-
Assert.Equal(HttpStatusCode.NotModified, responses["one-style.html"].Status);
82-
Assert.False(responses["one-style.html"].FromCache);
83-
Assert.Equal(HttpStatusCode.OK, responses["one-style.css"].Status);
84-
Assert.True(responses["one-style.css"].FromCache);
85-
}
86-
87-
[Fact]
88-
public async Task ResponseFromServiceWorker()
89-
{
90-
var responses = new Dictionary<string, Response>();
91-
Page.Response += (sender, e) => responses[e.Response.Url.Split('/').Last()] = e.Response;
92-
await Page.GoToAsync(TestConstants.ServerUrl + "/serviceworkers/fetch/sw.html",
93-
waitUntil: new[] { WaitUntilNavigation.Networkidle2 });
94-
await Page.EvaluateFunctionAsync("async () => await window.activationPromise");
95-
await Page.ReloadAsync();
96-
97-
Assert.Equal(2, responses.Count);
98-
Assert.Equal(HttpStatusCode.OK, responses["sw.html"].Status);
99-
Assert.True(responses["sw.html"].FromServiceWorker);
100-
Assert.Equal(HttpStatusCode.OK, responses["style.css"].Status);
101-
Assert.True(responses["style.css"].FromServiceWorker);
102-
}
103-
104-
[Fact]
105-
public async Task PageEventsResponseShouldProvideBody()
106-
{
107-
Response response = null;
108-
Page.Response += (sender, e) => response = e.Response;
109-
await Page.GoToAsync(TestConstants.ServerUrl + "/simple.json");
110-
Assert.NotNull(response);
111-
var responseText = await new HttpClient().GetStringAsync(TestConstants.ServerUrl + "/simple.json");
112-
Assert.Equal(responseText, await response.TextAsync());
113-
Assert.Equal(JObject.Parse(responseText), await response.JsonAsync());
114-
}
115-
116-
[Fact]
117-
public async Task PageEventsResponseShouldThrowWhenRequestingBodyOfRedirectedResponse()
118-
{
119-
Server.SetRedirect("/foo.html", "/empty.html");
120-
var response = await Page.GoToAsync(TestConstants.ServerUrl + "/foo.html");
121-
var redirectChain = response.Request.RedirectChain;
122-
Assert.Single(redirectChain);
123-
var redirected = redirectChain[0].Response;
124-
Assert.Equal(HttpStatusCode.Redirect, redirected.Status);
125-
126-
var exception = await Assert.ThrowsAsync<PuppeteerException>(async () => await redirected.TextAsync());
127-
Assert.Contains("Response body is unavailable for redirect responses", exception.Message);
128-
}
129-
130-
[Fact]
131-
public async Task PageEventsResponseShouldNotReportBodyUnlessRequestIsFinished()
132-
{
133-
await Page.GoToAsync(TestConstants.EmptyPage);
134-
// Setup server to trap request.
135-
var serverResponseCompletion = new TaskCompletionSource<bool>();
136-
HttpResponse serverResponse = null;
137-
Server.SetRoute("/get", context =>
138-
{
139-
serverResponse = context.Response;
140-
context.Response.WriteAsync("hello ");
141-
return serverResponseCompletion.Task;
142-
});
143-
// Setup page to trap response.
144-
Response pageResponse = null;
145-
var requestFinished = false;
146-
Page.Response += (sender, e) => pageResponse = e.Response;
147-
Page.RequestFinished += (sender, e) => requestFinished = true;
148-
// send request and wait for server response
149-
Task WaitForPageResponseEvent()
150-
{
151-
var completion = new TaskCompletionSource<bool>();
152-
Page.Response += (sender, e) => completion.SetResult(true);
153-
return completion.Task;
154-
}
155-
await Task.WhenAll(
156-
Page.EvaluateExpressionAsync("fetch('/get', { method: 'GET'})"),
157-
WaitForPageResponseEvent()
158-
);
159-
160-
Assert.NotNull(serverResponse);
161-
Assert.NotNull(pageResponse);
162-
Assert.Equal(HttpStatusCode.OK, pageResponse.Status);
163-
Assert.False(requestFinished);
164-
165-
var responseText = pageResponse.TextAsync();
166-
// Write part of the response and wait for it to be flushed.
167-
await serverResponse.WriteAsync("wor");
168-
// Finish response.
169-
await serverResponse.WriteAsync("ld!");
170-
serverResponseCompletion.SetResult(true);
171-
Assert.Equal("hello world!", await responseText);
172-
}
173-
17455
[Fact]
17556
public async Task PageEventsRequestFailed()
17657
{

lib/PuppeteerSharp.Tests/PageTests/AuthenticateTests.cs renamed to lib/PuppeteerSharp.Tests/NetworkTests/PageAuthenticateTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
using Xunit;
44
using Xunit.Abstractions;
55

6-
namespace PuppeteerSharp.Tests.PageTests
6+
namespace PuppeteerSharp.Tests.NetworkTests
77
{
88
[Collection("PuppeteerLoaderFixture collection")]
9-
public class AuthenticateTests : PuppeteerPageBaseTest
9+
public class PageAuthenticateTests : PuppeteerPageBaseTest
1010
{
11-
public AuthenticateTests(ITestOutputHelper output) : base(output)
11+
public PageAuthenticateTests(ITestOutputHelper output) : base(output)
1212
{
1313
}
1414

lib/PuppeteerSharp.Tests/PageTests/SetExtraHttpHeadersTests.cs renamed to lib/PuppeteerSharp.Tests/NetworkTests/PageSetExtraHttpHeadersTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
using Xunit;
44
using Xunit.Abstractions;
55

6-
namespace PuppeteerSharp.Tests.PageTests
6+
namespace PuppeteerSharp.Tests.NetworkTests
77
{
88
[Collection("PuppeteerLoaderFixture collection")]
9-
public class SetExtraHttpHeadersTests : PuppeteerPageBaseTest
9+
public class PageSetExtraHttpHeadersTests : PuppeteerPageBaseTest
1010
{
11-
public SetExtraHttpHeadersTests(ITestOutputHelper output) : base(output)
11+
public PageSetExtraHttpHeadersTests(ITestOutputHelper output) : base(output)
1212
{
1313
}
1414

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
using Microsoft.AspNetCore.Http;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Net;
7+
using System.Net.Http;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
using Xunit;
11+
using Xunit.Abstractions;
12+
using PuppeteerSharp.Helpers;
13+
14+
namespace PuppeteerSharp.Tests.NetworkTests
15+
{
16+
[Collection("PuppeteerLoaderFixture collection")]
17+
public class RequestContinueTests : PuppeteerPageBaseTest
18+
{
19+
public RequestContinueTests(ITestOutputHelper output) : base(output)
20+
{
21+
}
22+
23+
[Fact]
24+
public async Task ShouldWork()
25+
{
26+
await Page.SetRequestInterceptionAsync(true);
27+
Page.Request += async (sender, e) => await e.Request.ContinueAsync();
28+
await Page.GoToAsync(TestConstants.EmptyPage);
29+
}
30+
31+
[Fact]
32+
public async Task ShouldAmendHTTPHeaders()
33+
{
34+
await Page.SetRequestInterceptionAsync(true);
35+
Page.Request += async (sender, e) =>
36+
{
37+
var headers = new Dictionary<string, string>(e.Request.Headers)
38+
{
39+
["FOO"] = "bar"
40+
};
41+
await e.Request.ContinueAsync(new Payload { Headers = headers });
42+
};
43+
await Page.GoToAsync(TestConstants.EmptyPage);
44+
var requestTask = Server.WaitForRequest("/sleep.zzz", request => request.Headers["foo"].ToString());
45+
await Task.WhenAll(
46+
requestTask,
47+
Page.EvaluateExpressionAsync("fetch('/sleep.zzz')")
48+
);
49+
Assert.Equal("bar", requestTask.Result);
50+
}
51+
52+
[Fact]
53+
public async Task ShouldRedirectInAWayNonObservableToPage()
54+
{
55+
await Page.SetRequestInterceptionAsync(true);
56+
Page.Request += async (sender, e) =>
57+
{
58+
var redirectURL = e.Request.Url.Contains("/empty.html")
59+
? TestConstants.ServerUrl + "/consolelog.html" :
60+
null;
61+
await e.Request.ContinueAsync(new Payload { Url = redirectURL });
62+
};
63+
string consoleMessage = null;
64+
Page.Console += (sender, e) => consoleMessage = e.Message.Text;
65+
await Page.GoToAsync(TestConstants.EmptyPage);
66+
Assert.Equal(TestConstants.EmptyPage, Page.Url);
67+
Assert.Equal("yellow", consoleMessage);
68+
}
69+
70+
[Fact]
71+
public async Task ShouldAmendMethodData()
72+
{
73+
await Page.GoToAsync(TestConstants.EmptyPage);
74+
await Page.SetRequestInterceptionAsync(true);
75+
Page.Request += async (sender, e) =>
76+
{
77+
await e.Request.ContinueAsync(new Payload { Method = HttpMethod.Post });
78+
};
79+
80+
var requestTask = Server.WaitForRequest<string>("/sleep.zzz", request => request.Method);
81+
82+
await Task.WhenAll(
83+
requestTask,
84+
Page.EvaluateExpressionAsync("fetch('/sleep.zzz')")
85+
);
86+
87+
Assert.Equal("POST", requestTask.Result);
88+
}
89+
90+
[Fact]
91+
public async Task ShouldAmendPostData()
92+
{
93+
await Page.SetRequestInterceptionAsync(true);
94+
Page.Request += async (sender, e) =>
95+
{
96+
await e.Request.ContinueAsync(new Payload
97+
{
98+
Method = HttpMethod.Post,
99+
PostData = "FooBar"
100+
});
101+
};
102+
var requestTask = Server.WaitForRequest("/sleep.zzz", async request =>
103+
{
104+
using (var reader = new StreamReader(request.Body, Encoding.UTF8))
105+
{
106+
return await reader.ReadToEndAsync();
107+
}
108+
});
109+
110+
await Task.WhenAll(
111+
requestTask,
112+
Page.GoToAsync(TestConstants.ServerUrl + "/sleep.zzz")
113+
);
114+
115+
Assert.Equal("FooBar", await requestTask.Result);
116+
}
117+
}
118+
}

lib/PuppeteerSharp.Tests/RequestTests/RespondTests.cs renamed to lib/PuppeteerSharp.Tests/NetworkTests/RequestRespondTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
using Xunit;
66
using Xunit.Abstractions;
77

8-
namespace PuppeteerSharp.Tests.RequestTests
8+
namespace PuppeteerSharp.Tests.NetworkTests
99
{
1010
[Collection("PuppeteerLoaderFixture collection")]
11-
public class RespondTests : PuppeteerPageBaseTest
11+
public class RequestRespondTests : PuppeteerPageBaseTest
1212
{
13-
public RespondTests(ITestOutputHelper output) : base(output)
13+
public RequestRespondTests(ITestOutputHelper output) : base(output)
1414
{
1515
}
1616

0 commit comments

Comments
 (0)