feat: extend protocol

This commit is contained in:
dualfroz committed 2026-09-07 22:26:04 +02:00
1 parent d09dc6aaf0
commit 4f10674feb
1 file changed
+160
+160
View File
@@ -2195,3 +2195,163 @@ test "frame round trip through an in-memory buffer" {
try std.testing.expectEqualStrings("hello", frame.payload); try std.testing.expectEqualStrings("hello", frame.payload);
} }
test "frame with empty payload round trips" {
const allocator = std.testing.allocator;
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
try writeFrame(buf.writer(), @intFromEnum(Op.ping), "");
var stream = std.io.fixedBufferStream(buf.items);
var frame = try readFrame(allocator, stream.reader());
defer frame.deinit();
try std.testing.expectEqual(@as(usize, 0), frame.payload.len);
}
test "readFrame rejects a length prefix beyond the frame guard" {
const allocator = std.testing.allocator;
var header: [5]u8 = undefined;
header[0] = 0;
std.mem.writeInt(u32, header[1..5], maxFrameBytes + 1, encode.endian);
var stream = std.io.fixedBufferStream(&header);
try std.testing.expectError(error.FrameTooLarge, readFrame(allocator, stream.reader()));
}
test "readFrame rejects a truncated body" {
const allocator = std.testing.allocator;
var header: [5]u8 = undefined;
header[0] = 0;
std.mem.writeInt(u32, header[1..5], 10, encode.endian);
var stream = std.io.fixedBufferStream(&header);
try std.testing.expectError(error.EndOfStream, readFrame(allocator, stream.reader()));
}
test "Op.fromByte rejects unknown opcodes" {
try std.testing.expectError(error.UnknownOp, Op.fromByte(200));
try std.testing.expectEqual(Op.batch, try Op.fromByte(9));
try std.testing.expectEqual(Op.table_select, try Op.fromByte(10));
try std.testing.expectEqual(Op.auth, try Op.fromByte(11));
try std.testing.expectEqual(Op.user_admin, try Op.fromByte(12));
try std.testing.expectEqual(Op.auth_token, try Op.fromByte(13));
try std.testing.expectEqual(Op.metrics, try Op.fromByte(14));
try std.testing.expectEqual(Op.ttl_op, try Op.fromByte(15));
try std.testing.expectEqual(Op.coll_ttl_op, try Op.fromByte(16));
try std.testing.expectEqual(Op.coll_op, try Op.fromByte(17));
try std.testing.expectEqual(Op.txn_op, try Op.fromByte(18));
try std.testing.expectEqual(Op.table_join, try Op.fromByte(19));
try std.testing.expectEqual(Op.table_aggregate, try Op.fromByte(20));
try std.testing.expectEqual(Op.table_explain, try Op.fromByte(21));
try std.testing.expectEqual(Op.table_update, try Op.fromByte(22));
try std.testing.expectEqual(Op.table_delete, try Op.fromByte(23));
try std.testing.expectEqual(Op.table_export, try Op.fromByte(24));
try std.testing.expectEqual(Op.table_import, try Op.fromByte(25));
try std.testing.expectEqual(Op.table_window, try Op.fromByte(26));
try std.testing.expectEqual(Op.subscribe, try Op.fromByte(27));
try std.testing.expectEqual(Op.publish, try Op.fromByte(28));
try std.testing.expectEqual(Op.unsubscribe, try Op.fromByte(29));
}
test "Status.fromByte rejects unknown status codes" {
try std.testing.expectError(error.UnknownStatus, Status.fromByte(200));
try std.testing.expectEqual(Status.internal, try Status.fromByte(5));
try std.testing.expectEqual(Status.rate_limited, try Status.fromByte(6));
try std.testing.expectEqual(Status.unauthorized, try Status.fromByte(7));
try std.testing.expectEqual(Status.forbidden, try Status.fromByte(8));
}
test "auth payload encodes and decodes username and password" {
const allocator = std.testing.allocator;
const payload = try encodeAuth(allocator, "alice", "hunter2");
defer allocator.free(payload);
const args = try decodeAuth(payload);
try std.testing.expectEqualStrings("alice", args.username);
try std.testing.expectEqualStrings("hunter2", args.password);
}
test "auth payload handles an empty password" {
const allocator = std.testing.allocator;
const payload = try encodeAuth(allocator, "alice", "");
defer allocator.free(payload);
const args = try decodeAuth(payload);
try std.testing.expectEqualStrings("alice", args.username);
try std.testing.expectEqualStrings("", args.password);
}
test "encodeAuthOk with no token round trips to an empty payload" {
const allocator = std.testing.allocator;
const payload = try encodeAuthOk(allocator, null);
defer allocator.free(payload);
try std.testing.expectEqual(@as(usize, 0), payload.len);
}
test "encodeAuthOk with a token round trips exactly" {
const allocator = std.testing.allocator;
const payload = try encodeAuthOk(allocator, "deadbeef");
defer allocator.free(payload);
try std.testing.expectEqualStrings("deadbeef", payload);
}
test "auth_token payload round trips the opaque token bytes" {
const allocator = std.testing.allocator;
const payload = try encodeAuthToken(allocator, "abc123token");
defer allocator.free(payload);
try std.testing.expectEqualStrings("abc123token", decodeAuthToken(payload));
}
test "set payload encodes and decodes key and value" {
const allocator = std.testing.allocator;
const payload = try encodeSet(allocator, "k", "value-bytes");
defer allocator.free(payload);
const args = try decodeSet(payload);
try std.testing.expectEqualStrings("k", args.key);
try std.testing.expectEqualStrings("value-bytes", args.value);
}
test "set payload handles an empty value" {
const allocator = std.testing.allocator;
const payload = try encodeSet(allocator, "k", "");
defer allocator.free(payload);
const args = try decodeSet(payload);
try std.testing.expectEqualStrings("k", args.key);
try std.testing.expectEqualStrings("", args.value);
}
test "scan args round trip with both bounds" {
const allocator = std.testing.allocator;
const payload = try encodeScan(allocator, .{ .start = "a", .end = "z", .limit = 42, .reverse = true });
defer allocator.free(payload);
const args = try decodeScan(payload);
try std.testing.expectEqualStrings("a", args.start.?);
try std.testing.expectEqualStrings("z", args.end.?);
try std.testing.expectEqual(@as(u32, 42), args.limit);
try std.testing.expect(args.reverse);
}
test "scan args round trip with no bounds" {
const allocator = std.testing.allocator;
const payload = try encodeScan(allocator, .{});
defer allocator.free(payload);
const args = try decodeScan(payload);
try std.testing.expect(args.start == null);
try std.testing.expect(args.end == null);
try std.testing.expect(!args.reverse);
}
test "prefix args round trip" {
const allocator = std.testing.allocator;
const payload = try encodePrefix(allocator, "user:", 7);
defer allocator.free(payload);
const args = try decodePrefix(payload);
try std.testing.expectEqualStrings("user:", args.prefix);
try std.testing.expectEqual(@as(u32, 7), args.limit);
}
test "entries round trip and are independently owned" {
const allocator = std.testing.allocator;
const entries = [_]dbmod.Entry{
.{ .key = "a", .value = "1" },
.{ .key = "b", .value = "2" },
};
const payload = try encodeEntries(allocator, &entries);
defer allocator.free(payload);