PR-URL: https://github.com/nodejs/node/pull/61747 Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Aviv Keller <me@aviv.sh> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
228 lines
8.1 KiB
JavaScript
228 lines
8.1 KiB
JavaScript
'use strict';
|
|
|
|
require('../common');
|
|
const assert = require('node:assert');
|
|
const { spawnSync } = require('node:child_process');
|
|
const { join } = require('node:path');
|
|
const { describe, it } = require('node:test');
|
|
const fixtures = require('../common/fixtures');
|
|
|
|
const testFixtures = fixtures.path('test-runner');
|
|
const internalOrderFixture = fixtures.path('test-runner', 'randomize', 'internal-order.cjs');
|
|
const rerunStateFile = fixtures.path('test-runner', 'rerun-state.json');
|
|
const kShardFiles = ['a.cjs', 'b.cjs', 'c.cjs', 'd.cjs', 'e.cjs', 'f.cjs', 'g.cjs', 'h.cjs', 'i.cjs', 'j.cjs'];
|
|
const kInternalTests = ['a', 'b', 'c', 'd', 'e'];
|
|
|
|
function getShardOrder(stdout) {
|
|
return Array.from(stdout.matchAll(/ok \d+ - ([a-j]\.cjs) this should pass/g), ({ 1: name }) => name);
|
|
}
|
|
|
|
function getInternalExecutionOrder(stdout) {
|
|
const match = stdout.match(/EXECUTION_ORDER:([a-e](?:,[a-e])*)/);
|
|
assert(match, `Missing EXECUTION_ORDER marker in output: ${stdout}`);
|
|
return match[1].split(',');
|
|
}
|
|
|
|
describe('test runner randomize flags via command line', () => {
|
|
it('should be deterministic with --test-random-seed', () => {
|
|
const args = [
|
|
'--test',
|
|
'--test-reporter=tap',
|
|
'--test-concurrency=1',
|
|
'--test-randomize',
|
|
'--test-random-seed=12345',
|
|
join(testFixtures, 'shards/*.cjs'),
|
|
];
|
|
const first = spawnSync(process.execPath, args);
|
|
const second = spawnSync(process.execPath, args);
|
|
|
|
assert.strictEqual(first.stderr.toString(), '');
|
|
assert.strictEqual(second.stderr.toString(), '');
|
|
assert.strictEqual(first.status, 0);
|
|
assert.strictEqual(second.status, 0);
|
|
|
|
const firstOrder = getShardOrder(first.stdout.toString());
|
|
const secondOrder = getShardOrder(second.stdout.toString());
|
|
assert.deepStrictEqual(firstOrder, secondOrder);
|
|
assert.deepStrictEqual([...firstOrder].sort(), kShardFiles);
|
|
});
|
|
|
|
it('should use different orders for different seeds', () => {
|
|
const first = spawnSync(process.execPath, [
|
|
'--test',
|
|
'--test-reporter=tap',
|
|
'--test-concurrency=1',
|
|
'--test-randomize',
|
|
'--test-random-seed=11111',
|
|
join(testFixtures, 'shards/*.cjs'),
|
|
]);
|
|
const second = spawnSync(process.execPath, [
|
|
'--test',
|
|
'--test-reporter=tap',
|
|
'--test-concurrency=1',
|
|
'--test-randomize',
|
|
'--test-random-seed=22222',
|
|
join(testFixtures, 'shards/*.cjs'),
|
|
]);
|
|
|
|
assert.strictEqual(first.stderr.toString(), '');
|
|
assert.strictEqual(second.stderr.toString(), '');
|
|
assert.strictEqual(first.status, 0);
|
|
assert.strictEqual(second.status, 0);
|
|
|
|
const firstOrder = getShardOrder(first.stdout.toString());
|
|
const secondOrder = getShardOrder(second.stdout.toString());
|
|
assert.notDeepStrictEqual(firstOrder, secondOrder);
|
|
assert.deepStrictEqual([...firstOrder].sort(), kShardFiles);
|
|
assert.deepStrictEqual([...secondOrder].sort(), kShardFiles);
|
|
});
|
|
|
|
it('should randomize deterministically with --test-random-seed alone', () => {
|
|
const args = [
|
|
'--test',
|
|
'--test-reporter=tap',
|
|
'--test-concurrency=1',
|
|
'--test-random-seed=24680',
|
|
join(testFixtures, 'shards/*.cjs'),
|
|
];
|
|
const first = spawnSync(process.execPath, args);
|
|
const second = spawnSync(process.execPath, args);
|
|
|
|
assert.strictEqual(first.stderr.toString(), '');
|
|
assert.strictEqual(second.stderr.toString(), '');
|
|
assert.strictEqual(first.status, 0);
|
|
assert.strictEqual(second.status, 0);
|
|
|
|
const firstOrder = getShardOrder(first.stdout.toString());
|
|
const secondOrder = getShardOrder(second.stdout.toString());
|
|
assert.deepStrictEqual(firstOrder, secondOrder);
|
|
assert.deepStrictEqual([...firstOrder].sort(), kShardFiles);
|
|
assert.match(first.stdout.toString(), /# Randomized test order seed: 24680/);
|
|
});
|
|
|
|
it('should print the randomization seed when --test-randomize is used', () => {
|
|
const child = spawnSync(process.execPath, [
|
|
'--test',
|
|
'--test-reporter=tap',
|
|
'--test-concurrency=1',
|
|
'--test-randomize',
|
|
join(testFixtures, 'shards/*.cjs'),
|
|
]);
|
|
|
|
assert.strictEqual(child.stderr.toString(), '');
|
|
assert.strictEqual(child.status, 0);
|
|
assert.match(child.stdout.toString(), /# Randomized test order seed: \d+/);
|
|
});
|
|
|
|
it('should randomize internal test order deterministically with --test-random-seed', () => {
|
|
const args = [
|
|
'--test',
|
|
'--test-reporter=tap',
|
|
'--test-random-seed=12345',
|
|
internalOrderFixture,
|
|
];
|
|
const first = spawnSync(process.execPath, args);
|
|
const second = spawnSync(process.execPath, args);
|
|
|
|
assert.strictEqual(first.stderr.toString(), '');
|
|
assert.strictEqual(second.stderr.toString(), '');
|
|
assert.strictEqual(first.status, 0);
|
|
assert.strictEqual(second.status, 0);
|
|
|
|
const firstOrder = getInternalExecutionOrder(first.stdout.toString());
|
|
const secondOrder = getInternalExecutionOrder(second.stdout.toString());
|
|
assert.deepStrictEqual(firstOrder, secondOrder);
|
|
assert.deepStrictEqual([...firstOrder].sort(), kInternalTests);
|
|
});
|
|
|
|
it('should randomize internal test order differently across seeds', () => {
|
|
const orders = [];
|
|
for (const seed of [11111, 22222, 33333, 44444]) {
|
|
const child = spawnSync(process.execPath, [
|
|
'--test',
|
|
'--test-reporter=tap',
|
|
`--test-random-seed=${seed}`,
|
|
internalOrderFixture,
|
|
]);
|
|
assert.strictEqual(child.stderr.toString(), '');
|
|
assert.strictEqual(child.status, 0);
|
|
|
|
const order = getInternalExecutionOrder(child.stdout.toString());
|
|
assert.deepStrictEqual([...order].sort(), kInternalTests);
|
|
orders.push(order.join(','));
|
|
}
|
|
|
|
assert.notStrictEqual(new Set(orders).size, 1);
|
|
});
|
|
|
|
it('should reject --test-randomize with --watch', () => {
|
|
const child = spawnSync(process.execPath, [
|
|
'--test',
|
|
'--watch',
|
|
'--test-randomize',
|
|
join(testFixtures, 'shards/*.cjs'),
|
|
]);
|
|
|
|
assert.strictEqual(child.stdout.toString(), '');
|
|
assert.match(child.stderr.toString(), /The property 'options\.randomize' is not supported with watch mode\./);
|
|
assert.strictEqual(child.status, 1);
|
|
assert.strictEqual(child.signal, null);
|
|
});
|
|
|
|
it('should reject --test-random-seed with --watch', () => {
|
|
const child = spawnSync(process.execPath, [
|
|
'--test',
|
|
'--watch',
|
|
'--test-random-seed=12345',
|
|
join(testFixtures, 'shards/*.cjs'),
|
|
]);
|
|
|
|
assert.strictEqual(child.stdout.toString(), '');
|
|
assert.match(child.stderr.toString(), /The property 'options\.randomSeed' is not supported with watch mode\./);
|
|
assert.strictEqual(child.status, 1);
|
|
assert.strictEqual(child.signal, null);
|
|
});
|
|
|
|
it('should reject --test-randomize with --test-rerun-failures', () => {
|
|
const child = spawnSync(process.execPath, [
|
|
'--test',
|
|
'--test-randomize',
|
|
'--test-rerun-failures',
|
|
rerunStateFile,
|
|
join(testFixtures, 'shards/*.cjs'),
|
|
]);
|
|
|
|
assert.strictEqual(child.stdout.toString(), '');
|
|
assert.match(child.stderr.toString(), /The property 'options\.randomize' is not supported with rerun failures mode\./);
|
|
assert.strictEqual(child.status, 1);
|
|
assert.strictEqual(child.signal, null);
|
|
});
|
|
|
|
it('should reject --test-random-seed with --test-rerun-failures', () => {
|
|
const child = spawnSync(process.execPath, [
|
|
'--test',
|
|
'--test-random-seed=12345',
|
|
'--test-rerun-failures',
|
|
rerunStateFile,
|
|
join(testFixtures, 'shards/*.cjs'),
|
|
]);
|
|
|
|
assert.strictEqual(child.stdout.toString(), '');
|
|
assert.match(child.stderr.toString(), /The property 'options\.randomSeed' is not supported with rerun failures mode\./);
|
|
assert.strictEqual(child.status, 1);
|
|
assert.strictEqual(child.signal, null);
|
|
});
|
|
|
|
it('should reject out of range --test-random-seed values', () => {
|
|
const child = spawnSync(process.execPath, [
|
|
'--test',
|
|
'--test-random-seed=4294967296',
|
|
join(testFixtures, 'shards/*.cjs'),
|
|
]);
|
|
|
|
assert.strictEqual(child.stdout.toString(), '');
|
|
assert.match(child.stderr.toString(), /The value of "--test-random-seed" is out of range\. It must be >= 0 && <= 4294967295\. Received 4294967296/);
|
|
assert.strictEqual(child.status, 1);
|
|
assert.strictEqual(child.signal, null);
|
|
});
|
|
});
|