@nsshunt/ststestrunner 1.1.104 → 1.1.105

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.
@@ -1,10 +1,10 @@
1
1
  import { AbstractRunnerExecutionWorker } from "@nsshunt/stsrunnerframework";
2
- import chalk from "chalk";
3
2
  import { STSAxiosConfig, Sleep, createAgentManager, isNode } from "@nsshunt/stsutils";
3
+ import chalk from "chalk";
4
+ import axios from "axios";
4
5
  import { FhirRESTClient, FhirSocketClientAllInOne, FhirSocketClientIndividual, createRetryAxiosClient } from "@nsshunt/stsfhirclient";
5
6
  import http from "node:http";
6
7
  import https from "node:https";
7
- import axios from "axios";
8
8
  //#region \0rolldown/runtime.js
9
9
  var __defProp = Object.defineProperty;
10
10
  var __exportAll = (all, no_symbols) => {
@@ -379,190 +379,40 @@ var StatusCodes;
379
379
  //#region src/libmodule/testCaseFhirBase.ts
380
380
  var TestCaseFhirBase = class {
381
381
  #options;
382
- #randomDataRecordset = [];
383
382
  #runner;
384
383
  #runnerExecutionWorker;
385
- #accesssToken = null;
386
384
  #publishTelemetryCount = 0;
387
385
  #maxBufferSize = 50;
388
386
  #publishTelemetryTimeout = null;
389
387
  #publishTelemetryTimeoutVal = 1e3;
390
- #originRegex = /^(api:\/\/\w+)/;
391
- #resetSocketClientTrigger = 50;
392
- #clientSocketFetchCount = 0;
393
- #authAgentManager;
388
+ _RetryMap = [
389
+ 100,
390
+ 250,
391
+ 500,
392
+ 1e3,
393
+ 2e3,
394
+ 3e3
395
+ ];
394
396
  _id = crypto.randomUUID();
395
397
  retryCount = 0;
396
398
  maxAuthRetryCount = 5;
397
399
  runnerDurationList = [];
398
- _authMaxTimeout = 5e3;
399
- accessTokenTime = performance.now();
400
- newTokenLimitTime = 30;
401
- restFhirClient = null;
402
- defaultAgentOptions = {
403
- keepAlive: true,
404
- maxSockets: 10,
405
- maxTotalSockets: 20,
406
- maxFreeSockets: 10,
407
- timeout: 6e4,
408
- rejectUnauthorized: false
409
- };
410
- stressTestAgentOptions = {
411
- keepAlive: true,
412
- maxSockets: 200,
413
- maxTotalSockets: 500,
414
- maxFreeSockets: 50,
415
- timeout: 3e4,
416
- rejectUnauthorized: false
417
- };
418
- stressTestExtremeAgentOptions = {
419
- keepAlive: true,
420
- maxSockets: 500,
421
- maxTotalSockets: 1e3,
422
- maxFreeSockets: 500,
423
- timeout: 3e4,
424
- rejectUnauthorized: false
425
- };
426
400
  constructor(runnerExecutionWorker, runner) {
427
401
  this.#options = runner.options;
428
402
  this.#runnerExecutionWorker = runnerExecutionWorker;
429
403
  this.#runner = runner;
430
- this.#authAgentManager = this.GetAuthAgentManager();
431
404
  }
432
405
  get runnerExecutionWorker() {
433
406
  return this.#runnerExecutionWorker;
434
407
  }
435
408
  ResetClient = () => {};
436
- GetRESTClient = async () => {
437
- if (this.restFhirClient) return this.restFhirClient;
438
- const onRetryAttempt = (attempt, error, delayMs) => {
439
- this.#runner.instrumentData.errorCount++;
440
- this.#runner.instrumentData.requestCount++;
441
- const message = `TestCaseFhirBase:onRetryAttempt(): [${this._id}] Retry #${attempt} after ${delayMs}ms due to ${error.code || error.response?.status}`;
442
- this.Warning(message);
443
- this.#runner.instrumentData.message.push(chalk.red(message));
444
- };
445
- const fhirOptions = this.#options.fhirOptions;
446
- const fhirRESTClient = new FhirRESTClient({
447
- GetAccessToken: this.GetAccessToken,
448
- user: "USR_user01@stsmda.com.au",
449
- endpoint: fhirOptions.stsfhirserverendpoint,
450
- stsfhirapiroot: fhirOptions.stsfhirapiroot,
451
- stsfhirport: fhirOptions.stsfhirport,
452
- logger: this.#runnerExecutionWorker.logger,
453
- agentManager: this.GetFhirAgentManager(),
454
- onRetryAttempt
455
- });
456
- this.restFhirClient = fhirRESTClient;
457
- return fhirRESTClient;
458
- };
459
- GetAgentManager = (testingAgentOptions) => {
460
- let agentManager = void 0;
461
- let agentOptions = void 0;
462
- switch (testingAgentOptions.nodeAgentMode) {
463
- case "no-agent": break;
464
- case "custom-agent-options":
465
- if (testingAgentOptions.nodeAgentCustomOptions) agentOptions = { ...testingAgentOptions.nodeAgentCustomOptions };
466
- else agentOptions = { ...this.defaultAgentOptions };
467
- break;
468
- case "default-agent-options":
469
- agentOptions = { ...this.defaultAgentOptions };
470
- break;
471
- case "stress-test-agent-options":
472
- agentOptions = { ...this.stressTestAgentOptions };
473
- break;
474
- case "stress-test-extreme-agent-options":
475
- agentOptions = { ...this.stressTestExtremeAgentOptions };
476
- break;
477
- default: throw new Error(`TestCaseFhirBase:GetAgentManager(): [${this._id}] unknown nodeAgentMode: [${testingAgentOptions.nodeAgentMode}]`);
478
- }
479
- if (agentOptions) agentManager = createAgentManager({
480
- agentOptions,
481
- httpAgentFactory(options) {
482
- return new http.Agent(options);
483
- },
484
- httpsAgentFactory(options) {
485
- return new https.Agent(options);
486
- }
487
- });
488
- return agentManager;
489
- };
490
- GetFhirAgentManager = () => {
491
- return this.GetAgentManager(this.#options.fhirOptions.stsfhiragentOptions);
492
- };
493
- GetAuthAgentManager = () => {
494
- return this.GetAgentManager(this.#options.authOptions.asagentoptions);
495
- };
496
- GetFhirSocketClient = async () => {
497
- try {
498
- this.#clientSocketFetchCount++;
499
- let fhirClient = this.runnerExecutionWorker.GetFhirClient();
500
- if (fhirClient) return fhirClient;
501
- if (this.runnerExecutionWorker.GetOnHold("fhirclient") === true) {
502
- this.Debug(chalk.magenta(`[${this.runnerExecutionWorker.id}] [${this._id}] fhir client does not exist - some other client setting up the new client (on hold/lock) - waiting ...`));
503
- try {
504
- const start = performance.now();
505
- await this.runnerExecutionWorker.WaitOnHold("fhirclient", 6e4);
506
- this.Debug(chalk.yellow(`[${this.runnerExecutionWorker.id}] [${this._id}] hold (lock) released after: [${performance.now() - start}ms]`));
507
- const fhirClient = this.runnerExecutionWorker.GetFhirClient();
508
- if (fhirClient) {
509
- this.Debug(chalk.green(`[${this.runnerExecutionWorker.id}] [${this._id}] Getting existing fhir client (post hold release)`));
510
- return fhirClient;
511
- } else {
512
- this.Error(chalk.red(`[${this.runnerExecutionWorker.id}] [${this._id}] Could not get existing fhir client (post hold release)`));
513
- this.Error(chalk.red(`continue anyway ...`));
514
- }
515
- } catch (error) {
516
- this.Error(chalk.red(`GetFhirSocketClient(): Error: [${error}]`));
517
- }
518
- }
519
- const start = performance.now();
520
- this.Debug(chalk.yellow(`[${this.runnerExecutionWorker.id}] [${this._id}] fhir client does not exist - setting up new client`));
521
- this.Debug(chalk.yellow(`[${this.runnerExecutionWorker.id}] [${this._id}] setting hold (lock)`));
522
- this.runnerExecutionWorker.SetOnHold("fhirclient");
523
- const fhirOptions = this.#options.fhirOptions;
524
- const options = {
525
- fhirServerEndpoint: fhirOptions.stsfhirserverendpoint,
526
- fhirapiroot: fhirOptions.stsfhirapiroot,
527
- fhirServerPort: fhirOptions.stsfhirport,
528
- socketClientName: fhirOptions.stsfhirsocketname,
529
- socketIoCustomPath: fhirOptions.stsfhirsocketcustompath,
530
- timeout: fhirOptions.stsfhirsockettimeout,
531
- baseUrl: fhirOptions.stsfhirbaseurl,
532
- agentManager: this.GetFhirAgentManager(),
533
- joinRooms: [],
534
- logger: this.#runnerExecutionWorker.logger,
535
- verboseLogging: true,
536
- GetConnectionAccessToken: this.GetAccessTokenForSocketClientAccess,
537
- GetAccessToken: this.GetAccessToken
538
- };
539
- if (this.runner.options.fhirOptions.stsfhirsocketclientmode === "socket-client-all-in-one") fhirClient = new FhirSocketClientAllInOne("FhirSocketClient", options);
540
- else fhirClient = new FhirSocketClientIndividual("FhirSocketClient", options);
541
- await fhirClient.WaitForSocketConnected();
542
- this.Debug(chalk.yellow(`[${this.runnerExecutionWorker.id}] [${this._id}] setting fhir client into object`));
543
- this.runnerExecutionWorker.SetFhirClient(fhirClient);
544
- this.runnerExecutionWorker.ReleaseOnHold("fhirclient");
545
- this.Debug(chalk.yellow(`[${this.runnerExecutionWorker.id}] [${this._id}] release hold (lock) Time taken for socket connection and set object: [${performance.now() - start}ms]`));
546
- return fhirClient;
547
- } catch (error) {
548
- this.Error(error);
549
- throw error;
550
- }
551
- };
552
- #LogMessage = (message) => {};
553
- Debug = (message) => {
554
- this.#runnerExecutionWorker.logger.debug(message);
555
- };
556
409
  Error = (message) => {
557
410
  this.#runnerExecutionWorker.logger.error(message);
558
411
  this.#runner.instrumentData.message.push(chalk.red(`${message}`));
559
412
  };
560
- Warning = (message) => {
561
- this.#runnerExecutionWorker.logger.warn(message);
413
+ Debug = (message) => {
414
+ this.#runnerExecutionWorker.logger.debug(message);
562
415
  };
563
- get accesssToken() {
564
- return this.#accesssToken;
565
- }
566
416
  get runner() {
567
417
  return this.#runner;
568
418
  }
@@ -605,125 +455,6 @@ var TestCaseFhirBase = class {
605
455
  this.#runner.instrumentData.rx = 0;
606
456
  await this.SleepImmediate();
607
457
  };
608
- ExtractOrigin = (uri) => {
609
- const match = uri.match(this.#originRegex);
610
- return match ? match[1] : null;
611
- };
612
- GetAPITokenFromAuthServerUsingScope = async (options) => {
613
- const { scope, clientId, authClientSecret, endPoint } = options;
614
- let stage = "1";
615
- try {
616
- stage = "2";
617
- const scopes = scope.split(" ");
618
- let origin = null;
619
- let error = null;
620
- stage = "3";
621
- for (let i = 0; i < scopes.length; i++) {
622
- const s = scopes[i];
623
- if (!origin) {
624
- origin = this.ExtractOrigin(s);
625
- if (!origin) {
626
- error = /* @__PURE__ */ new Error(`Scope: [${scope}] not in required format. Must use (space seperated) api://<client id>[/<resource>.<permission>].`);
627
- break;
628
- }
629
- } else {
630
- const nextOrigin = this.ExtractOrigin(s);
631
- if (!nextOrigin) {
632
- error = /* @__PURE__ */ new Error(`Scope: [${scope}] not in required format. Must use (space seperated) api://<client id>[/<resource>.<permission>].`);
633
- break;
634
- } else if (origin.localeCompare(nextOrigin) !== 0) {
635
- error = /* @__PURE__ */ new Error(`Scope: [${scope}] not all from the same client API. All scopes must come from the same client API.`);
636
- break;
637
- }
638
- }
639
- }
640
- stage = "4";
641
- if (error) throw error;
642
- stage = "5";
643
- const payload = {
644
- client_id: clientId,
645
- client_secret: authClientSecret,
646
- scope,
647
- grant_type: "client_credentials"
648
- };
649
- stage = "6";
650
- const url = endPoint ? `${endPoint}${this.#options.authOptions.asoauthapiroot}/token` : `${this.#options.authOptions.asendpoint}:${this.#options.authOptions.asport}${this.#options.authOptions.asoauthapiroot}/token`;
651
- stage = `6.5: url: [${url}] payload: [${JSON.stringify(payload)}]`;
652
- const axiosConfig = new STSAxiosConfig(url, "post").withDefaultHeaders().withData(payload);
653
- if (this.#authAgentManager) axiosConfig.withAgentManager(this.#authAgentManager);
654
- const retVal = await createRetryAxiosClient({
655
- maxRetries: 4,
656
- retryDelayMs: 300,
657
- retryJitterMs: 150,
658
- maxRetryDurationMs: 5e3,
659
- onRetryAttempt: (attempt, error, delayMs) => {
660
- this.#runner.instrumentData.authenticationErrorCount++;
661
- this.#runner.instrumentData.authenticationRetryCount++;
662
- const message = `TestCaseFhirBase:GetAPITokenFromAuthServerUsingScope(): [${this._id}] Retry #${attempt} after ${delayMs}ms due to ${error.code || error.response?.status}`;
663
- this.Warning(message);
664
- this.#runner.instrumentData.message.push(chalk.red(message));
665
- }
666
- })(url, axiosConfig.config);
667
- this.#runner.instrumentData.authenticationCount++;
668
- stage = "7";
669
- if (retVal.status) {
670
- if (retVal.status !== 200) this.Warning(chalk.magenta(`TestCaseFhirBase:GetAPITokenFromAuthServerUsingScope(): [${this._id}] Invalid response from server: [${retVal.status}]`));
671
- } else throw new Error(chalk.red(`No retVal.status)`));
672
- stage = "8";
673
- if (retVal.data) {
674
- stage = "9";
675
- if (retVal.data.access_token) {
676
- stage = "12";
677
- return retVal.data.access_token;
678
- } else {
679
- stage = "13";
680
- throw new Error(`No retVal.data.access_token)`);
681
- }
682
- } else {
683
- stage = "14";
684
- throw new Error(`No retVal.data)`);
685
- }
686
- } catch (error) {
687
- this.Error(error);
688
- let details = "None available.";
689
- if (error.response && error.response.data) try {
690
- details = JSON.stringify(error.response.data);
691
- } catch (error) {
692
- details = `Could not JSON.stringify(error.response.data)`;
693
- }
694
- error.message = `TestCaseFhirBase:GetAPITokenFromAuthServerUsingScope(): [${this._id}] Error: [${error}], Stage: [${stage}], Details: [${details}]`;
695
- throw error;
696
- }
697
- };
698
- GetAccessTokenForSocketClientAccess = async () => {
699
- const timeout = setTimeout(() => {
700
- this.Warning(`TestCaseFhirBase:GetAccessTokenForSocketClientAccess(): [${this._id}] Timeout: [${this._authMaxTimeout}] exceeded for getting access token ...`);
701
- }, this._authMaxTimeout);
702
- const start = performance.now();
703
- try {
704
- const scopes = `api://fb6513e4-16fe-4931-bed8-33b82b404a14/_.stsfhir5:SocketConnection`.split(" ").sort().join(" ");
705
- const authendpointUrl = `${this.#options.authOptions.asendpoint}:${this.#options.authOptions.asport}`;
706
- const retVal = await this.GetAPITokenFromAuthServerUsingScope({
707
- clientId: "d8277fce-bb48-44c2-bbf1-257fe13a444b",
708
- authClientSecret: "64e3ef37-c7b8-4cb1-880a-e6ad3ab36e3c",
709
- scope: scopes,
710
- endPoint: authendpointUrl
711
- });
712
- clearTimeout(timeout);
713
- const totalTime = performance.now() - start;
714
- if (totalTime > this._authMaxTimeout) this.Warning(chalk.magenta(`TestCaseFhirBase:GetAccessTokenForSocketClientAccess(): [${this._id}] The total time for getting the access token: [${totalTime}]`));
715
- return retVal;
716
- } catch (error) {
717
- clearTimeout(timeout);
718
- const totalTime = performance.now() - start;
719
- error.message = `TestCaseFhirBase:GetAccessTokenForSocketClientAccess(): [${this._id}] Error: [${error}], Duration until error: [${totalTime}]`;
720
- this.Error(error);
721
- return "";
722
- }
723
- };
724
- ResetAccessToken = () => {
725
- this.#accesssToken = null;
726
- };
727
458
  HandleError = (error) => {
728
459
  this.Error(chalk.red(`TestCaseFhirBase:HandleError(): [${this._id}] Error: [${error}]`));
729
460
  this.Error(chalk.red(`TestCaseFhirBase:HandleError(): [${this._id}] description: [${this.runner.options.description}]`));
@@ -738,48 +469,18 @@ var TestCaseFhirBase = class {
738
469
  if (axiosError.response.status === StatusCodes.UNAUTHORIZED) {
739
470
  this.runner.instrumentData.authenticationErrorCount++;
740
471
  this.Error(chalk.red(`TestCaseFhirBase:HandleError(): [${this._id}] UNAUTHORIZED - Reset Access Token`));
741
- this.ResetAccessToken();
472
+ this.runnerExecutionWorker.ResetAccessToken();
742
473
  return true;
743
474
  }
744
475
  } else this.Error(chalk.red(`TestCaseFhirBase:HandleError(): [${this._id}] AXIOS Error = [${axiosError}]`));
745
476
  } else if (error.message === "UNAUTHORIZED") {
746
477
  this.runner.instrumentData.authenticationErrorCount++;
747
478
  this.Error(chalk.red(`TestCaseFhirBase:HandleError(): [${this._id}] UNAUTHORIZED - Reset Access Token`));
748
- this.ResetAccessToken();
479
+ this.runnerExecutionWorker.ResetAccessToken();
749
480
  return true;
750
481
  }
751
482
  return false;
752
483
  };
753
- GetAccessToken = async () => {
754
- let timeout = void 0;
755
- let start = performance.now();
756
- try {
757
- if (this.#accesssToken) return this.#accesssToken;
758
- timeout = setTimeout(() => {
759
- this.Warning(chalk.magenta(`TestCaseFhirBase:GetAccessToken(): [${this._id}] Timeout: [${this._authMaxTimeout}] exceeded for getting access token ...`));
760
- }, this._authMaxTimeout);
761
- const scopes = `api://fb6513e4-16fe-4931-bed8-33b82b404a14/_.stsfhir5:All`.split(" ").sort().join(" ");
762
- const authendpointUrl = `${this.#options.authOptions.asendpoint}:${this.#options.authOptions.asport}`;
763
- const retVal = await this.GetAPITokenFromAuthServerUsingScope({
764
- clientId: "d8277fce-bb48-44c2-bbf1-257fe13a444b",
765
- authClientSecret: "64e3ef37-c7b8-4cb1-880a-e6ad3ab36e3c",
766
- scope: scopes,
767
- endPoint: authendpointUrl
768
- });
769
- this.accessTokenTime = performance.now();
770
- this.#accesssToken = retVal;
771
- if (timeout) clearTimeout(timeout);
772
- const totalTime = performance.now() - start;
773
- if (totalTime > this._authMaxTimeout) this.Warning(chalk.magenta(`TestCaseFhirBase:GetAccessToken(): [${this._id}] The total time for getting the access token: [${totalTime}]`));
774
- return retVal;
775
- } catch (error) {
776
- if (timeout) clearTimeout(timeout);
777
- const totalTime = performance.now() - start;
778
- error.message = `TestCaseFhirBase:GetAccessToken(): [${this._id}] Error: [${error}], Duration until error: [${totalTime}]`;
779
- this.Error(error);
780
- return "";
781
- }
782
- };
783
484
  GetPersonRecord = async (prefix, index, version) => {
784
485
  const { workerIndex, runnerIndex, runId } = this.#options;
785
486
  const useId = `${prefix}-${index}`;
@@ -806,37 +507,12 @@ var TestCaseFhirBase = class {
806
507
  }
807
508
  };
808
509
  };
809
- StartTestDataLoad = async () => {
810
- this.Debug(chalk.magenta(`StartTestDataLoad(): Start ...`));
811
- let VU = 0;
812
- const blockNum = VU * 200;
813
- const blocksToLoad = 20;
814
- for (let i = 0; i < blocksToLoad; i++) {
815
- const recordId = `stsres_${blockNum + i}`;
816
- const retVal = await (await this.GetFhirSocketClient()).GetResource("Person", recordId);
817
- if (retVal) {
818
- const recordsetData = retVal.body.address;
819
- if (recordsetData) {
820
- const qqq = recordsetData[0].text;
821
- for (let j = 0; j < qqq.length; j++) this.#randomDataRecordset.push(qqq[j]);
822
- this.Error(chalk.magenta(this.#randomDataRecordset.length));
823
- }
824
- } else this.Error(chalk.magenta(`StartTestDataLoad(): Could not get person records.`));
825
- await Sleep(10);
826
- }
827
- this.Debug(`Finished load for VU: [${VU}]`);
828
- this.Debug(`First 10 entries`);
829
- for (let i = 0; i < 10; i++) this.Debug(this.#randomDataRecordset[i].id);
830
- this.Debug(`block num: [${blockNum}] length: [${this.#randomDataRecordset.length}] VU: [${VU}]`);
831
- this.Debug(chalk.magenta(`StartTestDataLoad(): End`));
832
- };
833
510
  #ForcePublishTelemetryData = async () => {
834
511
  await this.#PublishTelemetryData();
835
512
  };
836
513
  #SetupTimeout = async () => {
837
514
  if (!this.#publishTelemetryTimeout) {
838
515
  this.#publishTelemetryTimeout = setTimeout(async () => {
839
- this.#LogMessage(chalk.yellow(` **** TIMEOUT **** `));
840
516
  await this.#PublishTelemetryData();
841
517
  this.#publishTelemetryCount = 0;
842
518
  this.#publishTelemetryTimeout = null;
@@ -846,7 +522,6 @@ var TestCaseFhirBase = class {
846
522
  };
847
523
  PublishTelemetry = async () => {
848
524
  this.#publishTelemetryCount++;
849
- this.#LogMessage(chalk.red(this.#publishTelemetryCount));
850
525
  if (this.#publishTelemetryCount % this.#maxBufferSize === 0) {
851
526
  this.#publishTelemetryCount = 0;
852
527
  if (this.#publishTelemetryTimeout) {
@@ -859,7 +534,6 @@ var TestCaseFhirBase = class {
859
534
  };
860
535
  #OutputLogMessage = async (message) => {
861
536
  const messageOutput = chalk.grey(message);
862
- this.#LogMessage(messageOutput);
863
537
  this.#runner.instrumentData.message.push(messageOutput);
864
538
  await this.PublishTelemetry();
865
539
  };
@@ -907,12 +581,6 @@ var TestCaseFhirBase = class {
907
581
  await this.#ForcePublishTelemetryData();
908
582
  return true;
909
583
  };
910
- GetClient = async () => {
911
- let client;
912
- if (this.runner.options.fhirOptions.stsfhirsocketclientmode === "no-socket-client") client = await this.GetRESTClient();
913
- else client = await this.GetFhirSocketClient();
914
- return client;
915
- };
916
584
  _GetDetail = () => {
917
585
  return `testType: [${this.runner.options.testType}], description: [${this.runner.options.description}], workerManagerId: [${this.runner.workerManagerId}], Iteration: [${this.runner.iteration}]`;
918
586
  };
@@ -929,14 +597,6 @@ var TestCaseFhirBase = class {
929
597
  this.retryCount = 0;
930
598
  return this._ExecuteQuery();
931
599
  };
932
- _RetryMap = [
933
- 100,
934
- 250,
935
- 500,
936
- 1e3,
937
- 2e3,
938
- 3e3
939
- ];
940
600
  _ExecuteQuery = async () => {
941
601
  try {
942
602
  return await this.PerformExecuteQuery();
@@ -959,6 +619,9 @@ var TestCaseFhirBase = class {
959
619
  else throw error;
960
620
  }
961
621
  };
622
+ GetClient = async () => {
623
+ return this.runnerExecutionWorker.GetClient();
624
+ };
962
625
  };
963
626
  //#endregion
964
627
  //#region src/libmodule/testCaseFhirQueryBase.ts
@@ -1040,9 +703,9 @@ var TestCaseFhirQueryBase = class extends TestCaseFhirBase {
1040
703
  var TestCaseFhir01 = class extends TestCaseFhirQueryBase {
1041
704
  PerformExecuteQuery = async () => {
1042
705
  const __snapshot1 = performance.now();
1043
- await this.GetAccessToken();
706
+ await this.runnerExecutionWorker.GetAccessToken();
1044
707
  this._CheckOutputLongDurationError(__snapshot1, "await this.GetAccessToken()");
1045
- this.ResetAccessToken();
708
+ this.runnerExecutionWorker.ResetAccessToken();
1046
709
  return null;
1047
710
  };
1048
711
  };
@@ -36377,20 +36040,30 @@ var WorkerFhirTestCases = class extends AbstractRunnerExecutionWorker {
36377
36040
  fhirClient = void 0;
36378
36041
  _id = crypto.randomUUID();
36379
36042
  _onHoldKeys = {};
36043
+ #accesssToken = null;
36044
+ _authMaxTimeout = 5e3;
36045
+ #originRegex = /^(api:\/\/\w+)/;
36046
+ #authAgentManager;
36047
+ restFhirClient = null;
36048
+ logPrefix = `WorkerFhirTestCases:[${this._id}]:`;
36380
36049
  constructor(options) {
36381
36050
  super();
36382
36051
  this._options = options;
36383
36052
  this._resourceDataGenerator = new ResourceDataGenerator();
36053
+ this.#authAgentManager = this.GetAuthAgentManager();
36384
36054
  }
36055
+ Warning = (message) => {
36056
+ this.logger.warn(`${this.logPrefix}${message}`);
36057
+ };
36058
+ Error = (message) => {
36059
+ this.logger.error(`${this.logPrefix}${message}`);
36060
+ };
36061
+ Debug = (message) => {
36062
+ this.logger.debug(`${this.logPrefix}${message}`);
36063
+ };
36385
36064
  get id() {
36386
36065
  return this._id;
36387
36066
  }
36388
- GetFhirClient = () => {
36389
- return this.fhirClient;
36390
- };
36391
- SetFhirClient = (fhirClient) => {
36392
- this.fhirClient = fhirClient;
36393
- };
36394
36067
  get resourceDataGenerator() {
36395
36068
  return this._resourceDataGenerator;
36396
36069
  }
@@ -36401,9 +36074,9 @@ var WorkerFhirTestCases = class extends AbstractRunnerExecutionWorker {
36401
36074
  return AsyncRunnerFactory.CreateAsyncRunner(this, testRunnerTelemetryPayload);
36402
36075
  };
36403
36076
  async ProcessPreTerminateWorkerMessage(messagePayload) {
36404
- this.logger.debug(chalk.rgb(220, 100, 0)(`ProcessPreTerminateWorkerMessage: [${JSON.stringify(messagePayload, null, 2)}]`));
36077
+ this.logger.debug(chalk.rgb(220, 100, 0)(`ProcessPreTerminateWorkerMessage(): [${JSON.stringify(messagePayload, null, 2)}]`));
36405
36078
  if (this.fhirClient) {
36406
- this.logger.debug(chalk.rgb(220, 100, 0)(`ProcessPreTerminateWorkerMessage: ResetSocket()`));
36079
+ this.logger.debug(chalk.rgb(220, 100, 0)(`ProcessPreTerminateWorkerMessage(): ResetSocket()`));
36407
36080
  this.fhirClient.ResetSocket();
36408
36081
  this.fhirClient = void 0;
36409
36082
  }
@@ -36422,7 +36095,7 @@ var WorkerFhirTestCases = class extends AbstractRunnerExecutionWorker {
36422
36095
  for (;;) {
36423
36096
  if (this._onHoldKeys[holdKey]) await Sleep(100);
36424
36097
  else break;
36425
- if (performance.now() - start > timeout) throw new Error(`WaitOnHold timeout: [${timeout}] reached.`);
36098
+ if (performance.now() - start > timeout) throw new Error(`WorkerFhirTestCases:WaitOnHold(): Timeout: [${timeout}] reached.`);
36426
36099
  }
36427
36100
  return true;
36428
36101
  };
@@ -36432,6 +36105,322 @@ var WorkerFhirTestCases = class extends AbstractRunnerExecutionWorker {
36432
36105
  ReleaseOnHold = (holdKey) => {
36433
36106
  delete this._onHoldKeys[holdKey];
36434
36107
  };
36108
+ defaultAgentOptions = {
36109
+ keepAlive: true,
36110
+ maxSockets: 10,
36111
+ maxTotalSockets: 20,
36112
+ maxFreeSockets: 10,
36113
+ timeout: 6e4,
36114
+ rejectUnauthorized: false
36115
+ };
36116
+ stressTestAgentOptions = {
36117
+ keepAlive: true,
36118
+ maxSockets: 200,
36119
+ maxTotalSockets: 500,
36120
+ maxFreeSockets: 50,
36121
+ timeout: 3e4,
36122
+ rejectUnauthorized: false
36123
+ };
36124
+ stressTestExtremeAgentOptions = {
36125
+ keepAlive: true,
36126
+ maxSockets: 500,
36127
+ maxTotalSockets: 1e3,
36128
+ maxFreeSockets: 500,
36129
+ timeout: 3e4,
36130
+ rejectUnauthorized: false
36131
+ };
36132
+ GetAgentManager = (testingAgentOptions) => {
36133
+ let agentManager = void 0;
36134
+ let agentOptions = void 0;
36135
+ switch (testingAgentOptions.nodeAgentMode) {
36136
+ case "no-agent": break;
36137
+ case "custom-agent-options":
36138
+ if (testingAgentOptions.nodeAgentCustomOptions) agentOptions = { ...testingAgentOptions.nodeAgentCustomOptions };
36139
+ else agentOptions = { ...this.defaultAgentOptions };
36140
+ break;
36141
+ case "default-agent-options":
36142
+ agentOptions = { ...this.defaultAgentOptions };
36143
+ break;
36144
+ case "stress-test-agent-options":
36145
+ agentOptions = { ...this.stressTestAgentOptions };
36146
+ break;
36147
+ case "stress-test-extreme-agent-options":
36148
+ agentOptions = { ...this.stressTestExtremeAgentOptions };
36149
+ break;
36150
+ default: throw new Error(`TestCaseFhirBase:GetAgentManager(): [${this._id}] unknown nodeAgentMode: [${testingAgentOptions.nodeAgentMode}]`);
36151
+ }
36152
+ if (agentOptions) agentManager = createAgentManager({
36153
+ agentOptions,
36154
+ httpAgentFactory(options) {
36155
+ return new http.Agent(options);
36156
+ },
36157
+ httpsAgentFactory(options) {
36158
+ return new https.Agent(options);
36159
+ }
36160
+ });
36161
+ return agentManager;
36162
+ };
36163
+ GetFhirAgentManager = () => {
36164
+ return this.GetAgentManager(this._options.fhirOptions.stsfhiragentOptions);
36165
+ };
36166
+ GetAuthAgentManager = () => {
36167
+ return this.GetAgentManager(this._options.authOptions.asagentoptions);
36168
+ };
36169
+ ExtractOrigin = (uri) => {
36170
+ const match = uri.match(this.#originRegex);
36171
+ return match ? match[1] : null;
36172
+ };
36173
+ GetAPITokenFromAuthServerUsingScope = async (options) => {
36174
+ const { scope, clientId, authClientSecret, endPoint } = options;
36175
+ let stage = "1";
36176
+ try {
36177
+ stage = "2";
36178
+ const scopes = scope.split(" ");
36179
+ let origin = null;
36180
+ let error = null;
36181
+ stage = "3";
36182
+ for (let i = 0; i < scopes.length; i++) {
36183
+ const s = scopes[i];
36184
+ if (!origin) {
36185
+ origin = this.ExtractOrigin(s);
36186
+ if (!origin) {
36187
+ error = /* @__PURE__ */ new Error(`Scope: [${scope}] not in required format. Must use (space seperated) api://<client id>[/<resource>.<permission>].`);
36188
+ break;
36189
+ }
36190
+ } else {
36191
+ const nextOrigin = this.ExtractOrigin(s);
36192
+ if (!nextOrigin) {
36193
+ error = /* @__PURE__ */ new Error(`Scope: [${scope}] not in required format. Must use (space seperated) api://<client id>[/<resource>.<permission>].`);
36194
+ break;
36195
+ } else if (origin.localeCompare(nextOrigin) !== 0) {
36196
+ error = /* @__PURE__ */ new Error(`Scope: [${scope}] not all from the same client API. All scopes must come from the same client API.`);
36197
+ break;
36198
+ }
36199
+ }
36200
+ }
36201
+ stage = "4";
36202
+ if (error) throw error;
36203
+ stage = "5";
36204
+ const payload = {
36205
+ client_id: clientId,
36206
+ client_secret: authClientSecret,
36207
+ scope,
36208
+ grant_type: "client_credentials"
36209
+ };
36210
+ stage = "6";
36211
+ const url = endPoint ? `${endPoint}${this._options.authOptions.asoauthapiroot}/token` : `${this._options.authOptions.asendpoint}:${this._options.authOptions.asport}${this._options.authOptions.asoauthapiroot}/token`;
36212
+ stage = `6.5: url: [${url}] payload: [${JSON.stringify(payload)}]`;
36213
+ const axiosConfig = new STSAxiosConfig(url, "post").withDefaultHeaders().withData(payload);
36214
+ if (this.#authAgentManager) axiosConfig.withAgentManager(this.#authAgentManager);
36215
+ const retVal = await createRetryAxiosClient({
36216
+ maxRetries: 4,
36217
+ retryDelayMs: 300,
36218
+ retryJitterMs: 150,
36219
+ maxRetryDurationMs: 5e3,
36220
+ onRetryAttempt: (attempt, error, delayMs) => {
36221
+ this._options.runner.instrumentData.authenticationErrorCount++;
36222
+ this._options.runner.instrumentData.authenticationRetryCount++;
36223
+ const message = `GetAPITokenFromAuthServerUsingScope(): [${this._id}] Retry #${attempt} after ${delayMs}ms due to ${error.code || error.response?.status}`;
36224
+ this.Warning(message);
36225
+ this._options.runner.instrumentData.message.push(chalk.red(message));
36226
+ }
36227
+ })(url, axiosConfig.config);
36228
+ this._options.runner.instrumentData.authenticationCount++;
36229
+ stage = "7";
36230
+ if (retVal.status) {
36231
+ if (retVal.status !== 200) this.Warning(chalk.magenta(`GetAPITokenFromAuthServerUsingScope(): [${this._id}] Invalid response from server: [${retVal.status}]`));
36232
+ } else throw new Error(chalk.red(`No retVal.status)`));
36233
+ stage = "8";
36234
+ if (retVal.data) {
36235
+ stage = "9";
36236
+ if (retVal.data.access_token) {
36237
+ stage = "12";
36238
+ return retVal.data.access_token;
36239
+ } else {
36240
+ stage = "13";
36241
+ throw new Error(`No retVal.data.access_token)`);
36242
+ }
36243
+ } else {
36244
+ stage = "14";
36245
+ throw new Error(`No retVal.data)`);
36246
+ }
36247
+ } catch (error) {
36248
+ this.Error(error);
36249
+ let details = "None available.";
36250
+ if (error.response && error.response.data) try {
36251
+ details = JSON.stringify(error.response.data);
36252
+ } catch (error) {
36253
+ details = `Could not JSON.stringify(error.response.data)`;
36254
+ }
36255
+ error.message = `${this.logPrefix}GetAPITokenFromAuthServerUsingScope(): Error: [${error}], Stage: [${stage}], Details: [${details}]`;
36256
+ throw error;
36257
+ }
36258
+ };
36259
+ GetAccessToken = async () => {
36260
+ let timeout = void 0;
36261
+ const start = performance.now();
36262
+ try {
36263
+ if (this.#accesssToken) return this.#accesssToken;
36264
+ const lockKey = "GetAccessToken";
36265
+ const lockTimeout = 6e4;
36266
+ if (this.GetOnHold(lockKey) === true) {
36267
+ this.Debug(chalk.magenta(`GetAccessToken(): accesssToken does not exist - some other client setting up the new accesssToken (on hold/lock), lock key: [${lockKey}] - waiting ...`));
36268
+ try {
36269
+ const miniStart = performance.now();
36270
+ await this.WaitOnHold(lockKey, lockTimeout);
36271
+ this.Debug(chalk.yellow(`GetAccessToken(): hold (lock) released after: [${performance.now() - miniStart}ms], lock key: [${lockKey}]`));
36272
+ if (this.#accesssToken) {
36273
+ this.Debug(chalk.green(`GetAccessToken(): Getting existing accesssToken (post hold release), lock key: [${lockKey}]`));
36274
+ return this.#accesssToken;
36275
+ } else {
36276
+ this.Error(chalk.red(`GetAccessToken(): Could not get existing accesssToken (post hold release), lock key: [${lockKey}]`));
36277
+ this.Error(chalk.red(`GetAccessToken(): continue anyway ...`));
36278
+ }
36279
+ } catch (error) {
36280
+ this.Error(chalk.red(`GetAccessToken(): Error: [${error}]`));
36281
+ }
36282
+ }
36283
+ this.Debug(chalk.yellow(`GetAccessToken(): accesssToken does not exist - setting up new accesssToken`));
36284
+ this.Debug(chalk.yellow(`GetAccessToken(): setting hold (lock), lock key: [${lockKey}]`));
36285
+ this.SetOnHold(lockKey);
36286
+ timeout = setTimeout(() => {
36287
+ this.Warning(chalk.magenta(`GetAccessToken(): Timeout: [${this._authMaxTimeout}] exceeded for getting access token ...`));
36288
+ }, this._authMaxTimeout);
36289
+ const scopes = `api://fb6513e4-16fe-4931-bed8-33b82b404a14/_.stsfhir5:All`.split(" ").sort().join(" ");
36290
+ const authendpointUrl = `${this._options.authOptions.asendpoint}:${this._options.authOptions.asport}`;
36291
+ const workingAaccesssToken = await this.GetAPITokenFromAuthServerUsingScope({
36292
+ clientId: "d8277fce-bb48-44c2-bbf1-257fe13a444b",
36293
+ authClientSecret: "64e3ef37-c7b8-4cb1-880a-e6ad3ab36e3c",
36294
+ scope: scopes,
36295
+ endPoint: authendpointUrl
36296
+ });
36297
+ if (timeout) clearTimeout(timeout);
36298
+ const totalTime = performance.now() - start;
36299
+ if (totalTime > this._authMaxTimeout) this.Warning(chalk.magenta(`GetAccessToken(): The total time for getting the access token: [${totalTime}]`));
36300
+ this.#accesssToken = workingAaccesssToken;
36301
+ this.ReleaseOnHold(lockKey);
36302
+ this.Debug(chalk.yellow(`GetAccessToken(): release hold (lock) Time taken for get access token: [${performance.now() - start}ms]`));
36303
+ return this.#accesssToken;
36304
+ } catch (error) {
36305
+ if (timeout) clearTimeout(timeout);
36306
+ error.message = `GetAccessToken(): Error: [${error}], Duration until error: [${performance.now() - start}]`;
36307
+ this.Error(error);
36308
+ return "";
36309
+ }
36310
+ };
36311
+ GetAccessTokenForSocketClientAccess = async () => {
36312
+ const timeout = setTimeout(() => {
36313
+ this.Warning(`GetAccessTokenForSocketClientAccess(): Timeout: [${this._authMaxTimeout}] exceeded for getting access token ...`);
36314
+ }, this._authMaxTimeout);
36315
+ const start = performance.now();
36316
+ try {
36317
+ const scopes = `api://fb6513e4-16fe-4931-bed8-33b82b404a14/_.stsfhir5:SocketConnection`.split(" ").sort().join(" ");
36318
+ const authendpointUrl = `${this._options.authOptions.asendpoint}:${this._options.authOptions.asport}`;
36319
+ const retVal = await this.GetAPITokenFromAuthServerUsingScope({
36320
+ clientId: "d8277fce-bb48-44c2-bbf1-257fe13a444b",
36321
+ authClientSecret: "64e3ef37-c7b8-4cb1-880a-e6ad3ab36e3c",
36322
+ scope: scopes,
36323
+ endPoint: authendpointUrl
36324
+ });
36325
+ clearTimeout(timeout);
36326
+ const totalTime = performance.now() - start;
36327
+ if (totalTime > this._authMaxTimeout) this.Warning(chalk.magenta(`GetAccessTokenForSocketClientAccess(): The total time for getting the access token: [${totalTime}]`));
36328
+ return retVal;
36329
+ } catch (error) {
36330
+ clearTimeout(timeout);
36331
+ error.message = `GetAccessTokenForSocketClientAccess(): Error: [${error}], Duration until error: [${performance.now() - start}]`;
36332
+ this.Error(error);
36333
+ return "";
36334
+ }
36335
+ };
36336
+ ResetAccessToken = () => {
36337
+ this.#accesssToken = null;
36338
+ };
36339
+ GetFhirSocketClient = async () => {
36340
+ try {
36341
+ if (this.fhirClient) return this.fhirClient;
36342
+ const lockKey = "GetFhirSocketClient";
36343
+ const lockTimeout = 6e4;
36344
+ if (this.GetOnHold(lockKey) === true) {
36345
+ this.Debug(chalk.magenta(`GetFhirSocketClient(): fhir client does not exist - some other client setting up the new client (on hold/lock), lock key: [${lockKey}] - waiting ...`));
36346
+ try {
36347
+ const start = performance.now();
36348
+ await this.WaitOnHold(lockKey, lockTimeout);
36349
+ this.Debug(chalk.yellow(`GetFhirSocketClient(): hold (lock) released after: [${performance.now() - start}ms], lock key: [${lockKey}]`));
36350
+ if (this.fhirClient) {
36351
+ this.Debug(chalk.green(`GetFhirSocketClient(): Getting existing fhir client (post hold release), lock key: [${lockKey}]`));
36352
+ return this.fhirClient;
36353
+ } else {
36354
+ this.Error(chalk.red(`GetFhirSocketClient(): Could not get existing fhir client (post hold release), lock key: [${lockKey}]`));
36355
+ this.Error(chalk.red(`GetFhirSocketClient(): continue anyway ...`));
36356
+ }
36357
+ } catch (error) {
36358
+ this.Error(chalk.red(`GetFhirSocketClient(): Error: [${error}]`));
36359
+ }
36360
+ }
36361
+ const start = performance.now();
36362
+ this.Debug(chalk.yellow(`GetFhirSocketClient(): fhir client does not exist - setting up new client`));
36363
+ this.Debug(chalk.yellow(`GetFhirSocketClient(): setting hold (lock), lock key: [${lockKey}]`));
36364
+ this.SetOnHold(lockKey);
36365
+ const fhirOptions = this._options.fhirOptions;
36366
+ const options = {
36367
+ fhirServerEndpoint: fhirOptions.stsfhirserverendpoint,
36368
+ fhirapiroot: fhirOptions.stsfhirapiroot,
36369
+ fhirServerPort: fhirOptions.stsfhirport,
36370
+ socketClientName: fhirOptions.stsfhirsocketname,
36371
+ socketIoCustomPath: fhirOptions.stsfhirsocketcustompath,
36372
+ timeout: fhirOptions.stsfhirsockettimeout,
36373
+ baseUrl: fhirOptions.stsfhirbaseurl,
36374
+ agentManager: this.GetFhirAgentManager(),
36375
+ joinRooms: [],
36376
+ logger: this.logger,
36377
+ verboseLogging: true,
36378
+ GetConnectionAccessToken: this.GetAccessTokenForSocketClientAccess,
36379
+ GetAccessToken: this.GetAccessToken
36380
+ };
36381
+ let workingFhirClient;
36382
+ if (this._options.runner.options.fhirOptions.stsfhirsocketclientmode === "socket-client-all-in-one") workingFhirClient = new FhirSocketClientAllInOne("FhirSocketClient", options);
36383
+ else workingFhirClient = new FhirSocketClientIndividual("FhirSocketClient", options);
36384
+ await workingFhirClient.WaitForSocketConnected();
36385
+ this.Debug(chalk.yellow(`GetFhirSocketClient(): setting fhir client into object`));
36386
+ this.fhirClient = workingFhirClient;
36387
+ this.ReleaseOnHold(lockKey);
36388
+ this.Debug(chalk.yellow(`GetFhirSocketClient(): release hold (lock) Time taken for socket connection and set object: [${performance.now() - start}ms], lock key: [${lockKey}]`));
36389
+ return this.fhirClient;
36390
+ } catch (error) {
36391
+ this.Error(error);
36392
+ throw error;
36393
+ }
36394
+ };
36395
+ GetRESTClient = async () => {
36396
+ if (this.restFhirClient) return this.restFhirClient;
36397
+ const onRetryAttempt = (attempt, error, delayMs) => {
36398
+ this._options.runner.instrumentData.errorCount++;
36399
+ this._options.runner.instrumentData.requestCount++;
36400
+ const message = `TestCaseFhirBase:onRetryAttempt(): [${this._id}] Retry #${attempt} after ${delayMs}ms due to ${error.code || error.response?.status}`;
36401
+ this.Warning(message);
36402
+ this._options.runner.instrumentData.message.push(chalk.red(message));
36403
+ };
36404
+ const fhirOptions = this._options.fhirOptions;
36405
+ const fhirRESTClient = new FhirRESTClient({
36406
+ GetAccessToken: this.GetAccessToken,
36407
+ user: "USR_user01@stsmda.com.au",
36408
+ endpoint: fhirOptions.stsfhirserverendpoint,
36409
+ stsfhirapiroot: fhirOptions.stsfhirapiroot,
36410
+ stsfhirport: fhirOptions.stsfhirport,
36411
+ logger: this.logger,
36412
+ agentManager: this.GetFhirAgentManager(),
36413
+ onRetryAttempt
36414
+ });
36415
+ this.restFhirClient = fhirRESTClient;
36416
+ return fhirRESTClient;
36417
+ };
36418
+ GetClient = async () => {
36419
+ let client;
36420
+ if (this._options.runner.options.fhirOptions.stsfhirsocketclientmode === "no-socket-client") client = await this.GetRESTClient();
36421
+ else client = await this.GetFhirSocketClient();
36422
+ return client;
36423
+ };
36435
36424
  };
36436
36425
  //#endregion
36437
36426
  export { WorkerFhirTestCases };