mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
174 lines
5.6 KiB
JavaScript
174 lines
5.6 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Freight integration-suite launcher.
|
|
*
|
|
* node integration/scripts/it.mjs <up|test|down|logs> [vitest args...]
|
|
*
|
|
* Overlays docker-compose.it.yaml on docker-compose.e2e.yaml: same freight
|
|
* stack, but the payment microservice is real and only the bank gateways are
|
|
* stubbed. Web/Cypress containers are never started — this suite is HTTP only.
|
|
*
|
|
* Ports are fixed (and distinct from the Cypress e2e defaults) so both stacks
|
|
* can be up at once; they are separate compose projects.
|
|
*
|
|
* No dependencies — plain Node spawning `docker compose` and `pnpm`.
|
|
*/
|
|
|
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
import { generateKeyPairSync } from "node:crypto";
|
|
import { existsSync } from "node:fs";
|
|
import { dirname, join, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const itDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
const repoRoot = resolve(itDir, "..");
|
|
const composeBase = [
|
|
"compose",
|
|
"-f",
|
|
join(repoRoot, "docker-compose.e2e.yaml"),
|
|
"-f",
|
|
join(repoRoot, "docker-compose.it.yaml"),
|
|
];
|
|
|
|
/** Deliberately offset from the Cypress stack's defaults (3101/5533/9310…). */
|
|
const PORTS = {
|
|
E2E_API_PORT: 3111,
|
|
E2E_DB_PORT: 5543,
|
|
E2E_MINIO_PORT: 9320,
|
|
E2E_MINIO_CONSOLE_PORT: 9321,
|
|
// Unused here (no web containers) but referenced by the base file's build args.
|
|
E2E_PORTAL_PORT: 5393,
|
|
E2E_BACKOFFICE_PORT: 5394,
|
|
IT_PAYMENT_PORT: 3113,
|
|
IT_GATEWAY_PORT: 4600,
|
|
IT_RABBIT_PORT: 5772,
|
|
IT_RABBIT_UI_PORT: 15772,
|
|
};
|
|
|
|
/** Everything the suite needs up — web + cypress are deliberately absent. */
|
|
const SERVICES = [
|
|
"postgres-freight-e2e",
|
|
"minio-e2e",
|
|
"minio-init-e2e",
|
|
"freight-migration-e2e",
|
|
"fayda-mock-e2e",
|
|
"etrade-mock-e2e",
|
|
// Still a base-stack dependency of freight-api-e2e (reconcile-before-expire
|
|
// has its own client); cheap to run alongside the real payment API.
|
|
"payment-mock-e2e",
|
|
"gateway-mock-it",
|
|
"rabbitmq-it",
|
|
"payment-api-it",
|
|
"freight-api-e2e",
|
|
];
|
|
|
|
const RUNNING = SERVICES.filter(
|
|
(s) => !["minio-init-e2e", "freight-migration-e2e"].includes(s),
|
|
);
|
|
|
|
function fail(msg) {
|
|
console.error(`\nit: ${msg}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
function preflight() {
|
|
try {
|
|
execFileSync("docker", ["info"], { stdio: "ignore" });
|
|
} catch {
|
|
fail("docker is not running (or not installed) — start Docker and retry.");
|
|
}
|
|
if (!existsSync(join(repoRoot, ".npmrc"))) {
|
|
fail(".npmrc missing at repo root — image builds need GitHub Packages auth for @tria-plc.");
|
|
}
|
|
}
|
|
|
|
/** Throwaway RSA PEM — Telebirr PSS-signs every request object; the mock never
|
|
* verifies it, but the provider refuses to build a request without a real key. */
|
|
function fakeTelebirrPrivateKey() {
|
|
const { privateKey } = generateKeyPairSync("rsa", { modulusLength: 2048 });
|
|
return privateKey.export({ type: "pkcs8", format: "pem" }).toString();
|
|
}
|
|
|
|
/** Throwaway RSA JWK for FAYDA_PRIVATE_KEY_BASE64 (see e2e.mjs — same reason). */
|
|
function fakeFaydaPrivateKeyBase64() {
|
|
const { privateKey } = generateKeyPairSync("rsa", { modulusLength: 2048 });
|
|
const jwk = privateKey.export({ format: "jwk" });
|
|
Object.assign(jwk, { kty: "RSA", use: "sig", alg: "RS256", kid: "it-fayda-mock" });
|
|
return Buffer.from(JSON.stringify(jwk)).toString("base64");
|
|
}
|
|
|
|
const env = {
|
|
...process.env,
|
|
...Object.fromEntries(Object.entries(PORTS).map(([k, v]) => [k, String(v)])),
|
|
IT_API_URL: `http://localhost:${PORTS.E2E_API_PORT}`,
|
|
IT_PAYMENT_URL: `http://localhost:${PORTS.IT_PAYMENT_PORT}`,
|
|
IT_GATEWAY_URL: `http://localhost:${PORTS.IT_GATEWAY_PORT}`,
|
|
IT_DB_URL: `postgres://edr_e2e:edr_e2e@localhost:${PORTS.E2E_DB_PORT}/edr_freight_e2e`,
|
|
FAYDA_PRIVATE_KEY_BASE64:
|
|
process.env.FAYDA_PRIVATE_KEY_BASE64 ?? fakeFaydaPrivateKeyBase64(),
|
|
IT_TELEBIRR_PRIVATE_KEY:
|
|
process.env.IT_TELEBIRR_PRIVATE_KEY ?? fakeTelebirrPrivateKey(),
|
|
};
|
|
|
|
function compose(args) {
|
|
const { status } = spawnSync("docker", [...composeBase, ...args], { stdio: "inherit", env });
|
|
return status ?? 1;
|
|
}
|
|
|
|
function stackRunning() {
|
|
try {
|
|
const out = execFileSync("docker", [...composeBase, "ps", "--services", "--status", "running"], {
|
|
encoding: "utf8",
|
|
env,
|
|
stdio: ["ignore", "pipe", "ignore"],
|
|
});
|
|
const running = new Set(out.split("\n").filter(Boolean));
|
|
return RUNNING.every((s) => running.has(s));
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function up() {
|
|
preflight();
|
|
console.log(
|
|
`it: starting stack — freight :${PORTS.E2E_API_PORT} payment :${PORTS.IT_PAYMENT_PORT} ` +
|
|
`gateway :${PORTS.IT_GATEWAY_PORT} db :${PORTS.E2E_DB_PORT}`,
|
|
);
|
|
if (compose(["up", "-d", "--build", "--wait", ...SERVICES]) !== 0) {
|
|
fail(
|
|
"stack failed to become healthy. Inspect with:\n" +
|
|
" node integration/scripts/it.mjs logs payment-api-it",
|
|
);
|
|
}
|
|
}
|
|
|
|
const [cmd, ...rawExtra] = process.argv.slice(2);
|
|
// `pnpm it:test -- src/foo.it.ts` hands us a literal "--" first. Forwarding it
|
|
// makes vitest treat everything after it as CLI options and ignore the file
|
|
// filter — the "one file" run silently becomes the whole suite.
|
|
const extra = rawExtra[0] === "--" ? rawExtra.slice(1) : rawExtra;
|
|
|
|
switch (cmd) {
|
|
case "up":
|
|
up();
|
|
break;
|
|
case "test": {
|
|
if (!stackRunning()) up();
|
|
const { status } = spawnSync(
|
|
"pnpm",
|
|
["--filter", "@edr/freight-integration", "run", "test", ...extra],
|
|
{ cwd: repoRoot, stdio: "inherit", env },
|
|
);
|
|
process.exit(status ?? 1);
|
|
}
|
|
case "logs":
|
|
process.exit(compose(["logs", "--tail", "200", ...extra]));
|
|
break;
|
|
case "down":
|
|
process.exit(compose(["down", "-v", "--remove-orphans"]));
|
|
break;
|
|
default:
|
|
fail(`unknown command "${cmd ?? ""}" — use up | test | logs | down`);
|
|
}
|