package connections import ( "path/filepath" "testing" "github.com/vstockwell/wraith/internal/db" ) func strPtr(s string) *string { return &s } func setupTestService(t *testing.T) *ConnectionService { t.Helper() dir := t.TempDir() database, err := db.Open(filepath.Join(dir, "test.db")) if err != nil { t.Fatalf("db.Open() error: %v", err) } if err := db.Migrate(database); err != nil { t.Fatalf("db.Migrate() error: %v", err) } t.Cleanup(func() { database.Close() }) return NewConnectionService(database) } func TestCreateGroup(t *testing.T) { svc := setupTestService(t) g, err := svc.CreateGroup("Servers", nil) if err != nil { t.Fatalf("CreateGroup() error: %v", err) } if g.ID == 0 { t.Error("expected non-zero ID") } if g.Name != "Servers" { t.Errorf("Name = %q, want %q", g.Name, "Servers") } if g.ParentID != nil { t.Errorf("ParentID = %v, want nil", g.ParentID) } } func TestCreateSubGroup(t *testing.T) { svc := setupTestService(t) parent, err := svc.CreateGroup("Servers", nil) if err != nil { t.Fatalf("CreateGroup(parent) error: %v", err) } child, err := svc.CreateGroup("Production", &parent.ID) if err != nil { t.Fatalf("CreateGroup(child) error: %v", err) } if child.ParentID == nil { t.Fatal("expected non-nil ParentID") } if *child.ParentID != parent.ID { t.Errorf("ParentID = %d, want %d", *child.ParentID, parent.ID) } } func TestListGroups(t *testing.T) { svc := setupTestService(t) parent, err := svc.CreateGroup("Servers", nil) if err != nil { t.Fatalf("CreateGroup(parent) error: %v", err) } if _, err := svc.CreateGroup("Production", &parent.ID); err != nil { t.Fatalf("CreateGroup(child) error: %v", err) } groups, err := svc.ListGroups() if err != nil { t.Fatalf("ListGroups() error: %v", err) } if len(groups) != 1 { t.Fatalf("len(groups) = %d, want 1 (only root groups)", len(groups)) } if groups[0].Name != "Servers" { t.Errorf("groups[0].Name = %q, want %q", groups[0].Name, "Servers") } if len(groups[0].Children) != 1 { t.Fatalf("len(children) = %d, want 1", len(groups[0].Children)) } if groups[0].Children[0].Name != "Production" { t.Errorf("child name = %q, want %q", groups[0].Children[0].Name, "Production") } } func TestDeleteGroup(t *testing.T) { svc := setupTestService(t) g, err := svc.CreateGroup("ToDelete", nil) if err != nil { t.Fatalf("CreateGroup() error: %v", err) } if err := svc.DeleteGroup(g.ID); err != nil { t.Fatalf("DeleteGroup() error: %v", err) } groups, err := svc.ListGroups() if err != nil { t.Fatalf("ListGroups() error: %v", err) } if len(groups) != 0 { t.Errorf("len(groups) = %d, want 0 after delete", len(groups)) } } func TestCreateConnection(t *testing.T) { svc := setupTestService(t) conn, err := svc.CreateConnection(CreateConnectionInput{ Name: "Web Server", Hostname: "10.0.0.1", Port: 22, Protocol: "ssh", Tags: []string{"Prod", "Linux"}, Options: `{"keepAliveInterval": 60}`, }) if err != nil { t.Fatalf("CreateConnection() error: %v", err) } if conn.ID == 0 { t.Error("expected non-zero ID") } if conn.Name != "Web Server" { t.Errorf("Name = %q, want %q", conn.Name, "Web Server") } if len(conn.Tags) != 2 { t.Fatalf("len(Tags) = %d, want 2", len(conn.Tags)) } if conn.Tags[0] != "Prod" || conn.Tags[1] != "Linux" { t.Errorf("Tags = %v, want [Prod Linux]", conn.Tags) } if conn.Options != `{"keepAliveInterval": 60}` { t.Errorf("Options = %q, want JSON blob", conn.Options) } } func TestListConnections(t *testing.T) { svc := setupTestService(t) if _, err := svc.CreateConnection(CreateConnectionInput{ Name: "Server A", Hostname: "10.0.0.1", Port: 22, Protocol: "ssh", }); err != nil { t.Fatalf("CreateConnection(A) error: %v", err) } if _, err := svc.CreateConnection(CreateConnectionInput{ Name: "Server B", Hostname: "10.0.0.2", Port: 3389, Protocol: "rdp", }); err != nil { t.Fatalf("CreateConnection(B) error: %v", err) } conns, err := svc.ListConnections() if err != nil { t.Fatalf("ListConnections() error: %v", err) } if len(conns) != 2 { t.Fatalf("len(conns) = %d, want 2", len(conns)) } } func TestUpdateConnection(t *testing.T) { svc := setupTestService(t) conn, err := svc.CreateConnection(CreateConnectionInput{ Name: "Old Name", Hostname: "10.0.0.1", Port: 22, Protocol: "ssh", Tags: []string{"Dev"}, }) if err != nil { t.Fatalf("CreateConnection() error: %v", err) } updated, err := svc.UpdateConnection(conn.ID, UpdateConnectionInput{ Name: strPtr("New Name"), Tags: []string{"Prod", "Linux"}, }) if err != nil { t.Fatalf("UpdateConnection() error: %v", err) } if updated.Name != "New Name" { t.Errorf("Name = %q, want %q", updated.Name, "New Name") } if len(updated.Tags) != 2 { t.Fatalf("len(Tags) = %d, want 2", len(updated.Tags)) } if updated.Tags[0] != "Prod" { t.Errorf("Tags[0] = %q, want %q", updated.Tags[0], "Prod") } // Hostname should remain unchanged if updated.Hostname != "10.0.0.1" { t.Errorf("Hostname = %q, want %q (unchanged)", updated.Hostname, "10.0.0.1") } } func TestDeleteConnection(t *testing.T) { svc := setupTestService(t) conn, err := svc.CreateConnection(CreateConnectionInput{ Name: "ToDelete", Hostname: "10.0.0.1", Port: 22, Protocol: "ssh", }) if err != nil { t.Fatalf("CreateConnection() error: %v", err) } if err := svc.DeleteConnection(conn.ID); err != nil { t.Fatalf("DeleteConnection() error: %v", err) } conns, err := svc.ListConnections() if err != nil { t.Fatalf("ListConnections() error: %v", err) } if len(conns) != 0 { t.Errorf("len(conns) = %d, want 0 after delete", len(conns)) } }