fix(test): avoid walking extension test plans

This commit is contained in:
Vincent Koc
2026-05-16 09:02:05 +08:00
parent c4810e33f4
commit 7ccd3b8e8e
2 changed files with 86 additions and 0 deletions

View File

@@ -1,3 +1,4 @@
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { channelTestRoots } from "../../test/vitest/vitest.channel-paths.mjs";
@@ -64,7 +65,46 @@ function normalizeRelative(inputPath) {
return inputPath.split(path.sep).join("/");
}
function isPathInsideRepo(relativePath) {
return relativePath !== ".." && !relativePath.startsWith("../") && !path.isAbsolute(relativePath);
}
function isSkippedTrackedTestFile(relativePath) {
return relativePath.split("/").some((segment) => segment === "dist" || segment === "node_modules");
}
function listTrackedTestFiles(rootPath) {
const relativeRoot = normalizeRelative(path.relative(repoRoot, rootPath));
if (!isPathInsideRepo(relativeRoot)) {
return null;
}
const result = spawnSync("git", ["ls-files", "--", relativeRoot], {
cwd: repoRoot,
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
});
if (result.status !== 0) {
return null;
}
return result.stdout
.split("\n")
.map((line) => line.trim().replaceAll("\\", "/"))
.filter(
(line) =>
line.length > 0 &&
!isSkippedTrackedTestFile(line) &&
(line.endsWith(".test.ts") || line.endsWith(".test.tsx")),
);
}
function countTestFiles(rootPath) {
const trackedFiles = listTrackedTestFiles(rootPath);
if (trackedFiles) {
return trackedFiles.length;
}
let total = 0;
const stack = [rootPath];

View File

@@ -424,6 +424,52 @@ describe("scripts/test-extension.mjs", () => {
]);
});
it("counts tracked extension tests without walking extension directories", () => {
const output = execFileSync(
process.execPath,
[
"--input-type=module",
"--eval",
`
import fs from "node:fs";
import { syncBuiltinESMExports } from "node:module";
const counts = { readdirSync: 0 };
const originalReaddirSync = fs.readdirSync;
fs.readdirSync = (...args) => {
counts.readdirSync += 1;
return originalReaddirSync(...args);
};
syncBuiltinESMExports();
const { createExtensionTestShards, resolveExtensionBatchPlan } = await import("./scripts/lib/extension-test-plan.mjs");
const extensionIds = ["matrix", "openai", "slack", "telegram"];
const batch = resolveExtensionBatchPlan({ cwd: process.cwd(), extensionIds });
const shards = createExtensionTestShards({ cwd: process.cwd(), extensionIds, shardCount: 2 });
console.log(JSON.stringify({
batchTests: batch.testFileCount,
counts,
shards: shards.length,
shardTests: shards.reduce((total, shard) => total + shard.testFileCount, 0),
}));
`,
],
{
cwd: process.cwd(),
encoding: "utf8",
},
);
const payload = JSON.parse(output) as {
batchTests: number;
counts: { readdirSync: number };
shards: number;
shardTests: number;
};
expect(payload.batchTests).toBeGreaterThan(0);
expect(payload.shards).toBe(2);
expect(payload.shardTests).toBe(payload.batchTests);
expect(payload.counts.readdirSync).toBe(0);
});
it("balances extension test shards by estimated CI cost", () => {
const shards = createExtensionTestShards({
cwd: process.cwd(),