@webex/webex-core 2.59.3-next.1 → 2.59.4

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.
Files changed (189) hide show
  1. package/.eslintrc.js +6 -6
  2. package/README.md +79 -79
  3. package/babel.config.js +3 -3
  4. package/dist/config.js +24 -24
  5. package/dist/config.js.map +1 -1
  6. package/dist/credentials-config.js +56 -56
  7. package/dist/credentials-config.js.map +1 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/interceptors/auth.js +28 -28
  10. package/dist/interceptors/auth.js.map +1 -1
  11. package/dist/interceptors/default-options.js +24 -24
  12. package/dist/interceptors/default-options.js.map +1 -1
  13. package/dist/interceptors/embargo.js +9 -9
  14. package/dist/interceptors/embargo.js.map +1 -1
  15. package/dist/interceptors/network-timing.js +19 -19
  16. package/dist/interceptors/network-timing.js.map +1 -1
  17. package/dist/interceptors/payload-transformer.js +19 -19
  18. package/dist/interceptors/payload-transformer.js.map +1 -1
  19. package/dist/interceptors/rate-limit.js +40 -40
  20. package/dist/interceptors/rate-limit.js.map +1 -1
  21. package/dist/interceptors/redirect.js +13 -13
  22. package/dist/interceptors/redirect.js.map +1 -1
  23. package/dist/interceptors/request-event.js +23 -23
  24. package/dist/interceptors/request-event.js.map +1 -1
  25. package/dist/interceptors/request-logger.js +13 -13
  26. package/dist/interceptors/request-logger.js.map +1 -1
  27. package/dist/interceptors/request-timing.js +23 -23
  28. package/dist/interceptors/request-timing.js.map +1 -1
  29. package/dist/interceptors/response-logger.js +19 -19
  30. package/dist/interceptors/response-logger.js.map +1 -1
  31. package/dist/interceptors/user-agent.js +29 -29
  32. package/dist/interceptors/user-agent.js.map +1 -1
  33. package/dist/interceptors/webex-tracking-id.js +15 -15
  34. package/dist/interceptors/webex-tracking-id.js.map +1 -1
  35. package/dist/interceptors/webex-user-agent.js +13 -13
  36. package/dist/interceptors/webex-user-agent.js.map +1 -1
  37. package/dist/lib/batcher.js +83 -83
  38. package/dist/lib/batcher.js.map +1 -1
  39. package/dist/lib/credentials/credentials.js +103 -103
  40. package/dist/lib/credentials/credentials.js.map +1 -1
  41. package/dist/lib/credentials/grant-errors.js +17 -17
  42. package/dist/lib/credentials/grant-errors.js.map +1 -1
  43. package/dist/lib/credentials/index.js +2 -2
  44. package/dist/lib/credentials/index.js.map +1 -1
  45. package/dist/lib/credentials/scope.js +11 -11
  46. package/dist/lib/credentials/scope.js.map +1 -1
  47. package/dist/lib/credentials/token-collection.js +2 -2
  48. package/dist/lib/credentials/token-collection.js.map +1 -1
  49. package/dist/lib/credentials/token.js +145 -145
  50. package/dist/lib/credentials/token.js.map +1 -1
  51. package/dist/lib/page.js +49 -49
  52. package/dist/lib/page.js.map +1 -1
  53. package/dist/lib/services/constants.js.map +1 -1
  54. package/dist/lib/services/index.js +2 -2
  55. package/dist/lib/services/index.js.map +1 -1
  56. package/dist/lib/services/interceptors/server-error.js +9 -9
  57. package/dist/lib/services/interceptors/server-error.js.map +1 -1
  58. package/dist/lib/services/interceptors/service.js +24 -24
  59. package/dist/lib/services/interceptors/service.js.map +1 -1
  60. package/dist/lib/services/metrics.js.map +1 -1
  61. package/dist/lib/services/service-catalog.js +104 -104
  62. package/dist/lib/services/service-catalog.js.map +1 -1
  63. package/dist/lib/services/service-fed-ramp.js.map +1 -1
  64. package/dist/lib/services/service-host.js +134 -134
  65. package/dist/lib/services/service-host.js.map +1 -1
  66. package/dist/lib/services/service-registry.js +175 -175
  67. package/dist/lib/services/service-registry.js.map +1 -1
  68. package/dist/lib/services/service-state.js +38 -38
  69. package/dist/lib/services/service-state.js.map +1 -1
  70. package/dist/lib/services/service-url.js +31 -31
  71. package/dist/lib/services/service-url.js.map +1 -1
  72. package/dist/lib/services/services.js +245 -245
  73. package/dist/lib/services/services.js.map +1 -1
  74. package/dist/lib/stateless-webex-plugin.js +28 -28
  75. package/dist/lib/stateless-webex-plugin.js.map +1 -1
  76. package/dist/lib/storage/decorators.js +27 -27
  77. package/dist/lib/storage/decorators.js.map +1 -1
  78. package/dist/lib/storage/errors.js +4 -4
  79. package/dist/lib/storage/errors.js.map +1 -1
  80. package/dist/lib/storage/index.js.map +1 -1
  81. package/dist/lib/storage/make-webex-plugin-store.js +44 -44
  82. package/dist/lib/storage/make-webex-plugin-store.js.map +1 -1
  83. package/dist/lib/storage/make-webex-store.js +40 -40
  84. package/dist/lib/storage/make-webex-store.js.map +1 -1
  85. package/dist/lib/storage/memory-store-adapter.js +9 -9
  86. package/dist/lib/storage/memory-store-adapter.js.map +1 -1
  87. package/dist/lib/webex-core-plugin-mixin.js +13 -13
  88. package/dist/lib/webex-core-plugin-mixin.js.map +1 -1
  89. package/dist/lib/webex-http-error.js +9 -9
  90. package/dist/lib/webex-http-error.js.map +1 -1
  91. package/dist/lib/webex-internal-core-plugin-mixin.js +13 -13
  92. package/dist/lib/webex-internal-core-plugin-mixin.js.map +1 -1
  93. package/dist/lib/webex-plugin.js +36 -36
  94. package/dist/lib/webex-plugin.js.map +1 -1
  95. package/dist/plugins/logger.js +9 -9
  96. package/dist/plugins/logger.js.map +1 -1
  97. package/dist/webex-core.js +104 -104
  98. package/dist/webex-core.js.map +1 -1
  99. package/dist/webex-internal-core.js +12 -12
  100. package/dist/webex-internal-core.js.map +1 -1
  101. package/jest.config.js +3 -3
  102. package/package.json +19 -20
  103. package/process +1 -1
  104. package/src/config.js +90 -90
  105. package/src/credentials-config.js +212 -212
  106. package/src/index.js +62 -62
  107. package/src/interceptors/auth.js +186 -186
  108. package/src/interceptors/default-options.js +55 -55
  109. package/src/interceptors/embargo.js +43 -43
  110. package/src/interceptors/network-timing.js +54 -54
  111. package/src/interceptors/payload-transformer.js +55 -55
  112. package/src/interceptors/rate-limit.js +169 -169
  113. package/src/interceptors/redirect.js +106 -106
  114. package/src/interceptors/request-event.js +93 -93
  115. package/src/interceptors/request-logger.js +78 -78
  116. package/src/interceptors/request-timing.js +65 -65
  117. package/src/interceptors/response-logger.js +98 -98
  118. package/src/interceptors/user-agent.js +77 -77
  119. package/src/interceptors/webex-tracking-id.js +73 -73
  120. package/src/interceptors/webex-user-agent.js +79 -79
  121. package/src/lib/batcher.js +307 -307
  122. package/src/lib/credentials/credentials.js +552 -552
  123. package/src/lib/credentials/grant-errors.js +92 -92
  124. package/src/lib/credentials/index.js +16 -16
  125. package/src/lib/credentials/scope.js +34 -34
  126. package/src/lib/credentials/token-collection.js +17 -17
  127. package/src/lib/credentials/token.js +559 -559
  128. package/src/lib/page.js +159 -159
  129. package/src/lib/services/constants.js +9 -9
  130. package/src/lib/services/index.js +26 -26
  131. package/src/lib/services/interceptors/server-error.js +48 -48
  132. package/src/lib/services/interceptors/service.js +101 -101
  133. package/src/lib/services/metrics.js +4 -4
  134. package/src/lib/services/service-catalog.js +435 -435
  135. package/src/lib/services/service-fed-ramp.js +4 -4
  136. package/src/lib/services/service-host.js +267 -267
  137. package/src/lib/services/service-registry.js +465 -465
  138. package/src/lib/services/service-state.js +78 -78
  139. package/src/lib/services/service-url.js +124 -124
  140. package/src/lib/services/services.js +1018 -1018
  141. package/src/lib/stateless-webex-plugin.js +98 -98
  142. package/src/lib/storage/decorators.js +220 -220
  143. package/src/lib/storage/errors.js +15 -15
  144. package/src/lib/storage/index.js +10 -10
  145. package/src/lib/storage/make-webex-plugin-store.js +211 -211
  146. package/src/lib/storage/make-webex-store.js +140 -140
  147. package/src/lib/storage/memory-store-adapter.js +79 -79
  148. package/src/lib/webex-core-plugin-mixin.js +114 -114
  149. package/src/lib/webex-http-error.js +61 -61
  150. package/src/lib/webex-internal-core-plugin-mixin.js +107 -107
  151. package/src/lib/webex-plugin.js +222 -222
  152. package/src/plugins/logger.js +60 -60
  153. package/src/webex-core.js +745 -745
  154. package/src/webex-internal-core.js +46 -46
  155. package/test/integration/spec/credentials/credentials.js +139 -139
  156. package/test/integration/spec/credentials/token.js +102 -102
  157. package/test/integration/spec/services/service-catalog.js +838 -838
  158. package/test/integration/spec/services/services.js +1221 -1221
  159. package/test/integration/spec/webex-core.js +178 -178
  160. package/test/unit/spec/_setup.js +44 -44
  161. package/test/unit/spec/credentials/credentials.js +1017 -1017
  162. package/test/unit/spec/credentials/token.js +441 -441
  163. package/test/unit/spec/interceptors/auth.js +521 -521
  164. package/test/unit/spec/interceptors/default-options.js +84 -84
  165. package/test/unit/spec/interceptors/embargo.js +144 -144
  166. package/test/unit/spec/interceptors/network-timing.js +49 -49
  167. package/test/unit/spec/interceptors/payload-transformer.js +155 -155
  168. package/test/unit/spec/interceptors/rate-limit.js +302 -302
  169. package/test/unit/spec/interceptors/redirect.js +102 -102
  170. package/test/unit/spec/interceptors/request-timing.js +92 -92
  171. package/test/unit/spec/interceptors/user-agent.js +76 -76
  172. package/test/unit/spec/interceptors/webex-tracking-id.js +76 -76
  173. package/test/unit/spec/interceptors/webex-user-agent.js +159 -159
  174. package/test/unit/spec/lib/batcher.js +330 -330
  175. package/test/unit/spec/lib/page.js +148 -148
  176. package/test/unit/spec/lib/webex-plugin.js +48 -48
  177. package/test/unit/spec/services/interceptors/server-error.js +204 -204
  178. package/test/unit/spec/services/interceptors/service.js +188 -188
  179. package/test/unit/spec/services/service-catalog.js +194 -194
  180. package/test/unit/spec/services/service-host.js +260 -260
  181. package/test/unit/spec/services/service-registry.js +747 -747
  182. package/test/unit/spec/services/service-state.js +60 -60
  183. package/test/unit/spec/services/service-url.js +258 -258
  184. package/test/unit/spec/services/services.js +348 -348
  185. package/test/unit/spec/storage/persist.js +50 -50
  186. package/test/unit/spec/storage/storage-adapter.js +12 -12
  187. package/test/unit/spec/storage/wait-for-value.js +81 -81
  188. package/test/unit/spec/webex-core.js +253 -253
  189. package/test/unit/spec/webex-internal-core.js +91 -91
@@ -1,1221 +1,1221 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import '@webex/internal-plugin-device';
6
-
7
- import {assert} from '@webex/test-helper-chai';
8
- import {flaky} from '@webex/test-helper-mocha';
9
- import WebexCore, {
10
- ServiceCatalog,
11
- ServiceRegistry,
12
- ServiceState,
13
- ServiceUrl,
14
- } from '@webex/webex-core';
15
- import testUsers from '@webex/test-helper-test-users';
16
- import uuid from 'uuid';
17
- import sinon from 'sinon';
18
-
19
- /* eslint-disable no-underscore-dangle */
20
- describe('webex-core', () => {
21
- describe('Services', () => {
22
- let webexUser;
23
- let webexUserEU;
24
- let webex;
25
- let webexEU;
26
- let services;
27
- let servicesEU;
28
- let catalog;
29
-
30
- before('create users', () =>
31
- Promise.all([
32
- testUsers.create({count: 1}),
33
- testUsers.create({
34
- count: 1,
35
- config: {
36
- orgId: process.env.EU_PRIMARY_ORG_ID,
37
- },
38
- }),
39
- ]).then(([[user], [userEU]]) => {
40
- webexUser = user;
41
- webexUserEU = userEU;
42
- })
43
- );
44
-
45
- beforeEach('create webex instance', () => {
46
- webex = new WebexCore({credentials: {supertoken: webexUser.token}});
47
- webexEU = new WebexCore({credentials: {supertoken: webexUserEU.token}});
48
- services = webex.internal.services;
49
- servicesEU = webexEU.internal.services;
50
- catalog = services._getCatalog();
51
-
52
- return Promise.all([
53
- services.waitForCatalog('postauth', 10),
54
- servicesEU.waitForCatalog('postauth', 10),
55
- ]).then(() =>
56
- services.updateServices({
57
- from: 'limited',
58
- query: {userId: webexUser.id},
59
- })
60
- );
61
- });
62
-
63
- describe('#_getCatalog()', () => {
64
- it('returns a catalog', () => {
65
- const localCatalog = services._getCatalog();
66
-
67
- assert.equal(localCatalog.namespace, 'ServiceCatalog');
68
- });
69
- });
70
-
71
- describe('#list()', () => {
72
- it('matches the values in serviceUrl', () => {
73
- let serviceList = services.list();
74
-
75
- Object.keys(serviceList).forEach((key) => {
76
- assert.equal(serviceList[key], catalog._getUrl(key).get());
77
- });
78
-
79
- serviceList = services.list(true);
80
- Object.keys(serviceList).forEach((key) => {
81
- assert.equal(serviceList[key], catalog._getUrl(key).get(true));
82
- });
83
- });
84
- });
85
-
86
- describe('#get()', () => {
87
- let testUrlTemplate;
88
- let testUrl;
89
-
90
- beforeEach('load test url', () => {
91
- testUrlTemplate = {
92
- defaultUrl: 'https://www.example.com/api/v1',
93
- hosts: [],
94
- name: 'exampleValid',
95
- };
96
- testUrl = new ServiceUrl(testUrlTemplate);
97
- catalog._loadServiceUrls('preauth', [testUrl]);
98
- });
99
-
100
- afterEach('unload test url', () => {
101
- catalog._unloadServiceUrls('preauth', [testUrl]);
102
- });
103
-
104
- it('returns a valid string when name is specified', () => {
105
- const url = services.get(testUrlTemplate.name);
106
-
107
- assert.typeOf(url, 'string');
108
- assert.equal(url, testUrlTemplate.defaultUrl);
109
- });
110
-
111
- it("returns undefined if url doesn't exist", () => {
112
- const s = services.get('invalidUrl');
113
-
114
- assert.typeOf(s, 'undefined');
115
- });
116
-
117
- it('gets a service from a specific serviceGroup', () => {
118
- assert.isDefined(services.get(testUrlTemplate.name, false, 'preauth'));
119
- });
120
-
121
- it("fails to get a service if serviceGroup isn't accurate", () => {
122
- assert.isUndefined(services.get(testUrlTemplate.name, false, 'discovery'));
123
- });
124
- });
125
-
126
- describe('#getClusterId()', () => {
127
- let testUrlTemplate;
128
- let testUrl;
129
-
130
- beforeEach('load test url', () => {
131
- testUrlTemplate = {
132
- defaultUrl: 'https://www.example.com/api/v1',
133
- hosts: [
134
- {
135
- homeCluster: true,
136
- host: 'www.example-p5.com',
137
- ttl: -1,
138
- priority: 5,
139
- id: 'exampleClusterId',
140
- },
141
- {
142
- host: 'www.example-p3.com',
143
- ttl: -1,
144
- priority: 3,
145
- id: 'exampleClusterId',
146
- },
147
- ],
148
- name: 'exampleValid',
149
- };
150
- testUrl = new ServiceUrl(testUrlTemplate);
151
- catalog._loadServiceUrls('preauth', [testUrl]);
152
- });
153
-
154
- it('returns a clusterId when found with default url', () => {
155
- assert.equal(
156
- services.getClusterId(testUrlTemplate.defaultUrl),
157
- testUrlTemplate.hosts[0].id
158
- );
159
- });
160
-
161
- it('returns a clusterId when found with priority host url', () => {
162
- assert.equal(services.getClusterId(testUrl.get(true)), testUrlTemplate.hosts[0].id);
163
- });
164
-
165
- it('returns a clusterId when found with resource-appended url', () => {
166
- assert.equal(
167
- services.getClusterId(`${testUrl.get()}example/resource/value`),
168
- testUrlTemplate.hosts[0].id
169
- );
170
- });
171
-
172
- it("returns undefined when the url doesn't exist in catalog", () => {
173
- assert.isUndefined(services.getClusterId('http://not-a-known-url.com/'));
174
- });
175
-
176
- it("returns undefined when the string isn't a url", () => {
177
- assert.isUndefined(services.getClusterId('not a url'));
178
- });
179
- });
180
-
181
- describe('#getServiceFromClusterId()', () => {
182
- let testUrlTemplate;
183
- let testUrl;
184
-
185
- beforeEach('load test url', () => {
186
- testUrlTemplate = {
187
- defaultUrl: 'https://www.example.com/api/v1',
188
- hosts: [
189
- {
190
- homeCluster: true,
191
- host: 'www.example-p5.com',
192
- ttl: -1,
193
- priority: 5,
194
- id: '0:0:cluster-a:exampleValid',
195
- },
196
- {
197
- host: 'www.example-p3.com',
198
- ttl: -1,
199
- priority: 3,
200
- id: '0:0:cluster-b:exampleValid',
201
- },
202
- ],
203
- name: 'exampleValid',
204
- };
205
- testUrl = new ServiceUrl(testUrlTemplate);
206
- catalog._loadServiceUrls('preauth', [testUrl]);
207
- });
208
-
209
- it('finds a valid service url from only a clusterId', () => {
210
- const serviceFound = services.getServiceFromClusterId({
211
- clusterId: testUrlTemplate.hosts[0].id,
212
- priorityHost: false,
213
- });
214
-
215
- assert.equal(serviceFound.name, testUrl.name);
216
- assert.equal(serviceFound.url, testUrl.defaultUrl);
217
- });
218
-
219
- it('finds a valid priority service url', () => {
220
- const serviceFound = services.getServiceFromClusterId({
221
- clusterId: testUrlTemplate.hosts[0].id,
222
- priorityHost: true,
223
- });
224
-
225
- assert.equal(serviceFound.name, testUrl.name);
226
- assert.isTrue(
227
- serviceFound.url.includes(testUrlTemplate.hosts[0].host),
228
- `'${serviceFound.url}' is not host '${testUrlTemplate.hosts[0].host}'`
229
- );
230
- // assert.equal(serviceFound.url, catalog.get('exampleValid', true));
231
- });
232
-
233
- it('finds a valid service when a service group is defined', () => {
234
- const serviceFound = catalog.findServiceFromClusterId({
235
- clusterId: testUrlTemplate.hosts[0].id,
236
- priorityHost: false,
237
- serviceGroup: 'preauth',
238
- });
239
-
240
- assert.equal(serviceFound.name, testUrl.name);
241
- assert.equal(serviceFound.url, testUrl.defaultUrl);
242
- });
243
-
244
- it("fails to find a valid service when it's not in a group", () => {
245
- assert.isUndefined(
246
- services.getServiceFromClusterId({
247
- clusterId: testUrlTemplate.hosts[0].id,
248
- serviceGroup: 'signin',
249
- })
250
- );
251
- });
252
-
253
- it("returns undefined when service doesn't exist", () => {
254
- assert.isUndefined(services.getServiceFromClusterId({clusterId: 'not a clusterId'}));
255
- });
256
- });
257
-
258
- describe('#getServiceFromUrl()', () => {
259
- let testUrlTemplate;
260
- let testUrl;
261
-
262
- beforeEach('load test url', () => {
263
- testUrlTemplate = {
264
- defaultUrl: 'https://www.example.com/api/v1',
265
- hosts: [
266
- {
267
- host: 'www.example-p5.com',
268
- ttl: -1,
269
- priority: 5,
270
- id: 'exampleClusterId',
271
- },
272
- {
273
- host: 'www.example-p3.com',
274
- ttl: -1,
275
- priority: 3,
276
- id: 'exampleClusterId',
277
- },
278
- ],
279
- name: 'exampleValid',
280
- };
281
- testUrl = new ServiceUrl(testUrlTemplate);
282
- catalog._loadServiceUrls('preauth', [testUrl]);
283
- });
284
-
285
- afterEach('unload test url', () => {
286
- catalog._unloadServiceUrls('preauth', [testUrl]);
287
- });
288
-
289
- it('gets a valid service object from an existing service', () => {
290
- const serviceObject = services.getServiceFromUrl(testUrlTemplate.defaultUrl);
291
-
292
- assert.isDefined(serviceObject);
293
- assert.hasAllKeys(serviceObject, ['name', 'defaultUrl', 'priorityUrl']);
294
-
295
- assert.equal(testUrlTemplate.name, serviceObject.name);
296
- assert.equal(testUrlTemplate.defaultUrl, serviceObject.defaultUrl);
297
- assert.equal(testUrl.get(true), serviceObject.priorityUrl);
298
- });
299
-
300
- it("returns undefined when the service url doesn't exist", () => {
301
- const serviceObject = services.getServiceFromUrl('http://www.not-real.com/');
302
-
303
- assert.isUndefined(serviceObject);
304
- });
305
- });
306
-
307
- describe('#hasService()', () => {
308
- it('returns a boolean', () => {
309
- assert.isBoolean(services.hasService('some-url'));
310
- });
311
-
312
- it('validates that a service exists', () => {
313
- const service = Object.keys(services.list())[0];
314
-
315
- assert.isTrue(services.hasService(service));
316
- });
317
- });
318
-
319
- describe('#initConfig()', () => {
320
- it('should set the discovery catalog based on the provided links', () => {
321
- const key = 'test';
322
- const url = 'http://www.test.com/';
323
-
324
- webex.config.services.discovery[key] = url;
325
-
326
- services.initConfig();
327
-
328
- assert.equal(services.get(key), url);
329
- });
330
-
331
- it('should set the override catalog based on the provided links', () => {
332
- const key = 'testOverride';
333
- const url = 'http://www.test-override.com/';
334
-
335
- webex.config.services.override = {};
336
- webex.config.services.override[key] = url;
337
-
338
- services.initConfig();
339
-
340
- assert.equal(services.get(key), url);
341
- });
342
-
343
- it('should set validate domains to true when provided true', () => {
344
- webex.config.services.validateDomains = true;
345
-
346
- services.initConfig();
347
-
348
- assert.isTrue(services.validateDomains);
349
- });
350
-
351
- it('should set validate domains to false when provided false', () => {
352
- webex.config.services.validateDomains = false;
353
-
354
- services.initConfig();
355
-
356
- assert.isFalse(services.validateDomains);
357
- });
358
-
359
- it('should set the allowed domains based on the provided domains', () => {
360
- const allowedDomains = ['domain'];
361
-
362
- webex.config.services.allowedDomains = allowedDomains;
363
-
364
- services.initConfig();
365
-
366
- assert.deepEqual(allowedDomains, services._getCatalog().allowedDomains);
367
- });
368
- });
369
-
370
- describe('#initialize()', () => {
371
- it('should create a catalog', () =>
372
- assert.instanceOf(services._getCatalog(), ServiceCatalog));
373
-
374
- it('should create a registry', () =>
375
- assert.instanceOf(services.getRegistry(), ServiceRegistry));
376
-
377
- it('should create a state', () => assert.instanceOf(services.getState(), ServiceState));
378
-
379
- it('should call services#initConfig() when webex config changes', () => {
380
- services.initConfig = sinon.spy();
381
- services.initialize();
382
- webex.trigger('change:config');
383
- assert.called(services.initConfig);
384
- assert.isTrue(catalog.isReady);
385
- });
386
-
387
- it('should call services#initServiceCatalogs() on webex ready', () => {
388
- services.initServiceCatalogs = sinon.stub().resolves();
389
- services.initialize();
390
- webex.trigger('ready');
391
- assert.called(services.initServiceCatalogs);
392
- assert.isTrue(catalog.isReady);
393
- });
394
-
395
- it('should collect different catalogs based on OrgId region', () =>
396
- assert.notDeepEqual(services.list(true), servicesEU.list(true)));
397
-
398
- it('should not attempt to collect catalogs without authorization', (done) => {
399
- const otherWebex = new WebexCore();
400
- let {initServiceCatalogs} = otherWebex.internal.services;
401
-
402
- initServiceCatalogs = sinon.stub();
403
-
404
- setTimeout(() => {
405
- assert.notCalled(initServiceCatalogs);
406
- assert.isFalse(otherWebex.internal.services._getCatalog().isReady);
407
- done();
408
- }, 2000);
409
- });
410
- });
411
-
412
- describe('#initServiceCatalogs()', () => {
413
- it('should reject if a OrgId cannot be retrieved', () => {
414
- webex.credentials.getOrgId = sinon.stub().throws();
415
-
416
- return assert.isRejected(services.initServiceCatalogs());
417
- });
418
-
419
- it('should call services#collectPreauthCatalog with the OrgId', () => {
420
- services.collectPreauthCatalog = sinon.stub().resolves();
421
-
422
- return services.initServiceCatalogs().then(() =>
423
- assert.calledWith(
424
- services.collectPreauthCatalog,
425
- sinon.match({
426
- orgId: webex.credentials.getOrgId(),
427
- })
428
- )
429
- );
430
- });
431
-
432
- it('should not call services#updateServices() when not authed', () => {
433
- services.updateServices = sinon.stub().resolves();
434
-
435
- // Since credentials uses AmpState, we have to set the derived
436
- // properties of the dependent properties to undefined.
437
- webex.credentials.supertoken.access_token = undefined;
438
- webex.credentials.supertoken.refresh_token = undefined;
439
-
440
- webex.credentials.getOrgId = sinon.stub().returns(webexUser.orgId);
441
-
442
- return (
443
- services
444
- .initServiceCatalogs()
445
- // services#updateServices() gets called once by the limited catalog
446
- // retrieval and should not be called again when not authorized.
447
- .then(() => assert.calledOnce(services.updateServices))
448
- );
449
- });
450
-
451
- it('should call services#updateServices() when authed', () => {
452
- services.updateServices = sinon.stub().resolves();
453
-
454
- return (
455
- services
456
- .initServiceCatalogs()
457
- // services#updateServices() gets called once by the limited catalog
458
- // retrieval and should get called again when authorized.
459
- .then(() => assert.calledTwice(services.updateServices))
460
- );
461
- });
462
- });
463
-
464
- describe('#isServiceUrl()', () => {
465
- let testUrlTemplate;
466
- let testUrl;
467
-
468
- beforeEach('load test url', () => {
469
- testUrlTemplate = {
470
- defaultUrl: 'https://www.example.com/api/v1',
471
- hosts: [
472
- {
473
- homeCluster: true,
474
- host: 'www.example-p5.com',
475
- ttl: -1,
476
- priority: 5,
477
- id: 'exampleClusterId',
478
- },
479
- {
480
- host: 'www.example-p3.com',
481
- ttl: -1,
482
- priority: 3,
483
- id: 'exampleClusterId',
484
- },
485
- ],
486
- name: 'exampleValid',
487
- };
488
- testUrl = new ServiceUrl(testUrlTemplate);
489
- catalog._loadServiceUrls('preauth', [testUrl]);
490
- });
491
-
492
- it('returns true if url is a service url', () => {
493
- assert.isTrue(services.isServiceUrl(testUrlTemplate.defaultUrl));
494
- });
495
-
496
- it('returns true for priority host urls', () => {
497
- assert.isTrue(services.isServiceUrl(testUrl.get(true)));
498
- });
499
-
500
- it("returns undefined if the url doesn't exist", () => {
501
- assert.isFalse(services.isServiceUrl('https://na.com/'));
502
- });
503
-
504
- it('returns undefined if the param is not a url', () => {
505
- assert.isFalse(services.isServiceUrl('not a url'));
506
- });
507
- });
508
-
509
- describe('#isAllowedDomainUrl()', () => {
510
- let list;
511
-
512
- beforeEach(() => {
513
- catalog.setAllowedDomains(['some-domain-a', 'some-domain-b']);
514
-
515
- list = catalog.getAllowedDomains();
516
- });
517
-
518
- it('returns a boolean', () => {
519
- assert.isBoolean(services.isAllowedDomainUrl(''));
520
- });
521
-
522
- it('returns true if the url contains an allowed domain', () => {
523
- assert.isTrue(services.isAllowedDomainUrl(`https://${list[0]}/resource`));
524
- });
525
-
526
- it('returns false if the url does not contain an allowed domain', () => {
527
- assert.isFalse(services.isAllowedDomainUrl('https://bad-domain/resource'));
528
- });
529
- });
530
-
531
- describe('#convertUrlToPriorityUrl', () => {
532
- let testUrl;
533
- let testUrlTemplate;
534
-
535
- beforeEach('load test url', () => {
536
- testUrlTemplate = {
537
- defaultUrl: 'https://www.example.com/api/v1',
538
- hosts: [
539
- {
540
- homeCluster: true,
541
- host: 'www.example-p5.com',
542
- ttl: -1,
543
- priority: 5,
544
- id: '0:0:cluster-a:exampleValid',
545
- },
546
- {
547
- host: 'www.example-p3.com',
548
- ttl: -1,
549
- priority: 3,
550
- id: '0:0:cluster-b:exampleValid',
551
- },
552
- ],
553
- name: 'exampleValid',
554
- };
555
- testUrl = new ServiceUrl(testUrlTemplate);
556
- catalog._loadServiceUrls('preauth', [testUrl]);
557
- });
558
-
559
- it('converts the url to a priority host url', () => {
560
- const resource = 'path/to/resource';
561
- const url = `${testUrlTemplate.defaultUrl}/${resource}`;
562
-
563
- const convertUrl = services.convertUrlToPriorityHostUrl(url);
564
-
565
- assert.isDefined(convertUrl);
566
- assert.isTrue(convertUrl.includes(testUrlTemplate.hosts[0].host));
567
- });
568
-
569
- it('throws an exception if not a valid service', () => {
570
- assert.throws(services.convertUrlToPriorityHostUrl, Error);
571
-
572
- assert.throws(
573
- services.convertUrlToPriorityHostUrl.bind(services, 'not-a-valid-service'),
574
- Error
575
- );
576
- });
577
-
578
- afterEach('unload test url', () => {
579
- catalog._unloadServiceUrls('preauth', [testUrl]);
580
- });
581
- });
582
-
583
- describe('#markFailedUrl()', () => {
584
- let testUrlTemplate;
585
- let testUrl;
586
-
587
- beforeEach('load test url', () => {
588
- catalog.clean();
589
-
590
- testUrlTemplate = {
591
- defaultUrl: 'https://www.example-phr.com/api/v1',
592
- hosts: [
593
- {
594
- host: 'www.example-phr-p5.com',
595
- ttl: -1,
596
- priority: 5,
597
- homeCluster: true,
598
- },
599
- {
600
- host: 'www.example-phr-p3.com',
601
- ttl: -1,
602
- priority: 3,
603
- homeCluster: true,
604
- },
605
- ],
606
- name: 'exampleValid-phr',
607
- };
608
- testUrl = new ServiceUrl(testUrlTemplate);
609
- catalog._loadServiceUrls('preauth', [testUrl]);
610
- });
611
-
612
- afterEach('unload test url', () => {
613
- catalog._unloadServiceUrls('preauth', [testUrl]);
614
- });
615
-
616
- it('marks a host as failed', () => {
617
- const priorityServiceUrl = catalog._getUrl(testUrlTemplate.name);
618
- const priorityUrl = priorityServiceUrl._getPriorityHostUrl();
619
-
620
- services.markFailedUrl(priorityUrl);
621
-
622
- const failedHost = priorityServiceUrl.hosts.find((host) => host.failed);
623
-
624
- assert.isTrue(priorityUrl.includes(failedHost.host));
625
- });
626
-
627
- it('returns the next priority url', () => {
628
- const priorityUrl = services.get(testUrlTemplate.name, true);
629
-
630
- const nextPriorityUrl = services.markFailedUrl(priorityUrl);
631
-
632
- assert.notEqual(priorityUrl, nextPriorityUrl);
633
- });
634
-
635
- it('should reset hosts once all hosts have been marked failed', () => {
636
- const priorityServiceUrl = catalog._getUrl(testUrlTemplate.name);
637
- const firstPriorityUrl = priorityServiceUrl._getPriorityHostUrl();
638
-
639
- priorityServiceUrl.hosts.forEach(() => {
640
- const priorityUrl = priorityServiceUrl._getPriorityHostUrl();
641
-
642
- services.markFailedUrl(priorityUrl);
643
- });
644
-
645
- const lastPriorityUrl = priorityServiceUrl._getPriorityHostUrl();
646
-
647
- assert.equal(firstPriorityUrl, lastPriorityUrl);
648
- });
649
- });
650
-
651
- describe('#updateServices()', () => {
652
- it('returns a Promise that and resolves on success', (done) => {
653
- const servicesPromise = services.updateServices();
654
-
655
- assert.typeOf(servicesPromise, 'Promise');
656
-
657
- servicesPromise.then(() => {
658
- Object.keys(services.list()).forEach((key) => {
659
- assert.typeOf(key, 'string');
660
- assert.typeOf(services.list()[key], 'string');
661
- });
662
-
663
- done();
664
- });
665
- });
666
-
667
- it('updates the services list', (done) => {
668
- catalog.serviceGroups.postauth = [];
669
-
670
- services.updateServices().then(() => {
671
- assert.isAbove(catalog.serviceGroups.postauth.length, 0);
672
- done();
673
- });
674
-
675
- services.updateServices();
676
- });
677
-
678
- it('updates query.email to be emailhash-ed using SHA256', (done) => {
679
- catalog.updateServiceUrls = sinon.stub().returns({}); // returns `this`
680
- services._fetchNewServiceHostmap = sinon.stub().resolves();
681
-
682
- services
683
- .updateServices({
684
- from: 'limited',
685
- query: {email: webexUser.email},
686
- })
687
- .then(() => {
688
- assert.calledWith(
689
- services._fetchNewServiceHostmap,
690
- sinon.match.has('query', {emailhash: sinon.match(/\b[A-Fa-f0-9]{64}\b/)})
691
- );
692
- done();
693
- });
694
- });
695
-
696
- it('updates the limited catalog when email is provided', (done) => {
697
- catalog.serviceGroups.preauth = [];
698
-
699
- services
700
- .updateServices({
701
- from: 'limited',
702
- query: {email: webexUser.email},
703
- })
704
- .then(() => {
705
- assert.isAbove(catalog.serviceGroups.preauth.length, 0);
706
- done();
707
- });
708
- });
709
-
710
- it('updates the limited catalog when userId is provided', (done) => {
711
- catalog.serviceGroups.preauth = [];
712
-
713
- services
714
- .updateServices({
715
- from: 'limited',
716
- query: {userId: webexUser.id},
717
- })
718
- .then(() => {
719
- assert.isAbove(catalog.serviceGroups.preauth.length, 0);
720
- done();
721
- });
722
- });
723
-
724
- it('updates the limited catalog when orgId is provided', (done) => {
725
- catalog.serviceGroups.preauth = [];
726
-
727
- services
728
- .updateServices({
729
- from: 'limited',
730
- query: {orgId: webexUser.orgId},
731
- })
732
- .then(() => {
733
- assert.isAbove(catalog.serviceGroups.preauth.length, 0);
734
- done();
735
- });
736
- });
737
- it('updates the limited catalog when query param mode is provided', (done) => {
738
- catalog.serviceGroups.preauth = [];
739
-
740
- services
741
- .updateServices({
742
- from: 'limited',
743
- query: {mode: 'DEFAULT_BY_PROXIMITY'},
744
- })
745
- .then(() => {
746
- assert.isAbove(catalog.serviceGroups.preauth.length, 0);
747
- done();
748
- });
749
- });
750
- it('does not update the limited catalog when nothing is provided', () => {
751
- catalog.serviceGroups.preauth = [];
752
-
753
- return services
754
- .updateServices({from: 'limited'})
755
- .then(() => {
756
- assert(false, 'resolved, should have thrown');
757
- })
758
- .catch(() => {
759
- assert(true);
760
- });
761
- });
762
-
763
- it('updates limited catalog and calls _fetchNewServiceHostmap with forceRefresh = true', (done) => {
764
- const forceRefresh = true;
765
- const fetchNewServiceHostmapSpy = sinon.spy(services, '_fetchNewServiceHostmap');
766
-
767
- services
768
- .updateServices({
769
- from: 'limited',
770
- query: {email: webexUser.email},
771
- forceRefresh,
772
- })
773
- .then(() => {
774
- assert.calledOnce(fetchNewServiceHostmapSpy);
775
- assert.calledWith(
776
- fetchNewServiceHostmapSpy,
777
- sinon.match.has(
778
- 'from',
779
- 'limited',
780
- 'query',
781
- {emailhash: sinon.match(/\b[A-Fa-f0-9]{64}\b/)},
782
- 'forceFresh',
783
- forceRefresh
784
- )
785
- );
786
-
787
- fetchNewServiceHostmapSpy.returnValues[0].then((res) => {
788
- assert.isAbove(res.length, 0);
789
- });
790
- done();
791
- });
792
- });
793
- });
794
-
795
- describe('#fetchClientRegionInfo()', () => {
796
- it('returns client region info', () =>
797
- services.fetchClientRegionInfo().then((r) => {
798
- assert.isDefined(r.countryCode);
799
- assert.isDefined(r.timezone);
800
- }));
801
- });
802
-
803
- describe('#validateUser()', () => {
804
- const unauthWebex = new WebexCore();
805
- const unauthServices = unauthWebex.internal.services;
806
- let sandbox = null;
807
-
808
- const getActivationRequest = (requestStub) => {
809
- const requests = requestStub.args.filter(
810
- ([request]) => request.service === 'license' && request.resource === 'users/activations'
811
- );
812
-
813
- assert.strictEqual(requests.length, 1);
814
-
815
- return requests[0][0];
816
- };
817
-
818
- beforeEach(() => {
819
- sandbox = sinon.createSandbox();
820
- });
821
-
822
- afterEach(() => {
823
- sandbox.restore();
824
- sandbox = null;
825
- });
826
-
827
- it('returns a rejected promise when no email is specified', () =>
828
- unauthServices
829
- .validateUser({})
830
- .then(() => {
831
- assert(false, 'resolved, should have thrown');
832
- })
833
- .catch(() => {
834
- assert(true);
835
- }));
836
-
837
- it('validates an authorized user and webex instance', () =>
838
- services.validateUser({email: webexUser.email}).then((r) => {
839
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
840
- assert.equal(r.activated, true);
841
- assert.equal(r.exists, true);
842
- }));
843
-
844
- it('validates an authorized EU user and webex instance', () =>
845
- servicesEU.validateUser({email: webexUserEU.email}).then((r) => {
846
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
847
- assert.equal(r.activated, true);
848
- assert.equal(r.exists, true);
849
- }));
850
-
851
- it("returns a rejected promise if the provided email isn't valid", () =>
852
- unauthServices
853
- .validateUser({email: 'not an email'})
854
- .then(() => {
855
- assert(false, 'resolved, should have thrown');
856
- })
857
- .catch(() => {
858
- assert(true);
859
- }));
860
-
861
- it('validates a non-existing user', () =>
862
- unauthServices
863
- .validateUser({email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`})
864
- .then((r) => {
865
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
866
- assert.equal(r.activated, false);
867
- assert.equal(r.exists, false);
868
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
869
- assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
870
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
871
- }));
872
-
873
- it('validates new user with activationOptions suppressEmail false', () =>
874
- unauthServices
875
- .validateUser({
876
- email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
877
- activationOptions: {suppressEmail: false},
878
- })
879
- .then((r) => {
880
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
881
- assert.equal(r.activated, false);
882
- assert.equal(r.exists, false);
883
- assert.equal(r.user.verificationEmailTriggered, true);
884
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
885
- assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
886
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
887
- }));
888
-
889
- it('validates new user with activationOptions suppressEmail true', () =>
890
- unauthServices
891
- .validateUser({
892
- email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
893
- activationOptions: {suppressEmail: true},
894
- })
895
- .then((r) => {
896
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
897
- assert.equal(r.activated, false);
898
- assert.equal(r.exists, false);
899
- assert.equal(r.user.verificationEmailTriggered, false);
900
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
901
- assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
902
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
903
- }));
904
-
905
- it('validates an inactive user', () => {
906
- const inactive = 'webex.web.client+nonactivated@gmail.com';
907
-
908
- return unauthServices
909
- .validateUser({email: inactive, activationOptions: {suppressEmail: true}})
910
- .then((r) => {
911
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
912
- assert.equal(r.activated, false, 'activated');
913
- assert.equal(r.exists, true, 'exists');
914
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
915
- assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
916
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
917
- })
918
- .catch(() => {
919
- assert(true);
920
- });
921
- });
922
-
923
- it('validates an existing user', () =>
924
- unauthServices.validateUser({email: webexUser.email}).then((r) => {
925
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
926
- assert.equal(r.activated, true);
927
- assert.equal(r.exists, true);
928
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
929
- assert.isAbove(Object.keys(unauthServices.list(false, 'signin')).length, 0);
930
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
931
- }));
932
-
933
- it('validates an existing EU user', () =>
934
- unauthServices.validateUser({email: webexUserEU.email}).then((r) => {
935
- assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
936
- assert.equal(r.activated, true);
937
- assert.equal(r.exists, true);
938
- assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
939
- assert.isAbove(Object.keys(unauthServices.list(false, 'signin')).length, 0);
940
- assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
941
- }));
942
-
943
- it('sends the prelogin user id as undefined when not specified', () => {
944
- const requestStub = sandbox.spy(unauthServices, 'request');
945
-
946
- return unauthServices
947
- .validateUser({
948
- email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
949
- activationOptions: {suppressEmail: true},
950
- })
951
- .then(() => {
952
- assert.isUndefined(getActivationRequest(requestStub).headers['x-prelogin-userid']);
953
- });
954
- });
955
-
956
- it('sends the prelogin user id as provided when specified', () => {
957
- const requestStub = sandbox.spy(unauthServices, 'request');
958
- const preloginUserId = uuid.v4();
959
-
960
- return unauthServices
961
- .validateUser({
962
- email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
963
- activationOptions: {suppressEmail: true},
964
- preloginUserId,
965
- })
966
- .then(() => {
967
- assert.strictEqual(
968
- getActivationRequest(requestStub).headers['x-prelogin-userid'],
969
- preloginUserId
970
- );
971
- });
972
- });
973
- });
974
-
975
- describe('#waitForService()', () => {
976
- let name;
977
- let url;
978
-
979
- describe('when the service exists', () => {
980
- beforeEach('collect valid service info', () => {
981
- name = Object.keys(services.list())[0];
982
- url = services.list(true)[name];
983
- });
984
-
985
- describe('when using the name parameter property', () => {
986
- it('should resolve to the appropriate url', () =>
987
- services.waitForService({name}).then((foundUrl) => assert.equal(foundUrl, url)));
988
- });
989
-
990
- describe('when using the url parameter property', () => {
991
- it('should resolve to the appropriate url', () =>
992
- services.waitForService({url}).then((foundUrl) => assert.equal(foundUrl, url)));
993
- });
994
-
995
- describe('when using the url and name parameter properties', () => {
996
- it('should resolve to the appropriate url', () =>
997
- services.waitForService({name, url}).then((foundUrl) => assert.equal(foundUrl, url)));
998
- });
999
- });
1000
-
1001
- describe('when the service does not exist', () => {
1002
- let timeout;
1003
-
1004
- beforeEach('set up the parameters', () => {
1005
- name = 'not a service';
1006
- url = 'http://not-a-service.com/resource';
1007
- timeout = 1;
1008
- });
1009
-
1010
- describe('when using the url parameter property', () => {
1011
- it('should return a resolve promise', () =>
1012
- // const waitForService = services.waitForService({url, timeout});
1013
-
1014
- services.waitForService({url, timeout}).then((foundUrl) => {
1015
- assert.equal(foundUrl, url);
1016
- assert.isTrue(catalog.isReady);
1017
- }));
1018
- });
1019
-
1020
- describe('when using the name parameter property', () => {
1021
- it('should return a rejected promise', () => {
1022
- const submitMetrics = sinon.stub(webex.internal.metrics, 'submitClientMetrics');
1023
- const waitForService = services.waitForService({name, timeout});
1024
-
1025
- assert.called(submitMetrics);
1026
- assert.isRejected(waitForService);
1027
- assert.isTrue(catalog.isReady);
1028
- });
1029
- });
1030
-
1031
- describe('when using the name and url parameter properties', () => {
1032
- it('should return a rejected promise', () => {
1033
- const waitForService = services.waitForService({
1034
- name,
1035
- url,
1036
- timeout,
1037
- });
1038
-
1039
- assert.isRejected(waitForService);
1040
- assert.isTrue(catalog.isReady);
1041
- });
1042
- });
1043
-
1044
- describe('when the service will exist', () => {
1045
- beforeEach('collect existing service and clear the catalog', () => {
1046
- name = 'metrics';
1047
- url = services.get(name, true);
1048
- catalog.clean();
1049
- catalog.isReady = false;
1050
- });
1051
-
1052
- describe('when only the preauth (limited) catalog becomes available', () => {
1053
- describe('when using the name parameter property', () => {
1054
- it('should resolve to the appropriate url', () =>
1055
- Promise.all([
1056
- services.waitForService({name}),
1057
- services.collectPreauthCatalog(),
1058
- ]).then(([foundUrl]) => assert.equal(foundUrl, url)));
1059
- });
1060
-
1061
- describe('when using the url parameter property', () => {
1062
- it('should resolve to the appropriate url', () =>
1063
- Promise.all([
1064
- services.waitForService({url}),
1065
- services.collectPreauthCatalog(),
1066
- ]).then(([foundUrl]) => assert.equal(foundUrl, url)));
1067
- });
1068
-
1069
- describe('when using the name and url parameter property', () => {
1070
- it('should resolve to the appropriate url', () =>
1071
- Promise.all([
1072
- services.waitForService({name, url}),
1073
- services.collectPreauthCatalog(),
1074
- ]).then(([foundUrl]) => assert.equal(foundUrl, url)));
1075
- });
1076
- });
1077
-
1078
- describe('when all catalogs become available', () => {
1079
- describe('when using the name parameter property', () => {
1080
- it('should resolve to the appropriate url', () =>
1081
- Promise.all([services.waitForService({name}), services.initServiceCatalogs()]).then(
1082
- ([foundUrl]) => assert.equal(foundUrl, url)
1083
- ));
1084
- });
1085
-
1086
- describe('when using the url parameter property', () => {
1087
- it('should resolve to the appropriate url', () =>
1088
- Promise.all([services.waitForService({url}), services.initServiceCatalogs()]).then(
1089
- ([foundUrl]) => assert.equal(foundUrl, url)
1090
- ));
1091
- });
1092
-
1093
- describe('when using the name and url parameter property', () => {
1094
- it('should resolve to the appropriate url', () =>
1095
- Promise.all([
1096
- services.waitForService({name, url}),
1097
- services.initServiceCatalogs(),
1098
- ]).then(([foundUrl]) => assert.equal(foundUrl, url)));
1099
- });
1100
- });
1101
- });
1102
- });
1103
- });
1104
-
1105
- describe('#collectPreauthCatalog()', () => {
1106
- const unauthWebex = new WebexCore({config: {credentials: {federation: true}}});
1107
- const unauthServices = unauthWebex.internal.services;
1108
- const forceRefresh = true;
1109
-
1110
- it('updates the preauth catalog without email', () =>
1111
- unauthServices.collectPreauthCatalog().then(() => {
1112
- assert.isAbove(Object.keys(unauthServices.list()).length, 0);
1113
- }));
1114
-
1115
- it('updates the preauth catalog with email', () =>
1116
- unauthServices.collectPreauthCatalog({email: webexUser.email}).then(() => {
1117
- assert.isAbove(Object.keys(unauthServices.list()).length, 0);
1118
- }));
1119
-
1120
- it('updates the preauth catalog with email along with additional timestamp to address cache control', (done) => {
1121
- const updateServiceSpy = sinon.spy(unauthServices, 'updateServices');
1122
- const fetchNewServiceHostmapSpy = sinon.spy(unauthServices, '_fetchNewServiceHostmap');
1123
-
1124
- unauthServices.collectPreauthCatalog({email: webexUser.email}, forceRefresh).then(() => {
1125
- assert.calledOnce(updateServiceSpy);
1126
- assert.calledWith(
1127
- updateServiceSpy,
1128
- sinon.match.has(
1129
- 'from',
1130
- 'limited',
1131
- 'query',
1132
- {emailhash: sinon.match(/\b[A-Fa-f0-9]{64}\b/)},
1133
- 'forceRefresh',
1134
- forceRefresh
1135
- )
1136
- );
1137
-
1138
- assert.calledOnce(fetchNewServiceHostmapSpy);
1139
- assert.calledWith(
1140
- fetchNewServiceHostmapSpy,
1141
- sinon.match.has(
1142
- 'from',
1143
- 'limited',
1144
- 'query',
1145
- {emailhash: sinon.match(/\b[A-Fa-f0-9]{64}\b/)},
1146
- 'forceRefresh',
1147
- forceRefresh
1148
- )
1149
- );
1150
-
1151
- fetchNewServiceHostmapSpy.returnValues[0].then((res) => {
1152
- assert.isAbove(res.length, 0);
1153
- });
1154
- done();
1155
- });
1156
- });
1157
- });
1158
-
1159
- describe('#collectSigninCatalog()', () => {
1160
- const unauthWebex = new WebexCore({config: {credentials: {federation: true}}});
1161
- const unauthServices = unauthWebex.internal.services;
1162
-
1163
- it('requires an email as the parameter', () =>
1164
- unauthServices.collectPreauthCatalog().catch((e) => {
1165
- assert(true, e);
1166
- }));
1167
-
1168
- it('requires a token as the parameter', () =>
1169
- unauthServices.collectPreauthCatalog({email: 'email@website.com'}).catch((e) => {
1170
- assert(true, e);
1171
- }));
1172
-
1173
- it('updates the preauth catalog', () =>
1174
- unauthServices.collectPreauthCatalog({email: webexUser.email}).then(() => {
1175
- assert.isAbove(Object.keys(unauthServices.list()).length, 0);
1176
- }));
1177
- });
1178
-
1179
- flaky(describe, process.env.SKIP_FLAKY_TESTS)('#_fetchNewServiceHostmap()', () => {
1180
- let fullRemoteHM;
1181
- let limitedRemoteHM;
1182
-
1183
- before('collect remote catalogs', () =>
1184
- Promise.all([
1185
- services._fetchNewServiceHostmap(),
1186
- services._fetchNewServiceHostmap({
1187
- from: 'limited',
1188
- query: {userId: webexUser.id},
1189
- }),
1190
- ]).then(([fRHM, lRHM]) => {
1191
- fullRemoteHM = fRHM;
1192
- limitedRemoteHM = lRHM;
1193
- })
1194
- );
1195
-
1196
- it('resolves to an authed u2c hostmap when no params specified', () => {
1197
- assert.typeOf(fullRemoteHM, 'array');
1198
- assert.isAbove(fullRemoteHM.length, 0);
1199
- });
1200
-
1201
- it('resolves to a limited u2c hostmap when params specified', () => {
1202
- assert.typeOf(limitedRemoteHM, 'array');
1203
- assert.isAbove(limitedRemoteHM.length, 0);
1204
- });
1205
-
1206
- it('rejects if the params provided are invalid', () =>
1207
- services
1208
- ._fetchNewServiceHostmap({
1209
- from: 'limited',
1210
- query: {userId: 'notValid'},
1211
- })
1212
- .then(() => {
1213
- assert.isTrue(false, 'should have rejected');
1214
- })
1215
- .catch((e) => {
1216
- assert.typeOf(e, 'Error');
1217
- }));
1218
- });
1219
- });
1220
- });
1221
- /* eslint-enable no-underscore-dangle */
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import '@webex/internal-plugin-device';
6
+
7
+ import {assert} from '@webex/test-helper-chai';
8
+ import {flaky} from '@webex/test-helper-mocha';
9
+ import WebexCore, {
10
+ ServiceCatalog,
11
+ ServiceRegistry,
12
+ ServiceState,
13
+ ServiceUrl,
14
+ } from '@webex/webex-core';
15
+ import testUsers from '@webex/test-helper-test-users';
16
+ import uuid from 'uuid';
17
+ import sinon from 'sinon';
18
+
19
+ /* eslint-disable no-underscore-dangle */
20
+ describe('webex-core', () => {
21
+ describe('Services', () => {
22
+ let webexUser;
23
+ let webexUserEU;
24
+ let webex;
25
+ let webexEU;
26
+ let services;
27
+ let servicesEU;
28
+ let catalog;
29
+
30
+ before('create users', () =>
31
+ Promise.all([
32
+ testUsers.create({count: 1}),
33
+ testUsers.create({
34
+ count: 1,
35
+ config: {
36
+ orgId: process.env.EU_PRIMARY_ORG_ID,
37
+ },
38
+ }),
39
+ ]).then(([[user], [userEU]]) => {
40
+ webexUser = user;
41
+ webexUserEU = userEU;
42
+ })
43
+ );
44
+
45
+ beforeEach('create webex instance', () => {
46
+ webex = new WebexCore({credentials: {supertoken: webexUser.token}});
47
+ webexEU = new WebexCore({credentials: {supertoken: webexUserEU.token}});
48
+ services = webex.internal.services;
49
+ servicesEU = webexEU.internal.services;
50
+ catalog = services._getCatalog();
51
+
52
+ return Promise.all([
53
+ services.waitForCatalog('postauth', 10),
54
+ servicesEU.waitForCatalog('postauth', 10),
55
+ ]).then(() =>
56
+ services.updateServices({
57
+ from: 'limited',
58
+ query: {userId: webexUser.id},
59
+ })
60
+ );
61
+ });
62
+
63
+ describe('#_getCatalog()', () => {
64
+ it('returns a catalog', () => {
65
+ const localCatalog = services._getCatalog();
66
+
67
+ assert.equal(localCatalog.namespace, 'ServiceCatalog');
68
+ });
69
+ });
70
+
71
+ describe('#list()', () => {
72
+ it('matches the values in serviceUrl', () => {
73
+ let serviceList = services.list();
74
+
75
+ Object.keys(serviceList).forEach((key) => {
76
+ assert.equal(serviceList[key], catalog._getUrl(key).get());
77
+ });
78
+
79
+ serviceList = services.list(true);
80
+ Object.keys(serviceList).forEach((key) => {
81
+ assert.equal(serviceList[key], catalog._getUrl(key).get(true));
82
+ });
83
+ });
84
+ });
85
+
86
+ describe('#get()', () => {
87
+ let testUrlTemplate;
88
+ let testUrl;
89
+
90
+ beforeEach('load test url', () => {
91
+ testUrlTemplate = {
92
+ defaultUrl: 'https://www.example.com/api/v1',
93
+ hosts: [],
94
+ name: 'exampleValid',
95
+ };
96
+ testUrl = new ServiceUrl(testUrlTemplate);
97
+ catalog._loadServiceUrls('preauth', [testUrl]);
98
+ });
99
+
100
+ afterEach('unload test url', () => {
101
+ catalog._unloadServiceUrls('preauth', [testUrl]);
102
+ });
103
+
104
+ it('returns a valid string when name is specified', () => {
105
+ const url = services.get(testUrlTemplate.name);
106
+
107
+ assert.typeOf(url, 'string');
108
+ assert.equal(url, testUrlTemplate.defaultUrl);
109
+ });
110
+
111
+ it("returns undefined if url doesn't exist", () => {
112
+ const s = services.get('invalidUrl');
113
+
114
+ assert.typeOf(s, 'undefined');
115
+ });
116
+
117
+ it('gets a service from a specific serviceGroup', () => {
118
+ assert.isDefined(services.get(testUrlTemplate.name, false, 'preauth'));
119
+ });
120
+
121
+ it("fails to get a service if serviceGroup isn't accurate", () => {
122
+ assert.isUndefined(services.get(testUrlTemplate.name, false, 'discovery'));
123
+ });
124
+ });
125
+
126
+ describe('#getClusterId()', () => {
127
+ let testUrlTemplate;
128
+ let testUrl;
129
+
130
+ beforeEach('load test url', () => {
131
+ testUrlTemplate = {
132
+ defaultUrl: 'https://www.example.com/api/v1',
133
+ hosts: [
134
+ {
135
+ homeCluster: true,
136
+ host: 'www.example-p5.com',
137
+ ttl: -1,
138
+ priority: 5,
139
+ id: 'exampleClusterId',
140
+ },
141
+ {
142
+ host: 'www.example-p3.com',
143
+ ttl: -1,
144
+ priority: 3,
145
+ id: 'exampleClusterId',
146
+ },
147
+ ],
148
+ name: 'exampleValid',
149
+ };
150
+ testUrl = new ServiceUrl(testUrlTemplate);
151
+ catalog._loadServiceUrls('preauth', [testUrl]);
152
+ });
153
+
154
+ it('returns a clusterId when found with default url', () => {
155
+ assert.equal(
156
+ services.getClusterId(testUrlTemplate.defaultUrl),
157
+ testUrlTemplate.hosts[0].id
158
+ );
159
+ });
160
+
161
+ it('returns a clusterId when found with priority host url', () => {
162
+ assert.equal(services.getClusterId(testUrl.get(true)), testUrlTemplate.hosts[0].id);
163
+ });
164
+
165
+ it('returns a clusterId when found with resource-appended url', () => {
166
+ assert.equal(
167
+ services.getClusterId(`${testUrl.get()}example/resource/value`),
168
+ testUrlTemplate.hosts[0].id
169
+ );
170
+ });
171
+
172
+ it("returns undefined when the url doesn't exist in catalog", () => {
173
+ assert.isUndefined(services.getClusterId('http://not-a-known-url.com/'));
174
+ });
175
+
176
+ it("returns undefined when the string isn't a url", () => {
177
+ assert.isUndefined(services.getClusterId('not a url'));
178
+ });
179
+ });
180
+
181
+ describe('#getServiceFromClusterId()', () => {
182
+ let testUrlTemplate;
183
+ let testUrl;
184
+
185
+ beforeEach('load test url', () => {
186
+ testUrlTemplate = {
187
+ defaultUrl: 'https://www.example.com/api/v1',
188
+ hosts: [
189
+ {
190
+ homeCluster: true,
191
+ host: 'www.example-p5.com',
192
+ ttl: -1,
193
+ priority: 5,
194
+ id: '0:0:cluster-a:exampleValid',
195
+ },
196
+ {
197
+ host: 'www.example-p3.com',
198
+ ttl: -1,
199
+ priority: 3,
200
+ id: '0:0:cluster-b:exampleValid',
201
+ },
202
+ ],
203
+ name: 'exampleValid',
204
+ };
205
+ testUrl = new ServiceUrl(testUrlTemplate);
206
+ catalog._loadServiceUrls('preauth', [testUrl]);
207
+ });
208
+
209
+ it('finds a valid service url from only a clusterId', () => {
210
+ const serviceFound = services.getServiceFromClusterId({
211
+ clusterId: testUrlTemplate.hosts[0].id,
212
+ priorityHost: false,
213
+ });
214
+
215
+ assert.equal(serviceFound.name, testUrl.name);
216
+ assert.equal(serviceFound.url, testUrl.defaultUrl);
217
+ });
218
+
219
+ it('finds a valid priority service url', () => {
220
+ const serviceFound = services.getServiceFromClusterId({
221
+ clusterId: testUrlTemplate.hosts[0].id,
222
+ priorityHost: true,
223
+ });
224
+
225
+ assert.equal(serviceFound.name, testUrl.name);
226
+ assert.isTrue(
227
+ serviceFound.url.includes(testUrlTemplate.hosts[0].host),
228
+ `'${serviceFound.url}' is not host '${testUrlTemplate.hosts[0].host}'`
229
+ );
230
+ // assert.equal(serviceFound.url, catalog.get('exampleValid', true));
231
+ });
232
+
233
+ it('finds a valid service when a service group is defined', () => {
234
+ const serviceFound = catalog.findServiceFromClusterId({
235
+ clusterId: testUrlTemplate.hosts[0].id,
236
+ priorityHost: false,
237
+ serviceGroup: 'preauth',
238
+ });
239
+
240
+ assert.equal(serviceFound.name, testUrl.name);
241
+ assert.equal(serviceFound.url, testUrl.defaultUrl);
242
+ });
243
+
244
+ it("fails to find a valid service when it's not in a group", () => {
245
+ assert.isUndefined(
246
+ services.getServiceFromClusterId({
247
+ clusterId: testUrlTemplate.hosts[0].id,
248
+ serviceGroup: 'signin',
249
+ })
250
+ );
251
+ });
252
+
253
+ it("returns undefined when service doesn't exist", () => {
254
+ assert.isUndefined(services.getServiceFromClusterId({clusterId: 'not a clusterId'}));
255
+ });
256
+ });
257
+
258
+ describe('#getServiceFromUrl()', () => {
259
+ let testUrlTemplate;
260
+ let testUrl;
261
+
262
+ beforeEach('load test url', () => {
263
+ testUrlTemplate = {
264
+ defaultUrl: 'https://www.example.com/api/v1',
265
+ hosts: [
266
+ {
267
+ host: 'www.example-p5.com',
268
+ ttl: -1,
269
+ priority: 5,
270
+ id: 'exampleClusterId',
271
+ },
272
+ {
273
+ host: 'www.example-p3.com',
274
+ ttl: -1,
275
+ priority: 3,
276
+ id: 'exampleClusterId',
277
+ },
278
+ ],
279
+ name: 'exampleValid',
280
+ };
281
+ testUrl = new ServiceUrl(testUrlTemplate);
282
+ catalog._loadServiceUrls('preauth', [testUrl]);
283
+ });
284
+
285
+ afterEach('unload test url', () => {
286
+ catalog._unloadServiceUrls('preauth', [testUrl]);
287
+ });
288
+
289
+ it('gets a valid service object from an existing service', () => {
290
+ const serviceObject = services.getServiceFromUrl(testUrlTemplate.defaultUrl);
291
+
292
+ assert.isDefined(serviceObject);
293
+ assert.hasAllKeys(serviceObject, ['name', 'defaultUrl', 'priorityUrl']);
294
+
295
+ assert.equal(testUrlTemplate.name, serviceObject.name);
296
+ assert.equal(testUrlTemplate.defaultUrl, serviceObject.defaultUrl);
297
+ assert.equal(testUrl.get(true), serviceObject.priorityUrl);
298
+ });
299
+
300
+ it("returns undefined when the service url doesn't exist", () => {
301
+ const serviceObject = services.getServiceFromUrl('http://www.not-real.com/');
302
+
303
+ assert.isUndefined(serviceObject);
304
+ });
305
+ });
306
+
307
+ describe('#hasService()', () => {
308
+ it('returns a boolean', () => {
309
+ assert.isBoolean(services.hasService('some-url'));
310
+ });
311
+
312
+ it('validates that a service exists', () => {
313
+ const service = Object.keys(services.list())[0];
314
+
315
+ assert.isTrue(services.hasService(service));
316
+ });
317
+ });
318
+
319
+ describe('#initConfig()', () => {
320
+ it('should set the discovery catalog based on the provided links', () => {
321
+ const key = 'test';
322
+ const url = 'http://www.test.com/';
323
+
324
+ webex.config.services.discovery[key] = url;
325
+
326
+ services.initConfig();
327
+
328
+ assert.equal(services.get(key), url);
329
+ });
330
+
331
+ it('should set the override catalog based on the provided links', () => {
332
+ const key = 'testOverride';
333
+ const url = 'http://www.test-override.com/';
334
+
335
+ webex.config.services.override = {};
336
+ webex.config.services.override[key] = url;
337
+
338
+ services.initConfig();
339
+
340
+ assert.equal(services.get(key), url);
341
+ });
342
+
343
+ it('should set validate domains to true when provided true', () => {
344
+ webex.config.services.validateDomains = true;
345
+
346
+ services.initConfig();
347
+
348
+ assert.isTrue(services.validateDomains);
349
+ });
350
+
351
+ it('should set validate domains to false when provided false', () => {
352
+ webex.config.services.validateDomains = false;
353
+
354
+ services.initConfig();
355
+
356
+ assert.isFalse(services.validateDomains);
357
+ });
358
+
359
+ it('should set the allowed domains based on the provided domains', () => {
360
+ const allowedDomains = ['domain'];
361
+
362
+ webex.config.services.allowedDomains = allowedDomains;
363
+
364
+ services.initConfig();
365
+
366
+ assert.deepEqual(allowedDomains, services._getCatalog().allowedDomains);
367
+ });
368
+ });
369
+
370
+ describe('#initialize()', () => {
371
+ it('should create a catalog', () =>
372
+ assert.instanceOf(services._getCatalog(), ServiceCatalog));
373
+
374
+ it('should create a registry', () =>
375
+ assert.instanceOf(services.getRegistry(), ServiceRegistry));
376
+
377
+ it('should create a state', () => assert.instanceOf(services.getState(), ServiceState));
378
+
379
+ it('should call services#initConfig() when webex config changes', () => {
380
+ services.initConfig = sinon.spy();
381
+ services.initialize();
382
+ webex.trigger('change:config');
383
+ assert.called(services.initConfig);
384
+ assert.isTrue(catalog.isReady);
385
+ });
386
+
387
+ it('should call services#initServiceCatalogs() on webex ready', () => {
388
+ services.initServiceCatalogs = sinon.stub().resolves();
389
+ services.initialize();
390
+ webex.trigger('ready');
391
+ assert.called(services.initServiceCatalogs);
392
+ assert.isTrue(catalog.isReady);
393
+ });
394
+
395
+ it('should collect different catalogs based on OrgId region', () =>
396
+ assert.notDeepEqual(services.list(true), servicesEU.list(true)));
397
+
398
+ it('should not attempt to collect catalogs without authorization', (done) => {
399
+ const otherWebex = new WebexCore();
400
+ let {initServiceCatalogs} = otherWebex.internal.services;
401
+
402
+ initServiceCatalogs = sinon.stub();
403
+
404
+ setTimeout(() => {
405
+ assert.notCalled(initServiceCatalogs);
406
+ assert.isFalse(otherWebex.internal.services._getCatalog().isReady);
407
+ done();
408
+ }, 2000);
409
+ });
410
+ });
411
+
412
+ describe('#initServiceCatalogs()', () => {
413
+ it('should reject if a OrgId cannot be retrieved', () => {
414
+ webex.credentials.getOrgId = sinon.stub().throws();
415
+
416
+ return assert.isRejected(services.initServiceCatalogs());
417
+ });
418
+
419
+ it('should call services#collectPreauthCatalog with the OrgId', () => {
420
+ services.collectPreauthCatalog = sinon.stub().resolves();
421
+
422
+ return services.initServiceCatalogs().then(() =>
423
+ assert.calledWith(
424
+ services.collectPreauthCatalog,
425
+ sinon.match({
426
+ orgId: webex.credentials.getOrgId(),
427
+ })
428
+ )
429
+ );
430
+ });
431
+
432
+ it('should not call services#updateServices() when not authed', () => {
433
+ services.updateServices = sinon.stub().resolves();
434
+
435
+ // Since credentials uses AmpState, we have to set the derived
436
+ // properties of the dependent properties to undefined.
437
+ webex.credentials.supertoken.access_token = undefined;
438
+ webex.credentials.supertoken.refresh_token = undefined;
439
+
440
+ webex.credentials.getOrgId = sinon.stub().returns(webexUser.orgId);
441
+
442
+ return (
443
+ services
444
+ .initServiceCatalogs()
445
+ // services#updateServices() gets called once by the limited catalog
446
+ // retrieval and should not be called again when not authorized.
447
+ .then(() => assert.calledOnce(services.updateServices))
448
+ );
449
+ });
450
+
451
+ it('should call services#updateServices() when authed', () => {
452
+ services.updateServices = sinon.stub().resolves();
453
+
454
+ return (
455
+ services
456
+ .initServiceCatalogs()
457
+ // services#updateServices() gets called once by the limited catalog
458
+ // retrieval and should get called again when authorized.
459
+ .then(() => assert.calledTwice(services.updateServices))
460
+ );
461
+ });
462
+ });
463
+
464
+ describe('#isServiceUrl()', () => {
465
+ let testUrlTemplate;
466
+ let testUrl;
467
+
468
+ beforeEach('load test url', () => {
469
+ testUrlTemplate = {
470
+ defaultUrl: 'https://www.example.com/api/v1',
471
+ hosts: [
472
+ {
473
+ homeCluster: true,
474
+ host: 'www.example-p5.com',
475
+ ttl: -1,
476
+ priority: 5,
477
+ id: 'exampleClusterId',
478
+ },
479
+ {
480
+ host: 'www.example-p3.com',
481
+ ttl: -1,
482
+ priority: 3,
483
+ id: 'exampleClusterId',
484
+ },
485
+ ],
486
+ name: 'exampleValid',
487
+ };
488
+ testUrl = new ServiceUrl(testUrlTemplate);
489
+ catalog._loadServiceUrls('preauth', [testUrl]);
490
+ });
491
+
492
+ it('returns true if url is a service url', () => {
493
+ assert.isTrue(services.isServiceUrl(testUrlTemplate.defaultUrl));
494
+ });
495
+
496
+ it('returns true for priority host urls', () => {
497
+ assert.isTrue(services.isServiceUrl(testUrl.get(true)));
498
+ });
499
+
500
+ it("returns undefined if the url doesn't exist", () => {
501
+ assert.isFalse(services.isServiceUrl('https://na.com/'));
502
+ });
503
+
504
+ it('returns undefined if the param is not a url', () => {
505
+ assert.isFalse(services.isServiceUrl('not a url'));
506
+ });
507
+ });
508
+
509
+ describe('#isAllowedDomainUrl()', () => {
510
+ let list;
511
+
512
+ beforeEach(() => {
513
+ catalog.setAllowedDomains(['some-domain-a', 'some-domain-b']);
514
+
515
+ list = catalog.getAllowedDomains();
516
+ });
517
+
518
+ it('returns a boolean', () => {
519
+ assert.isBoolean(services.isAllowedDomainUrl(''));
520
+ });
521
+
522
+ it('returns true if the url contains an allowed domain', () => {
523
+ assert.isTrue(services.isAllowedDomainUrl(`https://${list[0]}/resource`));
524
+ });
525
+
526
+ it('returns false if the url does not contain an allowed domain', () => {
527
+ assert.isFalse(services.isAllowedDomainUrl('https://bad-domain/resource'));
528
+ });
529
+ });
530
+
531
+ describe('#convertUrlToPriorityUrl', () => {
532
+ let testUrl;
533
+ let testUrlTemplate;
534
+
535
+ beforeEach('load test url', () => {
536
+ testUrlTemplate = {
537
+ defaultUrl: 'https://www.example.com/api/v1',
538
+ hosts: [
539
+ {
540
+ homeCluster: true,
541
+ host: 'www.example-p5.com',
542
+ ttl: -1,
543
+ priority: 5,
544
+ id: '0:0:cluster-a:exampleValid',
545
+ },
546
+ {
547
+ host: 'www.example-p3.com',
548
+ ttl: -1,
549
+ priority: 3,
550
+ id: '0:0:cluster-b:exampleValid',
551
+ },
552
+ ],
553
+ name: 'exampleValid',
554
+ };
555
+ testUrl = new ServiceUrl(testUrlTemplate);
556
+ catalog._loadServiceUrls('preauth', [testUrl]);
557
+ });
558
+
559
+ it('converts the url to a priority host url', () => {
560
+ const resource = 'path/to/resource';
561
+ const url = `${testUrlTemplate.defaultUrl}/${resource}`;
562
+
563
+ const convertUrl = services.convertUrlToPriorityHostUrl(url);
564
+
565
+ assert.isDefined(convertUrl);
566
+ assert.isTrue(convertUrl.includes(testUrlTemplate.hosts[0].host));
567
+ });
568
+
569
+ it('throws an exception if not a valid service', () => {
570
+ assert.throws(services.convertUrlToPriorityHostUrl, Error);
571
+
572
+ assert.throws(
573
+ services.convertUrlToPriorityHostUrl.bind(services, 'not-a-valid-service'),
574
+ Error
575
+ );
576
+ });
577
+
578
+ afterEach('unload test url', () => {
579
+ catalog._unloadServiceUrls('preauth', [testUrl]);
580
+ });
581
+ });
582
+
583
+ describe('#markFailedUrl()', () => {
584
+ let testUrlTemplate;
585
+ let testUrl;
586
+
587
+ beforeEach('load test url', () => {
588
+ catalog.clean();
589
+
590
+ testUrlTemplate = {
591
+ defaultUrl: 'https://www.example-phr.com/api/v1',
592
+ hosts: [
593
+ {
594
+ host: 'www.example-phr-p5.com',
595
+ ttl: -1,
596
+ priority: 5,
597
+ homeCluster: true,
598
+ },
599
+ {
600
+ host: 'www.example-phr-p3.com',
601
+ ttl: -1,
602
+ priority: 3,
603
+ homeCluster: true,
604
+ },
605
+ ],
606
+ name: 'exampleValid-phr',
607
+ };
608
+ testUrl = new ServiceUrl(testUrlTemplate);
609
+ catalog._loadServiceUrls('preauth', [testUrl]);
610
+ });
611
+
612
+ afterEach('unload test url', () => {
613
+ catalog._unloadServiceUrls('preauth', [testUrl]);
614
+ });
615
+
616
+ it('marks a host as failed', () => {
617
+ const priorityServiceUrl = catalog._getUrl(testUrlTemplate.name);
618
+ const priorityUrl = priorityServiceUrl._getPriorityHostUrl();
619
+
620
+ services.markFailedUrl(priorityUrl);
621
+
622
+ const failedHost = priorityServiceUrl.hosts.find((host) => host.failed);
623
+
624
+ assert.isTrue(priorityUrl.includes(failedHost.host));
625
+ });
626
+
627
+ it('returns the next priority url', () => {
628
+ const priorityUrl = services.get(testUrlTemplate.name, true);
629
+
630
+ const nextPriorityUrl = services.markFailedUrl(priorityUrl);
631
+
632
+ assert.notEqual(priorityUrl, nextPriorityUrl);
633
+ });
634
+
635
+ it('should reset hosts once all hosts have been marked failed', () => {
636
+ const priorityServiceUrl = catalog._getUrl(testUrlTemplate.name);
637
+ const firstPriorityUrl = priorityServiceUrl._getPriorityHostUrl();
638
+
639
+ priorityServiceUrl.hosts.forEach(() => {
640
+ const priorityUrl = priorityServiceUrl._getPriorityHostUrl();
641
+
642
+ services.markFailedUrl(priorityUrl);
643
+ });
644
+
645
+ const lastPriorityUrl = priorityServiceUrl._getPriorityHostUrl();
646
+
647
+ assert.equal(firstPriorityUrl, lastPriorityUrl);
648
+ });
649
+ });
650
+
651
+ describe('#updateServices()', () => {
652
+ it('returns a Promise that and resolves on success', (done) => {
653
+ const servicesPromise = services.updateServices();
654
+
655
+ assert.typeOf(servicesPromise, 'Promise');
656
+
657
+ servicesPromise.then(() => {
658
+ Object.keys(services.list()).forEach((key) => {
659
+ assert.typeOf(key, 'string');
660
+ assert.typeOf(services.list()[key], 'string');
661
+ });
662
+
663
+ done();
664
+ });
665
+ });
666
+
667
+ it('updates the services list', (done) => {
668
+ catalog.serviceGroups.postauth = [];
669
+
670
+ services.updateServices().then(() => {
671
+ assert.isAbove(catalog.serviceGroups.postauth.length, 0);
672
+ done();
673
+ });
674
+
675
+ services.updateServices();
676
+ });
677
+
678
+ it('updates query.email to be emailhash-ed using SHA256', (done) => {
679
+ catalog.updateServiceUrls = sinon.stub().returns({}); // returns `this`
680
+ services._fetchNewServiceHostmap = sinon.stub().resolves();
681
+
682
+ services
683
+ .updateServices({
684
+ from: 'limited',
685
+ query: {email: webexUser.email},
686
+ })
687
+ .then(() => {
688
+ assert.calledWith(
689
+ services._fetchNewServiceHostmap,
690
+ sinon.match.has('query', {emailhash: sinon.match(/\b[A-Fa-f0-9]{64}\b/)})
691
+ );
692
+ done();
693
+ });
694
+ });
695
+
696
+ it('updates the limited catalog when email is provided', (done) => {
697
+ catalog.serviceGroups.preauth = [];
698
+
699
+ services
700
+ .updateServices({
701
+ from: 'limited',
702
+ query: {email: webexUser.email},
703
+ })
704
+ .then(() => {
705
+ assert.isAbove(catalog.serviceGroups.preauth.length, 0);
706
+ done();
707
+ });
708
+ });
709
+
710
+ it('updates the limited catalog when userId is provided', (done) => {
711
+ catalog.serviceGroups.preauth = [];
712
+
713
+ services
714
+ .updateServices({
715
+ from: 'limited',
716
+ query: {userId: webexUser.id},
717
+ })
718
+ .then(() => {
719
+ assert.isAbove(catalog.serviceGroups.preauth.length, 0);
720
+ done();
721
+ });
722
+ });
723
+
724
+ it('updates the limited catalog when orgId is provided', (done) => {
725
+ catalog.serviceGroups.preauth = [];
726
+
727
+ services
728
+ .updateServices({
729
+ from: 'limited',
730
+ query: {orgId: webexUser.orgId},
731
+ })
732
+ .then(() => {
733
+ assert.isAbove(catalog.serviceGroups.preauth.length, 0);
734
+ done();
735
+ });
736
+ });
737
+ it('updates the limited catalog when query param mode is provided', (done) => {
738
+ catalog.serviceGroups.preauth = [];
739
+
740
+ services
741
+ .updateServices({
742
+ from: 'limited',
743
+ query: {mode: 'DEFAULT_BY_PROXIMITY'},
744
+ })
745
+ .then(() => {
746
+ assert.isAbove(catalog.serviceGroups.preauth.length, 0);
747
+ done();
748
+ });
749
+ });
750
+ it('does not update the limited catalog when nothing is provided', () => {
751
+ catalog.serviceGroups.preauth = [];
752
+
753
+ return services
754
+ .updateServices({from: 'limited'})
755
+ .then(() => {
756
+ assert(false, 'resolved, should have thrown');
757
+ })
758
+ .catch(() => {
759
+ assert(true);
760
+ });
761
+ });
762
+
763
+ it('updates limited catalog and calls _fetchNewServiceHostmap with forceRefresh = true', (done) => {
764
+ const forceRefresh = true;
765
+ const fetchNewServiceHostmapSpy = sinon.spy(services, '_fetchNewServiceHostmap');
766
+
767
+ services
768
+ .updateServices({
769
+ from: 'limited',
770
+ query: {email: webexUser.email},
771
+ forceRefresh,
772
+ })
773
+ .then(() => {
774
+ assert.calledOnce(fetchNewServiceHostmapSpy);
775
+ assert.calledWith(
776
+ fetchNewServiceHostmapSpy,
777
+ sinon.match.has(
778
+ 'from',
779
+ 'limited',
780
+ 'query',
781
+ {emailhash: sinon.match(/\b[A-Fa-f0-9]{64}\b/)},
782
+ 'forceFresh',
783
+ forceRefresh
784
+ )
785
+ );
786
+
787
+ fetchNewServiceHostmapSpy.returnValues[0].then((res) => {
788
+ assert.isAbove(res.length, 0);
789
+ });
790
+ done();
791
+ });
792
+ });
793
+ });
794
+
795
+ describe('#fetchClientRegionInfo()', () => {
796
+ it('returns client region info', () =>
797
+ services.fetchClientRegionInfo().then((r) => {
798
+ assert.isDefined(r.countryCode);
799
+ assert.isDefined(r.timezone);
800
+ }));
801
+ });
802
+
803
+ describe('#validateUser()', () => {
804
+ const unauthWebex = new WebexCore();
805
+ const unauthServices = unauthWebex.internal.services;
806
+ let sandbox = null;
807
+
808
+ const getActivationRequest = (requestStub) => {
809
+ const requests = requestStub.args.filter(
810
+ ([request]) => request.service === 'license' && request.resource === 'users/activations'
811
+ );
812
+
813
+ assert.strictEqual(requests.length, 1);
814
+
815
+ return requests[0][0];
816
+ };
817
+
818
+ beforeEach(() => {
819
+ sandbox = sinon.createSandbox();
820
+ });
821
+
822
+ afterEach(() => {
823
+ sandbox.restore();
824
+ sandbox = null;
825
+ });
826
+
827
+ it('returns a rejected promise when no email is specified', () =>
828
+ unauthServices
829
+ .validateUser({})
830
+ .then(() => {
831
+ assert(false, 'resolved, should have thrown');
832
+ })
833
+ .catch(() => {
834
+ assert(true);
835
+ }));
836
+
837
+ it('validates an authorized user and webex instance', () =>
838
+ services.validateUser({email: webexUser.email}).then((r) => {
839
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
840
+ assert.equal(r.activated, true);
841
+ assert.equal(r.exists, true);
842
+ }));
843
+
844
+ it('validates an authorized EU user and webex instance', () =>
845
+ servicesEU.validateUser({email: webexUserEU.email}).then((r) => {
846
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
847
+ assert.equal(r.activated, true);
848
+ assert.equal(r.exists, true);
849
+ }));
850
+
851
+ it("returns a rejected promise if the provided email isn't valid", () =>
852
+ unauthServices
853
+ .validateUser({email: 'not an email'})
854
+ .then(() => {
855
+ assert(false, 'resolved, should have thrown');
856
+ })
857
+ .catch(() => {
858
+ assert(true);
859
+ }));
860
+
861
+ it('validates a non-existing user', () =>
862
+ unauthServices
863
+ .validateUser({email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`})
864
+ .then((r) => {
865
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
866
+ assert.equal(r.activated, false);
867
+ assert.equal(r.exists, false);
868
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
869
+ assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
870
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
871
+ }));
872
+
873
+ it('validates new user with activationOptions suppressEmail false', () =>
874
+ unauthServices
875
+ .validateUser({
876
+ email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
877
+ activationOptions: {suppressEmail: false},
878
+ })
879
+ .then((r) => {
880
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
881
+ assert.equal(r.activated, false);
882
+ assert.equal(r.exists, false);
883
+ assert.equal(r.user.verificationEmailTriggered, true);
884
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
885
+ assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
886
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
887
+ }));
888
+
889
+ it('validates new user with activationOptions suppressEmail true', () =>
890
+ unauthServices
891
+ .validateUser({
892
+ email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
893
+ activationOptions: {suppressEmail: true},
894
+ })
895
+ .then((r) => {
896
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
897
+ assert.equal(r.activated, false);
898
+ assert.equal(r.exists, false);
899
+ assert.equal(r.user.verificationEmailTriggered, false);
900
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
901
+ assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
902
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
903
+ }));
904
+
905
+ it('validates an inactive user', () => {
906
+ const inactive = 'webex.web.client+nonactivated@gmail.com';
907
+
908
+ return unauthServices
909
+ .validateUser({email: inactive, activationOptions: {suppressEmail: true}})
910
+ .then((r) => {
911
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
912
+ assert.equal(r.activated, false, 'activated');
913
+ assert.equal(r.exists, true, 'exists');
914
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
915
+ assert.equal(Object.keys(unauthServices.list(false, 'signin')).length, 0);
916
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
917
+ })
918
+ .catch(() => {
919
+ assert(true);
920
+ });
921
+ });
922
+
923
+ it('validates an existing user', () =>
924
+ unauthServices.validateUser({email: webexUser.email}).then((r) => {
925
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
926
+ assert.equal(r.activated, true);
927
+ assert.equal(r.exists, true);
928
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
929
+ assert.isAbove(Object.keys(unauthServices.list(false, 'signin')).length, 0);
930
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
931
+ }));
932
+
933
+ it('validates an existing EU user', () =>
934
+ unauthServices.validateUser({email: webexUserEU.email}).then((r) => {
935
+ assert.hasAllKeys(r, ['activated', 'exists', 'user', 'details']);
936
+ assert.equal(r.activated, true);
937
+ assert.equal(r.exists, true);
938
+ assert.isAbove(Object.keys(unauthServices.list(false, 'preauth')).length, 0);
939
+ assert.isAbove(Object.keys(unauthServices.list(false, 'signin')).length, 0);
940
+ assert.equal(Object.keys(unauthServices.list(false, 'postauth')).length, 0);
941
+ }));
942
+
943
+ it('sends the prelogin user id as undefined when not specified', () => {
944
+ const requestStub = sandbox.spy(unauthServices, 'request');
945
+
946
+ return unauthServices
947
+ .validateUser({
948
+ email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
949
+ activationOptions: {suppressEmail: true},
950
+ })
951
+ .then(() => {
952
+ assert.isUndefined(getActivationRequest(requestStub).headers['x-prelogin-userid']);
953
+ });
954
+ });
955
+
956
+ it('sends the prelogin user id as provided when specified', () => {
957
+ const requestStub = sandbox.spy(unauthServices, 'request');
958
+ const preloginUserId = uuid.v4();
959
+
960
+ return unauthServices
961
+ .validateUser({
962
+ email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`,
963
+ activationOptions: {suppressEmail: true},
964
+ preloginUserId,
965
+ })
966
+ .then(() => {
967
+ assert.strictEqual(
968
+ getActivationRequest(requestStub).headers['x-prelogin-userid'],
969
+ preloginUserId
970
+ );
971
+ });
972
+ });
973
+ });
974
+
975
+ describe('#waitForService()', () => {
976
+ let name;
977
+ let url;
978
+
979
+ describe('when the service exists', () => {
980
+ beforeEach('collect valid service info', () => {
981
+ name = Object.keys(services.list())[0];
982
+ url = services.list(true)[name];
983
+ });
984
+
985
+ describe('when using the name parameter property', () => {
986
+ it('should resolve to the appropriate url', () =>
987
+ services.waitForService({name}).then((foundUrl) => assert.equal(foundUrl, url)));
988
+ });
989
+
990
+ describe('when using the url parameter property', () => {
991
+ it('should resolve to the appropriate url', () =>
992
+ services.waitForService({url}).then((foundUrl) => assert.equal(foundUrl, url)));
993
+ });
994
+
995
+ describe('when using the url and name parameter properties', () => {
996
+ it('should resolve to the appropriate url', () =>
997
+ services.waitForService({name, url}).then((foundUrl) => assert.equal(foundUrl, url)));
998
+ });
999
+ });
1000
+
1001
+ describe('when the service does not exist', () => {
1002
+ let timeout;
1003
+
1004
+ beforeEach('set up the parameters', () => {
1005
+ name = 'not a service';
1006
+ url = 'http://not-a-service.com/resource';
1007
+ timeout = 1;
1008
+ });
1009
+
1010
+ describe('when using the url parameter property', () => {
1011
+ it('should return a resolve promise', () =>
1012
+ // const waitForService = services.waitForService({url, timeout});
1013
+
1014
+ services.waitForService({url, timeout}).then((foundUrl) => {
1015
+ assert.equal(foundUrl, url);
1016
+ assert.isTrue(catalog.isReady);
1017
+ }));
1018
+ });
1019
+
1020
+ describe('when using the name parameter property', () => {
1021
+ it('should return a rejected promise', () => {
1022
+ const submitMetrics = sinon.stub(webex.internal.metrics, 'submitClientMetrics');
1023
+ const waitForService = services.waitForService({name, timeout});
1024
+
1025
+ assert.called(submitMetrics);
1026
+ assert.isRejected(waitForService);
1027
+ assert.isTrue(catalog.isReady);
1028
+ });
1029
+ });
1030
+
1031
+ describe('when using the name and url parameter properties', () => {
1032
+ it('should return a rejected promise', () => {
1033
+ const waitForService = services.waitForService({
1034
+ name,
1035
+ url,
1036
+ timeout,
1037
+ });
1038
+
1039
+ assert.isRejected(waitForService);
1040
+ assert.isTrue(catalog.isReady);
1041
+ });
1042
+ });
1043
+
1044
+ describe('when the service will exist', () => {
1045
+ beforeEach('collect existing service and clear the catalog', () => {
1046
+ name = 'metrics';
1047
+ url = services.get(name, true);
1048
+ catalog.clean();
1049
+ catalog.isReady = false;
1050
+ });
1051
+
1052
+ describe('when only the preauth (limited) catalog becomes available', () => {
1053
+ describe('when using the name parameter property', () => {
1054
+ it('should resolve to the appropriate url', () =>
1055
+ Promise.all([
1056
+ services.waitForService({name}),
1057
+ services.collectPreauthCatalog(),
1058
+ ]).then(([foundUrl]) => assert.equal(foundUrl, url)));
1059
+ });
1060
+
1061
+ describe('when using the url parameter property', () => {
1062
+ it('should resolve to the appropriate url', () =>
1063
+ Promise.all([
1064
+ services.waitForService({url}),
1065
+ services.collectPreauthCatalog(),
1066
+ ]).then(([foundUrl]) => assert.equal(foundUrl, url)));
1067
+ });
1068
+
1069
+ describe('when using the name and url parameter property', () => {
1070
+ it('should resolve to the appropriate url', () =>
1071
+ Promise.all([
1072
+ services.waitForService({name, url}),
1073
+ services.collectPreauthCatalog(),
1074
+ ]).then(([foundUrl]) => assert.equal(foundUrl, url)));
1075
+ });
1076
+ });
1077
+
1078
+ describe('when all catalogs become available', () => {
1079
+ describe('when using the name parameter property', () => {
1080
+ it('should resolve to the appropriate url', () =>
1081
+ Promise.all([services.waitForService({name}), services.initServiceCatalogs()]).then(
1082
+ ([foundUrl]) => assert.equal(foundUrl, url)
1083
+ ));
1084
+ });
1085
+
1086
+ describe('when using the url parameter property', () => {
1087
+ it('should resolve to the appropriate url', () =>
1088
+ Promise.all([services.waitForService({url}), services.initServiceCatalogs()]).then(
1089
+ ([foundUrl]) => assert.equal(foundUrl, url)
1090
+ ));
1091
+ });
1092
+
1093
+ describe('when using the name and url parameter property', () => {
1094
+ it('should resolve to the appropriate url', () =>
1095
+ Promise.all([
1096
+ services.waitForService({name, url}),
1097
+ services.initServiceCatalogs(),
1098
+ ]).then(([foundUrl]) => assert.equal(foundUrl, url)));
1099
+ });
1100
+ });
1101
+ });
1102
+ });
1103
+ });
1104
+
1105
+ describe('#collectPreauthCatalog()', () => {
1106
+ const unauthWebex = new WebexCore({config: {credentials: {federation: true}}});
1107
+ const unauthServices = unauthWebex.internal.services;
1108
+ const forceRefresh = true;
1109
+
1110
+ it('updates the preauth catalog without email', () =>
1111
+ unauthServices.collectPreauthCatalog().then(() => {
1112
+ assert.isAbove(Object.keys(unauthServices.list()).length, 0);
1113
+ }));
1114
+
1115
+ it('updates the preauth catalog with email', () =>
1116
+ unauthServices.collectPreauthCatalog({email: webexUser.email}).then(() => {
1117
+ assert.isAbove(Object.keys(unauthServices.list()).length, 0);
1118
+ }));
1119
+
1120
+ it('updates the preauth catalog with email along with additional timestamp to address cache control', (done) => {
1121
+ const updateServiceSpy = sinon.spy(unauthServices, 'updateServices');
1122
+ const fetchNewServiceHostmapSpy = sinon.spy(unauthServices, '_fetchNewServiceHostmap');
1123
+
1124
+ unauthServices.collectPreauthCatalog({email: webexUser.email}, forceRefresh).then(() => {
1125
+ assert.calledOnce(updateServiceSpy);
1126
+ assert.calledWith(
1127
+ updateServiceSpy,
1128
+ sinon.match.has(
1129
+ 'from',
1130
+ 'limited',
1131
+ 'query',
1132
+ {emailhash: sinon.match(/\b[A-Fa-f0-9]{64}\b/)},
1133
+ 'forceRefresh',
1134
+ forceRefresh
1135
+ )
1136
+ );
1137
+
1138
+ assert.calledOnce(fetchNewServiceHostmapSpy);
1139
+ assert.calledWith(
1140
+ fetchNewServiceHostmapSpy,
1141
+ sinon.match.has(
1142
+ 'from',
1143
+ 'limited',
1144
+ 'query',
1145
+ {emailhash: sinon.match(/\b[A-Fa-f0-9]{64}\b/)},
1146
+ 'forceRefresh',
1147
+ forceRefresh
1148
+ )
1149
+ );
1150
+
1151
+ fetchNewServiceHostmapSpy.returnValues[0].then((res) => {
1152
+ assert.isAbove(res.length, 0);
1153
+ });
1154
+ done();
1155
+ });
1156
+ });
1157
+ });
1158
+
1159
+ describe('#collectSigninCatalog()', () => {
1160
+ const unauthWebex = new WebexCore({config: {credentials: {federation: true}}});
1161
+ const unauthServices = unauthWebex.internal.services;
1162
+
1163
+ it('requires an email as the parameter', () =>
1164
+ unauthServices.collectPreauthCatalog().catch((e) => {
1165
+ assert(true, e);
1166
+ }));
1167
+
1168
+ it('requires a token as the parameter', () =>
1169
+ unauthServices.collectPreauthCatalog({email: 'email@website.com'}).catch((e) => {
1170
+ assert(true, e);
1171
+ }));
1172
+
1173
+ it('updates the preauth catalog', () =>
1174
+ unauthServices.collectPreauthCatalog({email: webexUser.email}).then(() => {
1175
+ assert.isAbove(Object.keys(unauthServices.list()).length, 0);
1176
+ }));
1177
+ });
1178
+
1179
+ flaky(describe, process.env.SKIP_FLAKY_TESTS)('#_fetchNewServiceHostmap()', () => {
1180
+ let fullRemoteHM;
1181
+ let limitedRemoteHM;
1182
+
1183
+ before('collect remote catalogs', () =>
1184
+ Promise.all([
1185
+ services._fetchNewServiceHostmap(),
1186
+ services._fetchNewServiceHostmap({
1187
+ from: 'limited',
1188
+ query: {userId: webexUser.id},
1189
+ }),
1190
+ ]).then(([fRHM, lRHM]) => {
1191
+ fullRemoteHM = fRHM;
1192
+ limitedRemoteHM = lRHM;
1193
+ })
1194
+ );
1195
+
1196
+ it('resolves to an authed u2c hostmap when no params specified', () => {
1197
+ assert.typeOf(fullRemoteHM, 'array');
1198
+ assert.isAbove(fullRemoteHM.length, 0);
1199
+ });
1200
+
1201
+ it('resolves to a limited u2c hostmap when params specified', () => {
1202
+ assert.typeOf(limitedRemoteHM, 'array');
1203
+ assert.isAbove(limitedRemoteHM.length, 0);
1204
+ });
1205
+
1206
+ it('rejects if the params provided are invalid', () =>
1207
+ services
1208
+ ._fetchNewServiceHostmap({
1209
+ from: 'limited',
1210
+ query: {userId: 'notValid'},
1211
+ })
1212
+ .then(() => {
1213
+ assert.isTrue(false, 'should have rejected');
1214
+ })
1215
+ .catch((e) => {
1216
+ assert.typeOf(e, 'Error');
1217
+ }));
1218
+ });
1219
+ });
1220
+ });
1221
+ /* eslint-enable no-underscore-dangle */