Files
CHORUS/pkg/ucxi/ucxl_integration_test.go
anthonyrawlins 543ab216f9 Complete BZZZ functionality port to CHORUS
🎭 CHORUS now contains full BZZZ functionality adapted for containers

Core systems ported:
- P2P networking (libp2p with DHT and PubSub)
- Task coordination (COOEE protocol)
- HMMM collaborative reasoning
- SHHH encryption and security
- SLURP admin election system
- UCXL content addressing
- UCXI server integration
- Hypercore logging system
- Health monitoring and graceful shutdown
- License validation with KACHING

Container adaptations:
- Environment variable configuration (no YAML files)
- Container-optimized logging to stdout/stderr
- Auto-generated agent IDs for container deployments
- Docker-first architecture

All proven BZZZ P2P protocols, AI integration, and collaboration
features are now available in containerized form.

Next: Build and test container deployment.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-02 20:02:37 +10:00

409 lines
12 KiB
Go

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)
}
}