ww test: preserve combined product output order

Go 1.26.5 maps each test binary's stdout and stderr to the same product writer. Teach the captured executor to share one open file description for byte-equal output paths, then make directory test products emit that one ordered capture on coordinator stdout. Build captures and inherited-stdio routes remain unchanged.\n\nKeep the executor mechanism, package policy, native Cstage/WWstage proof, and normative contract together so every commit preserves the observable test-output behavior.
This commit is contained in:
2026-08-20 18:29:09 +09:00
parent b996099270
commit f28843f2f5
7 changed files with 310 additions and 48 deletions

View File

@@ -35,8 +35,7 @@ type pkggroup = struct {
root: str,
bin: str,
buildok: str,
runout: str,
runerr: str,
runoutput: str,
state: i32,
runstartfailed: bool,
runres: exec.result,
@@ -1359,8 +1358,7 @@ fn pkgsetplanpaths(p: *pkgplan, groups: []pkggroup, root: str, index: i32,
} else {
if (!pkgstring(&g.bin, g.root, "/package.test")) { return false; };
};
if (!pkgstring(&g.runout, g.root, "/test.stdout")
|| !pkgstring(&g.runerr, g.root, "/test.stderr")
if (!pkgstring(&g.runoutput, g.root, "/test.output")
|| !pkgstring(&g.buildok, g.root, "/build.ok")) { return false; };
i += 1;
};
@@ -1374,27 +1372,28 @@ fn pkglabel(g: *pkggroup) void = {
pkgput(os.STDOUT_FILENO, "]");
};
fn pkgreportcommand(kind: str, g: *pkggroup, r: *exec.result) void = {
pkgput(os.STDERR_FILENO, "FAIL ");
pkgput(os.STDERR_FILENO, g.dir);
pkgput(os.STDERR_FILENO, " [");
pkgput(os.STDERR_FILENO, g.pkg);
pkgput(os.STDERR_FILENO, "] (");
pkgput(os.STDERR_FILENO, kind);
fn pkgreportcommand(fd: i32, kind: str, g: *pkggroup,
r: *exec.result) void = {
pkgput(fd, "FAIL ");
pkgput(fd, g.dir);
pkgput(fd, " [");
pkgput(fd, g.pkg);
pkgput(fd, "] (");
pkgput(fd, kind);
if (r.errno != 0 || r.cleanuperrno != 0
|| r.termination == exec.termination.ERROR) {
pkgput(os.STDERR_FILENO, " harness error ");
pkgput(fd, " harness error ");
let code: i32 = r.errno;
if (code == 0) { code = r.cleanuperrno; };
pkgput(os.STDERR_FILENO, strconv.i32tos(code, strconv.base.DEC));
pkgput(fd, strconv.i32tos(code, strconv.base.DEC));
} else if (r.termination == exec.termination.SIGNAL) {
pkgput(os.STDERR_FILENO, " signal ");
pkgput(os.STDERR_FILENO, strconv.i32tos(r.code, strconv.base.DEC));
pkgput(fd, " signal ");
pkgput(fd, strconv.i32tos(r.code, strconv.base.DEC));
} else {
pkgput(os.STDERR_FILENO, " exit ");
pkgput(os.STDERR_FILENO, strconv.i32tos(r.code, strconv.base.DEC));
pkgput(fd, " exit ");
pkgput(fd, strconv.i32tos(r.code, strconv.base.DEC));
};
pkgputln(os.STDERR_FILENO, ")");
pkgputln(fd, ")");
};
fn pkgstartbuild(p: *pkgplan, groups: []pkggroup, builder: str, includes: []str,
@@ -1542,8 +1541,8 @@ fn pkgstartrun(g: *pkggroup, filters: []str, timeoutarg: str,
rcmd.argv = ra;
rcmd.env = env;
rcmd.dir = g.dir;
rcmd.stdoutpath = g.runout;
rcmd.stderrpath = g.runerr;
rcmd.stdoutpath = g.runoutput;
rcmd.stderrpath = g.runoutput;
rcmd.deadline.sec = 0i64;
rcmd.deadline.nsec = 0i64;
rcmd.grace = 0i64: time.duration;
@@ -1580,16 +1579,14 @@ fn pkgemitgroup(g: *pkggroup, compileonly: bool) bool = {
return true;
};
if (g.runstartfailed) { return false; };
let runstdout: str;
let runstderr: str;
if (!pkgread(g.runout, &runstdout) || !pkgread(g.runerr, &runstderr)) {
let runoutput: str;
if (!pkgread(g.runoutput, &runoutput)) {
pkgfailpath(g.root, "cannot read test capture");
return false;
};
pkgput(os.STDOUT_FILENO, runstdout);
pkgput(os.STDERR_FILENO, runstderr);
pkgput(os.STDOUT_FILENO, runoutput);
if (!pkgrunok(g)) {
pkgreportcommand("test", g, &g.runres);
pkgreportcommand(os.STDOUT_FILENO, "test", g, &g.runres);
return false;
};
pkgput(os.STDOUT_FILENO, "ok ");
@@ -1612,7 +1609,8 @@ fn pkgemitplan(p: *pkgplan, groups: []pkggroup,
let i: i32 = p.start;
for (i < p.end) {
if (!pkgproductbuilt(&groups[i], buildonly)) {
pkgreportcommand("build", &groups[i], &p.buildres);
pkgreportcommand(os.STDERR_FILENO, "build", &groups[i],
&p.buildres);
failed += 1;
} else if (buildonly) {
void;