nats.zig/tests/connection.zig
torque e155ba8bec
all: don't automatically convert userdata types to pointer types
One of the things I have not learned but done a better job of
internalizing while working with zig over the last few months is that
the less magic that exists, the better. In the case of parameterized
functions, this means that it is much better to restrict the range of
types that are permitted to be passed than to perform type
manipulation. In other words, it's more confusing to see a function
that is parameterized with `SomeType` taking a pointer to that type
than having it be parameterized directly to take the pointer.
Obviously there are exceptions to this rule, like std.mem.eql taking
slices of its parameterized type.
2024-01-01 15:11:21 -08:00

253 lines
8.1 KiB
Zig

// This file is licensed under the CC0 1.0 license.
// See: https://creativecommons.org/publicdomain/zero/1.0/legalcode
const std = @import("std");
const nats = @import("nats");
const util = @import("./util.zig");
const rsa_key = @embedFile("./data/client-rsa.key");
const rsa_cert = @embedFile("./data/client-rsa.cert");
const ecc_key = @embedFile("./data/client-ecc.key");
const ecc_cert = @embedFile("./data/client-ecc.cert");
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(server.url);
defer connection.destroy();
}
{
var server = try util.TestServer.launch(.{
.auth = .{ .token = "test_token" },
});
defer server.stop();
try nats.init(nats.default_spin_count);
defer nats.deinit();
const connection = try nats.Connection.connectTo(server.url);
defer connection.destroy();
}
{
var server = try util.TestServer.launch(.{ .auth = .{
.password = .{ .user = "user", .pass = "password" },
} });
defer server.stop();
try nats.init(nats.default_spin_count);
defer nats.deinit();
const connection = try nats.Connection.connectTo(server.url);
defer connection.destroy();
connection.close();
}
}
test "nats.Connection" {
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(server.url);
defer connection.destroy();
_ = connection.isClosed();
_ = connection.isReconnecting();
_ = connection.getStatus();
_ = connection.bytesBuffered();
try connection.flush();
try connection.flushTimeout(100);
_ = connection.getMaxPayload();
_ = try connection.getStats();
{
// id is 56 bytes plus terminating zero
var buf = [_]u8{0} ** 57;
_ = try connection.getConnectedUrl(&buf);
_ = try connection.getConnectedServerId(&buf);
}
{
var servers = try connection.getServers();
defer servers.deinit();
var discovered = try connection.getDiscoveredServers();
defer discovered.deinit();
}
_ = connection.getLastError();
_ = try connection.getClientId();
// our connection does not have a JWT, so this call will always fail
_ = connection.sign("greetings") catch {};
_ = try connection.getLocalIpAndPort();
_ = connection.getRtt() catch {};
_ = connection.hasHeaderSupport();
// this closes the connection, but it does not block until the connection is closed,
// which can result in nondeterministic behavior for calls after this one.
try connection.drain();
// this will return error.ConnectionClosed if the connection is already closed, so
// don't expect this to be error free.
connection.drainTimeout(1000) catch {};
}
fn reconnectDelayHandler(userdata: *u32, connection: *nats.Connection, attempts: c_int) i64 {
_ = userdata;
_ = connection;
_ = attempts;
return 0;
}
fn errorHandler(
userdata: *u32,
connection: *nats.Connection,
subscription: *nats.Subscription,
status: nats.Status,
) void {
_ = userdata;
_ = connection;
_ = subscription;
_ = status;
}
fn connectionHandler(userdata: *u32, connection: *nats.Connection) void {
_ = userdata;
_ = connection;
}
fn jwtHandler(userdata: *u32) nats.JwtResponseOrError {
_ = userdata;
// return .{ .jwt = std.heap.raw_c_allocator.dupeZ(u8, "abcdef") catch @panic("no!") };
return .{ .error_message = std.heap.raw_c_allocator.dupeZ(u8, "dang") catch @panic("no!") };
}
fn signatureHandler(userdata: *u32, nonce: [:0]const u8) nats.SignatureResponseOrError {
_ = userdata;
_ = nonce;
// return .{ .signature = std.heap.raw_c_allocator.dupe(u8, "01230123") catch @panic("no!") };
return .{ .error_message = std.heap.raw_c_allocator.dupeZ(u8, "whoops") catch @panic("no!") };
}
test "nats.ConnectionOptions" {
try nats.init(nats.default_spin_count);
defer nats.deinit();
const options = try nats.ConnectionOptions.create();
defer options.destroy();
var userdata: u32 = 0;
try options.setUrl(nats.default_server_url);
const servers = [_][*:0]const u8{ "nats://127.0.0.1:4442", "nats://127.0.0.1:4443" };
try options.setServers(&servers);
try options.setCredentials("user", "password");
try options.setToken("test_token");
try options.setNoRandomize(false);
try options.setTimeout(1000);
try options.setName("name");
try options.setVerbose(true);
try options.setPedantic(true);
try options.setPingInterval(1000);
try options.setMaxPingsOut(100);
try options.setIoBufSize(1024);
try options.setAllowReconnect(false);
try options.setMaxReconnect(10);
try options.setReconnectWait(500);
try options.setReconnectJitter(100, 200);
try options.setCustomReconnectDelay(*u32, reconnectDelayHandler, &userdata);
try options.setReconnectBufSize(1024);
try options.setMaxPendingMessages(50);
try options.setErrorHandler(*u32, errorHandler, &userdata);
try options.setClosedCallback(*u32, connectionHandler, &userdata);
try options.setDisconnectedCallback(*u32, connectionHandler, &userdata);
try options.setDiscoveredServersCallback(*u32, connectionHandler, &userdata);
try options.setLameDuckModeCallback(*u32, connectionHandler, &userdata);
try options.ignoreDiscoveredServers(true);
try options.useGlobalMessageDelivery(false);
try options.ipResolutionOrder(.ipv4_first);
try options.setSendAsap(true);
try options.useOldRequestStyle(false);
try options.setFailRequestsOnDisconnect(true);
try options.setNoEcho(true);
try options.setRetryOnFailedConnect(*u32, connectionHandler, true, &userdata);
try options.setUserCredentialsCallbacks(*u32, *u32, jwtHandler, signatureHandler, &userdata, &userdata);
try options.setWriteDeadline(5);
try options.disableNoResponders(true);
try options.setCustomInboxPrefix("_FOOBOX");
try options.setMessageBufferPadding(123);
}
fn tokenHandler(userdata: *u32) [:0]const u8 {
_ = userdata;
return "token";
}
test "nats.ConnectionOptions (crypto edition)" {
try nats.init(nats.default_spin_count);
defer nats.deinit();
const options = try nats.ConnectionOptions.create();
defer options.destroy();
var userdata: u32 = 0;
try options.setTokenHandler(*u32, tokenHandler, &userdata);
try options.setSecure(false);
try options.setCertificatesChain(rsa_cert, rsa_key);
try options.setCiphers("-ALL:HIGH");
try options.setCipherSuites("TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256");
try options.setExpectedHostname("test.nats.zig");
try options.skipServerVerification(true);
}
test "nats.ConnectionOptions (crypto connect)" {
{
var server = try util.TestServer.launch(.{ .tls = .rsa });
defer server.stop();
try nats.init(nats.default_spin_count);
defer nats.deinit();
const options = try nats.ConnectionOptions.create();
defer options.destroy();
try options.setSecure(true);
try options.skipServerVerification(true);
try options.setCertificatesChain(rsa_cert, rsa_key);
const connection = try nats.Connection.connect(options);
defer connection.destroy();
try connection.publish("foo", "bar");
}
{
var server = try util.TestServer.launch(.{ .tls = .ecc });
defer server.stop();
try nats.init(nats.default_spin_count);
defer nats.deinit();
const options = try nats.ConnectionOptions.create();
defer options.destroy();
try options.setSecure(true);
try options.skipServerVerification(true);
try options.setCertificatesChain(ecc_cert, ecc_key);
const connection = try nats.Connection.connect(options);
defer connection.destroy();
try connection.publish("foo", "bar");
}
}