From 184db2654ceea7ae233171effa2581163d05507d Mon Sep 17 00:00:00 2001 From: Anund Date: Thu, 26 Dec 2024 14:48:03 +1100 Subject: [PATCH] testing: handle execveZ failing during test execution Duplicating a test process via fork does unexepected things. zig build test will hang A test binary created via -Demit-test-exe will run 2 copies of the test suite --- src/Command.zig | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Command.zig b/src/Command.zig index 2b600979f..09ae86d84 100644 --- a/src/Command.zig +++ b/src/Command.zig @@ -182,9 +182,10 @@ fn startPosix(self: *Command, arena: Allocator) !void { _ = posix.execveZ(pathZ, argsZ, envp) catch null; // If we are executing this code, the exec failed. In that scenario, - // we return a very specific error that can be detected to determine - // we're in the child. - return error.ExecFailedInChild; + // terminate so we don't duplicate the original process + // note: returning to test code from this point would run 2 copies of the test suite + std.debug.print("failed to execveZ as child process, terminating", .{}); + std.process.exit(1); } fn startWindows(self: *Command, arena: Allocator) !void { @@ -722,3 +723,32 @@ test "Command: custom working directory" { try testing.expectEqualStrings("/usr/bin\n", contents); } } + +// Duplicating a test process via fork does unexepected things. +// zig build test will hang +// test binary created via -Demit-test-exe will run 2 copies of the test suite +// +// This test relys on cmd.start -> posix.start terminating the child process rather +// than returning to avoid those two strange behaviours +test "Command: posix fork handles execveZ failure" { + if (builtin.os.tag == .windows) { + return error.SkipZigTest; + } + var td = try TempDir.init(); + defer td.deinit(); + var stdout = try createTestStdout(td.dir); + defer stdout.close(); + + var cmd: Command = .{ + .path = "/not/a/binary", + .args = &.{ "/not/a/binary", "" }, + .stdout = stdout, + .cwd = "/bin", + }; + + try cmd.start(testing.allocator); + try testing.expect(cmd.pid != null); + const exit = try cmd.wait(true); + try testing.expect(exit == .Exited); + try testing.expect(exit.Exited == 1); +}