OLD | NEW |
---|---|
(Empty) | |
1 /** | |
2 * @fileoverview | |
3 * Unit tests for host_controller.js. | |
4 */ | |
5 | |
6 (function() { | |
7 | |
8 'use strict'; | |
9 | |
10 /** @type {sinon.Mock} */ | |
11 var hostListMock = null; | |
12 | |
13 /** @type {sinon.TestStub} */ | |
14 var generateUuidStub; | |
15 | |
16 /** @type {remoting.MockHostDaemonFacade} */ | |
17 var mockHostDaemonFacade; | |
18 | |
19 /** @type {sinon.TestStub} */ | |
20 var hostDaemonFacadeCtorStub; | |
21 | |
22 var FAKE_HOST_PIN = '<FAKE_HOST_PIN>'; | |
23 var FAKE_USER_EMAIL = '<FAKE_USER_EMAIL>'; | |
24 var FAKE_USER_NAME = '<FAKE_USER_NAME>'; | |
25 var FAKE_UUID = '0bad0bad-0bad-0bad-0bad-0bad0bad0bad'; | |
26 var FAKE_DAEMON_VERSION = '1.2.3.4'; | |
27 var FAKE_HOST_NAME = '<FAKE_HOST_NAME>'; | |
28 var FAKE_PUBLIC_KEY = '<FAKE_PUBLIC_KEY>'; | |
29 var FAKE_PRIVATE_KEY = '<FAKE_PRIVATE_KEY>'; | |
30 var FAKE_AUTH_CODE = '<FAKE_AUTH_CODE>'; | |
31 var FAKE_REFRESH_TOKEN = '<FAKE_REFRESH_TOKEN>'; | |
32 var FAKE_PIN_HASH = '<FAKE_PIN_HASH>'; | |
33 var FAKE_HOST_CLIENT_ID = '<FAKE_HOST_CLIENT_ID>'; | |
34 var FAKE_CLIENT_BASE_JID = '<FAKE_CLIENT_BASE_JID>'; | |
35 | |
36 /** @type {sinon.Spy|Function} */ | |
37 var getCredentialsFromAuthCodeSpy; | |
38 | |
39 /** @type {sinon.Spy|Function} */ | |
40 var getPinHashSpy; | |
41 | |
42 /** @type {sinon.Spy|Function} */ | |
43 var startDaemonSpy; | |
44 | |
45 /** @type {sinon.Spy} */ | |
46 var unregisterHostByIdSpy; | |
47 | |
48 /** @type {sinon.Spy} */ | |
49 var onLocalHostStartedSpy; | |
50 | |
51 QUnit.module('host_controller', { | |
52 beforeEach: function(/** QUnit.Assert */ assert) { | |
53 chromeMocks.activate(['identity', 'runtime']); | |
54 chromeMocks.identity.mock$setToken('my_token'); | |
55 remoting.identity = new remoting.Identity(); | |
56 remoting.MockXhr.activate(); | |
57 base.debug.assert(remoting.oauth2 === null); | |
58 remoting.oauth2 = new remoting.OAuth2(); | |
59 base.debug.assert(remoting.hostList === null); | |
60 remoting.hostList = /** @type {remoting.HostList} */ | |
61 (Object.create(remoting.HostList.prototype)); | |
62 | |
63 // When the HostList's unregisterHostById method is called, make | |
64 // sure the argument is correct. | |
65 unregisterHostByIdSpy = | |
66 sinon.stub(remoting.hostList, 'unregisterHostById', function( | |
67 /** string */ hostId) { | |
68 assert.equal(hostId, FAKE_UUID); | |
69 }); | |
70 | |
71 // When the HostList's onLocalHostStarted method is called, make | |
72 // sure the arguments are correct. | |
73 onLocalHostStartedSpy = | |
74 sinon.stub( | |
75 remoting.hostList, 'onLocalHostStarted', function( | |
76 /** string */ hostName, | |
77 /** string */ newHostId, | |
78 /** string */ publicKey) { | |
79 assert.equal(hostName, FAKE_HOST_NAME); | |
80 assert.equal(newHostId, FAKE_UUID); | |
81 assert.equal(publicKey, FAKE_PUBLIC_KEY); | |
82 }); | |
83 | |
84 hostDaemonFacadeCtorStub = sinon.stub(remoting, 'HostDaemonFacade'); | |
85 mockHostDaemonFacade = new remoting.MockHostDaemonFacade(); | |
86 hostDaemonFacadeCtorStub.returns(mockHostDaemonFacade); | |
87 generateUuidStub = sinon.stub(base, 'generateUuid'); | |
88 generateUuidStub.returns(FAKE_UUID); | |
89 getCredentialsFromAuthCodeSpy = sinon.spy( | |
90 mockHostDaemonFacade, 'getCredentialsFromAuthCode'); | |
91 getPinHashSpy = sinon.spy(mockHostDaemonFacade, 'getPinHash'); | |
92 startDaemonSpy = sinon.spy(mockHostDaemonFacade, 'startDaemon'); | |
93 | |
94 // Set up successful responses from mockHostDaemonFacade. | |
95 // Individual tests override these values to create errors. | |
96 mockHostDaemonFacade.features = | |
97 [remoting.HostController.Feature.OAUTH_CLIENT]; | |
98 mockHostDaemonFacade.daemonVersion = FAKE_DAEMON_VERSION; | |
99 mockHostDaemonFacade.hostName = FAKE_HOST_NAME; | |
100 mockHostDaemonFacade.privateKey = FAKE_PRIVATE_KEY; | |
101 mockHostDaemonFacade.publicKey = FAKE_PUBLIC_KEY; | |
102 mockHostDaemonFacade.hostClientId = FAKE_HOST_CLIENT_ID; | |
103 mockHostDaemonFacade.userEmail = FAKE_USER_EMAIL; | |
104 mockHostDaemonFacade.refreshToken = FAKE_REFRESH_TOKEN; | |
105 mockHostDaemonFacade.pinHash = FAKE_PIN_HASH; | |
106 mockHostDaemonFacade.startDaemonResult = | |
107 remoting.HostController.AsyncResult.OK; | |
108 | |
109 sinon.stub(remoting.identity, 'getEmail').returns( | |
110 Promise.resolve(FAKE_USER_EMAIL)); | |
111 sinon.stub(remoting.oauth2, 'getRefreshToken').returns( | |
112 FAKE_REFRESH_TOKEN); | |
113 }, | |
114 | |
115 afterEach: function() { | |
116 getCredentialsFromAuthCodeSpy.restore(); | |
117 generateUuidStub.restore(); | |
118 hostDaemonFacadeCtorStub.restore(); | |
119 remoting.hostList = null; | |
120 remoting.oauth2 = null; | |
121 remoting.MockXhr.restore(); | |
122 chromeMocks.restore(); | |
123 remoting.identity = null; | |
124 } | |
125 }); | |
126 | |
127 /** | |
128 * Install | |
Jamie
2015/04/08 00:16:15
The comment doesn't seem to have any relation to t
John Williams
2015/04/08 20:20:09
Must've typed errant ^K while I was thinking about
| |
129 * @param {QUnit.Assert} assert | |
130 * @param {boolean} withAuthCode | |
131 */ | |
132 function queueRegistryResponse(assert, withAuthCode) { | |
133 var responseJson = { | |
134 data: { | |
135 authorizationCode: FAKE_AUTH_CODE | |
136 } | |
137 }; | |
138 if (!withAuthCode) { | |
139 delete responseJson.data.authorizationCode; | |
140 } | |
141 | |
142 remoting.MockXhr.setResponseFor( | |
143 'POST', 'DIRECTORY_API_BASE_URL/@me/hosts', | |
144 function(/** remoting.MockXhr */ xhr) { | |
145 assert.deepEqual( | |
146 xhr.params.jsonContent, | |
147 { data: { | |
148 hostId: FAKE_UUID, | |
149 hostName: FAKE_HOST_NAME, | |
150 publicKey: FAKE_PUBLIC_KEY | |
151 } }); | |
152 xhr.setTextResponse(200, JSON.stringify(responseJson)); | |
153 }); | |
154 } | |
155 | |
156 /** | |
157 * @param {remoting.HostController} controller | |
158 */ | |
159 function mockGetClientBaseJid(controller) { | |
160 sinon.stub(controller, 'getClientBaseJid_'). | |
161 callsArgWith(0, FAKE_CLIENT_BASE_JID); | |
162 }; | |
163 | |
164 // Check that hasFeature returns false for missing features. | |
165 QUnit.test('hasFeature returns false', function(assert) { | |
166 var controller = new remoting.HostController(); | |
167 return new Promise(function(resolve, reject) { | |
168 controller.hasFeature( | |
169 remoting.HostController.Feature.PAIRING_REGISTRY, | |
170 resolve); | |
171 }).then(function(/** boolean */ result) { | |
172 assert.equal(result, false); | |
173 }); | |
174 }); | |
175 | |
176 // Check that hasFeature returns true for supported features. | |
177 QUnit.test('hasFeature returns true', function(assert) { | |
178 var controller = new remoting.HostController(); | |
179 return new Promise(function(resolve, reject) { | |
180 controller.hasFeature( | |
181 remoting.HostController.Feature.OAUTH_CLIENT, | |
182 resolve); | |
183 }).then(function(/** boolean */ result) { | |
184 assert.equal(result, true); | |
185 }); | |
186 }); | |
187 | |
188 // Check what happens when the HostDaemonFacade's getHostName method | |
189 // fails. | |
190 QUnit.test('start with getHostName failure', function(assert) { | |
191 mockHostDaemonFacade.hostName = null; | |
192 var controller = new remoting.HostController(); | |
Jamie
2015/04/08 00:16:14
Is the code from here on common to all tests? Can
John Williams
2015/04/08 20:20:09
Done.
Jamie
2015/04/08 22:29:29
IIRC, the controller used to be global and you opt
John Williams
2015/04/08 23:19:55
Right, I did. I misunderstood the comment, but I
Jamie
2015/04/08 23:28:42
Acknowledged.
| |
193 return new Promise(function(resolve, reject) { | |
194 controller.start(FAKE_HOST_PIN, true, function() { | |
195 reject('test failed'); | |
196 }, function(/** remoting.Error */ e) { | |
197 assert.equal(e.getDetail(), 'getHostName'); | |
198 assert.equal(getCredentialsFromAuthCodeSpy.callCount, 0); | |
Jamie
2015/04/08 00:16:14
Should it be a test failure if this was called? We
John Williams
2015/04/08 20:20:09
Good point. Changed.
| |
199 assert.equal(unregisterHostByIdSpy.callCount, 0); | |
200 assert.equal(onLocalHostStartedSpy.callCount, 0); | |
201 assert.equal(startDaemonSpy.callCount, 0); | |
202 resolve(null); | |
203 }); | |
204 }); | |
205 }); | |
206 | |
207 // Check what happens when the HostDaemonFacade's generateKeyPair | |
208 // method fails. | |
209 QUnit.test('start with generateKeyPair failure', function(assert) { | |
210 mockHostDaemonFacade.publicKey = null; | |
211 mockHostDaemonFacade.privateKey = null; | |
212 var controller = new remoting.HostController(); | |
213 return new Promise(function(resolve, reject) { | |
214 controller.start(FAKE_HOST_PIN, true, function() { | |
215 reject('test failed'); | |
216 }, function(/** remoting.Error */ e) { | |
217 assert.equal(e.getDetail(), 'generateKeyPair'); | |
218 assert.equal(getCredentialsFromAuthCodeSpy.callCount, 0); | |
219 assert.equal(unregisterHostByIdSpy.callCount, 0); | |
220 assert.equal(onLocalHostStartedSpy.callCount, 0); | |
221 assert.equal(startDaemonSpy.callCount, 0); | |
222 resolve(null); | |
223 }); | |
224 }); | |
225 }); | |
226 | |
227 // Check what happens when the HostDaemonFacade's getHostClientId | |
228 // method fails. | |
229 QUnit.test('start with getHostClientId failure', function(assert) { | |
230 var controller = new remoting.HostController(); | |
231 mockHostDaemonFacade.hostClientId = null; | |
232 return new Promise(function(resolve, reject) { | |
233 controller.start(FAKE_HOST_PIN, true, function() { | |
234 reject('test failed'); | |
235 }, function(/** remoting.Error */ e) { | |
236 assert.equal(e.getDetail(), 'getHostClientId'); | |
237 assert.equal(getCredentialsFromAuthCodeSpy.callCount, 0); | |
238 assert.equal(unregisterHostByIdSpy.callCount, 0); | |
239 assert.equal(onLocalHostStartedSpy.callCount, 0); | |
240 assert.equal(startDaemonSpy.callCount, 0); | |
241 resolve(null); | |
242 }); | |
243 }); | |
244 }); | |
245 | |
246 // Check what happens when the registry returns an HTTP when we try to | |
247 // register a host. | |
248 QUnit.test('start with host registration failure', function(assert) { | |
249 var controller = new remoting.HostController(); | |
250 remoting.MockXhr.setEmptyResponseFor( | |
251 'POST', 'DIRECTORY_API_BASE_URL/@me/hosts', 500); | |
252 return new Promise(function(resolve, reject) { | |
253 controller.start(FAKE_HOST_PIN, true, function() { | |
254 reject('test failed'); | |
255 }, function(/** remoting.Error */ e) { | |
256 assert.equal(e.getTag(), remoting.Error.Tag.REGISTRATION_FAILED); | |
257 assert.equal(getCredentialsFromAuthCodeSpy.callCount, 0); | |
258 assert.equal(unregisterHostByIdSpy.callCount, 0); | |
259 assert.equal(onLocalHostStartedSpy.callCount, 0); | |
260 assert.equal(startDaemonSpy.callCount, 0); | |
261 resolve(null); | |
262 }); | |
263 }); | |
264 }); | |
265 | |
266 // Check what happens when the HostDaemonFacade's | |
267 // getCredentialsFromAuthCode method fails. | |
268 QUnit.test('start with getCredentialsFromAuthCode failure', function(assert) { | |
269 var controller = new remoting.HostController(); | |
270 mockHostDaemonFacade.useEmail = null; | |
271 mockHostDaemonFacade.refreshToken = null; | |
272 queueRegistryResponse(assert, true); | |
273 return new Promise(function(resolve, reject) { | |
274 controller.start(FAKE_HOST_PIN, true, function() { | |
275 reject('test failed'); | |
276 }, function(/** remoting.Error */ e) { | |
277 assert.equal(e.getDetail(), 'getCredentialsFromAuthCode'); | |
278 assert.equal(getCredentialsFromAuthCodeSpy.callCount, 1); | |
279 assert.equal(unregisterHostByIdSpy.callCount, 0); | |
280 assert.equal(onLocalHostStartedSpy.callCount, 0); | |
281 assert.equal(startDaemonSpy.callCount, 0); | |
282 resolve(null); | |
283 }); | |
284 }); | |
285 }); | |
286 | |
287 // Check what happens when the HostDaemonFacade's getPinHash method | |
288 // fails, and verify that getPinHash is called when the registry | |
289 // does't return an auth code. | |
290 QUnit.test('start with getRefreshToken+getPinHash failure', function(assert) { | |
291 var controller = new remoting.HostController(); | |
292 mockHostDaemonFacade.pinHash = null; | |
293 queueRegistryResponse(assert, false); | |
294 return new Promise(function(resolve, reject) { | |
295 controller.start(FAKE_HOST_PIN, true, function() { | |
296 reject('test failed'); | |
297 }, function(/** remoting.Error */ e) { | |
298 assert.equal(e.getDetail(), 'getPinHash'); | |
299 assert.equal(getCredentialsFromAuthCodeSpy.callCount, 0); | |
300 assert.equal(unregisterHostByIdSpy.callCount, 0); | |
301 assert.equal(onLocalHostStartedSpy.callCount, 0); | |
302 assert.equal(startDaemonSpy.callCount, 0); | |
303 resolve(null); | |
304 }); | |
305 }); | |
306 }); | |
307 | |
308 // Check what happens when the HostController's getClientBaseJid_ | |
309 // method fails. | |
310 QUnit.test('start with getClientBaseJid_ failure', function(assert) { | |
311 var controller = new remoting.HostController(); | |
312 queueRegistryResponse(assert, true); | |
313 sinon.stub(controller, 'getClientBaseJid_'). | |
314 callsArgWith(1, remoting.Error.unexpected('getClientBaseJid_')); | |
315 return new Promise(function(resolve, reject) { | |
316 controller.start(FAKE_HOST_PIN, true, function() { | |
317 reject('test failed'); | |
318 }, function(/** remoting.Error */ e) { | |
319 assert.equal(e.getDetail(), 'getClientBaseJid_'); | |
320 assert.equal(unregisterHostByIdSpy.callCount, 1); | |
321 resolve(null); | |
322 }); | |
323 }); | |
324 }); | |
325 | |
326 // Check what happens when the HostDaemonFacade's startDaemon method | |
327 // fails and calls its onError argument. | |
328 QUnit.test('start with startDaemon failure', function(assert) { | |
329 var controller = new remoting.HostController(); | |
330 queueRegistryResponse(assert, true); | |
331 mockGetClientBaseJid(controller); | |
332 mockHostDaemonFacade.startDaemonResult = null; | |
Jamie
2015/04/08 00:16:14
Why not FAILED/FAILED_DIRECTORY?
John Williams
2015/04/08 20:20:09
Added this as a separate case, but there are two d
Jamie
2015/04/08 22:29:29
Yuck. That sounds like something worth cleaning up
John Williams
2015/04/08 23:19:55
SGTM. When I work on legacy code I usually end up
Jamie
2015/04/08 23:28:42
Acknowledged.
| |
333 return new Promise(function(resolve, reject) { | |
334 controller.start(FAKE_HOST_PIN, true, function() { | |
335 reject('test failed'); | |
336 }, function(/** remoting.Error */ e) { | |
337 assert.equal(e.getDetail(), 'startDaemon'); | |
338 assert.equal(unregisterHostByIdSpy.callCount, 1); | |
339 assert.equal(onLocalHostStartedSpy.callCount, 0); | |
340 resolve(null); | |
341 }); | |
342 }); | |
343 }); | |
344 | |
345 // Check what happens when the HostDaemonFacade's startDaemon method | |
346 // calls is onDone method with an async error code. | |
347 QUnit.test('start with startDaemon cancelled', function(assert) { | |
348 var controller = new remoting.HostController(); | |
349 queueRegistryResponse(assert, true); | |
350 mockGetClientBaseJid(controller); | |
351 mockHostDaemonFacade.startDaemonResult = | |
352 remoting.HostController.AsyncResult.CANCELLED; | |
353 return new Promise(function(resolve, reject) { | |
354 controller.start(FAKE_HOST_PIN, true, function() { | |
355 reject('test failed'); | |
356 }, function(/** remoting.Error */ e) { | |
357 assert.equal(e.getTag(), remoting.Error.Tag.CANCELLED); | |
358 assert.equal(unregisterHostByIdSpy.callCount, 1); | |
359 assert.equal(onLocalHostStartedSpy.callCount, 0); | |
360 resolve(null); | |
361 }); | |
362 }); | |
363 }); | |
364 | |
365 // Check what happens when the entire host registration process | |
366 // succeeds. | |
367 [false, true].forEach(function(/** boolean */ consent) { | |
368 QUnit.test('start succeeds with consent=' + consent, function(assert) { | |
369 var controller = new remoting.HostController(); | |
370 queueRegistryResponse(assert, true); | |
371 mockGetClientBaseJid(controller); | |
372 return new Promise(function(resolve, reject) { | |
373 controller.start(FAKE_HOST_PIN, consent, function() { | |
374 assert.equal(getCredentialsFromAuthCodeSpy.callCount, 1); | |
375 assert.deepEqual( | |
376 getCredentialsFromAuthCodeSpy.args[0][0], | |
377 FAKE_AUTH_CODE); | |
378 assert.equal(getPinHashSpy.callCount, 1); | |
379 assert.deepEqual( | |
380 getPinHashSpy.args[0].slice(0, 2), | |
381 [FAKE_UUID, FAKE_HOST_PIN]); | |
382 | |
383 assert.equal(unregisterHostByIdSpy.callCount, 0); | |
384 assert.equal(onLocalHostStartedSpy.callCount, 1); | |
385 assert.equal(startDaemonSpy.callCount, 1); | |
386 assert.deepEqual( | |
387 startDaemonSpy.args[0].slice(0, 2), | |
388 [{ | |
389 xmpp_login: FAKE_USER_EMAIL, | |
390 oauth_refresh_token: FAKE_REFRESH_TOKEN, | |
391 host_owner: FAKE_CLIENT_BASE_JID, | |
392 host_owner_email: FAKE_USER_EMAIL, | |
393 host_id: FAKE_UUID, | |
394 host_name: FAKE_HOST_NAME, | |
395 host_secret_hash: FAKE_PIN_HASH, | |
396 private_key: FAKE_PRIVATE_KEY | |
397 }, consent]); | |
398 resolve(null); | |
399 }, reject); | |
400 }); | |
401 }); | |
402 }); | |
403 | |
404 // TODO(jrw): Add tests for |stop| method. | |
405 // TODO(jrw): Add tests for |updatePin| method. | |
406 // TODO(jrw): Add tests for |getLocalHostState| method. | |
407 // TODO(jrw): Add tests for |getLocalHostId| method. | |
408 // TODO(jrw): Add tests for |getPairedClients| method. | |
409 // TODO(jrw): Add tests for |deletePairedClient| method. | |
410 // TODO(jrw): Add tests for |clearPairedClients| method. | |
411 // TODO(jrw): Make sure getClientBaseJid_ method is tested. | |
412 | |
413 })(); | |
OLD | NEW |