diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-20 00:58:22 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-09-20 00:58:22 -0300 |
| commit | 65209217b5b68f56bc0bd5bc6c4dce33911ded59 (patch) | |
| tree | be3848ef46b7a2ce1d0ad1a768b7a97d428481c4 /src/session_test.zig | |
| parent | 3e9f8805f293f622bb885cf849b5ce47dc062ad1 (diff) | |
| download | cloud9-65209217b5b68f56bc0bd5bc6c4dce33911ded59.tar.gz cloud9-65209217b5b68f56bc0bd5bc6c4dce33911ded59.zip | |
Add the file-server engine: cloud9.fs.Server(Backend, Options)
The asynchronous 9P file-server engine from the Pardes editor moves into the
library: fid table, walks, directory cursors, a job/slot model where backend
replies arrive later by tag (status again = parked), Tflush cancellation and
orphaned fids on hangup. Allocation-free, no OS calls, no std.Io; comptime
Options (fid, slot, park data, name and user capacities) replace the
editor's constants. Backend contract types (Req, Reply/ReplyWith, Op,
Status, Attr, E, error strings) live here. 29 engine tests plus the client
tests that sat beside it in Pardes.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Diffstat (limited to 'src/session_test.zig')
| -rw-r--r-- | src/session_test.zig | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/session_test.zig b/src/session_test.zig index 8600d03..f31ff31 100644 --- a/src/session_test.zig +++ b/src/session_test.zig @@ -220,3 +220,106 @@ test "server reserves cancellation capacity and rejects duplicate pending tags" try testing.expectError(error.Protocol, server.receive()); try testing.expect(server.dead); } + +test "client: an msize below the floor, and one the server tried to raise" { + var in: [512]u8 = undefined; + var out: [512]u8 = undefined; + var buf: [64]u8 = undefined; + + var c = c9.Client.init(.{ .in = &in, .out = &out }); + try testing.expectError(error.BadRequest, c.submit(.{ .version = .{ .msize = c9.Server.msize_min - 1 } })); + _ = try c.submit(.{ .version = .{} }); + try testing.expectEqual(@as(u32, 512), c.asked); + + _ = c.push(try c9.encode(.{ .rversion = .{ .msize = 1024, .version = "9P2000" } }, c9.notag, &buf)); + try testing.expect(c.take() == null); + try testing.expect(c.dead); + + var c2 = c9.Client.init(.{ .in = &in, .out = &out }); + _ = try c2.submit(.{ .version = .{} }); + _ = c2.push(try c9.encode(.{ .rversion = .{ .msize = 512, .version = "unknown" } }, c9.notag, &buf)); + const done = c2.take() orelse return error.NoReply; + try testing.expectEqualStrings("unknown", done.result.version.version); + try testing.expect(!c2.dead); + try testing.expectEqual(@as(u32, 0), c2.msize); + try testing.expectError(error.Handshake, c2.submit(.{ .stat = .{ .fid = 0 } })); + + var c3 = c9.Client.init(.{ .in = &in, .out = &out }); + _ = try c3.submit(.{ .version = .{} }); + _ = c3.push(try c9.encode(.{ .rversion = .{ .msize = 512, .version = "9P2000.u" } }, c9.notag, &buf)); + try testing.expect(c3.take() == null); + try testing.expect(c3.dead); +} + +test "client: what is not an answer to one of our requests ends the connection" { + var buf: [64]u8 = undefined; + const Case = struct { + fn armed(in: []u8, out: []u8, scratch: []u8) !c9.Client { + var c = c9.Client.init(.{ .in = in, .out = out }); + _ = try c.submit(.{ .version = .{} }); + c.wrote(c.output().len); + _ = c.push(try c9.encode(.{ .rversion = .{ .msize = 512, .version = "9P2000" } }, c9.notag, scratch)); + _ = c.take() orelse return error.NoReply; + _ = try c.submit(.{ .stat = .{ .fid = 0 } }); + c.wrote(c.output().len); + return c; + } + }; + var in: [512]u8 = undefined; + var out: [512]u8 = undefined; + + { + var c = try Case.armed(&in, &out, &buf); + _ = c.push(try c9.encode(.{ .tstat = .{ .fid = 0 } }, 0, &buf)); + try testing.expect(c.take() == null); + try testing.expect(c.dead); + } + { + var c = try Case.armed(&in, &out, &buf); + _ = c.push(try c9.encode(.rclunk, 3, &buf)); + try testing.expect(c.take() == null); + try testing.expect(c.dead); + } + { + var c = try Case.armed(&in, &out, &buf); + _ = c.push(try c9.encode(.rclunk, 900, &buf)); + try testing.expect(c.take() == null); + try testing.expect(c.dead); + } + { + var c = try Case.armed(&in, &out, &buf); + _ = c.push(try c9.encode(.rclunk, 0, &buf)); + try testing.expect(c.take() == null); + try testing.expect(c.dead); + } + { + var c = try Case.armed(&in, &out, &buf); + _ = c.push(try c9.encode(.rwstat, 0, &buf)); + try testing.expect(c.take() == null); + try testing.expect(c.dead); + } + { + var c = try Case.armed(&in, &out, &buf); + _ = c.push(&.{ 3, 0, 0, 0 }); + try testing.expect(c.take() == null); + try testing.expect(c.dead); + } + { + var c = try Case.armed(&in, &out, &buf); + _ = c.push(&.{ 0, 4, 0, 0 }); + try testing.expect(c.take() == null); + try testing.expect(c.dead); + } + { + var c = try Case.armed(&in, &out, &buf); + _ = c.push(&.{ 8, 0, 0, 0, @intFromEnum(c9.Type.rstat), 0, 0, 0 }); + try testing.expect(c.take() == null); + try testing.expect(c.dead); + } +} + +test "client: session memory is bounded independently of input" { + try testing.expect(@sizeOf(c9.Client) <= 512); + try testing.expect(2 * 8192 + @sizeOf(c9.Client) <= 17 * 1024); + try testing.expect(2 * c9.Server.msize_min + @sizeOf(c9.Client) <= 700); +} |
