Skip to content

Commit bcc4aaf

Browse files
committed
fixup! feat(bazel/integration): support tracking sizes within the integration test rule directly
1 parent fd9135a commit bcc4aaf

File tree

2 files changed

+128
-108
lines changed

2 files changed

+128
-108
lines changed

bazel/integration/test_runner/runner.mts

Lines changed: 4 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {existsSync} from 'node:fs';
109
import fs from 'node:fs/promises';
1110
import path from 'node:path';
1211
import os from 'node:os';
@@ -31,14 +30,7 @@ import {
3130
} from './process_utils.mjs';
3231
import {ENVIRONMENT_TMP_PLACEHOLDER} from './constants.mjs';
3332
import {debug} from './debug.mjs';
34-
import chalk from 'chalk';
35-
36-
// Convience access to chalk colors.
37-
const {red, green} = chalk;
38-
/** The size discrepancy we allow in bytes. */
39-
const THRESHOLD_BYTES = 5000;
40-
/** The size discrepancy as a percentage. */
41-
const THRESHOLD_PERCENT = 5;
33+
import {SizeTracker} from './size-tracking.mjs';
4234

4335
/** Error class that is used when an integration command fails. */
4436
class IntegrationTestCommandError extends Error {}
@@ -56,6 +48,7 @@ type EnvironmentConfig = Record<string, BazelExpandedValue>;
5648
*/
5749
export class TestRunner {
5850
private readonly environment: EnvironmentConfig;
51+
private readonly sizeTracker: SizeTracker;
5952

6053
constructor(
6154
private readonly isTestDebugMode: boolean,
@@ -68,6 +61,7 @@ export class TestRunner {
6861
environment: EnvironmentConfig,
6962
) {
7063
this.environment = this._assignDefaultEnvironmentVariables(environment);
64+
this.sizeTracker = new SizeTracker(this.testPackage);
7165
}
7266

7367
async run() {
@@ -91,6 +85,7 @@ export class TestRunner {
9185

9286
try {
9387
await this._runTestCommands(testWorkingDir, testEnv);
88+
await this.sizeTracker.run(testWorkingDir, testEnv);
9489
} finally {
9590
debug('Finished running integration test commands.');
9691

@@ -279,11 +274,6 @@ export class TestRunner {
279274
console.info(
280275
`Successfully ran all commands in test directory: ${path.normalize(testWorkingDir)}`,
281276
);
282-
283-
// If the integration test provides a size.json file we use it as a size tracking marker.
284-
if (existsSync(path.join(testWorkingDir, 'size.json'))) {
285-
await this._runSizeTracking(testWorkingDir, commandEnv);
286-
}
287277
}
288278

289279
/**
@@ -313,98 +303,4 @@ export class TestRunner {
313303

314304
return {...defaults, ...baseEnv};
315305
}
316-
317-
/**
318-
* Runs the size tracking scripting.
319-
*
320-
* Builds the integration test application and then checks if the size of the generated files varies too
321-
* far from our known file sizes.
322-
*/
323-
private async _runSizeTracking(
324-
testWorkingDir: string,
325-
commandEnv: NodeJS.ProcessEnv,
326-
): Promise<void> {
327-
const success = await runCommandInChildProcess('yarn', ['build'], testWorkingDir, commandEnv);
328-
if (!success) {
329-
throw Error('Failed to build for size tracking.');
330-
}
331-
332-
const sizes: {[key: string]: SizeCheckResult} = {};
333-
334-
const expectedSizes = JSON.parse(
335-
await fs.readFile(path.join(testWorkingDir, 'size.json'), 'utf-8'),
336-
) as {[key: string]: number};
337-
338-
for (let [filename, expectedSize] of Object.entries(expectedSizes)) {
339-
const generedFilePath = path.join(testWorkingDir, 'dist', filename);
340-
if (!existsSync(generedFilePath)) {
341-
sizes[filename] = {
342-
actual: undefined,
343-
failing: false,
344-
expected: expectedSize,
345-
details: 'missing',
346-
};
347-
} else {
348-
const {size: actualSize} = await fs.stat(path.join(testWorkingDir, 'dist', filename));
349-
const absoluteSizeDiff = Math.abs(actualSize - expectedSize);
350-
const percentSizeDiff = (absoluteSizeDiff / expectedSize) * 100;
351-
const direction = actualSize === expectedSize ? '' : actualSize > expectedSize ? '+' : '-';
352-
sizes[filename] = {
353-
actual: actualSize,
354-
expected: expectedSize,
355-
failing: absoluteSizeDiff > THRESHOLD_BYTES || percentSizeDiff > THRESHOLD_PERCENT,
356-
details: {
357-
raw: `${direction}${absoluteSizeDiff.toFixed(0)}`,
358-
percent: `${direction}${percentSizeDiff.toFixed(3)}`,
359-
},
360-
};
361-
}
362-
}
363-
364-
console.info(Array(80).fill('=').join(''));
365-
console.info(
366-
`${Array(28).fill('=').join('')} SIZE TRACKING RESULTS ${Array(29).fill('=').join('')}`,
367-
);
368-
console.info(Array(80).fill('=').join(''));
369-
let failed = false;
370-
for (let [filename, {actual, expected, failing, details}] of Object.entries(sizes)) {
371-
failed = failed || failing;
372-
const bullet = failing ? green('✔') : red('✘');
373-
console.info(` ${bullet} ${filename}`);
374-
if (details === 'missing') {
375-
console.info(
376-
` File not found in generated integration test application, either ensure the file is created or remove it from the size tracking json file.`,
377-
);
378-
} else {
379-
console.info(
380-
` Actual Size: ${actual} | Expected Size: ${expected} | ${details.raw} bytes (${details.raw}%)`,
381-
);
382-
}
383-
}
384-
console.info();
385-
if (failed) {
386-
const sizeFileLocation = path.join(this.testPackage, 'size.json');
387-
console.info(
388-
`If this is a desired change, please update the size limits in: ${sizeFileLocation}`,
389-
);
390-
process.exitCode = 1;
391-
} else {
392-
console.info(
393-
`Payload size check passed. All diffs are less than ${THRESHOLD_PERCENT}% or ${THRESHOLD_BYTES} bytes.`,
394-
);
395-
}
396-
console.info(Array(80).fill('=').join(''));
397-
}
398-
}
399-
400-
interface SizeCheckResult {
401-
expected: number;
402-
actual: number | undefined;
403-
failing: boolean;
404-
details:
405-
| 'missing'
406-
| {
407-
raw: string;
408-
percent: string;
409-
};
410306
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {runCommandInChildProcess} from './process_utils.mjs';
10+
import {existsSync} from 'node:fs';
11+
import fs from 'node:fs/promises';
12+
import path from 'node:path';
13+
import chalk from 'chalk';
14+
import {debug} from './debug.mjs';
15+
16+
// Convience access to chalk colors.
17+
const {red, green} = chalk;
18+
/** The size discrepancy we allow in bytes. */
19+
const THRESHOLD_BYTES = 5000;
20+
/** The size discrepancy as a percentage. */
21+
const THRESHOLD_PERCENT = 5;
22+
23+
interface SizeCheckResult {
24+
expected: number;
25+
actual: number | undefined;
26+
failing: boolean;
27+
details:
28+
| 'missing'
29+
| {
30+
raw: string;
31+
percent: string;
32+
};
33+
}
34+
35+
export class SizeTracker {
36+
constructor(private readonly testPackage: string) {}
37+
38+
/**
39+
* Runs the size tracking scripting.
40+
*
41+
* Builds the integration test application and then checks if the size of the generated files varies too
42+
* far from our known file sizes.
43+
*/
44+
async run(testWorkingDir: string, commandEnv: NodeJS.ProcessEnv): Promise<void> {
45+
const sizeJsonFilePath = path.join(testWorkingDir, 'size.json');
46+
// If the integration test provides a size.json file we use it as a size tracking marker.
47+
if (!existsSync(sizeJsonFilePath)) {
48+
debug(`Skipping size tracking as no size.json file was found at ${sizeJsonFilePath}`);
49+
return;
50+
}
51+
const success = await runCommandInChildProcess('yarn', ['build'], testWorkingDir, commandEnv);
52+
if (!success) {
53+
throw Error('Failed to build for size tracking.');
54+
}
55+
56+
const sizes: {[key: string]: SizeCheckResult} = {};
57+
58+
const expectedSizes = JSON.parse(await fs.readFile(sizeJsonFilePath, 'utf-8')) as {
59+
[key: string]: number;
60+
};
61+
62+
for (let [filename, expectedSize] of Object.entries(expectedSizes)) {
63+
const generedFilePath = path.join(testWorkingDir, filename);
64+
if (!existsSync(generedFilePath)) {
65+
sizes[filename] = {
66+
actual: undefined,
67+
failing: true,
68+
expected: expectedSize,
69+
details: 'missing',
70+
};
71+
} else {
72+
const {size: actualSize} = await fs.stat(generedFilePath);
73+
const absoluteSizeDiff = Math.abs(actualSize - expectedSize);
74+
const percentSizeDiff = (absoluteSizeDiff / expectedSize) * 100;
75+
const direction = actualSize === expectedSize ? '' : actualSize > expectedSize ? '+' : '-';
76+
sizes[filename] = {
77+
actual: actualSize,
78+
expected: expectedSize,
79+
failing: absoluteSizeDiff > THRESHOLD_BYTES || percentSizeDiff > THRESHOLD_PERCENT,
80+
details: {
81+
raw: `${direction}${absoluteSizeDiff.toFixed(0)}`,
82+
percent: `${direction}${Math.round(percentSizeDiff * 1000) / 1000}`,
83+
},
84+
};
85+
}
86+
}
87+
88+
console.info();
89+
console.info(Array(80).fill('=').join(''));
90+
console.info(
91+
`${Array(28).fill('=').join('')} SIZE TRACKING RESULTS ${Array(29).fill('=').join('')}`,
92+
);
93+
console.info(Array(80).fill('=').join(''));
94+
let failed = false;
95+
for (let [filename, {actual, expected, failing, details}] of Object.entries(sizes)) {
96+
failed = failed || failing;
97+
const bullet = failing ? red('✘') : green('✔');
98+
console.info(` ${bullet} ${filename}`);
99+
if (details === 'missing') {
100+
console.info(
101+
` File not found in generated integration test application, either ensure the file is created or remove it from the size tracking json file.`,
102+
);
103+
} else {
104+
console.info(
105+
` Actual Size: ${actual} | Expected Size: ${expected} | ${details.raw} bytes (${details.percent}%)`,
106+
);
107+
}
108+
}
109+
console.info();
110+
if (failed) {
111+
const originalSizeJsonFilePath = path.join(this.testPackage, 'size.json');
112+
console.info(
113+
`If this is a desired change, please update the size limits in: ${originalSizeJsonFilePath}`,
114+
);
115+
process.exitCode = 1;
116+
} else {
117+
console.info(
118+
`Payload size check passed. All diffs are less than ${THRESHOLD_PERCENT}% or ${THRESHOLD_BYTES} bytes.`,
119+
);
120+
}
121+
console.info(Array(80).fill('=').join(''));
122+
console.info();
123+
}
124+
}

0 commit comments

Comments
 (0)