stardb/testing/batch_test.go
2026-03-07 19:27:44 +08:00

564 lines
13 KiB
Go

package testing
import (
"context"
"testing"
"time"
"b612.me/stardb"
_ "modernc.org/sqlite"
)
type TestUser struct {
ID int64 `db:"id"`
Name string `db:"name"`
Email string `db:"email"`
Age int `db:"age"`
CreatedAt time.Time `db:"created_at"`
}
func setupBatchTestDB(t *testing.T) *stardb.StarDB {
db := stardb.NewStarDB()
err := db.Open("sqlite", ":memory:")
if err != nil {
t.Fatalf("Failed to open database: %v", err)
}
_, err = db.Exec(`
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT NOT NULL,
age INTEGER,
created_at DATETIME
)
`)
if err != nil {
t.Fatalf("Failed to create table: %v", err)
}
return db
}
func TestStarDB_BatchInsert_Basic(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
columns := []string{"name", "email", "age"}
values := [][]interface{}{
{"Alice", "alice@example.com", 25},
{"Bob", "bob@example.com", 30},
{"Charlie", "charlie@example.com", 35},
}
result, err := db.BatchInsert("users", columns, values)
if err != nil {
t.Fatalf("BatchInsert failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 3 {
t.Errorf("Expected 3 rows affected, got %d", affected)
}
// Verify insertion
rows, err := db.Query("SELECT COUNT(*) as count FROM users")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
count := rows.Row(0).MustInt("count")
if count != 3 {
t.Errorf("Expected 3 rows in database, got %d", count)
}
}
func TestStarDB_BatchInsert_Single(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
columns := []string{"name", "email", "age"}
values := [][]interface{}{
{"Alice", "alice@example.com", 25},
}
result, err := db.BatchInsert("users", columns, values)
if err != nil {
t.Fatalf("BatchInsert failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 1 {
t.Errorf("Expected 1 row affected, got %d", affected)
}
}
func TestStarDB_BatchInsert_Empty(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
columns := []string{"name", "email", "age"}
values := [][]interface{}{}
_, err := db.BatchInsert("users", columns, values)
if err == nil {
t.Error("Expected error with empty values, got nil")
}
}
func TestStarDB_BatchInsert_Large(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
columns := []string{"name", "email", "age"}
var values [][]interface{}
// Insert 100 rows
for i := 0; i < 100; i++ {
values = append(values, []interface{}{
"User" + string(rune(i)),
"user" + string(rune(i)) + "@example.com",
20 + i%50,
})
}
result, err := db.BatchInsert("users", columns, values)
if err != nil {
t.Fatalf("BatchInsert failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 100 {
t.Errorf("Expected 100 rows affected, got %d", affected)
}
// Verify
rows, err := db.Query("SELECT COUNT(*) as count FROM users")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
count := rows.Row(0).MustInt("count")
if count != 100 {
t.Errorf("Expected 100 rows in database, got %d", count)
}
}
func TestStarDB_BatchInsertContext(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
ctx := context.Background()
columns := []string{"name", "email", "age"}
values := [][]interface{}{
{"Alice", "alice@example.com", 25},
{"Bob", "bob@example.com", 30},
}
result, err := db.BatchInsertContext(ctx, "users", columns, values)
if err != nil {
t.Fatalf("BatchInsertContext failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 2 {
t.Errorf("Expected 2 rows affected, got %d", affected)
}
}
func TestStarDB_BatchInsertContext_Timeout(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
defer cancel()
time.Sleep(10 * time.Millisecond) // Ensure timeout
columns := []string{"name", "email", "age"}
values := [][]interface{}{
{"Alice", "alice@example.com", 25},
}
_, err := db.BatchInsertContext(ctx, "users", columns, values)
if err == nil {
t.Error("Expected timeout error, got nil")
}
}
func TestStarDB_BatchInsertStructs_Basic(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
users := []TestUser{
{Name: "Alice", Email: "alice@example.com", Age: 25, CreatedAt: time.Now()},
{Name: "Bob", Email: "bob@example.com", Age: 30, CreatedAt: time.Now()},
{Name: "Charlie", Email: "charlie@example.com", Age: 35, CreatedAt: time.Now()},
}
result, err := db.BatchInsertStructs("users", users, "id")
if err != nil {
t.Fatalf("BatchInsertStructs failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 3 {
t.Errorf("Expected 3 rows affected, got %d", affected)
}
// Verify insertion
rows, err := db.Query("SELECT * FROM users ORDER BY name")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
if rows.Length() != 3 {
t.Errorf("Expected 3 rows, got %d", rows.Length())
}
// Verify first user
name := rows.Row(0).MustString("name")
if name != "Alice" {
t.Errorf("Expected first user 'Alice', got '%s'", name)
}
}
func TestStarDB_BatchInsertStructs_Single(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
users := []TestUser{
{Name: "Alice", Email: "alice@example.com", Age: 25, CreatedAt: time.Now()},
}
result, err := db.BatchInsertStructs("users", users, "id")
if err != nil {
t.Fatalf("BatchInsertStructs failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 1 {
t.Errorf("Expected 1 row affected, got %d", affected)
}
}
func TestStarDB_BatchInsertStructs_Empty(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
users := []TestUser{}
_, err := db.BatchInsertStructs("users", users, "id")
if err == nil {
t.Error("Expected error with empty slice, got nil")
}
}
func TestStarDB_BatchInsertStructs_NotSlice(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
user := TestUser{Name: "Alice", Email: "alice@example.com", Age: 25}
_, err := db.BatchInsertStructs("users", user, "id")
if err == nil {
t.Error("Expected error with non-slice, got nil")
}
}
func TestStarDB_BatchInsertStructs_Pointer(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
users := []TestUser{
{Name: "Alice", Email: "alice@example.com", Age: 25, CreatedAt: time.Now()},
{Name: "Bob", Email: "bob@example.com", Age: 30, CreatedAt: time.Now()},
}
result, err := db.BatchInsertStructs("users", &users, "id")
if err != nil {
t.Fatalf("BatchInsertStructs with pointer failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 2 {
t.Errorf("Expected 2 rows affected, got %d", affected)
}
}
func TestStarDB_BatchInsertStructsContext(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
ctx := context.Background()
users := []TestUser{
{Name: "Alice", Email: "alice@example.com", Age: 25, CreatedAt: time.Now()},
{Name: "Bob", Email: "bob@example.com", Age: 30, CreatedAt: time.Now()},
}
result, err := db.BatchInsertStructsContext(ctx, "users", users, "id")
if err != nil {
t.Fatalf("BatchInsertStructsContext failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 2 {
t.Errorf("Expected 2 rows affected, got %d", affected)
}
}
func TestStarDB_BatchInsertStructs_Large(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
var users []TestUser
for i := 0; i < 50; i++ {
users = append(users, TestUser{
Name: "User" + string(rune(i)),
Email: "user" + string(rune(i)) + "@example.com",
Age: 20 + i%30,
CreatedAt: time.Now(),
})
}
result, err := db.BatchInsertStructs("users", users, "id")
if err != nil {
t.Fatalf("BatchInsertStructs failed: %v", err)
}
affected, err := result.RowsAffected()
if err != nil {
t.Fatalf("RowsAffected failed: %v", err)
}
if affected != 50 {
t.Errorf("Expected 50 rows affected, got %d", affected)
}
// Verify
rows, err := db.Query("SELECT COUNT(*) as count FROM users")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
count := rows.Row(0).MustInt("count")
if count != 50 {
t.Errorf("Expected 50 rows in database, got %d", count)
}
}
func TestStarDB_BatchInsert_VerifyData(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
columns := []string{"name", "email", "age"}
values := [][]interface{}{
{"Alice", "alice@example.com", 25},
{"Bob", "bob@example.com", 30},
}
_, err := db.BatchInsert("users", columns, values)
if err != nil {
t.Fatalf("BatchInsert failed: %v", err)
}
// Verify data integrity
rows, err := db.Query("SELECT name, email, age FROM users ORDER BY name")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
// Check Alice
row0 := rows.Row(0)
if row0.MustString("name") != "Alice" {
t.Errorf("Expected name 'Alice', got '%s'", row0.MustString("name"))
}
if row0.MustString("email") != "alice@example.com" {
t.Errorf("Expected email 'alice@example.com', got '%s'", row0.MustString("email"))
}
if row0.MustInt("age") != 25 {
t.Errorf("Expected age 25, got %d", row0.MustInt("age"))
}
// Check Bob
row1 := rows.Row(1)
if row1.MustString("name") != "Bob" {
t.Errorf("Expected name 'Bob', got '%s'", row1.MustString("name"))
}
if row1.MustString("email") != "bob@example.com" {
t.Errorf("Expected email 'bob@example.com', got '%s'", row1.MustString("email"))
}
if row1.MustInt("age") != 30 {
t.Errorf("Expected age 30, got %d", row1.MustInt("age"))
}
}
func TestStarDB_BatchInsertStructs_VerifyData(t *testing.T) {
db := setupBatchTestDB(t)
defer db.Close()
now := time.Now()
users := []TestUser{
{Name: "Alice", Email: "alice@example.com", Age: 25, CreatedAt: now},
{Name: "Bob", Email: "bob@example.com", Age: 30, CreatedAt: now},
}
_, err := db.BatchInsertStructs("users", users, "id")
if err != nil {
t.Fatalf("BatchInsertStructs failed: %v", err)
}
// Query and verify with ORM
rows, err := db.Query("SELECT * FROM users ORDER BY name")
if err != nil {
t.Fatalf("Query failed: %v", err)
}
defer rows.Close()
var resultUsers []TestUser
err = rows.Orm(&resultUsers)
if err != nil {
t.Fatalf("Orm failed: %v", err)
}
if len(resultUsers) != 2 {
t.Fatalf("Expected 2 users, got %d", len(resultUsers))
}
// Verify Alice
if resultUsers[0].Name != "Alice" {
t.Errorf("Expected name 'Alice', got '%s'", resultUsers[0].Name)
}
if resultUsers[0].Email != "alice@example.com" {
t.Errorf("Expected email 'alice@example.com', got '%s'", resultUsers[0].Email)
}
if resultUsers[0].Age != 25 {
t.Errorf("Expected age 25, got %d", resultUsers[0].Age)
}
// Verify Bob
if resultUsers[1].Name != "Bob" {
t.Errorf("Expected name 'Bob', got '%s'", resultUsers[1].Name)
}
if resultUsers[1].Email != "bob@example.com" {
t.Errorf("Expected email 'bob@example.com', got '%s'", resultUsers[1].Email)
}
if resultUsers[1].Age != 30 {
t.Errorf("Expected age 30, got %d", resultUsers[1].Age)
}
}
// Benchmark tests
func BenchmarkBatchInsert_10(b *testing.B) {
db := setupBatchTestDB(&testing.T{})
defer db.Close()
columns := []string{"name", "email", "age"}
var values [][]interface{}
for i := 0; i < 10; i++ {
values = append(values, []interface{}{"User", "user@example.com", 25})
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
db.BatchInsert("users", columns, values)
db.Exec("DELETE FROM users")
}
}
func BenchmarkBatchInsert_100(b *testing.B) {
db := setupBatchTestDB(&testing.T{})
defer db.Close()
columns := []string{"name", "email", "age"}
var values [][]interface{}
for i := 0; i < 100; i++ {
values = append(values, []interface{}{"User", "user@example.com", 25})
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
db.BatchInsert("users", columns, values)
db.Exec("DELETE FROM users")
}
}
func BenchmarkBatchInsertStructs_10(b *testing.B) {
db := setupBatchTestDB(&testing.T{})
defer db.Close()
var users []TestUser
for i := 0; i < 10; i++ {
users = append(users, TestUser{
Name: "User",
Email: "user@example.com",
Age: 25,
CreatedAt: time.Now(),
})
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
db.BatchInsertStructs("users", users, "id")
db.Exec("DELETE FROM users")
}
}
func BenchmarkBatchInsertStructs_100(b *testing.B) {
db := setupBatchTestDB(&testing.T{})
defer db.Close()
var users []TestUser
for i := 0; i < 100; i++ {
users = append(users, TestUser{
Name: "User",
Email: "user@example.com",
Age: 25,
CreatedAt: time.Now(),
})
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
db.BatchInsertStructs("users", users, "id")
db.Exec("DELETE FROM users")
}
}