| /** |
| * @license |
| * Copyright 2021 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. |
| */ |
| |
| import {assert} from '@open-wc/testing'; |
| import { |
| ChecksFetcher, |
| BuildbucketBuild, |
| BuildbucketBuilder, |
| BinarySizeRow, |
| BinarySizeConfig, |
| BuilderPair, |
| } from './binary-size'; |
| import { |
| ChangeInfo, |
| ChangeStatus, |
| NumericChangeId, |
| PatchSetNum, |
| RevisionKind, |
| } from '@gerritcodereview/typescript-api/rest-api'; |
| import {Category, ChangeData} from '@gerritcodereview/typescript-api/checks'; |
| import {PluginApi} from '@gerritcodereview/typescript-api/plugin'; |
| |
| suite('binary-size basic tests', () => { |
| let fetcher: ChecksFetcher; |
| |
| function stubSearch(searchPromise: object) { |
| class MockBuildbucketV2Client { |
| constructor() {} |
| |
| async searchBuilds() { |
| return searchPromise; |
| } |
| |
| async batch() { |
| return searchPromise; |
| } |
| } |
| |
| window.buildbucket = { |
| getAccessToken: async () => null, |
| compareBuildIds: (a: string, b: string) => { |
| const d = b.length - a.length; |
| if (d !== 0) { |
| return d; |
| } |
| if (a > b) { |
| return -1; |
| } |
| if (a < b) { |
| return 1; |
| } |
| return 0; |
| }, |
| convertLegacyBucket: (a: string) => { |
| const sep = a.indexOf('.', 5); |
| return { |
| project: a.slice(5, sep), |
| bucket: a.slice(sep + 1), |
| }; |
| }, |
| identicalBucket: (a: BuildbucketBuilder, b: BuildbucketBuilder) => |
| a.project === b.project && a.bucket === b.bucket, |
| BuildbucketV2Client: MockBuildbucketV2Client, |
| }; |
| return sinon.spy(MockBuildbucketV2Client.prototype, 'searchBuilds'); |
| } |
| |
| setup(() => { |
| const plugin = { |
| getPluginName() { |
| return 'binary-size'; |
| }, |
| restApi() { |
| return { |
| getLoggedIn: async () => true, |
| }; |
| }, |
| }; |
| |
| fetcher = new ChecksFetcher(plugin as PluginApi, 'host'); |
| }); |
| |
| teardown(() => { |
| sinon.restore(); |
| }); |
| |
| test('getBuilds empty batch response', async () => { |
| stubSearch(Promise.resolve({})); |
| const builders = [ |
| {project: 'project', bucket: 'some.bucket', builder: 'builder1'}, |
| {project: 'project', bucket: 'a.b.c', builder: 'builder2'}, |
| ]; |
| assert.deepEqual( |
| await fetcher.getBuilds(1 as NumericChangeId, builders, [], []), |
| [] |
| ); |
| }); |
| |
| test('getBuilds', async () => { |
| stubSearch( |
| Promise.resolve({ |
| responses: [ |
| { |
| searchBuilds: { |
| builds: [{id: 'build1'}, {id: 'build2'}], |
| }, |
| }, |
| ], |
| }) |
| ); |
| const builders: BuildbucketBuilder[] = [ |
| {project: 'project', bucket: 'some.bucket', builder: 'builder1'}, |
| {project: 'project', bucket: 'a.b.c', builder: 'builder2'}, |
| ]; |
| assert.deepEqual( |
| await fetcher.getBuilds( |
| 1 as NumericChangeId, |
| builders, |
| [], |
| [{key: 'buildset', value: 'foo/bar'}] |
| ), |
| [{id: 'build1'}, {id: 'build2'}] as BuildbucketBuild[] |
| ); |
| }); |
| |
| test('selectRelevantBuilds', () => { |
| const builds = [ |
| {output: {properties: {got_revision: 'abc', binary_sizes: {}}}}, |
| {output: {properties: {got_revision: 'abc'}}}, |
| {output: {}}, |
| {}, |
| ] as BuildbucketBuild[]; |
| assert.deepEqual(fetcher.selectRelevantBuilds(builds), [builds[0]]); |
| }); |
| |
| test('sortUniqueInfoRows sorts', () => { |
| const rows = [ |
| {builder: 'abc', binary: 'b.so', id: '2'}, |
| {builder: 'abc', binary: 'a.so', id: '1'}, |
| ] as BinarySizeRow[]; |
| assert.deepEqual(fetcher.sortUniqueInfoRows(rows), [rows[1], rows[0]]); |
| }); |
| |
| test('sortUniqueInfoRows keeps only latest', () => { |
| const rows = [ |
| {builder: 'abc', binary: 'a.so', id: '3'}, |
| {builder: 'abc', binary: 'b.so', id: '2'}, |
| {builder: 'abc', binary: 'a.so', id: '1'}, |
| ] as BinarySizeRow[]; |
| // Remember: build IDs are monotonically decreasing. |
| assert.deepEqual(fetcher.sortUniqueInfoRows(rows), [rows[2], rows[1]]); |
| }); |
| |
| test('getUniqueTryAndCiBuilders', () => { |
| fetcher.pluginConfig = { |
| builders: [ |
| { |
| tryBucket: 'luci.project.try', |
| tryBuilder: 'builder1', |
| ciBucket: 'luci.project.ci', |
| ciBuilder: 'Builder 1', |
| }, |
| { |
| tryBucket: 'luci.project.try', |
| tryBuilder: 'builder2', |
| // This should be deduplicated. |
| ciBucket: 'luci.project.ci', |
| ciBuilder: 'Builder 1', |
| }, |
| ], |
| } as BinarySizeConfig; |
| assert.deepEqual(fetcher.getUniqueTryAndCiBuilders(), [ |
| [ |
| {bucket: 'luci.project.try', builder: 'builder1'}, |
| {bucket: 'luci.project.try', builder: 'builder2'}, |
| ], |
| [{bucket: 'luci.project.ci', builder: 'Builder 1'}], |
| ]); |
| }); |
| |
| test('revisionTags', () => { |
| fetcher.pluginConfig = {gitHost: 'host'} as BinarySizeConfig; |
| const change = {project: 'src'} as ChangeInfo; |
| const tryBuildToBuilderPair = new Map([ |
| [{output: {properties: {got_revision: 'beef'}}}, {ciBuilderRepo: ''}], |
| [{output: {properties: {got_revision: 'a3ee'}}}, {ciBuilderRepo: ''}], |
| [{output: {properties: {got_revision: 'beef'}}}, {ciBuilderRepo: ''}], |
| [ |
| {output: {properties: {got_revision: 'a3ee'}}}, |
| {ciBuilderRepo: 'src/other'}, |
| ], |
| [ |
| {output: {properties: {got_revision: 'a3ee'}}}, |
| {ciBuilderGitHost: 'other-host'}, |
| ], |
| ]) as Map<BuildbucketBuild, BuilderPair>; |
| assert.deepEqual(fetcher.revisionTags(tryBuildToBuilderPair, change), [ |
| {key: 'buildset', value: 'commit/gitiles/host/src/+/beef'}, |
| {key: 'buildset', value: 'commit/gitiles/host/src/+/a3ee'}, |
| {key: 'buildset', value: 'commit/gitiles/host/src/other/+/a3ee'}, |
| {key: 'buildset', value: 'commit/gitiles/other-host/src/+/a3ee'}, |
| ]); |
| }); |
| |
| const BUILDERS = [ |
| { |
| tryBucket: 'luci.project.try', |
| tryBuilder: 'builder1', |
| ciBucket: 'luci.project.ci', |
| ciBuilder: 'Builder 1', |
| }, |
| { |
| tryBucket: 'luci.project.try', |
| tryBuilder: 'builder2', |
| ciBucket: 'luci.project.ci', |
| ciBuilder: 'Builder 2', |
| }, |
| { |
| tryBucket: 'luci.other.try', |
| tryBuilder: 'builder1', |
| ciBucket: 'luci.other.ci', |
| ciBuilder: 'Builder 1', |
| }, |
| ] as BuilderPair[]; |
| Object.freeze(BUILDERS); |
| |
| test('binarySizeInfo basic', () => { |
| assert.deepEqual( |
| fetcher.processBinarySizeInfo( |
| BUILDERS, |
| [ |
| { |
| builder: {builder: 'builder1', project: 'project', bucket: 'try'}, |
| tags: [{key: 'builder', value: 'builder1'}], |
| id: '7', |
| url: 'http://example.org/builder1/7', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1337, |
| 'a.owner': 'owner', |
| 'a.budget': 1339, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[], |
| [ |
| { |
| builder: {builder: 'Builder 1', project: 'project', bucket: 'ci'}, |
| tags: [{key: 'builder', value: 'Builder 1'}], |
| id: '8', |
| url: 'http://example.org/Builder%201/8', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1338, |
| 'a.owner': 'owner', |
| 'a.budget': 1339, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[] |
| ).rows, |
| [ |
| { |
| id: '7', |
| builder: 'builder1', |
| binary: 'a', |
| trySize: 1337, |
| tryUrl: 'http://example.org/builder1/7', |
| ciSize: 1338, |
| ciUrl: 'http://example.org/Builder%201/8', |
| tryBudget: 1339, |
| budgetExceeded: false, |
| tryCreepBudget: undefined, |
| creepExceeded: false, |
| ownerUrl: 'owner', |
| }, |
| ] |
| ); |
| }); |
| |
| test('binarySizeInfo with no budgets', () => { |
| assert.deepEqual( |
| fetcher.processBinarySizeInfo( |
| BUILDERS, |
| [ |
| { |
| builder: {builder: 'builder1', project: 'project', bucket: 'try'}, |
| tags: [{key: 'builder', value: 'builder1'}], |
| id: '7', |
| url: 'http://example.org/builder1/7', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1337, |
| 'a.owner': 'owner', |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[], |
| [ |
| { |
| builder: {builder: 'Builder 1', project: 'project', bucket: 'ci'}, |
| tags: [{key: 'builder', value: 'Builder 1'}], |
| id: '8', |
| url: 'http://example.org/Builder%201/8', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1338, |
| 'a.owner': 'owner', |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[] |
| ).rows, |
| [ |
| { |
| id: '7', |
| builder: 'builder1', |
| binary: 'a', |
| trySize: 1337, |
| tryUrl: 'http://example.org/builder1/7', |
| ciSize: 1338, |
| ciUrl: 'http://example.org/Builder%201/8', |
| tryBudget: undefined, |
| budgetExceeded: false, |
| tryCreepBudget: undefined, |
| creepExceeded: false, |
| ownerUrl: 'owner', |
| }, |
| ] |
| ); |
| }); |
| |
| test('binarySizeInfo with exceeded budget', () => { |
| assert.deepEqual( |
| fetcher.processBinarySizeInfo( |
| BUILDERS, |
| [ |
| { |
| builder: {builder: 'builder1', project: 'project', bucket: 'try'}, |
| tags: [{key: 'builder', value: 'builder1'}], |
| id: '7', |
| url: 'http://example.org/builder1/7', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1337, |
| 'a.owner': 'owner', |
| 'a.budget': 1, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[], |
| [ |
| { |
| builder: {builder: 'Builder 1', project: 'project', bucket: 'ci'}, |
| tags: [{key: 'builder', value: 'Builder 1'}], |
| id: '8', |
| url: 'http://example.org/Builder%201/8', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1338, |
| 'a.owner': 'owner', |
| 'a.budget': 1, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[] |
| ).rows, |
| [ |
| { |
| id: '7', |
| builder: 'builder1', |
| binary: 'a', |
| trySize: 1337, |
| tryUrl: 'http://example.org/builder1/7', |
| ciSize: 1338, |
| ciUrl: 'http://example.org/Builder%201/8', |
| tryBudget: 1, |
| budgetExceeded: true, |
| tryCreepBudget: undefined, |
| creepExceeded: false, |
| ownerUrl: 'owner', |
| }, |
| ] |
| ); |
| }); |
| |
| test('binarySizeInfo with creep budget', () => { |
| assert.deepEqual( |
| fetcher.processBinarySizeInfo( |
| BUILDERS, |
| [ |
| { |
| builder: {builder: 'builder1', project: 'project', bucket: 'try'}, |
| tags: [{key: 'builder', value: 'builder1'}], |
| id: '7', |
| url: 'http://example.org/builder1/7', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1337, |
| 'a.owner': 'owner', |
| 'a.budget': 2, |
| 'a.creepBudget': 1, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[], |
| [ |
| { |
| builder: {builder: 'Builder 1', project: 'project', bucket: 'ci'}, |
| tags: [{key: 'builder', value: 'Builder 1'}], |
| id: '8', |
| url: 'http://example.org/Builder%201/8', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1338, |
| 'a.owner': 'owner', |
| 'a.budget': 2, |
| 'a.creepBudget': 1, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[] |
| ).rows, |
| [ |
| { |
| id: '7', |
| builder: 'builder1', |
| binary: 'a', |
| trySize: 1337, |
| tryUrl: 'http://example.org/builder1/7', |
| ciSize: 1338, |
| ciUrl: 'http://example.org/Builder%201/8', |
| tryBudget: 2, |
| budgetExceeded: true, |
| tryCreepBudget: 1, |
| creepExceeded: false, |
| ownerUrl: 'owner', |
| }, |
| ] |
| ); |
| }); |
| |
| test('binarySizeInfo with exceeded creep budget', () => { |
| assert.deepEqual( |
| fetcher.processBinarySizeInfo( |
| BUILDERS, |
| [ |
| { |
| builder: {builder: 'builder1', project: 'project', bucket: 'try'}, |
| tags: [{key: 'builder', value: 'builder1'}], |
| id: '7', |
| url: 'http://example.org/builder1/7', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1340, |
| 'a.owner': 'owner', |
| 'a.budget': 2, |
| 'a.creepBudget': 1, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[], |
| [ |
| { |
| builder: {builder: 'Builder 1', project: 'project', bucket: 'ci'}, |
| tags: [{key: 'builder', value: 'Builder 1'}], |
| id: '8', |
| url: 'http://example.org/Builder%201/8', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1337, |
| 'a.owner': 'owner', |
| 'a.budget': 2, |
| 'a.creepBudget': 1, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[] |
| ).rows, |
| [ |
| { |
| id: '7', |
| builder: 'builder1', |
| binary: 'a', |
| trySize: 1340, |
| tryUrl: 'http://example.org/builder1/7', |
| ciSize: 1337, |
| ciUrl: 'http://example.org/Builder%201/8', |
| tryBudget: 2, |
| budgetExceeded: true, |
| tryCreepBudget: 1, |
| creepExceeded: true, |
| ownerUrl: 'owner', |
| }, |
| ] |
| ); |
| }); |
| |
| test('binarySizeInfo no match on bucket', () => { |
| assert.deepEqual( |
| fetcher.processBinarySizeInfo( |
| BUILDERS, |
| [ |
| { |
| builder: {builder: 'builder1', project: 'project', bucket: 'try'}, |
| tags: [{key: 'builder', value: 'builder1'}], |
| id: '7', |
| url: 'http://example.org/builder1/7', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1337, |
| 'a.owner': 'owner', |
| 'a.budget': 1, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[], |
| [ |
| { |
| builder: { |
| builder: 'Builder 1', |
| project: 'project', |
| bucket: 'other', |
| }, |
| tags: [{key: 'builder', value: 'Builder 1'}], |
| id: '8', |
| url: 'http://example.org/Builder%201/8', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1338, |
| 'a.owner': 'owner', |
| 'a.budget': 1, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[] |
| ).rows, |
| [] |
| ); |
| }); |
| |
| test('binarySizeInfo no match on binary', () => { |
| assert.deepEqual( |
| fetcher.processBinarySizeInfo( |
| BUILDERS, |
| [ |
| { |
| builder: {builder: 'builder1', project: 'project', bucket: 'try'}, |
| tags: [{key: 'builder', value: 'builder1'}], |
| id: '7', |
| url: 'http://example.org/builder1/7', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1337, |
| 'a.owner': 'owner', |
| 'a.budget': 1, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[], |
| [ |
| { |
| builder: {builder: 'Builder 1', project: 'project', bucket: 'ci'}, |
| tags: [{key: 'builder', value: 'Builder 1'}], |
| id: '8', |
| url: 'http://example.org/Builder%201/8', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| b: 1338, |
| 'b.owner': 'owner', |
| 'b.budget': 1, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[] |
| ).rows, |
| [] |
| ); |
| }); |
| |
| test('binarySizeInfo multiple try builds', () => { |
| const result = fetcher.processBinarySizeInfo( |
| BUILDERS, |
| [ |
| { |
| builder: {builder: 'builder1', project: 'project', bucket: 'try'}, |
| tags: [{key: 'builder', value: 'builder1'}], |
| id: '7', |
| url: 'http://example.org/builder1/7', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1337, |
| b: 2222, |
| }, |
| }, |
| }, |
| }, |
| { |
| builder: {builder: 'builder1', project: 'project', bucket: 'try'}, |
| tags: [{key: 'builder', value: 'builder1'}], |
| id: '7', |
| url: 'http://example.org/builder1/7', |
| output: { |
| properties: { |
| got_revision: 'da39a3ee', |
| binary_sizes: { |
| a: 1111, |
| }, |
| }, |
| }, |
| }, |
| { |
| builder: {builder: 'builder1', project: 'project', bucket: 'try'}, |
| tags: [{key: 'builder', value: 'builder1'}], |
| id: '7', |
| url: 'http://example.org/builder1/7', |
| output: { |
| properties: { |
| got_revision: 'da39a3ee', |
| binary_sizes: { |
| a: 1110, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[], |
| [ |
| { |
| builder: {builder: 'Builder 1', project: 'project', bucket: 'ci'}, |
| tags: [{key: 'builder', value: 'Builder 1'}], |
| id: '8', |
| url: 'http://example.org/Builder%201/8', |
| output: { |
| properties: { |
| got_revision: 'deadbeef', |
| binary_sizes: { |
| a: 1338, |
| b: 2223, |
| }, |
| }, |
| }, |
| }, |
| { |
| builder: {builder: 'Builder 1', project: 'project', bucket: 'ci'}, |
| tags: [{key: 'builder', value: 'Builder 1'}], |
| id: '8', |
| url: 'http://example.org/Builder%201/8', |
| output: { |
| properties: { |
| got_revision: 'da39a3ee', |
| binary_sizes: { |
| a: 1112, |
| }, |
| }, |
| }, |
| }, |
| ] as BuildbucketBuild[] |
| ).rows; |
| assert.equal(result.length, 2); |
| assert.equal(result[0].builder, 'builder1'); |
| assert.equal(result[0].binary, 'a'); |
| assert.equal(result[0].ciSize, 1338); |
| assert.equal(result[1].builder, 'builder1'); |
| assert.equal(result[1].binary, 'b'); |
| assert.equal(result[1].ciSize, 2223); |
| }); |
| |
| test('valid patch numbers', () => { |
| let change = { |
| revisions: { |
| rev1: {_number: 1, kind: RevisionKind.TRIVIAL_REBASE}, |
| rev2: {_number: 2, kind: RevisionKind.TRIVIAL_REBASE}, |
| rev3: {_number: 3, kind: RevisionKind.TRIVIAL_REBASE}, |
| }, |
| } as any; // eslint-disable-line @typescript-eslint/no-explicit-any |
| assert.deepEqual(fetcher.computeValidPatchNums(change, 3 as PatchSetNum), [ |
| 3, 2, 1, |
| ] as PatchSetNum[]); |
| assert.deepEqual(fetcher.computeValidPatchNums(change, 2 as PatchSetNum), [ |
| 2, 1, |
| ] as PatchSetNum[]); |
| |
| change.status = ChangeStatus.MERGED; |
| assert.deepEqual(fetcher.computeValidPatchNums(change, 3 as PatchSetNum), [ |
| 2, 1, |
| ] as PatchSetNum[]); |
| |
| change = { |
| revisions: { |
| rev1: {_number: 1, kind: RevisionKind.TRIVIAL_REBASE}, |
| rev2: {_number: 2, kind: RevisionKind.REWORK}, |
| rev3: {_number: 3, kind: RevisionKind.TRIVIAL_REBASE}, |
| }, |
| }; |
| assert.deepEqual(fetcher.computeValidPatchNums(change, 3 as PatchSetNum), [ |
| 3, 2, |
| ] as PatchSetNum[]); |
| }); |
| |
| test('fetchChecks creates results with messages and summaries', async () => { |
| sinon.stub(fetcher, 'isEnabled').returns(Promise.resolve(true)); |
| fetcher.pluginConfig = { |
| builders: [ |
| { |
| tryBucket: 'luci.project.try', |
| tryBuilder: 'builder1', |
| ciBucket: 'luci.project.ci', |
| ciBuilder: 'Builder 1', |
| }, |
| ], |
| } as BinarySizeConfig; |
| const changeData = { |
| changeNumber: 1, |
| patchsetNumber: 1, |
| changeInfo: {}, |
| } as ChangeData; |
| const stub = sinon.stub(fetcher, 'processBinarySizeInfo'); |
| |
| // No size changes, no budgets exceeded. |
| stub.returns({ |
| rows: [ |
| {binary: 'foo', budgetExceeded: false, trySize: 100, ciSize: 100}, |
| {binary: 'bar', budgetExceeded: false, trySize: 100, ciSize: 100}, |
| {binary: 'baz', budgetExceeded: false, trySize: 100, ciSize: 100}, |
| ], |
| } as any); // eslint-disable-line @typescript-eslint/no-explicit-any |
| let fetchRes = await fetcher.fetchChecks(changeData); |
| let res = fetchRes.runs![0].results![0]; |
| assert.strictEqual( |
| res.summary, |
| 'All 3 files within budgets. No sizes changed.' |
| ); |
| assert.strictEqual(res.message, 'Expand to view more.'); |
| |
| // 2 size changes, no budgets exceeded. |
| stub.returns({ |
| rows: [ |
| {binary: 'foo', budgetExceeded: false, trySize: 100, ciSize: 100}, |
| {binary: 'bar', budgetExceeded: false, trySize: 123, ciSize: 100}, |
| {binary: 'baz', budgetExceeded: false, trySize: 123, ciSize: 100}, |
| ], |
| } as any); // eslint-disable-line @typescript-eslint/no-explicit-any |
| fetchRes = await fetcher.fetchChecks(changeData); |
| res = fetchRes.runs![0].results![0]; |
| assert.strictEqual( |
| res.summary, |
| 'All 3 files within budgets. 2 of 3 sizes changed.' |
| ); |
| assert.strictEqual( |
| res.message, |
| 'Sizes changed: bar (+23 B), baz (+23 B). Expand to view more.' |
| ); |
| |
| // 3 size changes, 2 budgets exceeded. |
| stub.returns({ |
| rows: [ |
| {binary: 'foo', budgetExceeded: false, trySize: 123, ciSize: 100}, |
| {binary: 'bar', budgetExceeded: true, trySize: 123, ciSize: 100}, |
| {binary: 'baz', creepExceeded: true, trySize: 123, ciSize: 100}, |
| ], |
| } as any); // eslint-disable-line @typescript-eslint/no-explicit-any |
| fetchRes = await fetcher.fetchChecks(changeData); |
| res = fetchRes.runs![0].results![0]; |
| assert.strictEqual( |
| res.summary, |
| '2 of 3 budgets exceeded. 3 of 3 sizes changed.' |
| ); |
| assert.strictEqual( |
| res.message, |
| 'Exceeded budgets: bar (+23 B), baz (+23 B). Expand to view more.' |
| ); |
| }); |
| |
| test('getCheckRunAttempt', () => { |
| assert.deepEqual( |
| fetcher.getCheckRunAttempt([ |
| {builder: {builder: 'a'}}, |
| ] as BuildbucketBuild[]), |
| 1 |
| ); |
| assert.deepEqual( |
| fetcher.getCheckRunAttempt([ |
| {builder: {builder: 'a'}}, |
| {builder: {builder: 'b'}}, |
| ] as BuildbucketBuild[]), |
| 1 |
| ); |
| assert.deepEqual( |
| fetcher.getCheckRunAttempt([ |
| {builder: {builder: 'a'}}, |
| {builder: {builder: 'a'}}, |
| {builder: {builder: 'b'}}, |
| ] as BuildbucketBuild[]), |
| 2 |
| ); |
| assert.deepEqual( |
| fetcher.getCheckRunAttempt([ |
| {builder: {builder: 'a'}}, |
| {builder: {builder: 'a'}}, |
| {builder: {builder: 'b'}}, |
| {builder: {builder: 'b'}}, |
| {builder: {builder: 'b'}}, |
| ] as BuildbucketBuild[]), |
| 3 |
| ); |
| }); |
| |
| test('getCheckResultCategory', () => { |
| // If all no budgets were exceeded, category should be INFO. |
| let binarySizeRows = [ |
| {budgetExceeded: false}, |
| {budgetExceeded: false}, |
| ] as BinarySizeRow[]; |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'SUCCESS'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.INFO |
| ); |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'FAILURE'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.INFO |
| ); |
| |
| // If at least one budget was exceeded, category should be based on |
| // builds. |
| binarySizeRows = [ |
| {budgetExceeded: true}, |
| {budgetExceeded: false}, |
| ] as BinarySizeRow[]; |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'SUCCESS'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.WARNING |
| ); |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'SUCCESS'}, {status: 'FAILURE'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.ERROR |
| ); |
| |
| // If no creep budgets were exceeded, category should be INFO. |
| binarySizeRows = [ |
| {creepExceeded: false}, |
| {creepExceeded: false}, |
| ] as BinarySizeRow[]; |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'SUCCESS'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.INFO |
| ); |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'FAILURE'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.INFO |
| ); |
| |
| // If at least one creep budget was exceeded, category should be based on |
| // builds. |
| binarySizeRows = [ |
| {creepExceeded: false}, |
| {creepExceeded: true}, |
| ] as BinarySizeRow[]; |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'SUCCESS'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.WARNING |
| ); |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'SUCCESS'}, {status: 'FAILURE'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.ERROR |
| ); |
| |
| // If no budgets were exceeded and no creep budgets were exceeded, |
| // category should be INFO. |
| binarySizeRows = [ |
| {creepExceeded: false, budgetExceeded: false}, |
| {creepExceeded: false, budgetExceeded: false}, |
| ] as BinarySizeRow[]; |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'SUCCESS'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.INFO |
| ); |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'FAILURE'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.INFO |
| ); |
| |
| // If no budgets were exceeded but at least one creep budget was exceeded, |
| // category should be based on builds. |
| binarySizeRows = [ |
| {creepExceeded: false, budgetExceeded: false}, |
| {creepExceeded: true, budgetExceeded: false}, |
| ] as BinarySizeRow[]; |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'SUCCESS'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.WARNING |
| ); |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'SUCCESS'}, {status: 'FAILURE'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.ERROR |
| ); |
| |
| // If no creep budgets were exceeded but at least budget was exceeded, |
| // category should be based on builds. |
| binarySizeRows = [ |
| {creepExceeded: false, budgetExceeded: false}, |
| {creepExceeded: false, budgetExceeded: true}, |
| ] as BinarySizeRow[]; |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'SUCCESS'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.WARNING |
| ); |
| assert.deepEqual( |
| fetcher.getCheckResultCategory( |
| [{status: 'SUCCESS'}, {status: 'FAILURE'}] as BuildbucketBuild[], |
| binarySizeRows |
| ), |
| Category.ERROR |
| ); |
| }); |
| }); |