Chromium Code Reviews| 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 |