d39f9927
test: the handoff stderr check asks whether fd 2 is a pipe
a73x 2026-09-03 19:13
Commit message
src/client/client.zig
| Old | New | ||
|---|---|---|---|
| @@ -2378,9 +2378,15 @@ test "openHandoff: the handoff ssh's stderr is a pipe, and only `narrate` relays | |||
| 2378 | // A hosts line naming a box that is down used to put ssh's `No route to | 2378 | // A hosts line naming a box that is down used to put ssh's `No route to |
| 2379 | // host` onto the wall's alternate screen every poll, because the child's | 2379 | // host` onto the wall's alternate screen every poll, because the child's |
| 2380 | // stderr was INHERITED. It is a pipe mux reads now, whoever dialled. The | 2380 | // stderr was INHERITED. It is a pipe mux reads now, whoever dialled. The |
| 2381 | // fake records where its stderr POINTED, off `/dev/fd/2`, so "piped" is | 2381 | // fake records what KIND of file its stderr is, off `/dev/fd/2`, so |
| 2382 | // exact — `/dev/fd` because every OS this builds for has it and the | 2382 | // "piped" is exact — `/dev/fd` because every OS this builds for has it |
| 2383 | // Linux-only spelling would have to be ported alongside the test. | 2383 | // and the Linux-only spelling would have to be ported alongside the test. |
| 2384 | // Asked with `test -p` rather than by reading a link target: on Linux | ||
| 2385 | // `/dev/fd/2` is a symlink to `pipe:[N]` and on Darwin it is an entry of | ||
| 2386 | // the fdesc filesystem that is not a symlink at all, so `readlink` there | ||
| 2387 | // answers nothing and the check passed on an empty file. `test -p` stats | ||
| 2388 | // the path on both and reports the underlying object's type, which is the | ||
| 2389 | // claim being made. | ||
| 2384 | // BOTH values of `asked`, because the rule is the spawn's. | 2390 | // BOTH values of `asked`, because the rule is the spawn's. |
| 2385 | const alloc = std.testing.allocator; | 2391 | const alloc = std.testing.allocator; |
| 2386 | var stdin = try FakeStdin.install(""); | 2392 | var stdin = try FakeStdin.install(""); |
| @@ -2394,7 +2400,7 @@ test "openHandoff: the handoff ssh's stderr is a pipe, and only `narrate` relays | |||
| 2394 | 2400 | ||
| 2395 | var script_buf: [1024]u8 = undefined; | 2401 | var script_buf: [1024]u8 = undefined; |
| 2396 | const script = try std.fmt.bufPrint(&script_buf, | 2402 | const script = try std.fmt.bufPrint(&script_buf, |
| 2397 | \\readlink /dev/fd/2 > {[d]s}/e | 2403 | \\if [ -p /dev/fd/2 ]; then echo pipe > {[d]s}/e; else echo "not a pipe" > {[d]s}/e; fi |
| 2398 | \\printf 'boom: no route\n' >&2 | 2404 | \\printf 'boom: no route\n' >&2 |
| 2399 | \\exit 1 | 2405 | \\exit 1 |
| 2400 | , .{ .d = tmp.path() }); | 2406 | , .{ .d = tmp.path() }); |
| @@ -2416,7 +2422,7 @@ test "openHandoff: the handoff ssh's stderr is a pipe, and only `narrate` relays | |||
| 2416 | 2422 | ||
| 2417 | var err_buf: [std.fs.max_path_bytes]u8 = undefined; | 2423 | var err_buf: [std.fs.max_path_bytes]u8 = undefined; |
| 2418 | const on_err = try shimSaid(tmp.path(), "e", &err_buf); | 2424 | const on_err = try shimSaid(tmp.path(), "e", &err_buf); |
| 2419 | try std.testing.expect(std.mem.startsWith(u8, on_err, "pipe:")); | 2425 | try std.testing.expectEqualStrings("pipe", on_err); |
| 2420 | // Kept in every case: the picker row is painted from a dial | 2426 | // Kept in every case: the picker row is painted from a dial |
| 2421 | // nobody narrated, which is the whole point of keeping it here | 2427 | // nobody narrated, which is the whole point of keeping it here |
| 2422 | // rather than letting the bytes fall out onto a screen. | 2428 | // rather than letting the bytes fall out onto a screen. |