113 lines
3.1 KiB
Go
113 lines
3.1 KiB
Go
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
|
|
}
|