Public source validation / validate (push) Failing after 3m8s
113 lines
4.5 KiB
Go
113 lines
4.5 KiB
Go
package dashboardapi
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/itworx/pulse/internal/audit"
|
|
"github.com/itworx/pulse/internal/auth"
|
|
"github.com/itworx/pulse/internal/correlation"
|
|
"github.com/itworx/pulse/internal/dashboard"
|
|
)
|
|
|
|
func requestWithPrincipal(method, path, body string, principal *auth.Principal) *httptest.ResponseRecorder {
|
|
request := httptest.NewRequest(method, path, strings.NewReader(body))
|
|
request.Header.Set("Content-Type", "application/json")
|
|
request = request.WithContext(correlation.WithContext(request.Context(), "m3-03-test-correlation"))
|
|
if principal != nil {
|
|
request = request.WithContext(auth.WithPrincipal(request.Context(), *principal))
|
|
}
|
|
response := httptest.NewRecorder()
|
|
(Handler{Repository: dashboard.Repository{}}).ServeHTTP(response, request)
|
|
return response
|
|
}
|
|
|
|
func problemCode(t *testing.T, response *httptest.ResponseRecorder) string {
|
|
t.Helper()
|
|
var body struct{ Code string }
|
|
if err := json.Unmarshal(response.Body.Bytes(), &body); err != nil {
|
|
t.Fatalf("problem response is not JSON: %v", err)
|
|
}
|
|
return body.Code
|
|
}
|
|
|
|
func TestHandlerRequiresAuthenticationWithProblemResponse(t *testing.T) {
|
|
response := requestWithPrincipal(http.MethodGet, "/api/v1/dashboards", "", nil)
|
|
if response.Code != http.StatusUnauthorized {
|
|
t.Fatalf("status=%d", response.Code)
|
|
}
|
|
if got := response.Header().Get("Content-Type"); got != "application/problem+json" {
|
|
t.Fatalf("content type=%q", got)
|
|
}
|
|
if got := problemCode(t, response); got != "UNAUTHORIZED" {
|
|
t.Fatalf("code=%q", got)
|
|
}
|
|
if got := response.Header().Get(correlation.Header); got != "m3-03-test-correlation" {
|
|
t.Fatalf("correlation=%q", got)
|
|
}
|
|
}
|
|
|
|
func TestHandlerEnforcesEditorForMutation(t *testing.T) {
|
|
viewer := auth.Principal{Subject: "viewer", Role: auth.RoleViewer}
|
|
response := requestWithPrincipal(http.MethodPost, "/api/v1/dashboards", "{}", &viewer)
|
|
if response.Code != http.StatusForbidden {
|
|
t.Fatalf("status=%d", response.Code)
|
|
}
|
|
if got := problemCode(t, response); got != "FORBIDDEN" {
|
|
t.Fatalf("code=%q", got)
|
|
}
|
|
}
|
|
|
|
func TestHandlerEnforcesEditorForPreview(t *testing.T) {
|
|
viewer := auth.Principal{Subject: "viewer", Role: auth.RoleViewer}
|
|
response := requestWithPrincipal(http.MethodPost, "/api/v1/dashboards/00000000-0000-0000-0000-000000000001/preview", `{"widget":{}}`, &viewer)
|
|
if response.Code != http.StatusForbidden || problemCode(t, response) != "FORBIDDEN" {
|
|
t.Fatalf("response=%d %s", response.Code, response.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestHandlerRejectsInvalidContentTypeAndVersion(t *testing.T) {
|
|
editor := auth.Principal{Subject: "editor", Role: auth.RoleEditor}
|
|
request := httptest.NewRequest(http.MethodPost, "/api/v1/dashboards", strings.NewReader("{}"))
|
|
request.Header.Set("Content-Type", "text/plain")
|
|
request = request.WithContext(auth.WithPrincipal(context.Background(), editor))
|
|
response := httptest.NewRecorder()
|
|
(Handler{Repository: dashboard.Repository{}}).ServeHTTP(response, request)
|
|
if response.Code != http.StatusBadRequest || problemCode(t, response) != "INVALID_DOCUMENT" {
|
|
t.Fatalf("response=%d %s", response.Code, response.Body.String())
|
|
}
|
|
|
|
response = requestWithPrincipal(http.MethodPost, "/api/v1/dashboards/00000000-0000-0000-0000-000000000001/restore/not-a-number", "{}", &editor)
|
|
if response.Code != http.StatusBadRequest || problemCode(t, response) != "INVALID_VERSION" {
|
|
t.Fatalf("response=%d %s", response.Code, response.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestHandlerRejectsUnsupportedMethod(t *testing.T) {
|
|
viewer := auth.Principal{Subject: "viewer", Role: auth.RoleViewer}
|
|
response := requestWithPrincipal(http.MethodPut, "/api/v1/dashboards", "{}", &viewer)
|
|
if response.Code != http.StatusMethodNotAllowed {
|
|
t.Fatalf("status=%d", response.Code)
|
|
}
|
|
}
|
|
|
|
func TestHandlerRecordsAuditedSafeDiff(t *testing.T) {
|
|
store := &audit.MemoryStore{}
|
|
request := httptest.NewRequest(http.MethodPost, "/api/v1/dashboards", strings.NewReader("{}"))
|
|
request = request.WithContext(correlation.WithContext(request.Context(), "audit-correlation"))
|
|
handler := Handler{Audit: store}
|
|
if err := handler.record(request, "subject-1", "dashboard.update_document", "00000000-0000-0000-0000-000000000001", map[string]any{"revision": 1}, map[string]any{"revision": 2}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(store.Events) != 1 || store.Events[0].Action != "dashboard.update_document" || store.Events[0].CorrelationID != "audit-correlation" {
|
|
t.Fatalf("events=%+v", store.Events)
|
|
}
|
|
if _, ok := store.Events[0].After["document"]; ok {
|
|
t.Fatal("audit event unexpectedly contains full document")
|
|
}
|
|
}
|