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