aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-01-13 13:17:38 +0100
committerFlorian Dold <florian@dold.me>2021-01-13 13:17:38 +0100
commit9139a08c4d8e16b68682272aea629610739f7c67 (patch)
tree59f441ecf50289609a24b037a3aac75b5964e11b /packages
parent94e35ca70a53df81e513ca068eb71fd28a239c18 (diff)
run integration tests in worker process
Diffstat (limited to 'packages')
-rw-r--r--packages/taler-wallet-cli/src/integrationtests/harness.ts9
-rw-r--r--packages/taler-wallet-cli/src/integrationtests/testrunner.ts119
2 files changed, 116 insertions, 12 deletions
diff --git a/packages/taler-wallet-cli/src/integrationtests/harness.ts b/packages/taler-wallet-cli/src/integrationtests/harness.ts
index 6d1d4e16e..3bfe85701 100644
--- a/packages/taler-wallet-cli/src/integrationtests/harness.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/harness.ts
@@ -1086,13 +1086,13 @@ export class ExchangeService implements ExchangeServiceInterface {
this.helperCryptoEddsaProc = this.globalState.spawnService(
"taler-helper-crypto-eddsa",
- ["-c", this.configFilename, ...this.timetravelArgArr],
+ ["-c", this.configFilename, "-LDEBUG", ...this.timetravelArgArr],
`exchange-crypto-eddsa-${this.name}`,
);
this.helperCryptoRsaProc = this.globalState.spawnService(
"taler-helper-crypto-rsa",
- ["-c", this.configFilename, ...this.timetravelArgArr],
+ ["-c", this.configFilename, "-LDEBUG", ...this.timetravelArgArr],
`exchange-crypto-rsa-${this.name}`,
);
@@ -1458,10 +1458,9 @@ export async function runTestWithState(
const handleSignal = (s: string) => {
gc.shutdownSync();
console.warn(
- "**** received fatal proces event, shutting down test harness",
+ `**** received fatal proces event, terminating test ${testName}`,
);
- status = "fail";
- p.reject(Error("caught signal"));
+ process.exit(1);
};
process.on("SIGINT", handleSignal);
diff --git a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
index 578e9488c..5717bb767 100644
--- a/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/testrunner.ts
@@ -19,6 +19,7 @@ import { runPaymentTest } from "./test-payment";
import * as fs from "fs";
import * as path from "path";
import * as os from "os";
+import * as child_process from "child_process";
import { runBankApiTest } from "./test-bank-api";
import { runClaimLoopTest } from "./test-claim-loop";
import { runExchangeManagementTest } from "./test-exchange-management";
@@ -123,6 +124,11 @@ export function getTestName(tf: TestMainFunction): string {
.toLowerCase();
}
+interface RunTestChildInstruction {
+ testName: string;
+ testRootDir: string;
+}
+
export async function runTests(spec: TestRunSpec) {
const testRootDir = fs.mkdtempSync(
path.join(os.tmpdir(), "taler-integrationtests-"),
@@ -137,20 +143,70 @@ export async function runTests(spec: TestRunSpec) {
const testResults: TestRunResult[] = [];
+ let currentChild: child_process.ChildProcess | undefined;
+
+ const handleSignal = () => {
+ if (currentChild) {
+ currentChild.kill("SIGTERM");
+ }
+ process.exit(3);
+ };
+
+ process.on("SIGINT", () => handleSignal);
+ process.on("SIGTERM", () => handleSignal);
+ process.on("unhandledRejection", handleSignal);
+ process.on("uncaughtException", handleSignal);
+
for (const [n, testCase] of allTests.entries()) {
const testName = getTestName(testCase);
if (spec.include_pattern && !M(testName, spec.include_pattern)) {
continue;
}
- const testDir = path.join(testRootDir, testName);
- fs.mkdirSync(testDir);
- console.log(`running test ${testName}`);
- const gc = new GlobalTestState({
- testDir,
+
+ const testInstr: RunTestChildInstruction = {
+ testName,
+ testRootDir,
+ };
+
+ currentChild = child_process.fork(__filename, {
+ env: {
+ TWCLI_RUN_TEST_INSTRUCTION: JSON.stringify(testInstr),
+ ...process.env,
+ },
+ stdio: ["pipe", "pipe", "pipe", "ipc"],
});
- const result = await runTestWithState(gc, testCase, testName);
+
+ currentChild.stderr?.pipe(process.stderr);
+ currentChild.stdout?.pipe(process.stdout);
+
+ const result: TestRunResult = await new Promise((resolve, reject) => {
+ let msg: TestRunResult | undefined;
+ currentChild!.on("message", (m) => {
+ msg = m as TestRunResult;
+ });
+ currentChild!.on("exit", (code, signal) => {
+ if (signal) {
+ reject(new Error(`test worker exited with signal ${signal}`));
+ } else if (code != 0) {
+ reject(new Error(`test worker exited with code ${code}`));
+ } else if (!msg) {
+ reject(
+ new Error(
+ `test worker exited without giving back the test results`,
+ ),
+ );
+ } else {
+ resolve(msg);
+ }
+ });
+ currentChild!.on("error", (err) => {
+ reject(err);
+ });
+ });
+
+ console.log(`parent: got result ${JSON.stringify(result)}`);
+
testResults.push(result);
- console.log(result);
numTotal++;
if (result.status === "fail") {
numFail++;
@@ -160,6 +216,7 @@ export async function runTests(spec: TestRunSpec) {
numPass++;
}
}
+
const resultsFile = path.join(testRootDir, "results.json");
fs.writeFileSync(
path.join(testRootDir, "results.json"),
@@ -179,3 +236,51 @@ export function getTestInfo(): TestInfo[] {
name: getTestName(x),
}));
}
+
+const runTestInstrStr = process.env["TWCLI_RUN_TEST_INSTRUCTION"];
+if (runTestInstrStr) {
+ // Test will call taler-wallet-cli, so we must not propagate this variable.
+ delete process.env["TWCLI_RUN_TEST_NAME"];
+ const { testRootDir, testName } = JSON.parse(
+ runTestInstrStr,
+ ) as RunTestChildInstruction;
+ console.log(`running test ${testName} in worker process`);
+
+ process.on("disconnect", () => {
+ process.exit(3);
+ });
+
+ const runTest = async () => {
+ let testMain: TestMainFunction | undefined;
+ for (const t of allTests) {
+ if (getTestName(t) === testName) {
+ testMain = t;
+ break;
+ }
+ }
+
+ if (!process.send) {
+ console.error("can't communicate with parent");
+ process.exit(2);
+ }
+
+ if (!testMain) {
+ console.log(`test ${testName} not found`);
+ process.exit(2);
+ }
+
+ const testDir = path.join(testRootDir, testName);
+ fs.mkdirSync(testDir);
+ console.log(`running test ${testName}`);
+ const gc = new GlobalTestState({
+ testDir,
+ });
+ const testResult = await runTestWithState(gc, testMain, testName);
+ process.send(testResult);
+ };
+
+ runTest().catch((e) => {
+ console.log(e);
+ process.exit(1);
+ });
+}