@webex/internal-plugin-dss 3.0.0-beta.14 → 3.0.0-beta.140

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,33 +1,37 @@
1
1
  /*!
2
2
  * Copyright (c) 2015-2022 Cisco Systems, Inc. See LICENSE file.
3
3
  */
4
-
5
- import { assert } from "@webex/test-helper-chai";
6
- import DSS from "@webex/internal-plugin-dss";
7
- import MockWebex from "@webex/test-helper-mock-webex";
8
- import sinon from "sinon";
9
- import { expect } from "chai";
10
- import { set } from "lodash";
11
- import uuid from "uuid";
12
-
13
- describe("plugin-dss", () => {
14
- describe("DSS", () => {
4
+ /* eslint-disable no-underscore-dangle */
5
+
6
+ import {assert, expect} from '@webex/test-helper-chai';
7
+ import DSS from '@webex/internal-plugin-dss';
8
+ import {Batcher} from '@webex/webex-core';
9
+ import MockWebex from '@webex/test-helper-mock-webex';
10
+ import sinon from 'sinon';
11
+ import {set} from 'lodash';
12
+ import uuid from 'uuid';
13
+ import config from '@webex/internal-plugin-dss/src/config';
14
+
15
+ describe('plugin-dss', () => {
16
+ describe('DSS', () => {
15
17
  let webex;
16
18
  let uuidStub;
17
19
  let mercuryCallbacks;
20
+ let clock;
18
21
 
19
22
  beforeEach(() => {
20
- webex = new MockWebex({
23
+ webex = MockWebex({
21
24
  canAuthorize: false,
22
25
  children: {
23
26
  dss: DSS,
24
27
  },
25
28
  });
29
+ webex.config.dss = config.dss;
26
30
 
27
- uuidStub = sinon.stub(uuid, "v4").returns("randomid");
31
+ uuidStub = sinon.stub(uuid, 'v4').returns('randomid');
28
32
 
29
33
  webex.canAuthorize = true;
30
- webex.internal.device.orgId = "userOrgId";
34
+ webex.internal.device.orgId = 'userOrgId';
31
35
 
32
36
  mercuryCallbacks = {};
33
37
 
@@ -39,81 +43,90 @@ describe("plugin-dss", () => {
39
43
  }),
40
44
  off: sinon.spy(),
41
45
  };
46
+
47
+ clock = sinon.useFakeTimers();
42
48
  });
43
49
 
44
50
  afterEach(() => {
45
51
  uuidStub.restore();
52
+ clock.restore();
46
53
  });
47
54
 
48
- describe("#register()", () => {
49
- it("registers correctly", async () => {
55
+ describe('#register()', () => {
56
+ it('registers correctly', async () => {
50
57
  await webex.internal.dss.register();
51
58
 
52
59
  assert.callCount(webex.internal.mercury.on, 2);
53
60
 
54
61
  const firstCallArgs = webex.internal.mercury.on.getCall(0).args;
55
- expect(firstCallArgs[0]).to.equal("event:directory.lookup");
56
- expect(firstCallArgs[1]).to.be.a("function");
62
+
63
+ expect(firstCallArgs[0]).to.equal('event:directory.lookup');
64
+ expect(firstCallArgs[1]).to.be.a('function');
57
65
 
58
66
  const secondCallArgs = webex.internal.mercury.on.getCall(1).args;
59
- expect(secondCallArgs[0]).to.equal("event:directory.search");
60
- expect(secondCallArgs[1]).to.be.a("function");
67
+
68
+ expect(secondCallArgs[0]).to.equal('event:directory.search');
69
+ expect(secondCallArgs[1]).to.be.a('function');
61
70
 
62
71
  assert.equal(webex.internal.dss.registered, true);
63
72
  });
64
73
 
65
- it("rejects when it cannot authorize", async () => {
74
+ it('rejects when it cannot authorize', async () => {
66
75
  webex.canAuthorize = false;
76
+ // @ts-ignore
67
77
  await expect(webex.internal.dss.register()).to.be.rejectedWith(
68
78
  Error,
69
- "SDK cannot authorize"
79
+ 'SDK cannot authorize'
70
80
  );
71
81
  assert.equal(webex.internal.dss.registered, false);
72
82
  });
73
83
  });
74
84
 
75
- describe("#unregister()", () => {
76
- it("unregisters correctly", async () => {
85
+ describe('#unregister()', () => {
86
+ it('unregisters correctly', async () => {
77
87
  webex.internal.dss.registered = true;
78
88
  await webex.internal.dss.unregister();
79
89
 
80
90
  assert.callCount(webex.internal.mercury.off, 2);
81
91
 
82
92
  const firstCallArgs = webex.internal.mercury.off.getCall(0).args;
83
- expect(firstCallArgs[0]).to.equal("event:directory.lookup");
93
+
94
+ expect(firstCallArgs[0]).to.equal('event:directory.lookup');
84
95
 
85
96
  const secondCallArgs = webex.internal.mercury.off.getCall(1).args;
86
- expect(secondCallArgs[0]).to.equal("event:directory.search");
97
+
98
+ expect(secondCallArgs[0]).to.equal('event:directory.search');
87
99
 
88
100
  assert.equal(webex.internal.dss.registered, false);
89
101
  });
90
102
 
91
- it("handles unregister when it is not registered", async () => {
103
+ it('handles unregister when it is not registered', async () => {
92
104
  const result = await webex.internal.dss.unregister();
105
+
93
106
  await expect(result).equal(undefined);
94
107
  assert.equal(webex.internal.dss.registered, false);
95
108
  });
96
109
  });
97
110
 
98
- const createData = (requestId, sequence, finished, dataPath) => {
111
+ const createData = (requestId, sequence, finished, dataPath, results) => {
99
112
  const data = {
100
113
  requestId,
101
114
  sequence,
102
115
  };
116
+
103
117
  if (finished) {
104
118
  (data as any).finished = finished;
105
119
  }
106
- set(data, dataPath, [`data${sequence}`]);
107
- return { data };
120
+ set(data, dataPath, results);
121
+
122
+ return {data};
108
123
  };
109
124
 
110
- const testRequest = async ({
125
+ const testMakeRequest = async ({
111
126
  method,
112
127
  resource,
113
128
  params,
114
- bodyParams,
115
- dataPath,
116
- event,
129
+ bodyParams
117
130
  }) => {
118
131
  webex.request = sinon.stub();
119
132
 
@@ -121,261 +134,792 @@ describe("plugin-dss", () => {
121
134
 
122
135
  const promise = webex.internal.dss[method](params);
123
136
 
124
- const requestId = "randomid";
137
+ const requestId = 'randomid';
125
138
 
126
139
  expect(webex.request.getCall(0).args).to.deep.equal([
127
140
  {
128
- service: "directorySearch",
141
+ service: 'directorySearch',
129
142
  body: {
130
143
  requestId,
131
144
  ...bodyParams,
132
145
  },
133
- contentType: "application/json",
134
- method: "POST",
146
+ contentType: 'application/json',
147
+ method: 'POST',
135
148
  resource,
136
149
  },
137
150
  ]);
138
151
 
139
- mercuryCallbacks[event](createData(requestId, 1, false, dataPath));
140
- mercuryCallbacks[event](createData(requestId, 2, true, dataPath));
141
- mercuryCallbacks[event](createData(requestId, 0, false, dataPath));
152
+ return {requestId, promise};
153
+ };
154
+
155
+ const testMakeBatchedRequests = async ({
156
+ requests,
157
+ calls,
158
+ }) => {
159
+ requests.forEach((request, index) => { uuidStub.onCall(index).returns(request.id); });
160
+ webex.request = sinon.stub();
161
+
162
+ await webex.internal.dss.register();
163
+
164
+ const promises = calls.map((call) => webex.internal.dss[call.method](call.params));
165
+
166
+ await clock.tickAsync(49);
167
+ expect(webex.request.notCalled).to.be.true;
168
+ await clock.tickAsync(1);
169
+ expect(webex.request.called).to.be.true;
170
+
171
+ requests.forEach((request, index) => {
172
+ expect(webex.request.getCall(index).args).to.deep.equal([
173
+ {
174
+ service: 'directorySearch',
175
+ body: {
176
+ requestId: request.id,
177
+ ...request.bodyParams,
178
+ },
179
+ contentType: 'application/json',
180
+ method: 'POST',
181
+ resource: request.resource,
182
+ },
183
+ ]);
184
+ });
142
185
 
143
- const result = await promise;
144
- expect(result).to.deep.equal(["data0", "data1", "data2"]);
186
+ return {promises};
145
187
  };
146
188
 
147
- describe("#lookupDetail", () => {
148
- it("calls _request correctly", async () => {
149
- webex.internal.device.orgId = "userOrgId";
150
- webex.internal.dss._request = sinon
151
- .stub()
152
- .returns(Promise.resolve("some return value"));
189
+ describe('#lookupDetail', () => {
190
+ it('calls _request correctly', async () => {
191
+ webex.internal.device.orgId = 'userOrgId';
192
+ webex.internal.dss._request = sinon.stub().returns(
193
+ Promise.resolve({
194
+ resultArray: ['some return value'],
195
+ foundArray: ['test id'],
196
+ })
197
+ );
198
+
199
+ const result = await webex.internal.dss.lookupDetail({id: 'test id'});
153
200
 
154
- const result = await webex.internal.dss.lookupDetail({ id: "test id" });
155
201
  expect(webex.internal.dss._request.getCall(0).args).to.deep.equal([
156
202
  {
157
- dataPath: "lookupResult.entities",
203
+ dataPath: 'lookupResult.entities',
204
+ foundPath: 'lookupResult.entitiesFound',
158
205
  resource: '/lookup/orgid/userOrgId/identity/test id/detail',
159
206
  },
160
207
  ]);
161
- expect(result).to.equal("some return value");
208
+ expect(result).to.equal('some return value');
162
209
  });
163
210
 
164
- it("works correctly", async () => {
165
- await testRequest({
166
- method: "lookupDetail",
167
- dataPath: "lookupResult.entities",
168
- event: "event:directory.lookup",
211
+ it('works correctly', async () => {
212
+ const {requestId, promise} = await testMakeRequest({
213
+ method: 'lookupDetail',
169
214
  resource: '/lookup/orgid/userOrgId/identity/test id/detail',
170
- params: {
171
- id: "test id",
172
- },
215
+ params: {id: 'test id'},
173
216
  bodyParams: {},
174
217
  });
218
+
219
+ mercuryCallbacks['event:directory.lookup'](
220
+ createData(requestId, 0, true, 'lookupResult', {entities: ['data0'], entitiesFound: ['test id']})
221
+ );
222
+ const result = await promise;
223
+
224
+ expect(result).to.deep.equal('data0');
225
+ });
226
+
227
+ it('fails correctly if lookup fails', async () => {
228
+ const {requestId, promise} = await testMakeRequest({
229
+ method: 'lookupDetail',
230
+ resource: '/lookup/orgid/userOrgId/identity/test id/detail',
231
+ params: {id: 'test id'},
232
+ bodyParams: {},
233
+ });
234
+
235
+ mercuryCallbacks['event:directory.lookup'](
236
+ createData(requestId, 0, true, 'lookupResult', {entitiesNotFound: ['test id']})
237
+ );
238
+ const result = await promise;
239
+
240
+ expect(result).to.be.null;
175
241
  });
176
242
  });
177
243
 
178
- describe("#lookup", () => {
179
- it("calls _request correctly", async () => {
180
- webex.internal.device.orgId = "userOrgId";
181
- webex.internal.dss._request = sinon
182
- .stub()
183
- .returns(Promise.resolve("some return value"));
244
+ describe('#lookup', () => {
245
+ it('calls _request correctly', async () => {
246
+ webex.internal.device.orgId = 'userOrgId';
247
+ webex.internal.dss._request = sinon.stub().returns(
248
+ Promise.resolve({
249
+ resultArray: ['some return value'],
250
+ foundArray: ['id1'],
251
+ })
252
+ );
253
+
254
+ const result = await webex.internal.dss.lookup({id: 'id1', shouldBatch: false});
184
255
 
185
- const result = await webex.internal.dss.lookup({ ids: ["id1", "id2"] });
186
256
  expect(webex.internal.dss._request.getCall(0).args).to.deep.equal([
187
257
  {
188
- dataPath: "lookupResult.entities",
258
+ dataPath: 'lookupResult.entities',
259
+ foundPath: 'lookupResult.entitiesFound',
189
260
  resource: '/lookup/orgid/userOrgId/identities',
190
261
  params: {
191
- lookupValues: ["id1", "id2"],
262
+ lookupValues: ['id1'],
192
263
  },
193
264
  },
194
265
  ]);
195
- expect(result).to.equal("some return value");
266
+ expect(result).to.equal('some return value');
196
267
  });
197
268
 
198
- it("calls _request correctly with entityProviderType", async () => {
199
- webex.internal.device.orgId = "userOrgId";
200
- webex.internal.dss._request = sinon
201
- .stub()
202
- .returns(Promise.resolve("some return value"));
269
+ it('calls _request correctly with entityProviderType', async () => {
270
+ webex.internal.device.orgId = 'userOrgId';
271
+ webex.internal.dss._request = sinon.stub().returns(
272
+ Promise.resolve({
273
+ resultArray: ['some return value'],
274
+ foundArray: ['id1'],
275
+ })
276
+ );
277
+
278
+ const result = await webex.internal.dss.lookup({
279
+ id: 'id1',
280
+ entityProviderType: 'CI_USER',
281
+ shouldBatch: false,
282
+ });
203
283
 
204
- const result = await webex.internal.dss.lookup({ ids: ["id1", "id2"], entityProviderType: 'CI_USER' });
205
284
  expect(webex.internal.dss._request.getCall(0).args).to.deep.equal([
206
285
  {
207
- dataPath: "lookupResult.entities",
286
+ dataPath: 'lookupResult.entities',
287
+ foundPath: 'lookupResult.entitiesFound',
208
288
  resource: '/lookup/orgid/userOrgId/entityprovidertype/CI_USER',
209
289
  params: {
210
- lookupValues: ["id1", "id2"],
290
+ lookupValues: ['id1'],
211
291
  },
212
292
  },
213
293
  ]);
214
- expect(result).to.equal("some return value");
294
+ expect(result).to.equal('some return value');
215
295
  });
216
296
 
217
- it("works correctly", async () => {
218
- await testRequest({
219
- method: "lookup",
220
- dataPath: "lookupResult.entities",
221
- event: "event:directory.lookup",
297
+ it('works correctly', async () => {
298
+ const {requestId, promise} = await testMakeRequest({
299
+ method: 'lookup',
222
300
  resource: '/lookup/orgid/userOrgId/identities',
223
- params: {
224
- ids: ["id1", "id2"],
301
+ params: {id: 'id1', shouldBatch: false},
302
+ bodyParams: {lookupValues: ['id1']},
303
+ });
304
+
305
+ mercuryCallbacks['event:directory.lookup'](
306
+ createData(requestId, 0, true, 'lookupResult', {entities: ['data0'], entitiesFound: ['id1']})
307
+ );
308
+ const result = await promise;
309
+
310
+ expect(result).to.deep.equal('data0');
311
+ });
312
+
313
+ it('fails correctly if lookup fails', async () => {
314
+ const {requestId, promise} = await testMakeRequest({
315
+ method: 'lookup',
316
+ resource: '/lookup/orgid/userOrgId/identities',
317
+ params: {id: 'id1', shouldBatch: false},
318
+ bodyParams: {lookupValues: ['id1']},
319
+ });
320
+
321
+ mercuryCallbacks['event:directory.lookup'](
322
+ createData(requestId, 0, true, 'lookupResult', {entitiesNotFound: ['id1']})
323
+ );
324
+ const result = await promise;
325
+
326
+ expect(result).to.be.null;
327
+ });
328
+
329
+ it('calls _batchedLookup correctly', async () => {
330
+ webex.internal.device.orgId = 'userOrgId';
331
+ webex.internal.dss._batchedLookup = sinon.stub().returns(
332
+ Promise.resolve('some return value')
333
+ );
334
+
335
+ const result = await webex.internal.dss.lookup({id: 'id1'});
336
+
337
+ expect(webex.internal.dss._batchedLookup.getCall(0).args).to.deep.equal([
338
+ {
339
+ resource: '/lookup/orgid/userOrgId/identities',
340
+ lookupValue: 'id1',
225
341
  },
226
- bodyParams: {
227
- lookupValues: ["id1", "id2"],
342
+ ]);
343
+ expect(result).to.equal('some return value');
344
+ });
345
+
346
+ it('calls _batchedLookup correctly with entityProviderType', async () => {
347
+ webex.internal.device.orgId = 'userOrgId';
348
+ webex.internal.dss._batchedLookup = sinon.stub().returns(
349
+ Promise.resolve('some return value'),
350
+ );
351
+
352
+ const result = await webex.internal.dss.lookup({
353
+ id: 'id1',
354
+ entityProviderType: 'CI_USER',
355
+ });
356
+
357
+ expect(webex.internal.dss._batchedLookup.getCall(0).args).to.deep.equal([
358
+ {
359
+ resource: '/lookup/orgid/userOrgId/entityprovidertype/CI_USER',
360
+ lookupValue: 'id1',
228
361
  },
362
+ ]);
363
+ expect(result).to.equal('some return value');
364
+ });
365
+
366
+ it('Single batched lookup is made after 50 ms and works', async () => {
367
+ const {promises} = await testMakeBatchedRequests({
368
+ requests: [
369
+ {
370
+ id: 'randomid1',
371
+ resource: '/lookup/orgid/userOrgId/identities',
372
+ bodyParams: {lookupValues: ['id1']},
373
+ }
374
+ ],
375
+ calls: [
376
+ {
377
+ method: 'lookup',
378
+ params: {id: 'id1', shouldBatch: true},
379
+ }
380
+ ],
381
+ });
382
+
383
+ mercuryCallbacks['event:directory.lookup'](
384
+ createData('randomid1', 0, true, 'lookupResult', {entities: ['data0'], entitiesFound: ['id1']})
385
+ );
386
+ const result = await promises[0];
387
+
388
+ expect(result).to.deep.equal('data0');
389
+ });
390
+
391
+ it('Single batched lookup fails correctly if lookup fails', async () => {
392
+ const {promises} = await testMakeBatchedRequests({
393
+ requests: [
394
+ {
395
+ id: 'randomid1',
396
+ resource: '/lookup/orgid/userOrgId/identities',
397
+ bodyParams: {lookupValues: ['id1']},
398
+ }
399
+ ],
400
+ calls: [
401
+ {
402
+ method: 'lookup',
403
+ params: {id: 'id1', shouldBatch: true},
404
+ }
405
+ ],
406
+ });
407
+
408
+ mercuryCallbacks['event:directory.lookup'](
409
+ createData('randomid1', 0, true, 'lookupResult', {entitiesNotFound: ['id1']})
410
+ );
411
+
412
+ const result = await promises[0];
413
+
414
+ expect(result).to.be.null;
415
+ });
416
+
417
+ it('Batch of 2 lookups is made after 50 ms and works', async () => {
418
+ const {promises} = await testMakeBatchedRequests({
419
+ requests: [
420
+ {
421
+ id: 'randomid1',
422
+ resource: '/lookup/orgid/userOrgId/identities',
423
+ bodyParams: {lookupValues: ['id1', 'id2']},
424
+ }
425
+ ],
426
+ calls: [
427
+ {
428
+ method: 'lookup',
429
+ params: {id: 'id1', shouldBatch: true},
430
+ },
431
+ {
432
+ method: 'lookup',
433
+ params: {id: 'id2', shouldBatch: true},
434
+ },
435
+ ],
229
436
  });
437
+
438
+ mercuryCallbacks['event:directory.lookup'](
439
+ createData('randomid1', 0, true, 'lookupResult', {entities: ['data1', 'data2'], entitiesFound: ['id1', 'id2']})
440
+ );
441
+ const result1 = await promises[0];
442
+
443
+ expect(result1).to.equal('data1');
444
+ const result2 = await promises[1];
445
+
446
+ expect(result2).to.equal('data2');
447
+ });
448
+
449
+ it('Batch of 2 lookups is made after 50 ms and one fails correctly', async () => {
450
+ const {promises} = await testMakeBatchedRequests({
451
+ requests: [
452
+ {
453
+ id: 'randomid1',
454
+ resource: '/lookup/orgid/userOrgId/identities',
455
+ bodyParams: {lookupValues: ['id1', 'id2']},
456
+ }
457
+ ],
458
+ calls: [
459
+ {
460
+ method: 'lookup',
461
+ params: {id: 'id1', shouldBatch: true},
462
+ },
463
+ {
464
+ method: 'lookup',
465
+ params: {id: 'id2', shouldBatch: true},
466
+ },
467
+ ],
468
+ });
469
+
470
+ mercuryCallbacks['event:directory.lookup'](
471
+ createData('randomid1', 0, true, 'lookupResult', {entities: ['data2'], entitiesFound: ['id2'], entitiesNotFound: ['id1']})
472
+ );
473
+ const result1 = await promises[0];
474
+
475
+ expect(result1).to.be.null;
476
+
477
+ const result2 = await promises[1];
478
+
479
+ expect(result2).to.equal('data2');
480
+ });
481
+
482
+ it('Two unrelated lookups are made after 50 ms and work', async () => {
483
+ const {promises} = await testMakeBatchedRequests({
484
+ requests: [
485
+ {
486
+ id: 'randomid1',
487
+ resource: '/lookup/orgid/userOrgId/entityprovidertype/CI_USER',
488
+ bodyParams: {lookupValues: ['id1']},
489
+ },
490
+ {
491
+ id: 'randomid2',
492
+ resource: '/lookup/orgid/userOrgId/identities',
493
+ bodyParams: {lookupValues: ['id2']},
494
+ }
495
+ ],
496
+ calls: [
497
+ {
498
+ method: 'lookup',
499
+ params: {id: 'id1', entityProviderType: 'CI_USER', shouldBatch: true},
500
+ },
501
+ {
502
+ method: 'lookup',
503
+ params: {id: 'id2', shouldBatch: true},
504
+ },
505
+ ],
506
+ });
507
+
508
+ mercuryCallbacks['event:directory.lookup'](
509
+ createData('randomid1', 0, true, 'lookupResult', {entities: ['data1'], entitiesFound: ['id1']})
510
+ );
511
+ mercuryCallbacks['event:directory.lookup'](
512
+ createData('randomid2', 0, true, 'lookupResult', {entities: ['data2'], entitiesFound: ['id2']})
513
+ );
514
+ const result1 = await promises[0];
515
+
516
+ expect(result1).to.equal('data1');
517
+ const result2 = await promises[1];
518
+
519
+ expect(result2).to.equal('data2');
520
+ });
521
+
522
+ it('Two unrelated lookups are made after 50 ms and one fails correctly', async () => {
523
+ const {promises} = await testMakeBatchedRequests({
524
+ requests: [
525
+ {
526
+ id: 'randomid1',
527
+ resource: '/lookup/orgid/userOrgId/entityprovidertype/CI_USER',
528
+ bodyParams: {lookupValues: ['id1']},
529
+ },
530
+ {
531
+ id: 'randomid2',
532
+ resource: '/lookup/orgid/userOrgId/identities',
533
+ bodyParams: {lookupValues: ['id2']},
534
+ }
535
+ ],
536
+ calls: [
537
+ {
538
+ method: 'lookup',
539
+ params: {id: 'id1', entityProviderType: 'CI_USER', shouldBatch: true},
540
+ },
541
+ {
542
+ method: 'lookup',
543
+ params: {id: 'id2', shouldBatch: true},
544
+ },
545
+ ],
546
+ });
547
+
548
+ mercuryCallbacks['event:directory.lookup'](
549
+ createData('randomid1', 0, true, 'lookupResult', {entitiesNotFound: ['id1']})
550
+ );
551
+ mercuryCallbacks['event:directory.lookup'](
552
+ createData('randomid2', 0, true, 'lookupResult', {entities: ['data2'], entitiesFound: ['id2']})
553
+ );
554
+ const result1 = await promises[0];
555
+
556
+ expect(result1).to.be.null;
557
+ const result2 = await promises[1];
558
+
559
+ expect(result2).to.equal('data2');
230
560
  });
231
561
  });
232
562
 
233
- describe("#lookupByEmail", () => {
234
- it("calls _request correctly", async () => {
235
- webex.internal.device.orgId = "userOrgId";
236
- webex.internal.dss._request = sinon
237
- .stub()
238
- .returns(Promise.resolve("some return value"));
563
+ describe('#lookupByEmail', () => {
564
+ it('calls _request correctly', async () => {
565
+ webex.internal.device.orgId = 'userOrgId';
566
+ webex.internal.dss._request = sinon.stub().returns(
567
+ Promise.resolve({
568
+ resultArray: ['some return value'],
569
+ foundArray: ['email1'],
570
+ })
571
+ );
239
572
 
240
573
  const result = await webex.internal.dss.lookupByEmail({
241
- emails: ["email1", "email2"],
574
+ email: 'email1',
242
575
  });
576
+
243
577
  expect(webex.internal.dss._request.getCall(0).args).to.deep.equal([
244
578
  {
245
- dataPath: "lookupResult.entities",
579
+ dataPath: 'lookupResult.entities',
580
+ foundPath: 'lookupResult.entitiesFound',
246
581
  resource: '/lookup/orgid/userOrgId/emails',
582
+
247
583
  params: {
248
- lookupValues: ["email1", "email2"],
584
+ lookupValues: ['email1'],
249
585
  },
250
586
  },
251
587
  ]);
252
- expect(result).to.equal("some return value");
588
+ expect(result).to.equal('some return value');
253
589
  });
254
590
 
255
- it("works correctly", async () => {
256
- await testRequest({
257
- method: "lookupByEmail",
258
- dataPath: "lookupResult.entities",
259
- event: "event:directory.lookup",
591
+ it('works correctly', async () => {
592
+ const {requestId, promise} = await testMakeRequest({
593
+ method: 'lookupByEmail',
260
594
  resource: '/lookup/orgid/userOrgId/emails',
261
- params: {
262
- emails: ["email1", "email2"],
263
- },
264
- bodyParams: {
265
- lookupValues: ["email1", "email2"],
266
- },
595
+ params: {email: 'email1'},
596
+ bodyParams: {lookupValues: ['email1']},
267
597
  });
598
+
599
+ mercuryCallbacks['event:directory.lookup'](
600
+ createData(requestId, 0, true, 'lookupResult', {entities: ['data0'], entitiesFound: ['email1']})
601
+ );
602
+ const result = await promise;
603
+
604
+ expect(result).to.deep.equal('data0');
605
+ });
606
+
607
+ it('fails correctly if lookup fails', async () => {
608
+ const {requestId, promise} = await testMakeRequest({
609
+ method: 'lookupByEmail',
610
+ resource: '/lookup/orgid/userOrgId/emails',
611
+ params: {email: 'email1'},
612
+ bodyParams: {lookupValues: ['email1']},
613
+ });
614
+
615
+ mercuryCallbacks['event:directory.lookup'](
616
+ createData(requestId, 0, true, 'lookupResult', {}) // entitiesNotFound isn't returned for email
617
+ );
618
+ const result = await promise;
619
+
620
+ expect(result).to.be.null;
268
621
  });
269
622
  });
270
623
 
271
- describe("#search", () => {
272
- it("calls _request correctly", async () => {
273
- webex.internal.device.orgId = "userOrgId";
624
+ describe('#search', () => {
625
+ it('calls _request correctly', async () => {
626
+ webex.internal.device.orgId = 'userOrgId';
274
627
  webex.internal.dss._request = sinon
275
628
  .stub()
276
- .returns(Promise.resolve("some return value"));
629
+ .returns(Promise.resolve({resultArray: 'some return value'}));
277
630
 
278
631
  const result = await webex.internal.dss.search({
279
- requestedTypes: ["PERSON", "ROBOT"],
632
+ requestedTypes: ['PERSON', 'ROBOT'],
280
633
  resultSize: 100,
281
- queryString: "query",
634
+ queryString: 'query',
282
635
  });
636
+
283
637
  expect(webex.internal.dss._request.getCall(0).args).to.deep.equal([
284
638
  {
285
- dataPath: "directoryEntities",
639
+ dataPath: 'directoryEntities',
286
640
  resource: '/search/orgid/userOrgId/entities',
287
641
  params: {
288
- queryString: "query",
642
+ queryString: 'query',
289
643
  resultSize: 100,
290
- requestedTypes: ["PERSON", "ROBOT"],
644
+ requestedTypes: ['PERSON', 'ROBOT'],
291
645
  },
292
646
  },
293
647
  ]);
294
- expect(result).to.equal("some return value");
648
+ expect(result).to.equal('some return value');
295
649
  });
296
650
 
297
- it("works correctly", async () => {
298
- await testRequest({
299
- method: "search",
300
- event: "event:directory.search",
301
- dataPath: "directoryEntities",
651
+ it('works correctly', async () => {
652
+ const {requestId, promise} = await testMakeRequest({
653
+ method: 'search',
302
654
  resource: '/search/orgid/userOrgId/entities',
303
655
  params: {
304
- requestedTypes: ["PERSON", "ROBOT"],
656
+ requestedTypes: ['PERSON', 'ROBOT'],
305
657
  resultSize: 100,
306
- queryString: "query",
658
+ queryString: 'query',
307
659
  },
308
660
  bodyParams: {
309
- requestedTypes: ["PERSON", "ROBOT"],
661
+ requestedTypes: ['PERSON', 'ROBOT'],
310
662
  resultSize: 100,
311
- queryString: "query",
663
+ queryString: 'query',
312
664
  },
313
665
  });
666
+
667
+ mercuryCallbacks['event:directory.search'](createData(requestId, 1, false, 'directoryEntities', ['data1']));
668
+ mercuryCallbacks['event:directory.search'](createData(requestId, 2, true, 'directoryEntities', ['data2']));
669
+ mercuryCallbacks['event:directory.search'](createData(requestId, 0, false, 'directoryEntities', ['data0']));
670
+ const result = await promise;
671
+
672
+ expect(result).to.deep.equal(['data0', 'data1', 'data2']);
314
673
  });
315
674
  });
316
675
 
317
- describe("#_request", () => {
318
- it("handles a request correctly", async () => {
676
+ describe('#_request', () => {
677
+ it('handles a request correctly', async () => {
319
678
  webex.request = sinon.stub();
320
- uuid.v4.returns("randomid");
679
+ uuid.v4.returns('randomid');
321
680
  const promise = webex.internal.dss._request({
322
- resource: "/search/orgid/userOrgId/entities",
323
- params: { some: "param" },
324
- dataPath: "a.b.c",
681
+ resource: '/search/orgid/userOrgId/entities',
682
+ params: {some: 'param'},
683
+ dataPath: 'a.b.c',
325
684
  });
326
685
 
327
686
  expect(webex.request.getCall(0).args).to.deep.equal([
328
687
  {
329
- service: "directorySearch",
688
+ service: 'directorySearch',
330
689
  body: {
331
- requestId: "randomid",
332
- some: "param",
690
+ requestId: 'randomid',
691
+ some: 'param',
333
692
  },
334
- contentType: "application/json",
335
- method: "POST",
336
- resource: "/search/orgid/userOrgId/entities",
693
+ contentType: 'application/json',
694
+ method: 'POST',
695
+ resource: '/search/orgid/userOrgId/entities',
337
696
  },
338
697
  ]);
339
698
 
340
- webex.internal.dss.trigger(
341
- webex.internal.dss._getResultEventName("randomid"),
342
- {
343
- sequence: 1,
344
- a: {
345
- b: {
346
- c: ["data1"],
347
- },
348
- },
349
- }
350
- );
699
+ webex.internal.dss.trigger(webex.internal.dss._getResultEventName('randomid'), {
700
+ sequence: 1,
701
+ a: {b: {c: ['data1']}},
702
+ });
703
+ webex.internal.dss.trigger(webex.internal.dss._getResultEventName('randomid'), {
704
+ sequence: 2,
705
+ finished: true,
706
+ a: {b: {c: ['data2']}},
707
+ });
708
+ webex.internal.dss.trigger(webex.internal.dss._getResultEventName('randomid'), {
709
+ sequence: 0,
710
+ a: {b: {c: ['data0']}},
711
+ });
351
712
 
352
- webex.internal.dss.trigger(
353
- webex.internal.dss._getResultEventName("randomid"),
713
+ const result = await promise;
714
+
715
+ expect(result).to.deep.equal({
716
+ resultArray: ['data0', 'data1', 'data2'],
717
+ });
718
+ });
719
+
720
+ it('handles a request with foundPath correctly', async () => {
721
+ webex.request = sinon.stub();
722
+ uuid.v4.returns('randomid');
723
+ const promise = webex.internal.dss._request({
724
+ resource: '/search/orgid/userOrgId/entities',
725
+ params: {some: 'param'},
726
+ dataPath: 'a.b.c',
727
+ foundPath: 'someFoundPath'
728
+ });
729
+
730
+ expect(webex.request.getCall(0).args).to.deep.equal([
354
731
  {
355
- sequence: 2,
356
- finished: true,
357
- a: {
358
- b: {
359
- c: ["data2"],
360
- },
732
+ service: 'directorySearch',
733
+ body: {
734
+ requestId: 'randomid',
735
+ some: 'param',
361
736
  },
362
- }
363
- );
737
+ contentType: 'application/json',
738
+ method: 'POST',
739
+ resource: '/search/orgid/userOrgId/entities',
740
+ },
741
+ ]);
364
742
 
365
- webex.internal.dss.trigger(
366
- webex.internal.dss._getResultEventName("randomid"),
743
+ webex.internal.dss.trigger(webex.internal.dss._getResultEventName('randomid'), {
744
+ sequence: 1,
745
+ a: {b: {c: ['data1']}},
746
+ someFoundPath: ['id1'],
747
+ });
748
+ webex.internal.dss.trigger(webex.internal.dss._getResultEventName('randomid'), {
749
+ sequence: 2,
750
+ finished: true,
751
+ a: {b: {c: ['data2']}},
752
+ someFoundPath: ['id2'],
753
+ });
754
+ webex.internal.dss.trigger(webex.internal.dss._getResultEventName('randomid'), {
755
+ sequence: 0,
756
+ a: {b: {c: ['data0']}},
757
+ someFoundPath: ['id0'],
758
+ });
759
+
760
+ const result = await promise;
761
+
762
+ expect(result).to.deep.equal({
763
+ resultArray: ['data0', 'data1', 'data2'],
764
+ foundArray: ['id0', 'id1', 'id2'],
765
+ });
766
+ });
767
+
768
+ it('handles a request with foundPath and notFoundPath correctly', async () => {
769
+ webex.request = sinon.stub();
770
+ uuid.v4.returns('randomid');
771
+ const promise = webex.internal.dss._request({
772
+ resource: '/search/orgid/userOrgId/entities',
773
+ params: {some: 'param'},
774
+ dataPath: 'a.b.c',
775
+ foundPath: 'someFoundPath',
776
+ notFoundPath: 'someNotFoundPath',
777
+ });
778
+
779
+ expect(webex.request.getCall(0).args).to.deep.equal([
367
780
  {
368
- sequence: 0,
369
- a: {
370
- b: {
371
- c: ["data0"],
372
- },
781
+ service: 'directorySearch',
782
+ body: {
783
+ requestId: 'randomid',
784
+ some: 'param',
373
785
  },
374
- }
375
- );
786
+ contentType: 'application/json',
787
+ method: 'POST',
788
+ resource: '/search/orgid/userOrgId/entities',
789
+ },
790
+ ]);
791
+
792
+ webex.internal.dss.trigger(webex.internal.dss._getResultEventName('randomid'), {
793
+ sequence: 1,
794
+ a: {b: {c: ['data1']}},
795
+ someFoundPath: ['id1'],
796
+ });
797
+ webex.internal.dss.trigger(webex.internal.dss._getResultEventName('randomid'), {
798
+ sequence: 2,
799
+ finished: true,
800
+ a: {b: {c: ['data2']}},
801
+ someFoundPath: ['id2'],
802
+ someNotFoundPath: ['id3'],
803
+ });
804
+ webex.internal.dss.trigger(webex.internal.dss._getResultEventName('randomid'), {
805
+ sequence: 0,
806
+ a: {b: {c: ['data0']}},
807
+ someFoundPath: ['id0'],
808
+ });
376
809
 
377
810
  const result = await promise;
378
- expect(result).to.deep.equal(["data0", "data1", "data2"]);
811
+
812
+ expect(result).to.deep.equal({
813
+ resultArray: ['data0', 'data1', 'data2'],
814
+ foundArray: ['id0', 'id1', 'id2'],
815
+ notFoundArray: ['id3'],
816
+ });
817
+ });
818
+ });
819
+
820
+ describe('#_batchedLookup', () => {
821
+ const checkStandardProperties = (batcher) => {
822
+ expect(batcher.dataPath).to.equal('lookupResult.entities');
823
+ expect(batcher.entitiesFoundPath).to.equal('lookupResult.entitiesFound');
824
+ expect(batcher.entitiesNotFoundPath).to.equal('lookupResult.entitiesNotFound');
825
+ expect(batcher.requestKey).to.equal('lookupValues');
826
+ expect(batcher.config).to.deep.equal({
827
+ batcherWait: 50,
828
+ batcherMaxCalls: 50,
829
+ batcherMaxWait: 150
830
+ });
831
+ };
832
+
833
+ it('calls batcher.request on new batcher for first lookup', async () => {
834
+ const resource = '/lookup/orgid/userOrgId/identities';
835
+ const response = 'response1';
836
+
837
+ Batcher.prototype.request = sinon.stub()
838
+ .returns(Promise.resolve(response));
839
+
840
+ expect(webex.internal.dss.batchers).to.deep.equal({});
841
+
842
+ const result = await webex.internal.dss._batchedLookup({
843
+ resource,
844
+ lookupValue: 'id1',
845
+ });
846
+
847
+ const batcher = webex.internal.dss.batchers[resource];
848
+
849
+ expect(batcher).to.exist;
850
+ expect(batcher.resource).to.equal(resource);
851
+ checkStandardProperties(batcher);
852
+
853
+ expect(Batcher.prototype.request.getCall(0).args).to.deep.equal(['id1']);
854
+ expect(result).to.equal(response);
855
+ });
856
+
857
+ it('calls batcher.request on new batcher for lookup with new reource', async () => {
858
+ const resource1 = '/lookup/orgid/userOrgId/identities';
859
+ const resource2 = '/lookup/orgid/userOrgId/entityprovidertype/CI_USER';
860
+ const response1 = 'response1';
861
+ const response2 = 'response2';
862
+
863
+ Batcher.prototype.request = sinon.stub()
864
+ .onFirstCall().returns(Promise.resolve(response1))
865
+ .onSecondCall()
866
+ .returns(Promise.resolve(response2));
867
+
868
+ expect(webex.internal.dss.batchers).to.deep.equal({});
869
+
870
+ await webex.internal.dss._batchedLookup({
871
+ resource: resource1,
872
+ lookupValue: 'id1',
873
+ });
874
+
875
+ const result = await webex.internal.dss._batchedLookup({
876
+ resource: resource2,
877
+ lookupValue: 'id2',
878
+ });
879
+
880
+ expect(webex.internal.dss.batchers[resource1]).to.exist;
881
+ const batcher = webex.internal.dss.batchers[resource2];
882
+
883
+ expect(batcher).to.exist;
884
+ expect(batcher.resource).to.equal(resource2);
885
+ checkStandardProperties(batcher);
886
+
887
+ expect(Batcher.prototype.request.getCall(1).args).to.deep.equal(['id2']);
888
+ expect(result).to.equal(response2);
889
+ });
890
+
891
+ it('calls batcher.request on existing batcher for lookup with existing reource', async () => {
892
+ const resource1 = '/lookup/orgid/userOrgId/identities';
893
+ const response1 = 'response1';
894
+ const response2 = 'response2';
895
+
896
+ Batcher.prototype.request = sinon.stub()
897
+ .onFirstCall().returns(Promise.resolve(response1))
898
+ .onSecondCall()
899
+ .returns(Promise.resolve(response2));
900
+
901
+ expect(webex.internal.dss.batchers).to.deep.equal({});
902
+
903
+ await webex.internal.dss._batchedLookup({
904
+ resource: resource1,
905
+ lookupValue: 'id1',
906
+ });
907
+ expect(webex.internal.dss.batchers[resource1]).to.exist;
908
+ const initialBatcher = webex.internal.dss.batchers[resource1];
909
+
910
+ const result = await webex.internal.dss._batchedLookup({
911
+ resource: resource1,
912
+ lookupValue: 'id2',
913
+ });
914
+
915
+ const batcher = webex.internal.dss.batchers[resource1];
916
+
917
+ expect(batcher).to.equal(initialBatcher);
918
+ expect(batcher.resource).to.equal(resource1);
919
+ checkStandardProperties(batcher);
920
+
921
+ expect(Batcher.prototype.request.getCall(1).args).to.deep.equal(['id2']);
922
+ expect(result).to.equal(response2);
379
923
  });
380
924
  });
381
925
  });