|
|
|
|
@@ -1466,14 +1466,20 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// A visible raw test-source build observes only its initial package/import
|
|
|
|
|
// header. It must not turn that observation into a package, import, action,
|
|
|
|
|
// artifact, or work-state identity.
|
|
|
|
|
// header and then omits it. A .ww-spelled directory, including a symlink with
|
|
|
|
|
// a _test.ww spelling, instead enters the ordinary directory-package route.
|
|
|
|
|
// Neither classification may redefine package or dotted-import identity.
|
|
|
|
|
@test fn named_test_sources_are_header_loaded_then_omitted() void = {
|
|
|
|
|
let root: str = fresh();
|
|
|
|
|
let source: str = strings.concat(root, "/source");
|
|
|
|
|
let dirsource: str = strings.concat(source, "/directory");
|
|
|
|
|
let include: str = strings.concat(root, "/include");
|
|
|
|
|
let dependency: str = strings.concat(include, "/domain/value");
|
|
|
|
|
let dirsource: str = strings.concat(source, "/directory.ww");
|
|
|
|
|
let dirtarget: str = strings.concat(source, "/directory-target");
|
|
|
|
|
mkdirall(source); mkdirall(dirsource); mkdirall(dirtarget);
|
|
|
|
|
let emptydir: str = strings.concat(source, "/empty.ww");
|
|
|
|
|
let baddirtarget: str = strings.concat(source, "/broken-target");
|
|
|
|
|
mkdirall(source); mkdirall(dependency); mkdirall(dirsource); mkdirall(dirtarget);
|
|
|
|
|
mkdirall(emptydir); mkdirall(baddirtarget);
|
|
|
|
|
|
|
|
|
|
let ignored: str = strings.concat(source, "/raw_windows_test.ww");
|
|
|
|
|
let platform: str = strings.concat(source, "/platform_windows_test.ww");
|
|
|
|
|
@@ -1486,11 +1492,18 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|
|
|
|
let linktarget: str = strings.concat(source, "/target.ww");
|
|
|
|
|
let link: str = strings.concat(source, "/requested_test.ww");
|
|
|
|
|
let dirlink: str = strings.concat(source, "/directory_test.ww");
|
|
|
|
|
let baddirlink: str = strings.concat(source, "/broken_test.ww");
|
|
|
|
|
let rawmain: str = strings.concat(source, "/raw.ww");
|
|
|
|
|
let runsource: str = strings.concat(source, "/run_test.ww");
|
|
|
|
|
let testroute: str = strings.concat(source, "/route_test.ww");
|
|
|
|
|
let warmpath: str = strings.concat(source, "/warm.ww");
|
|
|
|
|
let warmtest: str = strings.concat(source, "/warm_test.ww");
|
|
|
|
|
let dirtargettest: str = strings.concat(dirtarget, "/ignored_test.ww");
|
|
|
|
|
let dirtargettestexcluded: str =
|
|
|
|
|
"package main;\nimport missing.test.only;\n";
|
|
|
|
|
let dirtargettestselected: str = strings.concat(
|
|
|
|
|
"package main;\nimport domain.value;\n",
|
|
|
|
|
"@test fn directory_selected() void = { assert(value.number() == 5); };\n");
|
|
|
|
|
let header: str = strings.concat(
|
|
|
|
|
"package raw_test;\nimport absent.pkg;\n",
|
|
|
|
|
"this body is deliberately malformed and never reaches a producer {\n",
|
|
|
|
|
@@ -1513,24 +1526,40 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|
|
|
|
"package route;\n",
|
|
|
|
|
"@test fn still_selected() void = { assert(true); };\n"));
|
|
|
|
|
writefile(warmpath, "package main;\nfn main() i32 = { return 6; };\n");
|
|
|
|
|
writefile(strings.concat(dependency, "/value.ww"), strings.concat(
|
|
|
|
|
"package value;\n",
|
|
|
|
|
"export fn number() i32 = { return 5; };\n"));
|
|
|
|
|
writefile(strings.concat(dirsource, "/main.ww"),
|
|
|
|
|
"package main;\nfn main() i32 = { return 3; };\n");
|
|
|
|
|
writefile(strings.concat(dirtarget, "/main.ww"),
|
|
|
|
|
"package main;\nfn main() i32 = { return 5; };\n");
|
|
|
|
|
writefile(strings.concat(dirsource, "/ignored_test.ww"),
|
|
|
|
|
"package main;\nimport missing.test.only;\n");
|
|
|
|
|
writefile(strings.concat(dirtarget, "/main.ww"), strings.concat(
|
|
|
|
|
"package main;\nimport domain.value;\n",
|
|
|
|
|
"fn main() i32 = { return value.number(); };\n"));
|
|
|
|
|
writefile(dirtargettest, dirtargettestexcluded);
|
|
|
|
|
writefile(strings.concat(baddirtarget, "/main.ww"),
|
|
|
|
|
"package main;\nimport ;\n");
|
|
|
|
|
assert(os.symlink(linktarget, link) == 0);
|
|
|
|
|
assert(os.symlink(dirtarget, dirlink) == 0);
|
|
|
|
|
assert(os.symlink(baddirtarget, baddirlink) == 0);
|
|
|
|
|
|
|
|
|
|
let compilerwrapper: str = strings.concat(root, "/testonly-w6c.sh");
|
|
|
|
|
let assemblerwrapper: str = strings.concat(root, "/testonly-w6a.sh");
|
|
|
|
|
let linkerwrapper: str = strings.concat(root, "/testonly-w6l.sh");
|
|
|
|
|
writeexecutable(compilerwrapper, strings.concat(
|
|
|
|
|
"#!/bin/sh\nprintf 'compile\\n' >> \"$WW_TESTONLY_CTRACE\"\n",
|
|
|
|
|
"if test \"$WW_TESTONLY_FAIL_C\" = 1; then\n",
|
|
|
|
|
" printf 'injected directory compiler failure\\n' >&2\n",
|
|
|
|
|
" exit 97\nfi\n",
|
|
|
|
|
"exec \"$WW_TESTONLY_REAL_C\" \"$@\"\n"));
|
|
|
|
|
writeexecutable(assemblerwrapper, strings.concat(
|
|
|
|
|
"#!/bin/sh\nprintf 'assemble\\n' >> \"$WW_TESTONLY_ATRACE\"\n",
|
|
|
|
|
"exec \"$WW_TESTONLY_REAL_A\" \"$@\"\n"));
|
|
|
|
|
writeexecutable(linkerwrapper, strings.concat(
|
|
|
|
|
"#!/bin/sh\nprintf 'link\\n' >> \"$WW_TESTONLY_LTRACE\"\n",
|
|
|
|
|
"if test \"$WW_TESTONLY_LINK_MODE\" = signal; then\n",
|
|
|
|
|
" kill -TERM \"$$\"\n",
|
|
|
|
|
"fi\n",
|
|
|
|
|
"exec \"$WW_TESTONLY_REAL_L\" \"$@\"\n"));
|
|
|
|
|
|
|
|
|
|
let stages: []str = ["ww", "ww_ww"];
|
|
|
|
|
@@ -1552,15 +1581,32 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|
|
|
|
let ccompiled: str = "";
|
|
|
|
|
let ctestasm: str = "";
|
|
|
|
|
let crawbin: str = "";
|
|
|
|
|
let cdirectdirbin: str = "";
|
|
|
|
|
let cdirectdirartifacts: str = "";
|
|
|
|
|
let clinkdirbin: str = "";
|
|
|
|
|
let clinkdirartifacts: str = "";
|
|
|
|
|
let clinkdirasm: str = "";
|
|
|
|
|
let clinkdirplainasm: str = "";
|
|
|
|
|
let clinkdirchanged: str = "";
|
|
|
|
|
let clinkdirchangedartifacts: str = "";
|
|
|
|
|
let compilerfaildiag: str = "";
|
|
|
|
|
let linkersignaldiag: str = "";
|
|
|
|
|
let directorytestrunout: str = "";
|
|
|
|
|
let directorytestrunerr: str = "";
|
|
|
|
|
let directorytestrunartifacts: str = "";
|
|
|
|
|
let directorytestbin: str = "";
|
|
|
|
|
let directorytestcompileartifacts: str = "";
|
|
|
|
|
let directorytestasm: str = "";
|
|
|
|
|
let baseenv: []str = os.getenvs();
|
|
|
|
|
let si: i32 = 0;
|
|
|
|
|
for (si < stages.len) {
|
|
|
|
|
rewritefile(dirtargettest, dirtargettestexcluded);
|
|
|
|
|
let ctrace: str = strings.concat(root, "/testonly-c-", tags[si]);
|
|
|
|
|
let atrace: str = strings.concat(root, "/testonly-a-", tags[si]);
|
|
|
|
|
let ltrace: str = strings.concat(root, "/testonly-l-", tags[si]);
|
|
|
|
|
writefile(ctrace, ""); writefile(atrace, ""); writefile(ltrace, "");
|
|
|
|
|
append(tracecs, ctrace); append(traceas, atrace); append(tracels, ltrace);
|
|
|
|
|
let env: []str = alloc([], (baseenv.len + 10): u64)!;
|
|
|
|
|
let env: []str = alloc([], (baseenv.len + 12): u64)!;
|
|
|
|
|
let ei: i32 = 0;
|
|
|
|
|
for (ei < baseenv.len) {
|
|
|
|
|
if (!strings.hasprefix(baseenv[ei], "WW_W6C=")
|
|
|
|
|
@@ -1580,6 +1626,10 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|
|
|
|
append(env, strings.concat("WW_TESTONLY_REAL_C=", driver(compilers[si])));
|
|
|
|
|
append(env, strings.concat("WW_TESTONLY_REAL_A=", driver(assemblers[si])));
|
|
|
|
|
append(env, strings.concat("WW_TESTONLY_REAL_L=", driver(linkers[si])));
|
|
|
|
|
let failcindex: i32 = env.len;
|
|
|
|
|
append(env, "WW_TESTONLY_FAIL_C=");
|
|
|
|
|
let linkmodeindex: i32 = env.len;
|
|
|
|
|
append(env, "WW_TESTONLY_LINK_MODE=");
|
|
|
|
|
append(environments, env);
|
|
|
|
|
|
|
|
|
|
let out: commandout;
|
|
|
|
|
@@ -1745,29 +1795,289 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|
|
|
|
&& readfile(ctrace).len == 0 && readfile(atrace).len == 0
|
|
|
|
|
&& readfile(ltrace).len == 0);
|
|
|
|
|
|
|
|
|
|
// Directory loading wins before raw-source suffix classification. Empty
|
|
|
|
|
// and malformed directories retain directory diagnostics, including the
|
|
|
|
|
// requested symlink spelling of a selected source.
|
|
|
|
|
let emptywork: str = strings.concat(root, "/empty-dir-work-", tags[si]);
|
|
|
|
|
let emptyout: str = strings.concat(root, "/empty-dir-output-", tags[si]);
|
|
|
|
|
mkdirall(emptywork);
|
|
|
|
|
let emptyav: []str = [driver(stages[si]), "build", "-w", emptywork,
|
|
|
|
|
"-I", include, "-o", emptyout, emptydir];
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-empty-directory-", tags[si]),
|
|
|
|
|
emptyav, env, (30i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
let emptywant: str = strings.concat("ww: ", emptydir,
|
|
|
|
|
": directory contains no WW package sources\n");
|
|
|
|
|
assert(out.stdout.len == 0 && same(out.stderr, emptywant)
|
|
|
|
|
&& !has(out.stderr, "cannot read source") && directoryisempty(emptywork)
|
|
|
|
|
&& !os.exists(emptyout) && readfile(ctrace).len == 0
|
|
|
|
|
&& readfile(atrace).len == 0 && readfile(ltrace).len == 0);
|
|
|
|
|
let baddirwork: str = strings.concat(root, "/bad-dir-work-", tags[si]);
|
|
|
|
|
let baddirout: str = strings.concat(root, "/bad-dir-output-", tags[si]);
|
|
|
|
|
mkdirall(baddirwork);
|
|
|
|
|
let baddirav: []str = [driver(stages[si]), "build", "-w", baddirwork,
|
|
|
|
|
"-I", include, "-o", baddirout, baddirlink];
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-bad-directory-", tags[si]),
|
|
|
|
|
baddirav, env, (30i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
let baddirwant: str = strings.concat(baddirlink,
|
|
|
|
|
"/main.ww:2:8: error: expected identifier, got ;\n");
|
|
|
|
|
assert(out.stdout.len == 0 && same(out.stderr, baddirwant)
|
|
|
|
|
&& !has(out.stderr, "cannot read source") && directoryisempty(baddirwork)
|
|
|
|
|
&& !os.exists(baddirout) && readfile(ctrace).len == 0
|
|
|
|
|
&& readfile(atrace).len == 0 && readfile(ltrace).len == 0);
|
|
|
|
|
|
|
|
|
|
// A real directory whose requested basename ends in .ww remains a
|
|
|
|
|
// directory request. The suffix does not make the directory a raw source.
|
|
|
|
|
let directdirwork: str = strings.concat(root, "/direct-dir-work-",
|
|
|
|
|
tags[si]);
|
|
|
|
|
let directdirout: str = strings.concat(root, "/direct-dir-output-",
|
|
|
|
|
tags[si]);
|
|
|
|
|
mkdirall(directdirwork);
|
|
|
|
|
let directdirav: []str = [driver(stages[si]), "build", "-w",
|
|
|
|
|
directdirwork, "-I", include, "-o", directdirout, dirsource];
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-direct-directory-",
|
|
|
|
|
tags[si]), directdirav, env,
|
|
|
|
|
(60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& os.exists(directdirout) && readfile(ctrace).len != 0
|
|
|
|
|
&& readfile(atrace).len != 0 && readfile(ltrace).len != 0);
|
|
|
|
|
let directdirbytes: str = strings.dup(readfile(directdirout));
|
|
|
|
|
let directdirartifacts: str = strings.dup(
|
|
|
|
|
artifacttreesnapshot(directdirwork));
|
|
|
|
|
if (si == 0) {
|
|
|
|
|
cdirectdirbin = strings.dup(directdirbytes);
|
|
|
|
|
cdirectdirartifacts = strings.dup(directdirartifacts);
|
|
|
|
|
} else {
|
|
|
|
|
assert(same(cdirectdirbin, directdirbytes)
|
|
|
|
|
&& same(cdirectdirartifacts, directdirartifacts));
|
|
|
|
|
};
|
|
|
|
|
let directrun: []str = [directdirout];
|
|
|
|
|
runcommand(root, strings.concat("testonly-direct-directory-run-",
|
|
|
|
|
tags[si]), directrun, time.second, &out);
|
|
|
|
|
expectexit(&out, 3);
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
|
|
|
|
|
// A directory target remains a directory request despite a test-looking
|
|
|
|
|
// requested spelling; this is deliberately the one producer-positive row.
|
|
|
|
|
// requested symlink spelling. Both stages reach the ordinary directory
|
|
|
|
|
// graph and produce byte-identical commands and semantic artifacts.
|
|
|
|
|
let linkdirwork: str = strings.concat(root, "/link-dir-work-", tags[si]);
|
|
|
|
|
let linkdirout: str = strings.concat(root, "/link-dir-output-", tags[si]);
|
|
|
|
|
mkdirall(linkdirwork);
|
|
|
|
|
let linkdirav: []str = [driver(stages[si]), "build", "-w", linkdirwork,
|
|
|
|
|
"-o", linkdirout, dirlink];
|
|
|
|
|
"-I", include, "-o", linkdirout, dirlink];
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-directory-link-", tags[si]),
|
|
|
|
|
linkdirav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& os.exists(linkdirout) && readfile(ctrace).len != 0
|
|
|
|
|
&& readfile(atrace).len != 0 && readfile(ltrace).len != 0);
|
|
|
|
|
let linkdirbytes: str = strings.dup(readfile(linkdirout));
|
|
|
|
|
let linkdirartifacts: str = strings.dup(
|
|
|
|
|
artifacttreesnapshot(linkdirwork));
|
|
|
|
|
if (si == 0) {
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& os.exists(linkdirout) && readfile(ctrace).len != 0
|
|
|
|
|
&& readfile(atrace).len != 0 && readfile(ltrace).len != 0);
|
|
|
|
|
clinkdirbin = strings.dup(linkdirbytes);
|
|
|
|
|
clinkdirartifacts = strings.dup(linkdirartifacts);
|
|
|
|
|
} else {
|
|
|
|
|
// The selected non-directory classifier must not absorb this
|
|
|
|
|
// pre-existing WWstage resolution difference into the slice.
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
assert(out.stdout.len == 0
|
|
|
|
|
&& same(out.stderr, "ww: cannot read source\n")
|
|
|
|
|
&& !os.exists(linkdirout) && readfile(ctrace).len == 0
|
|
|
|
|
&& readfile(atrace).len == 0 && readfile(ltrace).len == 0);
|
|
|
|
|
assert(same(clinkdirbin, linkdirbytes)
|
|
|
|
|
&& same(clinkdirartifacts, linkdirartifacts));
|
|
|
|
|
};
|
|
|
|
|
let linkdirrun: []str = [linkdirout];
|
|
|
|
|
runcommand(root, strings.concat("testonly-directory-link-run-", tags[si]),
|
|
|
|
|
linkdirrun, time.second, &out);
|
|
|
|
|
expectexit(&out, 5);
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-directory-link-warm-",
|
|
|
|
|
tags[si]), linkdirav, env,
|
|
|
|
|
(60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& same(linkdirbytes, readfile(linkdirout))
|
|
|
|
|
&& same(clinkdirartifacts, artifacttreesnapshot(linkdirwork))
|
|
|
|
|
&& readfile(ctrace).len == 0 && readfile(atrace).len == 0
|
|
|
|
|
&& readfile(ltrace).len != 0);
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
|
|
|
|
|
// Output-directory presentation comes from the canonical selected target,
|
|
|
|
|
// while exact-null and assembly-only disposition do not change selection.
|
|
|
|
|
let linkoutdir: str = strings.concat(root, "/link-output-directory-",
|
|
|
|
|
tags[si]);
|
|
|
|
|
let linkoutwork: str = strings.concat(root, "/link-output-work-",
|
|
|
|
|
tags[si]);
|
|
|
|
|
mkdirall(linkoutdir); mkdirall(linkoutwork);
|
|
|
|
|
writefile(strings.concat(linkoutdir, "/sentinel"), "caller-owned\n");
|
|
|
|
|
let linkoutav: []str = [driver(stages[si]), "build", "-w", linkoutwork,
|
|
|
|
|
"-I", include, "-o", linkoutdir, dirlink];
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-link-output-directory-",
|
|
|
|
|
tags[si]), linkoutav, env,
|
|
|
|
|
(60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
let linkoutchild: str = strings.concat(linkoutdir, "/directory-target");
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& same(readfile(strings.concat(linkoutdir, "/sentinel")),
|
|
|
|
|
"caller-owned\n")
|
|
|
|
|
&& same(linkdirbytes, readfile(linkoutchild))
|
|
|
|
|
&& readfile(ctrace).len != 0 && readfile(atrace).len != 0
|
|
|
|
|
&& readfile(ltrace).len != 0);
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
let linknullwork: str = strings.concat(root, "/link-null-work-", tags[si]);
|
|
|
|
|
mkdirall(linknullwork);
|
|
|
|
|
let linknullav: []str = [driver(stages[si]), "build", "-w", linknullwork,
|
|
|
|
|
"-I", include, "-o", "/dev/null", dirlink];
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-link-null-", tags[si]),
|
|
|
|
|
linknullav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& readfile(ctrace).len != 0 && readfile(atrace).len != 0
|
|
|
|
|
&& readfile(ltrace).len != 0
|
|
|
|
|
&& artifacttreesnapshot(linknullwork).len != 0);
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
let asmdirwork: str = strings.concat(root, "/link-asm-work-", tags[si]);
|
|
|
|
|
let asmdirstem: str = strings.concat(root, "/link-asm-output-", tags[si]);
|
|
|
|
|
mkdirall(asmdirwork);
|
|
|
|
|
let asmdirav: []str = [driver(stages[si]), "build", "-S", "-w",
|
|
|
|
|
asmdirwork, "-I", include, "-o", asmdirstem, dirlink];
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-link-assembly-", tags[si]),
|
|
|
|
|
asmdirav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& !os.exists(asmdirstem) && readfile(ctrace).len != 0
|
|
|
|
|
&& readfile(atrace).len == 0 && readfile(ltrace).len == 0);
|
|
|
|
|
let asmdirsnapshot: str = strings.dup(
|
|
|
|
|
artifacttreesnapshot(asmdirwork));
|
|
|
|
|
assert(asmdirsnapshot.len != 0);
|
|
|
|
|
if (si == 0) { clinkdirasm = strings.dup(asmdirsnapshot); }
|
|
|
|
|
else { assert(same(clinkdirasm, asmdirsnapshot)); };
|
|
|
|
|
|
|
|
|
|
// Without -o, the requested directory spelling owns presentation only.
|
|
|
|
|
// Plain -S keeps that selection but stops before public output, assembler,
|
|
|
|
|
// and link actions just like the explicit assembly-only form.
|
|
|
|
|
let defaultcaller: str = strings.concat(root, "/link-default-caller-",
|
|
|
|
|
tags[si]);
|
|
|
|
|
let defaultwork: str = strings.concat(root, "/link-default-work-",
|
|
|
|
|
tags[si]);
|
|
|
|
|
mkdirall(defaultcaller); mkdirall(defaultwork);
|
|
|
|
|
let defaultdirav: []str = [driver(stages[si]), "build", "-w",
|
|
|
|
|
defaultwork, "-I", include, dirlink];
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenvdir(root, strings.concat("testonly-link-default-", tags[si]),
|
|
|
|
|
defaultdirav, env, defaultcaller,
|
|
|
|
|
(60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
let defaultdirout: str = strings.concat(defaultcaller,
|
|
|
|
|
"/directory_test.ww");
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& same(linkdirbytes, readfile(defaultdirout))
|
|
|
|
|
&& !os.exists(strings.concat(defaultcaller, "/directory-target"))
|
|
|
|
|
&& same(clinkdirartifacts, artifacttreesnapshot(defaultwork))
|
|
|
|
|
&& readfile(ctrace).len != 0 && readfile(atrace).len != 0
|
|
|
|
|
&& readfile(ltrace).len != 0);
|
|
|
|
|
let defaultrun: []str = [defaultdirout];
|
|
|
|
|
runcommand(root, strings.concat("testonly-link-default-run-", tags[si]),
|
|
|
|
|
defaultrun, time.second, &out);
|
|
|
|
|
expectexit(&out, 5);
|
|
|
|
|
let plainasmcaller: str = strings.concat(root, "/link-plain-asm-caller-",
|
|
|
|
|
tags[si]);
|
|
|
|
|
let plainasmwork: str = strings.concat(root, "/link-plain-asm-work-",
|
|
|
|
|
tags[si]);
|
|
|
|
|
mkdirall(plainasmcaller); mkdirall(plainasmwork);
|
|
|
|
|
let plainasmav: []str = [driver(stages[si]), "build", "-S", "-w",
|
|
|
|
|
plainasmwork, "-I", include, dirlink];
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenvdir(root, strings.concat("testonly-link-plain-assembly-",
|
|
|
|
|
tags[si]), plainasmav, env, plainasmcaller,
|
|
|
|
|
(60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& !os.exists(strings.concat(plainasmcaller, "/directory_test.ww"))
|
|
|
|
|
&& readfile(ctrace).len != 0 && readfile(atrace).len == 0
|
|
|
|
|
&& readfile(ltrace).len == 0);
|
|
|
|
|
let plainasmsnapshot: str = strings.dup(
|
|
|
|
|
artifacttreesnapshot(plainasmwork));
|
|
|
|
|
assert(same(asmdirsnapshot, plainasmsnapshot));
|
|
|
|
|
if (si == 0) { clinkdirplainasm = strings.dup(plainasmsnapshot); }
|
|
|
|
|
else { assert(same(clinkdirplainasm, plainasmsnapshot)); };
|
|
|
|
|
|
|
|
|
|
// A failed invalidation leaves the prior command and committed work
|
|
|
|
|
// byte-for-byte intact. A later successful invalidation and restoration
|
|
|
|
|
// reuse the same directory identity rather than a raw-source identity.
|
|
|
|
|
let dirtargetmain: str = strings.concat(dirtarget, "/main.ww");
|
|
|
|
|
let dirtargetoriginal: str = strings.concat(
|
|
|
|
|
"package main;\nimport domain.value;\n",
|
|
|
|
|
"fn main() i32 = { return value.number(); };\n");
|
|
|
|
|
let dirtargetchanged: str = strings.concat(
|
|
|
|
|
"package main;\nimport domain.value;\n",
|
|
|
|
|
"fn main() i32 = { return value.number() + 2; };\n");
|
|
|
|
|
let linkdirworkbefore: str = strings.dup(treesnapshot(linkdirwork));
|
|
|
|
|
rewritefile(dirtargetmain, dirtargetchanged);
|
|
|
|
|
env[failcindex] = "WW_TESTONLY_FAIL_C=1";
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-link-rollback-", tags[si]),
|
|
|
|
|
linkdirav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
assert(out.stdout.len == 0
|
|
|
|
|
&& has(out.stderr, "injected directory compiler failure\n")
|
|
|
|
|
&& same(linkdirbytes, readfile(linkdirout))
|
|
|
|
|
&& same(linkdirworkbefore, treesnapshot(linkdirwork))
|
|
|
|
|
&& readfile(ctrace).len != 0 && readfile(atrace).len == 0
|
|
|
|
|
&& readfile(ltrace).len == 0
|
|
|
|
|
&& !os.exists(strings.concat(linkdirout, ".new"))
|
|
|
|
|
&& !directoryhasnew(linkdirwork)
|
|
|
|
|
&& !directoryhasfragment(linkdirwork, ".wwtxn."));
|
|
|
|
|
if (si == 0) { compilerfaildiag = strings.dup(out.stderr); }
|
|
|
|
|
else { assert(same(compilerfaildiag, out.stderr)); };
|
|
|
|
|
env[failcindex] = "WW_TESTONLY_FAIL_C=";
|
|
|
|
|
env[linkmodeindex] = "WW_TESTONLY_LINK_MODE=signal";
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-link-interrupted-", tags[si]),
|
|
|
|
|
linkdirav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len != 0
|
|
|
|
|
&& has(out.stderr, "ww: w6l failed\n")
|
|
|
|
|
&& same(linkdirbytes, readfile(linkdirout))
|
|
|
|
|
&& same(linkdirworkbefore, treesnapshot(linkdirwork))
|
|
|
|
|
&& readfile(ctrace).len != 0 && readfile(atrace).len != 0
|
|
|
|
|
&& readfile(ltrace).len != 0
|
|
|
|
|
&& !os.exists(strings.concat(linkdirout, ".new"))
|
|
|
|
|
&& !directoryhasnew(linkdirwork)
|
|
|
|
|
&& !directoryhasfragment(linkdirwork, ".wwtxn."));
|
|
|
|
|
if (si == 0) { linkersignaldiag = strings.dup(out.stderr); }
|
|
|
|
|
else { assert(same(linkersignaldiag, out.stderr)); };
|
|
|
|
|
env[linkmodeindex] = "WW_TESTONLY_LINK_MODE=";
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-link-invalidated-", tags[si]),
|
|
|
|
|
linkdirav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
let changedbytes: str = strings.dup(readfile(linkdirout));
|
|
|
|
|
let changedartifacts: str = strings.dup(
|
|
|
|
|
artifacttreesnapshot(linkdirwork));
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& !same(linkdirbytes, changedbytes)
|
|
|
|
|
&& readfile(ctrace).len != 0 && readfile(atrace).len != 0
|
|
|
|
|
&& readfile(ltrace).len != 0);
|
|
|
|
|
if (si == 0) {
|
|
|
|
|
clinkdirchanged = strings.dup(changedbytes);
|
|
|
|
|
clinkdirchangedartifacts = strings.dup(changedartifacts);
|
|
|
|
|
} else {
|
|
|
|
|
assert(same(clinkdirchanged, changedbytes)
|
|
|
|
|
&& same(clinkdirchangedartifacts, changedartifacts));
|
|
|
|
|
};
|
|
|
|
|
runcommand(root, strings.concat("testonly-link-invalidated-run-", tags[si]),
|
|
|
|
|
linkdirrun, time.second, &out);
|
|
|
|
|
expectexit(&out, 7);
|
|
|
|
|
rewritefile(dirtargetmain, dirtargetoriginal);
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-link-restored-", tags[si]),
|
|
|
|
|
linkdirav, env, (60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& same(linkdirbytes, readfile(linkdirout))
|
|
|
|
|
&& same(clinkdirartifacts, artifacttreesnapshot(linkdirwork))
|
|
|
|
|
&& readfile(ctrace).len != 0 && readfile(atrace).len != 0
|
|
|
|
|
&& readfile(ltrace).len != 0
|
|
|
|
|
&& !directoryhasnew(linkdirwork)
|
|
|
|
|
&& !directoryhasfragment(linkdirwork, ".wwtxn."));
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
|
|
|
|
|
// A valid retained raw source seeds state. Renaming only its requested
|
|
|
|
|
@@ -1819,8 +2129,99 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|
|
|
|
&& same(cwarmartifacts, artifacttreesnapshot(warmwork)));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Test and run keep their existing raw-source semantics, while a visible
|
|
|
|
|
// non-test raw build and a multi-operand error do not enter this slice.
|
|
|
|
|
// Test, test -c, and test -S already route this symlink as a directory.
|
|
|
|
|
// Temporarily make its otherwise build-excluded test source valid and pin
|
|
|
|
|
// exact stage parity without changing the negative production-build rows.
|
|
|
|
|
rewritefile(dirtargettest, dirtargettestselected);
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
let directorytestwork: str = strings.concat(root, "/directory-test-work-",
|
|
|
|
|
tags[si]);
|
|
|
|
|
mkdirall(directorytestwork);
|
|
|
|
|
let directorytestav: []str = [driver(stages[si]), "test", "-w",
|
|
|
|
|
directorytestwork, "-I", include, dirlink];
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-directory-test-", tags[si]),
|
|
|
|
|
directorytestav, env,
|
|
|
|
|
(60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stderr.len == 0
|
|
|
|
|
&& has(out.stdout, "directory_selected ... ok\n")
|
|
|
|
|
&& readfile(ctrace).len != 0 && readfile(atrace).len != 0
|
|
|
|
|
&& readfile(ltrace).len != 0);
|
|
|
|
|
let directorytestrunstate: str = strings.dup(
|
|
|
|
|
artifacttreesnapshot(directorytestwork));
|
|
|
|
|
if (si == 0) {
|
|
|
|
|
directorytestrunout = strings.dup(out.stdout);
|
|
|
|
|
directorytestrunerr = strings.dup(out.stderr);
|
|
|
|
|
directorytestrunartifacts = strings.dup(directorytestrunstate);
|
|
|
|
|
} else {
|
|
|
|
|
assert(same(directorytestrunout, out.stdout)
|
|
|
|
|
&& same(directorytestrunerr, out.stderr)
|
|
|
|
|
&& same(directorytestrunartifacts, directorytestrunstate));
|
|
|
|
|
};
|
|
|
|
|
let directorycompiled: str = strings.concat(root,
|
|
|
|
|
"/directory-test-compiled-", tags[si]);
|
|
|
|
|
let directorycompilework: str = strings.concat(root,
|
|
|
|
|
"/directory-test-compile-work-", tags[si]);
|
|
|
|
|
mkdirall(directorycompilework);
|
|
|
|
|
let directorycompileav: []str = [driver(stages[si]), "test", "-c", "-w",
|
|
|
|
|
directorycompilework, "-I", include, "-o", directorycompiled, dirlink];
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-directory-test-compile-",
|
|
|
|
|
tags[si]), directorycompileav, env,
|
|
|
|
|
(60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 0);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0
|
|
|
|
|
&& os.exists(directorycompiled));
|
|
|
|
|
let directorycompiledbytes: str = strings.dup(readfile(directorycompiled));
|
|
|
|
|
let directorycompiledstate: str = strings.dup(
|
|
|
|
|
artifacttreesnapshot(directorycompilework));
|
|
|
|
|
if (si == 0) {
|
|
|
|
|
directorytestbin = strings.dup(directorycompiledbytes);
|
|
|
|
|
directorytestcompileartifacts = strings.dup(directorycompiledstate);
|
|
|
|
|
} else {
|
|
|
|
|
assert(same(directorytestbin, directorycompiledbytes)
|
|
|
|
|
&& same(directorytestcompileartifacts, directorycompiledstate));
|
|
|
|
|
};
|
|
|
|
|
let directorytestasmwork: str = strings.concat(root,
|
|
|
|
|
"/directory-test-assembly-work-", tags[si]);
|
|
|
|
|
let directorytestasmout: str = strings.concat(root,
|
|
|
|
|
"/directory-test-assembly-output-", tags[si]);
|
|
|
|
|
mkdirall(directorytestasmwork);
|
|
|
|
|
let directorytestasmav: []str = [driver(stages[si]), "test", "-S", "-w",
|
|
|
|
|
directorytestasmwork, "-I", include, "-o", directorytestasmout, dirlink];
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-directory-test-assembly-",
|
|
|
|
|
tags[si]), directorytestasmav, env,
|
|
|
|
|
(60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
expectexit(&out, 2);
|
|
|
|
|
assert(out.stdout.len == 0
|
|
|
|
|
&& same(out.stderr, "ww test: -S needs a single test file\n")
|
|
|
|
|
&& !os.exists(directorytestasmout)
|
|
|
|
|
&& directoryisempty(directorytestasmwork)
|
|
|
|
|
&& readfile(ctrace).len == 0 && readfile(atrace).len == 0
|
|
|
|
|
&& readfile(ltrace).len == 0);
|
|
|
|
|
if (si == 0) { directorytestasm = strings.dup(out.stderr); }
|
|
|
|
|
else { assert(same(directorytestasm, out.stderr)); };
|
|
|
|
|
|
|
|
|
|
// Run was not changed by the build-only dispatcher fix. Cstage follows
|
|
|
|
|
// the selected directory and executes it; WWstage retains its exact
|
|
|
|
|
// pre-existing raw-source failure for the same requested symlink.
|
|
|
|
|
let directoryrunav: []str = [driver(stages[si]), "run", "-I", include,
|
|
|
|
|
dirlink];
|
|
|
|
|
runcommandenv(root, strings.concat("testonly-directory-run-", tags[si]),
|
|
|
|
|
directoryrunav, env,
|
|
|
|
|
(60i64 * (time.second: i64)): time.duration, &out);
|
|
|
|
|
if (si == 0) {
|
|
|
|
|
expectexit(&out, 5);
|
|
|
|
|
assert(out.stdout.len == 0 && out.stderr.len == 0);
|
|
|
|
|
} else {
|
|
|
|
|
expectexit(&out, 1);
|
|
|
|
|
assert(out.stdout.len == 0
|
|
|
|
|
&& same(out.stderr, "ww: cannot read source\n"));
|
|
|
|
|
};
|
|
|
|
|
rewritefile(dirtargettest, dirtargettestexcluded);
|
|
|
|
|
|
|
|
|
|
// Raw-source test and run retain their separate existing semantics, while
|
|
|
|
|
// a visible non-test raw build and multi-operand error stay out of this slice.
|
|
|
|
|
rewritefile(ctrace, ""); rewritefile(atrace, ""); rewritefile(ltrace, "");
|
|
|
|
|
let testwork: str = strings.concat(root, "/route-work-", tags[si]);
|
|
|
|
|
mkdirall(testwork);
|
|
|
|
|
@@ -1891,9 +2292,76 @@ fn cwdwritedata(dir: str, label: str) void = {
|
|
|
|
|
assert(same(commentbad[0], commentbad[1]));
|
|
|
|
|
assert(same(multibad[0], multibad[1]));
|
|
|
|
|
|
|
|
|
|
// Simultaneous selected-directory requests use isolated work and output
|
|
|
|
|
// transactions while retaining exact cross-stage product and artifact bytes.
|
|
|
|
|
let ti: i32 = 0;
|
|
|
|
|
for (ti < stages.len) {
|
|
|
|
|
rewritefile(tracecs[ti], "");
|
|
|
|
|
rewritefile(traceas[ti], "");
|
|
|
|
|
rewritefile(tracels[ti], "");
|
|
|
|
|
ti += 1;
|
|
|
|
|
};
|
|
|
|
|
let pdcwork: str = strings.concat(root, "/parallel-directory-c-work");
|
|
|
|
|
let pdwwork: str = strings.concat(root, "/parallel-directory-ww-work");
|
|
|
|
|
let pdcout: str = strings.concat(root, "/parallel-directory-c-output");
|
|
|
|
|
let pdwout: str = strings.concat(root, "/parallel-directory-ww-output");
|
|
|
|
|
mkdirall(pdcwork); mkdirall(pdwwork);
|
|
|
|
|
let pdcav: []str = [driver("ww"), "build", "-w", pdcwork, "-I", include,
|
|
|
|
|
"-o", pdcout, dirlink];
|
|
|
|
|
let pdwav: []str = [driver("ww_ww"), "build", "-w", pdwwork, "-I",
|
|
|
|
|
include, "-o", pdwout, dirlink];
|
|
|
|
|
let pdc: exec.command;
|
|
|
|
|
pdc.path = pdcav[0]; pdc.argv = pdcav; pdc.env = environments[0];
|
|
|
|
|
pdc.dir = repo();
|
|
|
|
|
pdc.stdoutpath = strings.concat(root, "/parallel-directory-c.stdout");
|
|
|
|
|
pdc.stderrpath = strings.concat(root, "/parallel-directory-c.stderr");
|
|
|
|
|
pdc.deadline = time.add(time.now(time.clock.monotonic),
|
|
|
|
|
(60i64 * (time.second: i64)): time.duration);
|
|
|
|
|
pdc.grace = (100i64 * (time.millisecond: i64)): time.duration;
|
|
|
|
|
let pdw: exec.command;
|
|
|
|
|
pdw.path = pdwav[0]; pdw.argv = pdwav; pdw.env = environments[1];
|
|
|
|
|
pdw.dir = repo();
|
|
|
|
|
pdw.stdoutpath = strings.concat(root, "/parallel-directory-ww.stdout");
|
|
|
|
|
pdw.stderrpath = strings.concat(root, "/parallel-directory-ww.stderr");
|
|
|
|
|
pdw.deadline = time.add(time.now(time.clock.monotonic),
|
|
|
|
|
(60i64 * (time.second: i64)): time.duration);
|
|
|
|
|
pdw.grace = (100i64 * (time.millisecond: i64)): time.duration;
|
|
|
|
|
let pdcp: exec.process;
|
|
|
|
|
let pdwp: exec.process;
|
|
|
|
|
exec.start(&pdcp, &pdc); exec.start(&pdwp, &pdw);
|
|
|
|
|
let pdcdone: bool = false;
|
|
|
|
|
let pdwdone: bool = false;
|
|
|
|
|
for (!pdcdone || !pdwdone) {
|
|
|
|
|
if (!pdcdone) { pdcdone = exec.poll(&pdcp); };
|
|
|
|
|
if (!pdwdone) { pdwdone = exec.poll(&pdwp); };
|
|
|
|
|
if (!pdcdone || !pdwdone) {
|
|
|
|
|
time.sleep(time.millisecond, time.clock.monotonic);
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
assert(pdcp.result.errno == 0 && pdcp.result.cleanuperrno == 0
|
|
|
|
|
&& pdcp.result.termination == exec.termination.EXIT
|
|
|
|
|
&& pdcp.result.code == 0 && pdwp.result.errno == 0
|
|
|
|
|
&& pdwp.result.cleanuperrno == 0
|
|
|
|
|
&& pdwp.result.termination == exec.termination.EXIT
|
|
|
|
|
&& pdwp.result.code == 0);
|
|
|
|
|
assert(readfile(pdc.stdoutpath).len == 0
|
|
|
|
|
&& readfile(pdc.stderrpath).len == 0
|
|
|
|
|
&& readfile(pdw.stdoutpath).len == 0
|
|
|
|
|
&& readfile(pdw.stderrpath).len == 0
|
|
|
|
|
&& same(clinkdirbin, readfile(pdcout))
|
|
|
|
|
&& same(clinkdirbin, readfile(pdwout))
|
|
|
|
|
&& same(clinkdirartifacts, artifacttreesnapshot(pdcwork))
|
|
|
|
|
&& same(clinkdirartifacts, artifacttreesnapshot(pdwwork))
|
|
|
|
|
&& readfile(tracecs[0]).len != 0 && readfile(traceas[0]).len != 0
|
|
|
|
|
&& readfile(tracels[0]).len != 0 && readfile(tracecs[1]).len != 0
|
|
|
|
|
&& readfile(traceas[1]).len != 0 && readfile(tracels[1]).len != 0
|
|
|
|
|
&& !directoryhasnew(pdcwork) && !directoryhasnew(pdwwork)
|
|
|
|
|
&& !directoryhasfragment(pdcwork, ".wwtxn.")
|
|
|
|
|
&& !directoryhasfragment(pdwwork, ".wwtxn."));
|
|
|
|
|
|
|
|
|
|
// Two simultaneous omitted requests have no work/output collision and no
|
|
|
|
|
// producer invocation in either stage.
|
|
|
|
|
let ti: i32 = 0;
|
|
|
|
|
ti = 0;
|
|
|
|
|
for (ti < stages.len) {
|
|
|
|
|
rewritefile(tracecs[ti], "");
|
|
|
|
|
rewritefile(traceas[ti], "");
|
|
|
|
|
|