test/package: wire the runtime fixture set into package_test
test/package/runtime/ was a manual README-driven corpus with no target. Its unique surface — the driver's single-file ww test leg, the unmet-expected-abort outcome, and the published -c binary's own CLI (repeated globs, -list, -timeout-ms, direct-binary timeout and descendant handling) — is now asserted by three new @test fns in package_test.ww; the README drops its manual-run instructions.
This commit is contained in:
@@ -442,3 +442,163 @@ fn packagepath(relative: str) str = {
|
|||||||
"/route_test.test.sepwork/__root.s"))));
|
"/route_test.test.sepwork/__root.s"))));
|
||||||
clean(root);
|
clean(root);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn runtimepath(relative: str) str = {
|
||||||
|
return strings.concat(repo(), "/test/package/runtime/", relative);
|
||||||
|
};
|
||||||
|
|
||||||
|
// The single-FILE `ww test <file>` route wraps the same in-binary test
|
||||||
|
// runtime as the directory-package route (cases/*), but through the
|
||||||
|
// driver's single-file leg. One row per outcome class keeps that leg's
|
||||||
|
// wiring honest; the runtime-internal classifications themselves are
|
||||||
|
// owned by the cases/* tests above.
|
||||||
|
@test fn singlefile_runtime_outcomes() void = {
|
||||||
|
let root: str = fresh();
|
||||||
|
let out: commandout;
|
||||||
|
let successav: []str = [driver("ww"), "test",
|
||||||
|
runtimepath("success_test.ww")];
|
||||||
|
runcommand(root, "sf-success", successav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(has(out.stdout, "alpha_pass ... ok\n"));
|
||||||
|
assert(has(out.stdout,
|
||||||
|
"beta_skip ... SKIP: synthetic unavailable feature\n"));
|
||||||
|
assert(has(out.stdout, "gamma_expected_abort ... ok\n"));
|
||||||
|
assert(has(out.stdout, "delta_pass ... ok\n"));
|
||||||
|
assert(has(out.stdout,
|
||||||
|
"3 passed, 0 failed, 1 skipped, 0 harness errors\n"));
|
||||||
|
assert(has(out.stdout,
|
||||||
|
"4 discovered, 4 selected, 4 started, 4 completed\n"));
|
||||||
|
|
||||||
|
let failav: []str = [driver("ww"), "test",
|
||||||
|
runtimepath("fail_test.ww")];
|
||||||
|
runcommand(root, "sf-fail", failav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 1);
|
||||||
|
assert(has(out.stdout, "assertion_failure ... FAIL (exit 1)\n"));
|
||||||
|
|
||||||
|
let multiav: []str = [driver("ww"), "test",
|
||||||
|
runtimepath("multiple_fail_test.ww")];
|
||||||
|
runcommand(root, "sf-multi", multiav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 1);
|
||||||
|
assert(has(out.stdout,
|
||||||
|
"0 passed, 2 failed, 0 skipped, 0 harness errors\n"));
|
||||||
|
|
||||||
|
let unmetav: []str = [driver("ww"), "test",
|
||||||
|
runtimepath("expected_abort_return_test.ww")];
|
||||||
|
runcommand(root, "sf-unmet", unmetav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 1);
|
||||||
|
assert(has(out.stdout,
|
||||||
|
"expected_abort_must_happen ... FAIL (expected abort)\n"));
|
||||||
|
|
||||||
|
let premav: []str = [driver("ww"), "test",
|
||||||
|
runtimepath("premature_exit_test.ww")];
|
||||||
|
runcommand(root, "sf-premature", premav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 1);
|
||||||
|
assert(has(out.stdout,
|
||||||
|
"clean_exit_without_completion ... HARNESS (incomplete result)\n"));
|
||||||
|
|
||||||
|
let sigav: []str = [driver("ww"), "test",
|
||||||
|
runtimepath("signal_test.ww")];
|
||||||
|
runcommand(root, "sf-signal", sigav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 1);
|
||||||
|
assert(has(out.stdout, "signal_is_not_exit ... FAIL (signal 15)\n"));
|
||||||
|
clean(root);
|
||||||
|
};
|
||||||
|
|
||||||
|
// The published test binary's OWN command surface: repeated glob args,
|
||||||
|
// -list (with and without a glob), and -timeout-ms. Only a direct
|
||||||
|
// invocation of the `-c` artifact proves these; every driver route
|
||||||
|
// parses its flags before the binary sees them.
|
||||||
|
@test fn published_binary_cli() void = {
|
||||||
|
let root: str = fresh();
|
||||||
|
let out: commandout;
|
||||||
|
let stem: str = strings.concat(root, "/rtsuccess");
|
||||||
|
let cav: []str = [driver("ww"), "test", "-c", "-o", stem,
|
||||||
|
runtimepath("success_test.ww")];
|
||||||
|
runcommand(root, "publish", cav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
|
||||||
|
let gav: []str = [stem, "alpha*", "delta*"];
|
||||||
|
runcommand(root, "globs", gav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(has(out.stdout, "alpha_pass ... ok\n"));
|
||||||
|
assert(has(out.stdout, "delta_pass ... ok\n"));
|
||||||
|
assert(has(out.stdout,
|
||||||
|
"2 passed, 0 failed, 0 skipped, 0 harness errors\n"));
|
||||||
|
assert(has(out.stdout,
|
||||||
|
"4 discovered, 2 selected, 2 started, 2 completed\n"));
|
||||||
|
|
||||||
|
let lav: []str = [stem, "-list"];
|
||||||
|
runcommand(root, "list", lav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(same(out.stdout,
|
||||||
|
"alpha_pass\nbeta_skip\ngamma_expected_abort\ndelta_pass\n"));
|
||||||
|
|
||||||
|
let lgav: []str = [stem, "-list", "gamma*"];
|
||||||
|
runcommand(root, "list-glob", lgav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(same(out.stdout, "gamma_expected_abort\n"));
|
||||||
|
|
||||||
|
let tav: []str = [stem, "-timeout-ms=50", "alpha*"];
|
||||||
|
runcommand(root, "cli-timeout", tav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(has(out.stdout,
|
||||||
|
"1 passed, 0 failed, 0 skipped, 0 harness errors\n"));
|
||||||
|
clean(root);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Direct-binary timeout classification and descendant handling. The
|
||||||
|
// runcommand deadline bounds the no-hang claims: a runner waiting on a
|
||||||
|
// SIGTERM-blocking or process-group-escaped pipe writer would trip it.
|
||||||
|
@test fn direct_binary_timeout_and_descendants() void = {
|
||||||
|
let root: str = fresh();
|
||||||
|
let out: commandout;
|
||||||
|
let tstem: str = strings.concat(root, "/rttimeout");
|
||||||
|
let tcav: []str = [driver("ww"), "test", "-c", "-o", tstem,
|
||||||
|
runtimepath("timeout_test.ww")];
|
||||||
|
runcommand(root, "publish-timeout", tcav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
let trun: []str = [tstem, "-timeout-ms=50"];
|
||||||
|
runcommand(root, "run-timeout", trun,
|
||||||
|
(20i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 1);
|
||||||
|
assert(has(out.stdout, "hang_times_out ... FAIL(timeout)\n"));
|
||||||
|
|
||||||
|
let lstem: str = strings.concat(root, "/rtlinger");
|
||||||
|
let lcav: []str = [driver("ww"), "test", "-c", "-o", lstem,
|
||||||
|
runtimepath("lingering_descendant_test.ww")];
|
||||||
|
runcommand(root, "publish-linger", lcav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
let lrun: []str = [lstem, "-timeout-ms=250"];
|
||||||
|
runcommand(root, "run-linger", lrun,
|
||||||
|
(20i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(has(out.stdout,
|
||||||
|
"returning_test_clears_descendant ... ok\n"));
|
||||||
|
|
||||||
|
let estem: str = strings.concat(root, "/rtescaped");
|
||||||
|
let ecav: []str = [driver("ww"), "test", "-c", "-o", estem,
|
||||||
|
runtimepath("escaped_descendant_test.ww")];
|
||||||
|
runcommand(root, "publish-escaped", ecav,
|
||||||
|
(30i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
let erun: []str = [estem, "-timeout-ms=250"];
|
||||||
|
runcommand(root, "run-escaped", erun,
|
||||||
|
(20i64 * (time.second: i64)): time.duration, &out);
|
||||||
|
expectexit(&out, 0);
|
||||||
|
assert(has(out.stdout,
|
||||||
|
"escaped_writer_does_not_hold_runner ... ok\n"));
|
||||||
|
clean(root);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,45 +1,23 @@
|
|||||||
# Native package-runtime fixtures
|
# Package-runtime fixtures
|
||||||
|
|
||||||
These fixtures exercise the compiled package test binary, rather than a
|
Single-file `@test` sources driven by `test/package/package_test.ww`
|
||||||
subprocess-per-assertion harness. Build the bootstrap tools once with `make all`,
|
(the `make test-package` binary): `singlefile_runtime_outcomes`,
|
||||||
then run the focused cases from the repository root:
|
`published_binary_cli`, and `direct_binary_timeout_and_descendants`.
|
||||||
|
They exercise the driver's single-file `ww test` leg and the published
|
||||||
|
`-c` binary's own command surface (repeated globs, `-list`,
|
||||||
|
`-timeout-ms`); the directory-package legs of the same outcome classes
|
||||||
|
are owned by `test/package/cases/*`.
|
||||||
|
|
||||||
```sh
|
Fixture notes:
|
||||||
out/bin/ww test test/package/runtime/success_test.ww
|
|
||||||
out/bin/ww test -c -o /tmp/ww-runtime-test test/package/runtime/success_test.ww
|
|
||||||
/tmp/ww-runtime-test 'alpha*' 'delta*'
|
|
||||||
/tmp/ww-runtime-test -list
|
|
||||||
/tmp/ww-runtime-test -list 'gamma*'
|
|
||||||
/tmp/ww-runtime-test -timeout-ms=50 'alpha*'
|
|
||||||
out/bin/ww test test/package/runtime/fail_test.ww
|
|
||||||
out/bin/ww test test/package/runtime/multiple_fail_test.ww
|
|
||||||
out/bin/ww test test/package/runtime/expected_abort_return_test.ww
|
|
||||||
out/bin/ww test test/package/runtime/premature_exit_test.ww
|
|
||||||
out/bin/ww test test/package/runtime/signal_test.ww
|
|
||||||
out/bin/ww test -c -o /tmp/ww-runtime-timeout test/package/runtime/timeout_test.ww
|
|
||||||
/tmp/ww-runtime-timeout -timeout-ms=50
|
|
||||||
out/bin/ww test -c -o /tmp/ww-runtime-descendant test/package/runtime/lingering_descendant_test.ww
|
|
||||||
/tmp/ww-runtime-descendant -timeout-ms=250
|
|
||||||
out/bin/ww test -c -o /tmp/ww-runtime-escaped test/package/runtime/escaped_descendant_test.ww
|
|
||||||
/tmp/ww-runtime-escaped -timeout-ms=250
|
|
||||||
```
|
|
||||||
|
|
||||||
The success fixture reports two ordinary passes, one expected-abort pass, and
|
- The runtime recognizes `expectabort(); os.exit(nonzero)` as an
|
||||||
one skip with its reason. The preserved test binary accepts repeated glob
|
expected abort because WW's abort primitive itself terminates with a
|
||||||
arguments directly. List mode prints selected names without starting tests.
|
normal exit status; the ABI cannot distinguish those two paths
|
||||||
Each test has a 30-second default timeout; `-timeout-ms=N` selects a positive
|
without a future abort hook.
|
||||||
per-test timeout up to one hour for a direct test-binary invocation.
|
- The lingering-descendant fixture blocks SIGTERM in its descendant, so
|
||||||
The current runtime recognizes `expectabort(); os.exit(nonzero)` as an expected
|
the runner exercises its grace period and SIGKILL escalation before
|
||||||
abort because WW's abort primitive itself terminates with a normal exit status;
|
draining the record.
|
||||||
the ABI cannot distinguish those two paths without a future abort hook.
|
- The escaped-descendant fixture moves its inherited pipe writer into
|
||||||
The assertion, multiple-failure, unmet-expected-abort, premature-exit, and
|
another process group for one second; the framed nonblocking protocol
|
||||||
signal fixtures fail respectively with a normal exit, two failures whose
|
must return after the test leader and owned group complete, never
|
||||||
process status is still clamped to 1, an expected abort that never happens, an
|
waiting for pipe EOF.
|
||||||
incomplete completion record, and signal 15; none may be mistaken for a pass.
|
|
||||||
The timeout fixture fails deterministically as `FAIL(timeout)`. The lingering
|
|
||||||
descendant fixture passes without waiting on the inherited control-pipe writer:
|
|
||||||
the descendant blocks SIGTERM, so the runner exercises its grace period and
|
|
||||||
SIGKILL escalation before draining the record.
|
|
||||||
The escaped-descendant fixture moves its inherited writer into another process
|
|
||||||
group for one second. The framed nonblocking protocol returns immediately after
|
|
||||||
the test leader and owned group complete; it never waits for pipe EOF.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user