package audit import ( "context" "encoding/json" "net/http" "net/http/httptest" "testing" "time" "proxui/backend/internal/auth" "proxui/backend/internal/membership" "proxui/backend/internal/rbac" ) func TestListTenantAuditReturnsEntries(t *testing.T) { repository := &stubRepository{ entries: []Entry{{ ID: "audit-1", TenantID: "tenant-1", ProfileID: "profile-1", Action: "vm.power.start", TargetType: "vm", TargetID: "vm-1", Metadata: json.RawMessage(`{"cluster_id":"c-1"}`), CreatedAt: time.Date(2026, 6, 11, 12, 0, 0, 0, time.UTC), }}, } handler := NewHandler(repository) req := requestWithPrincipalAndMembership(http.MethodGet, "/tenants/tenant-1/audit", "tenant-1", "owner") req.SetPathValue("tenantID", "tenant-1") rec := httptest.NewRecorder() handler.ListTenantAudit(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK) } var response struct { Data []Entry `json:"data"` } if err := json.Unmarshal(rec.Body.Bytes(), &response); err != nil { t.Fatalf("unmarshal response: %v", err) } if len(response.Data) != 1 { t.Fatalf("len(data) = %d, want 1", len(response.Data)) } if response.Data[0].ID != "audit-1" { t.Fatalf("entry ID = %q, want audit-1", response.Data[0].ID) } } func TestListTenantAuditReturnsEmptyArray(t *testing.T) { handler := NewHandler(&stubRepository{}) req := requestWithPrincipalAndMembership(http.MethodGet, "/tenants/tenant-1/audit", "tenant-1", "owner") req.SetPathValue("tenantID", "tenant-1") rec := httptest.NewRecorder() handler.ListTenantAudit(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK) } var response struct { Data []Entry `json:"data"` } if err := json.Unmarshal(rec.Body.Bytes(), &response); err != nil { t.Fatalf("unmarshal response: %v", err) } if response.Data == nil { t.Fatalf("data = nil, want empty array") } if len(response.Data) != 0 { t.Fatalf("len(data) = %d, want 0", len(response.Data)) } } func TestListTenantAuditReturnsForbiddenForViewer(t *testing.T) { handler := NewHandler(&stubRepository{}) req := requestWithPrincipalAndMembership(http.MethodGet, "/tenants/tenant-1/audit", "tenant-1", "viewer") req.SetPathValue("tenantID", "tenant-1") rec := httptest.NewRecorder() handler.ListTenantAudit(rec, req) if rec.Code != http.StatusForbidden { t.Fatalf("status = %d, want %d", rec.Code, http.StatusForbidden) } } func requestWithPrincipalAndMembership(method string, target string, tenantID string, role string) *http.Request { req := httptest.NewRequest(method, target, nil) ctx := auth.ContextWithPrincipal(req.Context(), auth.Principal{ Subject: "profile-1", Email: "user@example.test", Role: "authenticated", }) ctx = membership.ContextWithMembership(ctx, membership.Membership{ TenantID: tenantID, Role: rbac.Role(role), }) return req.WithContext(ctx) } type stubRepository struct { entries []Entry err error } func (s *stubRepository) ListTenantAudit(_ context.Context, _ string, _ int, _ int) ([]Entry, error) { return s.entries, s.err }