|
1 | 1 | import type * as events from '@/events';
|
2 | 2 | import type QUICStream from '@/QUICStream';
|
3 | 3 | import type { Crypto, Host, Port } from '@';
|
| 4 | +import type { TlsConfig } from '@/config'; |
4 | 5 | import { fc, testProp } from '@fast-check/jest';
|
5 | 6 | import Logger, { formatting, LogLevel, StreamHandler } from '@matrixai/logger';
|
6 | 7 | import QUICServer from '@/QUICServer';
|
@@ -133,7 +134,7 @@ describe('Concurrency tests', () => {
|
133 | 134 | fc.array(streamArb, { size: 'small', minLength }).noShrink();
|
134 | 135 | const connectionArb = fc
|
135 | 136 | .record({
|
136 |
| - streams: streamsArb(), |
| 137 | + streams: streamsArb(1), |
137 | 138 | startDelay: fc.integer({ min: 0, max: 50 }),
|
138 | 139 | endDelay: fc.integer({ min: 0, max: 50 }),
|
139 | 140 | })
|
@@ -257,7 +258,7 @@ describe('Concurrency tests', () => {
|
257 | 258 | },
|
258 | 259 | { numRuns: 3 },
|
259 | 260 | );
|
260 |
| - testProp.only( |
| 261 | + testProp( |
261 | 262 | 'Multiple clients sharing a socket',
|
262 | 263 | [tlsConfigWithCaArb, connectionsArb, streamsArb(3)],
|
263 | 264 | async (tlsConfigProm, clientDatas, serverStreams) => {
|
@@ -376,8 +377,216 @@ describe('Concurrency tests', () => {
|
376 | 377 | )}`,
|
377 | 378 | );
|
378 | 379 | }
|
| 380 | + await socket.stop(); |
379 | 381 | logger.info('TEST FULLY DONE!');
|
380 | 382 | },
|
381 | 383 | { numRuns: 3 },
|
382 | 384 | );
|
| 385 | + const spawnServer = async ({ |
| 386 | + socket, |
| 387 | + port, |
| 388 | + cleanUpHoldProm, |
| 389 | + tlsConfig, |
| 390 | + serverStreams, |
| 391 | + }: { |
| 392 | + socket: QUICSocket | undefined; |
| 393 | + port: Port | undefined; |
| 394 | + cleanUpHoldProm: Promise<void>; |
| 395 | + tlsConfig: TlsConfig; |
| 396 | + serverStreams: Array<StreamData>; |
| 397 | + }) => { |
| 398 | + const server = new QUICServer({ |
| 399 | + crypto, |
| 400 | + socket, |
| 401 | + logger: logger.getChild(QUICServer.name), |
| 402 | + config: { |
| 403 | + tlsConfig: tlsConfig, |
| 404 | + verifyPeer: false, |
| 405 | + }, |
| 406 | + }); |
| 407 | + const connProms: Array<Promise<void>> = []; |
| 408 | + server.addEventListener( |
| 409 | + 'connection', |
| 410 | + async (e: events.QUICServerConnectionEvent) => { |
| 411 | + const conn = e.detail; |
| 412 | + const connProm = (async () => { |
| 413 | + const serverStreamProms: Array<Promise<void>> = []; |
| 414 | + conn.addEventListener( |
| 415 | + 'stream', |
| 416 | + (streamEvent: events.QUICConnectionStreamEvent) => { |
| 417 | + const stream = streamEvent.detail; |
| 418 | + const streamData = |
| 419 | + serverStreams[serverStreamProms.length % serverStreams.length]; |
| 420 | + serverStreamProms.push(handleStreamProm(stream, streamData)); |
| 421 | + }, |
| 422 | + ); |
| 423 | + try { |
| 424 | + await cleanUpHoldProm; |
| 425 | + await Promise.race([ |
| 426 | + Promise.all(serverStreamProms), |
| 427 | + sleep(1000).then(() => { |
| 428 | + throw Error('Streams hanging'); |
| 429 | + }), |
| 430 | + ]); |
| 431 | + } finally { |
| 432 | + await conn.destroy({ force: true }); |
| 433 | + logger.info( |
| 434 | + `server conn result ${JSON.stringify( |
| 435 | + await Promise.allSettled(serverStreamProms), |
| 436 | + )}`, |
| 437 | + ); |
| 438 | + } |
| 439 | + })(); |
| 440 | + connProms.push(connProm); |
| 441 | + }, |
| 442 | + ); |
| 443 | + await sleep(100); |
| 444 | + await server.start({ |
| 445 | + host: '127.0.0.1' as Host, |
| 446 | + port, |
| 447 | + }); |
| 448 | + try { |
| 449 | + await cleanUpHoldProm; |
| 450 | + await Promise.all(connProms); |
| 451 | + } finally { |
| 452 | + await server.stop({ force: true }); |
| 453 | + logger.info( |
| 454 | + `server result ${JSON.stringify(await Promise.allSettled(connProms))}`, |
| 455 | + ); |
| 456 | + } |
| 457 | + }; |
| 458 | + jest.setTimeout(100000); |
| 459 | + testProp.only( |
| 460 | + 'Multiple clients sharing a socket with a server', |
| 461 | + [ |
| 462 | + tlsConfigWithCaArb, |
| 463 | + tlsConfigWithCaArb, |
| 464 | + connectionsArb, |
| 465 | + connectionsArb, |
| 466 | + streamsArb(3), |
| 467 | + streamsArb(3), |
| 468 | + ], |
| 469 | + async ( |
| 470 | + tlsConfigProm1, |
| 471 | + tlsConfigProm2, |
| 472 | + clientDatas1, |
| 473 | + clientDatas2, |
| 474 | + serverStreams1, |
| 475 | + serverStreams2, |
| 476 | + ) => { |
| 477 | + const tlsConfig1 = await tlsConfigProm1; |
| 478 | + const tlsConfig2 = await tlsConfigProm2; |
| 479 | + const cleanUpHoldProm = promise<void>(); |
| 480 | + // Creating socket |
| 481 | + const socket1 = new QUICSocket({ |
| 482 | + crypto, |
| 483 | + logger: logger.getChild('socket'), |
| 484 | + }); |
| 485 | + const socket2 = new QUICSocket({ |
| 486 | + crypto, |
| 487 | + logger: logger.getChild('socket'), |
| 488 | + }); |
| 489 | + await socket1.start({ |
| 490 | + host: '127.0.0.1' as Host, |
| 491 | + }); |
| 492 | + await socket2.start({ |
| 493 | + host: '127.0.0.1' as Host, |
| 494 | + }); |
| 495 | + |
| 496 | + const serverProm1 = spawnServer({ |
| 497 | + cleanUpHoldProm: cleanUpHoldProm.p, |
| 498 | + port: undefined, |
| 499 | + serverStreams: serverStreams1, |
| 500 | + socket: socket1, |
| 501 | + tlsConfig: tlsConfig1.tlsConfig, |
| 502 | + }); |
| 503 | + const serverProm2 = spawnServer({ |
| 504 | + cleanUpHoldProm: cleanUpHoldProm.p, |
| 505 | + port: undefined, |
| 506 | + serverStreams: serverStreams2, |
| 507 | + socket: socket2, |
| 508 | + tlsConfig: tlsConfig2.tlsConfig, |
| 509 | + }); |
| 510 | + |
| 511 | + // Creating client activity |
| 512 | + logger.info('STARTING CLIENTS'); |
| 513 | + const clientProms1: Array<Promise<void>> = []; |
| 514 | + const clientProms2: Array<Promise<void>> = []; |
| 515 | + for (const clientData of clientDatas1) { |
| 516 | + const clientProm = sleep(clientData.startDelay) |
| 517 | + .then(() => { |
| 518 | + logger.info('STARTING CLIENT'); |
| 519 | + return QUICClient.createQUICClient({ |
| 520 | + host: '127.0.0.1' as Host, |
| 521 | + port: socket2.port, |
| 522 | + socket: socket1, |
| 523 | + crypto, |
| 524 | + logger: logger.getChild(QUICClient.name), |
| 525 | + config: { |
| 526 | + verifyPeer: false, |
| 527 | + }, |
| 528 | + }); |
| 529 | + }) |
| 530 | + .then((client) => { |
| 531 | + return handleClientProm(client, clientData); |
| 532 | + }); |
| 533 | + clientProms1.push(clientProm); |
| 534 | + } |
| 535 | + for (const clientData of clientDatas2) { |
| 536 | + const clientProm = sleep(clientData.startDelay) |
| 537 | + .then(() => { |
| 538 | + logger.info('STARTING CLIENT'); |
| 539 | + return QUICClient.createQUICClient({ |
| 540 | + host: '127.0.0.1' as Host, |
| 541 | + port: socket1.port, |
| 542 | + socket: socket2, |
| 543 | + crypto, |
| 544 | + logger: logger.getChild(QUICClient.name), |
| 545 | + config: { |
| 546 | + verifyPeer: false, |
| 547 | + }, |
| 548 | + }); |
| 549 | + }) |
| 550 | + .then((client) => { |
| 551 | + return handleClientProm(client, clientData); |
| 552 | + }); |
| 553 | + clientProms2.push(clientProm); |
| 554 | + } |
| 555 | + // Wait for running activity to finish, should complete without error |
| 556 | + logger.info('STARTING TEST'); |
| 557 | + try { |
| 558 | + await (async () => { |
| 559 | + await Promise.all([ |
| 560 | + Promise.all(clientProms1), |
| 561 | + Promise.all(clientProms2), |
| 562 | + ]); |
| 563 | + // Allow for streams to be negotiated |
| 564 | + await sleep(200); |
| 565 | + cleanUpHoldProm.resolveP(); |
| 566 | + await serverProm1; |
| 567 | + await serverProm2; |
| 568 | + })(); |
| 569 | + } catch (e) { |
| 570 | + logger.error(`test failed with ${e.message}`); |
| 571 | + throw e; |
| 572 | + } finally { |
| 573 | + logger.info('STARTING TEST FINALLY'); |
| 574 | + cleanUpHoldProm.resolveP(); |
| 575 | + logger.info( |
| 576 | + `test result ${JSON.stringify( |
| 577 | + await Promise.allSettled([ |
| 578 | + ...clientProms1, |
| 579 | + ...clientProms2, |
| 580 | + serverProm1, |
| 581 | + serverProm2, |
| 582 | + ]), |
| 583 | + )}`, |
| 584 | + ); |
| 585 | + } |
| 586 | + await socket1.stop(); |
| 587 | + await socket2.stop(); |
| 588 | + logger.info('TEST FULLY DONE!'); |
| 589 | + }, |
| 590 | + { numRuns: 1 }, |
| 591 | + ); |
383 | 592 | });
|
0 commit comments