184 lines
6.0 KiB
Zig
184 lines
6.0 KiB
Zig
/// Integration tests for ZynamoDB
|
|
const std = @import("std");
|
|
|
|
// Import modules from main source
|
|
const rocksdb = @import("../src/rocksdb.zig");
|
|
const storage = @import("../src/dynamodb/storage.zig");
|
|
const types = @import("../src/dynamodb/types.zig");
|
|
|
|
test "integration: full table lifecycle" {
|
|
const allocator = std.testing.allocator;
|
|
|
|
// Setup
|
|
const path = "/tmp/test_integration_lifecycle";
|
|
defer std.fs.deleteTreeAbsolute(path) catch {};
|
|
|
|
var engine = try storage.StorageEngine.init(allocator, path);
|
|
defer engine.deinit();
|
|
|
|
// Create table
|
|
const key_schema = [_]types.KeySchemaElement{
|
|
.{ .attribute_name = "pk", .key_type = .HASH },
|
|
};
|
|
const attr_defs = [_]types.AttributeDefinition{
|
|
.{ .attribute_name = "pk", .attribute_type = .S },
|
|
};
|
|
|
|
const desc = try engine.createTable("Users", &key_schema, &attr_defs);
|
|
try std.testing.expectEqualStrings("Users", desc.table_name);
|
|
try std.testing.expectEqual(types.TableStatus.ACTIVE, desc.table_status);
|
|
|
|
// Put items
|
|
try engine.putItem("Users", "{\"pk\":{\"S\":\"user1\"},\"name\":{\"S\":\"Alice\"}}");
|
|
try engine.putItem("Users", "{\"pk\":{\"S\":\"user2\"},\"name\":{\"S\":\"Bob\"}}");
|
|
try engine.putItem("Users", "{\"pk\":{\"S\":\"user3\"},\"name\":{\"S\":\"Charlie\"}}");
|
|
|
|
// Get item
|
|
const item = try engine.getItem("Users", "{\"pk\":{\"S\":\"user1\"}}");
|
|
try std.testing.expect(item != null);
|
|
defer allocator.free(item.?);
|
|
|
|
// Scan
|
|
const all_items = try engine.scan("Users", null);
|
|
defer {
|
|
for (all_items) |i| allocator.free(i);
|
|
allocator.free(all_items);
|
|
}
|
|
try std.testing.expectEqual(@as(usize, 3), all_items.len);
|
|
|
|
// Delete item
|
|
try engine.deleteItem("Users", "{\"pk\":{\"S\":\"user2\"}}");
|
|
|
|
// Verify deletion
|
|
const after_delete = try engine.scan("Users", null);
|
|
defer {
|
|
for (after_delete) |i| allocator.free(i);
|
|
allocator.free(after_delete);
|
|
}
|
|
try std.testing.expectEqual(@as(usize, 2), after_delete.len);
|
|
|
|
// Delete table
|
|
try engine.deleteTable("Users");
|
|
|
|
// Verify table deletion
|
|
const tables = try engine.listTables();
|
|
defer allocator.free(tables);
|
|
try std.testing.expectEqual(@as(usize, 0), tables.len);
|
|
}
|
|
|
|
test "integration: multiple tables" {
|
|
const allocator = std.testing.allocator;
|
|
|
|
const path = "/tmp/test_integration_multi_table";
|
|
defer std.fs.deleteTreeAbsolute(path) catch {};
|
|
|
|
var engine = try storage.StorageEngine.init(allocator, path);
|
|
defer engine.deinit();
|
|
|
|
const key_schema = [_]types.KeySchemaElement{
|
|
.{ .attribute_name = "pk", .key_type = .HASH },
|
|
};
|
|
const attr_defs = [_]types.AttributeDefinition{
|
|
.{ .attribute_name = "pk", .attribute_type = .S },
|
|
};
|
|
|
|
// Create multiple tables
|
|
_ = try engine.createTable("Table1", &key_schema, &attr_defs);
|
|
_ = try engine.createTable("Table2", &key_schema, &attr_defs);
|
|
_ = try engine.createTable("Table3", &key_schema, &attr_defs);
|
|
|
|
// List tables
|
|
const tables = try engine.listTables();
|
|
defer {
|
|
for (tables) |t| allocator.free(t);
|
|
allocator.free(tables);
|
|
}
|
|
try std.testing.expectEqual(@as(usize, 3), tables.len);
|
|
|
|
// Put items in different tables
|
|
try engine.putItem("Table1", "{\"pk\":{\"S\":\"item1\"}}");
|
|
try engine.putItem("Table2", "{\"pk\":{\"S\":\"item2\"}}");
|
|
try engine.putItem("Table3", "{\"pk\":{\"S\":\"item3\"}}");
|
|
|
|
// Verify isolation - scan should only return items from that table
|
|
const table1_items = try engine.scan("Table1", null);
|
|
defer {
|
|
for (table1_items) |i| allocator.free(i);
|
|
allocator.free(table1_items);
|
|
}
|
|
try std.testing.expectEqual(@as(usize, 1), table1_items.len);
|
|
}
|
|
|
|
test "integration: table already exists error" {
|
|
const allocator = std.testing.allocator;
|
|
|
|
const path = "/tmp/test_integration_exists";
|
|
defer std.fs.deleteTreeAbsolute(path) catch {};
|
|
|
|
var engine = try storage.StorageEngine.init(allocator, path);
|
|
defer engine.deinit();
|
|
|
|
const key_schema = [_]types.KeySchemaElement{
|
|
.{ .attribute_name = "pk", .key_type = .HASH },
|
|
};
|
|
const attr_defs = [_]types.AttributeDefinition{
|
|
.{ .attribute_name = "pk", .attribute_type = .S },
|
|
};
|
|
|
|
// Create table
|
|
_ = try engine.createTable("DuplicateTest", &key_schema, &attr_defs);
|
|
|
|
// Try to create again - should fail
|
|
const result = engine.createTable("DuplicateTest", &key_schema, &attr_defs);
|
|
try std.testing.expectError(storage.StorageError.TableAlreadyExists, result);
|
|
}
|
|
|
|
test "integration: table not found error" {
|
|
const allocator = std.testing.allocator;
|
|
|
|
const path = "/tmp/test_integration_notfound";
|
|
defer std.fs.deleteTreeAbsolute(path) catch {};
|
|
|
|
var engine = try storage.StorageEngine.init(allocator, path);
|
|
defer engine.deinit();
|
|
|
|
// Try to put item in non-existent table
|
|
const result = engine.putItem("NonExistent", "{\"pk\":{\"S\":\"item1\"}}");
|
|
try std.testing.expectError(storage.StorageError.TableNotFound, result);
|
|
}
|
|
|
|
test "integration: scan with limit" {
|
|
const allocator = std.testing.allocator;
|
|
|
|
const path = "/tmp/test_integration_scan_limit";
|
|
defer std.fs.deleteTreeAbsolute(path) catch {};
|
|
|
|
var engine = try storage.StorageEngine.init(allocator, path);
|
|
defer engine.deinit();
|
|
|
|
const key_schema = [_]types.KeySchemaElement{
|
|
.{ .attribute_name = "pk", .key_type = .HASH },
|
|
};
|
|
const attr_defs = [_]types.AttributeDefinition{
|
|
.{ .attribute_name = "pk", .attribute_type = .S },
|
|
};
|
|
|
|
_ = try engine.createTable("LimitTest", &key_schema, &attr_defs);
|
|
|
|
// Add many items
|
|
var i: usize = 0;
|
|
while (i < 10) : (i += 1) {
|
|
var buf: [128]u8 = undefined;
|
|
const item = try std.fmt.bufPrint(&buf, "{{\"pk\":{{\"S\":\"item{d}\"}}}}", .{i});
|
|
try engine.putItem("LimitTest", item);
|
|
}
|
|
|
|
// Scan with limit
|
|
const limited = try engine.scan("LimitTest", 5);
|
|
defer {
|
|
for (limited) |item| allocator.free(item);
|
|
allocator.free(limited);
|
|
}
|
|
try std.testing.expectEqual(@as(usize, 5), limited.len);
|
|
}
|