feat: fill in server

This commit is contained in:
dualfroz committed 2026-09-12 14:01:46 +02:00
1 parent b65cde74c6
commit 5a74f25cfa
1 file changed
+161
+161
View File
@@ -5803,3 +5803,164 @@ test "user_admin requires admin role once auth is enabled" {
try server.start(); try server.start();
defer server.stop(); defer server.stop();
const client_mod = @import("client.zig");
var viewer = try client_mod.Client.connect(allocator, server.boundAddress());
defer viewer.close();
try viewer.authenticate("viewer", "pass");
try std.testing.expectError(client_mod.ClientError.ServerForbidden, viewer.adminCreateUser("nobody", "x", .readonly, 16));
var admin = try client_mod.Client.connect(allocator, server.boundAddress());
defer admin.close();
try admin.authenticate("root", "toor");
try admin.adminCreateUser("bob", "b-pass", .readwrite, 16);
const users = try admin.adminListUsers(allocator);
defer authmod.freeUserList(allocator, users);
try std.testing.expectEqual(@as(usize, 3), users.len);
}
test "user_admin set_password, set_role, and delete round trip over the wire, enforced by real auth" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
const path = try tmp.dir.realpathAlloc(allocator, ".");
defer allocator.free(path);
var db = try testDb(allocator, path);
defer db.close();
const store = authmod.Store.init(&db);
try store.createUser(allocator, "root", "toor", .admin, 16);
const address = try std.net.Address.parseIp("127.0.0.1", 0);
var server = try Server.init(allocator, &db, address);
server.enableAuth(store);
try server.start();
defer server.stop();
const client_mod = @import("client.zig");
var admin = try client_mod.Client.connect(allocator, server.boundAddress());
defer admin.close();
try admin.authenticate("root", "toor");
try admin.adminCreateUser("alice", "old-pass", .readonly, 16);
// The freshly created account really authenticates against the live,
// enforced auth store - not just written to a table nobody checks.
var probe = try client_mod.Client.connect(allocator, server.boundAddress());
defer probe.close();
try probe.authenticate("alice", "old-pass");
try admin.adminSetPassword("alice", "new-pass", 16);
var probe2 = try client_mod.Client.connect(allocator, server.boundAddress());
defer probe2.close();
try std.testing.expectError(client_mod.ClientError.ServerUnauthorized, probe2.authenticate("alice", "old-pass"));
try probe2.authenticate("alice", "new-pass");
try admin.adminSetRole("alice", .admin);
const users = try admin.adminListUsers(allocator);
defer authmod.freeUserList(allocator, users);
var sawAlice = false;
for (users) |u| {
if (std.mem.eql(u8, u.username, "alice")) {
try std.testing.expectEqual(authmod.Role.admin, u.role);
sawAlice = true;
}
}
try std.testing.expect(sawAlice);
try admin.adminDeleteUser("alice");
var probe3 = try client_mod.Client.connect(allocator, server.boundAddress());
defer probe3.close();
try std.testing.expectError(client_mod.ClientError.ServerUnauthorized, probe3.authenticate("alice", "new-pass"));
}
test "user_admin reports conflict on duplicate create and not-found on missing user" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
const path = try tmp.dir.realpathAlloc(allocator, ".");
defer allocator.free(path);
var db = try testDb(allocator, path);
defer db.close();
const address = try std.net.Address.parseIp("127.0.0.1", 0);
var server = try Server.init(allocator, &db, address);
try server.start();
defer server.stop();
const client_mod = @import("client.zig");
var client = try client_mod.Client.connect(allocator, server.boundAddress());
defer client.close();
try client.adminCreateUser("alice", "hunter2", .readonly, 16);
try std.testing.expectError(client_mod.ClientError.ServerConflict, client.adminCreateUser("alice", "other", .admin, 16));
try std.testing.expectError(client_mod.ClientError.ServerUserNotFound, client.adminSetPassword("ghost", "x", 16));
try std.testing.expectError(client_mod.ClientError.ServerUserNotFound, client.adminSetRole("ghost", .admin));
try std.testing.expectError(client_mod.ClientError.ServerUserNotFound, client.adminDeleteUser("ghost"));
}
test "server rejects a malformed user_admin frame with bad_request without crashing" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
const path = try tmp.dir.realpathAlloc(allocator, ".");
defer allocator.free(path);
var db = try testDb(allocator, path);
defer db.close();
const address = try std.net.Address.parseIp("127.0.0.1", 0);
var server = try Server.init(allocator, &db, address);
try server.start();
defer server.stop();
const stream = try std.net.tcpConnectToAddress(server.boundAddress());
defer stream.close();
try protocol.writeFrame(stream.writer(), @intFromEnum(protocol.Op.user_admin), "\x00");
var frame = try protocol.readFrame(allocator, stream.reader());
defer frame.deinit();
try std.testing.expectEqual(@intFromEnum(protocol.Status.bad_request), frame.tag);
}
test "server metrics register into an external Prometheus registry" {
const allocator = std.testing.allocator;
var tmp = std.testing.tmpDir(.{});
defer tmp.cleanup();
const path = try tmp.dir.realpathAlloc(allocator, ".");
defer allocator.free(path);
var db = try testDb(allocator, path);
defer db.close();
const address = try std.net.Address.parseIp("127.0.0.1", 0);
var server = try Server.init(allocator, &db, address);
server.enableRateLimit(1, 1000);
try server.start();
defer server.stop();
const client_mod = @import("client.zig");
var client = try client_mod.Client.connect(allocator, server.boundAddress());
defer client.close();
try client.ping();
client.ping() catch {};
var reg = metrics.Registry.init(allocator);
defer reg.deinit();
try server.registerMetrics(&reg);
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
try reg.exportText(allocator, buf.writer());
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_requests_total 2\n") != null);
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_rate_limited_total 1\n") != null);
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_conn_rate_limited_total 0\n") != null);
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_unauthorized_total 0\n") != null);
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_forbidden_total 0\n") != null);
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_session_expired_total 0\n") != null);
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_sessions_swept_total 0\n") != null);
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_ttl_swept_total 0\n") != null);
}