//go:build e2e // +build e2e package e2e import ( "bytes" "encoding/json" "io" "net/http" "net/http/httptest" "os" "testing" "github.com/rede5/gohorsejobs/backend/internal/database" "github.com/rede5/gohorsejobs/backend/internal/router" ) var testServer *httptest.Server // TestMain sets up the test environment for all E2E tests func TestMain(m *testing.M) { // Set environment variables for testing setTestEnv() // Initialize database connection database.InitDB() // Create test server testServer = httptest.NewServer(router.NewRouter()) defer testServer.Close() // Run tests code := m.Run() // Cleanup cleanupTestData() os.Exit(code) } // setTestEnv sets up environment variables for testing // Uses the same database as development (loaded from .env in CI/CD or manually set) func setTestEnv() { // Only set if not already set (allows override via .env file) // These are defaults for when running tests without sourcing .env if os.Getenv("DB_HOST") == "" { os.Setenv("DB_HOST", "db-60059.dc-sp-1.absamcloud.com") } if os.Getenv("DB_USER") == "" { os.Setenv("DB_USER", "yuki") } if os.Getenv("DB_PASSWORD") == "" { os.Setenv("DB_PASSWORD", "xl1zfmr6e9bb") } if os.Getenv("DB_NAME") == "" { os.Setenv("DB_NAME", "gohorsejobs_dev") } if os.Getenv("DB_PORT") == "" { os.Setenv("DB_PORT", "26868") } if os.Getenv("DB_SSLMODE") == "" { os.Setenv("DB_SSLMODE", "require") } if os.Getenv("JWT_SECRET") == "" { os.Setenv("JWT_SECRET", "gohorse-super-secret-key-2024-production") } } // cleanupTestData removes test data from the database func cleanupTestData() { if database.DB != nil { // Clean up in reverse order of dependencies database.DB.Exec("DELETE FROM applications WHERE id > 0") database.DB.Exec("DELETE FROM jobs WHERE title LIKE 'E2E Test%'") database.DB.Exec("DELETE FROM companies WHERE name LIKE 'E2E Test%'") } } // httpClient helper for making requests to test server type testClient struct { baseURL string token string } func newTestClient() *testClient { return &testClient{ baseURL: testServer.URL, } } func (c *testClient) setAuthToken(token string) { c.token = token } func (c *testClient) doRequest(method, path string, body interface{}) (*http.Response, error) { var reqBody io.Reader if body != nil { jsonData, err := json.Marshal(body) if err != nil { return nil, err } reqBody = bytes.NewReader(jsonData) } req, err := http.NewRequest(method, c.baseURL+path, reqBody) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/json") if c.token != "" { req.Header.Set("Authorization", "Bearer "+c.token) } return http.DefaultClient.Do(req) } func (c *testClient) get(path string) (*http.Response, error) { return c.doRequest("GET", path, nil) } func (c *testClient) post(path string, body interface{}) (*http.Response, error) { return c.doRequest("POST", path, body) } func (c *testClient) put(path string, body interface{}) (*http.Response, error) { return c.doRequest("PUT", path, body) } func (c *testClient) delete(path string) (*http.Response, error) { return c.doRequest("DELETE", path, nil) } // parseJSON helper to decode JSON response func parseJSON(resp *http.Response, target interface{}) error { defer resp.Body.Close() return json.NewDecoder(resp.Body).Decode(target) } // TestHealthCheck verifies the server is running func TestHealthCheck(t *testing.T) { client := newTestClient() resp, err := client.get("/health") if err != nil { t.Fatalf("Failed to make request: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Errorf("Expected status 200, got %d", resp.StatusCode) } } // TestRootEndpoint verifies the API info endpoint func TestRootEndpoint(t *testing.T) { client := newTestClient() resp, err := client.get("/") if err != nil { t.Fatalf("Failed to make request: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Errorf("Expected status 200, got %d", resp.StatusCode) } var result map[string]interface{} if err := parseJSON(resp, &result); err != nil { t.Fatalf("Failed to parse JSON: %v", err) } if result["message"] != "🐴 GoHorseJobs API is running!" { t.Errorf("Unexpected message: %v", result["message"]) } }