package testutils import ( "bytes" "encoding/json" "fmt" "io" "net/http" "net/http/cookiejar" "sync" "testing" "time" ) var ( globalTestServer *TestServer serverOnce sync.Once ) func getOrCreateServer() *TestServer { serverOnce.Do(func() { globalTestServer = NewTestServer() }) return globalTestServer } type TestConfig struct { BaseURL string Client *http.Client server *TestServer } func NewTestConfig() *TestConfig { ts := getOrCreateServer() jar, _ := cookiejar.New(nil) client := &http.Client{ Jar: jar, Timeout: 30 * time.Second, } return &TestConfig{ BaseURL: ts.Server.URL + "/api/v1", Client: client, server: ts, } } type TestUser struct { Email string Password string FirstName string LastName string Token string UserID uint } func (c *TestConfig) Request(method, path string, body interface{}, token string) (*http.Response, error) { var reqBody io.Reader if body != nil { jsonBody, err := json.Marshal(body) if err != nil { return nil, err } reqBody = bytes.NewBuffer(jsonBody) } req, err := http.NewRequest(method, c.BaseURL+path, reqBody) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/json") if token != "" { req.Header.Set("Authorization", "Bearer "+token) } return c.Client.Do(req) } func (c *TestConfig) ParseResponse(resp *http.Response, target interface{}) error { defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return err } return json.Unmarshal(body, target) } func (c *TestConfig) CreateTestUser(t *testing.T) *TestUser { user := &TestUser{ Email: fmt.Sprintf("test_%d@example.com", time.Now().UnixNano()), Password: "test123456", FirstName: "Test", LastName: "User", } resp, err := c.Request("POST", "/auth/register", map[string]interface{}{ "email": user.Email, "password": user.Password, "first_name": user.FirstName, "last_name": user.LastName, }, "") if err != nil { t.Fatalf("Failed to create test user: %v", err) } defer resp.Body.Close() var result map[string]interface{} if err := c.ParseResponse(resp, &result); err != nil { t.Fatalf("Failed to parse response: %v", err) } if token, ok := result["token"].(string); ok { user.Token = token } if userData, ok := result["user"].(map[string]interface{}); ok { if id, ok := userData["id"].(float64); ok { user.UserID = uint(id) } } return user } func (c *TestConfig) CleanupTestUser(t *testing.T, user *TestUser) { if user.Token != "" { _, err := c.Request("DELETE", "/me", nil, user.Token) if err != nil { t.Logf("Warning: Failed to cleanup test user: %v", err) } } } func (c *TestConfig) GetAuthToken(email, password string) (string, error) { resp, err := c.Request("POST", "/auth/login", map[string]interface{}{ "email": email, "password": password, }, "") if err != nil { return "", err } defer resp.Body.Close() var result map[string]interface{} if err := c.ParseResponse(resp, &result); err != nil { return "", err } if token, ok := result["token"].(string); ok { return token, nil } return "", fmt.Errorf("token not found in response") }