@webex/internal-plugin-device 3.0.0-beta.3 → 3.0.0-beta.300
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 +10 -6
- package/dist/config.js +0 -8
- package/dist/config.js.map +1 -1
- package/dist/constants.js +2 -3
- package/dist/constants.js.map +1 -1
- package/dist/device.js +102 -172
- package/dist/device.js.map +1 -1
- package/dist/features/feature-collection.js +1 -8
- package/dist/features/feature-collection.js.map +1 -1
- package/dist/features/feature-model.js +15 -42
- package/dist/features/feature-model.js.map +1 -1
- package/dist/features/features-model.js +9 -21
- package/dist/features/features-model.js.map +1 -1
- package/dist/features/index.js +0 -8
- package/dist/features/index.js.map +1 -1
- package/dist/index.js +2 -24
- package/dist/index.js.map +1 -1
- package/dist/interceptors/device-url.js +12 -33
- package/dist/interceptors/device-url.js.map +1 -1
- package/dist/ipNetworkDetector.js +200 -0
- package/dist/ipNetworkDetector.js.map +1 -0
- package/dist/metrics.js +0 -2
- package/dist/metrics.js.map +1 -1
- package/package.json +10 -10
- package/src/config.js +8 -9
- package/src/constants.js +3 -5
- package/src/device.js +149 -146
- package/src/features/feature-collection.js +1 -1
- package/src/features/feature-model.js +5 -11
- package/src/features/features-model.js +3 -9
- package/src/features/index.js +1 -5
- package/src/index.js +3 -11
- package/src/interceptors/device-url.js +5 -7
- package/src/ipNetworkDetector.ts +176 -0
- package/src/metrics.js +1 -2
- package/test/integration/spec/device.js +210 -239
- package/test/integration/spec/webex.js +9 -9
- package/test/unit/spec/device.js +44 -53
- package/test/unit/spec/features/feature-collection.js +2 -2
- package/test/unit/spec/features/feature-model.js +23 -39
- package/test/unit/spec/features/features-model.js +4 -12
- package/test/unit/spec/interceptors/device-url.js +69 -109
- package/test/unit/spec/ipNetworkDetector.js +410 -0
- package/test/unit/spec/wdm-dto.json +5 -13
|
@@ -21,19 +21,19 @@ describe('plugin-device', () => {
|
|
|
21
21
|
resource: '/example/resource/',
|
|
22
22
|
service: 'example',
|
|
23
23
|
serviceUrl: 'https://www.example-service.com/',
|
|
24
|
-
uri: 'https://www.example-uri.com/'
|
|
24
|
+
uri: 'https://www.example-uri.com/',
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
interceptor.webex = {
|
|
28
28
|
internal: {
|
|
29
29
|
device: {
|
|
30
|
-
url: fixture.uri
|
|
30
|
+
url: fixture.uri,
|
|
31
31
|
},
|
|
32
32
|
services: {
|
|
33
33
|
waitForService: sinon.stub().resolves(fixture.serviceUrl),
|
|
34
|
-
getServiceFromUrl: sinon.stub().returns({name: fixture.service})
|
|
35
|
-
}
|
|
36
|
-
}
|
|
34
|
+
getServiceFromUrl: sinon.stub().returns({name: fixture.service}),
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
waitForService = interceptor.webex.internal.services.waitForService;
|
|
@@ -48,12 +48,13 @@ describe('plugin-device', () => {
|
|
|
48
48
|
interceptor.webex.internal.device.url = undefined;
|
|
49
49
|
options = {
|
|
50
50
|
headers: {
|
|
51
|
-
'cisco-device-url': fixture.url
|
|
51
|
+
'cisco-device-url': fixture.url,
|
|
52
52
|
},
|
|
53
|
-
...options
|
|
53
|
+
...options,
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
-
return interceptor
|
|
56
|
+
return interceptor
|
|
57
|
+
.onRequest({...options})
|
|
57
58
|
.then((results) => assert.deepEqual(results, options));
|
|
58
59
|
});
|
|
59
60
|
|
|
@@ -62,12 +63,13 @@ describe('plugin-device', () => {
|
|
|
62
63
|
interceptor.webex.internal.device.url = undefined;
|
|
63
64
|
options = {
|
|
64
65
|
headers: {
|
|
65
|
-
'cisco-device-url': undefined
|
|
66
|
+
'cisco-device-url': undefined,
|
|
66
67
|
},
|
|
67
|
-
...options
|
|
68
|
+
...options,
|
|
68
69
|
};
|
|
69
70
|
|
|
70
|
-
return interceptor
|
|
71
|
+
return interceptor
|
|
72
|
+
.onRequest({...options})
|
|
71
73
|
.then((results) => assert.deepEqual(results, options));
|
|
72
74
|
});
|
|
73
75
|
});
|
|
@@ -75,12 +77,13 @@ describe('plugin-device', () => {
|
|
|
75
77
|
describe('when service does not exist', () => {
|
|
76
78
|
it('should return the options', () => {
|
|
77
79
|
interceptor.webex.internal.device.url = 'http://device-url.com/';
|
|
78
|
-
interceptor.webex.internal.services.waitForService =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
interceptor.webex.internal.services.waitForService = sinon
|
|
81
|
+
.stub()
|
|
82
|
+
.resolves('http://example-url.com/');
|
|
83
|
+
interceptor.webex.internal.services.getServiceFromUrl = sinon.stub().returns();
|
|
82
84
|
|
|
83
|
-
return interceptor
|
|
85
|
+
return interceptor
|
|
86
|
+
.onRequest({...options})
|
|
84
87
|
.then((results) => assert.deepEqual(results, options));
|
|
85
88
|
});
|
|
86
89
|
});
|
|
@@ -90,71 +93,50 @@ describe('plugin-device', () => {
|
|
|
90
93
|
it('when only the service property is provided', () => {
|
|
91
94
|
options.service = fixture.service;
|
|
92
95
|
|
|
93
|
-
interceptor.onRequest(options)
|
|
94
|
-
.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
{
|
|
98
|
-
service: options.service,
|
|
99
|
-
url: undefined
|
|
100
|
-
}
|
|
101
|
-
);
|
|
102
|
-
assert.calledWith(
|
|
103
|
-
getServiceFromUrl,
|
|
104
|
-
fixture.serviceUrl
|
|
105
|
-
);
|
|
106
|
-
assert.isDefined(options.headers['cisco-device-url']);
|
|
107
|
-
assert.equal(results.headers['cisco-device-url'], fixture.uri);
|
|
96
|
+
interceptor.onRequest(options).then((results) => {
|
|
97
|
+
assert.calledWith(waitForService, {
|
|
98
|
+
service: options.service,
|
|
99
|
+
url: undefined,
|
|
108
100
|
});
|
|
101
|
+
assert.calledWith(getServiceFromUrl, fixture.serviceUrl);
|
|
102
|
+
assert.isDefined(options.headers['cisco-device-url']);
|
|
103
|
+
assert.equal(results.headers['cisco-device-url'], fixture.uri);
|
|
104
|
+
});
|
|
109
105
|
});
|
|
110
106
|
|
|
111
107
|
it('when only the uri property is provided', () => {
|
|
112
108
|
options = {
|
|
113
109
|
uri: fixture.uri,
|
|
114
|
-
...options
|
|
110
|
+
...options,
|
|
115
111
|
};
|
|
116
112
|
|
|
117
|
-
interceptor.onRequest(options)
|
|
118
|
-
.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
{
|
|
122
|
-
service: undefined,
|
|
123
|
-
url: options.uri
|
|
124
|
-
}
|
|
125
|
-
);
|
|
126
|
-
assert.calledWith(
|
|
127
|
-
getServiceFromUrl,
|
|
128
|
-
fixture.serviceUrl
|
|
129
|
-
);
|
|
130
|
-
assert.isDefined(results.headers['cisco-device-url']);
|
|
131
|
-
assert.equal(results.headers['cisco-device-url'], fixture.uri);
|
|
113
|
+
interceptor.onRequest(options).then((results) => {
|
|
114
|
+
assert.calledWith(waitForService, {
|
|
115
|
+
service: undefined,
|
|
116
|
+
url: options.uri,
|
|
132
117
|
});
|
|
118
|
+
assert.calledWith(getServiceFromUrl, fixture.serviceUrl);
|
|
119
|
+
assert.isDefined(results.headers['cisco-device-url']);
|
|
120
|
+
assert.equal(results.headers['cisco-device-url'], fixture.uri);
|
|
121
|
+
});
|
|
133
122
|
});
|
|
134
123
|
|
|
135
124
|
it('when both the service and uri properties are provided', () => {
|
|
136
125
|
options = {
|
|
137
126
|
services: fixture.service,
|
|
138
127
|
uri: fixture.uri,
|
|
139
|
-
...options
|
|
128
|
+
...options,
|
|
140
129
|
};
|
|
141
130
|
|
|
142
|
-
interceptor.onRequest(options)
|
|
143
|
-
.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
{
|
|
147
|
-
service: options.service,
|
|
148
|
-
url: options.uri
|
|
149
|
-
}
|
|
150
|
-
);
|
|
151
|
-
assert.calledWith(
|
|
152
|
-
getServiceFromUrl,
|
|
153
|
-
fixture.serviceUrl
|
|
154
|
-
);
|
|
155
|
-
assert.isDefined(results.headers['cisco-device-url']);
|
|
156
|
-
assert.equal(results.headers['cisco-device-url'], fixture.uri);
|
|
131
|
+
interceptor.onRequest(options).then((results) => {
|
|
132
|
+
assert.calledWith(waitForService, {
|
|
133
|
+
service: options.service,
|
|
134
|
+
url: options.uri,
|
|
157
135
|
});
|
|
136
|
+
assert.calledWith(getServiceFromUrl, fixture.serviceUrl);
|
|
137
|
+
assert.isDefined(results.headers['cisco-device-url']);
|
|
138
|
+
assert.equal(results.headers['cisco-device-url'], fixture.uri);
|
|
139
|
+
});
|
|
158
140
|
});
|
|
159
141
|
|
|
160
142
|
describe('does not add cisco-device-url due to invalid service name', () => {
|
|
@@ -164,24 +146,17 @@ describe('plugin-device', () => {
|
|
|
164
146
|
options = {
|
|
165
147
|
services: fixture.service,
|
|
166
148
|
uri: fixture.uri,
|
|
167
|
-
...options
|
|
149
|
+
...options,
|
|
168
150
|
};
|
|
169
151
|
|
|
170
|
-
interceptor.onRequest(options)
|
|
171
|
-
.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
{
|
|
175
|
-
service: options.service,
|
|
176
|
-
url: options.uri
|
|
177
|
-
}
|
|
178
|
-
);
|
|
179
|
-
assert.calledWith(
|
|
180
|
-
getServiceFromUrl,
|
|
181
|
-
fixture.serviceUrl
|
|
182
|
-
);
|
|
183
|
-
assert.isUndefined(results.headers);
|
|
152
|
+
interceptor.onRequest(options).then((results) => {
|
|
153
|
+
assert.calledWith(waitForService, {
|
|
154
|
+
service: options.service,
|
|
155
|
+
url: options.uri,
|
|
184
156
|
});
|
|
157
|
+
assert.calledWith(getServiceFromUrl, fixture.serviceUrl);
|
|
158
|
+
assert.isUndefined(results.headers);
|
|
159
|
+
});
|
|
185
160
|
});
|
|
186
161
|
|
|
187
162
|
it('service is `oauth` returns the original object', () => {
|
|
@@ -190,24 +165,17 @@ describe('plugin-device', () => {
|
|
|
190
165
|
options = {
|
|
191
166
|
services: fixture.service,
|
|
192
167
|
uri: fixture.uri,
|
|
193
|
-
...options
|
|
168
|
+
...options,
|
|
194
169
|
};
|
|
195
170
|
|
|
196
|
-
interceptor.onRequest(options)
|
|
197
|
-
.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
{
|
|
201
|
-
service: options.service,
|
|
202
|
-
url: options.uri
|
|
203
|
-
}
|
|
204
|
-
);
|
|
205
|
-
assert.calledWith(
|
|
206
|
-
getServiceFromUrl,
|
|
207
|
-
fixture.serviceUrl
|
|
208
|
-
);
|
|
209
|
-
assert.isUndefined(results.headers);
|
|
171
|
+
interceptor.onRequest(options).then((results) => {
|
|
172
|
+
assert.calledWith(waitForService, {
|
|
173
|
+
service: options.service,
|
|
174
|
+
url: options.uri,
|
|
210
175
|
});
|
|
176
|
+
assert.calledWith(getServiceFromUrl, fixture.serviceUrl);
|
|
177
|
+
assert.isUndefined(results.headers);
|
|
178
|
+
});
|
|
211
179
|
});
|
|
212
180
|
|
|
213
181
|
it('service is `saml` returns the original object', () => {
|
|
@@ -216,28 +184,20 @@ describe('plugin-device', () => {
|
|
|
216
184
|
options = {
|
|
217
185
|
services: fixture.service,
|
|
218
186
|
uri: fixture.uri,
|
|
219
|
-
...options
|
|
187
|
+
...options,
|
|
220
188
|
};
|
|
221
189
|
|
|
222
|
-
interceptor.onRequest(options)
|
|
223
|
-
.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
{
|
|
227
|
-
service: options.service,
|
|
228
|
-
url: options.uri
|
|
229
|
-
}
|
|
230
|
-
);
|
|
231
|
-
assert.calledWith(
|
|
232
|
-
getServiceFromUrl,
|
|
233
|
-
fixture.serviceUrl
|
|
234
|
-
);
|
|
235
|
-
assert.isUndefined(results.headers);
|
|
190
|
+
interceptor.onRequest(options).then((results) => {
|
|
191
|
+
assert.calledWith(waitForService, {
|
|
192
|
+
service: options.service,
|
|
193
|
+
url: options.uri,
|
|
236
194
|
});
|
|
195
|
+
assert.calledWith(getServiceFromUrl, fixture.serviceUrl);
|
|
196
|
+
assert.isUndefined(results.headers);
|
|
197
|
+
});
|
|
237
198
|
});
|
|
238
199
|
});
|
|
239
200
|
|
|
240
|
-
|
|
241
201
|
describe('waitForService returns a rejection', () => {
|
|
242
202
|
beforeEach(() => {
|
|
243
203
|
waitForService.rejects();
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import {assert} from '@webex/test-helper-chai';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
import IpNetworkDetector from '@webex/internal-plugin-device/src/ipNetworkDetector';
|
|
4
|
+
import MockWebex from '@webex/test-helper-mock-webex';
|
|
5
|
+
|
|
6
|
+
describe('plugin-device', () => {
|
|
7
|
+
describe('IpNetworkDetector', () => {
|
|
8
|
+
let webex;
|
|
9
|
+
let ipNetworkDetector;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
webex = new MockWebex({});
|
|
13
|
+
|
|
14
|
+
ipNetworkDetector = new IpNetworkDetector({}, {parent: webex});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('is initialized correctly', () => {
|
|
18
|
+
assert.equal(ipNetworkDetector.supportsIpV4, undefined);
|
|
19
|
+
assert.equal(ipNetworkDetector.supportsIpV6, undefined);
|
|
20
|
+
assert.equal(ipNetworkDetector.firstIpV4, -1);
|
|
21
|
+
assert.equal(ipNetworkDetector.firstIpV6, -1);
|
|
22
|
+
assert.equal(ipNetworkDetector.firstMdns, -1);
|
|
23
|
+
assert.equal(ipNetworkDetector.totalTime, -1);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('detect', () => {
|
|
27
|
+
let previousRTCPeerConnection;
|
|
28
|
+
let clock;
|
|
29
|
+
let fakePeerConnection;
|
|
30
|
+
|
|
31
|
+
const FAKE_OFFER = {type: 'offer', sdp: 'some sdp'};
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
clock = sinon.useFakeTimers();
|
|
35
|
+
|
|
36
|
+
previousRTCPeerConnection = global.RTCPeerConnection;
|
|
37
|
+
|
|
38
|
+
fakePeerConnection = {
|
|
39
|
+
createDataChannel: sinon.stub(),
|
|
40
|
+
createOffer: sinon.stub().resolves(FAKE_OFFER),
|
|
41
|
+
setLocalDescription: sinon.stub().resolves(),
|
|
42
|
+
close: sinon.stub(),
|
|
43
|
+
iceGatheringState: 'new',
|
|
44
|
+
};
|
|
45
|
+
global.RTCPeerConnection = sinon.stub().returns(fakePeerConnection);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
global.RTCPeerConnection = previousRTCPeerConnection;
|
|
50
|
+
clock.restore();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const simulateCandidate = (delay, address) => {
|
|
54
|
+
clock.tick(delay);
|
|
55
|
+
|
|
56
|
+
fakePeerConnection.onicecandidate({
|
|
57
|
+
candidate: {address},
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const simulateEndOfCandidateGathering = (delay, useGatheringStateChange = true) => {
|
|
62
|
+
clock.tick(delay);
|
|
63
|
+
|
|
64
|
+
// browsers have 2 ways of notifying about ICE candidate gathering being completed
|
|
65
|
+
// 1. through gathering state change
|
|
66
|
+
// 2. by sending a null candidate
|
|
67
|
+
if (useGatheringStateChange) {
|
|
68
|
+
fakePeerConnection.iceGatheringState = 'complete';
|
|
69
|
+
fakePeerConnection.onicegatheringstatechange();
|
|
70
|
+
} else {
|
|
71
|
+
fakePeerConnection.onicecandidate({
|
|
72
|
+
candidate: null,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const checkResults = (expectedResults) => {
|
|
78
|
+
assert.equal(ipNetworkDetector.supportsIpV4, expectedResults.supportsIpV4);
|
|
79
|
+
assert.equal(ipNetworkDetector.supportsIpV6, expectedResults.supportsIpV6);
|
|
80
|
+
assert.equal(ipNetworkDetector.firstIpV4, expectedResults.timings.ipv4);
|
|
81
|
+
assert.equal(ipNetworkDetector.firstIpV6, expectedResults.timings.ipv6);
|
|
82
|
+
assert.equal(ipNetworkDetector.firstMdns, expectedResults.timings.mdns);
|
|
83
|
+
assert.equal(ipNetworkDetector.totalTime, expectedResults.timings.totalTime);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
it('creates an RTCPeerConnection with a data channel and does ice candidate gathering', async () => {
|
|
87
|
+
const promise = ipNetworkDetector.detect();
|
|
88
|
+
|
|
89
|
+
simulateEndOfCandidateGathering();
|
|
90
|
+
|
|
91
|
+
await promise;
|
|
92
|
+
|
|
93
|
+
assert.calledOnceWithExactly(fakePeerConnection.createDataChannel, 'data');
|
|
94
|
+
assert.calledOnceWithExactly(fakePeerConnection.createOffer);
|
|
95
|
+
assert.calledOnceWithExactly(fakePeerConnection.setLocalDescription, FAKE_OFFER);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('works correctly when we get only ipv4 candidates', async () => {
|
|
99
|
+
const promise = ipNetworkDetector.detect();
|
|
100
|
+
|
|
101
|
+
simulateCandidate(70, '192.168.0.1');
|
|
102
|
+
simulateCandidate(30, '192.168.16.1');
|
|
103
|
+
simulateEndOfCandidateGathering(50);
|
|
104
|
+
|
|
105
|
+
await promise;
|
|
106
|
+
|
|
107
|
+
checkResults({
|
|
108
|
+
supportsIpV4: true,
|
|
109
|
+
supportsIpV6: false,
|
|
110
|
+
timings: {
|
|
111
|
+
totalTime: 150,
|
|
112
|
+
ipv4: 70, // this should match the first ipv4 candidate's delay
|
|
113
|
+
ipv6: -1,
|
|
114
|
+
mdns: -1,
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('works correctly when we get only ipv6 candidates (chrome, safari)', async () => {
|
|
120
|
+
const promise = ipNetworkDetector.detect();
|
|
121
|
+
|
|
122
|
+
// chrome and safari for some reason wrap the ipv6 addresses with []
|
|
123
|
+
simulateCandidate(150, '[2a02:c7c:a0d0:8a00:db9b:d4de:d1f7:4c49]');
|
|
124
|
+
simulateCandidate(50, '[2a02:c7c:a0d0:8a00:d089:7baf:ceef:b9d8]');
|
|
125
|
+
simulateEndOfCandidateGathering(100);
|
|
126
|
+
|
|
127
|
+
await promise;
|
|
128
|
+
|
|
129
|
+
checkResults({
|
|
130
|
+
supportsIpV4: false,
|
|
131
|
+
supportsIpV6: true,
|
|
132
|
+
timings: {
|
|
133
|
+
totalTime: 300,
|
|
134
|
+
ipv4: -1,
|
|
135
|
+
ipv6: 150, // this should match the first ipv6 candidate's delay
|
|
136
|
+
mdns: -1,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('works correctly when we get only ipv6 candidates (Firefox)', async () => {
|
|
142
|
+
const promise = ipNetworkDetector.detect();
|
|
143
|
+
|
|
144
|
+
simulateCandidate(150, '2a02:c7c:a0d0:8a00:db9b:d4de:d1f7:4c49');
|
|
145
|
+
simulateCandidate(50, '2a02:c7c:a0d0:8a00:d089:7baf:ceef:b9d8');
|
|
146
|
+
simulateEndOfCandidateGathering(100);
|
|
147
|
+
|
|
148
|
+
await promise;
|
|
149
|
+
|
|
150
|
+
checkResults({
|
|
151
|
+
supportsIpV4: false,
|
|
152
|
+
supportsIpV6: true,
|
|
153
|
+
timings: {
|
|
154
|
+
totalTime: 300,
|
|
155
|
+
ipv4: -1,
|
|
156
|
+
ipv6: 150, // this should match the first ipv6 candidate's delay
|
|
157
|
+
mdns: -1,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it('works correctly when we get both ipv6 and ipv4 candidates', async () => {
|
|
163
|
+
const promise = ipNetworkDetector.detect();
|
|
164
|
+
|
|
165
|
+
simulateCandidate(50, '2a02:c7c:a0d0:8a00:db9b:d4de:d1f7:4c49');
|
|
166
|
+
simulateCandidate(50, '192.168.10.10');
|
|
167
|
+
|
|
168
|
+
// at this point, as we've got at least 1 IPv4 and IPv6 candidate the promise should already be resolved
|
|
169
|
+
await promise;
|
|
170
|
+
|
|
171
|
+
checkResults({
|
|
172
|
+
supportsIpV4: true,
|
|
173
|
+
supportsIpV6: true,
|
|
174
|
+
timings: {
|
|
175
|
+
totalTime: -1, // ice gathering has not finished, so this one is still -1
|
|
176
|
+
ipv4: 100,
|
|
177
|
+
ipv6: 50,
|
|
178
|
+
mdns: -1,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// receiving any more candidates should not cause any problems
|
|
183
|
+
simulateCandidate(50, '192.168.1.1');
|
|
184
|
+
simulateCandidate(50, '2a02:c7c:a0d0:8a00:d089:7baf:ceef:b9d8');
|
|
185
|
+
simulateEndOfCandidateGathering(100);
|
|
186
|
+
|
|
187
|
+
// check final results haven't changed (except for totalTime)
|
|
188
|
+
checkResults({
|
|
189
|
+
supportsIpV4: true,
|
|
190
|
+
supportsIpV6: true,
|
|
191
|
+
timings: {
|
|
192
|
+
totalTime: 300,
|
|
193
|
+
ipv4: 100,
|
|
194
|
+
ipv6: 50,
|
|
195
|
+
mdns: -1,
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('works correctly when we get only mDNS candidates', async () => {
|
|
201
|
+
const promise = ipNetworkDetector.detect();
|
|
202
|
+
|
|
203
|
+
// simulate some mDNS candidates (this happens if we don't have user media permissions)
|
|
204
|
+
simulateCandidate(50, '686a3cac-2840-4c62-9f85-9f0b03e84298.local');
|
|
205
|
+
simulateCandidate(50, '12f3ab4a3-4741-48c8-b1c9-8dd93d123aa1.local');
|
|
206
|
+
simulateEndOfCandidateGathering(100);
|
|
207
|
+
|
|
208
|
+
await promise;
|
|
209
|
+
|
|
210
|
+
checkResults({
|
|
211
|
+
supportsIpV4: undefined,
|
|
212
|
+
supportsIpV6: undefined,
|
|
213
|
+
timings: {
|
|
214
|
+
totalTime: 200,
|
|
215
|
+
ipv4: -1,
|
|
216
|
+
ipv6: -1,
|
|
217
|
+
mdns: 50,
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('works correctly when we get no candidates at all', async () => {
|
|
223
|
+
const promise = ipNetworkDetector.detect();
|
|
224
|
+
|
|
225
|
+
simulateEndOfCandidateGathering(100);
|
|
226
|
+
|
|
227
|
+
await promise;
|
|
228
|
+
|
|
229
|
+
checkResults({
|
|
230
|
+
supportsIpV4: false,
|
|
231
|
+
supportsIpV6: false,
|
|
232
|
+
timings: {
|
|
233
|
+
totalTime: 100,
|
|
234
|
+
ipv4: -1,
|
|
235
|
+
ipv6: -1,
|
|
236
|
+
mdns: -1,
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// this never happens right now, but in theory browsers might change and if we get
|
|
242
|
+
// mDNS candidates with IPv4, but without IPv6, it is probably safe to assume that we're only on IPv4 network
|
|
243
|
+
it('works correctly when we get mDNS and ipv4 candidates', async () => {
|
|
244
|
+
const promise = ipNetworkDetector.detect();
|
|
245
|
+
|
|
246
|
+
simulateCandidate(50, '686a3cac-2840-4c62-9f85-9f0b03e84298.local');
|
|
247
|
+
simulateCandidate(50, '192.168.0.0');
|
|
248
|
+
simulateEndOfCandidateGathering(100);
|
|
249
|
+
|
|
250
|
+
await promise;
|
|
251
|
+
|
|
252
|
+
checkResults({
|
|
253
|
+
supportsIpV4: true,
|
|
254
|
+
supportsIpV6: false,
|
|
255
|
+
timings: {
|
|
256
|
+
totalTime: 200,
|
|
257
|
+
ipv4: 100,
|
|
258
|
+
ipv6: -1,
|
|
259
|
+
mdns: 50,
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
// this never happens right now, but in theory browsers might change and if we get
|
|
265
|
+
// mDNS candidates with IPv6, but without IPv4, it is probably safe to assume that we're only on IPv6 network
|
|
266
|
+
it('works correctly when we get mDNS and ipv6 candidates', async () => {
|
|
267
|
+
const promise = ipNetworkDetector.detect();
|
|
268
|
+
|
|
269
|
+
simulateCandidate(50, '686a3cac-2840-4c62-9f85-9f0b03e84298.local');
|
|
270
|
+
simulateCandidate(50, '2a02:c7c:a0d0:8a00:db9b:d4de:d1f7:4c49');
|
|
271
|
+
simulateEndOfCandidateGathering(100);
|
|
272
|
+
|
|
273
|
+
await promise;
|
|
274
|
+
|
|
275
|
+
checkResults({
|
|
276
|
+
supportsIpV4: false,
|
|
277
|
+
supportsIpV6: true,
|
|
278
|
+
timings: {
|
|
279
|
+
totalTime: 200,
|
|
280
|
+
ipv4: -1,
|
|
281
|
+
ipv6: 100,
|
|
282
|
+
mdns: 50,
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('works correctly when we get null candidate at the end instead of gathering state change event', async () => {
|
|
288
|
+
const promise = ipNetworkDetector.detect();
|
|
289
|
+
|
|
290
|
+
simulateCandidate(50, '2a02:c7c:a0d0:8a00:db9b:d4de:d1f7:4c49');
|
|
291
|
+
simulateCandidate(50, '192.168.10.10');
|
|
292
|
+
simulateEndOfCandidateGathering(100, false);
|
|
293
|
+
|
|
294
|
+
await promise;
|
|
295
|
+
|
|
296
|
+
checkResults({
|
|
297
|
+
supportsIpV4: true,
|
|
298
|
+
supportsIpV6: true,
|
|
299
|
+
timings: {
|
|
300
|
+
totalTime: 200,
|
|
301
|
+
ipv4: 100,
|
|
302
|
+
ipv6: 50,
|
|
303
|
+
mdns: -1,
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('resets all the props when called again', async () => {
|
|
309
|
+
const promise = ipNetworkDetector.detect();
|
|
310
|
+
|
|
311
|
+
simulateCandidate(50, '192.168.0.1');
|
|
312
|
+
simulateCandidate(50, '2a02:c7c:a0d0:8a00:db9b:d4de:d1f7:4c49');
|
|
313
|
+
simulateEndOfCandidateGathering(10);
|
|
314
|
+
|
|
315
|
+
await promise;
|
|
316
|
+
|
|
317
|
+
checkResults({
|
|
318
|
+
supportsIpV4: true,
|
|
319
|
+
supportsIpV6: true,
|
|
320
|
+
timings: {
|
|
321
|
+
totalTime: 110,
|
|
322
|
+
ipv4: 50,
|
|
323
|
+
ipv6: 100,
|
|
324
|
+
mdns: -1,
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// now call detect() again
|
|
329
|
+
const promise2 = ipNetworkDetector.detect();
|
|
330
|
+
|
|
331
|
+
// everything should have been reset
|
|
332
|
+
assert.equal(ipNetworkDetector.supportsIpV4, undefined);
|
|
333
|
+
assert.equal(ipNetworkDetector.supportsIpV6, undefined);
|
|
334
|
+
assert.equal(ipNetworkDetector.firstIpV4, -1);
|
|
335
|
+
assert.equal(ipNetworkDetector.firstIpV6, -1);
|
|
336
|
+
assert.equal(ipNetworkDetector.firstMdns, -1);
|
|
337
|
+
assert.equal(ipNetworkDetector.totalTime, -1);
|
|
338
|
+
|
|
339
|
+
simulateEndOfCandidateGathering(10);
|
|
340
|
+
await promise2;
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('rejects if one of RTCPeerConnection operations fails', async () => {
|
|
344
|
+
const fakeError = new Error('fake error');
|
|
345
|
+
|
|
346
|
+
fakePeerConnection.createOffer.rejects(fakeError);
|
|
347
|
+
|
|
348
|
+
await assert.isRejected(ipNetworkDetector.detect(), fakeError);
|
|
349
|
+
|
|
350
|
+
assert.calledOnce(fakePeerConnection.close);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
describe('while detection is in progress', () => {
|
|
354
|
+
describe('supportsIpv4 prop', () => {
|
|
355
|
+
it('returns undefined before any ipv4 candidate is received and true afterwards', async () => {
|
|
356
|
+
const promise = ipNetworkDetector.detect();
|
|
357
|
+
|
|
358
|
+
assert.equal(ipNetworkDetector.supportsIpV4, undefined);
|
|
359
|
+
assert.equal(ipNetworkDetector.firstIpV4, -1);
|
|
360
|
+
|
|
361
|
+
simulateCandidate(50, 'fd64:17cf:f4ad:0:d089:7baf:ceef:b9d8');
|
|
362
|
+
// still no ipv4 candidates...
|
|
363
|
+
assert.equal(ipNetworkDetector.supportsIpV4, undefined);
|
|
364
|
+
assert.equal(ipNetworkDetector.firstIpV4, -1);
|
|
365
|
+
|
|
366
|
+
simulateCandidate(50, '686a3cac-2840-4c62-9f85-9f0b03e84298.local');
|
|
367
|
+
// still no ipv4 candidates...
|
|
368
|
+
assert.equal(ipNetworkDetector.supportsIpV4, undefined);
|
|
369
|
+
assert.equal(ipNetworkDetector.firstIpV4, -1);
|
|
370
|
+
|
|
371
|
+
simulateCandidate(50, '192.168.0.0');
|
|
372
|
+
// now we've got one
|
|
373
|
+
assert.equal(ipNetworkDetector.supportsIpV4, true);
|
|
374
|
+
assert.equal(ipNetworkDetector.firstIpV4, 150);
|
|
375
|
+
|
|
376
|
+
simulateEndOfCandidateGathering(1);
|
|
377
|
+
await promise;
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
describe('supportsIpv6 prop', () => {
|
|
382
|
+
it('returns undefined before any ipv6 candidate is received and true afterwards', async () => {
|
|
383
|
+
const promise = ipNetworkDetector.detect();
|
|
384
|
+
|
|
385
|
+
assert.equal(ipNetworkDetector.supportsIpV6, undefined);
|
|
386
|
+
assert.equal(ipNetworkDetector.firstIpV6, -1);
|
|
387
|
+
|
|
388
|
+
simulateCandidate(50, '192.168.0.0');
|
|
389
|
+
// still no ipv6 candidates...
|
|
390
|
+
assert.equal(ipNetworkDetector.supportsIpV6, undefined);
|
|
391
|
+
assert.equal(ipNetworkDetector.firstIpV6, -1);
|
|
392
|
+
|
|
393
|
+
simulateCandidate(50, '686a3cac-2860-6c62-9f85-9f0b03e86298.local');
|
|
394
|
+
// still no ipv6 candidates...
|
|
395
|
+
assert.equal(ipNetworkDetector.supportsIpV6, undefined);
|
|
396
|
+
assert.equal(ipNetworkDetector.firstIpV6, -1);
|
|
397
|
+
|
|
398
|
+
simulateCandidate(50, 'fd64:17cf:f4ad:0:d089:7baf:ceef:b9d8');
|
|
399
|
+
// now we've got one
|
|
400
|
+
assert.equal(ipNetworkDetector.supportsIpV6, true);
|
|
401
|
+
assert.equal(ipNetworkDetector.firstIpV6, 150);
|
|
402
|
+
|
|
403
|
+
simulateEndOfCandidateGathering(1);
|
|
404
|
+
await promise;
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
});
|