feat: continue work on protocol
This commit is contained in:
1 parent
d3d9c4e7e5
commit
711dc39448
1 file changed
+158
@@ -2983,3 +2983,161 @@ test "table_import rejects a format byte outside the DumpFormat enum" {
|
|||||||
try std.testing.expectError(error.Malformed, decodeTableImport(buf.items));
|
try std.testing.expectError(error.Malformed, decodeTableImport(buf.items));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Plan round trips full_scan with a null indexName" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
const payload = try encodePlan(allocator, .{ .kind = .full_scan });
|
||||||
|
defer allocator.free(payload);
|
||||||
|
var decoded = try decodePlan(allocator, payload);
|
||||||
|
defer decoded.deinit(allocator);
|
||||||
|
try std.testing.expectEqual(querymod.PlanKind.full_scan, decoded.kind);
|
||||||
|
try std.testing.expect(decoded.indexName == null);
|
||||||
|
try std.testing.expectEqual(@as(usize, 0), decoded.matchedFields);
|
||||||
|
try std.testing.expectEqual(@as(usize, 0), decoded.totalFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Plan round trips index_range with an indexName and field counts" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
const payload = try encodePlan(allocator, .{ .kind = .index_range, .indexName = "score", .matchedFields = 1, .totalFields = 1 });
|
||||||
|
defer allocator.free(payload);
|
||||||
|
var decoded = try decodePlan(allocator, payload);
|
||||||
|
defer decoded.deinit(allocator);
|
||||||
|
try std.testing.expectEqual(querymod.PlanKind.index_range, decoded.kind);
|
||||||
|
try std.testing.expectEqualStrings("score", decoded.indexName.?);
|
||||||
|
try std.testing.expectEqual(@as(usize, 1), decoded.matchedFields);
|
||||||
|
try std.testing.expectEqual(@as(usize, 1), decoded.totalFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Plan round trips composite_eq with a strict prefix match" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
const payload = try encodePlan(allocator, .{ .kind = .composite_eq, .indexName = "city_age", .matchedFields = 1, .totalFields = 2 });
|
||||||
|
defer allocator.free(payload);
|
||||||
|
var decoded = try decodePlan(allocator, payload);
|
||||||
|
defer decoded.deinit(allocator);
|
||||||
|
try std.testing.expectEqual(querymod.PlanKind.composite_eq, decoded.kind);
|
||||||
|
try std.testing.expectEqualStrings("city_age", decoded.indexName.?);
|
||||||
|
try std.testing.expectEqual(@as(usize, 1), decoded.matchedFields);
|
||||||
|
try std.testing.expectEqual(@as(usize, 2), decoded.totalFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "decodePlan rejects an unknown PlanKind byte instead of corrupting a plan" {
|
||||||
|
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); // not a valid PlanKind tag
|
||||||
|
try putLenPrefixed(w, "");
|
||||||
|
try w.putU32(0);
|
||||||
|
try w.putU32(0);
|
||||||
|
|
||||||
|
try std.testing.expectError(error.Malformed, decodePlan(allocator, buf.items));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "decodeRows rejects a corrupted row payload without leaking prior rows" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var buf = std.ArrayList(u8).init(allocator);
|
||||||
|
defer buf.deinit();
|
||||||
|
const w = encode.ByteWriter.init(&buf);
|
||||||
|
var goodRow = rowmod.Row.init(allocator);
|
||||||
|
defer goodRow.deinit();
|
||||||
|
try goodRow.set("a", .{ .int = 1 });
|
||||||
|
const encoded = try goodRow.encode(allocator);
|
||||||
|
defer allocator.free(encoded);
|
||||||
|
|
||||||
|
try w.putU32(2);
|
||||||
|
try putLenPrefixed(w, encoded);
|
||||||
|
try putLenPrefixed(w, &.{ 9, 9, 9 });
|
||||||
|
|
||||||
|
try std.testing.expectError(error.Malformed, decodeRows(allocator, buf.items));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Cursor.takeLenPrefixed rejects a length that overruns the buffer" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var buf = std.ArrayList(u8).init(allocator);
|
||||||
|
defer buf.deinit();
|
||||||
|
const w = encode.ByteWriter.init(&buf);
|
||||||
|
try w.putU32(100);
|
||||||
|
try w.slice("short");
|
||||||
|
var c = Cursor{ .data = buf.items };
|
||||||
|
try std.testing.expectError(error.Malformed, c.takeLenPrefixed());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "UserAdminAction.fromByte rejects an unknown action" {
|
||||||
|
try std.testing.expectError(error.Malformed, UserAdminAction.fromByte(200));
|
||||||
|
try std.testing.expectEqual(UserAdminAction.list, try UserAdminAction.fromByte(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "user_admin create payload round trips role and rounds" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
const payload = try encodeUserAdmin(allocator, .create, "alice", "hunter2", .admin, 100_000);
|
||||||
|
defer allocator.free(payload);
|
||||||
|
const args = try decodeUserAdmin(payload);
|
||||||
|
try std.testing.expectEqual(UserAdminAction.create, args.action);
|
||||||
|
try std.testing.expectEqualStrings("alice", args.username);
|
||||||
|
try std.testing.expectEqualStrings("hunter2", args.password);
|
||||||
|
try std.testing.expectEqual(@intFromEnum(authmod.Role.admin), args.roleByte);
|
||||||
|
try std.testing.expectEqual(@as(u32, 100_000), args.rounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "user_admin delete payload carries only the username" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
const payload = try encodeUserAdmin(allocator, .delete, "bob", "", .readonly, 0);
|
||||||
|
defer allocator.free(payload);
|
||||||
|
const args = try decodeUserAdmin(payload);
|
||||||
|
try std.testing.expectEqual(UserAdminAction.delete, args.action);
|
||||||
|
try std.testing.expectEqualStrings("bob", args.username);
|
||||||
|
try std.testing.expectEqualStrings("", args.password);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "user_admin list payload round trips with an empty username" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
const payload = try encodeUserAdmin(allocator, .list, "", "", .readonly, 0);
|
||||||
|
defer allocator.free(payload);
|
||||||
|
const args = try decodeUserAdmin(payload);
|
||||||
|
try std.testing.expectEqual(UserAdminAction.list, args.action);
|
||||||
|
try std.testing.expectEqualStrings("", args.username);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "user list round trips every username with its role" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
const users = [_]authmod.UserInfo{
|
||||||
|
.{ .username = @constCast("alice"), .role = .readonly },
|
||||||
|
.{ .username = @constCast("root"), .role = .admin },
|
||||||
|
};
|
||||||
|
const payload = try encodeUserList(allocator, &users);
|
||||||
|
defer allocator.free(payload);
|
||||||
|
|
||||||
|
const decoded = try decodeUserList(allocator, payload);
|
||||||
|
defer authmod.freeUserList(allocator, decoded);
|
||||||
|
|
||||||
|
try std.testing.expectEqual(@as(usize, 2), decoded.len);
|
||||||
|
try std.testing.expectEqualStrings("alice", decoded[0].username);
|
||||||
|
try std.testing.expectEqual(authmod.Role.readonly, decoded[0].role);
|
||||||
|
try std.testing.expectEqualStrings("root", decoded[1].username);
|
||||||
|
try std.testing.expectEqual(authmod.Role.admin, decoded[1].role);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "empty user list round trips" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
const payload = try encodeUserList(allocator, &[_]authmod.UserInfo{});
|
||||||
|
defer allocator.free(payload);
|
||||||
|
const decoded = try decodeUserList(allocator, payload);
|
||||||
|
defer authmod.freeUserList(allocator, decoded);
|
||||||
|
try std.testing.expectEqual(@as(usize, 0), decoded.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "decodeUserList rejects an unknown role byte" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var buf = std.ArrayList(u8).init(allocator);
|
||||||
|
defer buf.deinit();
|
||||||
|
const w = encode.ByteWriter.init(&buf);
|
||||||
|
try w.putU32(1);
|
||||||
|
try putLenPrefixed(w, "ghost");
|
||||||
|
try w.byte(200);
|
||||||
|
try std.testing.expectError(error.Malformed, decodeUserList(allocator, buf.items));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "TtlAction.fromByte rejects an unknown action" {
|
||||||
|
try std.testing.expectError(error.Malformed, TtlAction.fromByte(200));
|
||||||
|
try std.testing.expectEqual(TtlAction.sweep, try TtlAction.fromByte(3));
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user