Add some more node tests

This commit is contained in:
Jarred Sumner
2024-10-10 16:48:01 -07:00
parent 9593dcde98
commit b7e06a979a
5 changed files with 314 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
//#FILE: test-http-hex-write.js
//#SHA1: 77a5322a8fe08e8505f39d42614167d223c9fbb0
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const http = require("http");
const expectedResponse = "hex\nutf8\n";
test("HTTP server writes hex and utf8", async () => {
const server = http.createServer((req, res) => {
res.setHeader("content-length", expectedResponse.length);
res.write("6865780a", "hex");
res.write("utf8\n");
res.end();
server.close();
});
await new Promise(resolve => {
server.listen(0, () => {
const port = server.address().port;
http
.request({ port })
.on("response", res => {
let data = "";
res.setEncoding("ascii");
res.on("data", chunk => {
data += chunk;
});
res.on("end", () => {
expect(data).toBe(expectedResponse);
resolve();
});
})
.end();
});
});
});
//<#END_FILE: test-http-hex-write.js

View File

@@ -0,0 +1,99 @@
//#FILE: test-http-keepalive-request.js
//#SHA1: 31cc9b875e1ead9a0b98fb07b672b536f6d06fba
//-----------------
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
"use strict";
const http = require("http");
let serverSocket = null;
let clientSocket = null;
const expectRequests = 10;
let actualRequests = 0;
const server = http.createServer((req, res) => {
// They should all come in on the same server socket.
if (serverSocket) {
expect(req.socket).toBe(serverSocket);
} else {
serverSocket = req.socket;
}
res.end(req.url);
});
const agent = new http.Agent({ keepAlive: true });
function makeRequest(n) {
return new Promise(resolve => {
if (n === 0) {
server.close();
agent.destroy();
resolve();
return;
}
const req = http.request({
port: server.address().port,
path: `/${n}`,
agent: agent,
});
req.end();
req.on("socket", sock => {
if (clientSocket) {
expect(sock).toBe(clientSocket);
} else {
clientSocket = sock;
}
});
req.on("response", res => {
let data = "";
res.setEncoding("utf8");
res.on("data", c => {
data += c;
});
res.on("end", () => {
expect(data).toBe(`/${n}`);
setTimeout(() => {
actualRequests++;
resolve(makeRequest(n - 1));
}, 1);
});
});
});
}
test("HTTP keep-alive requests", async () => {
await new Promise(resolve => {
server.listen(0, () => {
resolve(makeRequest(expectRequests));
});
});
expect(actualRequests).toBe(expectRequests);
});
//<#END_FILE: test-http-keepalive-request.js

View File

@@ -0,0 +1,50 @@
//#FILE: test-http-pipeline-requests-connection-leak.js
//#SHA1: fc3e33a724cc7a499c7716fe8af6b78e7f72e943
//-----------------
"use strict";
const http = require("http");
const net = require("net");
const big = Buffer.alloc(16 * 1024, "A");
const COUNT = 1e4;
test("HTTP pipeline requests do not cause connection leak", done => {
let client;
const server = http.createServer((req, res) => {
res.end(big, () => {
countdown.dec();
});
});
const countdown = new Countdown(COUNT, () => {
server.close();
client.end();
done();
});
server.listen(0, () => {
const req = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".repeat(COUNT);
client = net.connect(server.address().port, () => {
client.write(req);
});
client.resume();
});
});
class Countdown {
constructor(count, callback) {
this.count = count;
this.callback = callback;
}
dec() {
this.count--;
if (this.count === 0) {
this.callback();
}
}
}
//<#END_FILE: test-http-pipeline-requests-connection-leak.js

View File

@@ -0,0 +1,75 @@
//#FILE: test-http-readable-data-event.js
//#SHA1: a094638e155550b5bc5ecdf5b11c54e8124d1dc1
//-----------------
"use strict";
const http = require("http");
const helloWorld = "Hello World!";
const helloAgainLater = "Hello again later!";
let next = null;
test("HTTP readable data event", async () => {
const server = http.createServer((req, res) => {
res.writeHead(200, {
"Content-Length": `${helloWorld.length + helloAgainLater.length}`,
});
// We need to make sure the data is flushed
// before writing again
next = () => {
res.end(helloAgainLater);
next = () => {};
};
res.write(helloWorld);
});
await new Promise(resolve => server.listen(0, resolve));
const opts = {
hostname: "localhost",
port: server.address().port,
path: "/",
};
const expectedData = [helloWorld, helloAgainLater];
const expectedRead = [helloWorld, null, helloAgainLater, null, null];
await new Promise((resolve, reject) => {
const req = http.request(opts, res => {
res.on("error", reject);
const readableSpy = jest.fn();
res.on("readable", readableSpy);
res.on("readable", () => {
let data;
do {
data = res.read();
expect(data).toBe(expectedRead.shift());
next();
} while (data !== null);
});
res.setEncoding("utf8");
const dataSpy = jest.fn();
res.on("data", dataSpy);
res.on("data", data => {
expect(data).toBe(expectedData.shift());
});
res.on("end", () => {
expect(readableSpy).toHaveBeenCalledTimes(3);
expect(dataSpy).toHaveBeenCalledTimes(2);
server.close(() => resolve());
});
});
req.end();
});
});
//<#END_FILE: test-http-readable-data-event.js

View File

@@ -0,0 +1,30 @@
//#FILE: test-http-response-remove-header-after-sent.js
//#SHA1: df9a9a2f545c88b70d6d33252a1568339ea6f5b3
//-----------------
"use strict";
const http = require("http");
test("remove header after response is sent", done => {
const server = http.createServer((req, res) => {
res.removeHeader("header1", 1);
res.write("abc");
expect(() => res.removeHeader("header2", 2)).toThrow(
expect.objectContaining({
code: "ERR_HTTP_HEADERS_SENT",
name: "Error",
message: expect.any(String),
}),
);
res.end();
});
server.listen(0, () => {
http.get({ port: server.address().port }, () => {
server.close();
done();
});
});
});
//<#END_FILE: test-http-response-remove-header-after-sent.js