package proxy import ( "io" "net/http/httptest" "os" "path/filepath" "strings" "testing" ) func TestLoggingProxy_Redaction(t *testing.T) { lp := NewLoggingProxy("http://example.com", true) if !lp.Redact { t.Error("Expected redact to be true") } } func TestIsSensitive(t *testing.T) { tests := []struct { header string want bool }{ {"Authorization", true}, {"authorization", true}, {"Cookie", true}, {"X-Bose-Token", true}, {"Content-Type", false}, {"Accept", false}, } for _, tt := range tests { if got := isSensitive(tt.header); got != tt.want { t.Errorf("isSensitive(%q) = %v, want %v", tt.header, got, tt.want) } } } func TestShouldLogBody(t *testing.T) { tests := []struct { contentType string want bool }{ {"application/xml", true}, {"application/json", true}, {"text/plain", true}, {"text/html", true}, {"", true}, {"audio/mpeg", false}, {"application/octet-stream", false}, } for _, tt := range tests { if got := shouldLogBody(tt.contentType); got != tt.want { t.Errorf("shouldLogBody(%q) = %v, want %v", tt.contentType, got, tt.want) } } } func TestLoggingProxy_LogRequest(t *testing.T) { if err := os.Setenv("LOG_PROXY_BODY", "true"); err != nil { t.Fatalf("Failed to set LOG_PROXY_BODY: %v", err) } defer func() { _ = os.Unsetenv("LOG_PROXY_BODY") }() lp := NewLoggingProxy("http://example.com", true) lp.LogBody = true body := "test body content" req := httptest.NewRequest("POST", "http://example.com/api", strings.NewReader(body)) req.Header.Set("Content-Type", "text/plain") req.Header.Set("Authorization", "bearer secret") lp.LogRequest(req) // Check if body is still readable readBody, _ := io.ReadAll(req.Body) if string(readBody) != body { t.Errorf("Request body was consumed or changed, got %q, want %q", string(readBody), body) } // Test truncation lp.MaxBodySize = 4 req2 := httptest.NewRequest("POST", "http://example.com/api", strings.NewReader("1234567890")) req2.Header.Set("Content-Type", "text/plain") lp.LogRequest(req2) } func TestLoggingProxy_LogResponse(t *testing.T) { t.Setenv("RECORDER_ASYNC", "false") lp := NewLoggingProxy("http://example.com", true) lp.LogBody = true body := "response content" req := httptest.NewRequest("GET", "http://example.com/api", nil) w := httptest.NewRecorder() w.Header().Set("Content-Type", "text/plain") _, _ = w.WriteString(body) res := w.Result() res.Request = req lp.LogResponse(res) // Check if body is still readable readBody, _ := io.ReadAll(res.Body) if string(readBody) != body { t.Errorf("Response body was consumed or changed, got %q, want %q", string(readBody), body) } // Test with recorder tmpDir, _ := os.MkdirTemp("", "proxy-recorder-test") defer os.RemoveAll(tmpDir) recorder := NewRecorder(tmpDir) lp.SetRecorder(recorder) lp.RecordEnabled = true lp.LogResponse(res) // Verify recording exists interactionsDir := filepath.Join(tmpDir, "interactions", recorder.SessionID, "upstream", "api") files, _ := os.ReadDir(interactionsDir) if len(files) == 0 { t.Error("LogResponse did not record the interaction") } }