net-helpers.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import { expect } from 'chai';
  2. import * as dns from 'node:dns';
  3. import * as http from 'node:http';
  4. import { Socket } from 'node:net';
  5. import { defer, listen } from './spec-helpers';
  6. // See https://github.com/nodejs/node/issues/40702.
  7. dns.setDefaultResultOrder('ipv4first');
  8. export const kOneKiloByte = 1024;
  9. export const kOneMegaByte = kOneKiloByte * kOneKiloByte;
  10. export function randomBuffer (size: number, start: number = 0, end: number = 255) {
  11. const range = 1 + end - start;
  12. const buffer = Buffer.allocUnsafe(size);
  13. for (let i = 0; i < size; ++i) {
  14. buffer[i] = start + Math.floor(Math.random() * range);
  15. }
  16. return buffer;
  17. }
  18. export function randomString (length: number) {
  19. const buffer = randomBuffer(length, '0'.charCodeAt(0), 'z'.charCodeAt(0));
  20. return buffer.toString();
  21. }
  22. export async function getResponse (urlRequest: Electron.ClientRequest) {
  23. return new Promise<Electron.IncomingMessage>((resolve, reject) => {
  24. urlRequest.on('error', reject);
  25. urlRequest.on('abort', reject);
  26. urlRequest.on('response', (response) => resolve(response));
  27. urlRequest.end();
  28. });
  29. }
  30. export async function collectStreamBody (response: Electron.IncomingMessage | http.IncomingMessage) {
  31. return (await collectStreamBodyBuffer(response)).toString();
  32. }
  33. export function collectStreamBodyBuffer (response: Electron.IncomingMessage | http.IncomingMessage) {
  34. return new Promise<Buffer>((resolve, reject) => {
  35. response.on('error', reject);
  36. (response as NodeJS.EventEmitter).on('aborted', reject);
  37. const data: Buffer[] = [];
  38. response.on('data', (chunk) => data.push(chunk));
  39. response.on('end', (chunk?: Buffer) => {
  40. if (chunk) data.push(chunk);
  41. resolve(Buffer.concat(data));
  42. });
  43. });
  44. }
  45. export async function respondNTimes (fn: http.RequestListener, n: number): Promise<string> {
  46. const server = http.createServer((request, response) => {
  47. fn(request, response);
  48. // don't close if a redirect was returned
  49. if ((response.statusCode < 300 || response.statusCode >= 399) && n <= 0) {
  50. n--;
  51. server.close();
  52. }
  53. });
  54. const sockets: Socket[] = [];
  55. server.on('connection', s => sockets.push(s));
  56. defer(() => {
  57. server.close();
  58. for (const socket of sockets) {
  59. socket.destroy();
  60. }
  61. });
  62. return (await listen(server)).url;
  63. }
  64. export function respondOnce (fn: http.RequestListener) {
  65. return respondNTimes(fn, 1);
  66. }
  67. respondNTimes.routeFailure = false;
  68. respondNTimes.toRoutes = (routes: Record<string, http.RequestListener>, n: number) => {
  69. return respondNTimes((request, response) => {
  70. if (Object.hasOwn(routes, request.url || '')) {
  71. (async () => {
  72. await Promise.resolve(routes[request.url || ''](request, response));
  73. })().catch((err) => {
  74. respondNTimes.routeFailure = true;
  75. console.error('Route handler failed, this is probably why your test failed', err);
  76. response.statusCode = 500;
  77. response.end();
  78. });
  79. } else {
  80. response.statusCode = 500;
  81. response.end();
  82. expect.fail(`Unexpected URL: ${request.url}`);
  83. }
  84. }, n);
  85. };
  86. respondOnce.toRoutes = (routes: Record<string, http.RequestListener>) => respondNTimes.toRoutes(routes, 1);
  87. respondNTimes.toURL = (url: string, fn: http.RequestListener, n: number) => {
  88. return respondNTimes.toRoutes({ [url]: fn }, n);
  89. };
  90. respondOnce.toURL = (url: string, fn: http.RequestListener) => respondNTimes.toURL(url, fn, 1);
  91. respondNTimes.toSingleURL = (fn: http.RequestListener, n: number) => {
  92. const requestUrl = '/requestUrl';
  93. return respondNTimes.toURL(requestUrl, fn, n).then(url => `${url}${requestUrl}`);
  94. };
  95. respondOnce.toSingleURL = (fn: http.RequestListener) => respondNTimes.toSingleURL(fn, 1);