feat: add IncrCtx to server
This commit is contained in:
1 parent
8f9376fed0
commit
aa1e1992e4
1 file changed
+153
+153
@@ -6600,3 +6600,156 @@ test "coll_op over the wire exercises all five collection kinds against a real s
|
||||
defer got.deinit(allocator);
|
||||
try std.testing.expectEqualStrings("grace", got.bytes);
|
||||
|
||||
var missing = try client.collOp(allocator, .hash_get, "profile", &[_][]const u8{"ghost"});
|
||||
defer missing.deinit(allocator);
|
||||
try std.testing.expect(missing == .nil);
|
||||
|
||||
var lenReply = try client.collOp(allocator, .hash_len, "profile", &.{});
|
||||
defer lenReply.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(i64, 2), lenReply.int);
|
||||
|
||||
var delReply = try client.collOp(allocator, .hash_del, "profile", &[_][]const u8{"age"});
|
||||
defer delReply.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(i64, 1), delReply.int);
|
||||
|
||||
var all = try client.collOp(allocator, .hash_getall, "profile", &.{});
|
||||
defer all.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(usize, 1), all.pairList.len);
|
||||
try std.testing.expectEqualStrings("name", all.pairList[0].field);
|
||||
try std.testing.expectEqualStrings("grace", all.pairList[0].value);
|
||||
}
|
||||
|
||||
// Set: add/rem/ismember/card/members plus the three multi-set ops,
|
||||
// where `name` is the first set and the extra `args` are the rest -
|
||||
// the same split `runColl` uses locally for `args[0]` vs `args[1..]`.
|
||||
{
|
||||
_ = try client.collOp(allocator, .set_add, "a", &[_][]const u8{"x"});
|
||||
_ = try client.collOp(allocator, .set_add, "a", &[_][]const u8{"y"});
|
||||
_ = try client.collOp(allocator, .set_add, "b", &[_][]const u8{"y"});
|
||||
_ = try client.collOp(allocator, .set_add, "b", &[_][]const u8{"z"});
|
||||
|
||||
var isMem = try client.collOp(allocator, .set_ismember, "a", &[_][]const u8{"x"});
|
||||
defer isMem.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(i64, 1), isMem.int);
|
||||
|
||||
var card = try client.collOp(allocator, .set_card, "a", &.{});
|
||||
defer card.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(i64, 2), card.int);
|
||||
|
||||
var inter = try client.collOp(allocator, .set_inter, "a", &[_][]const u8{"b"});
|
||||
defer inter.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(usize, 1), inter.stringList.len);
|
||||
try std.testing.expectEqualStrings("y", inter.stringList[0]);
|
||||
|
||||
var uni = try client.collOp(allocator, .set_union, "a", &[_][]const u8{"b"});
|
||||
defer uni.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(usize, 3), uni.stringList.len);
|
||||
|
||||
var diff = try client.collOp(allocator, .set_diff, "a", &[_][]const u8{"b"});
|
||||
defer diff.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(usize, 1), diff.stringList.len);
|
||||
try std.testing.expectEqualStrings("x", diff.stringList[0]);
|
||||
|
||||
var rem = try client.collOp(allocator, .set_rem, "a", &[_][]const u8{"x"});
|
||||
defer rem.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(i64, 1), rem.int);
|
||||
}
|
||||
|
||||
// List: push both ends, pop both ends, range with a redis-style
|
||||
// negative index, len reflecting what remains.
|
||||
{
|
||||
_ = try client.collOp(allocator, .list_rpush, "queue", &[_][]const u8{"one"});
|
||||
_ = try client.collOp(allocator, .list_rpush, "queue", &[_][]const u8{"two"});
|
||||
_ = try client.collOp(allocator, .list_lpush, "queue", &[_][]const u8{"zero"});
|
||||
|
||||
var ranged = try client.collOp(allocator, .list_range, "queue", &[_][]const u8{ "0", "-1" });
|
||||
defer ranged.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(usize, 3), ranged.stringList.len);
|
||||
try std.testing.expectEqualStrings("zero", ranged.stringList[0]);
|
||||
try std.testing.expectEqualStrings("two", ranged.stringList[2]);
|
||||
|
||||
var popped = try client.collOp(allocator, .list_lpop, "queue", &.{});
|
||||
defer popped.deinit(allocator);
|
||||
try std.testing.expectEqualStrings("zero", popped.bytes);
|
||||
|
||||
var lenReply = try client.collOp(allocator, .list_len, "queue", &.{});
|
||||
defer lenReply.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(i64, 2), lenReply.int);
|
||||
|
||||
var emptyPop = try client.collOp(allocator, .list_rpop, "never-existed", &.{});
|
||||
defer emptyPop.deinit(allocator);
|
||||
try std.testing.expect(emptyPop == .nil);
|
||||
}
|
||||
|
||||
// ZSet: add/incrby/score/rank/card/rangebyrank/rangebyscore, with a
|
||||
// real fractional score to exercise the f64 wire encoding end to end.
|
||||
{
|
||||
_ = try client.collOp(allocator, .zset_add, "board", &[_][]const u8{ "alice", "10.5" });
|
||||
_ = try client.collOp(allocator, .zset_add, "board", &[_][]const u8{ "bob", "20" });
|
||||
|
||||
var score = try client.collOp(allocator, .zset_score, "board", &[_][]const u8{"alice"});
|
||||
defer score.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(f64, 10.5), score.real);
|
||||
|
||||
var incr = try client.collOp(allocator, .zset_incrby, "board", &[_][]const u8{ "alice", "1.5" });
|
||||
defer incr.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(f64, 12.0), incr.real);
|
||||
|
||||
var rank = try client.collOp(allocator, .zset_rank, "board", &[_][]const u8{"alice"});
|
||||
defer rank.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(i64, 0), rank.int);
|
||||
|
||||
var byRank = try client.collOp(allocator, .zset_rangebyrank, "board", &[_][]const u8{ "0", "-1" });
|
||||
defer byRank.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(usize, 2), byRank.scorePairList.len);
|
||||
try std.testing.expectEqualStrings("alice", byRank.scorePairList[0].member);
|
||||
try std.testing.expectEqualStrings("bob", byRank.scorePairList[1].member);
|
||||
|
||||
var byScore = try client.collOp(allocator, .zset_rangebyscore, "board", &[_][]const u8{ "15", "25" });
|
||||
defer byScore.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(usize, 1), byScore.scorePairList.len);
|
||||
try std.testing.expectEqualStrings("bob", byScore.scorePairList[0].member);
|
||||
|
||||
var card = try client.collOp(allocator, .zset_card, "board", &.{});
|
||||
defer card.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(i64, 2), card.int);
|
||||
|
||||
var removed = try client.collOp(allocator, .zset_rem, "board", &[_][]const u8{"bob"});
|
||||
defer removed.deinit(allocator);
|
||||
try std.testing.expectEqual(@as(i64, 1), removed.int);
|
||||
}
|
||||
}
|
||||
|
||||
// Closes the gap every `coll_op` session note since #30 has flagged and
|
||||
// deferred: every existing `coll_op` test drives ONE connection at a
|
||||
// time, so nothing has ever proven that many independent TCP connections
|
||||
// hammering `coll_op` against the SAME named collection concurrently are
|
||||
// safe - `Server.dispatch` takes `self.mutex` once per request exactly
|
||||
// like every other opcode, but that claim had never been exercised here
|
||||
// with real OS threads and real sockets the way `concurrent.zig`'s
|
||||
// `GuardedDb` tests already exercise `Db`/`TableTxn` directly.
|
||||
test "coll_op survives many real concurrent connections hammering the same counter" {
|
||||
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");
|
||||
const threadCount = 8;
|
||||
const perThread = 50;
|
||||
|
||||
const IncrCtx = struct {
|
||||
allocator: Allocator,
|
||||
addr: std.net.Address,
|
||||
ok: bool = false,
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user