const std = @import("std"); const c9 = @import("cloud9"); const t = c9.transport; const testing = std.testing; test "standard readers and writers preserve frame boundaries" { var bytes: [128]u8 = undefined; const frame = try c9.encode(.{ .tversion = .{ .msize = 4096, .version = "9P2000" } }, c9.notag, &bytes); var source: testing.Reader = .init(&.{}, &.{.{ .buffer = frame }}); source.artificial_limit = .limited(1); var target: [128]u8 = undefined; const got = try t.readFrame(&source.interface, &target, 4096); try testing.expectEqualSlices(u8, frame, got); var output: [128]u8 = undefined; var writer: std.Io.Writer = .fixed(&output); try t.writeFrame(&writer, got, 4096); try testing.expectEqualSlices(u8, frame, writer.buffered()); } test "POSIX TCP and Unix streams handle retry and EOF" { var dir = testing.tmpDir(.{}); defer dir.cleanup(); const io = testing.io; var path_buffer: [std.fs.max_path_bytes]u8 = undefined; const parent_len = try dir.dir.realPath(io, &path_buffer); const parent = path_buffer[0..parent_len]; var unix_buffer: [t.sun_path_len]u8 = undefined; const unix = try std.fmt.bufPrintSentinel(&unix_buffer, "{s}/9p", .{parent}, 0); for ([_]t.Address{ .{ .tcp = .{ .ip4 = .loopback(0) } }, .{ .unix = unix } }) |address| { const listener = try t.listenFd(address, 4); defer t.close(listener); var destination = address; if (address == .tcp) { var actual: std.c.sockaddr.in = undefined; var len: std.c.socklen_t = @sizeOf(@TypeOf(actual)); try testing.expectEqual(@as(c_int, 0), std.c.getsockname(listener, @ptrCast(&actual), &len)); destination.tcp.setPort(std.mem.bigToNative(u16, actual.port)); } const client = try t.connectFd(destination, t.nowMs() + 1000); defer t.close(client); const server = (try t.acceptFd(listener, address == .tcp)) orelse return error.NoConnection; var buffer: [32]u8 = undefined; try testing.expectEqual(@as(?usize, null), try t.read(server, &buffer)); try testing.expectEqual(@as(?usize, 3), try t.write(client, "abc")); try t.wait(server, @intCast(std.c.POLL.IN), t.nowMs() + 1000); try testing.expectEqual(@as(?usize, 3), try t.read(server, &buffer)); try testing.expectEqualStrings("abc", buffer[0..3]); t.close(server); try t.wait(client, @intCast(std.c.POLL.IN), t.nowMs() + 1000); try testing.expectEqual(@as(?usize, 0), try t.read(client, &buffer)); } } test "std.Io TCP and Unix listener and client adapters" { var dir = testing.tmpDir(.{}); defer dir.cleanup(); const io = testing.io; var path_buffer: [std.fs.max_path_bytes]u8 = undefined; const parent_len = try dir.dir.realPath(io, &path_buffer); const parent = path_buffer[0..parent_len]; var unix_buffer: [t.sun_path_len]u8 = undefined; const unix = try std.fmt.bufPrintSentinel(&unix_buffer, "{s}/9p", .{parent}, 0); for ([_]t.Address{ .{ .tcp = .{ .ip4 = .loopback(0) } }, .{ .unix = unix } }) |address| { var listener = try t.listen(io, address, 4); defer listener.deinit(io); const destination: t.Address = if (address == .tcp) .{ .tcp = listener.socket.address } else address; const client = try t.connect(io, destination); defer client.close(io); const server = try listener.accept(io); defer server.close(io); var output: [128]u8 = undefined; var writer = client.writer(io, &output); var bytes: [128]u8 = undefined; const frame = try c9.encode(.rflush, 1, &bytes); try t.writeFrame(&writer.interface, frame, 4096); try writer.interface.flush(); var input: [128]u8 = undefined; var reader = server.reader(io, &input); var target: [128]u8 = undefined; try testing.expectEqualSlices(u8, frame, try t.readFrame(&reader.interface, &target, 4096)); } }