| <!DOCTYPE html> |
| <!-- |
| Copyright 2017 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes"> |
| <title>tricium-client</title> |
| |
| <script src="../bower_components/webcomponentsjs/webcomponents-lite.js"></script> |
| <script src="../bower_components/web-component-tester/browser.js"></script> |
| |
| <link rel="import" href="../bower_components/iron-test-helpers/iron-test-helpers.html"> |
| <link rel="import" href="../src/main/resources/static/tricium-client.html"> |
| |
| <test-fixture id="tricium-client-fixture"> |
| <template> |
| <tricium-client></tricium-client> |
| </template> |
| </test-fixture> |
| |
| <script> |
| |
| async function assertRejects(promise, expectedReason = null) { |
| try { |
| await promise(); |
| assert.fail('exception', 'no exception'); |
| } catch (actualReason) { |
| if (expectedReason) { |
| assert.deepEqual(actualReason, expectedReason); |
| } |
| } |
| } |
| |
| suite('<tricium-client> oauth-related behavior', () => { |
| let element; |
| let sandbox; |
| |
| setup(() => { |
| element = fixture('tricium-client-fixture'); |
| sandbox = sinon.sandbox.create(); |
| sandbox.stub(window, 'gapi', { |
| auth: { |
| init: () => { throw Error('should be stubbed'); }, |
| authorize: () => { throw Error('should be stubbed'); }, |
| }, |
| }); |
| }); |
| |
| teardown(() => { |
| sandbox.restore(); |
| }); |
| |
| function nowSeconds() { |
| return ~~(Date.now() / 1000); |
| } |
| |
| test('_oauthTokenIsValid with valid token', () => { |
| assert.isTrue(element._oauthTokenIsValid({ |
| access_token: 'foo', |
| expires_at: (nowSeconds() + 3600) + '', |
| })); |
| }); |
| |
| test('_oauthTokenIsValid with no access_token field', () => { |
| assert.isFalse(element._oauthTokenIsValid({ |
| expires_at: (nowSeconds() + 3600) + '', |
| })); |
| }); |
| |
| test('_oauthTokenIsValid with expired token', () => { |
| assert.isFalse(element._oauthTokenIsValid({ |
| access_token: 'foo', |
| expires_at: (nowSeconds() - 5) + '', |
| })); |
| }); |
| |
| test('_oauthTokenIsValid with invalid values', () => { |
| assert.isFalse(element._oauthTokenIsValid(null)); |
| assert.isFalse(element._oauthTokenIsValid(undefined)); |
| assert.isFalse(element._oauthTokenIsValid({access_token: 'foo'})); |
| }); |
| |
| test('_refreshToken resolves when authorize gives token', async () => { |
| const token = { |
| access_token: 'test_access_token', |
| expires_at: (nowSeconds() + 3600) + '', |
| }; |
| element._sharedAuthState = { |
| config: { |
| client_id: 'test_client_id', |
| email: 'johndoe@example.com', |
| }, |
| }; |
| sandbox.stub(window.gapi.auth, 'authorize', (opts, callback) => { |
| callback(token); |
| }); |
| const value = await element._refreshToken(100); |
| assert.deepEqual(value, token); |
| }); |
| |
| test('_refreshToken rejects when authorize gives error', async () => { |
| const token = {error: 'could not authorize'}; |
| sandbox.stub(window.gapi.auth, 'authorize', (opts, callback) => { |
| callback(token); |
| }); |
| assertRejects(async () => await element._refreshToken(100)); |
| }); |
| |
| test('_refreshToken rejects when authorize times out', async () => { |
| // In this test, we make it so that authorize never resolves, |
| // and the timeout is made smaller so that the test completes faster. |
| sandbox.stub(window.gapi.auth, 'authorize', () => new Promise(() => {})); |
| assertRejects(async () => await element._refreshToken(0)); |
| }); |
| }); |
| |
| suite('<tricium-client> rpc request behavior', () => { |
| let element; |
| |
| const change = { |
| id: 'myProject~master~I3ea943139cb62e86071996f2480e58bf3eeb9dd2', |
| project: 'myProject', |
| branch: 'master', |
| subject: 'Implement Feature X', |
| }; |
| |
| const revision = { |
| kind: 'REWORK', |
| ref: 'refs/changes/99/4799/2', |
| subject: 'My Patchset', |
| }; |
| |
| const comment = { |
| id: '8a0b9120_a01440e3', |
| robot_id: 'Hello', |
| robot_run_id: 123412341234, |
| properties: { |
| tricium_comment_uuid: 'f37e05e3-ce3b-475b-a4cd-2cc60814bc69', |
| }, |
| }; |
| |
| function newSuccessResponse(data) { |
| return new window.Response(')]}\'' + JSON.stringify(data), { |
| status: 200, |
| headers: { |
| 'Content-Type': 'application/json', |
| 'X-Prpc-Grpc-Code': '0', |
| }, |
| }); |
| } |
| |
| setup(() => { |
| element = fixture('tricium-client-fixture'); |
| element.triciumHost = 'tricium-mock.appspot.com'; |
| sinon.stub(window, 'fetch'); |
| }); |
| |
| teardown(() => { |
| window.fetch.restore(); |
| }); |
| |
| test('getProgress with a success response', async () => { |
| const responseData = { |
| runId: '56511', |
| state: 'SUCCESS', |
| functionProgress: [ |
| { |
| name: 'GitFileIsolator', |
| state: 'SUCCESS', |
| swarmingUrl: 'https://swarm.example.com', |
| swarmingTaskId: '390a', |
| }, |
| { |
| name: 'Spacey', |
| state: 'SUCCESS', |
| swarmingUrl: 'https://swarm.example.com', |
| swarmingTaskId: '390b', |
| numComments: 2, |
| }, |
| ], |
| }; |
| const response = newSuccessResponse(responseData); |
| window.fetch.returns(Promise.resolve(response)); |
| const data = await element.getProgress(change, revision); |
| assert.deepEqual(data, responseData); |
| }); |
| |
| test('getProgress with invalid argument response', async () => { |
| const response = new window.Response('Invalid Argument', { |
| status: 400, |
| headers: {'X-Prpc-Grpc-Code': '3'}, |
| }); |
| window.fetch.returns(Promise.resolve(response)); |
| assertRejects( |
| async () => element.getProgress(change, revision), |
| 'X-Prpc-Grpc-Code: 3\nHTTP status: 400\nBody: Invalid Argument'); |
| }); |
| |
| |
| test('getProgress with not found response', async () => { |
| // If no progress was found, we don't necessarily want |
| // to treat this as an error case because it may just |
| // not be finished yet. |
| const response = new window.Response('Not found', { |
| status: 404, |
| headers: {'X-Prpc-Grpc-Code': '5'}, |
| }); |
| window.fetch.returns(Promise.resolve(response)); |
| const data = await element.getProgress(change, revision); |
| assert.isNull(data); |
| }); |
| |
| test('getProgress with invalid response', async () => { |
| const response = new window.Response('No pRPC code', { |
| status: 200, |
| }); |
| window.fetch.returns(Promise.resolve(response)); |
| assertRejects( |
| async () => await element.getProgress(change, revision), |
| 'X-Prpc-Grpc-Code: NaN\nHTTP status: 200\nBody: No pRPC code'); |
| }); |
| |
| test('reportNotUseful with valid comment', async () => { |
| const responseData = {responseField: 123}; |
| const response = newSuccessResponse(responseData); |
| window.fetch.returns(Promise.resolve(response)); |
| const data = await element.reportNotUseful(comment); |
| assert.deepEqual(data, responseData); |
| }); |
| |
| test('reportNotUseful with invalid empty comment', async () => { |
| const response = newSuccessResponse({responseField: 123}); |
| window.fetch.returns(Promise.resolve(response)); |
| assertRejects( |
| async () => await element.reportNotUseful({properties: {}}), |
| 'No tricium_comment_uuid field in comment.properties: {}'); |
| }); |
| |
| test('_message describes response contents', async () => { |
| const successResponse = newSuccessResponse({responseField: 123}); |
| const message = await element._message(successResponse); |
| assert.equal( |
| message, |
| 'X-Prpc-Grpc-Code: 0\nHTTP status: 200\n' + |
| 'Body: )]}\'{"responseField":123}'); |
| }); |
| |
| test('_parseRpcJson parses pRPC JSON', async () => { |
| const response = newSuccessResponse({mydata: 42}); |
| const data = await element._parseRpcJson(response); |
| assert.deepEqual(data, {mydata: 42}); |
| }); |
| |
| test('_parseRpcJson raises with invalid JSON', async () => { |
| const response = new window.Response('not valid JSON', { |
| status: 500, |
| headers: {'X-Prpc-Grpc-Code': '1'}, |
| }); |
| assertRejects(async () => await element._parseRpcJson(response)); |
| }); |
| |
| test('_rpcCode with an error code present', () => { |
| const response = new window.Response('Invalid Argument', { |
| status: 400, |
| headers: {'X-Prpc-Grpc-Code': '3'}, |
| }); |
| assert.equal(element._rpcCode(response), 3); |
| }); |
| |
| test('_rpcCode with missing header', () => { |
| const response = new window.Response('Not pRPC', { |
| status: 200, |
| }); |
| assert.isNaN(element._rpcCode(response)); |
| }); |
| }); |
| </script> |