feat: extend protocol
This commit is contained in:
1 parent
d09dc6aaf0
commit
4f10674feb
1 file changed
+160
@@ -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);
|
||||||
|
|
||||||
Reference in new issue
Block a user