mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-07 21:07:46 +00:00
[tests] Run unit tests concurrently in chunks (#9615)
We can separate each package `test-unit` into a separate job. This will help isolate problems and we can re-run CI for a specific package.
This commit is contained in:
4
packages/node/test/integration-setup.js
vendored
4
packages/node/test/integration-setup.js
vendored
@@ -1,6 +1,6 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { intoChunks, NUMBER_OF_CHUNKS } = require('../../../utils/chunk-tests');
|
const { intoChunks } = require('../../../utils/chunk-tests');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
testDeployment,
|
testDeployment,
|
||||||
@@ -20,7 +20,7 @@ module.exports = function setupTests(groupIndex) {
|
|||||||
let fixtures = fs.readdirSync(fixturesPath);
|
let fixtures = fs.readdirSync(fixturesPath);
|
||||||
|
|
||||||
if (typeof groupIndex !== 'undefined') {
|
if (typeof groupIndex !== 'undefined') {
|
||||||
fixtures = intoChunks(NUMBER_OF_CHUNKS, fixtures)[groupIndex - 1];
|
fixtures = intoChunks(1, 5, fixtures)[groupIndex - 1];
|
||||||
|
|
||||||
console.log('testing group', groupIndex, fixtures);
|
console.log('testing group', groupIndex, fixtures);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { intoChunks, NUMBER_OF_CHUNKS } = require('../../../utils/chunk-tests');
|
const { intoChunks } = require('../../../utils/chunk-tests');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
testDeployment,
|
testDeployment,
|
||||||
@@ -33,7 +33,7 @@ module.exports = function setupTests(groupIndex) {
|
|||||||
let fixtures = fs.readdirSync(fixturesPath);
|
let fixtures = fs.readdirSync(fixturesPath);
|
||||||
|
|
||||||
if (typeof groupIndex !== 'undefined') {
|
if (typeof groupIndex !== 'undefined') {
|
||||||
fixtures = intoChunks(NUMBER_OF_CHUNKS, fixtures)[groupIndex - 1];
|
fixtures = intoChunks(1, 5, fixtures)[groupIndex - 1];
|
||||||
|
|
||||||
console.log('testing group', groupIndex, fixtures);
|
console.log('testing group', groupIndex, fixtures);
|
||||||
}
|
}
|
||||||
|
|||||||
43
utils/chunk-tests.js
vendored
43
utils/chunk-tests.js
vendored
@@ -1,12 +1,19 @@
|
|||||||
|
// @ts-check
|
||||||
const child_process = require('child_process');
|
const child_process = require('child_process');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const NUMBER_OF_CHUNKS = 5;
|
|
||||||
const MINIMUM_PER_CHUNK = 1;
|
|
||||||
const runnersMap = new Map([
|
const runnersMap = new Map([
|
||||||
['test-e2e', ['ubuntu-latest']],
|
[
|
||||||
['test-next-local', ['ubuntu-latest']],
|
'test-unit',
|
||||||
['test-dev', ['ubuntu-latest', 'macos-latest']],
|
{
|
||||||
|
min: 1,
|
||||||
|
max: 1,
|
||||||
|
runners: ['ubuntu-latest', 'macos-latest', 'windows-latest'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
['test-e2e', { min: 1, max: 5, runners: ['ubuntu-latest'] }],
|
||||||
|
['test-next-local', { min: 1, max: 5, runners: ['ubuntu-latest'] }],
|
||||||
|
['test-dev', { min: 1, max: 5, runners: ['ubuntu-latest', 'macos-latest'] }],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
async function getChunkedTests() {
|
async function getChunkedTests() {
|
||||||
@@ -60,11 +67,14 @@ async function getChunkedTests() {
|
|||||||
([packagePathAndName, scriptNames]) => {
|
([packagePathAndName, scriptNames]) => {
|
||||||
const [packagePath, packageName] = packagePathAndName.split(',');
|
const [packagePath, packageName] = packagePathAndName.split(',');
|
||||||
return Object.entries(scriptNames).flatMap(([scriptName, testPaths]) => {
|
return Object.entries(scriptNames).flatMap(([scriptName, testPaths]) => {
|
||||||
|
const {
|
||||||
|
runners = ['ubuntu-latest'],
|
||||||
|
min = 1,
|
||||||
|
max = 1,
|
||||||
|
} = runnersMap.get(scriptName) || {};
|
||||||
const sortedTestPaths = testPaths.sort((a, b) => a.localeCompare(b));
|
const sortedTestPaths = testPaths.sort((a, b) => a.localeCompare(b));
|
||||||
return intoChunks(NUMBER_OF_CHUNKS, sortedTestPaths).flatMap(
|
return intoChunks(min, max, sortedTestPaths).flatMap(
|
||||||
(chunk, chunkNumber, allChunks) => {
|
(chunk, chunkNumber, allChunks) => {
|
||||||
const runners = runnersMap.get(scriptName) || ['ubuntu-latest'];
|
|
||||||
|
|
||||||
return runners.map(runner => {
|
return runners.map(runner => {
|
||||||
return {
|
return {
|
||||||
runner,
|
runner,
|
||||||
@@ -115,7 +125,7 @@ async function turbo(args) {
|
|||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
reject(new Error(`Turbo exited with code ${code}`));
|
reject(new Error(`Turbo exited with code ${code}`));
|
||||||
} else {
|
} else {
|
||||||
resolve();
|
resolve(code);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -128,17 +138,15 @@ async function turbo(args) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @template T
|
* @template T
|
||||||
* @param {number} totalChunks maximum number of chunks
|
* @param {number} minChunks minimum number of chunks
|
||||||
* @param {T[]} values
|
* @param {number} maxChunks maximum number of chunks
|
||||||
|
* @param {T[]} arr
|
||||||
* @returns {T[][]}
|
* @returns {T[][]}
|
||||||
*/
|
*/
|
||||||
function intoChunks(totalChunks, arr) {
|
function intoChunks(minChunks, maxChunks, arr) {
|
||||||
const chunkSize = Math.max(
|
const chunkSize = Math.max(minChunks, Math.ceil(arr.length / maxChunks));
|
||||||
MINIMUM_PER_CHUNK,
|
|
||||||
Math.ceil(arr.length / totalChunks)
|
|
||||||
);
|
|
||||||
const chunks = [];
|
const chunks = [];
|
||||||
for (let i = 0; i < totalChunks; i++) {
|
for (let i = 0; i < maxChunks; i++) {
|
||||||
chunks.push(arr.slice(i * chunkSize, (i + 1) * chunkSize));
|
chunks.push(arr.slice(i * chunkSize, (i + 1) * chunkSize));
|
||||||
}
|
}
|
||||||
return chunks.filter(x => x.length > 0);
|
return chunks.filter(x => x.length > 0);
|
||||||
@@ -161,5 +169,4 @@ if (module === require.main || !module.parent) {
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
intoChunks,
|
intoChunks,
|
||||||
NUMBER_OF_CHUNKS,
|
|
||||||
};
|
};
|
||||||
|
|||||||
17
utils/chunk-tests.test.js
vendored
17
utils/chunk-tests.test.js
vendored
@@ -3,16 +3,27 @@ const { intoChunks } = require('./chunk-tests');
|
|||||||
describe('it should create chunks correctly', () => {
|
describe('it should create chunks correctly', () => {
|
||||||
it('should split chunks correctly less chunks than items', () => {
|
it('should split chunks correctly less chunks than items', () => {
|
||||||
const files = ['/first', '/second', '/third'];
|
const files = ['/first', '/second', '/third'];
|
||||||
expect(intoChunks(2, files)).toEqual([['/first', '/second'], ['/third']]);
|
expect(intoChunks(1, 2, files)).toEqual([
|
||||||
|
['/first', '/second'],
|
||||||
|
['/third'],
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should split chunks correctly more chunks than items', () => {
|
it('should split chunks correctly more chunks than items', () => {
|
||||||
const files = ['/first', '/second', '/third'];
|
const files = ['/first', '/second', '/third'];
|
||||||
expect(intoChunks(5, files)).toEqual([['/first'], ['/second'], ['/third']]);
|
expect(intoChunks(1, 5, files)).toEqual([
|
||||||
|
['/first'],
|
||||||
|
['/second'],
|
||||||
|
['/third'],
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should split chunks correctly equal chunks with items', () => {
|
it('should split chunks correctly equal chunks with items', () => {
|
||||||
const files = ['/first', '/second', '/third'];
|
const files = ['/first', '/second', '/third'];
|
||||||
expect(intoChunks(3, files)).toEqual([['/first'], ['/second'], ['/third']]);
|
expect(intoChunks(1, 3, files)).toEqual([
|
||||||
|
['/first'],
|
||||||
|
['/second'],
|
||||||
|
['/third'],
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user