@elench/testkit 0.1.40 → 0.1.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -13
- package/lib/cli/args.mjs +0 -4
- package/lib/cli/args.test.mjs +0 -5
- package/lib/cli/index.mjs +0 -9
- package/lib/config/index.mjs +67 -24
- package/lib/database/index.mjs +19 -7
- package/lib/database/naming.mjs +2 -2
- package/lib/database/naming.test.mjs +2 -2
- package/lib/runner/default-runtime-runner.mjs +31 -53
- package/lib/runner/execution-config.mjs +14 -70
- package/lib/runner/execution-config.test.mjs +22 -74
- package/lib/runner/formatting.mjs +0 -15
- package/lib/runner/formatting.test.mjs +0 -18
- package/lib/runner/lifecycle.mjs +7 -7
- package/lib/runner/orchestrator.mjs +9 -10
- package/lib/runner/planning.mjs +42 -136
- package/lib/runner/planning.test.mjs +70 -174
- package/lib/runner/playwright-config.mjs +8 -2
- package/lib/runner/playwright-config.test.mjs +20 -5
- package/lib/runner/playwright-runner.mjs +32 -54
- package/lib/runner/readiness.mjs +2 -2
- package/lib/runner/reporting.mjs +2 -3
- package/lib/runner/reporting.test.mjs +2 -5
- package/lib/runner/results.mjs +1 -1
- package/lib/runner/results.test.mjs +1 -1
- package/lib/runner/runtime-contexts.mjs +20 -24
- package/lib/runner/runtime-manager.mjs +181 -0
- package/lib/runner/runtime-manager.test.mjs +181 -0
- package/lib/runner/services.mjs +4 -4
- package/lib/runner/state.mjs +1 -2
- package/lib/runner/state.test.mjs +2 -4
- package/lib/runner/template.mjs +90 -60
- package/lib/runner/template.test.mjs +59 -27
- package/lib/runner/worker-loop.mjs +29 -32
- package/lib/setup/index.d.ts +14 -10
- package/package.json +1 -1
- package/lib/runner/stack-manager.mjs +0 -146
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
parseFileTimeoutOption,
|
|
5
5
|
} from "../shared/file-timeout.mjs";
|
|
6
6
|
|
|
7
|
-
export const
|
|
7
|
+
export const DATABASE_BINDINGS = new Set(["shared", "per-runtime"]);
|
|
8
8
|
|
|
9
9
|
export { DEFAULT_FILE_TIMEOUT_SECONDS, parseFileTimeoutOption };
|
|
10
10
|
|
|
@@ -12,19 +12,19 @@ export function parseWorkersOption(value) {
|
|
|
12
12
|
return parsePositiveInteger(value, "--workers");
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export function
|
|
16
|
-
return parsePositiveInteger(value,
|
|
15
|
+
export function parseRuntimeInstancesOption(value, label = "runtime.instances") {
|
|
16
|
+
return parsePositiveInteger(value, label);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export function
|
|
20
|
-
return
|
|
19
|
+
export function normalizeRuntimeInstances(value, label = "runtime.instances") {
|
|
20
|
+
return normalizePositiveInteger(value, label);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export function
|
|
23
|
+
export function normalizeDatabaseBinding(value, label = "database.binding") {
|
|
24
24
|
const normalized = String(value || "").trim();
|
|
25
|
-
if (!
|
|
25
|
+
if (!DATABASE_BINDINGS.has(normalized)) {
|
|
26
26
|
throw new Error(
|
|
27
|
-
`Invalid ${label} value "${value}". Expected one of: shared,
|
|
27
|
+
`Invalid ${label} value "${value}". Expected one of: shared, per-runtime.`
|
|
28
28
|
);
|
|
29
29
|
}
|
|
30
30
|
return normalized;
|
|
@@ -33,78 +33,22 @@ export function normalizeStackModeValue(value, label = "execution.stackMode") {
|
|
|
33
33
|
export function resolveExecutionConfig({ cli = {}, repo = {} } = {}) {
|
|
34
34
|
return normalizeExecutionConfig({
|
|
35
35
|
workers: cli.workers ?? repo.workers ?? 1,
|
|
36
|
-
stackMode: cli.stackMode ?? repo.stackMode ?? "isolated",
|
|
37
|
-
stackCount: cli.stackCount ?? repo.stackCount ?? null,
|
|
38
36
|
fileTimeoutSeconds:
|
|
39
37
|
cli.fileTimeoutSeconds ?? repo.fileTimeoutSeconds ?? DEFAULT_FILE_TIMEOUT_SECONDS,
|
|
40
38
|
});
|
|
41
39
|
}
|
|
42
40
|
|
|
43
41
|
export function normalizeExecutionConfig(input = {}) {
|
|
44
|
-
const workers = normalizePositiveInteger(input.workers, "execution.workers");
|
|
45
|
-
const stackMode = normalizeStackMode(input.stackMode);
|
|
46
|
-
const explicitStackCount =
|
|
47
|
-
input.stackCount == null ? null : normalizePositiveInteger(input.stackCount, "execution.stackCount");
|
|
48
|
-
const fileTimeoutSeconds = normalizeFileTimeoutSeconds(
|
|
49
|
-
input.fileTimeoutSeconds ?? DEFAULT_FILE_TIMEOUT_SECONDS
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
if (stackMode === "shared") {
|
|
53
|
-
if (explicitStackCount !== null && explicitStackCount !== 1) {
|
|
54
|
-
throw new Error(`execution.stackCount must be 1 when stackMode is "shared".`);
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
workers,
|
|
58
|
-
stackMode,
|
|
59
|
-
stackCount: 1,
|
|
60
|
-
fileTimeoutSeconds,
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (stackMode === "pooled") {
|
|
65
|
-
return {
|
|
66
|
-
workers,
|
|
67
|
-
stackMode,
|
|
68
|
-
stackCount: explicitStackCount ?? 1,
|
|
69
|
-
fileTimeoutSeconds,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (explicitStackCount !== null && explicitStackCount !== workers) {
|
|
74
|
-
throw new Error(
|
|
75
|
-
`execution.stackCount must equal execution.workers when stackMode is "isolated".`
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
42
|
return {
|
|
79
|
-
workers,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
43
|
+
workers: normalizePositiveInteger(input.workers ?? 1, "execution.workers"),
|
|
44
|
+
fileTimeoutSeconds: normalizeFileTimeoutSeconds(
|
|
45
|
+
input.fileTimeoutSeconds ?? DEFAULT_FILE_TIMEOUT_SECONDS
|
|
46
|
+
),
|
|
83
47
|
};
|
|
84
48
|
}
|
|
85
49
|
|
|
86
|
-
export function
|
|
87
|
-
|
|
88
|
-
return ["shared"];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return Array.from({ length: execution.stackCount }, (_unused, index) => `stack-${index + 1}`);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function resolveBatchStackMode(defaultMode, suiteMode = null) {
|
|
95
|
-
if (suiteMode == null) return defaultMode;
|
|
96
|
-
return normalizeStackMode(suiteMode);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function resolveBatchAccessMode({ framework, type, stackMode }) {
|
|
100
|
-
if (stackMode === "isolated") return "exclusive";
|
|
101
|
-
if ((framework || "k6") === "playwright") return "exclusive";
|
|
102
|
-
if (type === "dal") return "exclusive";
|
|
103
|
-
return "shared";
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function normalizeStackMode(value) {
|
|
107
|
-
return normalizeStackModeValue(value, "execution.stackMode");
|
|
50
|
+
export function buildRuntimeIds(count) {
|
|
51
|
+
return Array.from({ length: count }, (_unused, index) => `runtime-${index + 1}`);
|
|
108
52
|
}
|
|
109
53
|
|
|
110
54
|
function parsePositiveInteger(value, label) {
|
|
@@ -1,111 +1,59 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
buildRuntimeIds,
|
|
4
|
+
DATABASE_BINDINGS,
|
|
4
5
|
DEFAULT_FILE_TIMEOUT_SECONDS,
|
|
6
|
+
normalizeDatabaseBinding,
|
|
5
7
|
normalizeExecutionConfig,
|
|
8
|
+
normalizeRuntimeInstances,
|
|
6
9
|
parseFileTimeoutOption,
|
|
7
|
-
|
|
8
|
-
parseStackModeOption,
|
|
10
|
+
parseRuntimeInstancesOption,
|
|
9
11
|
parseWorkersOption,
|
|
10
|
-
resolveBatchAccessMode,
|
|
11
|
-
resolveBatchStackMode,
|
|
12
12
|
resolveExecutionConfig,
|
|
13
13
|
} from "./execution-config.mjs";
|
|
14
14
|
|
|
15
15
|
describe("execution-config", () => {
|
|
16
|
-
it("parses worker and
|
|
16
|
+
it("parses worker and runtime-instance options", () => {
|
|
17
17
|
expect(parseWorkersOption("8")).toBe(8);
|
|
18
|
+
expect(parseRuntimeInstancesOption("2")).toBe(2);
|
|
18
19
|
expect(parseFileTimeoutOption("45")).toBe(45);
|
|
19
|
-
expect(parseStackCountOption("2")).toBe(2);
|
|
20
|
-
expect(parseStackModeOption("pooled")).toBe("pooled");
|
|
21
20
|
expect(() => parseWorkersOption("0")).toThrow('Invalid --workers value "0"');
|
|
21
|
+
expect(() => parseRuntimeInstancesOption("0")).toThrow('Invalid runtime.instances value "0"');
|
|
22
22
|
expect(() => parseFileTimeoutOption("0")).toThrow(
|
|
23
23
|
'Invalid --file-timeout-seconds value "0"'
|
|
24
24
|
);
|
|
25
|
-
expect(() => parseStackModeOption("legacy")).toThrow('Invalid --stack-mode value "legacy"');
|
|
26
25
|
});
|
|
27
26
|
|
|
28
|
-
it("normalizes
|
|
29
|
-
expect(normalizeExecutionConfig({ workers: 8
|
|
27
|
+
it("normalizes execution defaults", () => {
|
|
28
|
+
expect(normalizeExecutionConfig({ workers: 8 })).toEqual({
|
|
30
29
|
workers: 8,
|
|
31
30
|
fileTimeoutSeconds: DEFAULT_FILE_TIMEOUT_SECONDS,
|
|
32
|
-
stackMode: "shared",
|
|
33
|
-
stackCount: 1,
|
|
34
31
|
});
|
|
35
|
-
|
|
36
|
-
expect(normalizeExecutionConfig({ workers: 8, stackMode: "pooled", stackCount: 3 })).toEqual({
|
|
37
|
-
workers: 8,
|
|
38
|
-
fileTimeoutSeconds: DEFAULT_FILE_TIMEOUT_SECONDS,
|
|
39
|
-
stackMode: "pooled",
|
|
40
|
-
stackCount: 3,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
expect(normalizeExecutionConfig({ workers: 8, stackMode: "isolated" })).toEqual({
|
|
44
|
-
workers: 8,
|
|
45
|
-
fileTimeoutSeconds: DEFAULT_FILE_TIMEOUT_SECONDS,
|
|
46
|
-
stackMode: "isolated",
|
|
47
|
-
stackCount: 8,
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("rejects invalid stack-count combinations", () => {
|
|
52
|
-
expect(() =>
|
|
53
|
-
normalizeExecutionConfig({ workers: 8, stackMode: "shared", stackCount: 2 })
|
|
54
|
-
).toThrow('execution.stackCount must be 1 when stackMode is "shared"');
|
|
55
|
-
|
|
56
|
-
expect(() =>
|
|
57
|
-
normalizeExecutionConfig({ workers: 8, stackMode: "isolated", stackCount: 2 })
|
|
58
|
-
).toThrow('execution.stackCount must equal execution.workers when stackMode is "isolated"');
|
|
59
32
|
});
|
|
60
33
|
|
|
61
34
|
it("applies CLI values over repo execution defaults", () => {
|
|
62
35
|
expect(
|
|
63
36
|
resolveExecutionConfig({
|
|
64
|
-
repo: { workers: 3,
|
|
65
|
-
cli: { workers: 6, fileTimeoutSeconds: 90
|
|
37
|
+
repo: { workers: 3, fileTimeoutSeconds: 30 },
|
|
38
|
+
cli: { workers: 6, fileTimeoutSeconds: 90 },
|
|
66
39
|
})
|
|
67
40
|
).toEqual({
|
|
68
41
|
workers: 6,
|
|
69
42
|
fileTimeoutSeconds: 90,
|
|
70
|
-
stackMode: "pooled",
|
|
71
|
-
stackCount: 2,
|
|
72
43
|
});
|
|
73
44
|
});
|
|
74
45
|
|
|
75
|
-
it("builds
|
|
76
|
-
expect(
|
|
77
|
-
expect(buildStackIds({ stackMode: "pooled", stackCount: 2 })).toEqual([
|
|
78
|
-
"stack-1",
|
|
79
|
-
"stack-2",
|
|
80
|
-
]);
|
|
46
|
+
it("builds runtime ids from an instance count", () => {
|
|
47
|
+
expect(buildRuntimeIds(3)).toEqual(["runtime-1", "runtime-2", "runtime-3"]);
|
|
81
48
|
});
|
|
82
49
|
|
|
83
|
-
it("
|
|
84
|
-
expect(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
stackMode: "shared",
|
|
92
|
-
})
|
|
93
|
-
).toBe("shared");
|
|
94
|
-
|
|
95
|
-
expect(
|
|
96
|
-
resolveBatchAccessMode({
|
|
97
|
-
framework: "playwright",
|
|
98
|
-
type: "e2e",
|
|
99
|
-
stackMode: "pooled",
|
|
100
|
-
})
|
|
101
|
-
).toBe("exclusive");
|
|
102
|
-
|
|
103
|
-
expect(
|
|
104
|
-
resolveBatchAccessMode({
|
|
105
|
-
framework: "k6",
|
|
106
|
-
type: "dal",
|
|
107
|
-
stackMode: "shared",
|
|
108
|
-
})
|
|
109
|
-
).toBe("exclusive");
|
|
50
|
+
it("normalizes runtime instances and database bindings", () => {
|
|
51
|
+
expect(normalizeRuntimeInstances(2)).toBe(2);
|
|
52
|
+
for (const binding of DATABASE_BINDINGS) {
|
|
53
|
+
expect(normalizeDatabaseBinding(binding)).toBe(binding);
|
|
54
|
+
}
|
|
55
|
+
expect(() => normalizeDatabaseBinding("legacy")).toThrow(
|
|
56
|
+
'Invalid database.binding value "legacy"'
|
|
57
|
+
);
|
|
110
58
|
});
|
|
111
59
|
});
|
|
@@ -36,21 +36,6 @@ export function longestServiceName(results) {
|
|
|
36
36
|
return results.reduce((max, result) => Math.max(max, result.name.length), 4);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
export function formatBatchDescriptor(batch) {
|
|
40
|
-
const fileLabel = `${batch.tasks.length} file${batch.tasks.length === 1 ? "" : "s"}`;
|
|
41
|
-
const frameworkLabel = formatFrameworkLabel(batch.framework);
|
|
42
|
-
return frameworkLabel ? ` (${frameworkLabel}, ${fileLabel})` : ` (${fileLabel})`;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function formatPlaywrightBatchFiles(batch) {
|
|
46
|
-
if (!batch?.tasks?.length) return "";
|
|
47
|
-
const files = batch.tasks.map((task) => task.file);
|
|
48
|
-
if (files.length === 1) return ` · ${files[0]}`;
|
|
49
|
-
const preview = files.slice(0, 3).join(", ");
|
|
50
|
-
const suffix = files.length > 3 ? `, +${files.length - 3} more` : "";
|
|
51
|
-
return ` · ${preview}${suffix}`;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
39
|
export function formatFrameworkLabel(framework) {
|
|
55
40
|
if (!framework || framework === "k6") return "";
|
|
56
41
|
return framework;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
buildRunSummaryLines,
|
|
4
|
-
formatBatchDescriptor,
|
|
5
4
|
formatDuration,
|
|
6
5
|
formatError,
|
|
7
6
|
formatFrameworkLabel,
|
|
8
|
-
formatPlaywrightBatchFiles,
|
|
9
7
|
formatServiceSummary,
|
|
10
8
|
formatSuiteFramework,
|
|
11
9
|
longestServiceName,
|
|
@@ -53,22 +51,6 @@ describe("runner formatting", () => {
|
|
|
53
51
|
).toBe("1/2 suites passed, 1/3 files passed, 1 suite skipped");
|
|
54
52
|
});
|
|
55
53
|
|
|
56
|
-
it("formats batch descriptors", () => {
|
|
57
|
-
expect(formatBatchDescriptor({ framework: "k6", tasks: [{}, {}] })).toBe(" (2 files)");
|
|
58
|
-
expect(formatBatchDescriptor({ framework: "playwright", tasks: [{}] })).toBe(
|
|
59
|
-
" (playwright, 1 file)"
|
|
60
|
-
);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it("formats Playwright file previews", () => {
|
|
64
|
-
expect(formatPlaywrightBatchFiles({ tasks: [{ file: "a" }] })).toBe(" · a");
|
|
65
|
-
expect(
|
|
66
|
-
formatPlaywrightBatchFiles({
|
|
67
|
-
tasks: [{ file: "a" }, { file: "b" }, { file: "c" }, { file: "d" }],
|
|
68
|
-
})
|
|
69
|
-
).toBe(" · a, b, c, +1 more");
|
|
70
|
-
});
|
|
71
|
-
|
|
72
54
|
it("formats framework labels", () => {
|
|
73
55
|
expect(formatFrameworkLabel("k6")).toBe("");
|
|
74
56
|
expect(formatFrameworkLabel("playwright")).toBe("playwright");
|
package/lib/runner/lifecycle.mjs
CHANGED
|
@@ -21,7 +21,7 @@ export function createRunLifecycle(productDir) {
|
|
|
21
21
|
interruptReason: null,
|
|
22
22
|
services: [],
|
|
23
23
|
graphDirs: [],
|
|
24
|
-
|
|
24
|
+
runtimeDirs: [],
|
|
25
25
|
runtimeStateDirs: [],
|
|
26
26
|
};
|
|
27
27
|
const signalListeners = [];
|
|
@@ -66,7 +66,7 @@ export function createRunLifecycle(productDir) {
|
|
|
66
66
|
trackGraphContext(context) {
|
|
67
67
|
mutate((draft) => {
|
|
68
68
|
pushUnique(draft.graphDirs, context.graphDir);
|
|
69
|
-
pushUnique(draft.
|
|
69
|
+
pushUnique(draft.runtimeDirs, context.runtimeDir);
|
|
70
70
|
for (const runtimeConfig of context.runtimeConfigs || []) {
|
|
71
71
|
if (runtimeConfig.stateDir) pushUnique(draft.runtimeStateDirs, runtimeConfig.stateDir);
|
|
72
72
|
}
|
|
@@ -78,7 +78,7 @@ export function createRunLifecycle(productDir) {
|
|
|
78
78
|
draft.services = draft.services.filter((service) => service.pid !== child.pid);
|
|
79
79
|
draft.services.push({
|
|
80
80
|
serviceName: config.name,
|
|
81
|
-
|
|
81
|
+
runtimeLabel: config.runtimeLabel,
|
|
82
82
|
command: config.testkit.local?.start || null,
|
|
83
83
|
cwd,
|
|
84
84
|
pid: child.pid,
|
|
@@ -195,8 +195,8 @@ export function findPortOwner(productDir, { host, port }) {
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
export function formatRunSummary(manifest) {
|
|
198
|
-
const
|
|
199
|
-
return `${manifest.runId} pid=${manifest.pid}${
|
|
198
|
+
const runtimeLabels = [...new Set((manifest.services || []).map((service) => service.runtimeLabel).filter(Boolean))];
|
|
199
|
+
return `${manifest.runId} pid=${manifest.pid}${runtimeLabels.length > 0 ? ` runtimes=${runtimeLabels.join(",")}` : ""}`;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
export function isPidRunning(pid) {
|
|
@@ -220,8 +220,8 @@ async function cleanupRunManifest(productDir, manifest, { removeRuntimeState = f
|
|
|
220
220
|
await destroyRuntimeDatabase({ productDir, stateDir });
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
-
for (const
|
|
224
|
-
fs.rmSync(
|
|
223
|
+
for (const runtimeDir of [...new Set(manifest.runtimeDirs || [])].sort((a, b) => b.length - a.length)) {
|
|
224
|
+
fs.rmSync(runtimeDir, { recursive: true, force: true });
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
for (const graphDir of [...new Set(manifest.graphDirs || [])].sort((a, b) => b.length - a.length)) {
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
applyShard,
|
|
3
3
|
buildRuntimeGraphs,
|
|
4
4
|
buildTaskQueue,
|
|
5
|
-
|
|
5
|
+
claimNextTask,
|
|
6
6
|
collectSuites,
|
|
7
7
|
resolveRuntimeConfigs,
|
|
8
8
|
} from "./planning.mjs";
|
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
safeUsername,
|
|
37
37
|
} from "./metadata.mjs";
|
|
38
38
|
import { resolveExecutionConfig } from "./execution-config.mjs";
|
|
39
|
-
import {
|
|
39
|
+
import { createRuntimeManager } from "./runtime-manager.mjs";
|
|
40
40
|
import { createWorker, runWorker } from "./worker-loop.mjs";
|
|
41
41
|
import { findUnmatchedRequestedFiles, isFullRunSelection } from "./selection.mjs";
|
|
42
42
|
import { uploadTelemetryArtifact } from "../telemetry/index.mjs";
|
|
@@ -105,7 +105,7 @@ export async function runAll(configs, typeValues, suiteSelectors, opts, allConfi
|
|
|
105
105
|
const trackers = buildServiceTrackers(servicePlans, startedAt);
|
|
106
106
|
const executedPlans = servicePlans.filter((plan) => !plan.skipped);
|
|
107
107
|
let workerCount = 0;
|
|
108
|
-
let
|
|
108
|
+
let runtimeInstanceCount = 0;
|
|
109
109
|
let exitCode = 0;
|
|
110
110
|
const lifecycle = createRunLifecycle(productDir);
|
|
111
111
|
lifecycle.markRunning();
|
|
@@ -119,14 +119,13 @@ export async function runAll(configs, typeValues, suiteSelectors, opts, allConfi
|
|
|
119
119
|
const graphs = buildRuntimeGraphs(executedPlans);
|
|
120
120
|
const queue = buildTaskQueue(executedPlans, graphs, timings);
|
|
121
121
|
workerCount = Math.max(1, Math.min(execution.workers, queue.length));
|
|
122
|
-
|
|
122
|
+
runtimeInstanceCount = graphs.reduce((sum, graph) => sum + graph.instanceCount, 0);
|
|
123
123
|
const workers = Array.from({ length: workerCount }, (_unused, index) =>
|
|
124
124
|
createWorker(index + 1, productDir)
|
|
125
125
|
);
|
|
126
|
-
const
|
|
126
|
+
const runtimeManager = createRuntimeManager({
|
|
127
127
|
productDir,
|
|
128
128
|
graphs,
|
|
129
|
-
execution,
|
|
130
129
|
lifecycle,
|
|
131
130
|
});
|
|
132
131
|
const timingUpdates = [];
|
|
@@ -137,11 +136,11 @@ export async function runAll(configs, typeValues, suiteSelectors, opts, allConfi
|
|
|
137
136
|
runWorker(
|
|
138
137
|
worker,
|
|
139
138
|
queue,
|
|
140
|
-
|
|
139
|
+
runtimeManager,
|
|
141
140
|
trackers,
|
|
142
141
|
timingUpdates,
|
|
143
142
|
lifecycle,
|
|
144
|
-
|
|
143
|
+
claimNextTask,
|
|
145
144
|
recordTaskOutcome,
|
|
146
145
|
recordGraphError
|
|
147
146
|
)
|
|
@@ -157,7 +156,7 @@ export async function runAll(configs, typeValues, suiteSelectors, opts, allConfi
|
|
|
157
156
|
}
|
|
158
157
|
}
|
|
159
158
|
} finally {
|
|
160
|
-
await
|
|
159
|
+
await runtimeManager.cleanupAll();
|
|
161
160
|
}
|
|
162
161
|
|
|
163
162
|
saveTimings(productDir, timings, timingUpdates);
|
|
@@ -174,7 +173,7 @@ export async function runAll(configs, typeValues, suiteSelectors, opts, allConfi
|
|
|
174
173
|
finishedAt,
|
|
175
174
|
execution,
|
|
176
175
|
workerCount,
|
|
177
|
-
|
|
176
|
+
runtimeInstanceCount,
|
|
178
177
|
typeValues,
|
|
179
178
|
suiteSelectors,
|
|
180
179
|
fileNames: requestedFiles,
|