| /* | |
| * 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'], | |
| ); | |
| }, | |
| ); | |
| }); |