feat: fill in protocol

This commit is contained in:
dualfroz committed 2026-09-08 15:43:27 +02:00
1 parent 711dc39448
commit 06e9e3fe13
1 file changed
+154
+154
View File
@@ -3141,3 +3141,157 @@ test "TtlAction.fromByte rejects an unknown action" {
try std.testing.expectEqual(TtlAction.sweep, try TtlAction.fromByte(3));
}
test "ttl_op expire payload round trips key and seconds" {
const allocator = std.testing.allocator;
const payload = try encodeTtlOp(allocator, .expire, "session:1", 30);
defer allocator.free(payload);
const args = try decodeTtlOp(payload);
try std.testing.expectEqual(TtlAction.expire, args.action);
try std.testing.expectEqualStrings("session:1", args.key);
try std.testing.expectEqual(@as(u64, 30), args.seconds);
}
test "ttl_op sweep payload carries an empty key and zero seconds" {
const allocator = std.testing.allocator;
const payload = try encodeTtlOp(allocator, .sweep, "", 0);
defer allocator.free(payload);
const args = try decodeTtlOp(payload);
try std.testing.expectEqual(TtlAction.sweep, args.action);
try std.testing.expectEqualStrings("", args.key);
try std.testing.expectEqual(@as(u64, 0), args.seconds);
}
test "ttl result round trips noKey, noExpiry, and seconds" {
const allocator = std.testing.allocator;
const noKeyPayload = try encodeTtlResult(allocator, .noKey);
defer allocator.free(noKeyPayload);
try std.testing.expectEqual(ttlmod.TtlResult.noKey, try decodeTtlResult(noKeyPayload));
const noExpiryPayload = try encodeTtlResult(allocator, .noExpiry);
defer allocator.free(noExpiryPayload);
try std.testing.expectEqual(ttlmod.TtlResult.noExpiry, try decodeTtlResult(noExpiryPayload));
const secondsPayload = try encodeTtlResult(allocator, .{ .seconds = 42 });
defer allocator.free(secondsPayload);
const decoded = try decodeTtlResult(secondsPayload);
try std.testing.expectEqual(@as(u64, 42), decoded.seconds);
}
test "decodeTtlResult rejects an unknown kind byte" {
const allocator = std.testing.allocator;
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
const w = encode.ByteWriter.init(&buf);
try w.byte(200);
try std.testing.expectError(error.Malformed, decodeTtlResult(buf.items));
}
test "ttl sweep count round trips" {
const allocator = std.testing.allocator;
const payload = try encodeTtlSweepCount(allocator, 7);
defer allocator.free(payload);
try std.testing.expectEqual(@as(u64, 7), try decodeTtlSweepCount(payload));
}
test "coll_ttl_op expire payload round trips action, kind, name and seconds" {
const allocator = std.testing.allocator;
const payload = try encodeCollTtlOp(allocator, .expire, .hash, "profile", 30);
defer allocator.free(payload);
const args = try decodeCollTtlOp(payload);
try std.testing.expectEqual(TtlAction.expire, args.action);
try std.testing.expectEqual(collmod.Kind.hash, args.kind);
try std.testing.expectEqualStrings("profile", args.name);
try std.testing.expectEqual(@as(u64, 30), args.seconds);
}
test "coll_ttl_op round trips every kind's tag byte" {
const allocator = std.testing.allocator;
const kinds = [_]collmod.Kind{ .counter, .hash, .set, .list, .zset };
for (kinds) |k| {
const payload = try encodeCollTtlOp(allocator, .query, k, "n", 0);
defer allocator.free(payload);
const args = try decodeCollTtlOp(payload);
try std.testing.expectEqual(k, args.kind);
}
}
test "coll_ttl_op sweep payload carries an empty name and zero seconds" {
const allocator = std.testing.allocator;
const payload = try encodeCollTtlOp(allocator, .sweep, .counter, "", 0);
defer allocator.free(payload);
const args = try decodeCollTtlOp(payload);
try std.testing.expectEqual(TtlAction.sweep, args.action);
try std.testing.expectEqualStrings("", args.name);
try std.testing.expectEqual(@as(u64, 0), args.seconds);
}
test "decodeCollTtlOp rejects an unknown kind byte" {
const allocator = std.testing.allocator;
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
const w = encode.ByteWriter.init(&buf);
try w.byte(@intFromEnum(TtlAction.query));
try w.byte('?');
try w.putU64(0);
try std.testing.expectError(error.Malformed, decodeCollTtlOp(buf.items));
}
test "decodeCollTtlOp rejects an unknown action byte before the kind byte is even read" {
const allocator = std.testing.allocator;
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
const w = encode.ByteWriter.init(&buf);
try w.byte(200);
try w.byte('H');
try w.putU64(0);
try std.testing.expectError(error.Malformed, decodeCollTtlOp(buf.items));
}
test "CollAction.fromByte rejects an unknown action" {
try std.testing.expectError(error.Malformed, CollAction.fromByte(200));
try std.testing.expectEqual(CollAction.zset_rank, try CollAction.fromByte(29));
}
test "CollAction.kind groups every action under its collection kind" {
try std.testing.expectEqual(collmod.Kind.counter, CollAction.counter_incrby.kind());
try std.testing.expectEqual(collmod.Kind.hash, CollAction.hash_getall.kind());
try std.testing.expectEqual(collmod.Kind.set, CollAction.set_diff.kind());
try std.testing.expectEqual(collmod.Kind.list, CollAction.list_range.kind());
try std.testing.expectEqual(collmod.Kind.zset, CollAction.zset_rangebyscore.kind());
}
test "CollAction.isReadOnly separates reads from writes" {
try std.testing.expect(CollAction.counter_get.isReadOnly());
try std.testing.expect(!CollAction.counter_set.isReadOnly());
try std.testing.expect(CollAction.zset_rank.isReadOnly());
try std.testing.expect(!CollAction.zset_add.isReadOnly());
try std.testing.expect(CollAction.set_inter.isReadOnly());
try std.testing.expect(!CollAction.list_lpush.isReadOnly());
}
test "coll_op payload round trips action, name, and a variable arg list" {
const allocator = std.testing.allocator;
const args = [_][]const u8{ "alice", "10" };
const payload = try encodeCollOp(allocator, .zset_add, "leaderboard", &args);
defer allocator.free(payload);
const decoded = try decodeCollOp(allocator, payload);
defer allocator.free(decoded.args);
try std.testing.expectEqual(CollAction.zset_add, decoded.action);
try std.testing.expectEqualStrings("leaderboard", decoded.name);
try std.testing.expectEqual(@as(usize, 2), decoded.args.len);
try std.testing.expectEqualStrings("alice", decoded.args[0]);
try std.testing.expectEqualStrings("10", decoded.args[1]);
}
test "coll_op payload round trips a zero-arg action" {
const allocator = std.testing.allocator;
const payload = try encodeCollOp(allocator, .hash_getall, "profile", &.{});
defer allocator.free(payload);
const decoded = try decodeCollOp(allocator, payload);
defer allocator.free(decoded.args);
try std.testing.expectEqual(CollAction.hash_getall, decoded.action);
try std.testing.expectEqualStrings("profile", decoded.name);
try std.testing.expectEqual(@as(usize, 0), decoded.args.len);
}