@webex/internal-plugin-device 3.12.0-next.9 → 3.12.0-task-refactor.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/dist/config.js +10 -16
- package/dist/config.js.map +1 -1
- package/dist/constants.js +1 -6
- package/dist/constants.js.map +1 -1
- package/dist/device.js +79 -181
- package/dist/device.js.map +1 -1
- package/dist/ipNetworkDetector.js +3 -3
- package/dist/ipNetworkDetector.js.map +1 -1
- package/package.json +10 -10
- package/src/config.js +9 -16
- package/src/constants.js +0 -5
- package/src/device.js +26 -150
- package/src/ipNetworkDetector.ts +1 -1
- package/test/unit/spec/device.js +46 -641
package/test/unit/spec/device.js
CHANGED
|
@@ -20,19 +20,10 @@ describe('plugin-device', () => {
|
|
|
20
20
|
let device;
|
|
21
21
|
|
|
22
22
|
beforeEach(() => {
|
|
23
|
-
const fakeStorage = {};
|
|
24
23
|
webex = new MockWebex({
|
|
25
24
|
children: {
|
|
26
25
|
device: Device,
|
|
27
26
|
},
|
|
28
|
-
getWindow: () => ({
|
|
29
|
-
sessionStorage: {
|
|
30
|
-
setItem: (key, value) => {
|
|
31
|
-
fakeStorage[key] = value;
|
|
32
|
-
},
|
|
33
|
-
getItem: (key) => fakeStorage[key],
|
|
34
|
-
},
|
|
35
|
-
}),
|
|
36
27
|
});
|
|
37
28
|
|
|
38
29
|
const clonedDTO = cloneDeep(dto);
|
|
@@ -112,54 +103,6 @@ describe('plugin-device', () => {
|
|
|
112
103
|
});
|
|
113
104
|
});
|
|
114
105
|
});
|
|
115
|
-
|
|
116
|
-
describe('when the config is changed', () => {
|
|
117
|
-
it("should unset the 'etag' if debug features are set", () => {
|
|
118
|
-
device.set('etag', 'etag-value');
|
|
119
|
-
device.config.debugFeatureTogglesKey = 'debug-feature-toggles';
|
|
120
|
-
|
|
121
|
-
webex.getWindow().sessionStorage.setItem(
|
|
122
|
-
'debug-feature-toggles',
|
|
123
|
-
JSON.stringify({
|
|
124
|
-
test_feature: true,
|
|
125
|
-
})
|
|
126
|
-
);
|
|
127
|
-
assert.equal(device.etag, 'etag-value');
|
|
128
|
-
|
|
129
|
-
webex.trigger('change:config');
|
|
130
|
-
assert.isUndefined(device.etag);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it("should not unset the 'etag' if debug features are not set", () => {
|
|
134
|
-
device.set('etag', 'etag-value');
|
|
135
|
-
device.config.debugFeatureTogglesKey = 'debug-feature-toggles';
|
|
136
|
-
|
|
137
|
-
assert.equal(device.etag, 'etag-value');
|
|
138
|
-
|
|
139
|
-
webex.trigger('change:config');
|
|
140
|
-
assert.equal(device.etag, 'etag-value');
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it("should only unset the 'etag' the first time the event is sent", () => {
|
|
144
|
-
device.set('etag', 'etag-value');
|
|
145
|
-
device.config.debugFeatureTogglesKey = 'debug-feature-toggles';
|
|
146
|
-
|
|
147
|
-
webex.getWindow().sessionStorage.setItem(
|
|
148
|
-
'debug-feature-toggles',
|
|
149
|
-
JSON.stringify({
|
|
150
|
-
test_feature: true,
|
|
151
|
-
})
|
|
152
|
-
);
|
|
153
|
-
assert.equal(device.etag, 'etag-value');
|
|
154
|
-
|
|
155
|
-
webex.trigger('change:config');
|
|
156
|
-
assert.isUndefined(device.etag);
|
|
157
|
-
|
|
158
|
-
device.set('etag', 'etag-value');
|
|
159
|
-
webex.trigger('change:config');
|
|
160
|
-
assert.equal(device.etag, 'etag-value');
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
106
|
});
|
|
164
107
|
|
|
165
108
|
describe('derived properties', () => {
|
|
@@ -481,34 +424,18 @@ describe('plugin-device', () => {
|
|
|
481
424
|
|
|
482
425
|
assert.calledOnce(device.processRegistrationSuccess);
|
|
483
426
|
});
|
|
427
|
+
|
|
484
428
|
});
|
|
485
429
|
|
|
486
430
|
describe('deleteDevices()', () => {
|
|
487
|
-
let requestStub;
|
|
488
|
-
let clock;
|
|
489
|
-
let waitForLimitStub;
|
|
490
|
-
|
|
491
431
|
const setup = (deviceType) => {
|
|
492
432
|
device.config.defaults = {body: {deviceType}};
|
|
493
433
|
};
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
afterEach(() => {
|
|
500
|
-
sinon.restore();
|
|
501
|
-
if (clock) {
|
|
502
|
-
clock.restore();
|
|
503
|
-
clock = null;
|
|
504
|
-
}
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
['WEB', 'WEBCLIENT'].forEach((deviceType) => {
|
|
508
|
-
it(`should delete correct number of devices for ${deviceType}`, async () => {
|
|
509
|
-
setup(deviceType);
|
|
510
|
-
const response = {
|
|
511
|
-
body: {
|
|
434
|
+
['WEB', 'WEBCLIENT'].forEach(deviceType => {
|
|
435
|
+
it(`should delete correct number of devices for ${deviceType}`, async () => {
|
|
436
|
+
setup(deviceType);
|
|
437
|
+
const response = {
|
|
438
|
+
body: {
|
|
512
439
|
devices: [
|
|
513
440
|
{url: 'url3', modificationTime: '2023-10-03T10:00:00Z', deviceType},
|
|
514
441
|
{url: 'url4', modificationTime: '2023-10-04T10:00:00Z', deviceType: 'notweb'},
|
|
@@ -518,428 +445,49 @@ describe('plugin-device', () => {
|
|
|
518
445
|
{url: 'url6', modificationTime: '2023-09-50T10:00:00Z', deviceType},
|
|
519
446
|
{url: 'url7', modificationTime: '2023-09-30T10:00:00Z', deviceType},
|
|
520
447
|
{url: 'url8', modificationTime: '2023-08-30T10:00:00Z', deviceType},
|
|
521
|
-
]
|
|
522
|
-
|
|
523
|
-
};
|
|
524
|
-
|
|
525
|
-
requestStub = sinon.stub(device, 'request');
|
|
526
|
-
requestStub.withArgs(sinon.match({method: 'GET'})).resolves(response);
|
|
527
|
-
requestStub.withArgs(sinon.match({method: 'DELETE'})).resolves();
|
|
528
|
-
|
|
529
|
-
await device.deleteDevices();
|
|
530
|
-
|
|
531
|
-
const expectedDeletions = ['url8', 'url7', 'url1'];
|
|
532
|
-
|
|
533
|
-
expectedDeletions.forEach((url) => {
|
|
534
|
-
assert(requestStub.calledWith(sinon.match({uri: url, method: 'DELETE'})));
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
const notDeletedUrls = ['url2', 'url3', 'url5', 'url6', 'url4'];
|
|
538
|
-
notDeletedUrls.forEach((url) => {
|
|
539
|
-
assert(requestStub.neverCalledWith(sinon.match({uri: url, method: 'DELETE'})));
|
|
540
|
-
});
|
|
541
|
-
});
|
|
542
|
-
});
|
|
543
|
-
|
|
544
|
-
it('does not delete when there are only 2 devices (below MIN_DEVICES_FOR_CLEANUP)', async () => {
|
|
545
|
-
setup('WEB');
|
|
546
|
-
const response = {
|
|
547
|
-
body: {
|
|
548
|
-
devices: [
|
|
549
|
-
{url: 'url1', modificationTime: '2023-10-01T10:00:00Z', deviceType: 'WEB'},
|
|
550
|
-
{url: 'url2', modificationTime: '2023-10-02T10:00:00Z', deviceType: 'WEB'},
|
|
551
|
-
],
|
|
552
|
-
},
|
|
448
|
+
]
|
|
449
|
+
}
|
|
553
450
|
};
|
|
451
|
+
const requestStub = sinon.stub(device, 'request');
|
|
452
|
+
requestStub.withArgs(sinon.match({method: 'GET'})).resolves(response);
|
|
453
|
+
requestStub.withArgs(sinon.match({method: 'DELETE'})).resolves();
|
|
554
454
|
|
|
555
|
-
|
|
556
|
-
requestStub.withArgs(sinon.match({method: 'GET'})).resolves(response);
|
|
557
|
-
requestStub.withArgs(sinon.match({method: 'DELETE'})).resolves();
|
|
558
|
-
|
|
559
|
-
await device.deleteDevices();
|
|
560
|
-
// MIN_DEVICES_FOR_CLEANUP = 5; 2 devices is below the threshold, so nothing should be deleted
|
|
561
|
-
assert(requestStub.neverCalledWith(sinon.match({method: 'DELETE'})));
|
|
562
|
-
});
|
|
563
|
-
|
|
564
|
-
it('does not delete when device count equals MIN_DEVICES_FOR_CLEANUP (5 devices)', async () => {
|
|
565
|
-
setup('WEB');
|
|
566
|
-
const devices = Array.from({length: 5}, (_, i) => ({
|
|
567
|
-
url: `url${i}`,
|
|
568
|
-
modificationTime: `2023-10-0${i + 1}T10:00:00Z`,
|
|
569
|
-
deviceType: 'WEB',
|
|
570
|
-
}));
|
|
571
|
-
|
|
572
|
-
requestStub = sinon.stub(device, 'request');
|
|
573
|
-
requestStub.withArgs(sinon.match({method: 'GET'})).resolves({body: {devices}});
|
|
574
|
-
requestStub.withArgs(sinon.match({method: 'DELETE'})).resolves();
|
|
575
|
-
|
|
576
|
-
await device.deleteDevices();
|
|
577
|
-
// MIN_DEVICES_FOR_CLEANUP = 5; exactly at the threshold means no deletion
|
|
578
|
-
assert(requestStub.neverCalledWith(sinon.match({method: 'DELETE'})));
|
|
579
|
-
});
|
|
455
|
+
await device.deleteDevices();
|
|
580
456
|
|
|
581
|
-
|
|
582
|
-
setup('WEB');
|
|
583
|
-
const devices = Array.from({length: 6}, (_, i) => ({
|
|
584
|
-
url: `url${i}`,
|
|
585
|
-
modificationTime: `2023-10-0${i}T10:00:00Z`,
|
|
586
|
-
deviceType: 'WEB',
|
|
587
|
-
}));
|
|
588
|
-
|
|
589
|
-
requestStub = sinon.stub(device, 'request');
|
|
590
|
-
requestStub.withArgs(sinon.match({method: 'GET'})).resolves({body: {devices}});
|
|
591
|
-
|
|
592
|
-
const deleteOrder = [];
|
|
593
|
-
requestStub.withArgs(sinon.match({method: 'DELETE'})).callsFake((opts) => {
|
|
594
|
-
deleteOrder.push(opts.uri);
|
|
595
|
-
return Promise.resolve();
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
await device.deleteDevices();
|
|
457
|
+
const expectedDeletions = ['url8', 'url7', 'url1'];
|
|
599
458
|
|
|
600
|
-
|
|
601
|
-
|
|
459
|
+
expectedDeletions.forEach(url => {
|
|
460
|
+
assert(requestStub.calledWith(sinon.match({uri: url, method: 'DELETE'})));
|
|
602
461
|
});
|
|
603
462
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
requestStub.withArgs(sinon.match({method: 'GET'})).resolves({body: {devices: []}});
|
|
608
|
-
requestStub.withArgs(sinon.match({method: 'DELETE'})).resolves();
|
|
609
|
-
|
|
610
|
-
await device.deleteDevices();
|
|
611
|
-
|
|
612
|
-
assert(requestStub.neverCalledWith(sinon.match({method: 'DELETE'})));
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
it('only deletes devices matching the current device type', async () => {
|
|
616
|
-
setup('WEB');
|
|
617
|
-
const devices = [
|
|
618
|
-
{url: 'web1', modificationTime: '2023-10-01T10:00:00Z', deviceType: 'WEB'},
|
|
619
|
-
{url: 'web2', modificationTime: '2023-10-02T10:00:00Z', deviceType: 'WEB'},
|
|
620
|
-
{url: 'web3', modificationTime: '2023-10-03T10:00:00Z', deviceType: 'WEB'},
|
|
621
|
-
{url: 'web4', modificationTime: '2023-10-04T10:00:00Z', deviceType: 'WEB'},
|
|
622
|
-
{url: 'web5', modificationTime: '2023-10-05T10:00:00Z', deviceType: 'WEB'},
|
|
623
|
-
{url: 'web6', modificationTime: '2023-10-06T10:00:00Z', deviceType: 'WEB'},
|
|
624
|
-
{url: 'desktop1', modificationTime: '2023-10-01T10:00:00Z', deviceType: 'DESKTOP'},
|
|
625
|
-
{url: 'mobile1', modificationTime: '2023-10-01T10:00:00Z', deviceType: 'MOBILE'},
|
|
626
|
-
];
|
|
627
|
-
|
|
628
|
-
requestStub = sinon.stub(device, 'request');
|
|
629
|
-
requestStub.withArgs(sinon.match({method: 'GET'})).resolves({body: {devices}});
|
|
630
|
-
requestStub.withArgs(sinon.match({method: 'DELETE'})).resolves();
|
|
631
|
-
|
|
632
|
-
await device.deleteDevices();
|
|
633
|
-
|
|
634
|
-
// Only WEB devices considered: 6 total (> MIN_DEVICES_FOR_CLEANUP=5), ceil(6/3)=2 deleted (oldest: web1, web2)
|
|
635
|
-
assert(requestStub.calledWith(sinon.match({uri: 'web1', method: 'DELETE'})));
|
|
636
|
-
assert(requestStub.calledWith(sinon.match({uri: 'web2', method: 'DELETE'})));
|
|
637
|
-
assert(requestStub.neverCalledWith(sinon.match({uri: 'desktop1', method: 'DELETE'})));
|
|
638
|
-
assert(requestStub.neverCalledWith(sinon.match({uri: 'mobile1', method: 'DELETE'})));
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
it('rejects when fetching devices fails', async () => {
|
|
642
|
-
setup('WEB');
|
|
643
|
-
requestStub = sinon.stub(device, 'request');
|
|
644
|
-
requestStub.withArgs(sinon.match({method: 'GET'})).rejects(new Error('network error'));
|
|
645
|
-
|
|
646
|
-
await assert.isRejected(device.deleteDevices(), 'network error');
|
|
647
|
-
});
|
|
648
|
-
|
|
649
|
-
it('resolves when all deletion requests fail (best-effort)', async () => {
|
|
650
|
-
setup('WEB');
|
|
651
|
-
// Use 6 devices (> MIN_DEVICES_FOR_CLEANUP=5) to ensure deletion is attempted
|
|
652
|
-
const devices = [
|
|
653
|
-
{url: 'url1', modificationTime: '2023-10-01T10:00:00Z', deviceType: 'WEB'},
|
|
654
|
-
{url: 'url2', modificationTime: '2023-10-02T10:00:00Z', deviceType: 'WEB'},
|
|
655
|
-
{url: 'url3', modificationTime: '2023-10-03T10:00:00Z', deviceType: 'WEB'},
|
|
656
|
-
{url: 'url4', modificationTime: '2023-10-04T10:00:00Z', deviceType: 'WEB'},
|
|
657
|
-
{url: 'url5', modificationTime: '2023-10-05T10:00:00Z', deviceType: 'WEB'},
|
|
658
|
-
{url: 'url6', modificationTime: '2023-10-06T10:00:00Z', deviceType: 'WEB'},
|
|
659
|
-
];
|
|
660
|
-
|
|
661
|
-
requestStub = sinon.stub(device, 'request');
|
|
662
|
-
requestStub.withArgs(sinon.match({method: 'GET'})).resolves({body: {devices}});
|
|
663
|
-
requestStub.withArgs(sinon.match({method: 'DELETE'})).rejects(new Error('delete failed'));
|
|
664
|
-
|
|
665
|
-
// Should resolve despite DELETE failures — best-effort cleanup must not block registration retry
|
|
666
|
-
await device.deleteDevices();
|
|
667
|
-
assert.calledWith(device.logger.warn, sinon.match(/deletions failed/));
|
|
668
|
-
});
|
|
669
|
-
|
|
670
|
-
it('resolves when only some deletion requests fail (partial failure)', async () => {
|
|
671
|
-
setup('WEB');
|
|
672
|
-
const devices = [
|
|
673
|
-
{url: 'url1', modificationTime: '2023-10-01T10:00:00Z', deviceType: 'WEB'},
|
|
674
|
-
{url: 'url2', modificationTime: '2023-10-02T10:00:00Z', deviceType: 'WEB'},
|
|
675
|
-
{url: 'url3', modificationTime: '2023-10-03T10:00:00Z', deviceType: 'WEB'},
|
|
676
|
-
{url: 'url4', modificationTime: '2023-10-04T10:00:00Z', deviceType: 'WEB'},
|
|
677
|
-
{url: 'url5', modificationTime: '2023-10-05T10:00:00Z', deviceType: 'WEB'},
|
|
678
|
-
{url: 'url6', modificationTime: '2023-10-06T10:00:00Z', deviceType: 'WEB'},
|
|
679
|
-
];
|
|
680
|
-
|
|
681
|
-
requestStub = sinon.stub(device, 'request');
|
|
682
|
-
requestStub.withArgs(sinon.match({method: 'GET'})).resolves({body: {devices}});
|
|
683
|
-
// ceil(6/3) = 2 deletions; first succeeds, second fails
|
|
684
|
-
requestStub
|
|
685
|
-
.withArgs(sinon.match({method: 'DELETE'}))
|
|
686
|
-
.onFirstCall()
|
|
687
|
-
.resolves()
|
|
688
|
-
.onSecondCall()
|
|
689
|
-
.rejects(new Error('404 not found'));
|
|
690
|
-
|
|
691
|
-
await device.deleteDevices();
|
|
692
|
-
assert.calledWith(device.logger.warn, sinon.match(/deletions failed/));
|
|
693
|
-
});
|
|
694
|
-
|
|
695
|
-
it('calls _waitForDeviceCountBelowLimit with targetCount equal to preCount minus min(5, deletedCount)', async () => {
|
|
696
|
-
setup('WEB');
|
|
697
|
-
const devices = Array.from({length: 20}, (_, i) => ({
|
|
698
|
-
url: `url${i}`,
|
|
699
|
-
modificationTime: `2023-10-${String(i + 1).padStart(2, '0')}T10:00:00Z`,
|
|
700
|
-
deviceType: 'WEB',
|
|
701
|
-
}));
|
|
702
|
-
|
|
703
|
-
requestStub = sinon.stub(device, 'request');
|
|
704
|
-
requestStub.withArgs(sinon.match({method: 'GET'})).resolves({body: {devices}});
|
|
705
|
-
requestStub.withArgs(sinon.match({method: 'DELETE'})).resolves();
|
|
706
|
-
|
|
707
|
-
await device.deleteDevices();
|
|
708
|
-
|
|
709
|
-
// 20 WEB devices, ceil(20/3) = 7 deletions (>= 5), targetCount = 20 - min(5, 7) = 15
|
|
710
|
-
assert.calledWith(waitForLimitStub, 15, 0);
|
|
711
|
-
});
|
|
712
|
-
|
|
713
|
-
it('small-n: 6-device case — targetCount is reachable (ceil(6/3)=2 < 5, so wait for 6-2=4)', async () => {
|
|
714
|
-
setup('WEB');
|
|
715
|
-
const devices = Array.from({length: 6}, (_, i) => ({
|
|
716
|
-
url: `url${i}`,
|
|
717
|
-
modificationTime: `2023-10-0${i + 1}T10:00:00Z`,
|
|
718
|
-
deviceType: 'WEB',
|
|
719
|
-
}));
|
|
720
|
-
|
|
721
|
-
requestStub = sinon.stub(device, 'request');
|
|
722
|
-
requestStub.withArgs(sinon.match({method: 'GET'})).resolves({body: {devices}});
|
|
723
|
-
requestStub.withArgs(sinon.match({method: 'DELETE'})).resolves();
|
|
724
|
-
|
|
725
|
-
await device.deleteDevices();
|
|
726
|
-
|
|
727
|
-
// ceil(6/3) = 2 deletions (< 5), targetCount = 6 - min(5, 2) = 4
|
|
728
|
-
// With the old n-5 formula this was 1, which is unreachable and burned all 5 polls
|
|
729
|
-
assert.equal(requestStub.withArgs(sinon.match({method: 'DELETE'})).callCount, 2);
|
|
730
|
-
assert.calledWith(waitForLimitStub, 4, 0);
|
|
731
|
-
});
|
|
732
|
-
|
|
733
|
-
it('regression: 144-device case — deleteDevices passes targetCount=139 (144 - min(5, ceil(144/3)))', async () => {
|
|
734
|
-
setup('WEB');
|
|
735
|
-
const devices = Array.from({length: 144}, (_, i) => ({
|
|
736
|
-
url: `url${i}`,
|
|
737
|
-
modificationTime: new Date(Date.UTC(2020, 0, 1, 0, i)).toISOString(),
|
|
738
|
-
deviceType: 'WEB',
|
|
739
|
-
}));
|
|
740
|
-
|
|
741
|
-
requestStub = sinon.stub(device, 'request');
|
|
742
|
-
requestStub.withArgs(sinon.match({method: 'GET'})).resolves({body: {devices}});
|
|
743
|
-
requestStub.withArgs(sinon.match({method: 'DELETE'})).resolves();
|
|
744
|
-
|
|
745
|
-
await device.deleteDevices();
|
|
746
|
-
|
|
747
|
-
// ceil(144/3) = 48 deletions (>= 5), targetCount = 144 - min(5, 48) = 139
|
|
748
|
-
assert.equal(requestStub.withArgs(sinon.match({method: 'DELETE'})).callCount, 48);
|
|
749
|
-
assert.calledWith(waitForLimitStub, 139, 0);
|
|
750
|
-
});
|
|
751
|
-
});
|
|
752
|
-
|
|
753
|
-
describe('_waitForDeviceCountBelowLimit()', () => {
|
|
754
|
-
let clock;
|
|
755
|
-
|
|
756
|
-
const setup = (deviceType) => {
|
|
757
|
-
device.config.defaults = {body: {deviceType}};
|
|
758
|
-
};
|
|
759
|
-
|
|
760
|
-
beforeEach(() => {
|
|
761
|
-
clock = sinon.useFakeTimers();
|
|
762
|
-
});
|
|
763
|
-
|
|
764
|
-
afterEach(() => {
|
|
765
|
-
sinon.restore();
|
|
766
|
-
clock.restore();
|
|
767
|
-
});
|
|
768
|
-
|
|
769
|
-
it('resolves immediately when device count is below the limit on first check', async () => {
|
|
770
|
-
setup('WEB');
|
|
771
|
-
const devices = Array.from({length: 50}, (_, i) => ({
|
|
772
|
-
url: `url${i}`,
|
|
773
|
-
modificationTime: `2023-10-01T10:00:00Z`,
|
|
774
|
-
deviceType: 'WEB',
|
|
775
|
-
}));
|
|
776
|
-
|
|
777
|
-
sinon.stub(device, 'request')
|
|
778
|
-
.withArgs(sinon.match({method: 'GET'}))
|
|
779
|
-
.resolves({body: {devices}});
|
|
780
|
-
|
|
781
|
-
const promise = device._waitForDeviceCountBelowLimit(55, 0);
|
|
782
|
-
await clock.tickAsync(3000);
|
|
783
|
-
await promise;
|
|
784
|
-
});
|
|
785
|
-
|
|
786
|
-
it('polls multiple times until device count drops below the limit', async () => {
|
|
787
|
-
setup('WEB');
|
|
788
|
-
const makeDevices = (count) =>
|
|
789
|
-
Array.from({length: count}, (_, i) => ({
|
|
790
|
-
url: `url${i}`,
|
|
791
|
-
modificationTime: `2023-10-01T10:00:00Z`,
|
|
792
|
-
deviceType: 'WEB',
|
|
793
|
-
}));
|
|
794
|
-
|
|
795
|
-
const requestStub = sinon.stub(device, 'request');
|
|
796
|
-
requestStub.withArgs(sinon.match({method: 'GET'}))
|
|
797
|
-
.onFirstCall().resolves({body: {devices: makeDevices(102)}})
|
|
798
|
-
.onSecondCall().resolves({body: {devices: makeDevices(100)}})
|
|
799
|
-
.onThirdCall().resolves({body: {devices: makeDevices(68)}});
|
|
800
|
-
|
|
801
|
-
const promise = device._waitForDeviceCountBelowLimit(95, 0);
|
|
802
|
-
|
|
803
|
-
// First poll: 102 devices (above target 95), continue polling
|
|
804
|
-
await clock.tickAsync(3000);
|
|
805
|
-
// Second poll: 100 devices (still above target 95), continue polling
|
|
806
|
-
await clock.tickAsync(3000);
|
|
807
|
-
// Third poll: 68 devices (below target 95), resolve
|
|
808
|
-
await clock.tickAsync(3000);
|
|
809
|
-
|
|
810
|
-
await promise;
|
|
811
|
-
|
|
812
|
-
assert.equal(requestStub.withArgs(sinon.match({method: 'GET'})).callCount, 3);
|
|
463
|
+
const notDeletedUrls = ['url2', 'url3', 'url5', 'url6', 'url4'];
|
|
464
|
+
notDeletedUrls.forEach(url => {
|
|
465
|
+
assert(requestStub.neverCalledWith(sinon.match({uri: url, method: 'DELETE'})));
|
|
813
466
|
});
|
|
467
|
+
});});
|
|
814
468
|
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
modificationTime:
|
|
821
|
-
deviceType: 'WEB',
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
const requestStub = sinon.stub(device, 'request');
|
|
825
|
-
requestStub.withArgs(sinon.match({method: 'GET'}))
|
|
826
|
-
.resolves({body: {devices: makeDevices(105)}});
|
|
827
|
-
|
|
828
|
-
const promise = device._waitForDeviceCountBelowLimit(100, 0);
|
|
829
|
-
|
|
830
|
-
// Tick through all 5 attempts (5 * 3000ms)
|
|
831
|
-
for (let i = 0; i < 5; i += 1) {
|
|
832
|
-
await clock.tickAsync(3000);
|
|
469
|
+
it('does not delete when there are just 2 devices', async () => {
|
|
470
|
+
setup('WEB');
|
|
471
|
+
const response = {
|
|
472
|
+
body: {
|
|
473
|
+
devices: [
|
|
474
|
+
{url: 'url1', modificationTime: '2023-10-01T10:00:00Z', deviceType: 'WEB'},
|
|
475
|
+
{url: 'url2', modificationTime: '2023-10-02T10:00:00Z', deviceType: 'WEB'},
|
|
476
|
+
]
|
|
833
477
|
}
|
|
834
|
-
|
|
835
|
-
await promise;
|
|
836
|
-
|
|
837
|
-
assert(device.logger.warn.calledWith('device: max confirmation attempts reached, proceeding anyway'));
|
|
838
|
-
assert.equal(requestStub.withArgs(sinon.match({method: 'GET'})).callCount, 5);
|
|
839
|
-
});
|
|
840
|
-
|
|
841
|
-
it('resolves when count equals exactly 95 (5 below limit)', async () => {
|
|
842
|
-
setup('WEB');
|
|
843
|
-
const devices = Array.from({length: 95}, (_, i) => ({
|
|
844
|
-
url: `url${i}`,
|
|
845
|
-
modificationTime: `2023-10-01T10:00:00Z`,
|
|
846
|
-
deviceType: 'WEB',
|
|
847
|
-
}));
|
|
848
|
-
|
|
849
|
-
sinon.stub(device, 'request')
|
|
850
|
-
.withArgs(sinon.match({method: 'GET'}))
|
|
851
|
-
.resolves({body: {devices}});
|
|
852
|
-
|
|
853
|
-
const promise = device._waitForDeviceCountBelowLimit(95, 0);
|
|
854
|
-
await clock.tickAsync(3000);
|
|
855
|
-
await promise;
|
|
856
|
-
});
|
|
857
|
-
|
|
858
|
-
it('keeps polling when count is above the 5-below-limit threshold', async () => {
|
|
859
|
-
setup('WEB');
|
|
860
|
-
const makeDevices = (count) =>
|
|
861
|
-
Array.from({length: count}, (_, i) => ({
|
|
862
|
-
url: `url${i}`,
|
|
863
|
-
modificationTime: `2023-10-01T10:00:00Z`,
|
|
864
|
-
deviceType: 'WEB',
|
|
865
|
-
}));
|
|
866
|
-
|
|
867
|
-
const requestStub = sinon.stub(device, 'request');
|
|
868
|
-
requestStub.withArgs(sinon.match({method: 'GET'}))
|
|
869
|
-
.onFirstCall().resolves({body: {devices: makeDevices(100)}})
|
|
870
|
-
.onSecondCall().resolves({body: {devices: makeDevices(99)}})
|
|
871
|
-
.onThirdCall().resolves({body: {devices: makeDevices(95)}});
|
|
872
|
-
|
|
873
|
-
const promise = device._waitForDeviceCountBelowLimit(95, 0);
|
|
874
|
-
// First poll: 100 devices (still over the 95 threshold), continue polling
|
|
875
|
-
await clock.tickAsync(3000);
|
|
876
|
-
// Second poll: 99 devices (still over the 95 threshold), continue polling
|
|
877
|
-
await clock.tickAsync(3000);
|
|
878
|
-
// Third poll: 95 devices (at the safe threshold), resolve
|
|
879
|
-
await clock.tickAsync(3000);
|
|
880
|
-
await promise;
|
|
881
|
-
|
|
882
|
-
assert.equal(requestStub.withArgs(sinon.match({method: 'GET'})).callCount, 3);
|
|
883
|
-
});
|
|
884
|
-
|
|
885
|
-
it('resolves (best-effort) when the polling GET throws a transient error', async () => {
|
|
886
|
-
setup('WEB');
|
|
887
|
-
|
|
888
|
-
sinon.stub(device, 'request')
|
|
889
|
-
.withArgs(sinon.match({method: 'GET'}))
|
|
890
|
-
.rejects(new Error('transient network error'));
|
|
891
|
-
|
|
892
|
-
const promise = device._waitForDeviceCountBelowLimit(95, 0);
|
|
893
|
-
await clock.tickAsync(3000);
|
|
894
|
-
await promise;
|
|
895
|
-
|
|
896
|
-
assert(device.logger.warn.calledWith(
|
|
897
|
-
sinon.match('device: confirmation check 1 failed, proceeding anyway:')
|
|
898
|
-
));
|
|
899
|
-
});
|
|
900
|
-
});
|
|
901
|
-
|
|
902
|
-
describe('_getDevicesOfCurrentType()', () => {
|
|
903
|
-
const setup = (deviceType) => {
|
|
904
|
-
device.config.defaults = {body: {deviceType}};
|
|
905
478
|
};
|
|
906
479
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
});
|
|
910
|
-
|
|
911
|
-
it('filters devices by the current device type', async () => {
|
|
912
|
-
setup('WEB');
|
|
913
|
-
const allDevices = [
|
|
914
|
-
{url: 'web1', deviceType: 'WEB'},
|
|
915
|
-
{url: 'desktop1', deviceType: 'DESKTOP'},
|
|
916
|
-
{url: 'web2', deviceType: 'WEB'},
|
|
917
|
-
{url: 'mobile1', deviceType: 'MOBILE'},
|
|
918
|
-
];
|
|
919
|
-
|
|
920
|
-
sinon.stub(device, 'request').resolves({body: {devices: allDevices}});
|
|
921
|
-
|
|
922
|
-
const result = await device._getDevicesOfCurrentType();
|
|
923
|
-
|
|
924
|
-
assert.equal(result.length, 2);
|
|
925
|
-
assert.equal(result[0].url, 'web1');
|
|
926
|
-
assert.equal(result[1].url, 'web2');
|
|
927
|
-
});
|
|
480
|
+
const requestStub = sinon.stub(device, 'request');
|
|
481
|
+
requestStub.withArgs(sinon.match({method: 'GET'})).resolves(response);
|
|
482
|
+
requestStub.withArgs(sinon.match({method: 'DELETE'})).resolves();
|
|
928
483
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
{
|
|
933
|
-
{url: 'mobile1', deviceType: 'MOBILE'},
|
|
934
|
-
];
|
|
935
|
-
|
|
936
|
-
sinon.stub(device, 'request').resolves({body: {devices: allDevices}});
|
|
937
|
-
|
|
938
|
-
const result = await device._getDevicesOfCurrentType();
|
|
939
|
-
|
|
940
|
-
assert.equal(result.length, 0);
|
|
484
|
+
await device.deleteDevices();
|
|
485
|
+
const notDeletedUrls = ['url1', 'url2'];
|
|
486
|
+
notDeletedUrls.forEach(url => {
|
|
487
|
+
assert(requestStub.neverCalledWith(sinon.match({uri: url, method: 'DELETE'})));
|
|
941
488
|
});
|
|
942
489
|
});
|
|
490
|
+
});
|
|
943
491
|
|
|
944
492
|
describe('#unregister()', () => {
|
|
945
493
|
it('resolves immediately if the device is not registered', async () => {
|
|
@@ -1015,17 +563,11 @@ describe('plugin-device', () => {
|
|
|
1015
563
|
it('calls delete devices when errors with User has excessive device registrations', async () => {
|
|
1016
564
|
setup();
|
|
1017
565
|
sinon.stub(device, 'canRegister').callsFake(() => Promise.resolve());
|
|
1018
|
-
const deleteDeviceSpy = sinon
|
|
1019
|
-
.stub(device, 'deleteDevices')
|
|
1020
|
-
.callsFake(() => Promise.resolve());
|
|
566
|
+
const deleteDeviceSpy = sinon.stub(device, 'deleteDevices').callsFake(() => Promise.resolve());
|
|
1021
567
|
const registerStub = sinon.stub(device, '_registerInternal');
|
|
1022
|
-
|
|
1023
|
-
registerStub
|
|
1024
|
-
|
|
1025
|
-
.rejects({body: {message: 'User has excessive device registrations'}});
|
|
1026
|
-
registerStub
|
|
1027
|
-
.onSecondCall()
|
|
1028
|
-
.callsFake(() => Promise.resolve({exampleKey: 'example response value'}));
|
|
568
|
+
|
|
569
|
+
registerStub.onFirstCall().rejects({body: {message: 'User has excessive device registrations'}});
|
|
570
|
+
registerStub.onSecondCall().callsFake(() => Promise.resolve({exampleKey: 'example response value',}));
|
|
1029
571
|
|
|
1030
572
|
const result = await device.register();
|
|
1031
573
|
|
|
@@ -1040,12 +582,8 @@ describe('plugin-device', () => {
|
|
|
1040
582
|
setup();
|
|
1041
583
|
|
|
1042
584
|
sinon.stub(device, 'canRegister').callsFake(() => Promise.resolve());
|
|
1043
|
-
const deleteDeviceSpy = sinon
|
|
1044
|
-
|
|
1045
|
-
.callsFake(() => Promise.resolve());
|
|
1046
|
-
const registerStub = sinon
|
|
1047
|
-
.stub(device, '_registerInternal')
|
|
1048
|
-
.rejects(new Error('some error'));
|
|
585
|
+
const deleteDeviceSpy = sinon.stub(device, 'deleteDevices').callsFake(() => Promise.resolve());
|
|
586
|
+
const registerStub = sinon.stub(device, '_registerInternal').rejects(new Error('some error'));
|
|
1049
587
|
|
|
1050
588
|
try {
|
|
1051
589
|
await device.register({deleteFlag: true});
|
|
@@ -1095,7 +633,7 @@ describe('plugin-device', () => {
|
|
|
1095
633
|
resolve({
|
|
1096
634
|
body: {
|
|
1097
635
|
exampleKey: 'example response value',
|
|
1098
|
-
}
|
|
636
|
+
}
|
|
1099
637
|
});
|
|
1100
638
|
|
|
1101
639
|
await resultPromise;
|
|
@@ -1132,6 +670,7 @@ describe('plugin-device', () => {
|
|
|
1132
670
|
assert.calledOnce(device.processRegistrationSuccess);
|
|
1133
671
|
});
|
|
1134
672
|
|
|
673
|
+
|
|
1135
674
|
it('checks that submitInternalEvent gets called with internal.register.device.response on success', async () => {
|
|
1136
675
|
setup();
|
|
1137
676
|
sinon.stub(device, 'canRegister').callsFake(() => Promise.resolve());
|
|
@@ -1283,7 +822,7 @@ describe('plugin-device', () => {
|
|
|
1283
822
|
|
|
1284
823
|
it('works when request returns 404 when already registered', async () => {
|
|
1285
824
|
setup();
|
|
1286
|
-
|
|
825
|
+
|
|
1287
826
|
sinon.stub(device, 'canRegister').callsFake(() => Promise.resolve());
|
|
1288
827
|
|
|
1289
828
|
const requestStub = sinon.stub(device, 'request');
|
|
@@ -1299,52 +838,7 @@ describe('plugin-device', () => {
|
|
|
1299
838
|
});
|
|
1300
839
|
});
|
|
1301
840
|
|
|
1302
|
-
describe('getDebugFeatures()', () => {
|
|
1303
|
-
it('returns empty list if debugFeatureTogglesKey is not set', () => {
|
|
1304
|
-
assert.isUndefined(device.config.debugFeatureTogglesKey);
|
|
1305
|
-
const debugFeatures = device.getDebugFeatures();
|
|
1306
|
-
|
|
1307
|
-
assert.deepEqual(debugFeatures, []);
|
|
1308
|
-
});
|
|
1309
|
-
|
|
1310
|
-
it('returns empty list if no debug features in session storage', () => {
|
|
1311
|
-
device.config.debugFeatureTogglesKey = 'debug-feature-toggles';
|
|
1312
|
-
assert.isUndefined(webex.getWindow().sessionStorage.getItem('debug-feature-toggles'));
|
|
1313
|
-
const debugFeatures = device.getDebugFeatures();
|
|
1314
|
-
|
|
1315
|
-
assert.deepEqual(debugFeatures, []);
|
|
1316
|
-
});
|
|
1317
|
-
|
|
1318
|
-
it('returns debug features from session storage', () => {
|
|
1319
|
-
device.config.debugFeatureTogglesKey = 'debug-feature-toggles';
|
|
1320
|
-
webex.getWindow().sessionStorage.setItem(
|
|
1321
|
-
'debug-feature-toggles',
|
|
1322
|
-
JSON.stringify({
|
|
1323
|
-
feature_to_debug_enable: true,
|
|
1324
|
-
feature_to_debug_disable: false,
|
|
1325
|
-
})
|
|
1326
|
-
);
|
|
1327
|
-
const debugFeatures = device.getDebugFeatures();
|
|
1328
|
-
|
|
1329
|
-
assert.equal(debugFeatures.length, 2);
|
|
1330
|
-
|
|
1331
|
-
assert.properties(debugFeatures[0], ['key', 'val', 'mutable', 'lastModified']);
|
|
1332
|
-
assert.equal(debugFeatures[0].key, 'feature_to_debug_enable');
|
|
1333
|
-
assert.equal(debugFeatures[0].val, 'true');
|
|
1334
|
-
assert.isTrue(debugFeatures[0].mutable);
|
|
1335
|
-
assert.isISODate(debugFeatures[0].lastModified);
|
|
1336
|
-
|
|
1337
|
-
assert.properties(debugFeatures[1], ['key', 'val', 'mutable', 'lastModified']);
|
|
1338
|
-
assert.equal(debugFeatures[1].key, 'feature_to_debug_disable');
|
|
1339
|
-
assert.equal(debugFeatures[1].val, 'false');
|
|
1340
|
-
assert.isTrue(debugFeatures[1].mutable);
|
|
1341
|
-
assert.isISODate(debugFeatures[1].lastModified);
|
|
1342
|
-
});
|
|
1343
|
-
});
|
|
1344
|
-
|
|
1345
841
|
describe('#processRegistrationSuccess()', () => {
|
|
1346
|
-
const initialDTOFeatureCounts = {developer: 2, entitlement: 1, user: 1};
|
|
1347
|
-
|
|
1348
842
|
const getClonedDTO = (overrides) => {
|
|
1349
843
|
const clonedDTO = cloneDeep(dto);
|
|
1350
844
|
|
|
@@ -1358,22 +852,6 @@ describe('plugin-device', () => {
|
|
|
1358
852
|
mutable: true,
|
|
1359
853
|
lastModified: '2015-06-29T20:02:48.033Z',
|
|
1360
854
|
},
|
|
1361
|
-
{
|
|
1362
|
-
key: 'feature_to_debug_enable',
|
|
1363
|
-
type: 'boolean',
|
|
1364
|
-
val: 'false',
|
|
1365
|
-
value: false,
|
|
1366
|
-
mutable: true,
|
|
1367
|
-
lastModified: '2015-06-29T20:02:48.033Z',
|
|
1368
|
-
},
|
|
1369
|
-
{
|
|
1370
|
-
key: 'feature_to_debug_disable',
|
|
1371
|
-
type: 'boolean',
|
|
1372
|
-
val: 'true',
|
|
1373
|
-
value: true,
|
|
1374
|
-
mutable: true,
|
|
1375
|
-
lastModified: '2015-06-29T20:02:48.033Z',
|
|
1376
|
-
},
|
|
1377
855
|
],
|
|
1378
856
|
entitlement: [
|
|
1379
857
|
{
|
|
@@ -1397,21 +875,16 @@ describe('plugin-device', () => {
|
|
|
1397
875
|
return clonedDTO;
|
|
1398
876
|
};
|
|
1399
877
|
|
|
1400
|
-
const checkFeatureTypeCounts = (expectedCounts) => {
|
|
1401
|
-
Object.entries(expectedCounts).forEach(([type, expectedCount]) => {
|
|
1402
|
-
assert.equal(device.features[type].length, expectedCount);
|
|
1403
|
-
});
|
|
1404
|
-
};
|
|
1405
|
-
|
|
1406
878
|
const checkFeatureNotPresent = (type, key) => {
|
|
1407
879
|
assert.isUndefined(device.features[type].get(key));
|
|
1408
880
|
};
|
|
1409
881
|
|
|
1410
882
|
const checkFeature = (type, key, expectedValue) => {
|
|
883
|
+
assert.equal(device.features[type].length, 1);
|
|
1411
884
|
assert.deepEqual(device.features[type].get(key).get('value'), expectedValue);
|
|
1412
885
|
};
|
|
1413
886
|
|
|
1414
|
-
it('features are set correctly if etag not in headers
|
|
887
|
+
it('features are set correctly if etag not in headers', () => {
|
|
1415
888
|
const clonedDTO = getClonedDTO();
|
|
1416
889
|
|
|
1417
890
|
const response = {
|
|
@@ -1421,61 +894,13 @@ describe('plugin-device', () => {
|
|
|
1421
894
|
headers: {},
|
|
1422
895
|
};
|
|
1423
896
|
|
|
1424
|
-
checkFeatureTypeCounts(initialDTOFeatureCounts);
|
|
1425
897
|
checkFeatureNotPresent('developer', '1');
|
|
1426
|
-
checkFeatureNotPresent('developer', 'feature_to_debug_enable');
|
|
1427
|
-
checkFeatureNotPresent('developer', 'feature_to_debug_disable');
|
|
1428
|
-
checkFeatureNotPresent('developer', 'feature_debug_only');
|
|
1429
898
|
checkFeatureNotPresent('entitlement', '2');
|
|
1430
899
|
checkFeatureNotPresent('user', '3');
|
|
1431
900
|
|
|
1432
901
|
device.processRegistrationSuccess(response);
|
|
1433
902
|
|
|
1434
|
-
checkFeatureTypeCounts({developer: 3, entitlement: 1, user: 1});
|
|
1435
903
|
checkFeature('developer', '1', true);
|
|
1436
|
-
checkFeature('developer', 'feature_to_debug_enable', false);
|
|
1437
|
-
checkFeature('developer', 'feature_to_debug_disable', true);
|
|
1438
|
-
checkFeatureNotPresent('developer', 'feature_debug_only');
|
|
1439
|
-
checkFeature('entitlement', '2', true);
|
|
1440
|
-
checkFeature('user', '3', true);
|
|
1441
|
-
});
|
|
1442
|
-
|
|
1443
|
-
it('features are set correctly if etag not in headers, debug features in session storage', () => {
|
|
1444
|
-
const clonedDTO = getClonedDTO();
|
|
1445
|
-
|
|
1446
|
-
const response = {
|
|
1447
|
-
body: {
|
|
1448
|
-
...clonedDTO,
|
|
1449
|
-
},
|
|
1450
|
-
headers: {},
|
|
1451
|
-
};
|
|
1452
|
-
|
|
1453
|
-
device.config.debugFeatureTogglesKey = 'debug-feature-toggles';
|
|
1454
|
-
|
|
1455
|
-
webex.getWindow().sessionStorage.setItem(
|
|
1456
|
-
'debug-feature-toggles',
|
|
1457
|
-
JSON.stringify({
|
|
1458
|
-
feature_to_debug_enable: true,
|
|
1459
|
-
feature_to_debug_disable: false,
|
|
1460
|
-
feature_debug_only: true,
|
|
1461
|
-
})
|
|
1462
|
-
);
|
|
1463
|
-
|
|
1464
|
-
checkFeatureTypeCounts(initialDTOFeatureCounts);
|
|
1465
|
-
checkFeatureNotPresent('developer', '1');
|
|
1466
|
-
checkFeatureNotPresent('developer', 'feature_to_debug_enable');
|
|
1467
|
-
checkFeatureNotPresent('developer', 'feature_to_debug_disable');
|
|
1468
|
-
checkFeatureNotPresent('developer', 'feature_debug_only');
|
|
1469
|
-
checkFeatureNotPresent('entitlement', '2');
|
|
1470
|
-
checkFeatureNotPresent('user', '3');
|
|
1471
|
-
|
|
1472
|
-
device.processRegistrationSuccess(response);
|
|
1473
|
-
|
|
1474
|
-
checkFeatureTypeCounts({developer: 4, entitlement: 1, user: 1});
|
|
1475
|
-
checkFeature('developer', '1', true);
|
|
1476
|
-
checkFeature('developer', 'feature_to_debug_enable', true);
|
|
1477
|
-
checkFeature('developer', 'feature_to_debug_disable', false);
|
|
1478
|
-
checkFeature('developer', 'feature_debug_only', true);
|
|
1479
904
|
checkFeature('entitlement', '2', true);
|
|
1480
905
|
checkFeature('user', '3', true);
|
|
1481
906
|
});
|
|
@@ -1494,17 +919,12 @@ describe('plugin-device', () => {
|
|
|
1494
919
|
},
|
|
1495
920
|
};
|
|
1496
921
|
|
|
1497
|
-
checkFeatureTypeCounts(initialDTOFeatureCounts);
|
|
1498
922
|
checkFeatureNotPresent('developer', '1');
|
|
1499
|
-
checkFeatureNotPresent('developer', 'feature_to_debug_enable');
|
|
1500
|
-
checkFeatureNotPresent('developer', 'feature_to_debug_disable');
|
|
1501
|
-
checkFeatureNotPresent('developer', 'feature_debug_only');
|
|
1502
923
|
checkFeatureNotPresent('entitlement', '2');
|
|
1503
924
|
checkFeatureNotPresent('user', '3');
|
|
1504
925
|
|
|
1505
926
|
device.processRegistrationSuccess(response);
|
|
1506
927
|
|
|
1507
|
-
checkFeatureTypeCounts(initialDTOFeatureCounts.developer);
|
|
1508
928
|
checkFeatureNotPresent('developer', '1');
|
|
1509
929
|
checkFeature('entitlement', '2', true);
|
|
1510
930
|
checkFeature('user', '3', true);
|
|
@@ -1527,21 +947,12 @@ describe('plugin-device', () => {
|
|
|
1527
947
|
},
|
|
1528
948
|
};
|
|
1529
949
|
|
|
1530
|
-
checkFeatureTypeCounts(initialDTOFeatureCounts);
|
|
1531
950
|
checkFeatureNotPresent('developer', '1');
|
|
1532
|
-
checkFeatureNotPresent('developer', 'feature_to_debug_enable');
|
|
1533
|
-
checkFeatureNotPresent('developer', 'feature_to_debug_disable');
|
|
1534
|
-
checkFeatureNotPresent('developer', 'feature_debug_only');
|
|
1535
951
|
checkFeatureNotPresent('entitlement', '2');
|
|
1536
952
|
checkFeatureNotPresent('user', '3');
|
|
1537
953
|
|
|
1538
954
|
device.processRegistrationSuccess(response);
|
|
1539
955
|
|
|
1540
|
-
checkFeatureTypeCounts({
|
|
1541
|
-
developer: initialDTOFeatureCounts.developer,
|
|
1542
|
-
entitlement: 1,
|
|
1543
|
-
user: 1,
|
|
1544
|
-
});
|
|
1545
956
|
checkFeatureNotPresent('developer', '1');
|
|
1546
957
|
checkFeature('entitlement', '2', true);
|
|
1547
958
|
checkFeature('user', '3', true);
|
|
@@ -1564,17 +975,12 @@ describe('plugin-device', () => {
|
|
|
1564
975
|
},
|
|
1565
976
|
};
|
|
1566
977
|
|
|
1567
|
-
checkFeatureTypeCounts(initialDTOFeatureCounts);
|
|
1568
978
|
checkFeatureNotPresent('developer', '1');
|
|
1569
|
-
checkFeatureNotPresent('developer', 'feature_to_debug_enable');
|
|
1570
|
-
checkFeatureNotPresent('developer', 'feature_to_debug_disable');
|
|
1571
|
-
checkFeatureNotPresent('developer', 'feature_debug_only');
|
|
1572
979
|
checkFeatureNotPresent('entitlement', '2');
|
|
1573
980
|
checkFeatureNotPresent('user', '3');
|
|
1574
981
|
|
|
1575
982
|
device.processRegistrationSuccess(response);
|
|
1576
983
|
|
|
1577
|
-
checkFeatureTypeCounts({developer: 3, entitlement: 1, user: 1});
|
|
1578
984
|
checkFeature('developer', '1', true);
|
|
1579
985
|
checkFeature('entitlement', '2', true);
|
|
1580
986
|
checkFeature('user', '3', true);
|
|
@@ -1623,7 +1029,6 @@ describe('plugin-device', () => {
|
|
|
1623
1029
|
device.processRegistrationSuccess(newResponse);
|
|
1624
1030
|
|
|
1625
1031
|
// only the entitlement and user features should have been changed to false
|
|
1626
|
-
checkFeatureTypeCounts({developer: 3, entitlement: 1, user: 1});
|
|
1627
1032
|
checkFeature('developer', '1', true);
|
|
1628
1033
|
checkFeature('entitlement', '2', false);
|
|
1629
1034
|
checkFeature('user', '3', false);
|