diff --git a/tests/connection.zig b/tests/connection.zig new file mode 100644 index 0000000..6c45ac9 --- /dev/null +++ b/tests/connection.zig @@ -0,0 +1,18 @@ +const std = @import("std"); + +const nats = @import("nats"); + +const util = @import("./util.zig"); + +test "nats.Connection.connectTo" { + var server = try util.TestServer.launch(.{}); + defer server.stop(); + + { + try nats.init(nats.default_spin_count); + defer nats.deinit(); + + const connection = try nats.Connection.connectTo(nats.default_server_url); + defer connection.destroy(); + } +} diff --git a/tests/main.zig b/tests/main.zig index bdcd393..a219ae8 100644 --- a/tests/main.zig +++ b/tests/main.zig @@ -1,4 +1,5 @@ test { _ = @import("./nats.zig"); + _ = @import("./connection.zig"); _ = @import("./message.zig"); } diff --git a/tests/util.zig b/tests/util.zig new file mode 100644 index 0000000..bf3e92b --- /dev/null +++ b/tests/util.zig @@ -0,0 +1,73 @@ +const std = @import("std"); + +const TestLaunchError = error{ + NoLaunchStringFound, +}; + +pub const TestServer = struct { + process: std.ChildProcess, + + pub const LaunchOptions = struct { + executable: []const u8 = "nats-server", + port: u16 = 4222, + auth: union(enum) { + none: void, + token: []const u8, + password: struct { user: []const u8, pass: []const u8 }, + } = .none, + allocator: std.mem.Allocator = std.testing.allocator, + + fn argLen(self: LaunchOptions) usize { + // executable, -a, 127.0.0.1, -p, 4222 + const base_len: usize = 5; + return base_len + switch (self.auth) { + .none => @as(usize, 0), + .token => @as(usize, 2), + .password => @as(usize, 4), + }; + } + }; + + pub fn launch(options: LaunchOptions) !TestServer { + // const allocator = std.testing.allocator; + var portbuf = [_]u8{0} ** 5; + const strport = try std.fmt.bufPrint(&portbuf, "{d}", .{options.port}); + + const argsbuf: [9][]const u8 = blk: { + const executable: [1][]const u8 = .{options.executable}; + const listen: [2][]const u8 = .{ "-a", "127.0.0.1" }; + const port: [2][]const u8 = .{ "-p", strport }; + const auth: [4][]const u8 = switch (options.auth) { + .none => .{""} ** 4, + .token => |tok| .{ "--auth", tok, "", "" }, + .password => |auth| .{ "--user", auth.user, "--password", auth.pass }, + }; + + break :blk executable ++ listen ++ port ++ auth; + }; + + const args = argsbuf[0..options.argLen()]; + + var child = std.ChildProcess.init(args, options.allocator); + child.stdin_behavior = .Ignore; + child.stdout_behavior = .Pipe; + child.stderr_behavior = .Pipe; + + try child.spawn(); + var poller = std.io.poll(options.allocator, enum { stderr }, .{ .stderr = child.stderr.? }); + defer poller.deinit(); + + while (try poller.poll()) { + if (std.mem.indexOf(u8, poller.fifo(.stderr).buf, "[INF] Server is ready")) |_| { + return .{ .process = child }; + } + } + + _ = try child.kill(); + return error.NoLaunchStringFound; + } + + pub fn stop(self: *TestServer) void { + _ = self.process.kill() catch return; + } +};