@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.
@@ -31,16 +31,16 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
  }) : target, mod));
32
32
  //#endregion
33
33
  let _nsshunt_stsrunnerframework = require("@nsshunt/stsrunnerframework");
34
+ let _nsshunt_stsutils = require("@nsshunt/stsutils");
34
35
  let chalk = require("chalk");
35
36
  chalk = __toESM(chalk, 1);
36
- let _nsshunt_stsutils = require("@nsshunt/stsutils");
37
+ let axios = require("axios");
38
+ axios = __toESM(axios, 1);
37
39
  let _nsshunt_stsfhirclient = require("@nsshunt/stsfhirclient");
38
40
  let node_http = require("node:http");
39
41
  node_http = __toESM(node_http, 1);
40
42
  let node_https = require("node:https");
41
43
  node_https = __toESM(node_https, 1);
42
- let axios = require("axios");
43
- axios = __toESM(axios, 1);
44
44
  //#region node_modules/http-status-codes/build/es/status-codes.js
45
45
  var StatusCodes;
46
46
  (function(StatusCodes) {
@@ -403,190 +403,40 @@ var StatusCodes;
403
403
  //#region src/libmodule/testCaseFhirBase.ts
404
404
  var TestCaseFhirBase = class {
405
405
  #options;
406
- #randomDataRecordset = [];
407
406
  #runner;
408
407
  #runnerExecutionWorker;
409
- #accesssToken = null;
410
408
  #publishTelemetryCount = 0;
411
409
  #maxBufferSize = 50;
412
410
  #publishTelemetryTimeout = null;
413
411
  #publishTelemetryTimeoutVal = 1e3;
414
- #originRegex = /^(api:\/\/\w+)/;
415
- #resetSocketClientTrigger = 50;
416
- #clientSocketFetchCount = 0;
417
- #authAgentManager;
412
+ _RetryMap = [
413
+ 100,
414
+ 250,
415
+ 500,
416
+ 1e3,
417
+ 2e3,
418
+ 3e3
419
+ ];
418
420
  _id = crypto.randomUUID();
419
421
  retryCount = 0;
420
422
  maxAuthRetryCount = 5;
421
423
  runnerDurationList = [];
422
- _authMaxTimeout = 5e3;
423
- accessTokenTime = performance.now();
424
- newTokenLimitTime = 30;
425
- restFhirClient = null;
426
- defaultAgentOptions = {
427
- keepAlive: true,
428
- maxSockets: 10,
429
- maxTotalSockets: 20,
430
- maxFreeSockets: 10,
431
- timeout: 6e4,
432
- rejectUnauthorized: false
433
- };
434
- stressTestAgentOptions = {
435
- keepAlive: true,
436
- maxSockets: 200,
437
- maxTotalSockets: 500,
438
- maxFreeSockets: 50,
439
- timeout: 3e4,
440
- rejectUnauthorized: false
441
- };
442
- stressTestExtremeAgentOptions = {
443
- keepAlive: true,
444
- maxSockets: 500,
445
- maxTotalSockets: 1e3,
446
- maxFreeSockets: 500,
447
- timeout: 3e4,
448
- rejectUnauthorized: false
449
- };
450
424
  constructor(runnerExecutionWorker, runner) {
451
425
  this.#options = runner.options;
452
426
  this.#runnerExecutionWorker = runnerExecutionWorker;
453
427
  this.#runner = runner;
454
- this.#authAgentManager = this.GetAuthAgentManager();
455
428
  }
456
429
  get runnerExecutionWorker() {
457
430
  return this.#runnerExecutionWorker;
458
431
  }
459
432
  ResetClient = () => {};
460
- GetRESTClient = async () => {
461
- if (this.restFhirClient) return this.restFhirClient;
462
- const onRetryAttempt = (attempt, error, delayMs) => {
463
- this.#runner.instrumentData.errorCount++;
464
- this.#runner.instrumentData.requestCount++;
465
- const message = `TestCaseFhirBase:onRetryAttempt(): [${this._id}] Retry #${attempt} after ${delayMs}ms due to ${error.code || error.response?.status}`;
466
- this.Warning(message);
467
- this.#runner.instrumentData.message.push(chalk.default.red(message));
468
- };
469
- const fhirOptions = this.#options.fhirOptions;
470
- const fhirRESTClient = new _nsshunt_stsfhirclient.FhirRESTClient({
471
- GetAccessToken: this.GetAccessToken,
472
- user: "USR_user01@stsmda.com.au",
473
- endpoint: fhirOptions.stsfhirserverendpoint,
474
- stsfhirapiroot: fhirOptions.stsfhirapiroot,
475
- stsfhirport: fhirOptions.stsfhirport,
476
- logger: this.#runnerExecutionWorker.logger,
477
- agentManager: this.GetFhirAgentManager(),
478
- onRetryAttempt
479
- });
480
- this.restFhirClient = fhirRESTClient;
481
- return fhirRESTClient;
482
- };
483
- GetAgentManager = (testingAgentOptions) => {
484
- let agentManager = void 0;
485
- let agentOptions = void 0;
486
- switch (testingAgentOptions.nodeAgentMode) {
487
- case "no-agent": break;
488
- case "custom-agent-options":
489
- if (testingAgentOptions.nodeAgentCustomOptions) agentOptions = { ...testingAgentOptions.nodeAgentCustomOptions };
490
- else agentOptions = { ...this.defaultAgentOptions };
491
- break;
492
- case "default-agent-options":
493
- agentOptions = { ...this.defaultAgentOptions };
494
- break;
495
- case "stress-test-agent-options":
496
- agentOptions = { ...this.stressTestAgentOptions };
497
- break;
498
- case "stress-test-extreme-agent-options":
499
- agentOptions = { ...this.stressTestExtremeAgentOptions };
500
- break;
501
- default: throw new Error(`TestCaseFhirBase:GetAgentManager(): [${this._id}] unknown nodeAgentMode: [${testingAgentOptions.nodeAgentMode}]`);
502
- }
503
- if (agentOptions) agentManager = (0, _nsshunt_stsutils.createAgentManager)({
504
- agentOptions,
505
- httpAgentFactory(options) {
506
- return new node_http.default.Agent(options);
507
- },
508
- httpsAgentFactory(options) {
509
- return new node_https.default.Agent(options);
510
- }
511
- });
512
- return agentManager;
513
- };
514
- GetFhirAgentManager = () => {
515
- return this.GetAgentManager(this.#options.fhirOptions.stsfhiragentOptions);
516
- };
517
- GetAuthAgentManager = () => {
518
- return this.GetAgentManager(this.#options.authOptions.asagentoptions);
519
- };
520
- GetFhirSocketClient = async () => {
521
- try {
522
- this.#clientSocketFetchCount++;
523
- let fhirClient = this.runnerExecutionWorker.GetFhirClient();
524
- if (fhirClient) return fhirClient;
525
- if (this.runnerExecutionWorker.GetOnHold("fhirclient") === true) {
526
- this.Debug(chalk.default.magenta(`[${this.runnerExecutionWorker.id}] [${this._id}] fhir client does not exist - some other client setting up the new client (on hold/lock) - waiting ...`));
527
- try {
528
- const start = performance.now();
529
- await this.runnerExecutionWorker.WaitOnHold("fhirclient", 6e4);
530
- this.Debug(chalk.default.yellow(`[${this.runnerExecutionWorker.id}] [${this._id}] hold (lock) released after: [${performance.now() - start}ms]`));
531
- const fhirClient = this.runnerExecutionWorker.GetFhirClient();
532
- if (fhirClient) {
533
- this.Debug(chalk.default.green(`[${this.runnerExecutionWorker.id}] [${this._id}] Getting existing fhir client (post hold release)`));
534
- return fhirClient;
535
- } else {
536
- this.Error(chalk.default.red(`[${this.runnerExecutionWorker.id}] [${this._id}] Could not get existing fhir client (post hold release)`));
537
- this.Error(chalk.default.red(`continue anyway ...`));
538
- }
539
- } catch (error) {
540
- this.Error(chalk.default.red(`GetFhirSocketClient(): Error: [${error}]`));
541
- }
542
- }
543
- const start = performance.now();
544
- this.Debug(chalk.default.yellow(`[${this.runnerExecutionWorker.id}] [${this._id}] fhir client does not exist - setting up new client`));
545
- this.Debug(chalk.default.yellow(`[${this.runnerExecutionWorker.id}] [${this._id}] setting hold (lock)`));
546
- this.runnerExecutionWorker.SetOnHold("fhirclient");
547
- const fhirOptions = this.#options.fhirOptions;
548
- const options = {
549
- fhirServerEndpoint: fhirOptions.stsfhirserverendpoint,
550
- fhirapiroot: fhirOptions.stsfhirapiroot,
551
- fhirServerPort: fhirOptions.stsfhirport,
552
- socketClientName: fhirOptions.stsfhirsocketname,
553
- socketIoCustomPath: fhirOptions.stsfhirsocketcustompath,
554
- timeout: fhirOptions.stsfhirsockettimeout,
555
- baseUrl: fhirOptions.stsfhirbaseurl,
556
- agentManager: this.GetFhirAgentManager(),
557
- joinRooms: [],
558
- logger: this.#runnerExecutionWorker.logger,
559
- verboseLogging: true,
560
- GetConnectionAccessToken: this.GetAccessTokenForSocketClientAccess,
561
- GetAccessToken: this.GetAccessToken
562
- };
563
- if (this.runner.options.fhirOptions.stsfhirsocketclientmode === "socket-client-all-in-one") fhirClient = new _nsshunt_stsfhirclient.FhirSocketClientAllInOne("FhirSocketClient", options);
564
- else fhirClient = new _nsshunt_stsfhirclient.FhirSocketClientIndividual("FhirSocketClient", options);
565
- await fhirClient.WaitForSocketConnected();
566
- this.Debug(chalk.default.yellow(`[${this.runnerExecutionWorker.id}] [${this._id}] setting fhir client into object`));
567
- this.runnerExecutionWorker.SetFhirClient(fhirClient);
568
- this.runnerExecutionWorker.ReleaseOnHold("fhirclient");
569
- this.Debug(chalk.default.yellow(`[${this.runnerExecutionWorker.id}] [${this._id}] release hold (lock) Time taken for socket connection and set object: [${performance.now() - start}ms]`));
570
- return fhirClient;
571
- } catch (error) {
572
- this.Error(error);
573
- throw error;
574
- }
575
- };
576
- #LogMessage = (message) => {};
577
- Debug = (message) => {
578
- this.#runnerExecutionWorker.logger.debug(message);
579
- };
580
433
  Error = (message) => {
581
434
  this.#runnerExecutionWorker.logger.error(message);
582
435
  this.#runner.instrumentData.message.push(chalk.default.red(`${message}`));
583
436
  };
584
- Warning = (message) => {
585
- this.#runnerExecutionWorker.logger.warn(message);
437
+ Debug = (message) => {
438
+ this.#runnerExecutionWorker.logger.debug(message);
586
439
  };
587
- get accesssToken() {
588
- return this.#accesssToken;
589
- }
590
440
  get runner() {
591
441
  return this.#runner;
592
442
  }
@@ -629,125 +479,6 @@ var TestCaseFhirBase = class {
629
479
  this.#runner.instrumentData.rx = 0;
630
480
  await this.SleepImmediate();
631
481
  };
632
- ExtractOrigin = (uri) => {
633
- const match = uri.match(this.#originRegex);
634
- return match ? match[1] : null;
635
- };
636
- GetAPITokenFromAuthServerUsingScope = async (options) => {
637
- const { scope, clientId, authClientSecret, endPoint } = options;
638
- let stage = "1";
639
- try {
640
- stage = "2";
641
- const scopes = scope.split(" ");
642
- let origin = null;
643
- let error = null;
644
- stage = "3";
645
- for (let i = 0; i < scopes.length; i++) {
646
- const s = scopes[i];
647
- if (!origin) {
648
- origin = this.ExtractOrigin(s);
649
- if (!origin) {
650
- error = /* @__PURE__ */ new Error(`Scope: [${scope}] not in required format. Must use (space seperated) api://<client id>[/<resource>.<permission>].`);
651
- break;
652
- }
653
- } else {
654
- const nextOrigin = this.ExtractOrigin(s);
655
- if (!nextOrigin) {
656
- error = /* @__PURE__ */ new Error(`Scope: [${scope}] not in required format. Must use (space seperated) api://<client id>[/<resource>.<permission>].`);
657
- break;
658
- } else if (origin.localeCompare(nextOrigin) !== 0) {
659
- error = /* @__PURE__ */ new Error(`Scope: [${scope}] not all from the same client API. All scopes must come from the same client API.`);
660
- break;
661
- }
662
- }
663
- }
664
- stage = "4";
665
- if (error) throw error;
666
- stage = "5";
667
- const payload = {
668
- client_id: clientId,
669
- client_secret: authClientSecret,
670
- scope,
671
- grant_type: "client_credentials"
672
- };
673
- stage = "6";
674
- const url = endPoint ? `${endPoint}${this.#options.authOptions.asoauthapiroot}/token` : `${this.#options.authOptions.asendpoint}:${this.#options.authOptions.asport}${this.#options.authOptions.asoauthapiroot}/token`;
675
- stage = `6.5: url: [${url}] payload: [${JSON.stringify(payload)}]`;
676
- const axiosConfig = new _nsshunt_stsutils.STSAxiosConfig(url, "post").withDefaultHeaders().withData(payload);
677
- if (this.#authAgentManager) axiosConfig.withAgentManager(this.#authAgentManager);
678
- const retVal = await (0, _nsshunt_stsfhirclient.createRetryAxiosClient)({
679
- maxRetries: 4,
680
- retryDelayMs: 300,
681
- retryJitterMs: 150,
682
- maxRetryDurationMs: 5e3,
683
- onRetryAttempt: (attempt, error, delayMs) => {
684
- this.#runner.instrumentData.authenticationErrorCount++;
685
- this.#runner.instrumentData.authenticationRetryCount++;
686
- const message = `TestCaseFhirBase:GetAPITokenFromAuthServerUsingScope(): [${this._id}] Retry #${attempt} after ${delayMs}ms due to ${error.code || error.response?.status}`;
687
- this.Warning(message);
688
- this.#runner.instrumentData.message.push(chalk.default.red(message));
689
- }
690
- })(url, axiosConfig.config);
691
- this.#runner.instrumentData.authenticationCount++;
692
- stage = "7";
693
- if (retVal.status) {
694
- if (retVal.status !== 200) this.Warning(chalk.default.magenta(`TestCaseFhirBase:GetAPITokenFromAuthServerUsingScope(): [${this._id}] Invalid response from server: [${retVal.status}]`));
695
- } else throw new Error(chalk.default.red(`No retVal.status)`));
696
- stage = "8";
697
- if (retVal.data) {
698
- stage = "9";
699
- if (retVal.data.access_token) {
700
- stage = "12";
701
- return retVal.data.access_token;
702
- } else {
703
- stage = "13";
704
- throw new Error(`No retVal.data.access_token)`);
705
- }
706
- } else {
707
- stage = "14";
708
- throw new Error(`No retVal.data)`);
709
- }
710
- } catch (error) {
711
- this.Error(error);
712
- let details = "None available.";
713
- if (error.response && error.response.data) try {
714
- details = JSON.stringify(error.response.data);
715
- } catch (error) {
716
- details = `Could not JSON.stringify(error.response.data)`;
717
- }
718
- error.message = `TestCaseFhirBase:GetAPITokenFromAuthServerUsingScope(): [${this._id}] Error: [${error}], Stage: [${stage}], Details: [${details}]`;
719
- throw error;
720
- }
721
- };
722
- GetAccessTokenForSocketClientAccess = async () => {
723
- const timeout = setTimeout(() => {
724
- this.Warning(`TestCaseFhirBase:GetAccessTokenForSocketClientAccess(): [${this._id}] Timeout: [${this._authMaxTimeout}] exceeded for getting access token ...`);
725
- }, this._authMaxTimeout);
726
- const start = performance.now();
727
- try {
728
- const scopes = `api://fb6513e4-16fe-4931-bed8-33b82b404a14/_.stsfhir5:SocketConnection`.split(" ").sort().join(" ");
729
- const authendpointUrl = `${this.#options.authOptions.asendpoint}:${this.#options.authOptions.asport}`;
730
- const retVal = await this.GetAPITokenFromAuthServerUsingScope({
731
- clientId: "d8277fce-bb48-44c2-bbf1-257fe13a444b",
732
- authClientSecret: "64e3ef37-c7b8-4cb1-880a-e6ad3ab36e3c",
733
- scope: scopes,
734
- endPoint: authendpointUrl
735
- });
736
- clearTimeout(timeout);
737
- const totalTime = performance.now() - start;
738
- if (totalTime > this._authMaxTimeout) this.Warning(chalk.default.magenta(`TestCaseFhirBase:GetAccessTokenForSocketClientAccess(): [${this._id}] The total time for getting the access token: [${totalTime}]`));
739
- return retVal;
740
- } catch (error) {
741
- clearTimeout(timeout);
742
- const totalTime = performance.now() - start;
743
- error.message = `TestCaseFhirBase:GetAccessTokenForSocketClientAccess(): [${this._id}] Error: [${error}], Duration until error: [${totalTime}]`;
744
- this.Error(error);
745
- return "";
746
- }
747
- };
748
- ResetAccessToken = () => {
749
- this.#accesssToken = null;
750
- };
751
482
  HandleError = (error) => {
752
483
  this.Error(chalk.default.red(`TestCaseFhirBase:HandleError(): [${this._id}] Error: [${error}]`));
753
484
  this.Error(chalk.default.red(`TestCaseFhirBase:HandleError(): [${this._id}] description: [${this.runner.options.description}]`));
@@ -762,48 +493,18 @@ var TestCaseFhirBase = class {
762
493
  if (axiosError.response.status === StatusCodes.UNAUTHORIZED) {
763
494
  this.runner.instrumentData.authenticationErrorCount++;
764
495
  this.Error(chalk.default.red(`TestCaseFhirBase:HandleError(): [${this._id}] UNAUTHORIZED - Reset Access Token`));
765
- this.ResetAccessToken();
496
+ this.runnerExecutionWorker.ResetAccessToken();
766
497
  return true;
767
498
  }
768
499
  } else this.Error(chalk.default.red(`TestCaseFhirBase:HandleError(): [${this._id}] AXIOS Error = [${axiosError}]`));
769
500
  } else if (error.message === "UNAUTHORIZED") {
770
501
  this.runner.instrumentData.authenticationErrorCount++;
771
502
  this.Error(chalk.default.red(`TestCaseFhirBase:HandleError(): [${this._id}] UNAUTHORIZED - Reset Access Token`));
772
- this.ResetAccessToken();
503
+ this.runnerExecutionWorker.ResetAccessToken();
773
504
  return true;
774
505
  }
775
506
  return false;
776
507
  };
777
- GetAccessToken = async () => {
778
- let timeout = void 0;
779
- let start = performance.now();
780
- try {
781
- if (this.#accesssToken) return this.#accesssToken;
782
- timeout = setTimeout(() => {
783
- this.Warning(chalk.default.magenta(`TestCaseFhirBase:GetAccessToken(): [${this._id}] Timeout: [${this._authMaxTimeout}] exceeded for getting access token ...`));
784
- }, this._authMaxTimeout);
785
- const scopes = `api://fb6513e4-16fe-4931-bed8-33b82b404a14/_.stsfhir5:All`.split(" ").sort().join(" ");
786
- const authendpointUrl = `${this.#options.authOptions.asendpoint}:${this.#options.authOptions.asport}`;
787
- const retVal = await this.GetAPITokenFromAuthServerUsingScope({
788
- clientId: "d8277fce-bb48-44c2-bbf1-257fe13a444b",
789
- authClientSecret: "64e3ef37-c7b8-4cb1-880a-e6ad3ab36e3c",
790
- scope: scopes,
791
- endPoint: authendpointUrl
792
- });
793
- this.accessTokenTime = performance.now();
794
- this.#accesssToken = retVal;
795
- if (timeout) clearTimeout(timeout);
796
- const totalTime = performance.now() - start;
797
- if (totalTime > this._authMaxTimeout) this.Warning(chalk.default.magenta(`TestCaseFhirBase:GetAccessToken(): [${this._id}] The total time for getting the access token: [${totalTime}]`));
798
- return retVal;
799
- } catch (error) {
800
- if (timeout) clearTimeout(timeout);
801
- const totalTime = performance.now() - start;
802
- error.message = `TestCaseFhirBase:GetAccessToken(): [${this._id}] Error: [${error}], Duration until error: [${totalTime}]`;
803
- this.Error(error);
804
- return "";
805
- }
806
- };
807
508
  GetPersonRecord = async (prefix, index, version) => {
808
509
  const { workerIndex, runnerIndex, runId } = this.#options;
809
510
  const useId = `${prefix}-${index}`;
@@ -830,37 +531,12 @@ var TestCaseFhirBase = class {
830
531
  }
831
532
  };
832
533
  };
833
- StartTestDataLoad = async () => {
834
- this.Debug(chalk.default.magenta(`StartTestDataLoad(): Start ...`));
835
- let VU = 0;
836
- const blockNum = VU * 200;
837
- const blocksToLoad = 20;
838
- for (let i = 0; i < blocksToLoad; i++) {
839
- const recordId = `stsres_${blockNum + i}`;
840
- const retVal = await (await this.GetFhirSocketClient()).GetResource("Person", recordId);
841
- if (retVal) {
842
- const recordsetData = retVal.body.address;
843
- if (recordsetData) {
844
- const qqq = recordsetData[0].text;
845
- for (let j = 0; j < qqq.length; j++) this.#randomDataRecordset.push(qqq[j]);
846
- this.Error(chalk.default.magenta(this.#randomDataRecordset.length));
847
- }
848
- } else this.Error(chalk.default.magenta(`StartTestDataLoad(): Could not get person records.`));
849
- await (0, _nsshunt_stsutils.Sleep)(10);
850
- }
851
- this.Debug(`Finished load for VU: [${VU}]`);
852
- this.Debug(`First 10 entries`);
853
- for (let i = 0; i < 10; i++) this.Debug(this.#randomDataRecordset[i].id);
854
- this.Debug(`block num: [${blockNum}] length: [${this.#randomDataRecordset.length}] VU: [${VU}]`);
855
- this.Debug(chalk.default.magenta(`StartTestDataLoad(): End`));
856
- };
857
534
  #ForcePublishTelemetryData = async () => {
858
535
  await this.#PublishTelemetryData();
859
536
  };
860
537
  #SetupTimeout = async () => {
861
538
  if (!this.#publishTelemetryTimeout) {
862
539
  this.#publishTelemetryTimeout = setTimeout(async () => {
863
- this.#LogMessage(chalk.default.yellow(` **** TIMEOUT **** `));
864
540
  await this.#PublishTelemetryData();
865
541
  this.#publishTelemetryCount = 0;
866
542
  this.#publishTelemetryTimeout = null;
@@ -870,7 +546,6 @@ var TestCaseFhirBase = class {
870
546
  };
871
547
  PublishTelemetry = async () => {
872
548
  this.#publishTelemetryCount++;
873
- this.#LogMessage(chalk.default.red(this.#publishTelemetryCount));
874
549
  if (this.#publishTelemetryCount % this.#maxBufferSize === 0) {
875
550
  this.#publishTelemetryCount = 0;
876
551
  if (this.#publishTelemetryTimeout) {
@@ -883,7 +558,6 @@ var TestCaseFhirBase = class {
883
558
  };
884
559
  #OutputLogMessage = async (message) => {
885
560
  const messageOutput = chalk.default.grey(message);
886
- this.#LogMessage(messageOutput);
887
561
  this.#runner.instrumentData.message.push(messageOutput);
888
562
  await this.PublishTelemetry();
889
563
  };
@@ -931,12 +605,6 @@ var TestCaseFhirBase = class {
931
605
  await this.#ForcePublishTelemetryData();
932
606
  return true;
933
607
  };
934
- GetClient = async () => {
935
- let client;
936
- if (this.runner.options.fhirOptions.stsfhirsocketclientmode === "no-socket-client") client = await this.GetRESTClient();
937
- else client = await this.GetFhirSocketClient();
938
- return client;
939
- };
940
608
  _GetDetail = () => {
941
609
  return `testType: [${this.runner.options.testType}], description: [${this.runner.options.description}], workerManagerId: [${this.runner.workerManagerId}], Iteration: [${this.runner.iteration}]`;
942
610
  };
@@ -953,14 +621,6 @@ var TestCaseFhirBase = class {
953
621
  this.retryCount = 0;
954
622
  return this._ExecuteQuery();
955
623
  };
956
- _RetryMap = [
957
- 100,
958
- 250,
959
- 500,
960
- 1e3,
961
- 2e3,
962
- 3e3
963
- ];
964
624
  _ExecuteQuery = async () => {
965
625
  try {
966
626
  return await this.PerformExecuteQuery();
@@ -983,6 +643,9 @@ var TestCaseFhirBase = class {
983
643
  else throw error;
984
644
  }
985
645
  };
646
+ GetClient = async () => {
647
+ return this.runnerExecutionWorker.GetClient();
648
+ };
986
649
  };
987
650
  //#endregion
988
651
  //#region src/libmodule/testCaseFhirQueryBase.ts
@@ -1064,9 +727,9 @@ var TestCaseFhirQueryBase = class extends TestCaseFhirBase {
1064
727
  var TestCaseFhir01 = class extends TestCaseFhirQueryBase {
1065
728
  PerformExecuteQuery = async () => {
1066
729
  const __snapshot1 = performance.now();
1067
- await this.GetAccessToken();
730
+ await this.runnerExecutionWorker.GetAccessToken();
1068
731
  this._CheckOutputLongDurationError(__snapshot1, "await this.GetAccessToken()");
1069
- this.ResetAccessToken();
732
+ this.runnerExecutionWorker.ResetAccessToken();
1070
733
  return null;
1071
734
  };
1072
735
  };
@@ -36401,20 +36064,30 @@ var WorkerFhirTestCases = class extends _nsshunt_stsrunnerframework.AbstractRunn
36401
36064
  fhirClient = void 0;
36402
36065
  _id = crypto.randomUUID();
36403
36066
  _onHoldKeys = {};
36067
+ #accesssToken = null;
36068
+ _authMaxTimeout = 5e3;
36069
+ #originRegex = /^(api:\/\/\w+)/;
36070
+ #authAgentManager;
36071
+ restFhirClient = null;
36072
+ logPrefix = `WorkerFhirTestCases:[${this._id}]:`;
36404
36073
  constructor(options) {
36405
36074
  super();
36406
36075
  this._options = options;
36407
36076
  this._resourceDataGenerator = new ResourceDataGenerator();
36077
+ this.#authAgentManager = this.GetAuthAgentManager();
36408
36078
  }
36079
+ Warning = (message) => {
36080
+ this.logger.warn(`${this.logPrefix}${message}`);
36081
+ };
36082
+ Error = (message) => {
36083
+ this.logger.error(`${this.logPrefix}${message}`);
36084
+ };
36085
+ Debug = (message) => {
36086
+ this.logger.debug(`${this.logPrefix}${message}`);
36087
+ };
36409
36088
  get id() {
36410
36089
  return this._id;
36411
36090
  }
36412
- GetFhirClient = () => {
36413
- return this.fhirClient;
36414
- };
36415
- SetFhirClient = (fhirClient) => {
36416
- this.fhirClient = fhirClient;
36417
- };
36418
36091
  get resourceDataGenerator() {
36419
36092
  return this._resourceDataGenerator;
36420
36093
  }
@@ -36425,9 +36098,9 @@ var WorkerFhirTestCases = class extends _nsshunt_stsrunnerframework.AbstractRunn
36425
36098
  return AsyncRunnerFactory.CreateAsyncRunner(this, testRunnerTelemetryPayload);
36426
36099
  };
36427
36100
  async ProcessPreTerminateWorkerMessage(messagePayload) {
36428
- this.logger.debug(chalk.default.rgb(220, 100, 0)(`ProcessPreTerminateWorkerMessage: [${JSON.stringify(messagePayload, null, 2)}]`));
36101
+ this.logger.debug(chalk.default.rgb(220, 100, 0)(`ProcessPreTerminateWorkerMessage(): [${JSON.stringify(messagePayload, null, 2)}]`));
36429
36102
  if (this.fhirClient) {
36430
- this.logger.debug(chalk.default.rgb(220, 100, 0)(`ProcessPreTerminateWorkerMessage: ResetSocket()`));
36103
+ this.logger.debug(chalk.default.rgb(220, 100, 0)(`ProcessPreTerminateWorkerMessage(): ResetSocket()`));
36431
36104
  this.fhirClient.ResetSocket();
36432
36105
  this.fhirClient = void 0;
36433
36106
  }
@@ -36446,7 +36119,7 @@ var WorkerFhirTestCases = class extends _nsshunt_stsrunnerframework.AbstractRunn
36446
36119
  for (;;) {
36447
36120
  if (this._onHoldKeys[holdKey]) await (0, _nsshunt_stsutils.Sleep)(100);
36448
36121
  else break;
36449
- if (performance.now() - start > timeout) throw new Error(`WaitOnHold timeout: [${timeout}] reached.`);
36122
+ if (performance.now() - start > timeout) throw new Error(`WorkerFhirTestCases:WaitOnHold(): Timeout: [${timeout}] reached.`);
36450
36123
  }
36451
36124
  return true;
36452
36125
  };
@@ -36456,6 +36129,322 @@ var WorkerFhirTestCases = class extends _nsshunt_stsrunnerframework.AbstractRunn
36456
36129
  ReleaseOnHold = (holdKey) => {
36457
36130
  delete this._onHoldKeys[holdKey];
36458
36131
  };
36132
+ defaultAgentOptions = {
36133
+ keepAlive: true,
36134
+ maxSockets: 10,
36135
+ maxTotalSockets: 20,
36136
+ maxFreeSockets: 10,
36137
+ timeout: 6e4,
36138
+ rejectUnauthorized: false
36139
+ };
36140
+ stressTestAgentOptions = {
36141
+ keepAlive: true,
36142
+ maxSockets: 200,
36143
+ maxTotalSockets: 500,
36144
+ maxFreeSockets: 50,
36145
+ timeout: 3e4,
36146
+ rejectUnauthorized: false
36147
+ };
36148
+ stressTestExtremeAgentOptions = {
36149
+ keepAlive: true,
36150
+ maxSockets: 500,
36151
+ maxTotalSockets: 1e3,
36152
+ maxFreeSockets: 500,
36153
+ timeout: 3e4,
36154
+ rejectUnauthorized: false
36155
+ };
36156
+ GetAgentManager = (testingAgentOptions) => {
36157
+ let agentManager = void 0;
36158
+ let agentOptions = void 0;
36159
+ switch (testingAgentOptions.nodeAgentMode) {
36160
+ case "no-agent": break;
36161
+ case "custom-agent-options":
36162
+ if (testingAgentOptions.nodeAgentCustomOptions) agentOptions = { ...testingAgentOptions.nodeAgentCustomOptions };
36163
+ else agentOptions = { ...this.defaultAgentOptions };
36164
+ break;
36165
+ case "default-agent-options":
36166
+ agentOptions = { ...this.defaultAgentOptions };
36167
+ break;
36168
+ case "stress-test-agent-options":
36169
+ agentOptions = { ...this.stressTestAgentOptions };
36170
+ break;
36171
+ case "stress-test-extreme-agent-options":
36172
+ agentOptions = { ...this.stressTestExtremeAgentOptions };
36173
+ break;
36174
+ default: throw new Error(`TestCaseFhirBase:GetAgentManager(): [${this._id}] unknown nodeAgentMode: [${testingAgentOptions.nodeAgentMode}]`);
36175
+ }
36176
+ if (agentOptions) agentManager = (0, _nsshunt_stsutils.createAgentManager)({
36177
+ agentOptions,
36178
+ httpAgentFactory(options) {
36179
+ return new node_http.default.Agent(options);
36180
+ },
36181
+ httpsAgentFactory(options) {
36182
+ return new node_https.default.Agent(options);
36183
+ }
36184
+ });
36185
+ return agentManager;
36186
+ };
36187
+ GetFhirAgentManager = () => {
36188
+ return this.GetAgentManager(this._options.fhirOptions.stsfhiragentOptions);
36189
+ };
36190
+ GetAuthAgentManager = () => {
36191
+ return this.GetAgentManager(this._options.authOptions.asagentoptions);
36192
+ };
36193
+ ExtractOrigin = (uri) => {
36194
+ const match = uri.match(this.#originRegex);
36195
+ return match ? match[1] : null;
36196
+ };
36197
+ GetAPITokenFromAuthServerUsingScope = async (options) => {
36198
+ const { scope, clientId, authClientSecret, endPoint } = options;
36199
+ let stage = "1";
36200
+ try {
36201
+ stage = "2";
36202
+ const scopes = scope.split(" ");
36203
+ let origin = null;
36204
+ let error = null;
36205
+ stage = "3";
36206
+ for (let i = 0; i < scopes.length; i++) {
36207
+ const s = scopes[i];
36208
+ if (!origin) {
36209
+ origin = this.ExtractOrigin(s);
36210
+ if (!origin) {
36211
+ error = /* @__PURE__ */ new Error(`Scope: [${scope}] not in required format. Must use (space seperated) api://<client id>[/<resource>.<permission>].`);
36212
+ break;
36213
+ }
36214
+ } else {
36215
+ const nextOrigin = this.ExtractOrigin(s);
36216
+ if (!nextOrigin) {
36217
+ error = /* @__PURE__ */ new Error(`Scope: [${scope}] not in required format. Must use (space seperated) api://<client id>[/<resource>.<permission>].`);
36218
+ break;
36219
+ } else if (origin.localeCompare(nextOrigin) !== 0) {
36220
+ error = /* @__PURE__ */ new Error(`Scope: [${scope}] not all from the same client API. All scopes must come from the same client API.`);
36221
+ break;
36222
+ }
36223
+ }
36224
+ }
36225
+ stage = "4";
36226
+ if (error) throw error;
36227
+ stage = "5";
36228
+ const payload = {
36229
+ client_id: clientId,
36230
+ client_secret: authClientSecret,
36231
+ scope,
36232
+ grant_type: "client_credentials"
36233
+ };
36234
+ stage = "6";
36235
+ const url = endPoint ? `${endPoint}${this._options.authOptions.asoauthapiroot}/token` : `${this._options.authOptions.asendpoint}:${this._options.authOptions.asport}${this._options.authOptions.asoauthapiroot}/token`;
36236
+ stage = `6.5: url: [${url}] payload: [${JSON.stringify(payload)}]`;
36237
+ const axiosConfig = new _nsshunt_stsutils.STSAxiosConfig(url, "post").withDefaultHeaders().withData(payload);
36238
+ if (this.#authAgentManager) axiosConfig.withAgentManager(this.#authAgentManager);
36239
+ const retVal = await (0, _nsshunt_stsfhirclient.createRetryAxiosClient)({
36240
+ maxRetries: 4,
36241
+ retryDelayMs: 300,
36242
+ retryJitterMs: 150,
36243
+ maxRetryDurationMs: 5e3,
36244
+ onRetryAttempt: (attempt, error, delayMs) => {
36245
+ this._options.runner.instrumentData.authenticationErrorCount++;
36246
+ this._options.runner.instrumentData.authenticationRetryCount++;
36247
+ const message = `GetAPITokenFromAuthServerUsingScope(): [${this._id}] Retry #${attempt} after ${delayMs}ms due to ${error.code || error.response?.status}`;
36248
+ this.Warning(message);
36249
+ this._options.runner.instrumentData.message.push(chalk.default.red(message));
36250
+ }
36251
+ })(url, axiosConfig.config);
36252
+ this._options.runner.instrumentData.authenticationCount++;
36253
+ stage = "7";
36254
+ if (retVal.status) {
36255
+ if (retVal.status !== 200) this.Warning(chalk.default.magenta(`GetAPITokenFromAuthServerUsingScope(): [${this._id}] Invalid response from server: [${retVal.status}]`));
36256
+ } else throw new Error(chalk.default.red(`No retVal.status)`));
36257
+ stage = "8";
36258
+ if (retVal.data) {
36259
+ stage = "9";
36260
+ if (retVal.data.access_token) {
36261
+ stage = "12";
36262
+ return retVal.data.access_token;
36263
+ } else {
36264
+ stage = "13";
36265
+ throw new Error(`No retVal.data.access_token)`);
36266
+ }
36267
+ } else {
36268
+ stage = "14";
36269
+ throw new Error(`No retVal.data)`);
36270
+ }
36271
+ } catch (error) {
36272
+ this.Error(error);
36273
+ let details = "None available.";
36274
+ if (error.response && error.response.data) try {
36275
+ details = JSON.stringify(error.response.data);
36276
+ } catch (error) {
36277
+ details = `Could not JSON.stringify(error.response.data)`;
36278
+ }
36279
+ error.message = `${this.logPrefix}GetAPITokenFromAuthServerUsingScope(): Error: [${error}], Stage: [${stage}], Details: [${details}]`;
36280
+ throw error;
36281
+ }
36282
+ };
36283
+ GetAccessToken = async () => {
36284
+ let timeout = void 0;
36285
+ const start = performance.now();
36286
+ try {
36287
+ if (this.#accesssToken) return this.#accesssToken;
36288
+ const lockKey = "GetAccessToken";
36289
+ const lockTimeout = 6e4;
36290
+ if (this.GetOnHold(lockKey) === true) {
36291
+ this.Debug(chalk.default.magenta(`GetAccessToken(): accesssToken does not exist - some other client setting up the new accesssToken (on hold/lock), lock key: [${lockKey}] - waiting ...`));
36292
+ try {
36293
+ const miniStart = performance.now();
36294
+ await this.WaitOnHold(lockKey, lockTimeout);
36295
+ this.Debug(chalk.default.yellow(`GetAccessToken(): hold (lock) released after: [${performance.now() - miniStart}ms], lock key: [${lockKey}]`));
36296
+ if (this.#accesssToken) {
36297
+ this.Debug(chalk.default.green(`GetAccessToken(): Getting existing accesssToken (post hold release), lock key: [${lockKey}]`));
36298
+ return this.#accesssToken;
36299
+ } else {
36300
+ this.Error(chalk.default.red(`GetAccessToken(): Could not get existing accesssToken (post hold release), lock key: [${lockKey}]`));
36301
+ this.Error(chalk.default.red(`GetAccessToken(): continue anyway ...`));
36302
+ }
36303
+ } catch (error) {
36304
+ this.Error(chalk.default.red(`GetAccessToken(): Error: [${error}]`));
36305
+ }
36306
+ }
36307
+ this.Debug(chalk.default.yellow(`GetAccessToken(): accesssToken does not exist - setting up new accesssToken`));
36308
+ this.Debug(chalk.default.yellow(`GetAccessToken(): setting hold (lock), lock key: [${lockKey}]`));
36309
+ this.SetOnHold(lockKey);
36310
+ timeout = setTimeout(() => {
36311
+ this.Warning(chalk.default.magenta(`GetAccessToken(): Timeout: [${this._authMaxTimeout}] exceeded for getting access token ...`));
36312
+ }, this._authMaxTimeout);
36313
+ const scopes = `api://fb6513e4-16fe-4931-bed8-33b82b404a14/_.stsfhir5:All`.split(" ").sort().join(" ");
36314
+ const authendpointUrl = `${this._options.authOptions.asendpoint}:${this._options.authOptions.asport}`;
36315
+ const workingAaccesssToken = await this.GetAPITokenFromAuthServerUsingScope({
36316
+ clientId: "d8277fce-bb48-44c2-bbf1-257fe13a444b",
36317
+ authClientSecret: "64e3ef37-c7b8-4cb1-880a-e6ad3ab36e3c",
36318
+ scope: scopes,
36319
+ endPoint: authendpointUrl
36320
+ });
36321
+ if (timeout) clearTimeout(timeout);
36322
+ const totalTime = performance.now() - start;
36323
+ if (totalTime > this._authMaxTimeout) this.Warning(chalk.default.magenta(`GetAccessToken(): The total time for getting the access token: [${totalTime}]`));
36324
+ this.#accesssToken = workingAaccesssToken;
36325
+ this.ReleaseOnHold(lockKey);
36326
+ this.Debug(chalk.default.yellow(`GetAccessToken(): release hold (lock) Time taken for get access token: [${performance.now() - start}ms]`));
36327
+ return this.#accesssToken;
36328
+ } catch (error) {
36329
+ if (timeout) clearTimeout(timeout);
36330
+ error.message = `GetAccessToken(): Error: [${error}], Duration until error: [${performance.now() - start}]`;
36331
+ this.Error(error);
36332
+ return "";
36333
+ }
36334
+ };
36335
+ GetAccessTokenForSocketClientAccess = async () => {
36336
+ const timeout = setTimeout(() => {
36337
+ this.Warning(`GetAccessTokenForSocketClientAccess(): Timeout: [${this._authMaxTimeout}] exceeded for getting access token ...`);
36338
+ }, this._authMaxTimeout);
36339
+ const start = performance.now();
36340
+ try {
36341
+ const scopes = `api://fb6513e4-16fe-4931-bed8-33b82b404a14/_.stsfhir5:SocketConnection`.split(" ").sort().join(" ");
36342
+ const authendpointUrl = `${this._options.authOptions.asendpoint}:${this._options.authOptions.asport}`;
36343
+ const retVal = await this.GetAPITokenFromAuthServerUsingScope({
36344
+ clientId: "d8277fce-bb48-44c2-bbf1-257fe13a444b",
36345
+ authClientSecret: "64e3ef37-c7b8-4cb1-880a-e6ad3ab36e3c",
36346
+ scope: scopes,
36347
+ endPoint: authendpointUrl
36348
+ });
36349
+ clearTimeout(timeout);
36350
+ const totalTime = performance.now() - start;
36351
+ if (totalTime > this._authMaxTimeout) this.Warning(chalk.default.magenta(`GetAccessTokenForSocketClientAccess(): The total time for getting the access token: [${totalTime}]`));
36352
+ return retVal;
36353
+ } catch (error) {
36354
+ clearTimeout(timeout);
36355
+ error.message = `GetAccessTokenForSocketClientAccess(): Error: [${error}], Duration until error: [${performance.now() - start}]`;
36356
+ this.Error(error);
36357
+ return "";
36358
+ }
36359
+ };
36360
+ ResetAccessToken = () => {
36361
+ this.#accesssToken = null;
36362
+ };
36363
+ GetFhirSocketClient = async () => {
36364
+ try {
36365
+ if (this.fhirClient) return this.fhirClient;
36366
+ const lockKey = "GetFhirSocketClient";
36367
+ const lockTimeout = 6e4;
36368
+ if (this.GetOnHold(lockKey) === true) {
36369
+ this.Debug(chalk.default.magenta(`GetFhirSocketClient(): fhir client does not exist - some other client setting up the new client (on hold/lock), lock key: [${lockKey}] - waiting ...`));
36370
+ try {
36371
+ const start = performance.now();
36372
+ await this.WaitOnHold(lockKey, lockTimeout);
36373
+ this.Debug(chalk.default.yellow(`GetFhirSocketClient(): hold (lock) released after: [${performance.now() - start}ms], lock key: [${lockKey}]`));
36374
+ if (this.fhirClient) {
36375
+ this.Debug(chalk.default.green(`GetFhirSocketClient(): Getting existing fhir client (post hold release), lock key: [${lockKey}]`));
36376
+ return this.fhirClient;
36377
+ } else {
36378
+ this.Error(chalk.default.red(`GetFhirSocketClient(): Could not get existing fhir client (post hold release), lock key: [${lockKey}]`));
36379
+ this.Error(chalk.default.red(`GetFhirSocketClient(): continue anyway ...`));
36380
+ }
36381
+ } catch (error) {
36382
+ this.Error(chalk.default.red(`GetFhirSocketClient(): Error: [${error}]`));
36383
+ }
36384
+ }
36385
+ const start = performance.now();
36386
+ this.Debug(chalk.default.yellow(`GetFhirSocketClient(): fhir client does not exist - setting up new client`));
36387
+ this.Debug(chalk.default.yellow(`GetFhirSocketClient(): setting hold (lock), lock key: [${lockKey}]`));
36388
+ this.SetOnHold(lockKey);
36389
+ const fhirOptions = this._options.fhirOptions;
36390
+ const options = {
36391
+ fhirServerEndpoint: fhirOptions.stsfhirserverendpoint,
36392
+ fhirapiroot: fhirOptions.stsfhirapiroot,
36393
+ fhirServerPort: fhirOptions.stsfhirport,
36394
+ socketClientName: fhirOptions.stsfhirsocketname,
36395
+ socketIoCustomPath: fhirOptions.stsfhirsocketcustompath,
36396
+ timeout: fhirOptions.stsfhirsockettimeout,
36397
+ baseUrl: fhirOptions.stsfhirbaseurl,
36398
+ agentManager: this.GetFhirAgentManager(),
36399
+ joinRooms: [],
36400
+ logger: this.logger,
36401
+ verboseLogging: true,
36402
+ GetConnectionAccessToken: this.GetAccessTokenForSocketClientAccess,
36403
+ GetAccessToken: this.GetAccessToken
36404
+ };
36405
+ let workingFhirClient;
36406
+ if (this._options.runner.options.fhirOptions.stsfhirsocketclientmode === "socket-client-all-in-one") workingFhirClient = new _nsshunt_stsfhirclient.FhirSocketClientAllInOne("FhirSocketClient", options);
36407
+ else workingFhirClient = new _nsshunt_stsfhirclient.FhirSocketClientIndividual("FhirSocketClient", options);
36408
+ await workingFhirClient.WaitForSocketConnected();
36409
+ this.Debug(chalk.default.yellow(`GetFhirSocketClient(): setting fhir client into object`));
36410
+ this.fhirClient = workingFhirClient;
36411
+ this.ReleaseOnHold(lockKey);
36412
+ this.Debug(chalk.default.yellow(`GetFhirSocketClient(): release hold (lock) Time taken for socket connection and set object: [${performance.now() - start}ms], lock key: [${lockKey}]`));
36413
+ return this.fhirClient;
36414
+ } catch (error) {
36415
+ this.Error(error);
36416
+ throw error;
36417
+ }
36418
+ };
36419
+ GetRESTClient = async () => {
36420
+ if (this.restFhirClient) return this.restFhirClient;
36421
+ const onRetryAttempt = (attempt, error, delayMs) => {
36422
+ this._options.runner.instrumentData.errorCount++;
36423
+ this._options.runner.instrumentData.requestCount++;
36424
+ const message = `TestCaseFhirBase:onRetryAttempt(): [${this._id}] Retry #${attempt} after ${delayMs}ms due to ${error.code || error.response?.status}`;
36425
+ this.Warning(message);
36426
+ this._options.runner.instrumentData.message.push(chalk.default.red(message));
36427
+ };
36428
+ const fhirOptions = this._options.fhirOptions;
36429
+ const fhirRESTClient = new _nsshunt_stsfhirclient.FhirRESTClient({
36430
+ GetAccessToken: this.GetAccessToken,
36431
+ user: "USR_user01@stsmda.com.au",
36432
+ endpoint: fhirOptions.stsfhirserverendpoint,
36433
+ stsfhirapiroot: fhirOptions.stsfhirapiroot,
36434
+ stsfhirport: fhirOptions.stsfhirport,
36435
+ logger: this.logger,
36436
+ agentManager: this.GetFhirAgentManager(),
36437
+ onRetryAttempt
36438
+ });
36439
+ this.restFhirClient = fhirRESTClient;
36440
+ return fhirRESTClient;
36441
+ };
36442
+ GetClient = async () => {
36443
+ let client;
36444
+ if (this._options.runner.options.fhirOptions.stsfhirsocketclientmode === "no-socket-client") client = await this.GetRESTClient();
36445
+ else client = await this.GetFhirSocketClient();
36446
+ return client;
36447
+ };
36459
36448
  };
36460
36449
  //#endregion
36461
36450
  exports.WorkerFhirTestCases = WorkerFhirTestCases;