package testing import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" ) // TestRequest represents a test HTTP request type TestRequest struct { Method string Path string Body interface{} Headers map[string]string } // TestResponse represents a test HTTP response type TestResponse struct { StatusCode int Body map[string]interface{} Headers http.Header } // MakeRequest creates and executes an HTTP request for testing func MakeRequest(t *testing.T, handler http.Handler, req TestRequest) *httptest.ResponseRecorder { var bodyBytes []byte if req.Body != nil { var err error bodyBytes, err = json.Marshal(req.Body) if err != nil { t.Fatalf("marshal request body: %v", err) } } httpReq, err := http.NewRequest(req.Method, req.Path, bytes.NewReader(bodyBytes)) if err != nil { t.Fatalf("create request: %v", err) } // Set headers if req.Headers != nil { for k, v := range req.Headers { httpReq.Header.Set(k, v) } } // Set Content-Type if body is present if bodyBytes != nil && httpReq.Header.Get("Content-Type") == "" { httpReq.Header.Set("Content-Type", "application/json") } recorder := httptest.NewRecorder() handler.ServeHTTP(recorder, httpReq) return recorder } // AssertStatusCode asserts the response status code func AssertStatusCode(t *testing.T, recorder *httptest.ResponseRecorder, expected int) { if recorder.Code != expected { t.Errorf("expected status %d, got %d", expected, recorder.Code) } } // AssertJSONResponse asserts the response is valid JSON and matches expected structure func AssertJSONResponse(t *testing.T, recorder *httptest.ResponseRecorder) map[string]interface{} { var response map[string]interface{} if err := json.Unmarshal(recorder.Body.Bytes(), &response); err != nil { t.Fatalf("unmarshal JSON response: %v\nBody: %s", err, recorder.Body.String()) } return response } // AssertHeader asserts a header value func AssertHeader(t *testing.T, recorder *httptest.ResponseRecorder, key, expected string) { actual := recorder.Header().Get(key) if actual != expected { t.Errorf("expected header %s=%s, got %s", key, expected, actual) } } // AssertErrorResponse asserts the response is an error response func AssertErrorResponse(t *testing.T, recorder *httptest.ResponseRecorder, expectedCode string) { response := AssertJSONResponse(t, recorder) if code, ok := response["code"].(string); !ok || code != expectedCode { t.Errorf("expected error code %s, got %v", expectedCode, response["code"]) } } // AssertSuccessResponse asserts the response is a success response func AssertSuccessResponse(t *testing.T, recorder *httptest.ResponseRecorder) map[string]interface{} { AssertStatusCode(t, recorder, http.StatusOK) return AssertJSONResponse(t, recorder) } // CreateTestUser creates a test user for authentication tests func CreateTestUser() map[string]interface{} { return map[string]interface{}{ "username": "testuser", "password": "TestPass123", "email": "test@example.com", "role": "viewer", } } // CreateTestToken creates a mock JWT token for testing func CreateTestToken(userID, role string) string { // In a real test, you'd use the actual auth service // This is a placeholder for test token generation return "test-token-" + userID } // MockZFSClient provides a mock ZFS client for testing type MockZFSClient struct { Pools []map[string]interface{} Datasets []map[string]interface{} ZVOLs []map[string]interface{} Snapshots []map[string]interface{} Error error } // NewMockZFSClient creates a new mock ZFS client func NewMockZFSClient() *MockZFSClient { return &MockZFSClient{ Pools: []map[string]interface{}{}, Datasets: []map[string]interface{}{}, ZVOLs: []map[string]interface{}{}, Snapshots: []map[string]interface{}{}, } } // SetError sets an error to return func (m *MockZFSClient) SetError(err error) { m.Error = err } // AddPool adds a mock pool func (m *MockZFSClient) AddPool(pool map[string]interface{}) { m.Pools = append(m.Pools, pool) } // AddDataset adds a mock dataset func (m *MockZFSClient) AddDataset(dataset map[string]interface{}) { m.Datasets = append(m.Datasets, dataset) } // Reset clears all mock data func (m *MockZFSClient) Reset() { m.Pools = []map[string]interface{}{} m.Datasets = []map[string]interface{}{} m.ZVOLs = []map[string]interface{}{} m.Snapshots = []map[string]interface{}{} m.Error = nil }