(input: {
readonly dbPath: string;
readonly tenantId: string;
readonly pauseAt: MigrationPausePoint;
})
| 774 | }; |
| 775 | |
| 776 | const killMigrationAtPause = async (input: { |
| 777 | readonly dbPath: string; |
| 778 | readonly tenantId: string; |
| 779 | readonly pauseAt: MigrationPausePoint; |
| 780 | }): Promise<void> => { |
| 781 | const marker = join(workDir, `pause-${input.pauseAt}`); |
| 782 | const code = ` |
| 783 | import { collectTables } from "@executor-js/api/server"; |
| 784 | import { migrateLocalV1ToV2IfNeeded } from "./src/db/v1-v2-migration.ts"; |
| 785 | await migrateLocalV1ToV2IfNeeded({ |
| 786 | sqlitePath: ${JSON.stringify(input.dbPath)}, |
| 787 | tables: collectTables(), |
| 788 | namespace: "executor_local", |
| 789 | tenantId: ${JSON.stringify(input.tenantId)}, |
| 790 | }); |
| 791 | `; |
| 792 | const child = spawn(process.execPath, ["-e", code], { |
| 793 | cwd: join(import.meta.dirname, "../.."), |
| 794 | env: { |
| 795 | ...process.env, |
| 796 | NODE_ENV: "test", |
| 797 | EXECUTOR_V1_V2_MIGRATION_PAUSE_AT: input.pauseAt, |
| 798 | EXECUTOR_V1_V2_MIGRATION_PAUSE_FILE: marker, |
| 799 | }, |
| 800 | stdio: "pipe", |
| 801 | }); |
| 802 | child.unref(); |
| 803 | const output: ChildOutput = { stdout: "", stderr: "" }; |
| 804 | child.stdout.setEncoding("utf-8"); |
| 805 | child.stderr.setEncoding("utf-8"); |
| 806 | child.stdout.on("data", (chunk) => { |
| 807 | output.stdout += chunk; |
| 808 | }); |
| 809 | child.stderr.on("data", (chunk) => { |
| 810 | output.stderr += chunk; |
| 811 | }); |
| 812 | // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: subprocess kill harness must clean up marker/child even when assertions fail |
| 813 | try { |
| 814 | const paused = await waitForPauseMarker(marker, child, output); |
| 815 | if (!paused.markerFound) { |
| 816 | child.kill("SIGKILL"); |
| 817 | await waitForChildExit(child); |
| 818 | } |
| 819 | expect(paused).toMatchObject({ markerFound: true, exitCode: null, signalCode: null }); |
| 820 | child.kill("SIGKILL"); |
| 821 | await waitForChildExit(child); |
| 822 | expect(child.signalCode).toBe("SIGKILL"); |
| 823 | } finally { |
| 824 | if (child.exitCode === null && child.signalCode === null) { |
| 825 | child.kill("SIGKILL"); |
| 826 | await waitForChildExit(child); |
| 827 | } |
| 828 | child.stdout.destroy(); |
| 829 | child.stderr.destroy(); |
| 830 | rmSync(marker, { force: true }); |
| 831 | } |
| 832 | }; |
| 833 |
no test coverage detected