d81f7277
test: the browser stand-in re-attaches on every `up`, as the page does
a73x 2026-08-26 14:26
Commit message
test/wsclient.zig
| Old | New | ||
|---|---|---|---|
| @@ -17,6 +17,8 @@ | |||
| 17 | //! expectrefused MS wait for an exit_status that arrived before any | 17 | //! expectrefused MS wait for an exit_status that arrived before any |
| 18 | //! grid — the browser's own refusal discriminator | 18 | //! grid — the browser's own refusal discriminator |
| 19 | //! expectups N MS wait until N `up` control messages have arrived | 19 | //! expectups N MS wait until N `up` control messages have arrived |
| 20 | //! reattach C R MS [NAME] mux.js's ENV_CONTROL handler for MS ms: attach | ||
| 21 | //! once now and once per `up` that follows | ||
| 20 | //! settle QUIET MS drain frames until QUIET ms of silence | 22 | //! settle QUIET MS drain frames until QUIET ms of silence |
| 21 | //! dumpexit write the replica grid (muxd dump format) to | 23 | //! dumpexit write the replica grid (muxd dump format) to |
| 22 | //! --out and exit 0 | 24 | //! --out and exit 0 |
| @@ -523,6 +525,33 @@ pub fn main() !void { | |||
| 523 | if (nowMs() >= deadline) fatal(EXIT_TIMEOUT, "expectups {d} timed out at {d}", .{ want, cl.ups }); | 525 | if (nowMs() >= deadline) fatal(EXIT_TIMEOUT, "expectups {d} timed out at {d}", .{ want, cl.ups }); |
| 524 | if (!cl.pump(50)) fatal(EXIT_DIED, "hub hung up during expectups", .{}); | 526 | if (!cl.pump(50)) fatal(EXIT_DIED, "hub hung up during expectups", .{}); |
| 525 | } | 527 | } |
| 528 | } else if (std.mem.eql(u8, verb, "reattach")) { | ||
| 529 | // The page's own reflex, which no other verb models: mux.js | ||
| 530 | // re-attaches on EVERY `up`, so a hub that redials in a tight | ||
| 531 | // loop gets a tight loop of attaches back. A scenario that | ||
| 532 | // scripted a fixed number of attaches would measure its own | ||
| 533 | // script instead of the hub's dial rate. | ||
| 534 | var it = std.mem.tokenizeScalar(u8, rest, ' '); | ||
| 535 | const cols = std.fmt.parseInt(u16, it.next() orelse fatal(EXIT_USAGE, "reattach C R MS [NAME]", .{}), 10) catch fatal(EXIT_USAGE, "reattach C R MS [NAME]", .{}); | ||
| 536 | const rows = std.fmt.parseInt(u16, it.next() orelse fatal(EXIT_USAGE, "reattach C R MS [NAME]", .{}), 10) catch fatal(EXIT_USAGE, "reattach C R MS [NAME]", .{}); | ||
| 537 | const ms = std.fmt.parseInt(i64, it.next() orelse fatal(EXIT_USAGE, "reattach C R MS [NAME]", .{}), 10) catch fatal(EXIT_USAGE, "reattach C R MS [NAME]", .{}); | ||
| 538 | const name = it.next() orelse ""; | ||
| 539 | if (name.len > 0 and !proto.validSessionName(name)) | ||
| 540 | fatal(EXIT_USAGE, "reattach C R MS [NAME]: bad session name {s}", .{name}); | ||
| 541 | if (it.next() != null) fatal(EXIT_USAGE, "reattach C R MS [NAME] takes at most four arguments", .{}); | ||
| 542 | const deadline = nowMs() + ms; | ||
| 543 | var seen = cl.ups; | ||
| 544 | cl.sendAttach(cols, rows, true, name); | ||
| 545 | while (nowMs() < deadline) { | ||
| 546 | // A hub that hangs up ends the window rather than the run: | ||
| 547 | // the dial count outside is the assertion, and it is | ||
| 548 | // readable either way. | ||
| 549 | if (!cl.pump(50)) break; | ||
| 550 | if (cl.ups != seen) { | ||
| 551 | seen = cl.ups; | ||
| 552 | cl.sendAttach(cols, rows, true, name); | ||
| 553 | } | ||
| 554 | } | ||
| 526 | } else if (std.mem.eql(u8, verb, "settle")) { | 555 | } else if (std.mem.eql(u8, verb, "settle")) { |
| 527 | var it = std.mem.tokenizeScalar(u8, rest, ' '); | 556 | var it = std.mem.tokenizeScalar(u8, rest, ' '); |
| 528 | const quiet = std.fmt.parseInt(i64, it.next() orelse fatal(EXIT_USAGE, "settle QUIET MS", .{}), 10) catch fatal(EXIT_USAGE, "settle QUIET MS", .{}); | 557 | const quiet = std.fmt.parseInt(i64, it.next() orelse fatal(EXIT_USAGE, "settle QUIET MS", .{}), 10) catch fatal(EXIT_USAGE, "settle QUIET MS", .{}); |