@webex/webex-core 3.12.0-llmrefactor.1 → 3.12.0-llmrefactor.3

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.
@@ -1103,9 +1103,16 @@ const Services = WebexPlugin.extend({
1103
1103
  requestObject.headers = {authorization: token};
1104
1104
  }
1105
1105
 
1106
- return this.webex.internal.newMetrics.callDiagnosticLatencies
1107
- .measureLatency(() => this.request(requestObject), 'internal.get.u2c.time')
1108
- .then(({body}) => body);
1106
+ const sendRequest = () => this.request(requestObject);
1107
+
1108
+ const responsePromise = this.webex.internal.newMetrics
1109
+ ? this.webex.internal.newMetrics.callDiagnosticLatencies.measureLatency(
1110
+ sendRequest,
1111
+ 'internal.get.u2c.time'
1112
+ )
1113
+ : sendRequest();
1114
+
1115
+ return responsePromise.then(({body}) => body);
1109
1116
  },
1110
1117
 
1111
1118
  /**
@@ -1418,6 +1425,28 @@ const Services = WebexPlugin.extend({
1418
1425
  this.ready = true;
1419
1426
  },
1420
1427
 
1428
+ /**
1429
+ * Build a promise that rejects once the catalog init timeout elapses. Race
1430
+ * this against catalog collection so a hung request never leaves
1431
+ * `services.ready` false forever - that would stall `webex.ready` and leave
1432
+ * consumers waiting on it indefinitely. Timeout is configurable via
1433
+ * `config.services.catalogInitTimeout` (defaults to 15s in config). Created
1434
+ * lazily so paths that skip catalog collection never schedule a stray timer.
1435
+ *
1436
+ * @private
1437
+ * @returns {Promise<never>}
1438
+ */
1439
+ _makeInitTimeout() {
1440
+ const initTimeoutMs = this.webex.config?.services?.catalogInitTimeout;
1441
+
1442
+ return new Promise((_, reject) => {
1443
+ setTimeout(
1444
+ () => reject(new Error(`services: init timed out after ${initTimeoutMs}ms`)),
1445
+ initTimeoutMs
1446
+ );
1447
+ });
1448
+ },
1449
+
1421
1450
  /**
1422
1451
  * Initializer
1423
1452
  *
@@ -1492,6 +1521,14 @@ const Services = WebexPlugin.extend({
1492
1521
  } else {
1493
1522
  const {email} = this.webex.config;
1494
1523
 
1524
+ if (this.webex.config?.services?.skipPreauthCatalogOnUnauthenticated === true) {
1525
+ this.logger.info(
1526
+ 'services: skipping preauth catalog collection while unauthenticated as per the config'
1527
+ );
1528
+
1529
+ return;
1530
+ }
1531
+
1495
1532
  this.collectPreauthCatalog(email ? {email} : undefined).catch((error) => {
1496
1533
  this.initFailed = true;
1497
1534
  this.logger.error(
@@ -1526,25 +1563,12 @@ const Services = WebexPlugin.extend({
1526
1563
  }
1527
1564
  const {supertoken} = this.webex.credentials;
1528
1565
 
1529
- // Race init against a hard timeout so a hung request never leaves
1530
- // `services.ready` false forever - that would stall `webex.ready` and
1531
- // leave consumers waiting on it indefinitely. Timeout is configurable via
1532
- // `config.services.catalogInitTimeout` (defaults to 15s in config).
1533
- const initTimeoutMs = this.webex.config?.services?.catalogInitTimeout;
1534
-
1535
- const initServiceCatalogsTimeout = new Promise((_, reject) => {
1536
- setTimeout(
1537
- () => reject(new Error(`services: init timed out after ${initTimeoutMs}ms`)),
1538
- initTimeoutMs
1539
- );
1540
- });
1541
-
1542
1566
  // Validate if the supertoken exists.
1543
1567
  if (supertoken && supertoken.access_token) {
1544
1568
  // `initServiceCatalogs` marks the catalog ready internally once the
1545
1569
  // postauth catalog is collected - even if it loses the timeout race
1546
- // above, so a slow fetch still eventually flips `catalog.isReady`.
1547
- Promise.race([this.initServiceCatalogs(), initServiceCatalogsTimeout])
1570
+ // below, so a slow fetch still eventually flips `catalog.isReady`.
1571
+ Promise.race([this.initServiceCatalogs(), this._makeInitTimeout()])
1548
1572
  .catch((error) => {
1549
1573
  this.initFailed = true;
1550
1574
  this.logger.error(
@@ -1555,18 +1579,6 @@ const Services = WebexPlugin.extend({
1555
1579
  } else {
1556
1580
  const {email} = this.webex.config;
1557
1581
 
1558
- Promise.race([
1559
- this.collectPreauthCatalog(email ? {email} : undefined),
1560
- initServiceCatalogsTimeout,
1561
- ])
1562
- .catch((error) => {
1563
- this.initFailed = true;
1564
- this.logger.error(
1565
- `services: failed to init initial services when no credentials available, ${error?.message}`
1566
- );
1567
- })
1568
- .finally(() => this._finalizeReady());
1569
-
1570
1582
  // Handle fresh login: 'loaded' fires before OAuth completes, so listen
1571
1583
  // for `canAuthorize` flipping true and then collect the postauth catalog.
1572
1584
  this.listenToOnce(this.webex, 'change:canAuthorize', () => {
@@ -1579,6 +1591,29 @@ const Services = WebexPlugin.extend({
1579
1591
  });
1580
1592
  }
1581
1593
  });
1594
+
1595
+ if (this.webex.config?.services?.skipPreauthCatalogOnUnauthenticated === true) {
1596
+ // Skip the preauth catalog fetch (it will be collected manually
1597
+ // later), but still finalize `services.ready` so `webex.ready` is not
1598
+ // stalled while unauthenticated. No timeout is created here so there
1599
+ // is no stray timer or unhandled rejection.
1600
+ this.logger.info(
1601
+ 'services: skipping preauth catalog collection while unauthenticated as per the config'
1602
+ );
1603
+ this._finalizeReady();
1604
+ } else {
1605
+ Promise.race([
1606
+ this.collectPreauthCatalog(email ? {email} : undefined),
1607
+ this._makeInitTimeout(),
1608
+ ])
1609
+ .catch((error) => {
1610
+ this.initFailed = true;
1611
+ this.logger.error(
1612
+ `services: failed to init initial services when no credentials available, ${error?.message}`
1613
+ );
1614
+ })
1615
+ .finally(() => this._finalizeReady());
1616
+ }
1582
1617
  }
1583
1618
  });
1584
1619
  },
@@ -1257,9 +1257,16 @@ const Services = WebexPlugin.extend({
1257
1257
  requestObject.headers = {authorization: token};
1258
1258
  }
1259
1259
 
1260
- return this.webex.internal.newMetrics.callDiagnosticLatencies
1261
- .measureLatency(() => this.request(requestObject), 'internal.get.u2c.time')
1262
- .then(({body}) => this._formatReceivedHostmap(body || {}));
1260
+ const sendRequest = () => this.request(requestObject);
1261
+
1262
+ const responsePromise = this.webex.internal.newMetrics
1263
+ ? this.webex.internal.newMetrics.callDiagnosticLatencies.measureLatency(
1264
+ sendRequest,
1265
+ 'internal.get.u2c.time'
1266
+ )
1267
+ : sendRequest();
1268
+
1269
+ return responsePromise.then(({body}) => this._formatReceivedHostmap(body || {}));
1263
1270
  },
1264
1271
 
1265
1272
  /**
@@ -1388,6 +1395,28 @@ const Services = WebexPlugin.extend({
1388
1395
  this.ready = true;
1389
1396
  },
1390
1397
 
1398
+ /**
1399
+ * Build a promise that rejects once the catalog init timeout elapses. Race
1400
+ * this against catalog collection so a hung request never leaves
1401
+ * `services.ready` false forever - that would stall `webex.ready` and leave
1402
+ * consumers waiting on it indefinitely. Timeout is configurable via
1403
+ * `config.services.catalogInitTimeout` (defaults to 15s in config). Created
1404
+ * lazily so paths that skip catalog collection never schedule a stray timer.
1405
+ *
1406
+ * @private
1407
+ * @returns {Promise<never>}
1408
+ */
1409
+ _makeInitTimeout(): Promise<never> {
1410
+ const initTimeoutMs = this.webex.config?.services?.catalogInitTimeout;
1411
+
1412
+ return new Promise<never>((_, reject) => {
1413
+ setTimeout(
1414
+ () => reject(new Error(`services: init timed out after ${initTimeoutMs}ms`)),
1415
+ initTimeoutMs
1416
+ );
1417
+ });
1418
+ },
1419
+
1391
1420
  /**
1392
1421
  * Initializer
1393
1422
  *
@@ -1455,6 +1484,14 @@ const Services = WebexPlugin.extend({
1455
1484
  } else {
1456
1485
  const {email} = this.webex.config;
1457
1486
 
1487
+ if (this.webex.config?.services?.skipPreauthCatalogOnUnauthenticated === true) {
1488
+ this.logger.info(
1489
+ 'services: skipping preauth catalog collection while unauthenticated as per the config'
1490
+ );
1491
+
1492
+ return;
1493
+ }
1494
+
1458
1495
  this.collectPreauthCatalog(email ? {email} : undefined).catch((error) => {
1459
1496
  this.initFailed = true;
1460
1497
  this.logger.error(
@@ -1489,24 +1526,12 @@ const Services = WebexPlugin.extend({
1489
1526
  }
1490
1527
  const {supertoken} = this.webex.credentials;
1491
1528
 
1492
- // Race init against a hard timeout so a hung request never leaves
1493
- // `services.ready` false forever - that would stall `webex.ready` and
1494
- // leave consumers waiting on it indefinitely. Timeout is configurable via
1495
- // `config.services.catalogInitTimeout` (defaults to 15s in config).
1496
- const initTimeoutMs = this.webex.config?.services?.catalogInitTimeout;
1497
- const initServiceCatalogsTimeout = new Promise<never>((_, reject) => {
1498
- setTimeout(
1499
- () => reject(new Error(`services: init timed out after ${initTimeoutMs}ms`)),
1500
- initTimeoutMs
1501
- );
1502
- });
1503
-
1504
1529
  // Validate if the supertoken exists.
1505
1530
  if (supertoken && supertoken.access_token) {
1506
1531
  // `initServiceCatalogs` marks the catalog ready internally once the
1507
1532
  // postauth catalog is collected - even if it loses the timeout race
1508
- // above, so a slow fetch still eventually flips `catalog.isReady`.
1509
- Promise.race([this.initServiceCatalogs(), initServiceCatalogsTimeout])
1533
+ // below, so a slow fetch still eventually flips `catalog.isReady`.
1534
+ Promise.race([this.initServiceCatalogs(), this._makeInitTimeout()])
1510
1535
  .catch((error) => {
1511
1536
  this.initFailed = true;
1512
1537
  this.logger.error(
@@ -1517,18 +1542,6 @@ const Services = WebexPlugin.extend({
1517
1542
  } else {
1518
1543
  const {email} = this.webex.config;
1519
1544
 
1520
- Promise.race([
1521
- this.collectPreauthCatalog(email ? {email} : undefined),
1522
- initServiceCatalogsTimeout,
1523
- ])
1524
- .catch((error) => {
1525
- this.initFailed = true;
1526
- this.logger.error(
1527
- `services: failed to init initial services when no credentials available, ${error?.message}`
1528
- );
1529
- })
1530
- .finally(() => this._finalizeReady());
1531
-
1532
1545
  // Handle fresh login: 'loaded' fires before OAuth completes, so listen
1533
1546
  // for `canAuthorize` flipping true and then collect the postauth catalog.
1534
1547
  this.listenToOnce(this.webex, 'change:canAuthorize', () => {
@@ -1541,6 +1554,29 @@ const Services = WebexPlugin.extend({
1541
1554
  });
1542
1555
  }
1543
1556
  });
1557
+
1558
+ if (this.webex.config?.services?.skipPreauthCatalogOnUnauthenticated === true) {
1559
+ // Skip the preauth catalog fetch (it will be collected manually
1560
+ // later), but still finalize `services.ready` so `webex.ready` is not
1561
+ // stalled while unauthenticated. No timeout is created here so there
1562
+ // is no stray timer or unhandled rejection.
1563
+ this.logger.info(
1564
+ 'services: skipping preauth catalog collection while unauthenticated as per the config'
1565
+ );
1566
+ this._finalizeReady();
1567
+ } else {
1568
+ Promise.race([
1569
+ this.collectPreauthCatalog(email ? {email} : undefined),
1570
+ this._makeInitTimeout(),
1571
+ ])
1572
+ .catch((error) => {
1573
+ this.initFailed = true;
1574
+ this.logger.error(
1575
+ `services: failed to init initial services when no credentials available, ${error?.message}`
1576
+ );
1577
+ })
1578
+ .finally(() => this._finalizeReady());
1579
+ }
1544
1580
  }
1545
1581
  });
1546
1582
  },
@@ -5,7 +5,7 @@
5
5
  import '@webex/internal-plugin-device';
6
6
 
7
7
  import {assert} from '@webex/test-helper-chai';
8
- import {flaky} from '@webex/test-helper-mocha';
8
+ import {flaky, retryOn429} from '@webex/test-helper-mocha';
9
9
  import WebexCore, {
10
10
  ServiceCatalog,
11
11
  ServiceRegistry,
@@ -443,7 +443,10 @@ describe('webex-core', () => {
443
443
  // Before init settles, webex.ready must be false because services.ready
444
444
  // is a dependency and starts false in the gated path.
445
445
  assert.isFalse(gatedWebex.internal.services.ready, 'services.ready should start false');
446
- assert.isFalse(gatedWebex.ready, 'webex.ready should not fire while services.ready is false');
446
+ assert.isFalse(
447
+ gatedWebex.ready,
448
+ 'webex.ready should not fire while services.ready is false'
449
+ );
447
450
 
448
451
  // Wait up to 30s for services init to complete and flip ready.
449
452
  await new Promise((resolve, reject) => {
@@ -463,7 +466,10 @@ describe('webex-core', () => {
463
466
  });
464
467
  });
465
468
 
466
- assert.isTrue(gatedWebex.internal.services.ready, 'services.ready should flip true after init settles');
469
+ assert.isTrue(
470
+ gatedWebex.internal.services.ready,
471
+ 'services.ready should flip true after init settles'
472
+ );
467
473
  assert.isTrue(gatedWebex.ready, 'webex.ready should fire once services.ready flips');
468
474
  });
469
475
  });
@@ -903,18 +909,22 @@ describe('webex-core', () => {
903
909
  }));
904
910
 
905
911
  it('validates an authorized user and webex instance', () =>
906
- services.validateUser({email: webexUser.email}).then((r) => {
907
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
908
- assert.equal(r.activated, true);
909
- assert.equal(r.exists, true);
910
- }));
912
+ retryOn429(() =>
913
+ services.validateUser({email: webexUser.email}).then((r) => {
914
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
915
+ assert.equal(r.activated, true);
916
+ assert.equal(r.exists, true);
917
+ })
918
+ ));
911
919
 
912
920
  it('validates an authorized EU user and webex instance', () =>
913
- servicesEU.validateUser({email: webexUserEU.email}).then((r) => {
914
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
915
- assert.equal(r.activated, true);
916
- assert.equal(r.exists, true);
917
- }));
921
+ retryOn429(() =>
922
+ servicesEU.validateUser({email: webexUserEU.email}).then((r) => {
923
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
924
+ assert.equal(r.activated, true);
925
+ assert.equal(r.exists, true);
926
+ })
927
+ ));
918
928
 
919
929
  it("returns a rejected promise if the provided email isn't valid", () =>
920
930
  unauthServices
@@ -927,131 +937,152 @@ describe('webex-core', () => {
927
937
  }));
928
938
 
929
939
  it('validates a non-existing user', () =>
930
- unauthServices
931
- .validateUser({email: createActivationEmail()})
932
- .then((r) => {
940
+ retryOn429(() =>
941
+ unauthServices.validateUser({email: createActivationEmail()}).then((r) => {
933
942
  assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
934
943
  assert.equal(r.activated, false);
935
944
  assert.equal(r.exists, false);
936
945
  assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
937
946
  assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
938
947
  assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
939
- }));
948
+ })
949
+ ));
940
950
 
941
951
  it('validates new user with activationOptions suppressEmail false', () =>
942
- unauthServices
943
- .validateUser({
944
- email: createActivationEmail(),
945
- activationOptions: {suppressEmail: false},
946
- })
947
- .then((r) => {
948
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
949
- assert.equal(r.activated, false);
950
- assert.equal(r.exists, false);
951
- assert.equal(r.user.verificationEmailTriggered, true);
952
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
953
- assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
954
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
955
- }));
952
+ retryOn429(() =>
953
+ unauthServices
954
+ .validateUser({
955
+ email: createActivationEmail(),
956
+ activationOptions: {suppressEmail: false},
957
+ })
958
+ .then((r) => {
959
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
960
+ assert.equal(r.activated, false);
961
+ assert.equal(r.exists, false);
962
+ assert.equal(r.user.verificationEmailTriggered, true);
963
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
964
+ assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
965
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
966
+ })
967
+ ));
956
968
 
957
969
  it('validates new user with activationOptions suppressEmail true', () =>
958
- unauthServices
959
- .validateUser({
960
- email: createActivationEmail(),
961
- activationOptions: {suppressEmail: true},
962
- })
963
- .then((r) => {
964
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
965
- assert.equal(r.activated, false);
966
- assert.equal(r.exists, false);
967
- assert.equal(r.user.verificationEmailTriggered, false);
968
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
969
- assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
970
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
971
- }));
970
+ retryOn429(() =>
971
+ unauthServices
972
+ .validateUser({
973
+ email: createActivationEmail(),
974
+ activationOptions: {suppressEmail: true},
975
+ })
976
+ .then((r) => {
977
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
978
+ assert.equal(r.activated, false);
979
+ assert.equal(r.exists, false);
980
+ assert.equal(r.user.verificationEmailTriggered, false);
981
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
982
+ assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
983
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
984
+ })
985
+ ));
972
986
 
973
987
  it('validates an inactive user', () => {
974
988
  const inactive = 'webex.web.client+nonactivated@gmail.com';
975
989
 
976
- return unauthServices
977
- .validateUser({email: inactive, activationOptions: {suppressEmail: true}})
978
- .then((r) => {
990
+ return retryOn429(() =>
991
+ unauthServices
992
+ .validateUser({email: inactive, activationOptions: {suppressEmail: true}})
993
+ .then((r) => {
994
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
995
+ assert.equal(r.activated, false, 'activated');
996
+ assert.equal(r.exists, true, 'exists');
997
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
998
+ assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
999
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
1000
+ })
1001
+ ).catch(() => {
1002
+ assert(true);
1003
+ });
1004
+ });
1005
+
1006
+ it('validates an existing user', () =>
1007
+ retryOn429(() =>
1008
+ unauthServices.validateUser({email: webexUser.email}).then((r) => {
979
1009
  assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
980
- assert.equal(r.activated, false, 'activated');
981
- assert.equal(r.exists, true, 'exists');
1010
+ assert.equal(r.activated, true);
1011
+ assert.equal(r.exists, true);
982
1012
  assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
983
- assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
1013
+ assert.isAbove(Object.keys(unauthServices.list(false, 'signin')).length, 0);
984
1014
  assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
985
1015
  })
986
- .catch(() => {
987
- assert(true);
988
- });
989
- });
990
-
991
- it('validates an existing user', () =>
992
- unauthServices.validateUser({email: webexUser.email}).then((r) => {
993
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
994
- assert.equal(r.activated, true);
995
- assert.equal(r.exists, true);
996
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
997
- assert.isAbove(Object.keys(unauthServices.list(false, 'signin')).length, 0);
998
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
999
- }));
1016
+ ));
1000
1017
 
1001
1018
  it('validates an existing EU user', () =>
1002
- unauthServices.validateUser({email: webexUserEU.email}).then((r) => {
1003
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
1004
- assert.equal(r.activated, true);
1005
- assert.equal(r.exists, true);
1006
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
1007
- assert.isAbove(Object.keys(unauthServices.list(false, 'signin')).length, 0);
1008
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
1009
- }));
1019
+ retryOn429(() =>
1020
+ unauthServices.validateUser({email: webexUserEU.email}).then((r) => {
1021
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
1022
+ assert.equal(r.activated, true);
1023
+ assert.equal(r.exists, true);
1024
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
1025
+ assert.isAbove(Object.keys(unauthServices.list(false, 'signin')).length, 0);
1026
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
1027
+ })
1028
+ ));
1010
1029
 
1011
1030
  it('sends the prelogin user id as undefined when not specified', () => {
1012
1031
  const requestStub = sandbox.spy(unauthServices, 'request');
1013
1032
 
1014
- return unauthServices
1015
- .validateUser({
1016
- email: createActivationEmail(),
1017
- activationOptions: {suppressEmail: true},
1018
- })
1019
- .then(() => {
1020
- assert.isUndefined(getActivationRequest(requestStub).headers['x-prelogin-userid']);
1021
- });
1033
+ return retryOn429(() => {
1034
+ requestStub.resetHistory();
1035
+
1036
+ return unauthServices
1037
+ .validateUser({
1038
+ email: createActivationEmail(),
1039
+ activationOptions: {suppressEmail: true},
1040
+ })
1041
+ .then(() => {
1042
+ assert.isUndefined(getActivationRequest(requestStub).headers['x-prelogin-userid']);
1043
+ });
1044
+ });
1022
1045
  });
1023
1046
 
1024
1047
  it('sends the prelogin user id as provided when specified', () => {
1025
1048
  const requestStub = sandbox.spy(unauthServices, 'request');
1026
1049
  const preloginUserId = uuid.v4();
1027
1050
 
1028
- return unauthServices
1029
- .validateUser({
1030
- email: createActivationEmail(),
1031
- activationOptions: {suppressEmail: true},
1032
- preloginUserId,
1033
- })
1034
- .then(() => {
1035
- assert.strictEqual(
1036
- getActivationRequest(requestStub).headers['x-prelogin-userid'],
1037
- preloginUserId
1038
- );
1039
- });
1051
+ return retryOn429(() => {
1052
+ requestStub.resetHistory();
1053
+
1054
+ return unauthServices
1055
+ .validateUser({
1056
+ email: createActivationEmail(),
1057
+ activationOptions: {suppressEmail: true},
1058
+ preloginUserId,
1059
+ })
1060
+ .then(() => {
1061
+ assert.strictEqual(
1062
+ getActivationRequest(requestStub).headers['x-prelogin-userid'],
1063
+ preloginUserId
1064
+ );
1065
+ });
1066
+ });
1040
1067
  });
1041
1068
 
1042
1069
  it('uses the license service by default', () => {
1043
1070
  const requestStub = sandbox.spy(unauthServices, 'request');
1044
1071
 
1045
- return unauthServices
1046
- .validateUser({
1047
- email: createActivationEmail(),
1048
- activationOptions: {suppressEmail: true},
1049
- })
1050
- .then(() => {
1051
- const request = getActivationRequest(requestStub, false);
1052
- assert.strictEqual(request.service, 'license');
1053
- assert.strictEqual(request.resource, 'users/activations');
1054
- });
1072
+ return retryOn429(() => {
1073
+ requestStub.resetHistory();
1074
+
1075
+ return unauthServices
1076
+ .validateUser({
1077
+ email: createActivationEmail(),
1078
+ activationOptions: {suppressEmail: true},
1079
+ })
1080
+ .then(() => {
1081
+ const request = getActivationRequest(requestStub, false);
1082
+ assert.strictEqual(request.service, 'license');
1083
+ assert.strictEqual(request.resource, 'users/activations');
1084
+ });
1085
+ });
1055
1086
  });
1056
1087
 
1057
1088
  it('uses the user-onboarding service when useUserOnboardingServiceForActivations config is true', () => {
@@ -1065,16 +1096,20 @@ describe('webex-core', () => {
1065
1096
  const userOnboardingServices = userOnboardingWebex.internal.services;
1066
1097
  const requestStub = sandbox.spy(userOnboardingServices, 'request');
1067
1098
 
1068
- return userOnboardingServices
1069
- .validateUser({
1070
- email: createActivationEmail(),
1071
- activationOptions: {suppressEmail: true},
1072
- })
1073
- .then(() => {
1074
- const request = getActivationRequest(requestStub, true);
1075
- assert.strictEqual(request.service, 'user-onboarding');
1076
- assert.strictEqual(request.resource, 'api/v1/users/activations');
1077
- });
1099
+ return retryOn429(() => {
1100
+ requestStub.resetHistory();
1101
+
1102
+ return userOnboardingServices
1103
+ .validateUser({
1104
+ email: createActivationEmail(),
1105
+ activationOptions: {suppressEmail: true},
1106
+ })
1107
+ .then(() => {
1108
+ const request = getActivationRequest(requestStub, true);
1109
+ assert.strictEqual(request.service, 'user-onboarding');
1110
+ assert.strictEqual(request.resource, 'api/v1/users/activations');
1111
+ });
1112
+ });
1078
1113
  });
1079
1114
  });
1080
1115