package database import ( "context" "os" "testing" "time" "git.dws.rip/DWS/dyn/internal/models" ) func setupTestDB(t *testing.T) (*DB, func()) { tmpFile := "/tmp/test_dyn_" + time.Now().Format("20060102150405") + ".db" db, err := New(tmpFile) if err != nil { t.Fatalf("Failed to create test database: %v", err) } cleanup := func() { db.Close() os.Remove(tmpFile) } return db, cleanup } func TestCreateSpace(t *testing.T) { db, cleanup := setupTestDB(t) defer cleanup() ctx := context.Background() tests := []struct { name string subdomain string wantErr bool }{ { name: "create valid space", subdomain: "myhome", wantErr: false, }, { name: "create another valid space", subdomain: "office", wantErr: false, }, { name: "duplicate subdomain", subdomain: "myhome", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { space, err := db.CreateSpace(ctx, tt.subdomain) if tt.wantErr { if err == nil { t.Errorf("CreateSpace() expected error but got none") } return } if err != nil { t.Errorf("CreateSpace() unexpected error: %v", err) return } if space == nil { t.Errorf("CreateSpace() returned nil space") return } if space.Subdomain != tt.subdomain { t.Errorf("CreateSpace() subdomain = %v, want %v", space.Subdomain, tt.subdomain) } if space.Token == "" { t.Errorf("CreateSpace() token is empty") } }) } } func TestGetSpaceByToken(t *testing.T) { db, cleanup := setupTestDB(t) defer cleanup() ctx := context.Background() // Create a test space created, err := db.CreateSpace(ctx, "testspace") if err != nil { t.Fatalf("Failed to create test space: %v", err) } tests := []struct { name string token string wantNil bool }{ { name: "existing space", token: created.Token, wantNil: false, }, { name: "non-existent token", token: "invalid-token-12345", wantNil: true, }, { name: "empty token", token: "", wantNil: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { space, err := db.GetSpaceByToken(ctx, tt.token) if err != nil { t.Errorf("GetSpaceByToken() unexpected error: %v", err) return } if tt.wantNil && space != nil { t.Errorf("GetSpaceByToken() expected nil, got %v", space) } if !tt.wantNil && space == nil { t.Errorf("GetSpaceByToken() expected space, got nil") } }) } } func TestGetSpaceBySubdomain(t *testing.T) { db, cleanup := setupTestDB(t) defer cleanup() ctx := context.Background() // Create a test space created, err := db.CreateSpace(ctx, "mytestspace") if err != nil { t.Fatalf("Failed to create test space: %v", err) } tests := []struct { name string subdomain string wantNil bool }{ { name: "existing subdomain", subdomain: "mytestspace", wantNil: false, }, { name: "non-existent subdomain", subdomain: "nonexistent", wantNil: true, }, { name: "case sensitivity test", subdomain: "MyTestSpace", wantNil: true, // SQLite is case-sensitive by default }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { space, err := db.GetSpaceBySubdomain(ctx, tt.subdomain) if err != nil { t.Errorf("GetSpaceBySubdomain() unexpected error: %v", err) return } if tt.wantNil && space != nil { t.Errorf("GetSpaceBySubdomain() expected nil, got %v", space) } if !tt.wantNil && space == nil { t.Errorf("GetSpaceBySubdomain() expected space, got nil") } if !tt.wantNil && space.Token != created.Token { t.Errorf("GetSpaceBySubdomain() token mismatch") } }) } } func TestUpdateSpaceIP(t *testing.T) { db, cleanup := setupTestDB(t) defer cleanup() ctx := context.Background() // Create a test space created, err := db.CreateSpace(ctx, "updatespace") if err != nil { t.Fatalf("Failed to create test space: %v", err) } tests := []struct { name string token string ip string wantErr bool }{ { name: "update valid space", token: created.Token, ip: "192.168.1.100", wantErr: false, }, { name: "update with different IP", token: created.Token, ip: "10.0.0.50", wantErr: false, }, { name: "update non-existent space", token: "invalid-token", ip: "192.168.1.1", wantErr: false, // SQL UPDATE with no match doesn't error }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := db.UpdateSpaceIP(ctx, tt.token, tt.ip) if tt.wantErr && err == nil { t.Errorf("UpdateSpaceIP() expected error but got none") } if !tt.wantErr && err != nil { t.Errorf("UpdateSpaceIP() unexpected error: %v", err) } // Verify the update for valid token if !tt.wantErr && tt.token == created.Token { space, err := db.GetSpaceByToken(ctx, tt.token) if err != nil { t.Errorf("Failed to get space after update: %v", err) return } if space.LastIP != tt.ip { t.Errorf("UpdateSpaceIP() IP = %v, want %v", space.LastIP, tt.ip) } } }) } } func TestSubdomainExists(t *testing.T) { db, cleanup := setupTestDB(t) defer cleanup() ctx := context.Background() // Create a test space _, err := db.CreateSpace(ctx, "existingspace") if err != nil { t.Fatalf("Failed to create test space: %v", err) } tests := []struct { name string subdomain string want bool }{ { name: "existing subdomain", subdomain: "existingspace", want: true, }, { name: "non-existent subdomain", subdomain: "newspace", want: false, }, { name: "empty subdomain", subdomain: "", want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { exists, err := db.SubdomainExists(ctx, tt.subdomain) if err != nil { t.Errorf("SubdomainExists() unexpected error: %v", err) return } if exists != tt.want { t.Errorf("SubdomainExists() = %v, want %v", exists, tt.want) } }) } } func TestTokenGeneration(t *testing.T) { tokens := make(map[string]bool) // Generate 100 tokens and ensure they're all unique for i := 0; i < 100; i++ { token, err := generateToken() if err != nil { t.Fatalf("generateToken() error: %v", err) } if token == "" { t.Errorf("generateToken() returned empty string") } if len(token) < 16 { t.Errorf("generateToken() returned short token: %d chars", len(token)) } if tokens[token] { t.Errorf("generateToken() returned duplicate token: %s", token) } tokens[token] = true } } func TestSpaceModel(t *testing.T) { space := &models.Space{ Token: "test-token", Subdomain: "myspace", LastIP: "192.168.1.1", } fqdn := space.GetFQDN("space.dws.rip") if fqdn != "myspace.space.dws.rip" { t.Errorf("GetFQDN() = %v, want %v", fqdn, "myspace.space.dws.rip") } }