package ui import ( "net/http" "net/http/httptest" "os" "path/filepath" "strings" "testing" "git.pengzhan.dev/haopengzhan/hireme/internal/config" "git.pengzhan.dev/haopengzhan/hireme/internal/db" ) func TestHandleDeleteTarget(t *testing.T) { tempDir := t.TempDir() dbPath := filepath.Join(tempDir, "test_ui_delete_target.db") yamlPath := filepath.Join(tempDir, "targets.yaml") initialYAML := `targets: - name: "Test Target" target_url: "https://example.com/test-jobs" platform: "google_jobs" is_active: true ` if err := osWriteFile(yamlPath, []byte(initialYAML)); err != nil { t.Fatalf("failed to write yaml: %v", err) } database, err := db.InitDB(dbPath) if err != nil { t.Fatalf("failed to init db: %v", err) } defer func() { _ = database.Close() }() target, err := database.CreateTarget("Test Target", "https://example.com/test-jobs", "google_jobs", true) if err != nil { t.Fatalf("failed to create target: %v", err) } _, _, err = database.InsertRawJob("canon-ui-test", &target.ID, "Software Engineer", "Google", "Seattle", "https://example.com/job/1", "Go backend") if err != nil { t.Fatalf("failed to insert raw job: %v", err) } cfg := &config.Config{ TargetConfig: yamlPath, } server := NewServer(cfg, database, nil) mux := http.NewServeMux() server.RegisterRoutes(mux) // Send POST /targets/{id}/delete req := httptest.NewRequest("POST", "/targets/1/delete", nil) w := httptest.NewRecorder() mux.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String()) } // Verify target table in response does not contain the deleted target body := w.Body.String() if strings.Contains(body, "Test Target") { t.Errorf("expected target list in response to not contain 'Test Target', got:\n%s", body) } // Verify DB is empty of targets and jobs targets, err := database.GetAllTargets() if err != nil || len(targets) != 0 { t.Errorf("expected 0 targets in DB, got %v (err: %v)", targets, err) } jobs, err := database.GetJobsWithAnalysis() if err != nil || len(jobs) != 0 { t.Errorf("expected 0 jobs in DB, got %v (err: %v)", jobs, err) } } func osWriteFile(path string, data []byte) error { return os.WriteFile(path, data, 0644) } func TestMaintenanceHandlers(t *testing.T) { tempDir := t.TempDir() dbPath := filepath.Join(tempDir, "test_ui_maintenance.db") database, err := db.InitDB(dbPath) if err != nil { t.Fatalf("failed to init db: %v", err) } defer func() { _ = database.Close() }() // Insert job job, _, err := database.InsertRawJob("canon-m-1", nil, "Software Engineer", "Google", "Seattle", "https://example.com/job/1", "Go backend") if err != nil { t.Fatalf("failed to insert raw job: %v", err) } // Make stale (25 days old) _, _ = database.Exec(`UPDATE raw_jobs SET last_seen_at = datetime('now', '-25 days') WHERE id = ?`, job.ID) cfg := &config.Config{} server := NewServer(cfg, database, nil) mux := http.NewServeMux() server.RegisterRoutes(mux) // 1. Test POST /api/maintenance/stale-expire req := httptest.NewRequest("POST", "/api/maintenance/stale-expire", strings.NewReader("days=14&protect=true")) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") w := httptest.NewRecorder() mux.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Fatalf("expected status 200, got %d: %s", w.Code, w.Body.String()) } if !strings.Contains(w.Body.String(), `"status":"success"`) || !strings.Contains(w.Body.String(), `"count":1`) { t.Errorf("unexpected body: %s", w.Body.String()) } // 2. Test GET /api/maintenance/stats reqStats := httptest.NewRequest("GET", "/api/maintenance/stats", nil) wStats := httptest.NewRecorder() mux.ServeHTTP(wStats, reqStats) if wStats.Code != http.StatusOK { t.Fatalf("expected status 200, got %d: %s", wStats.Code, wStats.Body.String()) } if !strings.Contains(wStats.Body.String(), `"total_jobs":1`) { t.Errorf("expected stats to show total_jobs:1, got %s", wStats.Body.String()) } }