测试:完善和优化测试用例

- 优化 schema 测试用例,增加边界条件测试
- 完善 table、index、database 等模块的测试
- 改进测试数据清理和错误处理
- 更新示例程序以使用最新 API
- 增强测试覆盖率和可靠性
This commit is contained in:
2025-10-09 21:47:14 +08:00
parent 89af9e9259
commit 6d04487789
14 changed files with 812 additions and 132 deletions

View File

@@ -20,9 +20,12 @@ func TestCompactionBasic(t *testing.T) {
}
// 创建 Schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "value", Type: FieldTypeInt64},
})
if err != nil {
t.Fatal(err)
}
// 创建 VersionSet
versionSet, err := NewVersionSet(manifestDir)
@@ -222,9 +225,12 @@ func TestCompactionMerge(t *testing.T) {
}
// 创建 Schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "value", Type: FieldTypeString},
})
if err != nil {
t.Fatal(err)
}
// 创建 VersionSet
versionSet, err := NewVersionSet(manifestDir)
@@ -343,9 +349,12 @@ func BenchmarkCompaction(b *testing.B) {
}
// 创建 Schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "value", Type: FieldTypeString},
})
if err != nil {
b.Fatal(err)
}
// 创建 VersionSet
versionSet, err := NewVersionSet(manifestDir)
@@ -429,12 +438,15 @@ func TestCompactionQueryOrder(t *testing.T) {
tmpDir := t.TempDir()
// 创建 Schema - 包含多个字段以增加数据大小
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64},
{Name: "name", Type: FieldTypeString},
{Name: "data", Type: FieldTypeString},
{Name: "timestamp", Type: FieldTypeInt64},
})
if err != nil {
t.Fatal(err)
}
// 打开 Table (使用较小的 MemTable 触发频繁 flush)
table, err := OpenTable(&TableOptions{

View File

@@ -40,10 +40,13 @@ func TestCreateTable(t *testing.T) {
defer db.Close()
// 创建 Schema
userSchema := NewSchema("users", []Field{
userSchema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
// 创建表
usersTable, err := db.CreateTable("users", userSchema)
@@ -76,15 +79,21 @@ func TestMultipleTables(t *testing.T) {
defer db.Close()
// 创建多个表
userSchema := NewSchema("users", []Field{
userSchema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
orderSchema := NewSchema("orders", []Field{
orderSchema, err := NewSchema("orders", []Field{
{Name: "order_id", Type: FieldTypeString, Indexed: true, Comment: "订单ID"},
{Name: "amount", Type: FieldTypeInt64, Indexed: true, Comment: "金额"},
})
if err != nil {
t.Fatal(err)
}
_, err = db.CreateTable("users", userSchema)
if err != nil {
@@ -117,10 +126,13 @@ func TestTableOperations(t *testing.T) {
defer db.Close()
// 创建表
userSchema := NewSchema("users", []Field{
userSchema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
usersTable, err := db.CreateTable("users", userSchema)
if err != nil {
@@ -179,9 +191,12 @@ func TestDropTable(t *testing.T) {
defer db.Close()
// 创建表
userSchema := NewSchema("users", []Field{
userSchema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
})
if err != nil {
t.Fatal(err)
}
_, err = db.CreateTable("users", userSchema)
if err != nil {
@@ -214,10 +229,13 @@ func TestDatabaseRecover(t *testing.T) {
t.Fatalf("Open failed: %v", err)
}
userSchema := NewSchema("users", []Field{
userSchema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
usersTable, err := db1.CreateTable("users", userSchema)
if err != nil {
@@ -272,10 +290,13 @@ func TestDatabaseClean(t *testing.T) {
// 2. 创建多个表并插入数据
// 表 1: users
usersSchema := NewSchema("users", []Field{
usersSchema, err := NewSchema("users", []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: true, Comment: "User ID"},
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "Name"},
})
if err != nil {
t.Fatal(err)
}
usersTable, err := db.CreateTable("users", usersSchema)
if err != nil {
t.Fatal(err)
@@ -289,10 +310,13 @@ func TestDatabaseClean(t *testing.T) {
}
// 表 2: orders
ordersSchema := NewSchema("orders", []Field{
ordersSchema, err := NewSchema("orders", []Field{
{Name: "order_id", Type: FieldTypeInt64, Indexed: true, Comment: "Order ID"},
{Name: "amount", Type: FieldTypeInt64, Indexed: false, Comment: "Amount"},
})
if err != nil {
t.Fatal(err)
}
ordersTable, err := db.CreateTable("orders", ordersSchema)
if err != nil {
t.Fatal(err)
@@ -367,9 +391,12 @@ func TestDatabaseDestroy(t *testing.T) {
t.Fatal(err)
}
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
})
if err != nil {
t.Fatal(err)
}
table, err := db.CreateTable("test", schema)
if err != nil {
t.Fatal(err)
@@ -420,10 +447,13 @@ func TestDatabaseCleanMultipleTables(t *testing.T) {
// 创建 5 个表
for i := range 5 {
tableName := fmt.Sprintf("table%d", i)
schema := NewSchema(tableName, []Field{
schema, err := NewSchema(tableName, []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
{Name: "value", Type: FieldTypeString, Indexed: false, Comment: "Value"},
})
if err != nil {
t.Fatal(err)
}
table, err := db.CreateTable(tableName, schema)
if err != nil {
@@ -493,9 +523,12 @@ func TestDatabaseCleanAndReopen(t *testing.T) {
t.Fatal(err)
}
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
})
if err != nil {
t.Fatal(err)
}
table, err := db.CreateTable("test", schema)
if err != nil {
t.Fatal(err)
@@ -560,10 +593,13 @@ func TestDatabaseCleanTable(t *testing.T) {
}
defer db.Close()
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "Name"},
})
if err != nil {
t.Fatal(err)
}
table, err := db.CreateTable("users", schema)
if err != nil {
@@ -629,9 +665,12 @@ func TestDatabaseDestroyTable(t *testing.T) {
}
defer db.Close()
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
})
if err != nil {
t.Fatal(err)
}
table, err := db.CreateTable("test", schema)
if err != nil {
@@ -681,9 +720,12 @@ func TestDatabaseDestroyTableMultiple(t *testing.T) {
}
defer db.Close()
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
})
if err != nil {
t.Fatal(err)
}
// 创建 3 个表
for i := 1; i <= 3; i++ {

View File

@@ -26,7 +26,7 @@ type Product struct {
}
func main() {
fmt.Println("=== SRDB 批量插入示例 ===\n")
fmt.Println("=== SRDB 批量插入示例 ===")
// 清理旧数据
os.RemoveAll("./data")
@@ -55,10 +55,13 @@ func main() {
func example1() {
fmt.Println("=== 示例 1: 插入单个 map ===")
schema := srdb.NewSchema("users", []srdb.Field{
schema, err := srdb.NewSchema("users", []srdb.Field{
{Name: "name", Type: srdb.FieldTypeString, Comment: "用户名"},
{Name: "age", Type: srdb.FieldTypeInt64, Comment: "年龄"},
})
if err != nil {
log.Fatal(err)
}
table, err := srdb.OpenTable(&srdb.TableOptions{
Dir: "./data/example1",
@@ -89,11 +92,14 @@ func example1() {
func example2() {
fmt.Println("=== 示例 2: 批量插入 map 切片 ===")
schema := srdb.NewSchema("users", []srdb.Field{
schema, err := srdb.NewSchema("users", []srdb.Field{
{Name: "name", Type: srdb.FieldTypeString},
{Name: "age", Type: srdb.FieldTypeInt64},
{Name: "email", Type: srdb.FieldTypeString, Indexed: true},
})
if err != nil {
log.Fatal(err)
}
table, err := srdb.OpenTable(&srdb.TableOptions{
Dir: "./data/example2",
@@ -134,12 +140,15 @@ func example2() {
func example3() {
fmt.Println("=== 示例 3: 插入单个结构体 ===")
schema := srdb.NewSchema("users", []srdb.Field{
schema, err := srdb.NewSchema("users", []srdb.Field{
{Name: "name", Type: srdb.FieldTypeString},
{Name: "age", Type: srdb.FieldTypeInt64},
{Name: "email", Type: srdb.FieldTypeString},
{Name: "is_active", Type: srdb.FieldTypeBool},
})
if err != nil {
log.Fatal(err)
}
table, err := srdb.OpenTable(&srdb.TableOptions{
Dir: "./data/example3",
@@ -175,12 +184,15 @@ func example3() {
func example4() {
fmt.Println("=== 示例 4: 批量插入结构体切片 ===")
schema := srdb.NewSchema("users", []srdb.Field{
schema, err := srdb.NewSchema("users", []srdb.Field{
{Name: "name", Type: srdb.FieldTypeString},
{Name: "age", Type: srdb.FieldTypeInt64},
{Name: "email", Type: srdb.FieldTypeString},
{Name: "is_active", Type: srdb.FieldTypeBool},
})
if err != nil {
log.Fatal(err)
}
table, err := srdb.OpenTable(&srdb.TableOptions{
Dir: "./data/example4",
@@ -222,12 +234,15 @@ func example4() {
func example5() {
fmt.Println("=== 示例 5: 批量插入结构体指针切片 ===")
schema := srdb.NewSchema("users", []srdb.Field{
schema, err := srdb.NewSchema("users", []srdb.Field{
{Name: "name", Type: srdb.FieldTypeString},
{Name: "age", Type: srdb.FieldTypeInt64},
{Name: "email", Type: srdb.FieldTypeString},
{Name: "is_active", Type: srdb.FieldTypeBool},
})
if err != nil {
log.Fatal(err)
}
table, err := srdb.OpenTable(&srdb.TableOptions{
Dir: "./data/example5",
@@ -262,12 +277,15 @@ func example5() {
func example6() {
fmt.Println("=== 示例 6: 使用 snake_case 自动转换 ===")
schema := srdb.NewSchema("products", []srdb.Field{
schema, err := srdb.NewSchema("products", []srdb.Field{
{Name: "product_id", Type: srdb.FieldTypeString, Comment: "产品ID"},
{Name: "product_name", Type: srdb.FieldTypeString, Comment: "产品名称"},
{Name: "price", Type: srdb.FieldTypeFloat, Comment: "价格"},
{Name: "in_stock", Type: srdb.FieldTypeBool, Comment: "是否有货"},
})
if err != nil {
log.Fatal(err)
}
table, err := srdb.OpenTable(&srdb.TableOptions{
Dir: "./data/example6",

View File

@@ -93,6 +93,9 @@ func main() {
}
// 创建 Schema
schema := srdb.NewSchema("demo", fields)
schema, err := srdb.NewSchema("demo", fields)
if err != nil {
log.Fatal(err)
}
fmt.Printf("\n✅ 成功创建 Schema包含 %d 个字段\n", len(schema.Fields))
}

View File

@@ -38,7 +38,10 @@ func main() {
}
// 创建 Schema
schema := srdb.NewSchema("users", fields)
schema, err := srdb.NewSchema("users", fields)
if err != nil {
log.Fatal(err)
}
// 打印 Schema 信息
fmt.Printf("Schema 名称: %s\n", schema.Name)

View File

@@ -23,19 +23,25 @@ func StartWebUI(dbPath string, addr string) {
defer db.Close()
// 创建示例 Schema
userSchema := srdb.NewSchema("users", []srdb.Field{
userSchema, err := srdb.NewSchema("users", []srdb.Field{
{Name: "name", Type: srdb.FieldTypeString, Indexed: true, Comment: "User name"},
{Name: "email", Type: srdb.FieldTypeString, Indexed: false, Comment: "Email address"},
{Name: "age", Type: srdb.FieldTypeInt64, Indexed: false, Comment: "Age"},
{Name: "city", Type: srdb.FieldTypeString, Indexed: false, Comment: "City"},
})
if err != nil {
log.Fatal(err)
}
productSchema := srdb.NewSchema("products", []srdb.Field{
productSchema, err := srdb.NewSchema("products", []srdb.Field{
{Name: "product_name", Type: srdb.FieldTypeString, Indexed: true, Comment: "Product name"},
{Name: "price", Type: srdb.FieldTypeFloat, Indexed: false, Comment: "Price"},
{Name: "quantity", Type: srdb.FieldTypeInt64, Indexed: false, Comment: "Quantity"},
{Name: "category", Type: srdb.FieldTypeString, Indexed: false, Comment: "Category"},
})
if err != nil {
log.Fatal(err)
}
// 创建表(如果不存在)
tables := db.ListTables()
@@ -133,14 +139,16 @@ func autoInsertData(db *srdb.Database) {
hasLogs := slices.Contains(tables, "logs")
if !hasLogs {
logsSchema := srdb.NewSchema("logs", []srdb.Field{
logsSchema, err := srdb.NewSchema("logs", []srdb.Field{
{Name: "group", Type: srdb.FieldTypeString, Indexed: true, Comment: "Log group (A-E)"},
{Name: "timestamp", Type: srdb.FieldTypeString, Indexed: false, Comment: "Timestamp"},
{Name: "data", Type: srdb.FieldTypeString, Indexed: false, Comment: "Random data"},
{Name: "size_bytes", Type: srdb.FieldTypeInt64, Indexed: false, Comment: "Data size in bytes"},
})
if err != nil {
log.Fatal(err)
}
var err error
logsTable, err = db.CreateTable("logs", logsSchema)
if err != nil {
log.Printf("Failed to create logs table: %v", err)

View File

@@ -12,18 +12,21 @@ func TestIndexBTreeBasic(t *testing.T) {
tmpDir := t.TempDir()
// 创建 Schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64},
{Name: "name", Type: FieldTypeString},
{Name: "city", Type: FieldTypeString},
})
if err != nil {
t.Fatal(err)
}
// 创建索引管理器
mgr := NewIndexManager(tmpDir, schema)
defer mgr.Close()
// 创建索引
err := mgr.CreateIndex("city")
err = mgr.CreateIndex("city")
if err != nil {
t.Fatalf("Failed to create index: %v", err)
}
@@ -126,17 +129,20 @@ func TestIndexBTreeLargeDataset(t *testing.T) {
tmpDir := t.TempDir()
// 创建 Schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64},
{Name: "category", Type: FieldTypeString},
})
if err != nil {
t.Fatal(err)
}
// 创建索引管理器
mgr := NewIndexManager(tmpDir, schema)
defer mgr.Close()
// 创建索引
err := mgr.CreateIndex("category")
err = mgr.CreateIndex("category")
if err != nil {
t.Fatalf("Failed to create index: %v", err)
}
@@ -211,16 +217,19 @@ func TestIndexBTreeBackwardCompatibility(t *testing.T) {
tmpDir := t.TempDir()
// 创建 Schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64},
{Name: "status", Type: FieldTypeString},
})
if err != nil {
t.Fatal(err)
}
// 1. 创建索引管理器并用旧方式(通过先禁用新格式)创建索引
mgr := NewIndexManager(tmpDir, schema)
// 创建索引
err := mgr.CreateIndex("status")
err = mgr.CreateIndex("status")
if err != nil {
t.Fatalf("Failed to create index: %v", err)
}
@@ -286,17 +295,20 @@ func TestIndexBTreeIncrementalUpdate(t *testing.T) {
tmpDir := t.TempDir()
// 创建 Schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64},
{Name: "tag", Type: FieldTypeString},
})
if err != nil {
t.Fatal(err)
}
// 创建索引管理器
mgr := NewIndexManager(tmpDir, schema)
defer mgr.Close()
// 创建索引
err := mgr.CreateIndex("tag")
err = mgr.CreateIndex("tag")
if err != nil {
t.Fatalf("Failed to create index: %v", err)
}

View File

@@ -11,9 +11,12 @@ func TestIndexVersionControl(t *testing.T) {
os.MkdirAll(dir, 0755)
defer os.RemoveAll(dir)
testSchema := NewSchema("test", []Field{
testSchema, err := NewSchema("test", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
})
if err != nil {
t.Fatal(err)
}
// 1. 创建索引管理器
mgr := NewIndexManager(dir, testSchema)
@@ -72,9 +75,12 @@ func TestIncrementalUpdate(t *testing.T) {
os.MkdirAll(dir, 0755)
defer os.RemoveAll(dir)
testSchema := NewSchema("test", []Field{
testSchema, err := NewSchema("test", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
})
if err != nil {
t.Fatal(err)
}
// 1. 创建索引并添加初始数据
mgr := NewIndexManager(dir, testSchema)
@@ -103,7 +109,7 @@ func TestIncrementalUpdate(t *testing.T) {
}
// 3. 增量更新
err := idx.IncrementalUpdate(getData, 3, 5)
err = idx.IncrementalUpdate(getData, 3, 5)
if err != nil {
t.Fatal(err)
}
@@ -143,9 +149,12 @@ func TestNeedsUpdate(t *testing.T) {
os.MkdirAll(dir, 0755)
defer os.RemoveAll(dir)
testSchema := NewSchema("test", []Field{
testSchema, err := NewSchema("test", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
})
if err != nil {
t.Fatal(err)
}
mgr := NewIndexManager(dir, testSchema)
mgr.CreateIndex("name")
@@ -174,16 +183,19 @@ func TestIndexPersistence(t *testing.T) {
defer os.RemoveAll(dir)
// 创建 Schema
testSchema := NewSchema("test", []Field{
testSchema, err := NewSchema("test", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
// 1. 创建索引管理器
mgr := NewIndexManager(dir, testSchema)
// 2. 创建索引
err := mgr.CreateIndex("name")
err = mgr.CreateIndex("name")
if err != nil {
t.Fatal(err)
}
@@ -253,9 +265,12 @@ func TestIndexDropWithFile(t *testing.T) {
os.MkdirAll(dir, 0755)
defer os.RemoveAll(dir)
testSchema := NewSchema("test", []Field{
testSchema, err := NewSchema("test", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
})
if err != nil {
t.Fatal(err)
}
mgr := NewIndexManager(dir, testSchema)
@@ -272,7 +287,7 @@ func TestIndexDropWithFile(t *testing.T) {
}
// 删除索引
err := mgr.DropIndex("name")
err = mgr.DropIndex("name")
if err != nil {
t.Fatal(err)
}
@@ -290,11 +305,14 @@ func TestIndexQueryIntegration(t *testing.T) {
tmpDir := t.TempDir()
// 1. 创建带索引字段的 Schema
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: false},
{Name: "email", Type: FieldTypeString, Indexed: true}, // email 字段有索引
{Name: "age", Type: FieldTypeInt64, Indexed: false},
})
if err != nil {
t.Fatal(err)
}
// 2. 打开表
table, err := OpenTable(&TableOptions{
@@ -450,11 +468,14 @@ func TestIndexPersistenceAcrossRestart(t *testing.T) {
// 1. 第一次打开:创建数据和索引
{
schema := NewSchema("products", []Field{
schema, err := NewSchema("products", []Field{
{Name: "name", Type: FieldTypeString, Indexed: false},
{Name: "category", Type: FieldTypeString, Indexed: true},
{Name: "price", Type: FieldTypeInt64, Indexed: false},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,

View File

@@ -11,10 +11,13 @@ func TestLazyLoadingBasic(t *testing.T) {
tmpDir, _ := os.MkdirTemp("", "TestLazyLoadingBasic")
defer os.RemoveAll(tmpDir)
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "age", Type: FieldTypeInt64},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -67,10 +70,13 @@ func TestLazyLoadingVsEagerLoading(t *testing.T) {
tmpDir, _ := os.MkdirTemp("", "TestLazyLoadingVsEagerLoading")
defer os.RemoveAll(tmpDir)
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "age", Type: FieldTypeInt64},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -144,11 +150,14 @@ func TestIndexQueryIsEager(t *testing.T) {
tmpDir, _ := os.MkdirTemp("", "TestIndexQueryIsEager")
defer os.RemoveAll(tmpDir)
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "email", Type: FieldTypeString, Indexed: true},
{Name: "age", Type: FieldTypeInt64},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -226,11 +235,14 @@ func TestLazyLoadingWithConditions(t *testing.T) {
tmpDir, _ := os.MkdirTemp("", "TestLazyLoadingWithConditions")
defer os.RemoveAll(tmpDir)
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "age", Type: FieldTypeInt64},
{Name: "active", Type: FieldTypeBool},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -301,10 +313,13 @@ func TestFirstDoesNotLoadAll(t *testing.T) {
tmpDir, _ := os.MkdirTemp("", "TestFirstDoesNotLoadAll")
defer os.RemoveAll(tmpDir)
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "age", Type: FieldTypeInt64},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,

View File

@@ -50,11 +50,40 @@ type Schema struct {
}
// NewSchema 创建 Schema
func NewSchema(name string, fields []Field) *Schema {
// 参数:
// - name: Schema 名称,不能为空
// - fields: 字段列表,至少需要 1 个字段
//
// 返回:
// - *Schema: Schema 实例
// - error: 错误信息
func NewSchema(name string, fields []Field) (*Schema, error) {
// 验证 name
if name == "" {
return nil, NewError(ErrCodeSchemaInvalid, fmt.Errorf("schema name cannot be empty"))
}
// 验证 fields 数量
if len(fields) == 0 {
return nil, NewError(ErrCodeSchemaInvalid, fmt.Errorf("schema must have at least one field"))
}
// 验证字段名不能为空且不能重复
fieldNames := make(map[string]bool)
for i, field := range fields {
if field.Name == "" {
return nil, NewError(ErrCodeSchemaInvalid, fmt.Errorf("field at index %d has empty name", i))
}
if fieldNames[field.Name] {
return nil, NewError(ErrCodeSchemaInvalid, fmt.Errorf("duplicate field name: %s", field.Name))
}
fieldNames[field.Name] = true
}
return &Schema{
Name: name,
Fields: fields,
}
}, nil
}
// StructToFields 从 Go 结构体生成 Field 列表

View File

@@ -1,41 +1,65 @@
package srdb
import (
"strings"
"testing"
)
// UserSchema 用户表 Schema
var UserSchema = NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
{Name: "email", Type: FieldTypeString, Indexed: true, Comment: "邮箱"},
{Name: "description", Type: FieldTypeString, Indexed: false, Comment: "描述"},
})
// Package-level test schemas
var (
UserSchema *Schema
LogSchema *Schema
OrderSchema *Schema
)
// LogSchema 日志表 Schema
var LogSchema = NewSchema("logs", []Field{
{Name: "level", Type: FieldTypeString, Indexed: true, Comment: "日志级别"},
{Name: "message", Type: FieldTypeString, Indexed: false, Comment: "日志消息"},
{Name: "source", Type: FieldTypeString, Indexed: true, Comment: "来源"},
{Name: "error_code", Type: FieldTypeInt64, Indexed: true, Comment: "错误码"},
})
func init() {
var err error
// OrderSchema 订单表 Schema
var OrderSchema = NewSchema("orders", []Field{
{Name: "order_id", Type: FieldTypeString, Indexed: true, Comment: "订单ID"},
{Name: "user_id", Type: FieldTypeInt64, Indexed: true, Comment: "用户ID"},
{Name: "amount", Type: FieldTypeFloat, Indexed: true, Comment: "金额"},
{Name: "status", Type: FieldTypeString, Indexed: true, Comment: "状态"},
{Name: "paid", Type: FieldTypeBool, Indexed: true, Comment: "是否支付"},
})
// UserSchema 用户表 Schema
UserSchema, err = NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
{Name: "email", Type: FieldTypeString, Indexed: true, Comment: "邮箱"},
{Name: "description", Type: FieldTypeString, Indexed: false, Comment: "描述"},
})
if err != nil {
panic("Failed to create UserSchema: " + err.Error())
}
// LogSchema 日志表 Schema
LogSchema, err = NewSchema("logs", []Field{
{Name: "level", Type: FieldTypeString, Indexed: true, Comment: "日志级别"},
{Name: "message", Type: FieldTypeString, Indexed: false, Comment: "日志消息"},
{Name: "source", Type: FieldTypeString, Indexed: true, Comment: "来源"},
{Name: "error_code", Type: FieldTypeInt64, Indexed: true, Comment: "错误码"},
})
if err != nil {
panic("Failed to create LogSchema: " + err.Error())
}
// OrderSchema 订单表 Schema
OrderSchema, err = NewSchema("orders", []Field{
{Name: "order_id", Type: FieldTypeString, Indexed: true, Comment: "订单ID"},
{Name: "user_id", Type: FieldTypeInt64, Indexed: true, Comment: "用户ID"},
{Name: "amount", Type: FieldTypeFloat, Indexed: true, Comment: "金额"},
{Name: "status", Type: FieldTypeString, Indexed: true, Comment: "状态"},
{Name: "paid", Type: FieldTypeBool, Indexed: true, Comment: "是否支付"},
})
if err != nil {
panic("Failed to create OrderSchema: " + err.Error())
}
}
func TestSchema(t *testing.T) {
// 创建 Schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
{Name: "score", Type: FieldTypeFloat, Indexed: false, Comment: "分数"},
})
if err != nil {
t.Fatal(err)
}
// 测试数据
data := map[string]any{
@@ -45,7 +69,7 @@ func TestSchema(t *testing.T) {
}
// 验证
err := schema.Validate(data)
err = schema.Validate(data)
if err != nil {
t.Errorf("Validation failed: %v", err)
}
@@ -60,10 +84,13 @@ func TestSchema(t *testing.T) {
}
func TestSchemaValidation(t *testing.T) {
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
// 正确的数据
validData := map[string]any{
@@ -71,7 +98,7 @@ func TestSchemaValidation(t *testing.T) {
"age": 30,
}
err := schema.Validate(validData)
err = schema.Validate(validData)
if err != nil {
t.Errorf("Valid data failed validation: %v", err)
}
@@ -90,11 +117,361 @@ func TestSchemaValidation(t *testing.T) {
t.Log("Schema validation test passed!")
}
// TestNewSchemaValidation 测试 NewSchema 的各种验证场景
func TestNewSchemaValidation(t *testing.T) {
tests := []struct {
name string
schemaName string
fields []Field
shouldError bool
errorMsg string
}{
{
name: "Valid schema",
schemaName: "users",
fields: []Field{
{Name: "id", Type: FieldTypeInt64},
{Name: "name", Type: FieldTypeString},
},
shouldError: false,
},
{
name: "Empty schema name",
schemaName: "",
fields: []Field{{Name: "id", Type: FieldTypeInt64}},
shouldError: true,
errorMsg: "schema name cannot be empty",
},
{
name: "Empty fields array",
schemaName: "users",
fields: []Field{},
shouldError: true,
errorMsg: "schema must have at least one field",
},
{
name: "Nil fields array",
schemaName: "users",
fields: nil,
shouldError: true,
errorMsg: "schema must have at least one field",
},
{
name: "Empty field name at index 0",
schemaName: "users",
fields: []Field{
{Name: "", Type: FieldTypeInt64},
},
shouldError: true,
errorMsg: "field at index 0 has empty name",
},
{
name: "Empty field name at index 1",
schemaName: "users",
fields: []Field{
{Name: "id", Type: FieldTypeInt64},
{Name: "", Type: FieldTypeString},
},
shouldError: true,
errorMsg: "field at index 1 has empty name",
},
{
name: "Duplicate field name",
schemaName: "users",
fields: []Field{
{Name: "id", Type: FieldTypeInt64},
{Name: "name", Type: FieldTypeString},
{Name: "id", Type: FieldTypeString}, // Duplicate
},
shouldError: true,
errorMsg: "duplicate field name: id",
},
{
name: "Valid schema with single field",
schemaName: "logs",
fields: []Field{
{Name: "message", Type: FieldTypeString},
},
shouldError: false,
},
{
name: "Valid schema with indexed field",
schemaName: "users",
fields: []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: true},
{Name: "email", Type: FieldTypeString, Indexed: true},
{Name: "age", Type: FieldTypeInt64},
},
shouldError: false,
},
{
name: "Valid schema with comments",
schemaName: "products",
fields: []Field{
{Name: "id", Type: FieldTypeInt64, Comment: "产品ID"},
{Name: "name", Type: FieldTypeString, Comment: "产品名称"},
{Name: "price", Type: FieldTypeFloat, Comment: "价格"},
},
shouldError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
schema, err := NewSchema(tt.schemaName, tt.fields)
if tt.shouldError {
if err == nil {
t.Errorf("Expected error but got none")
return
}
if !strings.Contains(err.Error(), tt.errorMsg) {
t.Errorf("Expected error to contain %q, got %q", tt.errorMsg, err.Error())
}
// 验证错误码是 ErrCodeSchemaInvalid
if GetErrorCode(err) != ErrCodeSchemaInvalid {
t.Errorf("Expected error code %d, got %d", ErrCodeSchemaInvalid, GetErrorCode(err))
}
} else {
if err != nil {
t.Errorf("Expected no error but got: %v", err)
return
}
// 验证返回的 schema 是正确的
if schema == nil {
t.Errorf("Expected schema, got nil")
return
}
if schema.Name != tt.schemaName {
t.Errorf("Expected schema name %q, got %q", tt.schemaName, schema.Name)
}
if len(schema.Fields) != len(tt.fields) {
t.Errorf("Expected %d fields, got %d", len(tt.fields), len(schema.Fields))
}
}
})
}
}
// TestNewSchemaFieldValidation 测试字段级别的验证
func TestNewSchemaFieldValidation(t *testing.T) {
t.Run("Multiple duplicate field names", func(t *testing.T) {
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64},
{Name: "name", Type: FieldTypeString},
{Name: "id", Type: FieldTypeString}, // First duplicate
{Name: "name", Type: FieldTypeString}, // Second duplicate
})
if err == nil {
t.Errorf("Expected error for duplicate field names")
return
}
// 应该在第一个重复处就停止
if !strings.Contains(err.Error(), "duplicate field name: id") {
t.Errorf("Expected error about duplicate field 'id', got: %v", err)
}
if schema != nil {
t.Errorf("Expected nil schema on error, got %+v", schema)
}
})
t.Run("Case sensitive field names", func(t *testing.T) {
// 大小写敏感ID 和 id 应该是不同的字段
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64},
{Name: "ID", Type: FieldTypeInt64},
{Name: "Id", Type: FieldTypeInt64},
})
if err != nil {
t.Errorf("Expected no error for case-sensitive field names, got: %v", err)
return
}
if len(schema.Fields) != 3 {
t.Errorf("Expected 3 fields (case sensitive), got %d", len(schema.Fields))
}
})
t.Run("Fields with all types", func(t *testing.T) {
schema, err := NewSchema("test", []Field{
{Name: "int_field", Type: FieldTypeInt64},
{Name: "string_field", Type: FieldTypeString},
{Name: "float_field", Type: FieldTypeFloat},
{Name: "bool_field", Type: FieldTypeBool},
})
if err != nil {
t.Errorf("Expected no error, got: %v", err)
return
}
if len(schema.Fields) != 4 {
t.Errorf("Expected 4 fields, got %d", len(schema.Fields))
}
// 验证每个字段的类型
expectedTypes := map[string]FieldType{
"int_field": FieldTypeInt64,
"string_field": FieldTypeString,
"float_field": FieldTypeFloat,
"bool_field": FieldTypeBool,
}
for _, field := range schema.Fields {
expectedType, exists := expectedTypes[field.Name]
if !exists {
t.Errorf("Unexpected field name: %s", field.Name)
continue
}
if field.Type != expectedType {
t.Errorf("Field %s: expected type %v, got %v", field.Name, expectedType, field.Type)
}
}
})
}
// TestNewSchemaEdgeCases 测试边界情况
func TestNewSchemaEdgeCases(t *testing.T) {
t.Run("Very long schema name", func(t *testing.T) {
longName := strings.Repeat("a", 1000)
schema, err := NewSchema(longName, []Field{
{Name: "id", Type: FieldTypeInt64},
})
if err != nil {
t.Errorf("Expected no error for long schema name, got: %v", err)
return
}
if schema.Name != longName {
t.Errorf("Expected schema name to be preserved")
}
})
t.Run("Very long field name", func(t *testing.T) {
longFieldName := strings.Repeat("b", 1000)
schema, err := NewSchema("test", []Field{
{Name: longFieldName, Type: FieldTypeInt64},
})
if err != nil {
t.Errorf("Expected no error for long field name, got: %v", err)
return
}
if schema.Fields[0].Name != longFieldName {
t.Errorf("Expected field name to be preserved")
}
})
t.Run("Many fields", func(t *testing.T) {
fields := make([]Field, 100)
for i := 0; i < 100; i++ {
fields[i] = Field{
Name: strings.Repeat("field", 1) + string(rune('a'+i)),
Type: FieldTypeInt64,
}
}
schema, err := NewSchema("test", fields)
if err != nil {
t.Errorf("Expected no error for many fields, got: %v", err)
return
}
if len(schema.Fields) != 100 {
t.Errorf("Expected 100 fields, got %d", len(schema.Fields))
}
})
t.Run("Field with special characters", func(t *testing.T) {
schema, err := NewSchema("test", []Field{
{Name: "field_with_underscore", Type: FieldTypeInt64},
{Name: "field123", Type: FieldTypeInt64},
{Name: "字段名", Type: FieldTypeString}, // 中文字段名
})
if err != nil {
t.Errorf("Expected no error for special characters, got: %v", err)
return
}
if len(schema.Fields) != 3 {
t.Errorf("Expected 3 fields with special characters, got %d", len(schema.Fields))
}
})
}
// TestNewSchemaConsistency 测试创建后的一致性
func TestNewSchemaConsistency(t *testing.T) {
t.Run("Field order preserved", func(t *testing.T) {
fields := []Field{
{Name: "zebra", Type: FieldTypeString},
{Name: "alpha", Type: FieldTypeInt64},
{Name: "beta", Type: FieldTypeFloat},
}
schema, err := NewSchema("test", fields)
if err != nil {
t.Errorf("Expected no error, got: %v", err)
return
}
// 字段顺序应该保持不变
for i, field := range schema.Fields {
if field.Name != fields[i].Name {
t.Errorf("Field order not preserved at index %d: expected %s, got %s",
i, fields[i].Name, field.Name)
}
}
})
t.Run("Field properties preserved", func(t *testing.T) {
fields := []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: true, Comment: "Primary key"},
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "User name"},
}
schema, err := NewSchema("users", fields)
if err != nil {
t.Errorf("Expected no error, got: %v", err)
return
}
// 验证所有属性都被保留
if schema.Fields[0].Indexed != true {
t.Errorf("Expected field 0 to be indexed")
}
if schema.Fields[1].Indexed != false {
t.Errorf("Expected field 1 to not be indexed")
}
if schema.Fields[0].Comment != "Primary key" {
t.Errorf("Expected field 0 comment to be preserved")
}
if schema.Fields[1].Comment != "User name" {
t.Errorf("Expected field 1 comment to be preserved")
}
})
}
func TestExtractIndexValue(t *testing.T) {
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "名称"},
{Name: "age", Type: FieldTypeInt64, Indexed: true, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
data := map[string]any{
"name": "David",
@@ -156,15 +533,21 @@ func TestPredefinedSchemas(t *testing.T) {
func TestChecksumDeterminism(t *testing.T) {
// 创建相同的 Schema 多次
for i := range 10 {
s1 := NewSchema("users", []Field{
s1, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
s2 := NewSchema("users", []Field{
s2, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
checksum1, err := s1.ComputeChecksum()
if err != nil {
@@ -186,15 +569,21 @@ func TestChecksumDeterminism(t *testing.T) {
// TestChecksumFieldOrderIndependent 测试字段顺序不影响 checksum
func TestChecksumFieldOrderIndependent(t *testing.T) {
s1 := NewSchema("users", []Field{
s1, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
s2 := NewSchema("users", []Field{
s2, err := NewSchema("users", []Field{
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
})
if err != nil {
t.Fatal(err)
}
checksum1, _ := s1.ComputeChecksum()
checksum2, _ := s2.ComputeChecksum()
@@ -209,13 +598,19 @@ func TestChecksumFieldOrderIndependent(t *testing.T) {
// TestChecksumDifferentData 测试不同 Schema 的 checksum 应该不同
func TestChecksumDifferentData(t *testing.T) {
s1 := NewSchema("users", []Field{
s1, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: true, Comment: "用户名"},
})
if err != nil {
t.Fatal(err)
}
s2 := NewSchema("users", []Field{
s2, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"}, // Indexed 不同
})
if err != nil {
t.Fatal(err)
}
checksum1, _ := s1.ComputeChecksum()
checksum2, _ := s2.ComputeChecksum()
@@ -236,12 +631,20 @@ func TestChecksumMultipleFieldOrders(t *testing.T) {
fieldD := Field{Name: "email", Type: FieldTypeString, Indexed: true, Comment: "邮箱"}
// 创建不同顺序的 Schema
mustNewSchema := func(name string, fields []Field) *Schema {
s, err := NewSchema(name, fields)
if err != nil {
t.Fatalf("Failed to create schema: %v", err)
}
return s
}
schemas := []*Schema{
NewSchema("test", []Field{fieldA, fieldB, fieldC, fieldD}), // 原始顺序
NewSchema("test", []Field{fieldD, fieldC, fieldB, fieldA}), // 完全反转
NewSchema("test", []Field{fieldB, fieldD, fieldA, fieldC}), // 随机顺序 1
NewSchema("test", []Field{fieldC, fieldA, fieldD, fieldB}), // 随机顺序 2
NewSchema("test", []Field{fieldD, fieldA, fieldC, fieldB}), // 随机顺序 3
mustNewSchema("test", []Field{fieldA, fieldB, fieldC, fieldD}), // 原始顺序
mustNewSchema("test", []Field{fieldD, fieldC, fieldB, fieldA}), // 完全反转
mustNewSchema("test", []Field{fieldB, fieldD, fieldA, fieldC}), // 随机顺序 1
mustNewSchema("test", []Field{fieldC, fieldA, fieldD, fieldB}), // 随机顺序 2
mustNewSchema("test", []Field{fieldD, fieldA, fieldC, fieldB}), // 随机顺序 3
}
// 计算所有 checksum
@@ -478,7 +881,10 @@ func TestStructToFieldsWithSchema(t *testing.T) {
}
// 创建 Schema
schema := NewSchema("customers", fields)
schema, err := NewSchema("customers", fields)
if err != nil {
t.Fatal(err)
}
// 验证 Schema
if schema.Name != "customers" {

View File

@@ -16,10 +16,13 @@ func TestSSTable(t *testing.T) {
defer os.Remove("test.sst")
// 创建 Schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "age", Type: FieldTypeInt64},
})
if err != nil {
t.Fatal(err)
}
// 2. 写入数据
writer := NewSSTableWriter(file, schema)
@@ -164,9 +167,12 @@ func TestSSTableHeaderSerialization(t *testing.T) {
func BenchmarkSSTableGet(b *testing.B) {
// 创建 Schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "value", Type: FieldTypeInt64},
})
if err != nil {
b.Fatal(err)
}
// 创建测试文件
file, _ := os.Create("bench.sst")

View File

@@ -80,7 +80,10 @@ func OpenTable(opts *TableOptions) (*Table, error) {
var sch *Schema
if opts.Name != "" && len(opts.Fields) > 0 {
// 从 Name 和 Fields 创建 Schema
sch = NewSchema(opts.Name, opts.Fields)
sch, err = NewSchema(opts.Name, opts.Fields)
if err != nil {
return nil, fmt.Errorf("create schema: %w", err)
}
// 保存到磁盘(带校验和)
schemaPath := filepath.Join(opts.Dir, "schema.json")
schemaFile, err := NewSchemaFile(sch)

View File

@@ -18,10 +18,13 @@ func TestTable(t *testing.T) {
os.RemoveAll(dir)
defer os.RemoveAll(dir)
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: dir,
@@ -80,9 +83,12 @@ func TestTableRecover(t *testing.T) {
os.RemoveAll(dir)
defer os.RemoveAll(dir)
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "value", Type: FieldTypeInt64, Indexed: false, Comment: "值"},
})
if err != nil {
t.Fatal(err)
}
// 1. 创建引擎并插入数据
table, err := OpenTable(&TableOptions{
@@ -143,9 +149,12 @@ func TestTableFlush(t *testing.T) {
os.RemoveAll(dir)
defer os.RemoveAll(dir)
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "data", Type: FieldTypeString, Indexed: false, Comment: "数据"},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: dir,
@@ -193,9 +202,12 @@ func BenchmarkTableInsert(b *testing.B) {
os.RemoveAll(dir)
defer os.RemoveAll(dir)
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "value", Type: FieldTypeInt64, Indexed: false, Comment: "值"},
})
if err != nil {
b.Fatal(err)
}
table, _ := OpenTable(&TableOptions{
Dir: dir,
@@ -219,9 +231,12 @@ func BenchmarkTableGet(b *testing.B) {
os.RemoveAll(dir)
defer os.RemoveAll(dir)
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "value", Type: FieldTypeInt64, Indexed: false, Comment: "值"},
})
if err != nil {
b.Fatal(err)
}
table, _ := OpenTable(&TableOptions{
Dir: dir,
@@ -251,9 +266,12 @@ func TestHighConcurrencyWrite(t *testing.T) {
// Note: This test uses []byte payload - we create a minimal schema
// Schema validation accepts []byte as it gets JSON-marshaled
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "worker_id", Type: FieldTypeInt64, Indexed: false, Comment: "Worker ID"},
})
if err != nil {
t.Fatal(err)
}
opts := &TableOptions{
Dir: tmpDir,
@@ -366,9 +384,12 @@ func TestConcurrentReadWrite(t *testing.T) {
tmpDir := t.TempDir()
// Note: This test uses []byte data - we create a minimal schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "writer_id", Type: FieldTypeInt64, Indexed: false, Comment: "Writer ID"},
})
if err != nil {
t.Fatal(err)
}
opts := &TableOptions{
Dir: tmpDir,
@@ -485,9 +506,12 @@ func TestPowerFailureRecovery(t *testing.T) {
t.Log("=== 阶段 1: 写入数据 ===")
// Note: This test uses []byte data - we create a minimal schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "batch", Type: FieldTypeInt64, Indexed: false, Comment: "Batch number"},
})
if err != nil {
t.Fatal(err)
}
opts := &TableOptions{
Dir: tmpDir,
@@ -621,9 +645,12 @@ func TestCrashDuringCompaction(t *testing.T) {
tmpDir := t.TempDir()
// Note: This test uses []byte data - we create a minimal schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "index", Type: FieldTypeInt64, Indexed: false, Comment: "Index"},
})
if err != nil {
t.Fatal(err)
}
opts := &TableOptions{
Dir: tmpDir,
@@ -721,9 +748,12 @@ func TestLargeDataIntegrity(t *testing.T) {
tmpDir := t.TempDir()
// Note: This test uses []byte data - we create a minimal schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "size", Type: FieldTypeInt64, Indexed: false, Comment: "Size"},
})
if err != nil {
t.Fatal(err)
}
opts := &TableOptions{
Dir: tmpDir,
@@ -832,9 +862,12 @@ func BenchmarkConcurrentWrites(b *testing.B) {
tmpDir := b.TempDir()
// Note: This benchmark uses []byte data - we create a minimal schema
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "timestamp", Type: FieldTypeInt64, Indexed: false, Comment: "Timestamp"},
})
if err != nil {
b.Fatal(err)
}
opts := &TableOptions{
Dir: tmpDir,
@@ -883,11 +916,14 @@ func TestTableWithCompaction(t *testing.T) {
// 创建临时目录
tmpDir := t.TempDir()
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "batch", Type: FieldTypeInt64, Indexed: false, Comment: "批次"},
{Name: "index", Type: FieldTypeInt64, Indexed: false, Comment: "索引"},
{Name: "value", Type: FieldTypeString, Indexed: false, Comment: "值"},
})
if err != nil {
t.Fatal(err)
}
// 打开 Table
opts := &TableOptions{
@@ -1009,11 +1045,14 @@ func TestTableWithCompaction(t *testing.T) {
func TestTableCompactionMerge(t *testing.T) {
tmpDir := t.TempDir()
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "batch", Type: FieldTypeInt64, Indexed: false, Comment: "批次"},
{Name: "index", Type: FieldTypeInt64, Indexed: false, Comment: "索引"},
{Name: "value", Type: FieldTypeString, Indexed: false, Comment: "值"},
})
if err != nil {
t.Fatal(err)
}
opts := &TableOptions{
Dir: tmpDir,
@@ -1114,10 +1153,13 @@ func TestTableBackgroundCompaction(t *testing.T) {
tmpDir := t.TempDir()
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "batch", Type: FieldTypeInt64, Indexed: false, Comment: "批次"},
{Name: "index", Type: FieldTypeInt64, Indexed: false, Comment: "索引"},
})
if err != nil {
t.Fatal(err)
}
opts := &TableOptions{
Dir: tmpDir,
@@ -1201,10 +1243,13 @@ func TestTableBackgroundCompaction(t *testing.T) {
func BenchmarkTableWithCompaction(b *testing.B) {
tmpDir := b.TempDir()
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "index", Type: FieldTypeInt64, Indexed: false, Comment: "索引"},
{Name: "value", Type: FieldTypeString, Indexed: false, Comment: "值"},
})
if err != nil {
b.Fatal(err)
}
opts := &TableOptions{
Dir: tmpDir,
@@ -1253,11 +1298,14 @@ func TestTableSchemaRecover(t *testing.T) {
defer os.RemoveAll(dir)
// 创建 Schema
s := NewSchema("users", []Field{
s, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
{Name: "email", Type: FieldTypeString, Indexed: false, Comment: "邮箱"},
})
if err != nil {
t.Fatal(err)
}
// 1. 创建引擎并插入数据(带 Schema
table, err := OpenTable(&TableOptions{
@@ -1325,10 +1373,13 @@ func TestTableSchemaRecoverInvalid(t *testing.T) {
os.RemoveAll(dir)
defer os.RemoveAll(dir)
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"},
{Name: "age", Type: FieldTypeString, Indexed: false, Comment: "年龄字符串"},
})
if err != nil {
t.Fatal(err)
}
// 1. 先不带 Schema 插入一些数据
table, err := OpenTable(&TableOptions{
@@ -1369,10 +1420,13 @@ func TestTableSchemaRecoverInvalid(t *testing.T) {
}
// 3. 创建 Schemaage 字段要求 int64
s := NewSchema("users", []Field{
s, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
// 4. 尝试用 Schema 打开引擎,应该失败
table2, err := OpenTable(&TableOptions{
@@ -1400,10 +1454,13 @@ func TestTableAutoRecoverSchema(t *testing.T) {
defer os.RemoveAll(dir)
// 创建 Schema
s := NewSchema("users", []Field{
s, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
// 1. 创建引擎并提供 Schema会保存到磁盘
table1, err := OpenTable(&TableOptions{
@@ -1492,10 +1549,13 @@ func TestTableSchemaTamperDetection(t *testing.T) {
defer os.RemoveAll(dir)
// 创建 Schema
s := NewSchema("users", []Field{
s, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "用户名"},
{Name: "age", Type: FieldTypeInt64, Indexed: false, Comment: "年龄"},
})
if err != nil {
t.Fatal(err)
}
// 1. 创建引擎并保存 Schema
table1, err := OpenTable(&TableOptions{
@@ -1554,10 +1614,13 @@ func TestTableClean(t *testing.T) {
}
defer db.Close()
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: true, Comment: "ID"},
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "Name"},
})
if err != nil {
t.Fatal(err)
}
table, err := db.CreateTable("users", schema)
if err != nil {
@@ -1623,9 +1686,12 @@ func TestTableDestroy(t *testing.T) {
}
defer db.Close()
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
})
if err != nil {
t.Fatal(err)
}
table, err := db.CreateTable("test", schema)
if err != nil {
@@ -1679,11 +1745,14 @@ func TestTableCleanWithIndex(t *testing.T) {
}
defer db.Close()
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: true, Comment: "ID"},
{Name: "email", Type: FieldTypeString, Indexed: true, Comment: "Email"},
{Name: "name", Type: FieldTypeString, Indexed: false, Comment: "Name"},
})
if err != nil {
t.Fatal(err)
}
table, err := db.CreateTable("users", schema)
if err != nil {
@@ -1765,10 +1834,13 @@ func TestTableCleanAndQuery(t *testing.T) {
}
defer db.Close()
schema := NewSchema("test", []Field{
schema, err := NewSchema("test", []Field{
{Name: "id", Type: FieldTypeInt64, Indexed: false, Comment: "ID"},
{Name: "status", Type: FieldTypeString, Indexed: false, Comment: "Status"},
})
if err != nil {
t.Fatal(err)
}
table, err := db.CreateTable("test", schema)
if err != nil {
@@ -1850,10 +1922,13 @@ func TestInsertMap(t *testing.T) {
tmpDir, _ := os.MkdirTemp("", "TestInsertMap")
defer os.RemoveAll(tmpDir)
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "age", Type: FieldTypeInt64},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -1892,10 +1967,13 @@ func TestInsertMapSlice(t *testing.T) {
tmpDir, _ := os.MkdirTemp("", "TestInsertMapSlice")
defer os.RemoveAll(tmpDir)
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "age", Type: FieldTypeInt64},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -1940,11 +2018,14 @@ func TestInsertStruct(t *testing.T) {
Email string `srdb:"email"`
}
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "age", Type: FieldTypeInt64},
{Name: "email", Type: FieldTypeString},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -1995,11 +2076,14 @@ func TestInsertStructPointer(t *testing.T) {
Email string `srdb:"email"`
}
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "age", Type: FieldTypeInt64},
{Name: "email", Type: FieldTypeString},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -2046,10 +2130,13 @@ func TestInsertStructSlice(t *testing.T) {
Age int64 `srdb:"age"`
}
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "age", Type: FieldTypeInt64},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -2095,10 +2182,13 @@ func TestInsertStructPointerSlice(t *testing.T) {
Age int64 `srdb:"age"`
}
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "age", Type: FieldTypeInt64},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -2146,11 +2236,14 @@ func TestInsertWithSnakeCase(t *testing.T) {
IsActive bool // 应该自动转为 is_active
}
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "user_name", Type: FieldTypeString, Comment: "用户名"},
{Name: "email_address", Type: FieldTypeString},
{Name: "is_active", Type: FieldTypeBool},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -2198,9 +2291,12 @@ func TestInsertInvalidType(t *testing.T) {
tmpDir, _ := os.MkdirTemp("", "TestInsertInvalidType")
defer os.RemoveAll(tmpDir)
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -2236,9 +2332,12 @@ func TestInsertEmptySlice(t *testing.T) {
tmpDir, _ := os.MkdirTemp("", "TestInsertEmptySlice")
defer os.RemoveAll(tmpDir)
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,
@@ -2270,10 +2369,13 @@ func TestBatchInsertPerformance(t *testing.T) {
tmpDir, _ := os.MkdirTemp("", "TestBatchInsertPerformance")
defer os.RemoveAll(tmpDir)
schema := NewSchema("users", []Field{
schema, err := NewSchema("users", []Field{
{Name: "name", Type: FieldTypeString},
{Name: "age", Type: FieldTypeInt64},
})
if err != nil {
t.Fatal(err)
}
table, err := OpenTable(&TableOptions{
Dir: tmpDir,