@webex/webex-core 3.11.0-webex-services-ready.1 → 3.12.0-auth-prejoin-fetch.1
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.
- package/README.md +5 -2
- package/dist/config.js +24 -0
- package/dist/config.js.map +1 -1
- package/dist/credentials-config.js +12 -0
- package/dist/credentials-config.js.map +1 -1
- package/dist/interceptors/redirect.js +1 -1
- package/dist/interceptors/redirect.js.map +1 -1
- package/dist/lib/batcher.js +23 -7
- package/dist/lib/batcher.js.map +1 -1
- package/dist/lib/credentials/credentials.js +48 -4
- package/dist/lib/credentials/credentials.js.map +1 -1
- package/dist/lib/credentials/token.js +1 -1
- package/dist/lib/domains.js +90 -0
- package/dist/lib/domains.js.map +1 -0
- package/dist/lib/services/service-catalog.js +6 -10
- package/dist/lib/services/service-catalog.js.map +1 -1
- package/dist/lib/services/services.js +244 -57
- package/dist/lib/services/services.js.map +1 -1
- package/dist/lib/services-v2/service-catalog.js +6 -12
- package/dist/lib/services-v2/service-catalog.js.map +1 -1
- package/dist/lib/services-v2/services-v2.js +243 -52
- package/dist/lib/services-v2/services-v2.js.map +1 -1
- package/dist/plugins/logger.js +1 -1
- package/dist/webex-core.js +2 -2
- package/dist/webex-core.js.map +1 -1
- package/package.json +13 -13
- package/src/config.js +27 -0
- package/src/credentials-config.js +13 -0
- package/src/interceptors/redirect.js +4 -1
- package/src/lib/batcher.js +25 -10
- package/src/lib/credentials/credentials.js +50 -3
- package/src/lib/domains.ts +94 -0
- package/src/lib/services/service-catalog.js +6 -10
- package/src/lib/services/services.js +218 -46
- package/src/lib/services-v2/service-catalog.ts +6 -11
- package/src/lib/services-v2/services-v2.ts +218 -42
- package/test/fixtures/activation-email.ts +22 -0
- package/test/integration/spec/services/service-catalog.js +7 -6
- package/test/integration/spec/services/services.js +188 -128
- package/test/integration/spec/services-v2/services-v2.js +174 -114
- package/test/unit/spec/credentials/credentials.js +133 -2
- package/test/unit/spec/interceptors/auth.js +56 -0
- package/test/unit/spec/lib/batcher.js +56 -0
- package/test/unit/spec/services/service-catalog.js +93 -11
- package/test/unit/spec/services/services.js +591 -322
- package/test/unit/spec/services-v2/service-catalog.ts +93 -11
- package/test/unit/spec/services-v2/services-v2.ts +539 -214
- package/test/unit/spec/webex-core.js +0 -2
- package/test/unit/spec/webex-internal-core.js +0 -2
|
@@ -34,53 +34,6 @@ describe('webex-core', () => {
|
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
describe('#initialize', () => {
|
|
37
|
-
it('listens for "loaded" event instead of "ready" to avoid deadlock', () => {
|
|
38
|
-
services.listenToOnce = sinon.stub();
|
|
39
|
-
services.initialize();
|
|
40
|
-
|
|
41
|
-
// Second listenToOnce call should be for 'loaded' event
|
|
42
|
-
assert.equal(services.listenToOnce.getCall(1).args[1], 'loaded');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('services.ready starts as false', () => {
|
|
46
|
-
assert.isFalse(services.ready);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('sets ready to true and triggers services:initialized when initialization succeeds with credentials', async () => {
|
|
50
|
-
services.listenToOnce = sinon.stub();
|
|
51
|
-
services.initServiceCatalogs = sinon.stub().returns(Promise.resolve());
|
|
52
|
-
services.trigger = sinon.stub();
|
|
53
|
-
services.webex.credentials = {
|
|
54
|
-
supertoken: {
|
|
55
|
-
access_token: 'token',
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
services.initialize();
|
|
60
|
-
|
|
61
|
-
// call the onLoaded callback
|
|
62
|
-
services.listenToOnce.getCall(1).args[2]();
|
|
63
|
-
await waitForAsync();
|
|
64
|
-
|
|
65
|
-
assert.isTrue(services.ready);
|
|
66
|
-
sinon.assert.calledWith(services.trigger, 'services:initialized');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('sets ready to true and triggers services:initialized when initialization succeeds without credentials', async () => {
|
|
70
|
-
services.listenToOnce = sinon.stub();
|
|
71
|
-
services.collectPreauthCatalog = sinon.stub().returns(Promise.resolve());
|
|
72
|
-
services.trigger = sinon.stub();
|
|
73
|
-
|
|
74
|
-
services.initialize();
|
|
75
|
-
|
|
76
|
-
// call the onLoaded callback
|
|
77
|
-
services.listenToOnce.getCall(1).args[2]();
|
|
78
|
-
await waitForAsync();
|
|
79
|
-
|
|
80
|
-
assert.isTrue(services.ready);
|
|
81
|
-
sinon.assert.calledWith(services.trigger, 'services:initialized');
|
|
82
|
-
});
|
|
83
|
-
|
|
84
37
|
it('initFailed is false when initialization succeeds and credentials are available', async () => {
|
|
85
38
|
services.listenToOnce = sinon.stub();
|
|
86
39
|
services.initServiceCatalogs = sinon.stub().returns(Promise.resolve());
|
|
@@ -92,7 +45,8 @@ describe('webex-core', () => {
|
|
|
92
45
|
|
|
93
46
|
services.initialize();
|
|
94
47
|
|
|
95
|
-
// call the
|
|
48
|
+
// call the onReady callback
|
|
49
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
96
50
|
services.listenToOnce.getCall(1).args[2]();
|
|
97
51
|
await waitForAsync();
|
|
98
52
|
|
|
@@ -105,7 +59,8 @@ describe('webex-core', () => {
|
|
|
105
59
|
|
|
106
60
|
services.initialize();
|
|
107
61
|
|
|
108
|
-
// call the
|
|
62
|
+
// call the onReady callback
|
|
63
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
109
64
|
services.listenToOnce.getCall(1).args[2]();
|
|
110
65
|
await waitForAsync();
|
|
111
66
|
|
|
@@ -116,7 +71,7 @@ describe('webex-core', () => {
|
|
|
116
71
|
{error: new Error('failed'), expectedMessage: 'failed'},
|
|
117
72
|
{error: undefined, expectedMessage: undefined},
|
|
118
73
|
])(
|
|
119
|
-
'sets initFailed to true when collectPreauthCatalog errors
|
|
74
|
+
'sets initFailed to true when collectPreauthCatalog errors',
|
|
120
75
|
async ({error, expectedMessage}) => {
|
|
121
76
|
services.collectPreauthCatalog = sinon.stub().callsFake(() => {
|
|
122
77
|
return Promise.reject(error);
|
|
@@ -124,18 +79,16 @@ describe('webex-core', () => {
|
|
|
124
79
|
|
|
125
80
|
services.listenToOnce = sinon.stub();
|
|
126
81
|
services.logger.error = sinon.stub();
|
|
127
|
-
services.trigger = sinon.stub();
|
|
128
82
|
|
|
129
83
|
services.initialize();
|
|
130
84
|
|
|
131
|
-
// call the
|
|
85
|
+
// call the onReady callback
|
|
86
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
132
87
|
services.listenToOnce.getCall(1).args[2]();
|
|
133
88
|
|
|
134
89
|
await waitForAsync();
|
|
135
90
|
|
|
136
91
|
assert.isTrue(services.initFailed);
|
|
137
|
-
assert.isTrue(services.ready);
|
|
138
|
-
sinon.assert.calledWith(services.trigger, 'services:initialized');
|
|
139
92
|
sinon.assert.calledWith(
|
|
140
93
|
services.logger.error,
|
|
141
94
|
`services: failed to init initial services when no credentials available, ${expectedMessage}`
|
|
@@ -147,7 +100,7 @@ describe('webex-core', () => {
|
|
|
147
100
|
{error: new Error('failed'), expectedMessage: 'failed'},
|
|
148
101
|
{error: undefined, expectedMessage: undefined},
|
|
149
102
|
])(
|
|
150
|
-
'sets initFailed to true when initServiceCatalogs errors
|
|
103
|
+
'sets initFailed to true when initServiceCatalogs errors',
|
|
151
104
|
async ({error, expectedMessage}) => {
|
|
152
105
|
services.initServiceCatalogs = sinon.stub().callsFake(() => {
|
|
153
106
|
return Promise.reject(error);
|
|
@@ -160,18 +113,16 @@ describe('webex-core', () => {
|
|
|
160
113
|
|
|
161
114
|
services.listenToOnce = sinon.stub();
|
|
162
115
|
services.logger.error = sinon.stub();
|
|
163
|
-
services.trigger = sinon.stub();
|
|
164
116
|
|
|
165
117
|
services.initialize();
|
|
166
118
|
|
|
167
|
-
// call the
|
|
119
|
+
// call the onReady callback
|
|
120
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
168
121
|
services.listenToOnce.getCall(1).args[2]();
|
|
169
122
|
|
|
170
123
|
await waitForAsync();
|
|
171
124
|
|
|
172
125
|
assert.isTrue(services.initFailed);
|
|
173
|
-
assert.isTrue(services.ready);
|
|
174
|
-
sinon.assert.calledWith(services.trigger, 'services:initialized');
|
|
175
126
|
sinon.assert.calledWith(
|
|
176
127
|
services.logger.error,
|
|
177
128
|
`services: failed to init initial services when credentials available, ${expectedMessage}`
|
|
@@ -179,98 +130,431 @@ describe('webex-core', () => {
|
|
|
179
130
|
}
|
|
180
131
|
);
|
|
181
132
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
services._loadCatalogFromCache = sinon.stub().returns(Promise.resolve(false));
|
|
186
|
-
services.collectPreauthCatalog = sinon.stub().returns(Promise.resolve());
|
|
187
|
-
services.initServiceCatalogs = sinon.stub().returns(Promise.resolve());
|
|
188
|
-
services.trigger = sinon.stub();
|
|
189
|
-
// Ensure no credentials so we go to the preauth path
|
|
190
|
-
services.webex.credentials = {};
|
|
133
|
+
it('sets services.ready to true when waitForCatalogInit is disabled (default)', () => {
|
|
134
|
+
services.listenToOnce = sinon.stub();
|
|
135
|
+
services.initialize();
|
|
191
136
|
|
|
192
|
-
|
|
137
|
+
// Fire the change:config handler which decides gated-vs-ungated and, in
|
|
138
|
+
// ungated mode, flips services.ready to true.
|
|
139
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
193
140
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
testCatalog.status.postauth.ready = false;
|
|
141
|
+
assert.isTrue(services.ready, 'services.ready should be true so it does not block webex.ready');
|
|
142
|
+
});
|
|
197
143
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
144
|
+
it('listens on the "ready" event when waitForCatalogInit is disabled (default)', () => {
|
|
145
|
+
services.listenToOnce = sinon.stub();
|
|
146
|
+
services.initialize();
|
|
201
147
|
|
|
202
|
-
|
|
203
|
-
|
|
148
|
+
// Fire change:config to trigger the mode-specific listener registration.
|
|
149
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
204
150
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
151
|
+
const [, event] = services.listenToOnce.getCall(1).args;
|
|
152
|
+
assert.equal(event, 'ready', 'default path listens on webex ready');
|
|
153
|
+
});
|
|
208
154
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
155
|
+
it('skips preauth catalog collection when skipPreauthCatalogOnUnauthenticated is true and no credentials', async () => {
|
|
156
|
+
services.webex.config = {
|
|
157
|
+
...(services.webex.config || {}),
|
|
158
|
+
services: {skipPreauthCatalogOnUnauthenticated: true},
|
|
159
|
+
};
|
|
160
|
+
services.listenToOnce = sinon.stub();
|
|
161
|
+
services.collectPreauthCatalog = sinon.stub().returns(Promise.resolve());
|
|
162
|
+
services.logger.info = sinon.stub();
|
|
212
163
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
services.initServiceCatalogs = sinon.stub().returns(Promise.resolve());
|
|
218
|
-
services.trigger = sinon.stub();
|
|
219
|
-
// Ensure no credentials so we go to the preauth path
|
|
220
|
-
services.webex.credentials = {};
|
|
164
|
+
services.initialize();
|
|
165
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
166
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
167
|
+
await waitForAsync();
|
|
221
168
|
|
|
222
|
-
|
|
169
|
+
assert.isFalse(
|
|
170
|
+
services.collectPreauthCatalog.called,
|
|
171
|
+
'must not collect preauth catalog while unauthenticated when option is enabled'
|
|
172
|
+
);
|
|
173
|
+
assert.isFalse(services.initFailed);
|
|
174
|
+
sinon.assert.calledWith(
|
|
175
|
+
services.logger.info,
|
|
176
|
+
'services: skipping preauth catalog collection while unauthenticated as per the config'
|
|
177
|
+
);
|
|
178
|
+
});
|
|
223
179
|
|
|
224
|
-
|
|
225
|
-
|
|
180
|
+
it('still collects preauth catalog when skipPreauthCatalogOnUnauthenticated is false (default)', async () => {
|
|
181
|
+
services.webex.config = {
|
|
182
|
+
...(services.webex.config || {}),
|
|
183
|
+
services: {skipPreauthCatalogOnUnauthenticated: false},
|
|
184
|
+
};
|
|
185
|
+
services.listenToOnce = sinon.stub();
|
|
186
|
+
services.collectPreauthCatalog = sinon.stub().returns(Promise.resolve());
|
|
226
187
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
188
|
+
services.initialize();
|
|
189
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
190
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
191
|
+
await waitForAsync();
|
|
230
192
|
|
|
231
|
-
|
|
232
|
-
services.
|
|
233
|
-
|
|
193
|
+
assert.isTrue(
|
|
194
|
+
services.collectPreauthCatalog.called,
|
|
195
|
+
'must collect preauth catalog when option is disabled'
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
234
199
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
await waitForAsync();
|
|
200
|
+
describe('#initialize (waitForCatalogInit=true)', () => {
|
|
201
|
+
let clock;
|
|
238
202
|
|
|
239
|
-
|
|
240
|
-
|
|
203
|
+
beforeEach(() => {
|
|
204
|
+
services.webex.config = {
|
|
205
|
+
...(services.webex.config || {}),
|
|
206
|
+
services: {waitForCatalogInit: true, catalogInitTimeout: 15000},
|
|
207
|
+
};
|
|
208
|
+
// Reset ready flag: the outer beforeEach constructs services which
|
|
209
|
+
// runs initialize() once with no config (ungated path, flips ready to
|
|
210
|
+
// true). We reset here so tests that call initialize() a second time
|
|
211
|
+
// with the flag enabled observe the gated behavior from a clean state.
|
|
212
|
+
services.ready = false;
|
|
213
|
+
// The gated path schedules a real 15s setTimeout via _makeInitTimeout()
|
|
214
|
+
// that is not cleared when the init race resolves. Fake only setTimeout/
|
|
215
|
+
// clearTimeout (leaving setImmediate real so waitForAsync still works)
|
|
216
|
+
// so restoring in afterEach clears the pending timer and Jest can exit.
|
|
217
|
+
clock = sinon.useFakeTimers({toFake: ['setTimeout', 'clearTimeout']});
|
|
218
|
+
});
|
|
241
219
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
services.collectPreauthCatalog = sinon.stub().returns(Promise.resolve());
|
|
246
|
-
services.initServiceCatalogs = sinon.stub().rejects(new Error('auth failed'));
|
|
247
|
-
services.logger.error = sinon.stub();
|
|
248
|
-
services.trigger = sinon.stub();
|
|
249
|
-
// Ensure no credentials so we go to the preauth path
|
|
250
|
-
services.webex.credentials = {};
|
|
220
|
+
afterEach(() => {
|
|
221
|
+
clock.restore();
|
|
222
|
+
});
|
|
251
223
|
|
|
252
|
-
|
|
224
|
+
it('leaves services.ready=false after initialize (does not flip until finalize)', () => {
|
|
225
|
+
services.listenToOnce = sinon.stub();
|
|
226
|
+
services.initialize();
|
|
253
227
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
testCatalog.status.postauth.ready = false;
|
|
228
|
+
assert.isFalse(services.ready, 'services.ready should block webex.ready until finalize');
|
|
229
|
+
});
|
|
257
230
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
231
|
+
it('listens on the "loaded" event (not "ready") to avoid deadlock', () => {
|
|
232
|
+
services.listenToOnce = sinon.stub();
|
|
233
|
+
services.initialize();
|
|
261
234
|
|
|
262
|
-
|
|
263
|
-
|
|
235
|
+
// Fire change:config to trigger the mode-specific listener registration.
|
|
236
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
264
237
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
238
|
+
const [, event] = services.listenToOnce.getCall(1).args;
|
|
239
|
+
assert.equal(event, 'loaded', 'gated path must listen on loaded to avoid deadlock');
|
|
240
|
+
});
|
|
268
241
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
242
|
+
it('flips services.ready=true after init succeeds with credentials', async () => {
|
|
243
|
+
services.listenToOnce = sinon.stub();
|
|
244
|
+
services.initServiceCatalogs = sinon.stub().returns(Promise.resolve());
|
|
245
|
+
services.webex.credentials = {
|
|
246
|
+
supertoken: {access_token: 'token'},
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
services.initialize();
|
|
250
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
251
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
252
|
+
await waitForAsync();
|
|
253
|
+
|
|
254
|
+
assert.isTrue(services.ready);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('flips services.ready=true after init succeeds without credentials (preauth path)', async () => {
|
|
258
|
+
services.listenToOnce = sinon.stub();
|
|
259
|
+
services.collectPreauthCatalog = sinon.stub().returns(Promise.resolve());
|
|
260
|
+
|
|
261
|
+
services.initialize();
|
|
262
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
263
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
264
|
+
await waitForAsync();
|
|
265
|
+
|
|
266
|
+
assert.isTrue(services.ready);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('flips services.ready=true even when initServiceCatalogs errors, so webex.ready can fire', async () => {
|
|
270
|
+
services.listenToOnce = sinon.stub();
|
|
271
|
+
services.initServiceCatalogs = sinon.stub().returns(Promise.reject(new Error('boom')));
|
|
272
|
+
services.webex.credentials = {
|
|
273
|
+
supertoken: {access_token: 'token'},
|
|
274
|
+
};
|
|
275
|
+
services.logger.error = sinon.stub();
|
|
276
|
+
|
|
277
|
+
services.initialize();
|
|
278
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
279
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
280
|
+
await waitForAsync();
|
|
281
|
+
|
|
282
|
+
assert.isTrue(services.initFailed);
|
|
283
|
+
assert.isTrue(services.ready);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it('flips services.ready=true even when collectPreauthCatalog errors', async () => {
|
|
287
|
+
services.listenToOnce = sinon.stub();
|
|
288
|
+
services.collectPreauthCatalog = sinon.stub().returns(Promise.reject(new Error('boom')));
|
|
289
|
+
services.logger.error = sinon.stub();
|
|
290
|
+
|
|
291
|
+
services.initialize();
|
|
292
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
293
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
294
|
+
await waitForAsync();
|
|
295
|
+
|
|
296
|
+
assert.isTrue(services.initFailed);
|
|
297
|
+
assert.isTrue(services.ready);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('flips services.ready=true when init times out', async () => {
|
|
301
|
+
services.listenToOnce = sinon.stub();
|
|
302
|
+
services.initServiceCatalogs = sinon.stub().returns(new Promise(() => {}));
|
|
303
|
+
services.webex.credentials = {
|
|
304
|
+
supertoken: {access_token: 'token'},
|
|
305
|
+
};
|
|
306
|
+
services.logger.error = sinon.stub();
|
|
307
|
+
|
|
308
|
+
services.initialize();
|
|
309
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
310
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
311
|
+
|
|
312
|
+
await clock.tickAsync(15_001);
|
|
313
|
+
|
|
314
|
+
assert.isTrue(services.initFailed);
|
|
315
|
+
assert.isTrue(services.ready);
|
|
316
|
+
sinon.assert.calledWithMatch(
|
|
317
|
+
services.logger.error,
|
|
318
|
+
/services: init timed out after 15000ms/
|
|
319
|
+
);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('awaits an in-flight credentials refresh before flipping services.ready=true', async () => {
|
|
323
|
+
services.listenToOnce = sinon.stub();
|
|
324
|
+
services.initServiceCatalogs = sinon.stub().returns(Promise.resolve());
|
|
325
|
+
|
|
326
|
+
let onChangeIsRefreshing: (() => void) | undefined;
|
|
327
|
+
services.webex.credentials = {
|
|
328
|
+
supertoken: {access_token: 'token'},
|
|
329
|
+
isRefreshing: true,
|
|
330
|
+
once: sinon.stub().callsFake((event: string, cb: () => void) => {
|
|
331
|
+
if (event === 'change:isRefreshing') onChangeIsRefreshing = cb;
|
|
332
|
+
}),
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
services.initialize();
|
|
336
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
337
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
338
|
+
await waitForAsync();
|
|
339
|
+
|
|
340
|
+
assert.isFalse(services.ready, 'must not flip ready while refresh is in flight');
|
|
341
|
+
assert.isFunction(onChangeIsRefreshing, 'must subscribe to change:isRefreshing');
|
|
342
|
+
sinon.assert.calledWith(services.webex.credentials.once, 'change:isRefreshing');
|
|
343
|
+
|
|
344
|
+
onChangeIsRefreshing!();
|
|
345
|
+
await waitForAsync();
|
|
346
|
+
|
|
347
|
+
assert.isTrue(services.ready);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it('registers a change:canAuthorize listener when there is no supertoken (fresh-login path)', async () => {
|
|
351
|
+
services.listenToOnce = sinon.stub();
|
|
352
|
+
services.collectPreauthCatalog = sinon.stub().returns(Promise.resolve());
|
|
353
|
+
services.initServiceCatalogs = sinon.stub().returns(Promise.resolve());
|
|
354
|
+
|
|
355
|
+
services.initialize();
|
|
356
|
+
// initialize() creates a new catalog and replaces the WeakMap entry.
|
|
357
|
+
const currentCatalog = services._getCatalog();
|
|
358
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
359
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
360
|
+
await waitForAsync();
|
|
361
|
+
|
|
362
|
+
const freshLoginCall = services.listenToOnce
|
|
363
|
+
.getCalls()
|
|
364
|
+
.find((call: any) => call.args[1] === 'change:canAuthorize');
|
|
365
|
+
assert.isDefined(freshLoginCall, 'expected change:canAuthorize listener to be registered');
|
|
366
|
+
|
|
367
|
+
services.webex.canAuthorize = true;
|
|
368
|
+
currentCatalog.status.postauth.ready = false;
|
|
369
|
+
freshLoginCall!.args[2]();
|
|
370
|
+
|
|
371
|
+
assert.isTrue(
|
|
372
|
+
services.initServiceCatalogs.called,
|
|
373
|
+
'expected postauth catalog init after canAuthorize flips'
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
// `catalog.isReady` is now set inside initServiceCatalogs (after the
|
|
377
|
+
// postauth updateServices) rather than by this listener, so it is not
|
|
378
|
+
// asserted here where initServiceCatalogs is stubbed.
|
|
379
|
+
await waitForAsync();
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it('does not re-init postauth catalog when canAuthorize fires but catalog is already ready', async () => {
|
|
383
|
+
services.listenToOnce = sinon.stub();
|
|
384
|
+
services.collectPreauthCatalog = sinon.stub().returns(Promise.resolve());
|
|
385
|
+
services.initServiceCatalogs = sinon.stub().returns(Promise.resolve());
|
|
386
|
+
|
|
387
|
+
services.initialize();
|
|
388
|
+
// initialize() creates a new catalog; grab the current one.
|
|
389
|
+
const currentCatalog = services._getCatalog();
|
|
390
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
391
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
392
|
+
await waitForAsync();
|
|
393
|
+
|
|
394
|
+
const freshLoginCall = services.listenToOnce
|
|
395
|
+
.getCalls()
|
|
396
|
+
.find((call: any) => call.args[1] === 'change:canAuthorize');
|
|
397
|
+
|
|
398
|
+
services.webex.canAuthorize = true;
|
|
399
|
+
currentCatalog.status.postauth.ready = true;
|
|
400
|
+
freshLoginCall!.args[2]();
|
|
401
|
+
|
|
402
|
+
assert.isFalse(
|
|
403
|
+
services.initServiceCatalogs.called,
|
|
404
|
+
'must not re-fetch postauth catalog if it is already ready'
|
|
405
|
+
);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('finalizes ready when cache is warm (skips network fetch)', async () => {
|
|
409
|
+
services.listenToOnce = sinon.stub();
|
|
410
|
+
services._loadCatalogFromCache = sinon.stub().returns(Promise.resolve(true));
|
|
411
|
+
services.initServiceCatalogs = sinon.stub().returns(Promise.resolve());
|
|
412
|
+
services.collectPreauthCatalog = sinon.stub().returns(Promise.resolve());
|
|
413
|
+
|
|
414
|
+
services.initialize();
|
|
415
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
416
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
417
|
+
await waitForAsync();
|
|
418
|
+
await waitForAsync();
|
|
419
|
+
|
|
420
|
+
assert.isTrue(services.ready);
|
|
421
|
+
assert.isFalse(
|
|
422
|
+
services.initServiceCatalogs.called,
|
|
423
|
+
'must skip network fetch when cache is warm'
|
|
424
|
+
);
|
|
425
|
+
assert.isFalse(
|
|
426
|
+
services.collectPreauthCatalog.called,
|
|
427
|
+
'must skip preauth fetch when cache is warm'
|
|
428
|
+
);
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
describe('#initialize (waitForCatalogInit=true, skipPreauthCatalogOnUnauthenticated=true)', () => {
|
|
433
|
+
beforeEach(() => {
|
|
434
|
+
services.webex.config = {
|
|
435
|
+
...(services.webex.config || {}),
|
|
436
|
+
services: {
|
|
437
|
+
waitForCatalogInit: true,
|
|
438
|
+
catalogInitTimeout: 15000,
|
|
439
|
+
skipPreauthCatalogOnUnauthenticated: true,
|
|
440
|
+
},
|
|
441
|
+
};
|
|
442
|
+
services.ready = false;
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it('skips preauth catalog collection but still finalizes services.ready when unauthenticated', async () => {
|
|
446
|
+
services.listenToOnce = sinon.stub();
|
|
447
|
+
services.collectPreauthCatalog = sinon.stub().returns(Promise.resolve());
|
|
448
|
+
services.logger.info = sinon.stub();
|
|
449
|
+
|
|
450
|
+
services.initialize();
|
|
451
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
452
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
453
|
+
await waitForAsync();
|
|
454
|
+
|
|
455
|
+
assert.isFalse(
|
|
456
|
+
services.collectPreauthCatalog.called,
|
|
457
|
+
'must not collect preauth catalog while unauthenticated when option is enabled'
|
|
458
|
+
);
|
|
459
|
+
assert.isTrue(services.ready, 'must still finalize ready so webex.ready is not stalled');
|
|
460
|
+
sinon.assert.calledWith(
|
|
461
|
+
services.logger.info,
|
|
462
|
+
'services: skipping preauth catalog collection while unauthenticated as per the config'
|
|
463
|
+
);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
it('still registers a change:canAuthorize listener when skipping preauth (fresh-login path)', async () => {
|
|
467
|
+
services.listenToOnce = sinon.stub();
|
|
468
|
+
services.collectPreauthCatalog = sinon.stub().returns(Promise.resolve());
|
|
469
|
+
services.initServiceCatalogs = sinon.stub().returns(Promise.resolve());
|
|
470
|
+
|
|
471
|
+
services.initialize();
|
|
472
|
+
const currentCatalog = services._getCatalog();
|
|
473
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
474
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
475
|
+
await waitForAsync();
|
|
476
|
+
|
|
477
|
+
const freshLoginCall = services.listenToOnce
|
|
478
|
+
.getCalls()
|
|
479
|
+
.find((call: any) => call.args[1] === 'change:canAuthorize');
|
|
480
|
+
assert.isDefined(freshLoginCall, 'expected change:canAuthorize listener to be registered');
|
|
481
|
+
|
|
482
|
+
services.webex.canAuthorize = true;
|
|
483
|
+
currentCatalog.status.postauth.ready = false;
|
|
484
|
+
freshLoginCall!.args[2]();
|
|
485
|
+
|
|
486
|
+
assert.isTrue(
|
|
487
|
+
services.initServiceCatalogs.called,
|
|
488
|
+
'expected postauth catalog init after canAuthorize flips'
|
|
489
|
+
);
|
|
490
|
+
await waitForAsync();
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
it('does not schedule an init timeout when skipping preauth (no stray timer/rejection)', async () => {
|
|
494
|
+
const clock = sinon.useFakeTimers();
|
|
495
|
+
services.listenToOnce = sinon.stub();
|
|
496
|
+
services.collectPreauthCatalog = sinon.stub().returns(Promise.resolve());
|
|
497
|
+
services.logger.error = sinon.stub();
|
|
498
|
+
|
|
499
|
+
services.initialize();
|
|
500
|
+
services.listenToOnce.getCall(0).args[2]();
|
|
501
|
+
services.listenToOnce.getCall(1).args[2]();
|
|
502
|
+
|
|
503
|
+
// Advance well past the configured init timeout; since no timeout was
|
|
504
|
+
// scheduled in skip mode, no timeout error should ever be logged.
|
|
505
|
+
await clock.tickAsync(30_000);
|
|
506
|
+
clock.restore();
|
|
507
|
+
|
|
508
|
+
sinon.assert.neverCalledWithMatch(
|
|
509
|
+
services.logger.error,
|
|
510
|
+
/services: init timed out/
|
|
511
|
+
);
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
describe('#_finalizeReady', () => {
|
|
516
|
+
beforeEach(() => {
|
|
517
|
+
// Outer beforeEach construction already ran initialize() (ungated,
|
|
518
|
+
// sets ready=true). Reset so _finalizeReady's flip is observable.
|
|
519
|
+
services.ready = false;
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
it('sets ready=true immediately when credentials are not refreshing', async () => {
|
|
523
|
+
services.webex.credentials = {isRefreshing: false};
|
|
524
|
+
assert.isFalse(services.ready);
|
|
525
|
+
|
|
526
|
+
await services._finalizeReady();
|
|
527
|
+
|
|
528
|
+
assert.isTrue(services.ready);
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
it('sets ready=true when credentials are missing', async () => {
|
|
532
|
+
services.webex.credentials = undefined;
|
|
533
|
+
|
|
534
|
+
await services._finalizeReady();
|
|
535
|
+
|
|
536
|
+
assert.isTrue(services.ready);
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
it('awaits change:isRefreshing before setting ready=true', async () => {
|
|
540
|
+
let onChangeIsRefreshing: (() => void) | undefined;
|
|
541
|
+
services.webex.credentials = {
|
|
542
|
+
isRefreshing: true,
|
|
543
|
+
once: sinon.stub().callsFake((event: string, cb: () => void) => {
|
|
544
|
+
if (event === 'change:isRefreshing') onChangeIsRefreshing = cb;
|
|
545
|
+
}),
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
const settled = services._finalizeReady();
|
|
549
|
+
await waitForAsync();
|
|
550
|
+
|
|
551
|
+
assert.isFalse(services.ready, 'ready must not flip while refresh is in flight');
|
|
552
|
+
assert.isFunction(onChangeIsRefreshing);
|
|
553
|
+
|
|
554
|
+
onChangeIsRefreshing!();
|
|
555
|
+
await settled;
|
|
556
|
+
|
|
557
|
+
assert.isTrue(services.ready);
|
|
274
558
|
});
|
|
275
559
|
});
|
|
276
560
|
|
|
@@ -425,7 +709,7 @@ describe('webex-core', () => {
|
|
|
425
709
|
|
|
426
710
|
services.initServiceCatalogs = sinon.stub().returns(Promise.resolve());
|
|
427
711
|
services.webex.credentials = {
|
|
428
|
-
getOrgId: sinon.stub().returns('')
|
|
712
|
+
getOrgId: sinon.stub().returns('')
|
|
429
713
|
};
|
|
430
714
|
catalog.status = {};
|
|
431
715
|
});
|
|
@@ -466,7 +750,7 @@ describe('webex-core', () => {
|
|
|
466
750
|
const serviceGroup = 'postauth';
|
|
467
751
|
const hostmap = {services: [{hostmap: 'hostmap'}]};
|
|
468
752
|
|
|
469
|
-
services._formatReceivedHostmap = sinon.stub().returns({services: [{some: 'hostmap'}]});
|
|
753
|
+
services._formatReceivedHostmap = sinon.stub().returns({services : [{some: 'hostmap'}]});
|
|
470
754
|
|
|
471
755
|
catalog.updateServiceGroups = sinon.stub().returns(Promise.resolve([{some: 'value'}]));
|
|
472
756
|
|
|
@@ -482,7 +766,7 @@ describe('webex-core', () => {
|
|
|
482
766
|
const serviceGroup = 'postauth';
|
|
483
767
|
const hostmap = {};
|
|
484
768
|
|
|
485
|
-
services._formatReceivedHostmap = sinon.stub().returns({services: undefined});
|
|
769
|
+
services._formatReceivedHostmap = sinon.stub().returns({services : undefined});
|
|
486
770
|
|
|
487
771
|
catalog.updateServiceGroups = sinon.stub().returns(Promise.resolve([{some: 'value'}]));
|
|
488
772
|
|
|
@@ -527,6 +811,22 @@ describe('webex-core', () => {
|
|
|
527
811
|
);
|
|
528
812
|
});
|
|
529
813
|
|
|
814
|
+
it('includes the catalog override query when configured', async () => {
|
|
815
|
+
services.webex.config.services = {useCatalogOverride: true};
|
|
816
|
+
sinon.stub(services, '_formatReceivedHostmap').resolves('map response');
|
|
817
|
+
sinon.stub(services, 'request').resolves({});
|
|
818
|
+
|
|
819
|
+
await services._fetchNewServiceHostmap({from: 'limited'});
|
|
820
|
+
|
|
821
|
+
assert.calledOnceWithExactly(services.request, {
|
|
822
|
+
method: 'GET',
|
|
823
|
+
service: 'u2c',
|
|
824
|
+
resource: '/limited/catalog',
|
|
825
|
+
qs: {format: 'U2CV2', useCatalogOverride: true},
|
|
826
|
+
headers: {},
|
|
827
|
+
});
|
|
828
|
+
});
|
|
829
|
+
|
|
530
830
|
it('checks service request rejects', async () => {
|
|
531
831
|
const error = new Error('some error');
|
|
532
832
|
|
|
@@ -721,13 +1021,13 @@ describe('webex-core', () => {
|
|
|
721
1021
|
});
|
|
722
1022
|
|
|
723
1023
|
describe('#invalidateCache', () => {
|
|
724
|
-
beforeEach(() => {
|
|
1024
|
+
beforeEach( () => {
|
|
725
1025
|
services.initServiceCatalogs = sinon.stub().returns(Promise.resolve());
|
|
726
1026
|
services.webex.credentials = {
|
|
727
|
-
getOrgId: sinon.stub().returns('')
|
|
1027
|
+
getOrgId: sinon.stub().returns('')
|
|
728
1028
|
};
|
|
729
1029
|
catalog.status = {};
|
|
730
|
-
})
|
|
1030
|
+
})
|
|
731
1031
|
it('should log the timestamp parameter', async () => {
|
|
732
1032
|
const timestamp = '1234567890';
|
|
733
1033
|
services.logger.info = sinon.stub();
|
|
@@ -735,11 +1035,7 @@ describe('webex-core', () => {
|
|
|
735
1035
|
|
|
736
1036
|
await services.invalidateCache(timestamp);
|
|
737
1037
|
|
|
738
|
-
assert.calledWith(
|
|
739
|
-
services.logger.info,
|
|
740
|
-
'services: invalidate cache, timestamp:',
|
|
741
|
-
timestamp
|
|
742
|
-
);
|
|
1038
|
+
assert.calledWith(services.logger.info, 'services: invalidate cache, timestamp:', timestamp);
|
|
743
1039
|
});
|
|
744
1040
|
|
|
745
1041
|
it('should call initServiceCatalogs when invalidate timestamp is newer than catalog timestamp', async () => {
|
|
@@ -866,30 +1162,30 @@ describe('webex-core', () => {
|
|
|
866
1162
|
// Arrange: seed internal _services with mobius (including duplicate baseUrl)
|
|
867
1163
|
services._services = [
|
|
868
1164
|
{
|
|
869
|
-
id:
|
|
870
|
-
serviceName: 'mobius',
|
|
871
|
-
serviceUrls: [
|
|
872
|
-
{baseUrl: 'https://mobius-us-east-2.prod.infra.webex.com/api/v1', priority: 5},
|
|
873
|
-
{baseUrl: 'https://mobius-eu-central-1.prod.infra.webex.com/api/v1', priority: 10},
|
|
874
|
-
{baseUrl: 'https://mobius-ap-southeast-2.prod.infra.webex.com/api/v1', priority: 15}, // duplicate
|
|
1165
|
+
"id": "urn:TEAM:us-east-2_a:mobius",
|
|
1166
|
+
"serviceName": 'mobius',
|
|
1167
|
+
"serviceUrls": [
|
|
1168
|
+
{"baseUrl": 'https://mobius-us-east-2.prod.infra.webex.com/api/v1', "priority": 5},
|
|
1169
|
+
{"baseUrl": 'https://mobius-eu-central-1.prod.infra.webex.com/api/v1', "priority": 10},
|
|
1170
|
+
{"baseUrl": 'https://mobius-ap-southeast-2.prod.infra.webex.com/api/v1', "priority": 15}, // duplicate
|
|
875
1171
|
],
|
|
876
1172
|
},
|
|
877
1173
|
{
|
|
878
|
-
id:
|
|
879
|
-
serviceName:
|
|
880
|
-
serviceUrls: [
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
1174
|
+
"id": "urn:TEAM:ap-southeast-2_m:mobius",
|
|
1175
|
+
"serviceName": "mobius",
|
|
1176
|
+
"serviceUrls": [
|
|
1177
|
+
{
|
|
1178
|
+
"baseUrl": "https://mobius-me-central-1.prod.infra.webex.com/api/v1",
|
|
1179
|
+
"priority": 5
|
|
1180
|
+
},
|
|
1181
|
+
{
|
|
1182
|
+
"baseUrl": "https://mobius-eu-central-1.prod.infra.webex.com/api/v1",
|
|
1183
|
+
"priority": 10
|
|
1184
|
+
},
|
|
1185
|
+
{
|
|
1186
|
+
"baseUrl": "https://mobius-ap-southeast-2.prod.infra.webex.com/api/v1",
|
|
1187
|
+
"priority": 15
|
|
1188
|
+
},
|
|
893
1189
|
],
|
|
894
1190
|
},
|
|
895
1191
|
// Non-mobius service should be ignored by getMobiusClusters
|
|
@@ -907,64 +1203,42 @@ describe('webex-core', () => {
|
|
|
907
1203
|
assert.deepEqual(
|
|
908
1204
|
clusters.map(({host, id, ttl, priority}) => ({host, id, ttl, priority})),
|
|
909
1205
|
[
|
|
910
|
-
{
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
priority: 5,
|
|
915
|
-
},
|
|
916
|
-
{
|
|
917
|
-
host: 'mobius-eu-central-1.prod.infra.webex.com',
|
|
918
|
-
id: 'urn:TEAM:us-east-2_a:mobius',
|
|
919
|
-
ttl: 0,
|
|
920
|
-
priority: 10,
|
|
921
|
-
},
|
|
922
|
-
{
|
|
923
|
-
host: 'mobius-ap-southeast-2.prod.infra.webex.com',
|
|
924
|
-
id: 'urn:TEAM:us-east-2_a:mobius',
|
|
925
|
-
ttl: 0,
|
|
926
|
-
priority: 15,
|
|
927
|
-
},
|
|
928
|
-
{
|
|
929
|
-
host: 'mobius-me-central-1.prod.infra.webex.com',
|
|
930
|
-
id: 'urn:TEAM:ap-southeast-2_m:mobius',
|
|
931
|
-
ttl: 0,
|
|
932
|
-
priority: 5,
|
|
933
|
-
},
|
|
1206
|
+
{host: 'mobius-us-east-2.prod.infra.webex.com', id: 'urn:TEAM:us-east-2_a:mobius', ttl: 0, priority: 5},
|
|
1207
|
+
{host: 'mobius-eu-central-1.prod.infra.webex.com', id: 'urn:TEAM:us-east-2_a:mobius', ttl: 0, priority: 10},
|
|
1208
|
+
{host: 'mobius-ap-southeast-2.prod.infra.webex.com', id: 'urn:TEAM:us-east-2_a:mobius', ttl: 0, priority: 15},
|
|
1209
|
+
{host: 'mobius-me-central-1.prod.infra.webex.com', id: 'urn:TEAM:ap-southeast-2_m:mobius', ttl: 0, priority: 5},
|
|
934
1210
|
]
|
|
935
1211
|
);
|
|
936
1212
|
});
|
|
937
1213
|
});
|
|
938
|
-
|
|
1214
|
+
|
|
939
1215
|
describe('#isValidHost', () => {
|
|
940
1216
|
beforeEach(() => {
|
|
941
1217
|
// Setting up a mock services list
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
},
|
|
967
|
-
];
|
|
1218
|
+
services._services = [{
|
|
1219
|
+
"id": "urn:IDENTITY:PC75:adminAudit",
|
|
1220
|
+
"serviceName": "adminAudit",
|
|
1221
|
+
"serviceUrls": [
|
|
1222
|
+
{
|
|
1223
|
+
"baseUrl": "https://audit-ci-r.wbx2.com/audit-ci/api/v2",
|
|
1224
|
+
"priority": 5
|
|
1225
|
+
},
|
|
1226
|
+
{
|
|
1227
|
+
"baseUrl": "https://audit-ci-t.wbx2.com/audit-ci/api/v2",
|
|
1228
|
+
"priority": 10
|
|
1229
|
+
}
|
|
1230
|
+
]
|
|
1231
|
+
},
|
|
1232
|
+
{
|
|
1233
|
+
"id": "urn:IDENTITY:PC75:cdf",
|
|
1234
|
+
"serviceName": "cdf",
|
|
1235
|
+
"serviceUrls": [
|
|
1236
|
+
{
|
|
1237
|
+
"baseUrl": "https://wapdavis.webex.com/davis/api/v1",
|
|
1238
|
+
"priority": 5
|
|
1239
|
+
}
|
|
1240
|
+
]
|
|
1241
|
+
}];
|
|
968
1242
|
});
|
|
969
1243
|
afterAll(() => {
|
|
970
1244
|
// Clean up the mock services list
|
|
@@ -988,6 +1262,57 @@ describe('webex-core', () => {
|
|
|
988
1262
|
});
|
|
989
1263
|
});
|
|
990
1264
|
|
|
1265
|
+
describe('#isIntegrationEnvironment', () => {
|
|
1266
|
+
it('returns true when u2c URL contains "intb"', () => {
|
|
1267
|
+
services.webex.config = {
|
|
1268
|
+
services: {
|
|
1269
|
+
discovery: {
|
|
1270
|
+
u2c: 'https://u2c-intb.ciscospark.com/u2c/api/v1',
|
|
1271
|
+
},
|
|
1272
|
+
},
|
|
1273
|
+
};
|
|
1274
|
+
assert.isTrue(services.isIntegrationEnvironment());
|
|
1275
|
+
});
|
|
1276
|
+
|
|
1277
|
+
it('returns false when u2c URL does not contain "intb" (production)', () => {
|
|
1278
|
+
services.webex.config = {
|
|
1279
|
+
services: {
|
|
1280
|
+
discovery: {
|
|
1281
|
+
u2c: 'https://u2c.wbx2.com/u2c/api/v1',
|
|
1282
|
+
},
|
|
1283
|
+
},
|
|
1284
|
+
};
|
|
1285
|
+
assert.isFalse(services.isIntegrationEnvironment());
|
|
1286
|
+
});
|
|
1287
|
+
|
|
1288
|
+
it('returns false when u2c URL is for FedRAMP', () => {
|
|
1289
|
+
services.webex.config = {
|
|
1290
|
+
services: {
|
|
1291
|
+
discovery: {
|
|
1292
|
+
u2c: 'https://u2c.gov.ciscospark.com/u2c/api/v1',
|
|
1293
|
+
},
|
|
1294
|
+
},
|
|
1295
|
+
};
|
|
1296
|
+
assert.isFalse(services.isIntegrationEnvironment());
|
|
1297
|
+
});
|
|
1298
|
+
|
|
1299
|
+
it('returns false when u2c URL is undefined', () => {
|
|
1300
|
+
services.webex.config = {
|
|
1301
|
+
services: {
|
|
1302
|
+
discovery: {
|
|
1303
|
+
u2c: undefined,
|
|
1304
|
+
},
|
|
1305
|
+
},
|
|
1306
|
+
};
|
|
1307
|
+
assert.isFalse(services.isIntegrationEnvironment());
|
|
1308
|
+
});
|
|
1309
|
+
|
|
1310
|
+
it('returns false when config is not available', () => {
|
|
1311
|
+
services.webex.config = undefined;
|
|
1312
|
+
assert.isFalse(services.isIntegrationEnvironment());
|
|
1313
|
+
});
|
|
1314
|
+
});
|
|
1315
|
+
|
|
991
1316
|
describe('U2C catalog cache behavior (v2)', () => {
|
|
992
1317
|
const CATALOG_CACHE_KEY_V2 = 'services.v2.u2cHostMap';
|
|
993
1318
|
let windowBackup;
|