test(txn): add commit and conflict tests
This commit is contained in:
1 parent
c593d2459d
commit
6bb904de2c
1 file changed
+84
+84
@@ -102,3 +102,87 @@ pub const Transaction = struct {
|
|||||||
self.finished = true;
|
self.finished = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn openTemp(tmp: *std.testing.TmpDir, allocator: Allocator) !Db {
|
||||||
|
var pathBuf: [std.fs.max_path_bytes]u8 = undefined;
|
||||||
|
const base = try tmp.dir.realpath(".", &pathBuf);
|
||||||
|
var dbPathBuf: [std.fs.max_path_bytes]u8 = undefined;
|
||||||
|
const dbPath = try std.fmt.bufPrint(&dbPathBuf, "{s}/store", .{base});
|
||||||
|
return Db.open(allocator, dbPath, .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "transaction commits buffered writes atomically" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var tmp = std.testing.tmpDir(.{});
|
||||||
|
defer tmp.cleanup();
|
||||||
|
|
||||||
|
var db = try openTemp(&tmp, allocator);
|
||||||
|
defer db.close();
|
||||||
|
|
||||||
|
var txn = Transaction.begin(&db);
|
||||||
|
defer txn.deinit();
|
||||||
|
try txn.put("alpha", "1");
|
||||||
|
try txn.put("bravo", "2");
|
||||||
|
try txn.delete("alpha");
|
||||||
|
|
||||||
|
try std.testing.expectEqual(@as(?[]u8, null), try db.get(allocator, "bravo"));
|
||||||
|
|
||||||
|
try txn.commit();
|
||||||
|
|
||||||
|
const bravo = (try db.get(allocator, "bravo")).?;
|
||||||
|
defer allocator.free(bravo);
|
||||||
|
try std.testing.expectEqualStrings("2", bravo);
|
||||||
|
try std.testing.expectEqual(@as(?[]u8, null), try db.get(allocator, "alpha"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "transaction reads its own writes" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var tmp = std.testing.tmpDir(.{});
|
||||||
|
defer tmp.cleanup();
|
||||||
|
|
||||||
|
var db = try openTemp(&tmp, allocator);
|
||||||
|
defer db.close();
|
||||||
|
|
||||||
|
var txn = Transaction.begin(&db);
|
||||||
|
defer txn.deinit();
|
||||||
|
try txn.put("k", "staged");
|
||||||
|
const staged = (try txn.get(allocator, "k")).?;
|
||||||
|
defer allocator.free(staged);
|
||||||
|
try std.testing.expectEqualStrings("staged", staged);
|
||||||
|
|
||||||
|
try txn.delete("k");
|
||||||
|
try std.testing.expectEqual(@as(?[]u8, null), try txn.get(allocator, "k"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "conflicting commit is rejected but clean commit succeeds" {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var tmp = std.testing.tmpDir(.{});
|
||||||
|
defer tmp.cleanup();
|
||||||
|
|
||||||
|
var db = try openTemp(&tmp, allocator);
|
||||||
|
defer db.close();
|
||||||
|
|
||||||
|
try db.put("balance", "100");
|
||||||
|
|
||||||
|
var txn = Transaction.begin(&db);
|
||||||
|
defer txn.deinit();
|
||||||
|
const seen = (try txn.get(allocator, "balance")).?;
|
||||||
|
defer allocator.free(seen);
|
||||||
|
try std.testing.expectEqualStrings("100", seen);
|
||||||
|
|
||||||
|
try db.put("balance", "external");
|
||||||
|
|
||||||
|
try txn.put("balance", "150");
|
||||||
|
try std.testing.expectError(error.Conflict, txn.commit());
|
||||||
|
|
||||||
|
var clean = Transaction.begin(&db);
|
||||||
|
defer clean.deinit();
|
||||||
|
const current = (try clean.get(allocator, "balance")).?;
|
||||||
|
defer allocator.free(current);
|
||||||
|
try clean.put("note", "ok");
|
||||||
|
try clean.commit();
|
||||||
|
|
||||||
|
const note = (try db.get(allocator, "note")).?;
|
||||||
|
defer allocator.free(note);
|
||||||
|
try std.testing.expectEqualStrings("ok", note);
|
||||||
|
}
|
||||||
Reference in new issue
Block a user