// Admin service tests - automated verification of all endpoints package main import ( "bytes" "crypto/hmac" "crypto/sha256" "database/sql" "encoding/hex" "fmt" "io" "net/http" "net/http/httptest" "net/url" "strconv" "strings" "testing" "time" "github.com/go-chi/chi/v5" _ "github.com/mattn/go-sqlite3" ) // TestSuite holds test state type TestSuite struct { Router *chi.Mux DB *sql.DB } // setup creates a test environment with fresh database func setup() *TestSuite { // Create in-memory database for tests testDB, err := sql.Open("sqlite3", ":memory:") if err != nil { panic(err) } // Initialize schema initDBWithConn(testDB) // Set global db for handlers db = testDB // Create router r := chi.NewRouter() // Mount all routes r.Get("/", handleDynamicHome) r.Get("/table/{table}", handleDynamicList) r.Get("/table/{table}/new", handleDynamicForm) r.Post("/table/{table}", handleDynamicCreate) r.Get("/table/{table}/{id}", handleDynamicView) r.Get("/table/{table}/{id}/edit", handleDynamicEdit) r.Post("/table/{table}/{id}", handleDynamicUpdate) // API routes r.Post("/api/checkout", HandleCheckout) r.Post("/webhooks/paddle", HandlePaddleWebhook) return &TestSuite{Router: r, DB: testDB} } func (s *TestSuite) teardown() { s.DB.Close() } // Helper to make requests func (s *TestSuite) request(method, path string, body io.Reader) *httptest.ResponseRecorder { req := httptest.NewRequest(method, path, body) if method == "POST" { req.Header.Set("Content-Type", "application/x-www-form-urlencoded") } rr := httptest.NewRecorder() s.Router.ServeHTTP(rr, req) return rr } // Test 1: Home page loads and shows all tables func TestHomePage(t *testing.T) { s := setup() defer s.teardown() rr := s.request("GET", "/", nil) if rr.Code != http.StatusOK { t.Errorf("Expected status 200, got %d", rr.Code) } body := rr.Body.String() // Check that all expected tables are listed expectedTables := []string{"products", "customers", "subscriptions", "vaults", "events"} for _, table := range expectedTables { if !strings.Contains(body, table) { t.Errorf("Home page missing table: %s", table) } } // Check products are pre-populated if !strings.Contains(body, "pro_personal") { t.Log("Note: products may not be pre-populated in test DB") } } // Test 2: All tables have list pages func TestTableListPages(t *testing.T) { s := setup() defer s.teardown() tables := []string{ "products", "prices", "discounts", "customers", "addresses", "businesses", "subscriptions", "subscription_items", "transactions", "adjustments", "vaults", "credentials", "roles", "humans", "role_assignments", "pop_sync_state", "events", "wl3_storage", } for _, table := range tables { rr := s.request("GET", "/table/"+table, nil) if rr.Code != http.StatusOK { t.Errorf("Table %s list page failed: status %d", table, rr.Code) continue } body := rr.Body.String() // Check table header exists if !strings.Contains(body, "