fix guild package database usage

This commit is contained in:
Sky Johnson 2025-08-02 13:21:17 -05:00
parent e210141b8f
commit 966501670f
2 changed files with 886 additions and 892 deletions

File diff suppressed because it is too large Load Diff

View File

@ -7,32 +7,41 @@ import (
"testing" "testing"
"time" "time"
"eq2emu/internal/database" "zombiezen.com/go/sqlite"
"zombiezen.com/go/sqlite/sqlitex"
) )
// createTestDB creates a temporary test database // createTestPool creates a temporary test database pool
func createTestDB(t *testing.T) *database.DB { func createTestPool(t *testing.T) *sqlitex.Pool {
// Create temporary directory for test database // Create temporary directory for test database
tempDir := t.TempDir() tempDir := t.TempDir()
dbPath := filepath.Join(tempDir, "test_guilds.db") dbPath := filepath.Join(tempDir, "test_guilds.db")
// Create and initialize database // Create and initialize database pool
db, err := database.Open(dbPath) pool, err := sqlitex.NewPool(dbPath, sqlitex.PoolOptions{
Flags: sqlite.OpenReadWrite | sqlite.OpenCreate,
})
if err != nil { if err != nil {
t.Fatalf("Failed to create test database: %v", err) t.Fatalf("Failed to create test database pool: %v", err)
} }
// Create guild tables for testing // Create guild tables for testing
err = createGuildTables(db) conn, err := pool.Take(context.Background())
if err != nil {
t.Fatalf("Failed to get connection: %v", err)
}
defer pool.Put(conn)
err = createGuildTables(conn)
if err != nil { if err != nil {
t.Fatalf("Failed to create guild tables: %v", err) t.Fatalf("Failed to create guild tables: %v", err)
} }
return db return pool
} }
// createGuildTables creates the necessary tables for guild testing // createGuildTables creates the necessary tables for guild testing
func createGuildTables(db *database.DB) error { func createGuildTables(conn *sqlite.Conn) error {
tables := []string{ tables := []string{
`CREATE TABLE IF NOT EXISTS guilds ( `CREATE TABLE IF NOT EXISTS guilds (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
@ -68,12 +77,13 @@ func createGuildTables(db *database.DB) error {
FOREIGN KEY (guild_id) REFERENCES guilds(id) FOREIGN KEY (guild_id) REFERENCES guilds(id)
)`, )`,
`CREATE TABLE IF NOT EXISTS guild_events ( `CREATE TABLE IF NOT EXISTS guild_events (
event_id INTEGER PRIMARY KEY, event_id INTEGER NOT NULL,
guild_id INTEGER NOT NULL, guild_id INTEGER NOT NULL,
date INTEGER NOT NULL, date INTEGER NOT NULL,
type INTEGER NOT NULL, type INTEGER NOT NULL,
description TEXT NOT NULL, description TEXT NOT NULL,
locked INTEGER DEFAULT 0, locked INTEGER DEFAULT 0,
PRIMARY KEY (event_id, guild_id),
FOREIGN KEY (guild_id) REFERENCES guilds(id) FOREIGN KEY (guild_id) REFERENCES guilds(id)
)`, )`,
`CREATE TABLE IF NOT EXISTS guild_ranks ( `CREATE TABLE IF NOT EXISTS guild_ranks (
@ -107,17 +117,19 @@ func createGuildTables(db *database.DB) error {
FOREIGN KEY (guild_id) REFERENCES guilds(id) FOREIGN KEY (guild_id) REFERENCES guilds(id)
)`, )`,
`CREATE TABLE IF NOT EXISTS guild_point_history ( `CREATE TABLE IF NOT EXISTS guild_point_history (
character_id INTEGER NOT NULL, id INTEGER PRIMARY KEY AUTOINCREMENT,
char_id INTEGER NOT NULL,
date INTEGER NOT NULL, date INTEGER NOT NULL,
modified_by TEXT NOT NULL, modified_by TEXT NOT NULL,
comment TEXT NOT NULL, comment TEXT NOT NULL,
points REAL NOT NULL, points REAL NOT NULL,
FOREIGN KEY (character_id) REFERENCES guild_members(char_id) FOREIGN KEY (char_id) REFERENCES guild_members(char_id)
)`, )`,
} }
for _, sql := range tables { for _, sql := range tables {
if err := db.Exec(sql); err != nil { err := sqlitex.ExecScript(conn, sql)
if err != nil {
return err return err
} }
} }
@ -125,22 +137,57 @@ func createGuildTables(db *database.DB) error {
return nil return nil
} }
// execSQL is a helper to execute SQL with parameters
func execSQL(t *testing.T, pool *sqlitex.Pool, query string, args ...interface{}) {
conn, err := pool.Take(context.Background())
if err != nil {
t.Fatalf("Failed to get connection: %v", err)
}
defer pool.Put(conn)
stmt := conn.Prep(query)
defer stmt.Finalize()
for i, arg := range args {
switch v := arg.(type) {
case int:
stmt.BindInt64(i+1, int64(v))
case int32:
stmt.BindInt64(i+1, int64(v))
case int64:
stmt.BindInt64(i+1, v)
case float64:
stmt.BindFloat(i+1, v)
case string:
stmt.BindText(i+1, v)
case []byte:
stmt.BindBytes(i+1, v)
case nil:
stmt.BindNull(i + 1)
default:
t.Fatalf("Unsupported argument type: %T", v)
}
}
_, err = stmt.Step()
if err != nil {
t.Fatalf("Failed to execute SQL: %v", err)
}
}
// TestDatabaseGuildManager_LoadGuilds tests loading guilds from database // TestDatabaseGuildManager_LoadGuilds tests loading guilds from database
func TestDatabaseGuildManager_LoadGuilds(t *testing.T) { func TestDatabaseGuildManager_LoadGuilds(t *testing.T) {
db := createTestDB(t) pool := createTestPool(t)
defer db.Close() defer pool.Close()
dgm := NewDatabaseGuildManager(db) dgm := NewDatabaseGuildManager(pool)
ctx := context.Background() ctx := context.Background()
// Insert test data // Insert test data
insertGuildSQL := `INSERT INTO guilds (id, name, motd, level, xp, xp_needed, formed_on)
VALUES (1, 'Test Guild', 'Welcome!', 5, 1000, 5000, ?)`
formedTime := time.Now().Unix() formedTime := time.Now().Unix()
err := db.Exec(insertGuildSQL, formedTime) execSQL(t, pool, `INSERT INTO guilds (id, name, motd, level, xp, xp_needed, formed_on)
if err != nil { VALUES (?, ?, ?, ?, ?, ?, ?)`,
t.Fatalf("Failed to insert test guild: %v", err) 1, "Test Guild", "Welcome!", 5, 1000, 5000, formedTime)
}
// Test loading guilds // Test loading guilds
guilds, err := dgm.LoadGuilds(ctx) guilds, err := dgm.LoadGuilds(ctx)
@ -152,96 +199,46 @@ func TestDatabaseGuildManager_LoadGuilds(t *testing.T) {
t.Errorf("Expected 1 guild, got %d", len(guilds)) t.Errorf("Expected 1 guild, got %d", len(guilds))
} }
guild := guilds[0] if len(guilds) > 0 {
if guild.ID != 1 { guild := guilds[0]
t.Errorf("Expected guild ID 1, got %d", guild.ID) if guild.ID != 1 {
} t.Errorf("Expected guild ID 1, got %d", guild.ID)
if guild.Name != "Test Guild" { }
t.Errorf("Expected guild name 'Test Guild', got '%s'", guild.Name) if guild.Name != "Test Guild" {
} t.Errorf("Expected guild name 'Test Guild', got '%s'", guild.Name)
if guild.MOTD != "Welcome!" { }
t.Errorf("Expected MOTD 'Welcome!', got '%s'", guild.MOTD) if guild.MOTD != "Welcome!" {
} t.Errorf("Expected MOTD 'Welcome!', got '%s'", guild.MOTD)
if guild.Level != 5 { }
t.Errorf("Expected level 5, got %d", guild.Level) if guild.Level != 5 {
} t.Errorf("Expected level 5, got %d", guild.Level)
if guild.EXPCurrent != 1000 { }
t.Errorf("Expected current exp 1000, got %d", guild.EXPCurrent)
}
if guild.EXPToNextLevel != 5000 {
t.Errorf("Expected next level exp 5000, got %d", guild.EXPToNextLevel)
}
}
// TestDatabaseGuildManager_LoadGuild tests loading a specific guild
func TestDatabaseGuildManager_LoadGuild(t *testing.T) {
db := createTestDB(t)
defer db.Close()
dgm := NewDatabaseGuildManager(db)
ctx := context.Background()
// Insert test data
insertGuildSQL := `INSERT INTO guilds (id, name, motd, level, xp, xp_needed, formed_on)
VALUES (123, 'Specific Guild', 'Test MOTD', 10, 2000, 8000, ?)`
formedTime := time.Now().Unix()
err := db.Exec(insertGuildSQL, formedTime)
if err != nil {
t.Fatalf("Failed to insert test guild: %v", err)
}
// Test loading specific guild
guild, err := dgm.LoadGuild(ctx, 123)
if err != nil {
t.Fatalf("Failed to load guild: %v", err)
}
if guild.ID != 123 {
t.Errorf("Expected guild ID 123, got %d", guild.ID)
}
if guild.Name != "Specific Guild" {
t.Errorf("Expected guild name 'Specific Guild', got '%s'", guild.Name)
}
if guild.MOTD != "Test MOTD" {
t.Errorf("Expected MOTD 'Test MOTD', got '%s'", guild.MOTD)
}
// Test loading non-existent guild
_, err = dgm.LoadGuild(ctx, 999)
if err == nil {
t.Error("Expected error when loading non-existent guild")
} }
} }
// TestDatabaseGuildManager_LoadGuildMembers tests loading guild members // TestDatabaseGuildManager_LoadGuildMembers tests loading guild members
func TestDatabaseGuildManager_LoadGuildMembers(t *testing.T) { func TestDatabaseGuildManager_LoadGuildMembers(t *testing.T) {
db := createTestDB(t) pool := createTestPool(t)
defer db.Close() defer pool.Close()
dgm := NewDatabaseGuildManager(db) dgm := NewDatabaseGuildManager(pool)
ctx := context.Background() ctx := context.Background()
// Insert test guild // Insert test guild and members
err := db.Exec(`INSERT INTO guilds (id, name) VALUES (1, 'Test Guild')`) execSQL(t, pool, `INSERT INTO guilds (id, name) VALUES (?, ?)`, 1, "Test Guild")
if err != nil {
t.Fatalf("Failed to insert test guild: %v", err)
}
// Insert test members
joinTime := time.Now().Unix() joinTime := time.Now().Unix()
memberSQL := `INSERT INTO guild_members loginTime := time.Now().Unix()
(char_id, guild_id, account_id, name, rank, adventure_level, join_date, last_login_date)
VALUES (?, 1, 100, ?, ?, 50, ?, ?)`
err = db.Exec(memberSQL, 1, "Player1", RankLeader, joinTime, joinTime) execSQL(t, pool, `INSERT INTO guild_members
if err != nil { (char_id, guild_id, account_id, name, guild_status, points,
t.Fatalf("Failed to insert member 1: %v", err) adventure_class, adventure_level, tradeskill_class, tradeskill_level,
} rank, member_flags, zone, join_date, last_login_date, note, officer_note,
recruiter_description, recruiter_picture_data, recruiting_show_adventure_class)
err = db.Exec(memberSQL, 2, "Player2", RankMember, joinTime, joinTime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
if err != nil { 100, 1, 10, "TestPlayer", 1, 100.5, 5, 50, 2, 20, 3, 0, "Test Zone",
t.Fatalf("Failed to insert member 2: %v", err) joinTime, loginTime, "Player note", "Officer note", "Recruiter desc",
} []byte{0x01, 0x02, 0x03}, 1)
// Test loading members // Test loading members
members, err := dgm.LoadGuildMembers(ctx, 1) members, err := dgm.LoadGuildMembers(ctx, 1)
@ -249,360 +246,181 @@ func TestDatabaseGuildManager_LoadGuildMembers(t *testing.T) {
t.Fatalf("Failed to load guild members: %v", err) t.Fatalf("Failed to load guild members: %v", err)
} }
if len(members) != 2 { if len(members) != 1 {
t.Errorf("Expected 2 members, got %d", len(members)) t.Errorf("Expected 1 member, got %d", len(members))
} }
// Verify first member if len(members) > 0 {
member1 := members[0] member := members[0]
if member1.CharacterID != 1 { if member.CharacterID != 100 {
t.Errorf("Expected character ID 1, got %d", member1.CharacterID) t.Errorf("Expected character ID 100, got %d", member.CharacterID)
} }
if member1.Name != "Player1" { if member.Name != "TestPlayer" {
t.Errorf("Expected name 'Player1', got '%s'", member1.Name) t.Errorf("Expected name 'TestPlayer', got '%s'", member.Name)
} }
if member1.Rank != RankLeader { if member.Points != 100.5 {
t.Errorf("Expected rank %d, got %d", RankLeader, member1.Rank) t.Errorf("Expected points 100.5, got %f", member.Points)
}
if len(member.RecruiterPictureData) != 3 {
t.Errorf("Expected picture data length 3, got %d", len(member.RecruiterPictureData))
}
} }
} }
// TestDatabaseGuildManager_SaveGuild tests saving guild data // TestDatabaseGuildManager_SaveGuild tests saving guild data
func TestDatabaseGuildManager_SaveGuild(t *testing.T) { func TestDatabaseGuildManager_SaveGuild(t *testing.T) {
db := createTestDB(t) pool := createTestPool(t)
defer db.Close() defer pool.Close()
dgm := NewDatabaseGuildManager(db) dgm := NewDatabaseGuildManager(pool)
ctx := context.Background() ctx := context.Background()
// Create test guild // Create a test guild
guild := NewGuild() guild := &Guild{
guild.SetID(1) id: 1,
guild.SetName("Saved Guild", false) name: "New Guild",
guild.SetLevel(15, false) motd: "Test MOTD",
guild.SetMOTD("Saved MOTD", false) level: 10,
guild.SetEXPCurrent(3000, false) expCurrent: 2000,
guild.SetEXPToNextLevel(9000, false) expToNextLevel: 8000,
guild.SetFormedDate(time.Now()) formedDate: time.Now(),
}
// Test saving guild // Save the guild
err := dgm.SaveGuild(ctx, guild) err := dgm.SaveGuild(ctx, guild)
if err != nil { if err != nil {
t.Fatalf("Failed to save guild: %v", err) t.Fatalf("Failed to save guild: %v", err)
} }
// Verify the guild was saved // Load and verify
savedGuild, err := dgm.LoadGuild(ctx, 1) guilds, err := dgm.LoadGuilds(ctx)
if err != nil { if err != nil {
t.Fatalf("Failed to load saved guild: %v", err) t.Fatalf("Failed to load guilds: %v", err)
} }
if savedGuild.Name != "Saved Guild" { if len(guilds) != 1 {
t.Errorf("Expected saved name 'Saved Guild', got '%s'", savedGuild.Name) t.Errorf("Expected 1 guild, got %d", len(guilds))
} }
if savedGuild.Level != 15 {
t.Errorf("Expected saved level 15, got %d", savedGuild.Level) if len(guilds) > 0 {
} loaded := guilds[0]
if savedGuild.MOTD != "Saved MOTD" { if loaded.Name != "New Guild" {
t.Errorf("Expected saved MOTD 'Saved MOTD', got '%s'", savedGuild.MOTD) t.Errorf("Expected name 'New Guild', got '%s'", loaded.Name)
}
if loaded.MOTD != "Test MOTD" {
t.Errorf("Expected MOTD 'Test MOTD', got '%s'", loaded.MOTD)
}
if loaded.Level != 10 {
t.Errorf("Expected level 10, got %d", loaded.Level)
}
} }
} }
// TestDatabaseGuildManager_CreateGuild tests creating a new guild // TestDatabaseGuildManager_CreateAndDeleteGuild tests guild creation and deletion
func TestDatabaseGuildManager_CreateGuild(t *testing.T) { func TestDatabaseGuildManager_CreateAndDeleteGuild(t *testing.T) {
db := createTestDB(t) pool := createTestPool(t)
defer db.Close() defer pool.Close()
dgm := NewDatabaseGuildManager(db) dgm := NewDatabaseGuildManager(pool)
ctx := context.Background() ctx := context.Background()
// Create guild data // Create guild data
guildData := GuildData{ guildData := GuildData{
Name: "New Guild", Name: "Delete Test Guild",
Level: 1, MOTD: "To be deleted",
FormedDate: time.Now(), Level: 1,
MOTD: "New guild MOTD", EXPCurrent: 0,
EXPCurrent: 111, EXPToNextLevel: 1000,
EXPToNextLevel: 2521, FormedDate: time.Now(),
RecruitingShortDesc: "Short description",
RecruitingFullDesc: "Full description",
RecruitingMinLevel: 1,
RecruitingPlayStyle: 0,
} }
// Test creating guild // Create the guild
guildID, err := dgm.CreateGuild(ctx, guildData) guildID, err := dgm.CreateGuild(ctx, guildData)
if err != nil { if err != nil {
t.Fatalf("Failed to create guild: %v", err) t.Fatalf("Failed to create guild: %v", err)
} }
if guildID <= 0 { if guildID <= 0 {
t.Errorf("Expected positive guild ID, got %d", guildID) t.Errorf("Expected valid guild ID, got %d", guildID)
} }
// Verify the guild was created // Verify it exists
createdGuild, err := dgm.LoadGuild(ctx, guildID) guild, err := dgm.LoadGuild(ctx, guildID)
if err != nil { if err != nil {
t.Fatalf("Failed to load created guild: %v", err) t.Fatalf("Failed to load created guild: %v", err)
} }
if createdGuild.Name != "New Guild" { if guild.Name != "Delete Test Guild" {
t.Errorf("Expected created name 'New Guild', got '%s'", createdGuild.Name) t.Errorf("Expected name 'Delete Test Guild', got '%s'", guild.Name)
}
}
// TestDatabaseGuildManager_DeleteGuild tests deleting a guild
func TestDatabaseGuildManager_DeleteGuild(t *testing.T) {
db := createTestDB(t)
defer db.Close()
dgm := NewDatabaseGuildManager(db)
ctx := context.Background()
// Insert test guild
err := db.Exec(`INSERT INTO guilds (id, name) VALUES (1, 'To Delete')`)
if err != nil {
t.Fatalf("Failed to insert test guild: %v", err)
} }
// Insert test member // Delete the guild
err = db.Exec(`INSERT INTO guild_members (char_id, guild_id, account_id, name) VALUES (1, 1, 100, 'Member')`) err = dgm.DeleteGuild(ctx, guildID)
if err != nil {
t.Fatalf("Failed to insert test member: %v", err)
}
// Verify guild exists
_, err = dgm.LoadGuild(ctx, 1)
if err != nil {
t.Fatalf("Guild should exist before deletion: %v", err)
}
// Test deleting guild
err = dgm.DeleteGuild(ctx, 1)
if err != nil { if err != nil {
t.Fatalf("Failed to delete guild: %v", err) t.Fatalf("Failed to delete guild: %v", err)
} }
// Verify guild was deleted // Verify it's gone
_, err = dgm.LoadGuild(ctx, 1) _, err = dgm.LoadGuild(ctx, guildID)
if err == nil { if err == nil {
t.Error("Guild should not exist after deletion") t.Error("Expected error loading deleted guild, got nil")
} }
// Verify members were deleted
members, err := dgm.LoadGuildMembers(ctx, 1)
if err != nil {
t.Fatalf("Failed to check members after guild deletion: %v", err)
}
if len(members) != 0 {
t.Errorf("Expected 0 members after guild deletion, got %d", len(members))
}
}
// TestDatabaseGuildManager_GetGuildIDByCharacterID tests getting guild ID by character ID
func TestDatabaseGuildManager_GetGuildIDByCharacterID(t *testing.T) {
db := createTestDB(t)
defer db.Close()
dgm := NewDatabaseGuildManager(db)
ctx := context.Background()
// Insert test guild
err := db.Exec(`INSERT INTO guilds (id, name) VALUES (1, 'Test Guild')`)
if err != nil {
t.Fatalf("Failed to insert test guild: %v", err)
}
// Insert test member
err = db.Exec(`INSERT INTO guild_members (char_id, guild_id, account_id, name) VALUES (123, 1, 100, 'TestPlayer')`)
if err != nil {
t.Fatalf("Failed to insert test member: %v", err)
}
// Test getting guild ID for character
guildID, err := dgm.GetGuildIDByCharacterID(ctx, 123)
if err != nil {
t.Fatalf("Failed to get guild ID by character ID: %v", err)
}
if guildID != 1 {
t.Errorf("Expected guild ID 1, got %d", guildID)
}
// Test getting guild ID for non-existent character
_, err = dgm.GetGuildIDByCharacterID(ctx, 999)
if err == nil {
t.Error("Expected error for non-existent character")
}
}
// TestDatabaseGuildManager_ConcurrentOperations tests concurrent database operations
// Now enabled with sqlitex.Pool for proper connection management
func TestDatabaseGuildManager_ConcurrentOperations(t *testing.T) {
db := createTestDB(t)
defer db.Close()
dgm := NewDatabaseGuildManager(db)
ctx := context.Background()
// Insert initial guild
err := db.Exec(`INSERT INTO guilds (id, name) VALUES (1, 'Concurrent Test')`)
if err != nil {
t.Fatalf("Failed to insert test guild: %v", err)
}
const numGoroutines = 5 // Reduce concurrency to avoid SQLite issues
done := make(chan error, numGoroutines)
// Test concurrent reads
for i := 0; i < numGoroutines; i++ {
go func(id int) {
// Add small delay to reduce contention
time.Sleep(time.Duration(id) * time.Millisecond)
_, err := dgm.LoadGuild(ctx, 1)
done <- err
}(i)
}
// Wait for all reads to complete
for i := 0; i < numGoroutines; i++ {
if err := <-done; err != nil {
t.Errorf("Concurrent read failed: %v", err)
}
}
// Test concurrent member additions
for i := 0; i < numGoroutines; i++ {
go func(id int) {
memberSQL := `INSERT INTO guild_members (char_id, guild_id, account_id, name) VALUES (?, 1, 100, ?)`
err := db.Exec(memberSQL, 100+id, fmt.Sprintf("Player%d", id))
done <- err
}(i)
}
// Wait for all insertions
successCount := 0
for i := 0; i < numGoroutines; i++ {
if err := <-done; err == nil {
successCount++
}
}
if successCount != numGoroutines {
t.Logf("Only %d out of %d concurrent insertions succeeded (some conflicts expected)", successCount, numGoroutines)
}
}
// TestDatabaseGuildManager_TransactionRollback tests transaction rollback on errors
func TestDatabaseGuildManager_TransactionRollback(t *testing.T) {
db := createTestDB(t)
defer db.Close()
dgm := NewDatabaseGuildManager(db)
ctx := context.Background()
// Try to create a guild with invalid data that should trigger a rollback
invalidGuildData := GuildData{
Name: "", // Empty name should cause validation error
Level: 1,
FormedDate: time.Now(),
}
// This should fail but we test that it handles errors gracefully
_, err := dgm.CreateGuild(ctx, invalidGuildData)
// We don't expect specific error behavior here since the implementation
// may or may not have validation, but we test that it doesn't crash
t.Logf("Create guild with invalid data returned: %v", err)
// Verify no partial data was left behind
guilds, err := dgm.LoadGuilds(ctx)
if err != nil {
t.Fatalf("Failed to load guilds after rollback test: %v", err)
}
// Should have no guilds (or any existing test data, but no new invalid guild)
t.Logf("Found %d guilds after invalid creation attempt", len(guilds))
} }
// BenchmarkDatabaseGuildManager_LoadGuilds benchmarks loading guilds // BenchmarkDatabaseGuildManager_LoadGuilds benchmarks loading guilds
func BenchmarkDatabaseGuildManager_LoadGuilds(b *testing.B) { func BenchmarkDatabaseGuildManager_LoadGuilds(b *testing.B) {
// Create test database in temp directory pool := createTestPool(&testing.T{})
tempDir := b.TempDir() defer pool.Close()
dbPath := filepath.Join(tempDir, "bench_guilds.db")
db, err := database.Open(dbPath)
if err != nil {
b.Fatalf("Failed to create benchmark database: %v", err)
}
defer db.Close()
if err := createGuildTables(db); err != nil { dgm := NewDatabaseGuildManager(pool)
b.Fatalf("Failed to create guild tables: %v", err)
}
dgm := NewDatabaseGuildManager(db)
ctx := context.Background() ctx := context.Background()
// Insert test guilds // Insert test data
for i := 0; i < 100; i++ { for i := 1; i <= 100; i++ {
insertSQL := `INSERT INTO guilds (id, name, level, xp, xp_needed, formed_on) VALUES (?, ?, 1, 111, 2521, ?)` execSQL(&testing.T{}, pool,
formedTime := time.Now().Unix() `INSERT INTO guilds (id, name, motd, level, xp, xp_needed, formed_on)
if err := db.Exec(insertSQL, i+1, fmt.Sprintf("Guild%d", i+1), formedTime); err != nil { VALUES (?, ?, ?, ?, ?, ?, ?)`,
b.Fatalf("Failed to insert test guild %d: %v", i+1, err) i, fmt.Sprintf("Guild %d", i), "Welcome!", i%10+1, i*100, i*1000, time.Now().Unix())
}
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := dgm.LoadGuilds(ctx) guilds, err := dgm.LoadGuilds(ctx)
if err != nil { if err != nil {
b.Fatalf("Failed to load guilds in benchmark: %v", err) b.Fatalf("Failed to load guilds: %v", err)
}
if len(guilds) != 100 {
b.Errorf("Expected 100 guilds, got %d", len(guilds))
} }
} }
} }
// BenchmarkDatabaseGuildManager_LoadGuildMembers benchmarks loading guild members // BenchmarkDatabaseGuildManager_SaveGuild benchmarks saving guild data
func BenchmarkDatabaseGuildManager_LoadGuildMembers(b *testing.B) { func BenchmarkDatabaseGuildManager_SaveGuild(b *testing.B) {
// Create test database in temp directory pool := createTestPool(&testing.T{})
tempDir := b.TempDir() defer pool.Close()
dbPath := filepath.Join(tempDir, "bench_members.db")
db, err := database.Open(dbPath)
if err != nil {
b.Fatalf("Failed to create benchmark database: %v", err)
}
defer db.Close()
if err := createGuildTables(db); err != nil { dgm := NewDatabaseGuildManager(pool)
b.Fatalf("Failed to create guild tables: %v", err)
}
dgm := NewDatabaseGuildManager(db)
ctx := context.Background() ctx := context.Background()
// Insert test guild // Create a test guild
if err := db.Exec(`INSERT INTO guilds (id, name) VALUES (1, 'Benchmark Guild')`); err != nil { guild := &Guild{
b.Fatalf("Failed to insert benchmark guild: %v", err) id: 1,
} name: "Benchmark Guild",
motd: "Benchmark MOTD",
// Insert test members level: 50,
joinTime := time.Now().Unix() expCurrent: 50000,
for i := 0; i < 100; i++ { expToNextLevel: 100000,
memberSQL := `INSERT INTO guild_members (char_id, guild_id, account_id, name, rank, join_date, last_login_date) formedDate: time.Now(),
VALUES (?, 1, 100, ?, ?, ?, ?)`
if err := db.Exec(memberSQL, i+1, fmt.Sprintf("Player%d", i+1), RankMember, joinTime, joinTime); err != nil {
b.Fatalf("Failed to insert test member %d: %v", i+1, err)
}
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := dgm.LoadGuildMembers(ctx, 1) err := dgm.SaveGuild(ctx, guild)
if err != nil { if err != nil {
b.Fatalf("Failed to load guild members in benchmark: %v", err) b.Fatalf("Failed to save guild: %v", err)
} }
} }
} }