From b16a47efaec7b1becc922c52f19854e71cab8cb2 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Wed, 4 Mar 2026 18:34:42 +0100 Subject: [PATCH] fix: ip_tcp_client_server.zig testcase --- test/ip_tcp_client_server.cpp | 6 --- test/ip_tcp_client_server.zig | 89 +++++++++++++++++++++++++++-------- test/tests_cpp.zig | 10 ++++ 3 files changed, 79 insertions(+), 26 deletions(-) diff --git a/test/ip_tcp_client_server.cpp b/test/ip_tcp_client_server.cpp index 766df78..5202517 100644 --- a/test/ip_tcp_client_server.cpp +++ b/test/ip_tcp_client_server.cpp @@ -52,17 +52,14 @@ struct client_connection { auto receive(const buffer &m) { int written{}; - int err{}; string_view buf{}; if (m("socket", "client_connection", "read_complete", extract(buf))) { check(buf == "ping"); - check(err == 0); socket.write("pong"); } else if (m("socket", "client_connection", "write_complete", extract(written))) { check(written == 4); - check(err == 0); // socket.close(); // let server close } else if (m("socket", "client_connection", "closed")) { auto ret = connector.send("client_connection", "done"); @@ -130,17 +127,14 @@ struct server_connection { auto receive(const buffer &m) { int written{}; - int err{}; string_view buf{}; if (m("socket", "server_connection", "write_complete", extract(written))) { check(written == 4); - check(err == 0); socket.read(); } else if (m("socket", "server_connection", "read_complete", extract(buf))) { check(buf == "pong"); - check(err == 0); socket.close(); } else if (m("socket", "server_connection", "closed")) { auto ret = server.send("server_connection", "done"); diff --git a/test/ip_tcp_client_server.zig b/test/ip_tcp_client_server.zig index 8bc696f..59f8fd0 100644 --- a/test/ip_tcp_client_server.zig +++ b/test/ip_tcp_client_server.zig @@ -3,6 +3,7 @@ const thespian = @import("thespian"); const Allocator = std.mem.Allocator; +const exit = thespian.exit; const exit_normal = thespian.exit_normal; const exit_error = thespian.exit_error; const result = thespian.result; @@ -23,10 +24,6 @@ const tcp_acceptor = thespian.tcp_acceptor; const tcp_connector = thespian.tcp_connector; const in6addr_loopback = thespian.in6addr_loopback; -pub const std_options = .{ - .log_level = .err, -}; - const ClientConnection = struct { allocator: Allocator, sock: socket, @@ -36,7 +33,12 @@ const ClientConnection = struct { const Args = struct { allocator: Allocator, fd: i32, client_pid: pid }; fn start(args: Args) result { - const sock = socket.init("client_connection", args.fd) catch |e| return exit_error(e, @errorReturnTrace()); + std.log.err("ClientConnection.start entered fd={d}", .{args.fd}); + const sock = socket.init("client_connection", args.fd) catch |e| { + std.log.err("ClientConnection.start socket.init FAILED: {any}", .{e}); + return exit_error(e, @errorReturnTrace()); + }; + std.log.err("ClientConnection.start socket created", .{}); var self = args.allocator.create(@This()) catch |e| return exit_error(e, @errorReturnTrace()); self.* = .{ .allocator = args.allocator, @@ -45,13 +47,20 @@ const ClientConnection = struct { .receiver = .init(receive_safe, self), }; errdefer self.deinit(); - self.sock.read() catch |e| return exit_error(e, @errorReturnTrace()); + self.sock.read() catch |e| { + std.log.err("ClientConnection.start sock.read FAILED: {any}", .{e}); + return exit_error(e, @errorReturnTrace()); + }; + std.log.err("ClientConnection.start calling receive()", .{}); thespian.receive(&self.receiver); + std.log.err("ClientConnection.start returning", .{}); } fn deinit(self: *@This()) void { + self.sock.deinit(); self.client_pid.deinit(); self.allocator.destroy(self); + std.log.err("ClientConnection.deinit: client connection destroyed", .{}); } fn receive_safe(self: *@This(), from: pid_ref, m: message) result { @@ -60,18 +69,25 @@ const ClientConnection = struct { } fn receive(self: *@This(), _: pid_ref, m: message) !void { + std.log.err("ClientConnection.receive msg={f}", .{m}); var buf: []const u8 = ""; var written: i64 = 0; if (try m.match(.{ "socket", "client_connection", "read_complete", extract(&buf) })) { - if (std.mem.eql(u8, buf, "ping")) - try self.sock.write("pong"); + std.log.err("ClientConnection.receive: read_complete buf={s}", .{buf}); + try std.testing.expectEqualSlices(u8, "ping", buf); + try self.sock.write("pong"); + // try self.sock.read(); } else if (try m.match(.{ "socket", "client_connection", "write_complete", extract(&written) })) { - // just wait for server to close + std.log.err("ClientConnection.receive: write_complete written={d}", .{written}); + try std.testing.expectEqual(4, written); + // wait for server to close - must keep a read pending to detect it + // try self.sock.read(); } else if (try m.match(.{ "socket", "client_connection", "closed" })) { - // connection done + std.log.err("ClientConnection.receive: closed, sending done", .{}); _ = self.client_pid.send(.{ "client_connection", "done" }) catch {}; - return exit_normal(); + return exit("success"); } else { + std.log.err("ClientConnection.receive: UNEXPECTED msg={f}", .{m}); return unexpected(m); } } @@ -90,6 +106,7 @@ const Client = struct { } fn init(args: Args) !void { + std.log.err("Client.init entered port={d}", .{args.port}); const connector: tcp_connector = try .init("client"); var self = try args.allocator.create(@This()); self.* = .{ @@ -100,12 +117,15 @@ const Client = struct { }; errdefer self.deinit(); try self.connector.connect(in6addr_loopback, args.port); + std.log.err("Client.init connect() called, calling receive()", .{}); thespian.receive(&self.receiver); + std.log.err("Client.init returning", .{}); } fn deinit(self: *@This()) void { self.server_pid.deinit(); self.allocator.destroy(self); + std.log.err("Client.deinit: client destroyed", .{}); } fn receive_safe(self: *@This(), from: pid_ref, m: message) result { @@ -114,17 +134,22 @@ const Client = struct { } fn receive(self: *@This(), _: pid_ref, m: message) !void { + std.log.err("Client.receive msg={f}", .{m}); var fd: i32 = 0; if (try m.match(.{ "connector", "client", "connected", extract(&fd) })) { + std.log.err("Client.receive: connected fd={d}, spawning ClientConnection", .{fd}); _ = try spawn_link(self.allocator, ClientConnection.Args{ .allocator = self.allocator, .fd = fd, .client_pid = self_pid().clone(), }, ClientConnection.start, "client_connection"); + std.log.err("Client.receive: ClientConnection spawned", .{}); } else if (try m.match(.{ "client_connection", "done" })) { + std.log.err("Client.receive: client_connection done, exiting", .{}); _ = try self.server_pid.send(.{ "client", "done" }); return exit_normal(); } else { + std.log.err("Client.receive: UNEXPECTED msg={f}", .{m}); return unexpected(m); } } @@ -143,6 +168,7 @@ const ServerConnection = struct { } fn init(args: Args) !void { + std.log.err("ServerConnection.init entered fd={d}", .{args.fd}); const sock = try socket.init("server_connection", args.fd); var self = try args.allocator.create(@This()); self.* = .{ @@ -153,12 +179,16 @@ const ServerConnection = struct { }; errdefer self.deinit(); try self.sock.write("ping"); + std.log.err("ServerConnection.init write(ping) called, calling receive()", .{}); thespian.receive(&self.receiver); + std.log.err("ServerConnection.init returning", .{}); } fn deinit(self: *@This()) void { + self.sock.deinit(); self.server_pid.deinit(); self.allocator.destroy(self); + std.log.err("ServerConnection.deinit: server connection destroyed", .{}); } fn receive_safe(self: *@This(), from: pid_ref, m: message) result { @@ -167,21 +197,26 @@ const ServerConnection = struct { } fn receive(self: *@This(), _: pid_ref, m: message) !void { + std.log.err("ServerConnection.receive msg={f}", .{m}); var buf: []const u8 = ""; var written: i64 = 0; if (try m.match(.{ "socket", "server_connection", "write_complete", extract(&written) })) { + std.log.err("ServerConnection.receive: write_complete written={d}", .{written}); + try std.testing.expectEqual(4, written); // ping sent, start reading try self.sock.read(); } else if (try m.match(.{ "socket", "server_connection", "read_complete", extract(&buf) })) { + std.log.err("ServerConnection.receive: read_complete buf={s}", .{buf}); + try std.testing.expectEqualSlices(u8, "pong", buf); // received pong, close socket - if (std.mem.eql(u8, buf, "pong")) - try self.sock.close(); + try self.sock.close(); } else if (try m.match(.{ "socket", "server_connection", "closed" })) { - // connection done, notify server - _ = self.server_pid.send(.{ "server_connection", "done" }) catch {}; - return exit_normal(); + std.log.err("ServerConnection.receive: closed, sending done", .{}); + self.server_pid.send(.{ "server_connection", "done" }) catch |e| return exit_error(e, @errorReturnTrace()); + return exit("success"); } else { + std.log.err("ServerConnection.receive: UNEXPECTED msg={f}", .{m}); return unexpected(m); } } @@ -202,6 +237,7 @@ const Server = struct { } fn init(args: Args) !void { + std.log.err("Server.init entered", .{}); const acceptor: tcp_acceptor = try .init("server"); var self = try args.allocator.create(@This()); self.* = .{ @@ -212,19 +248,23 @@ const Server = struct { errdefer self.deinit(); const port = try self.acceptor.listen(in6addr_loopback, 0); + std.log.err("Server.init listening on port={d}", .{port}); _ = try spawn_link(args.allocator, Client.Args{ .allocator = args.allocator, .server_pid = self_pid().clone(), .port = port, }, Client.start, "client"); + std.log.err("Server.init Client spawned, calling receive()", .{}); thespian.receive(&self.receiver); + std.log.err("Server.init returning", .{}); } fn deinit(self: *@This()) void { self.acceptor.deinit(); self.allocator.destroy(self); + std.log.err("Server.deinit: server destroyed", .{}); } fn receive_safe(self: *@This(), from: pid_ref, m: message) result { @@ -233,26 +273,34 @@ const Server = struct { } fn receive(self: *@This(), _: pid_ref, m: message) !void { + std.log.err("Server.receive msg={f}", .{m}); var fd: i32 = 0; if (try m.match(.{ "acceptor", "server", "accept", extract(&fd) })) { + std.log.err("Server.receive: accept fd={d}, spawning ServerConnection", .{fd}); _ = try spawn_link(self.allocator, ServerConnection.Args{ .allocator = self.allocator, .fd = fd, .server_pid = self_pid().clone(), }, ServerConnection.start, "server_connection"); - // just one connection for this test + std.log.err("Server.receive: ServerConnection spawned, closing acceptor", .{}); try self.acceptor.close(); } else if (try m.match(.{ "acceptor", "server", "closed" })) { + std.log.err("Server.receive: acceptor closed (flags: client={} conn={})", .{ self.client_done, self.server_conn_done }); self.acceptor_closed = true; } else if (try m.match(.{ "client", "done" })) { + std.log.err("Server.receive: client done (flags: acceptor={} conn={})", .{ self.acceptor_closed, self.server_conn_done }); self.client_done = true; } else if (try m.match(.{ "server_connection", "done" })) { + std.log.err("Server.receive: server_connection done (flags: acceptor={} client={})", .{ self.acceptor_closed, self.client_done }); self.server_conn_done = true; } else { + std.log.err("Server.receive: UNEXPECTED msg={f}", .{m}); return unexpected(m); } - if (self.acceptor_closed and self.client_done and self.server_conn_done) - return exit_normal(); + if (self.acceptor_closed and self.client_done and self.server_conn_done) { + std.log.err("Server.receive: all done, exiting with 'success'", .{}); + return exit("success"); + } } }; @@ -265,8 +313,9 @@ test "ip_tcp_client_server test" { var exit_handler = thespian.make_exit_handler(&success, struct { fn handle(ok: *bool, status: []const u8) void { - if (std.mem.eql(u8, status, "normal")) { + if (std.mem.eql(u8, status, "success")) { ok.* = true; + std.log.err("EXITED: {s}", .{status}); } else { std.log.err("EXITED: {s}", .{status}); } diff --git a/test/tests_cpp.zig b/test/tests_cpp.zig index b16e698..8b24081 100644 --- a/test/tests_cpp.zig +++ b/test/tests_cpp.zig @@ -66,3 +66,13 @@ test "spawn_exit" { test "timeout_test" { try testcase("timeout_test"); } + +test "unx_c_api" { + try testcase("unx_c_api"); +} +test "tcp_c_api" { + try testcase("tcp_c_api"); +} +test "socket_c_api" { + try testcase("socket_c_api"); +}