package ucxi import ( "bytes" "encoding/json" "fmt" "net/http" "net/http/httptest" "strings" "testing" "chorus.services/bzzz/pkg/ucxl" ) // Helper function to create test server for UCXL testing func createUCXLTestServer() *Server { config := ServerConfig{ Port: 8080, BasePath: "/test", Resolver: NewMockResolver(), // Use existing MockResolver from server_test.go Storage: NewMockStorage(), // Use existing MockStorage from server_test.go Logger: SimpleLogger{}, } return NewServer(config) } // Test UCXL standardized response formats func TestUCXLResponseFormats(t *testing.T) { server := createUCXLTestServer() tests := []struct { name string method string endpoint string query string body string expectedCode ucxl.UCXLCode expectedStatus int }{ { name: "GET with valid address returns UCXL-200-SUCCESS", method: "GET", endpoint: "/test/ucxi/v1/get", query: "address=ucxl://agent:role@project:task/*^", body: "", expectedCode: ucxl.CodeSuccess, expectedStatus: 200, }, { name: "GET without address returns UCXL-400-BAD_REQUEST", method: "GET", endpoint: "/test/ucxi/v1/get", query: "", body: "", expectedCode: ucxl.CodeBadRequest, expectedStatus: 400, }, { name: "GET with invalid address returns UCXL-400-INVALID_ADDRESS", method: "GET", endpoint: "/test/ucxi/v1/get", query: "address=invalid-address", body: "", expectedCode: ucxl.CodeInvalidAddress, expectedStatus: 400, }, { name: "PUT with valid data returns UCXL-201-CREATED", method: "PUT", endpoint: "/test/ucxi/v1/put", query: "address=ucxl://agent:role@project:task/*^", body: "test content", expectedCode: ucxl.CodeCreated, expectedStatus: 201, }, { name: "DELETE with valid address returns UCXL-200-SUCCESS", method: "DELETE", endpoint: "/test/ucxi/v1/delete", query: "address=ucxl://agent:role@project:task/*^", body: "", expectedCode: ucxl.CodeSuccess, expectedStatus: 200, }, { name: "POST to GET endpoint returns UCXL-405-METHOD_NOT_ALLOWED", method: "POST", endpoint: "/test/ucxi/v1/get", query: "", body: "", expectedCode: ucxl.CodeMethodNotAllowed, expectedStatus: 405, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create request var req *http.Request var err error if tt.body != "" { req, err = http.NewRequest(tt.method, tt.endpoint+"?"+tt.query, strings.NewReader(tt.body)) } else { req, err = http.NewRequest(tt.method, tt.endpoint+"?"+tt.query, nil) } if err != nil { t.Fatalf("Failed to create request: %v", err) } req.Header.Set("Content-Type", "text/plain") req.Header.Set("X-Request-ID", "test-"+tt.name) // Create response recorder rr := httptest.NewRecorder() // Create HTTP handler mux := http.NewServeMux() server.registerRoutes(mux) handler := server.withMiddleware(mux) // Execute request handler.ServeHTTP(rr, req) // Check status code if rr.Code != tt.expectedStatus { t.Errorf("Expected status %d, got %d", tt.expectedStatus, rr.Code) } // Parse response var response map[string]interface{} if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil { t.Fatalf("Failed to parse response JSON: %v", err) } // Check for UCXL response structure if rr.Code >= 200 && rr.Code < 300 { // Success response should have "response" field if responseData, ok := response["response"]; ok { if responseMap, ok := responseData.(map[string]interface{}); ok { if code, ok := responseMap["code"].(string); ok { if ucxl.UCXLCode(code) != tt.expectedCode { t.Errorf("Expected UCXL code %s, got %s", tt.expectedCode, code) } } else { t.Error("Response missing 'code' field") } // Check required fields if _, ok := responseMap["message"]; !ok { t.Error("Response missing 'message' field") } if _, ok := responseMap["request_id"]; !ok { t.Error("Response missing 'request_id' field") } if _, ok := responseMap["timestamp"]; !ok { t.Error("Response missing 'timestamp' field") } } } else { t.Error("Success response missing 'response' field") } } else { // Error response should have "error" field if errorData, ok := response["error"]; ok { if errorMap, ok := errorData.(map[string]interface{}); ok { if code, ok := errorMap["code"].(string); ok { if ucxl.UCXLCode(code) != tt.expectedCode { t.Errorf("Expected UCXL code %s, got %s", tt.expectedCode, code) } } else { t.Error("Error response missing 'code' field") } // Check required fields if _, ok := errorMap["message"]; !ok { t.Error("Error response missing 'message' field") } if _, ok := errorMap["source"]; !ok { t.Error("Error response missing 'source' field") } if _, ok := errorMap["path"]; !ok { t.Error("Error response missing 'path' field") } if _, ok := errorMap["request_id"]; !ok { t.Error("Error response missing 'request_id' field") } if _, ok := errorMap["timestamp"]; !ok { t.Error("Error response missing 'timestamp' field") } } } else { t.Error("Error response missing 'error' field") } } }) } } // Test status endpoint provides comprehensive information per Issue 010 func TestStatusEndpoint(t *testing.T) { server := createUCXLTestServer() req, err := http.NewRequest("GET", "/test/ucxi/v1/status", nil) if err != nil { t.Fatalf("Failed to create request: %v", err) } req.Header.Set("X-Request-ID", "test-status") rr := httptest.NewRecorder() mux := http.NewServeMux() server.registerRoutes(mux) handler := server.withMiddleware(mux) handler.ServeHTTP(rr, req) if rr.Code != 200 { t.Errorf("Expected status 200, got %d", rr.Code) } var response map[string]interface{} if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil { t.Fatalf("Failed to parse response JSON: %v", err) } // Check UCXL response structure responseData, ok := response["response"].(map[string]interface{}) if !ok { t.Fatal("Response missing 'response' field") } data, ok := responseData["data"].(map[string]interface{}) if !ok { t.Fatal("Response data missing") } // Check required status fields per Issue 010 requiredFields := []string{"server", "ucxi", "resolver", "storage", "navigators", "p2p", "metrics"} for _, field := range requiredFields { if _, ok := data[field]; !ok { t.Errorf("Status response missing required field: %s", field) } } // Check server info if serverInfo, ok := data["server"].(map[string]interface{}); ok { serverFields := []string{"port", "base_path", "running", "version"} for _, field := range serverFields { if _, ok := serverInfo[field]; !ok { t.Errorf("Server info missing field: %s", field) } } } else { t.Error("Status response missing server information") } // Check resolver stats if resolverInfo, ok := data["resolver"].(map[string]interface{}); ok { if enabled, ok := resolverInfo["enabled"].(bool); !ok || !enabled { t.Error("Resolver should be enabled in test") } } else { t.Error("Status response missing resolver information") } // Check storage metrics if storageInfo, ok := data["storage"].(map[string]interface{}); ok { if enabled, ok := storageInfo["enabled"].(bool); !ok || !enabled { t.Error("Storage should be enabled in test") } } else { t.Error("Status response missing storage information") } } // Test announce endpoint with JSON payload func TestAnnounceEndpoint(t *testing.T) { server := createUCXLTestServer() payload := map[string]interface{}{ "address": "ucxl://agent:role@project:task/*^", "content": map[string]interface{}{ "data": "dGVzdCBjb250ZW50", // base64 encoded "test content" "content_type": "text/plain", "metadata": map[string]string{"author": "test"}, }, } payloadBytes, err := json.Marshal(payload) if err != nil { t.Fatalf("Failed to marshal payload: %v", err) } req, err := http.NewRequest("POST", "/test/ucxi/v1/announce", bytes.NewReader(payloadBytes)) if err != nil { t.Fatalf("Failed to create request: %v", err) } req.Header.Set("Content-Type", "application/json") req.Header.Set("X-Request-ID", "test-announce") rr := httptest.NewRecorder() mux := http.NewServeMux() server.registerRoutes(mux) handler := server.withMiddleware(mux) handler.ServeHTTP(rr, req) if rr.Code != 200 { t.Errorf("Expected status 200, got %d", rr.Code) } var response map[string]interface{} if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil { t.Fatalf("Failed to parse response JSON: %v", err) } // Verify UCXL success response structure responseData, ok := response["response"].(map[string]interface{}) if !ok { t.Fatal("Response missing 'response' field") } if code, ok := responseData["code"].(string); !ok || ucxl.UCXLCode(code) != ucxl.CodeSuccess { t.Errorf("Expected UCXL-200-SUCCESS, got %s", code) } } // Test error handling with invalid UCXL addresses func TestInvalidAddressHandling(t *testing.T) { server := createUCXLTestServer() invalidAddresses := []string{ "not-a-ucxl-address", "ucxl://", "ucxl://agent", "ucxl://agent:role", "ucxl://agent:role@project", "ucxl://agent:role@project:task", "ucxl://agent:role@project:task/invalid-temporal", } for i, address := range invalidAddresses { t.Run(fmt.Sprintf("InvalidAddress%d", i), func(t *testing.T) { req, err := http.NewRequest("GET", "/test/ucxi/v1/get?address="+address, nil) if err != nil { t.Fatalf("Failed to create request: %v", err) } req.Header.Set("X-Request-ID", fmt.Sprintf("test-invalid-%d", i)) rr := httptest.NewRecorder() mux := http.NewServeMux() server.registerRoutes(mux) handler := server.withMiddleware(mux) handler.ServeHTTP(rr, req) if rr.Code != 400 { t.Errorf("Expected status 400, got %d", rr.Code) } var response map[string]interface{} if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil { t.Fatalf("Failed to parse response JSON: %v", err) } // Should be UCXL error format errorData, ok := response["error"].(map[string]interface{}) if !ok { t.Fatal("Error response missing 'error' field") } code, ok := errorData["code"].(string) if !ok { t.Fatal("Error missing 'code' field") } // Should be either invalid address or bad request ucxlCode := ucxl.UCXLCode(code) if ucxlCode != ucxl.CodeInvalidAddress && ucxlCode != ucxl.CodeBadRequest { t.Errorf("Expected INVALID_ADDRESS or BAD_REQUEST, got %s", code) } }) } } // Benchmark UCXL response building func BenchmarkUCXLResponseBuilding(b *testing.B) { builder := ucxl.NewResponseBuilder("test-request-id", "ucxi-server") data := map[string]interface{}{ "test": "data", "count": 42, } b.ResetTimer() for i := 0; i < b.N; i++ { _ = builder.OK(data) } } // Benchmark UCXL error building func BenchmarkUCXLErrorBuilding(b *testing.B) { builder := ucxl.NewResponseBuilder("test-request-id", "ucxi-server") details := map[string]interface{}{ "field": "address", "provided": "invalid-address", } b.ResetTimer() for i := 0; i < b.N; i++ { _ = builder.ErrorWithDetails(ucxl.CodeInvalidAddress, "Invalid address", "/test/path", details) } }