t3-code-android-nightly/.repos/alchemy-effect/packages/alchemy/scripts/aws-test-lanes.ts
Julius Marminge 108e01746c
Upgrade Effect and Alchemy betas (#4643)
Prepare Relay production infrastructure for the PlanetScale PS_20 HA topology, upgrade Effect and Alchemy to compatible betas, reconcile migration state, and preserve patched MCP session termination behavior.\n\nCo-authored-by: codex <codex@users.noreply.github.com>
2026-07-27 16:21:02 +02:00

378 lines
12 KiB
TypeScript

/**
* Split the live AWS suite into disjoint quota-aware lanes.
*
* The quota lane contains every binding test, every Lambda service test, and
* every test whose local import graph reaches a Lambda fixture. The
* network lanes contain every test whose local import graph creates a VPC.
* AWS accounts default to five VPCs per Region, so those files must not inherit
* the otherwise-safe high service concurrency. Tests that hold two VPCs live
* at once run in a separate sequential lane; never overlap it with `network`.
* The distributed lane contains the complement, so it can retain very high
* file concurrency without stampeding either shared control plane.
*
* Examples (wrap live invocations in the coordinator's hard timeout):
*
* bun scripts/aws-test-lanes.ts inventory
* bun scripts/aws-test-lanes.ts network-heavy --profile testing --concurrency 1 --retry 0
* bun scripts/aws-test-lanes.ts network --profile testing --concurrency 3 --retry 0
* bun scripts/aws-test-lanes.ts quota --profile testing --concurrency 24 --retry 0
* bun scripts/aws-test-lanes.ts distributed --profile testing --concurrency 128 --retry 0
*/
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
import { dirname, extname, relative, resolve, sep } from "node:path";
type Lane = "network-heavy" | "network" | "quota" | "distributed";
const alchemyDir = resolve(import.meta.dir, "..");
const awsTestDir = resolve(alchemyDir, "test", "AWS");
const isTestFile = (name: string) =>
name.endsWith(".test.ts") || name.endsWith(".test.tsx");
const isTypeScriptFile = (name: string) =>
name.endsWith(".ts") || name.endsWith(".tsx");
const walk = (directory: string): string[] =>
readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
const path = resolve(directory, entry.name);
return entry.isDirectory()
? walk(path)
: isTypeScriptFile(entry.name)
? [path]
: [];
});
const resolveLocalImport = (from: string, specifier: string) => {
if (!specifier.startsWith(".")) return undefined;
const base = resolve(dirname(from), specifier);
const candidates = extname(base)
? [base, base.replace(/\.js$/, ".ts"), base.replace(/\.jsx$/, ".tsx")]
: [
base,
`${base}.ts`,
`${base}.tsx`,
resolve(base, "index.ts"),
resolve(base, "index.tsx"),
];
return candidates.find(
(candidate) =>
candidate.startsWith(`${awsTestDir}${sep}`) &&
existsSync(candidate) &&
statSync(candidate).isFile(),
);
};
const files = walk(awsTestDir).sort();
const tests = files.filter((file) => isTestFile(file));
const reverseImports = new Map<string, Set<string>>();
const lambdaSources = new Set<string>();
const networkSources = new Set<string>();
const importPattern =
/(?:from\s*|import\s*\(|new\s+URL\s*\()\s*["']([^"']+)["']/g;
const isEc2ResourceModule = (specifier: string) =>
specifier === "@/AWS/EC2" ||
/^@\/AWS\/EC2\/(?:Vpc|Network)(?:\.ts)?$/.test(specifier);
const escapeRegExp = (value: string) =>
value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
// Keep executable tokens while masking comments and string/template contents.
// This prevents prose such as "AWS Partner Network (...)" from becoming a
// scarce-capacity seed. Imports are parsed separately from the original text.
const maskCommentsAndStrings = (source: string) => {
const chars = [...source];
let state: "code" | "line" | "block" | "single" | "double" | "template" =
"code";
for (let index = 0; index < chars.length; index++) {
const char = chars[index];
const next = chars[index + 1];
if (state === "code") {
if (char === "/" && next === "/") {
state = "line";
chars[index] = chars[index + 1] = " ";
index++;
} else if (char === "/" && next === "*") {
state = "block";
chars[index] = chars[index + 1] = " ";
index++;
} else if (char === "'") {
state = "single";
chars[index] = " ";
} else if (char === '"') {
state = "double";
chars[index] = " ";
} else if (char === "`") {
state = "template";
chars[index] = " ";
}
continue;
}
if (state === "line") {
if (char === "\n" || char === "\r") state = "code";
else chars[index] = " ";
continue;
}
if (state === "block") {
if (char === "*" && next === "/") {
chars[index] = chars[index + 1] = " ";
index++;
state = "code";
} else if (char !== "\n" && char !== "\r") {
chars[index] = " ";
}
continue;
}
const quote = state === "single" ? "'" : state === "double" ? '"' : "`";
if (char === "\\") {
chars[index] = " ";
if (index + 1 < chars.length) {
chars[index + 1] = " ";
index++;
}
} else if (char === quote) {
chars[index] = " ";
state = "code";
} else if (char !== "\n" && char !== "\r") {
chars[index] = " ";
}
}
return chars.join("");
};
/**
* Find calls that can allocate a regional VPC without matching comments,
* strings, or unrelated identifiers such as `ServiceNetwork` and
* `listHostedZonesByVpc`. Import aliases are resolved so `Vpc as TestVpc`,
* EC2 namespace imports, and the top-level AWS namespace remain visible.
*/
const createsVpc = (source: string) => {
const resourceCalls = new Set<string>();
const ec2Namespaces = new Set<string>();
const awsNamespaces = new Set<string>();
const namedImportPattern =
/import\s*\{([\s\S]*?)\}\s*from\s*["']([^"']+)["']/g;
for (const match of source.matchAll(namedImportPattern)) {
const [, bindings, specifier] = match;
if (isEc2ResourceModule(specifier)) {
for (const binding of bindings.split(",")) {
const parts = binding
.trim()
.replace(/^type\s+/, "")
.split(/\s+as\s+/);
if (parts[0] === "Vpc" || parts[0] === "Network") {
resourceCalls.add(parts[1] ?? parts[0]);
}
}
} else if (specifier === "@/AWS") {
for (const binding of bindings.split(",")) {
const parts = binding.trim().split(/\s+as\s+/);
if (parts[0] === "EC2") {
ec2Namespaces.add(parts[1] ?? parts[0]);
}
}
}
}
const namespaceImportPattern =
/import\s*\*\s*as\s*(\w+)\s*from\s*["']([^"']+)["']/g;
for (const match of source.matchAll(namespaceImportPattern)) {
const [, alias, specifier] = match;
if (isEc2ResourceModule(specifier)) ec2Namespaces.add(alias);
else if (specifier === "@/AWS") awsNamespaces.add(alias);
}
const defaultImportPattern =
/import\s+(\w+)\s+from\s*["'](@\/AWS\/EC2\/(?:Vpc|Network)(?:\.ts)?)["']/g;
for (const match of source.matchAll(defaultImportPattern)) {
resourceCalls.add(match[1]);
}
const targets = [
...[...resourceCalls].map(escapeRegExp),
...[...ec2Namespaces].map(
(alias) => `${escapeRegExp(alias)}\\.(?:Vpc|Network)`,
),
...[...awsNamespaces].map(
(alias) => `${escapeRegExp(alias)}\\.EC2\\.(?:Vpc|Network)`,
),
];
const code = maskCommentsAndStrings(source);
if (/\bcreate(?:Default)?Vpc\s*\(/.test(code)) return true;
if (targets.length === 0) return false;
return new RegExp(`\\b(?:${targets.join("|")})(?:<[^>]+>)?\\s*\\(`).test(
code,
);
};
for (const file of files) {
const source = readFileSync(file, "utf8");
// Lambda fixtures use either the focused module or the AWS namespace.
if (
/@\/AWS\/Lambda(?:["'/]|$)|AWS\.Lambda\.Function(?:<[^>]+>)?\s*\(/.test(
source,
)
) {
lambdaSources.add(file);
}
// Include direct provider resources, the EC2 Network composite, distilled
// default-VPC helpers, and every local fixture importing one of them. This
// is based on the import graph rather than service names because Batch,
// AppRunner, DMS, EFS, RDS, and many others all consume EC2 capacity.
if (createsVpc(source)) {
networkSources.add(file);
}
for (const match of source.matchAll(importPattern)) {
const imported = resolveLocalImport(file, match[1]);
if (imported === undefined) continue;
const importers = reverseImports.get(imported) ?? new Set<string>();
importers.add(file);
reverseImports.set(imported, importers);
}
}
// Mark every local importer that can reach a scarce fixture. Walking the
// reverse graph avoids false negatives from cycles between fixture modules.
const lambdaReachable = new Set(lambdaSources);
const networkReachable = new Set(networkSources);
const expandImporters = (reachable: Set<string>, sources: Set<string>) => {
const pending = [...sources];
while (pending.length > 0) {
const imported = pending.pop()!;
for (const importer of reverseImports.get(imported) ?? []) {
if (reachable.has(importer)) continue;
reachable.add(importer);
pending.push(importer);
}
}
};
expandImporters(lambdaReachable, lambdaSources);
expandImporters(networkReachable, networkSources);
// These files hold two custom VPCs simultaneously. Run this lane sequentially
// and never at the same time as `network`: default VPC (1) + heavy file (2)
// stays below the regional default quota of 5. The ordinary network lane at
// concurrency 3 likewise peaks at default VPC (1) + three custom VPCs (3).
const networkHeavyPaths = new Set([
resolve(awsTestDir, "EC2", "VpcPeeringConnection.test.ts"),
resolve(awsTestDir, "Route53", "ZoneVpcAssociation.test.ts"),
]);
const networkHeavy = tests.filter(
(file) => networkReachable.has(file) && networkHeavyPaths.has(file),
);
const network = tests.filter(
(file) => networkReachable.has(file) && !networkHeavyPaths.has(file),
);
const networkSet = new Set([...networkHeavy, ...network]);
const quota = tests.filter(
(file) =>
!networkSet.has(file) &&
(/Bindings\.test\.tsx?$/.test(file) ||
file.includes(`${sep}AWS${sep}Lambda${sep}`) ||
lambdaReachable.has(file)),
);
const quotaSet = new Set(quota);
const distributed = tests.filter(
(file) => !networkSet.has(file) && !quotaSet.has(file),
);
const lanes: Record<Lane, string[]> = {
"network-heavy": networkHeavy,
network,
quota,
distributed,
};
const command = process.argv[2] ?? "inventory";
if (command === "inventory") {
process.stdout.write(
`${JSON.stringify(
{
total: tests.length,
networkHeavy: networkHeavy.length,
network: network.length,
quota: quota.length,
distributed: distributed.length,
overlap:
[...networkHeavy, ...network, ...quota, ...distributed].length -
new Set([...networkHeavy, ...network, ...quota, ...distributed]).size,
covered: new Set([
...networkHeavy,
...network,
...quota,
...distributed,
]).size,
},
null,
2,
)}\n`,
);
process.exit(0);
}
if (
command === "list-network-heavy" ||
command === "list-network" ||
command === "list-quota" ||
command === "list-distributed"
) {
const lane = command.slice("list-".length) as Lane;
process.stdout.write(
`${lanes[lane].map((file) => relative(alchemyDir, file)).join("\n")}\n`,
);
process.exit(0);
}
if (
command !== "network-heavy" &&
command !== "network" &&
command !== "quota" &&
command !== "distributed"
) {
process.stderr.write(
"Usage: aws-test-lanes.ts <inventory|list-network-heavy|list-network|list-quota|list-distributed|network-heavy|network|quota|distributed> [alchemy-test options...]\n",
);
process.exit(2);
}
const lane = command as Lane;
const testFiles = lanes[lane].map((file) => relative(alchemyDir, file));
const args = process.argv.slice(3);
process.stderr.write(
`AWS ${lane} lane: ${testFiles.length}/${tests.length} files\n`,
);
const child = Bun.spawn(["bun", "alchemy-test", ...testFiles, ...args], {
cwd: alchemyDir,
env: process.env,
stdin: "inherit",
stdout: "inherit",
stderr: "inherit",
});
let terminating = false;
for (const signal of ["SIGINT", "SIGTERM"] as const) {
process.on(signal, () => {
if (terminating) return;
terminating = true;
child.kill(signal);
});
}
process.exit(await child.exited);