@nsshunt/ststestrunner 1.1.13 → 1.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -57,24 +57,25 @@ var TestCaseFhirBase = class {
57
57
  return new https.Agent(options);
58
58
  }
59
59
  });
60
+ const agentManager = createAgentManager({
61
+ agentOptions: {
62
+ keepAlive: true,
63
+ maxFreeSockets: 10,
64
+ maxSockets: 10,
65
+ maxTotalSockets: 20,
66
+ timeout: 6e4,
67
+ rejectUnauthorized: false
68
+ },
69
+ httpAgentFactory(options) {
70
+ return new http.Agent(options);
71
+ },
72
+ httpsAgentFactory(options) {
73
+ return new https.Agent(options);
74
+ }
75
+ });
60
76
  this.authUtilsNode = new AuthUtilsNode({
61
77
  logger: defaultLogger,
62
- agentManager: createAgentManager({
63
- agentOptions: {
64
- keepAlive: true,
65
- maxFreeSockets: 10,
66
- maxSockets: 10,
67
- maxTotalSockets: 20,
68
- timeout: 6e4,
69
- rejectUnauthorized: false
70
- },
71
- httpAgentFactory(options) {
72
- return new http.Agent(options);
73
- },
74
- httpsAgentFactory(options) {
75
- return new https.Agent(options);
76
- }
77
- })
78
+ agentManager
78
79
  });
79
80
  }
80
81
  get runnerExecutionWorker() {
@@ -1334,11 +1335,837 @@ var TestCaseFhir10 = class extends TestCaseFhirQueryBase {
1334
1335
  };
1335
1336
  };
1336
1337
  //#endregion
1338
+ //#region src/libmodule/testCase01.ts
1339
+ /**
1340
+ * Concrete synthetic test runner implementation.
1341
+ *
1342
+ * This runner:
1343
+ * - simulates work
1344
+ * - updates telemetry counters
1345
+ * - batches telemetry publishing
1346
+ * - emits lifecycle log messages
1347
+ */
1348
+ var TestCase01 = class {
1349
+ /**
1350
+ * The live serialisable runner model/state owned by this test runner.
1351
+ *
1352
+ * This object is mutated as telemetry and execution progress change.
1353
+ */
1354
+ #runner;
1355
+ /**
1356
+ * Owning worker-side execution host.
1357
+ *
1358
+ * Used primarily to publish telemetry back to the manager by runner id.
1359
+ */
1360
+ #runnerExecutionWorker;
1361
+ /**
1362
+ * Per-runner state used for animated/indented generated log messages.
1363
+ */
1364
+ #logMessageDataSet = {};
1365
+ /**
1366
+ * Timeout handle used to perform delayed telemetry publication.
1367
+ *
1368
+ * This supports the "publish on timeout if buffer threshold is not reached"
1369
+ * batching strategy.
1370
+ */
1371
+ #publishTelemetryTimeout = null;
1372
+ /**
1373
+ * Counter of buffered telemetry publication events since the last publish.
1374
+ *
1375
+ * When this reaches `#maxBufferSize`, telemetry is published immediately.
1376
+ */
1377
+ #publishTelemetryCount = 0;
1378
+ /**
1379
+ * Maximum number of telemetry buffer events allowed before forcing a publish.
1380
+ *
1381
+ * This is intended to remain lower than the logging/instrument buffer size
1382
+ * used elsewhere in the observability stack.
1383
+ */
1384
+ #maxBufferSize = 50;
1385
+ /**
1386
+ * Maximum time in milliseconds to wait before publishing buffered telemetry.
1387
+ *
1388
+ * Telemetry publish strategy:
1389
+ * - whichever happens first wins:
1390
+ * - max buffer count reached
1391
+ * - timeout reached
1392
+ */
1393
+ #publishTelemetryTimeoutVal = 1e3;
1394
+ /**
1395
+ * Construct a new synthetic test runner.
1396
+ *
1397
+ * @param runnerExecutionWorker Owning worker-side execution host.
1398
+ * @param runner Live runner model/state for this test runner.
1399
+ */
1400
+ constructor(runnerExecutionWorker, runner) {
1401
+ this.#runnerExecutionWorker = runnerExecutionWorker;
1402
+ this.#runner = runner;
1403
+ }
1404
+ /**
1405
+ * Internal low-level log sink used by this test case.
1406
+ *
1407
+ * Currently disabled/commented out to avoid noisy console output during tests.
1408
+ *
1409
+ * @param message Message to output.
1410
+ */
1411
+ #LogMessage = (message) => {};
1412
+ /**
1413
+ * Generate an animated indented log message for the runner.
1414
+ *
1415
+ * Behaviour:
1416
+ * - lazily initialises per-runner indentation state
1417
+ * - creates a message with varying indentation
1418
+ * - appends that message to runner telemetry messages
1419
+ * - updates indentation direction when bounds are reached
1420
+ *
1421
+ * Indentation behaviour:
1422
+ * - increases from 0 upward
1423
+ * - reverses direction after passing 20
1424
+ * - reverses again when returning to 0
1425
+ *
1426
+ * This exists purely to generate visually changing test log output.
1427
+ *
1428
+ * @param runner Runner whose message should be generated.
1429
+ * @param iteration Current runner iteration number.
1430
+ */
1431
+ #GenLogMessage = (runner, iteration) => {
1432
+ if (!this.#logMessageDataSet[runner.id]) this.#logMessageDataSet[runner.id] = {
1433
+ adder: 1,
1434
+ indent: 0
1435
+ };
1436
+ const logMessageData = this.#logMessageDataSet[runner.id];
1437
+ const message = `${" ".repeat(logMessageData.indent)} [${runner.id}] >> Hello World << ${iteration}`;
1438
+ this.#LogMessage(message);
1439
+ runner.instrumentData.message.push(message);
1440
+ logMessageData.indent += logMessageData.adder;
1441
+ if (logMessageData.indent > 20) logMessageData.adder = -1;
1442
+ else if (logMessageData.indent === 0) logMessageData.adder = 1;
1443
+ };
1444
+ /**
1445
+ * Ensure a timeout-based telemetry publish is scheduled.
1446
+ *
1447
+ * Behaviour:
1448
+ * - if no publish timeout exists, creates one
1449
+ * - when the timeout fires:
1450
+ * - publishes telemetry
1451
+ * - resets buffered publish count
1452
+ * - clears the timeout handle
1453
+ *
1454
+ * In Node.js the timer is `unref()`'d so it does not keep the process alive.
1455
+ */
1456
+ #SetupTimeout = async () => {
1457
+ if (!this.#publishTelemetryTimeout) {
1458
+ this.#publishTelemetryTimeout = setTimeout(async () => {
1459
+ this.#LogMessage(chalk.yellow(` PublishTelemetryData - Normal Behaviour (**** TIMEOUT ****) `));
1460
+ await this.#PublishTelemetryData();
1461
+ this.#publishTelemetryCount = 0;
1462
+ this.#publishTelemetryTimeout = null;
1463
+ }, this.#publishTelemetryTimeoutVal);
1464
+ if (isNode) this.#publishTelemetryTimeout.unref();
1465
+ }
1466
+ };
1467
+ /**
1468
+ * Publish the current runner telemetry snapshot immediately.
1469
+ *
1470
+ * Behaviour:
1471
+ * - asks the owning worker execution host to post telemetry for this runner
1472
+ * - writes a separator line to the local log sink
1473
+ * - resets selected per-cycle telemetry fields ready for the next publish window
1474
+ * - yields immediately before returning
1475
+ *
1476
+ * Telemetry fields reset after publish:
1477
+ * - `velocity`
1478
+ * - `message`
1479
+ * - `tx`
1480
+ * - `rx`
1481
+ *
1482
+ * Notes:
1483
+ * - not all telemetry fields are reset here; only those intended to behave
1484
+ * as per-publish-window accumulators
1485
+ */
1486
+ #PublishTelemetryData = async () => {
1487
+ this.#runnerExecutionWorker.PostTelemetryById(this.#runner.id);
1488
+ this.#LogMessage(chalk.red(`------------------------------------------------------------------------------------------------------------`));
1489
+ this.#runner.instrumentData.velocity = 0;
1490
+ this.#runner.instrumentData.message = [];
1491
+ this.#runner.instrumentData.tx = 0;
1492
+ this.#runner.instrumentData.rx = 0;
1493
+ await this.SleepImmediate();
1494
+ };
1495
+ /**
1496
+ * Force an immediate telemetry publish regardless of current buffer count.
1497
+ *
1498
+ * Used for important lifecycle transitions such as:
1499
+ * - start
1500
+ * - stop
1501
+ * - pause
1502
+ * - resume
1503
+ * - reset
1504
+ * - terminate
1505
+ * - complete
1506
+ */
1507
+ #ForcePublishTelemetryData = async () => {
1508
+ this.#LogMessage(chalk.magenta(` **** FORCED PUBLISH **** `));
1509
+ await this.#PublishTelemetryData();
1510
+ };
1511
+ /**
1512
+ * Buffer and publish telemetry using a mixed threshold/timeout strategy.
1513
+ *
1514
+ * Behaviour:
1515
+ * - increments the buffered telemetry count
1516
+ * - if the count reaches `#maxBufferSize`:
1517
+ * - clears any pending timeout
1518
+ * - publishes immediately
1519
+ * - resets the buffered count
1520
+ * - otherwise ensures a timeout is scheduled
1521
+ *
1522
+ * This creates a "whichever happens first" batching model:
1523
+ * - count threshold
1524
+ * - timeout threshold
1525
+ */
1526
+ #PublishTelemetry = async () => {
1527
+ this.#publishTelemetryCount++;
1528
+ if (this.#publishTelemetryCount % this.#maxBufferSize === 0) {
1529
+ this.#LogMessage(chalk.cyan(` **** MAX COUNT REACHED **** `));
1530
+ this.#publishTelemetryCount = 0;
1531
+ if (this.#publishTelemetryTimeout) {
1532
+ clearTimeout(this.#publishTelemetryTimeout);
1533
+ this.#publishTelemetryTimeout = null;
1534
+ }
1535
+ await this.#PublishTelemetryData();
1536
+ }
1537
+ if (!this.#publishTelemetryTimeout) this.#SetupTimeout();
1538
+ };
1539
+ /**
1540
+ * Yield immediately to the event loop/microtask queue.
1541
+ *
1542
+ * Used when the runner wants to behave asynchronously but does not need
1543
+ * a real delay.
1544
+ *
1545
+ * @returns Resolved promise.
1546
+ */
1547
+ SleepImmediate() {
1548
+ return new Promise((resolve, reject) => {
1549
+ resolve();
1550
+ });
1551
+ }
1552
+ /**
1553
+ * Execute one synthetic unit of work for this runner.
1554
+ *
1555
+ * Behaviour
1556
+ * ---------
1557
+ * - captures start time
1558
+ * - reads extended runner options
1559
+ * - updates telemetry counters/metrics
1560
+ * - optionally generates log messages
1561
+ * - optionally emits status/progress messages
1562
+ * - simulates actual work using:
1563
+ * - `Sleep(options.sleepDuration)`, or
1564
+ * - immediate yield
1565
+ * - decrements active request count
1566
+ * - records duration
1567
+ * - publishes telemetry using buffered publish logic
1568
+ *
1569
+ * Telemetry updates performed
1570
+ * ---------------------------
1571
+ * - `coreCount = 1`
1572
+ * - `activeRequestCount++`
1573
+ * - `requestCount++`
1574
+ * - `velocity++`
1575
+ * - `tx += 256000`
1576
+ * - `rx += 6500000`
1577
+ * - `duration = measured execution time`
1578
+ *
1579
+ * Notes
1580
+ * -----
1581
+ * - This method simulates real work rather than performing domain logic
1582
+ * - It is intended to validate the framework's runner/telemetry lifecycle
1583
+ * - After the awaited work delay, the actual framework runner state may have
1584
+ * changed externally, but this test implementation does not directly react here
1585
+ *
1586
+ * @returns `true` when the synthetic work cycle completes.
1587
+ */
1588
+ ExecuteRunner = async () => {
1589
+ const start = performance.now();
1590
+ const options = this.#runner.options;
1591
+ this.#runner.instrumentData.coreCount = 1;
1592
+ this.#runner.instrumentData.activeRequestCount++;
1593
+ this.#runner.instrumentData.requestCount++;
1594
+ this.#runner.instrumentData.velocity++;
1595
+ this.#runner.instrumentData.tx += 256e3;
1596
+ this.#runner.instrumentData.rx += 65e5;
1597
+ if (this.#runner.instrumentData.requestCount % options.logMessageMod === 0) this.#GenLogMessage(this.#runner, this.#runner.iteration);
1598
+ if (this.#runner.instrumentData.requestCount % 1 === 0) {
1599
+ const message = `Worker: [${this.#runner.asyncRunnerContext.threadId}], Runner: [${this.#runner.asyncRunnerContext.id}] has completed: [${this.#runner.instrumentData.requestCount}] iterations of max: [${options.executionProfile.iterations}]`;
1600
+ this.#LogMessage(message);
1601
+ this.#runner.instrumentData.message = [message];
1602
+ }
1603
+ /**
1604
+ * Simulate actual work.
1605
+ *
1606
+ * In real runner implementations this is where domain-specific work would occur:
1607
+ * - REST calls
1608
+ * - DB access
1609
+ * - browser automation
1610
+ * - file processing
1611
+ * etc.
1612
+ */
1613
+ if (options.sleepDuration > 0) await Sleep(options.sleepDuration);
1614
+ else await this.SleepImmediate();
1615
+ this.#runner.instrumentData.activeRequestCount--;
1616
+ const diff = performance.now() - start;
1617
+ this.#runner.instrumentData.duration = diff;
1618
+ await this.#PublishTelemetry();
1619
+ return true;
1620
+ };
1621
+ /**
1622
+ * Write a grey-coloured lifecycle message into the runner telemetry message buffer
1623
+ * and publish telemetry using normal buffered publish logic.
1624
+ *
1625
+ * @param message Lifecycle/status message to emit.
1626
+ */
1627
+ #OutputLogMessage = async (message) => {
1628
+ const messageOutput = chalk.grey(message);
1629
+ this.#LogMessage(messageOutput);
1630
+ this.#runner.instrumentData.message.push(messageOutput);
1631
+ await this.#PublishTelemetry();
1632
+ };
1633
+ /**
1634
+ * Handle framework "start" lifecycle event for this runner.
1635
+ *
1636
+ * Behaviour:
1637
+ * - writes a lifecycle message
1638
+ * - forces immediate telemetry publication
1639
+ *
1640
+ * @returns `true`
1641
+ */
1642
+ StartRunner = async () => {
1643
+ await this.#OutputLogMessage(`StartRunner [${this.#runner.id}]`);
1644
+ await this.#ForcePublishTelemetryData();
1645
+ return true;
1646
+ };
1647
+ /**
1648
+ * Handle framework "stop" lifecycle event for this runner.
1649
+ *
1650
+ * Behaviour:
1651
+ * - writes a lifecycle message
1652
+ * - forces immediate telemetry publication
1653
+ *
1654
+ * @returns `true`
1655
+ */
1656
+ StopRunner = async () => {
1657
+ await this.#OutputLogMessage(`StopRunner [${this.#runner.id}]`);
1658
+ await this.#ForcePublishTelemetryData();
1659
+ return true;
1660
+ };
1661
+ /**
1662
+ * Handle framework "terminate" lifecycle event for this runner.
1663
+ *
1664
+ * Behaviour:
1665
+ * - writes a lifecycle message
1666
+ * - forces immediate telemetry publication
1667
+ *
1668
+ * @returns `true`
1669
+ */
1670
+ TerminateRunner = async () => {
1671
+ await this.#OutputLogMessage(`TerminateRunner [${this.#runner.id}]`);
1672
+ await this.#ForcePublishTelemetryData();
1673
+ return true;
1674
+ };
1675
+ /**
1676
+ * Handle framework "completed" lifecycle event for this runner.
1677
+ *
1678
+ * Behaviour:
1679
+ * - writes a completion lifecycle message including current telemetry snapshot
1680
+ * - forces immediate telemetry publication
1681
+ *
1682
+ * @returns `true`
1683
+ */
1684
+ Completed = async () => {
1685
+ await this.#OutputLogMessage(`Completed [${this.#runner.id}] [${JSON.stringify(this.#runner.instrumentData)}]`);
1686
+ await this.#ForcePublishTelemetryData();
1687
+ return true;
1688
+ };
1689
+ /**
1690
+ * Handle framework "pause" lifecycle event for this runner.
1691
+ *
1692
+ * Behaviour:
1693
+ * - writes a lifecycle message
1694
+ * - forces immediate telemetry publication
1695
+ * - returns a descriptive diagnostic string
1696
+ *
1697
+ * @returns Diagnostic pause message.
1698
+ */
1699
+ PauseRunner = async () => {
1700
+ await this.#OutputLogMessage(`PauseRunner [${this.#runner.id}]`);
1701
+ await this.#ForcePublishTelemetryData();
1702
+ return `I have been paused at iteration: [${this.#runner.iteration}] Date: [${/* @__PURE__ */ new Date()}] Performance: [${performance.now()}]`;
1703
+ };
1704
+ /**
1705
+ * Handle framework "resume" lifecycle event for this runner.
1706
+ *
1707
+ * Behaviour:
1708
+ * - writes a lifecycle message
1709
+ * - forces immediate telemetry publication
1710
+ * - returns a descriptive diagnostic string
1711
+ *
1712
+ * @returns Diagnostic resume message.
1713
+ */
1714
+ ResumeRunner = async () => {
1715
+ await this.#OutputLogMessage(`ResumeRunner [${this.#runner.id}]`);
1716
+ await this.#ForcePublishTelemetryData();
1717
+ return `I have been resumed at iteration: [${this.#runner.iteration}] Date: [${/* @__PURE__ */ new Date()}] Performance: [${performance.now()}]`;
1718
+ };
1719
+ /**
1720
+ * Handle framework "reset" lifecycle event for this runner.
1721
+ *
1722
+ * Behaviour:
1723
+ * - writes a lifecycle message
1724
+ * - resets `requestCount` to zero
1725
+ * - forces immediate telemetry publication
1726
+ *
1727
+ * @returns `true`
1728
+ */
1729
+ ResetRunner = async () => {
1730
+ await this.#OutputLogMessage(`ResetRunner [${this.#runner.id}]`);
1731
+ this.#runner.instrumentData.requestCount = 0;
1732
+ await this.#ForcePublishTelemetryData();
1733
+ return true;
1734
+ };
1735
+ /**
1736
+ * Handle framework "update" lifecycle event for this runner.
1737
+ *
1738
+ * Behaviour:
1739
+ * - writes a lifecycle message
1740
+ * - forces immediate telemetry publication
1741
+ *
1742
+ * Note:
1743
+ * - this implementation does not directly apply option changes itself;
1744
+ * it simply acknowledges the lifecycle event for framework testing
1745
+ *
1746
+ * @returns `true`
1747
+ */
1748
+ UpdateRunner = async () => {
1749
+ await this.#OutputLogMessage(`UpdateOptions [${this.#runner.id}]`);
1750
+ await this.#ForcePublishTelemetryData();
1751
+ return true;
1752
+ };
1753
+ };
1754
+ //#endregion
1755
+ //#region src/libmodule/testCase02.ts
1756
+ /**
1757
+ * Concrete synthetic test runner implementation.
1758
+ *
1759
+ * This runner simulates work, updates telemetry, batches telemetry publishing,
1760
+ * and writes both internal telemetry messages and visible console progress.
1761
+ */
1762
+ var TestCase02 = class {
1763
+ /**
1764
+ * Live serialisable runner model/state for this test runner.
1765
+ *
1766
+ * This object is mutated as execution and telemetry progress.
1767
+ */
1768
+ #runner;
1769
+ /**
1770
+ * Owning worker-side execution host.
1771
+ *
1772
+ * Used primarily to publish telemetry for this runner back to the manager.
1773
+ */
1774
+ #runnerExecutionWorker;
1775
+ /**
1776
+ * Per-runner animated log message state.
1777
+ */
1778
+ #logMessageDataSet = {};
1779
+ /**
1780
+ * Timeout handle used for delayed telemetry publication.
1781
+ *
1782
+ * Supports timeout-based flush behaviour when the publish count threshold
1783
+ * has not yet been reached.
1784
+ */
1785
+ #publishTelemetryTimeout = null;
1786
+ /**
1787
+ * Count of buffered telemetry-publish requests since the last flush.
1788
+ */
1789
+ #publishTelemetryCount = 0;
1790
+ /**
1791
+ * Maximum buffered publish count before telemetry is flushed immediately.
1792
+ *
1793
+ * This should remain lower than the maximum observability/logging buffer size
1794
+ * used elsewhere in the framework.
1795
+ */
1796
+ #maxBufferSize = 50;
1797
+ /**
1798
+ * Maximum time in milliseconds to wait before flushing telemetry.
1799
+ *
1800
+ * Publish strategy:
1801
+ * - whichever happens first:
1802
+ * - max buffer size reached
1803
+ * - timeout reached
1804
+ */
1805
+ #publishTelemetryTimeoutVal = 1e3;
1806
+ /**
1807
+ * Construct a new `TestCase02` runner.
1808
+ *
1809
+ * @param runnerExecutionWorker Owning worker-side execution host.
1810
+ * @param runner Live runner model/state.
1811
+ */
1812
+ constructor(runnerExecutionWorker, runner) {
1813
+ this.#runnerExecutionWorker = runnerExecutionWorker;
1814
+ this.#runner = runner;
1815
+ }
1816
+ /**
1817
+ * Internal low-level log sink.
1818
+ *
1819
+ * Currently disabled/commented out to avoid noisy console output during normal testing.
1820
+ * The class still uses `console.log(...)` directly in `ExecuteRunner()` for visible progress.
1821
+ *
1822
+ * @param message Message to output.
1823
+ */
1824
+ #LogMessage = (message) => {};
1825
+ /**
1826
+ * Generate an animated indented "Hello World" style log message.
1827
+ *
1828
+ * Behaviour:
1829
+ * - initialises per-runner indentation state if needed
1830
+ * - builds a message with variable indentation
1831
+ * - appends the message to the runner telemetry message buffer
1832
+ * - updates indentation direction when bounds are reached
1833
+ *
1834
+ * Indentation pattern:
1835
+ * - grows from 0 upward
1836
+ * - reverses after exceeding 20
1837
+ * - reverses again when returning to 0
1838
+ *
1839
+ * @param runner Runner whose message should be generated.
1840
+ * @param iteration Current iteration number.
1841
+ */
1842
+ #GenLogMessage = (runner, iteration) => {
1843
+ if (!this.#logMessageDataSet[runner.id]) this.#logMessageDataSet[runner.id] = {
1844
+ adder: 1,
1845
+ indent: 0
1846
+ };
1847
+ const logMessageData = this.#logMessageDataSet[runner.id];
1848
+ const message = `${" ".repeat(logMessageData.indent)} [${runner.id}] >> Hello World << ${iteration}`;
1849
+ this.#LogMessage(message);
1850
+ runner.instrumentData.message.push(message);
1851
+ logMessageData.indent += logMessageData.adder;
1852
+ if (logMessageData.indent > 20) logMessageData.adder = -1;
1853
+ else if (logMessageData.indent === 0) logMessageData.adder = 1;
1854
+ };
1855
+ /**
1856
+ * Schedule a timeout-based telemetry flush if one is not already active.
1857
+ *
1858
+ * Behaviour:
1859
+ * - creates a timeout only when no current timeout exists
1860
+ * - when the timeout fires:
1861
+ * - telemetry is published
1862
+ * - buffered publish count is reset
1863
+ * - timeout handle is cleared
1864
+ *
1865
+ * In Node.js, the timer is `unref()`'d so it does not keep the process alive.
1866
+ */
1867
+ #SetupTimeout = async () => {
1868
+ if (!this.#publishTelemetryTimeout) {
1869
+ this.#publishTelemetryTimeout = setTimeout(async () => {
1870
+ this.#LogMessage(chalk.yellow(` PublishTelemetryData - Normal Behaviour (**** TIMEOUT ****) `));
1871
+ await this.#PublishTelemetryData();
1872
+ this.#publishTelemetryCount = 0;
1873
+ this.#publishTelemetryTimeout = null;
1874
+ }, this.#publishTelemetryTimeoutVal);
1875
+ if (isNode) this.#publishTelemetryTimeout.unref();
1876
+ }
1877
+ };
1878
+ /**
1879
+ * Publish the current telemetry snapshot immediately.
1880
+ *
1881
+ * Behaviour:
1882
+ * - asks the owning execution worker to post telemetry for this runner
1883
+ * - writes a separator line to the local test log sink
1884
+ * - resets transient per-publish telemetry fields
1885
+ * - yields immediately before returning
1886
+ *
1887
+ * Reset after publish:
1888
+ * - `velocity`
1889
+ * - `message`
1890
+ * - `tx`
1891
+ * - `rx`
1892
+ */
1893
+ #PublishTelemetryData = async () => {
1894
+ this.#runnerExecutionWorker.PostTelemetryById(this.#runner.id);
1895
+ this.#LogMessage(chalk.red(`------------------------------------------------------------------------------------------------------------`));
1896
+ this.#runner.instrumentData.velocity = 0;
1897
+ this.#runner.instrumentData.message = [];
1898
+ this.#runner.instrumentData.tx = 0;
1899
+ this.#runner.instrumentData.rx = 0;
1900
+ await this.SleepImmediate();
1901
+ };
1902
+ /**
1903
+ * Force an immediate telemetry publication.
1904
+ *
1905
+ * Used for lifecycle transitions where immediate visibility is desirable.
1906
+ */
1907
+ #ForcePublishTelemetryData = async () => {
1908
+ this.#LogMessage(chalk.magenta(` **** FORCED PUBLISH **** `));
1909
+ await this.#PublishTelemetryData();
1910
+ };
1911
+ /**
1912
+ * Buffer telemetry and publish using a threshold-or-timeout strategy.
1913
+ *
1914
+ * Behaviour:
1915
+ * - increments buffered telemetry count
1916
+ * - when the count reaches `#maxBufferSize`:
1917
+ * - clears any pending timeout
1918
+ * - immediately publishes telemetry
1919
+ * - resets buffered count
1920
+ * - otherwise ensures a timeout flush is scheduled
1921
+ *
1922
+ * This gives a "first trigger wins" strategy:
1923
+ * - count threshold reached
1924
+ * - timeout reached
1925
+ */
1926
+ #PublishTelemetry = async () => {
1927
+ this.#publishTelemetryCount++;
1928
+ if (this.#publishTelemetryCount % this.#maxBufferSize === 0) {
1929
+ this.#LogMessage(chalk.cyan(` **** MAX COUNT REACHED **** `));
1930
+ this.#publishTelemetryCount = 0;
1931
+ if (this.#publishTelemetryTimeout) {
1932
+ clearTimeout(this.#publishTelemetryTimeout);
1933
+ this.#publishTelemetryTimeout = null;
1934
+ }
1935
+ await this.#PublishTelemetryData();
1936
+ }
1937
+ if (!this.#publishTelemetryTimeout) this.#SetupTimeout();
1938
+ };
1939
+ /**
1940
+ * Yield immediately to the event loop/microtask queue.
1941
+ *
1942
+ * Used when asynchronous behaviour is desired but no real delay is needed.
1943
+ *
1944
+ * @returns Resolved promise.
1945
+ */
1946
+ SleepImmediate() {
1947
+ return new Promise((resolve, reject) => {
1948
+ resolve();
1949
+ });
1950
+ }
1951
+ /**
1952
+ * Execute one synthetic unit of work for this runner.
1953
+ *
1954
+ * Behaviour
1955
+ * ---------
1956
+ * - captures start time
1957
+ * - reads extended test options
1958
+ * - updates runner telemetry
1959
+ * - optionally generates animated telemetry messages
1960
+ * - always generates a progress message for telemetry
1961
+ * - always writes a progress message to `console.log(...)`
1962
+ * - simulates work with either:
1963
+ * - `Sleep(options.sleepDuration)`, or
1964
+ * - immediate yield
1965
+ * - decrements active request count
1966
+ * - calculates and stores execution duration
1967
+ * - performs buffered telemetry publication
1968
+ *
1969
+ * Telemetry fields updated
1970
+ * ------------------------
1971
+ * - `coreCount = 1`
1972
+ * - `activeRequestCount++`
1973
+ * - `requestCount++`
1974
+ * - `velocity++`
1975
+ * - `tx += 256000`
1976
+ * - `rx += 6500000`
1977
+ * - `duration = measured elapsed time`
1978
+ *
1979
+ * Additional visible behaviour
1980
+ * ----------------------------
1981
+ * Unlike `TestCase01`, this implementation always writes a progress message
1982
+ * directly to the process/browser console using `console.log(...)`.
1983
+ *
1984
+ * This makes it more useful for manually watching test progress while the
1985
+ * framework is running.
1986
+ *
1987
+ * @returns `true` when the simulated work cycle completes.
1988
+ */
1989
+ ExecuteRunner = async () => {
1990
+ const start = performance.now();
1991
+ const options = this.#runner.options;
1992
+ this.#runner.instrumentData.coreCount = 1;
1993
+ this.#runner.instrumentData.activeRequestCount++;
1994
+ this.#runner.instrumentData.requestCount++;
1995
+ this.#runner.instrumentData.velocity++;
1996
+ this.#runner.instrumentData.tx += 256e3;
1997
+ this.#runner.instrumentData.rx += 65e5;
1998
+ if (this.#runner.instrumentData.requestCount % options.logMessageMod === 0) this.#GenLogMessage(this.#runner, this.#runner.iteration);
1999
+ if (this.#runner.instrumentData.requestCount % 1 === 0) {
2000
+ const message = `Worker: [${this.#runner.asyncRunnerContext.threadId}], Runner: [${this.#runner.asyncRunnerContext.id}] has completed: [${this.#runner.instrumentData.requestCount}] iterations of max: [${options.executionProfile.iterations}]`;
2001
+ this.#LogMessage(message);
2002
+ this.#runner.instrumentData.message = [message];
2003
+ }
2004
+ /**
2005
+ * Visible console output for manual observation/debugging.
2006
+ *
2007
+ * This is the main behavioural difference from `TestCase01`.
2008
+ */
2009
+ const message = `Worker: [${this.#runner.asyncRunnerContext.threadId}], Runner: [${this.#runner.asyncRunnerContext.id}] has completed: [${this.#runner.instrumentData.requestCount}] iterations of max: [${options.executionProfile.iterations}]`;
2010
+ console.log(message);
2011
+ /**
2012
+ * Simulate actual work.
2013
+ *
2014
+ * In a real runner implementation this would be replaced with
2015
+ * domain-specific work such as:
2016
+ * - REST/API calls
2017
+ * - browser interactions
2018
+ * - DB operations
2019
+ * - file processing
2020
+ * etc.
2021
+ */
2022
+ if (options.sleepDuration > 0) await Sleep(options.sleepDuration);
2023
+ else await this.SleepImmediate();
2024
+ this.#runner.instrumentData.activeRequestCount--;
2025
+ const diff = performance.now() - start;
2026
+ this.#runner.instrumentData.duration = diff;
2027
+ await this.#PublishTelemetry();
2028
+ return true;
2029
+ };
2030
+ /**
2031
+ * Write a grey-coloured lifecycle message into the runner telemetry message buffer
2032
+ * and publish telemetry using normal buffered publish rules.
2033
+ *
2034
+ * @param message Lifecycle/status message to emit.
2035
+ */
2036
+ #OutputLogMessage = async (message) => {
2037
+ const messageOutput = chalk.grey(message);
2038
+ this.#LogMessage(messageOutput);
2039
+ this.#runner.instrumentData.message.push(messageOutput);
2040
+ await this.#PublishTelemetry();
2041
+ };
2042
+ /**
2043
+ * Handle framework "start" lifecycle event.
2044
+ *
2045
+ * Behaviour:
2046
+ * - writes a lifecycle message
2047
+ * - forces immediate telemetry publication
2048
+ *
2049
+ * @returns `true`
2050
+ */
2051
+ StartRunner = async () => {
2052
+ await this.#OutputLogMessage(`StartRunner [${this.#runner.id}]`);
2053
+ await this.#ForcePublishTelemetryData();
2054
+ return true;
2055
+ };
2056
+ /**
2057
+ * Handle framework "stop" lifecycle event.
2058
+ *
2059
+ * Behaviour:
2060
+ * - writes a lifecycle message
2061
+ * - forces immediate telemetry publication
2062
+ *
2063
+ * @returns `true`
2064
+ */
2065
+ StopRunner = async () => {
2066
+ await this.#OutputLogMessage(`StopRunner [${this.#runner.id}]`);
2067
+ await this.#ForcePublishTelemetryData();
2068
+ return true;
2069
+ };
2070
+ /**
2071
+ * Handle framework "terminate" lifecycle event.
2072
+ *
2073
+ * Behaviour:
2074
+ * - writes a lifecycle message
2075
+ * - forces immediate telemetry publication
2076
+ *
2077
+ * @returns `true`
2078
+ */
2079
+ TerminateRunner = async () => {
2080
+ await this.#OutputLogMessage(`TerminateRunner [${this.#runner.id}]`);
2081
+ await this.#ForcePublishTelemetryData();
2082
+ return true;
2083
+ };
2084
+ /**
2085
+ * Handle framework "completed" lifecycle event.
2086
+ *
2087
+ * Behaviour:
2088
+ * - writes a completion message including the current telemetry snapshot
2089
+ * - forces immediate telemetry publication
2090
+ *
2091
+ * @returns `true`
2092
+ */
2093
+ Completed = async () => {
2094
+ await this.#OutputLogMessage(`Completed [${this.#runner.id}] [${JSON.stringify(this.#runner.instrumentData)}]`);
2095
+ await this.#ForcePublishTelemetryData();
2096
+ return true;
2097
+ };
2098
+ /**
2099
+ * Handle framework "pause" lifecycle event.
2100
+ *
2101
+ * Behaviour:
2102
+ * - writes a lifecycle message
2103
+ * - forces immediate telemetry publication
2104
+ *
2105
+ * @returns `true`
2106
+ */
2107
+ PauseRunner = async () => {
2108
+ await this.#OutputLogMessage(`PauseRunner [${this.#runner.id}]`);
2109
+ await this.#ForcePublishTelemetryData();
2110
+ return true;
2111
+ };
2112
+ /**
2113
+ * Handle framework "resume" lifecycle event.
2114
+ *
2115
+ * Behaviour:
2116
+ * - writes a lifecycle message
2117
+ * - forces immediate telemetry publication
2118
+ *
2119
+ * @returns `true`
2120
+ */
2121
+ ResumeRunner = async () => {
2122
+ await this.#OutputLogMessage(`ResumeRunner [${this.#runner.id}]`);
2123
+ await this.#ForcePublishTelemetryData();
2124
+ return true;
2125
+ };
2126
+ /**
2127
+ * Handle framework "reset" lifecycle event.
2128
+ *
2129
+ * Behaviour:
2130
+ * - writes a lifecycle message
2131
+ * - resets `requestCount` to zero
2132
+ * - forces immediate telemetry publication
2133
+ *
2134
+ * @returns `true`
2135
+ */
2136
+ ResetRunner = async () => {
2137
+ await this.#OutputLogMessage(`ResetRunner [${this.#runner.id}]`);
2138
+ this.#runner.instrumentData.requestCount = 0;
2139
+ await this.#ForcePublishTelemetryData();
2140
+ return true;
2141
+ };
2142
+ /**
2143
+ * Handle framework "update" lifecycle event.
2144
+ *
2145
+ * Behaviour:
2146
+ * - writes a lifecycle message
2147
+ * - forces immediate telemetry publication
2148
+ *
2149
+ * Note:
2150
+ * - this implementation acknowledges the update event but does not apply
2151
+ * custom update logic itself
2152
+ *
2153
+ * @returns `true`
2154
+ */
2155
+ UpdateRunner = async () => {
2156
+ await this.#OutputLogMessage(`UpdateOptions [${this.#runner.id}]`);
2157
+ await this.#ForcePublishTelemetryData();
2158
+ return true;
2159
+ };
2160
+ };
2161
+ //#endregion
1337
2162
  //#region src/libmodule/asyncRunnerFactory.ts
1338
2163
  var AsyncRunnerFactory = class {
1339
2164
  static CreateAsyncRunner = async (runnerExecutionWorker, testRunnerTelemetryPayload) => {
1340
2165
  const { runner } = testRunnerTelemetryPayload;
1341
2166
  switch (runner.options.testType) {
2167
+ case "TestCase01": return new TestCase01(runnerExecutionWorker, runner);
2168
+ case "TestCase02": return new TestCase02(runnerExecutionWorker, runner);
1342
2169
  case "TestCaseFhir01": return new TestCaseFhir01(runnerExecutionWorker, runner);
1343
2170
  case "TestCaseFhir02": return new TestCaseFhir02(runnerExecutionWorker, runner);
1344
2171
  case "TestCaseFhir03": return new TestCaseFhir03(runnerExecutionWorker, runner);