GeezerVison is showing github.com — tests: start adding quic test server utilities · nodejs/node@8d97dee
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: deps/ngtcp2/ngtcp2.gyp +20-38Lines changed: 20 additions & 38 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 268 | 268 | 'HAVE_CONFIG_H', | 269 | 269 | 'WITH_EXAMPLE_OSSL', | 270 | 270 | 'EV_STANDALONE=1', | | 271 | + 'HAVE_UNISTD_H', | | 272 | + 'HAVE_ARPA_INET_H', | | 273 | + 'HAVE_NETINET_IN_H', | | 274 | + 'HAVE_NETINET_IP_H', | 271 | 275 | ], | 272 | 276 | 'conditions': [ | | 277 | + ['OS=="aix" or OS=="win"', { | | 278 | + # AIX does not support some of the networking features used in | | 279 | + # the test server. Windows also lacks the Unix-specific headers | | 280 | + # and system calls required by the ngtcp2 examples. | | 281 | + 'type': 'none', # Disable as executable on AIX and Windows | | 282 | + }], | 273 | 283 | ['OS=="mac"', { | 274 | 284 | 'defines': [ | 275 | 285 | '__APPLE_USE_RFC_3542', | | 283 | 293 | 'libraries': [ '-lsocket', '-lnsl' ], | 284 | 294 | }, | 285 | 295 | }], | 286 | | - ['OS=="win"', { | 287 | | - 'defines': [ | 288 | | - 'WIN32', | 289 | | - '_WINDOWS', | 290 | | - ], | 291 | | - 'msvs_settings': { | 292 | | - 'VCCLCompilerTool': { | 293 | | - 'CompileAs': '1' | 294 | | - }, | 295 | | - }, | 296 | | - }], | 297 | | - ['OS!="win"', { | 298 | | - 'defines': [ | 299 | | - 'HAVE_UNISTD_H', | 300 | | - 'HAVE_ARPA_INET_H', | 301 | | - 'HAVE_NETINET_IN_H', | 302 | | - 'HAVE_NETINET_IP_H', | 303 | | - ], | 304 | | - }], | 305 | 296 | [ 'OS=="linux" or OS=="openharmony"', { | 306 | 297 | 'link_settings': { | 307 | 298 | 'libraries': [ '-ldl', '-lrt' ], | | 335 | 326 | 'HAVE_CONFIG_H', | 336 | 327 | 'WITH_EXAMPLE_OSSL', | 337 | 328 | 'EV_STANDALONE=1', | | 329 | + 'HAVE_UNISTD_H', | | 330 | + 'HAVE_ARPA_INET_H', | | 331 | + 'HAVE_NETINET_IN_H', | | 332 | + 'HAVE_NETINET_IP_H', | 338 | 333 | ], | 339 | 334 | 'conditions': [ | | 335 | + ['OS=="aix" or OS=="win"', { | | 336 | + # AIX does not support some of the networking features used in | | 337 | + # the test client. Windows also lacks the Unix-specific headers | | 338 | + # and system calls required by the ngtcp2 examples. | | 339 | + 'type': 'none', # Disable as executable on AIX and Windows | | 340 | + }], | 340 | 341 | ['OS=="mac"', { | 341 | 342 | 'defines': [ | 342 | 343 | '__APPLE_USE_RFC_3542', | | 350 | 351 | 'libraries': [ '-lsocket', '-lnsl' ], | 351 | 352 | }, | 352 | 353 | }], | 353 | | - ['OS=="win"', { | 354 | | - 'defines': [ | 355 | | - 'WIN32', | 356 | | - '_WINDOWS', | 357 | | - ], | 358 | | - 'msvs_settings': { | 359 | | - 'VCCLCompilerTool': { | 360 | | - 'CompileAs': '1' | 361 | | - }, | 362 | | - }, | 363 | | - }], | 364 | | - ['OS!="win"', { | 365 | | - 'defines': [ | 366 | | - 'HAVE_UNISTD_H', | 367 | | - 'HAVE_ARPA_INET_H', | 368 | | - 'HAVE_NETINET_IN_H', | 369 | | - 'HAVE_NETINET_IP_H', | 370 | | - ], | 371 | | - }], | 372 | 354 | [ 'OS=="linux" or OS=="openharmony"', { | 373 | 355 | 'link_settings': { | 374 | 356 | 'libraries': [ '-ldl', '-lrt' ], | |
Collapse file Copy file name to clipboard +64Lines changed: 64 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +import { resolve } from 'node:path'; | | 2 | +import { spawn } from 'node:child_process'; | | 3 | + | | 4 | +export default class QuicTestClient { | | 5 | + #pathToClient; | | 6 | + #runningProcess; | | 7 | + | | 8 | + constructor() { | | 9 | + this.#pathToClient = resolve(process.execPath, '../ngtcp2_test_client'); | | 10 | + console.log(this.#pathToClient); | | 11 | + } | | 12 | + | | 13 | + help(options = { stdio: 'inherit' }) { | | 14 | + const { promise, resolve, reject } = Promise.withResolvers(); | | 15 | + const proc = spawn(this.#pathToClient, ['--help'], options); | | 16 | + proc.on('error', reject); | | 17 | + proc.on('exit', (code, signal) => { | | 18 | + if (code === 0) { | | 19 | + resolve(); | | 20 | + } else { | | 21 | + reject(new Error(`Process exited with code ${code} and signal ${signal}`)); | | 22 | + } | | 23 | + }); | | 24 | + return promise; | | 25 | + } | | 26 | + | | 27 | + run(address, port, uri, options = { stdio: 'inherit' }) { | | 28 | + const { promise, resolve, reject } = Promise.withResolvers(); | | 29 | + if (this.#runningProcess) { | | 30 | + reject(new Error('Server is already running')); | | 31 | + return promise; | | 32 | + } | | 33 | + const args = [ | | 34 | + address, | | 35 | + port, | | 36 | + uri ?? '', | | 37 | + ]; | | 38 | + this.#runningProcess = spawn(this.#pathToClient, args, options); | | 39 | + this.#runningProcess.on('error', (err) => { | | 40 | + this.#runningProcess = undefined; | | 41 | + reject(err); | | 42 | + }); | | 43 | + this.#runningProcess.on('exit', (code, signal) => { | | 44 | + if (code === 0) { | | 45 | + resolve(); | | 46 | + } else { | | 47 | + if (code === null && signal === 'SIGTERM') { | | 48 | + // Normal termination due to stop() being called. | | 49 | + resolve(); | | 50 | + return; | | 51 | + } | | 52 | + reject(new Error(`Process exited with code ${code} and signal ${signal}`)); | | 53 | + } | | 54 | + }); | | 55 | + return promise; | | 56 | + } | | 57 | + | | 58 | + stop() { | | 59 | + if (this.#runningProcess) { | | 60 | + this.#runningProcess.kill(); | | 61 | + this.#runningProcess = undefined; | | 62 | + } | | 63 | + } | | 64 | +}; |
Collapse file Copy file name to clipboard +66Lines changed: 66 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +import { resolve } from 'node:path'; | | 2 | +import { spawn } from 'node:child_process'; | | 3 | + | | 4 | +export default class QuicTestServer { | | 5 | + #pathToServer; | | 6 | + #runningProcess; | | 7 | + | | 8 | + constructor() { | | 9 | + this.#pathToServer = resolve(process.execPath, '../ngtcp2_test_server'); | | 10 | + console.log(this.#pathToServer); | | 11 | + } | | 12 | + | | 13 | + help(options = { stdio: 'inherit' }) { | | 14 | + const { promise, resolve, reject } = Promise.withResolvers(); | | 15 | + const proc = spawn(this.#pathToServer, ['--help'], options); | | 16 | + proc.on('error', reject); | | 17 | + proc.on('exit', (code, signal) => { | | 18 | + if (code === 0) { | | 19 | + resolve(); | | 20 | + } else { | | 21 | + reject(new Error(`Process exited with code ${code} and signal ${signal}`)); | | 22 | + } | | 23 | + }); | | 24 | + return promise; | | 25 | + } | | 26 | + | | 27 | + run(address, port, keyFile, certFile, options = { stdio: 'inherit' }) { | | 28 | + const { promise, resolve, reject } = Promise.withResolvers(); | | 29 | + if (this.#runningProcess) { | | 30 | + reject(new Error('Server is already running')); | | 31 | + return promise; | | 32 | + } | | 33 | + const args = [ | | 34 | + address, | | 35 | + port, | | 36 | + keyFile, | | 37 | + certFile, | | 38 | + ]; | | 39 | + this.#runningProcess = spawn(this.#pathToServer, args, options); | | 40 | + this.#runningProcess.on('error', (err) => { | | 41 | + this.#runningProcess = undefined; | | 42 | + reject(err); | | 43 | + }); | | 44 | + this.#runningProcess.on('exit', (code, signal) => { | | 45 | + this.#runningProcess = undefined; | | 46 | + if (code === 0) { | | 47 | + resolve(); | | 48 | + } else { | | 49 | + if (code === null && signal === 'SIGTERM') { | | 50 | + // Normal termination due to stop() being called. | | 51 | + resolve(); | | 52 | + return; | | 53 | + } | | 54 | + reject(new Error(`Process exited with code ${code} and signal ${signal}`)); | | 55 | + } | | 56 | + }); | | 57 | + return promise; | | 58 | + } | | 59 | + | | 60 | + stop() { | | 61 | + if (this.#runningProcess) { | | 62 | + this.#runningProcess.kill(); | | 63 | + this.#runningProcess = undefined; | | 64 | + } | | 65 | + } | | 66 | +}; |
Collapse file Copy file name to clipboard +32Lines changed: 32 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +// Flags: --experimental-quic | | 2 | +import { hasQuic, isAIX, isWindows, skip } from '../common/index.mjs'; | | 3 | +import { rejects } from 'node:assert'; | | 4 | + | | 5 | +if (!hasQuic) { | | 6 | + skip('QUIC support is not enabled'); | | 7 | +} | | 8 | +if (isAIX) { | | 9 | + // AIX does not support some of the networking features used in the ngtcp2 | | 10 | + // example server and client. | | 11 | + skip('QUIC third-party tests are disabled on AIX'); | | 12 | +} | | 13 | +if (isWindows) { | | 14 | + // Windows does not support the [Li/U]nix specific headers and system calls | | 15 | + // required by the ngtcp2 example server/client. | | 16 | + skip('QUIC third-party tests are disabled on Windows'); | | 17 | +} | | 18 | + | | 19 | +const { default: QuicTestClient } = await import('../common/quic/test-client.mjs'); | | 20 | + | | 21 | +const client = new QuicTestClient(); | | 22 | + | | 23 | +// If this completes without throwing, the test passes. | | 24 | +await client.help({ stdio: 'ignore' }); | | 25 | + | | 26 | +setTimeout(() => { | | 27 | + client.stop(); | | 28 | +}, 100); | | 29 | + | | 30 | +// We expect this to fail since there's no server running. | | 31 | +await rejects(client.run('localhost', '12345', undefined, { stdio: 'ignore' }), | | 32 | + { message: /Process exited with code 1 and signal null/ }); |
Collapse file Copy file name to clipboard +34Lines changed: 34 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +// Flags: --experimental-quic | | 2 | +import { hasQuic, isAIX, isWindows, skip } from '../common/index.mjs'; | | 3 | + | | 4 | +if (!hasQuic) { | | 5 | + skip('QUIC support is not enabled'); | | 6 | +} | | 7 | +if (isAIX) { | | 8 | + // AIX does not support some of the networking features used in the ngtcp2 | | 9 | + // example server and client. | | 10 | + skip('QUIC third-party tests are disabled on AIX'); | | 11 | +} | | 12 | +if (isWindows) { | | 13 | + // Windows does not support the [Li/U]nix specific headers and system calls | | 14 | + // required by the ngtcp2 example server/client. | | 15 | + skip('QUIC third-party tests are disabled on Windows'); | | 16 | +} | | 17 | + | | 18 | +const { default: QuicTestServer } = await import('../common/quic/test-server.mjs'); | | 19 | +const fixtures = await import('../common/fixtures.mjs'); | | 20 | + | | 21 | +const server = new QuicTestServer(); | | 22 | +const fixturesPath = fixtures.path(); | | 23 | + | | 24 | +// If this completes without throwing, the test passes. | | 25 | +await server.help({ stdio: 'ignore' }); | | 26 | + | | 27 | +setTimeout(() => { | | 28 | + server.stop(); | | 29 | +}, 100); | | 30 | + | | 31 | +await server.run('localhost', '12345', | | 32 | + `${fixturesPath}/keys/agent1-key.pem`, | | 33 | + `${fixturesPath}/keys/agent1-cert.pem`, | | 34 | + { stdio: 'inherit' }); |
|