rdev/pkg/api/openapi_test.go
jordan 72d16929ca feat: Implement hexagonal architecture with services, webhooks, queue, and telemetry
Major refactoring to hexagonal (ports & adapters) architecture:

- Add service layer (apikey_service, project_service) for business logic
- Add webhook system with dispatcher and delivery tracking
- Add command queue with priority-based processing
- Add rate limiting with sliding window algorithm
- Add audit logging for command execution
- Add OpenTelemetry integration (traces, metrics, spans)
- Add circuit breaker for fault tolerance
- Add cached repository wrapper for performance
- Add comprehensive validation package
- Add Kubernetes client integration for pod management
- Add database migrations (allowed_ips, audit_log, rate_limiting, queue, webhooks)
- Add network policy and PodDisruptionBudget for k8s
- Remove legacy executor and projects/registry packages
- Untrack secrets.yaml (now managed via envault)
- Add coverage.out to .gitignore
- Add e2e test infrastructure with docker-compose
- Add comprehensive documentation (API, architecture, operations, plans)
- Add golangci-lint config and pre-commit hook

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 19:57:46 -07:00

121 lines
2.8 KiB
Go

package api
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestDocsEndpointSchemeDetection(t *testing.T) {
// Create a simple app with docs enabled
app := New("test-api")
spec := NewOpenAPISpec("Test API", "1.0.0")
app.EnableDocs(spec)
tests := []struct {
name string
xForwardedProto string
expectedScheme string
}{
{
name: "no header defaults to http",
xForwardedProto: "",
expectedScheme: "http",
},
{
name: "X-Forwarded-Proto https",
xForwardedProto: "https",
expectedScheme: "https",
},
{
name: "X-Forwarded-Proto http",
xForwardedProto: "http",
expectedScheme: "http",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/docs", nil)
if tt.xForwardedProto != "" {
req.Header.Set("X-Forwarded-Proto", tt.xForwardedProto)
}
rec := httptest.NewRecorder()
app.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("expected status 200, got %d", rec.Code)
}
body := rec.Body.String()
expectedURL := tt.expectedScheme + "://"
if !strings.Contains(body, expectedURL) {
t.Errorf("expected body to contain %q scheme URL", expectedURL)
}
})
}
}
func TestOpenAPISpec(t *testing.T) {
spec := NewOpenAPISpec("Test API", "1.0.0").
WithDescription("Test description").
WithServer("https://api.example.com", "Production").
WithTag("test", "Test operations")
// Add a path
spec.AddPath("/test", "get", Op("Get test", "Gets a test", "test"))
// Generate JSON
jsonBytes, err := spec.JSON()
if err != nil {
t.Fatalf("failed to generate JSON: %v", err)
}
json := string(jsonBytes)
// Verify content
if !strings.Contains(json, `"title": "Test API"`) {
t.Error("expected title in JSON")
}
if !strings.Contains(json, `"version": "1.0.0"`) {
t.Error("expected version in JSON")
}
if !strings.Contains(json, `"description": "Test description"`) {
t.Error("expected description in JSON")
}
if !strings.Contains(json, `"url": "https://api.example.com"`) {
t.Error("expected server URL in JSON")
}
if !strings.Contains(json, `"/test"`) {
t.Error("expected path in JSON")
}
}
func TestOpenAPIJSONEndpoint(t *testing.T) {
app := New("test-api")
spec := NewOpenAPISpec("Test API", "1.0.0")
app.EnableDocs(spec)
req := httptest.NewRequest(http.MethodGet, "/openapi.json", nil)
rec := httptest.NewRecorder()
app.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("expected status 200, got %d", rec.Code)
}
contentType := rec.Header().Get("Content-Type")
if contentType != "application/json" {
t.Errorf("expected Content-Type application/json, got %s", contentType)
}
// Check CORS header
cors := rec.Header().Get("Access-Control-Allow-Origin")
if cors != "*" {
t.Errorf("expected CORS header *, got %s", cors)
}
}