blob: f72151db2d027338f176a365ce887364770328c5 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import assert from 'node:assert/strict';
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
import { EventEmitter } from 'node:events';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import test from 'node:test';
import {
orderByDescendingWeight,
runWorkspaceTests,
testSourceWeight,
} from './run-workspace-tests-parallel.mjs';
function immediateSuccessSpawn(started) {
return (_command, options) => {
assert.ok(existsSync(options.cwd), `spawned into a missing directory: ${options.cwd}`);
started.push(options.cwd);
const child = new EventEmitter();
queueMicrotask(() => child.emit('close', 0));
return child;
};
}
async function withWorkspaceTree(files, body) {
const root = mkdtempSync(join(tmpdir(), 'maka-workspace-order-'));
try {
for (const [path, contents] of Object.entries(files)) {
const absolute = join(root, path);
mkdirSync(join(absolute, '..'), { recursive: true });
writeFileSync(absolute, contents);
}
return await body(root);
} finally {
rmSync(root, { recursive: true, force: true });
}
}
test('the heaviest workspace is scheduled first', () => {
const weights = { light: 1, heavy: 100, middle: 50 };
assert.deepEqual(
orderByDescendingWeight(['light', 'heavy', 'middle'], (dir) => weights[dir]),
['heavy', 'middle', 'light'],
);
});
test('a single workspace is never weighed', () => {
let weighed = 0;
assert.deepEqual(
orderByDescendingWeight(['only'], () => {
weighed += 1;
return 1;
}),
['only'],
);
assert.equal(weighed, 0);
});
test('equally weighted workspaces keep their declared order', () => {
assert.deepEqual(
orderByDescendingWeight(['b', 'a', 'c'], () => 7),
['b', 'a', 'c'],
);
});
test('build output and dependencies do not count toward a workspace weight', async () => {
await withWorkspaceTree(
{
'ws-one/src/a.test.ts': 'x'.repeat(40),
'ws-one/dist/a.test.js': 'x'.repeat(9000),
'ws-one/node_modules/dep/dep.test.js': 'x'.repeat(9000),
'ws-one/src/a.ts': 'x'.repeat(9000),
},
(root) => {
assert.equal(testSourceWeight(root, 'ws-one'), 40);
},
);
});
test('an unreadable workspace weighs nothing instead of failing the run', () => {
assert.equal(testSourceWeight(tmpdir(), 'no/such/workspace'), 0);
});
test('the run queues the heaviest workspace ahead of the lighter one', async () => {
await withWorkspaceTree(
{
'ws-light/src/a.test.ts': 'x'.repeat(10),
'ws-heavy/src/a.test.ts': 'x'.repeat(5000),
},
async (root) => {
const started = [];
await runWorkspaceTests({
repoRoot: root,
workspaceDirs: ['ws-light', 'ws-heavy'],
concurrency: 1,
spawn: immediateSuccessSpawn(started),
});
assert.deepEqual(
started.map((cwd) => cwd.slice(root.length + 1)),
['ws-heavy', 'ws-light'],
);
},
);
});