chore: establish local platform baseline
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
package httpapi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"data-terminal-cloud/internal/deviceauth"
|
||||
"data-terminal-cloud/internal/identity"
|
||||
"data-terminal-cloud/internal/media"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func TestMediaWebHandlersRejectInvalidRequestsBeforeService(t *testing.T) {
|
||||
principal := identity.Principal{Issuer: "issuer", Subject: "subject"}
|
||||
resourceID := uuid.NewString()
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.Handler
|
||||
request *http.Request
|
||||
status int
|
||||
code string
|
||||
}{
|
||||
{"grant unauthenticated", GrantRecordingAccessHandler(nil), httptest.NewRequest(http.MethodPost, "/api/v1/conversations/"+resourceID+"/recording-grants", nil), http.StatusUnauthorized, "AUTHENTICATION_REQUIRED"},
|
||||
{"grant invalid resource", GrantRecordingAccessHandler(nil), authenticatedRequest(http.MethodPost, "/api/v1/conversations/bad/recording-grants", `{}`, principal), http.StatusBadRequest, "VALIDATION_FAILED"},
|
||||
{"grant malformed body", GrantRecordingAccessHandler(nil), authenticatedRequest(http.MethodPost, "/api/v1/conversations/"+resourceID+"/recording-grants", `{`, principal), http.StatusBadRequest, "VALIDATION_FAILED"},
|
||||
{"grant missing fields", GrantRecordingAccessHandler(nil), authenticatedRequest(http.MethodPost, "/api/v1/conversations/"+resourceID+"/recording-grants", `{}`, principal), http.StatusBadRequest, "VALIDATION_FAILED"},
|
||||
{"list unauthenticated", ListRecordingAccessGrantsHandler(nil), httptest.NewRequest(http.MethodGet, "/api/v1/conversations/"+resourceID+"/recording-grants", nil), http.StatusUnauthorized, "AUTHENTICATION_REQUIRED"},
|
||||
{"revoke invalid resource", RevokeRecordingAccessHandler(nil), authenticatedRequest(http.MethodDelete, "/api/v1/recording-grants/bad", "", principal), http.StatusBadRequest, "VALIDATION_FAILED"},
|
||||
{"conversation unauthenticated", GetConversationMediaHandler(nil), httptest.NewRequest(http.MethodGet, "/api/v1/conversations/"+resourceID+"/media", nil), http.StatusUnauthorized, "AUTHENTICATION_REQUIRED"},
|
||||
{"access malformed body", CreateMediaAccessHandler(nil), authenticatedRequest(http.MethodPost, "/api/v1/media/"+resourceID+":access", `{`, principal), http.StatusBadRequest, "VALIDATION_FAILED"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if !strings.Contains(test.name, "invalid resource") && !strings.Contains(test.name, "unauthenticated") {
|
||||
test.request.SetPathValue("id", resourceID)
|
||||
} else if strings.Contains(test.name, "invalid resource") {
|
||||
test.request.SetPathValue("id", "bad")
|
||||
}
|
||||
recorder := httptest.NewRecorder()
|
||||
test.handler.ServeHTTP(recorder, test.request)
|
||||
if recorder.Code != test.status || !strings.Contains(recorder.Body.String(), test.code) {
|
||||
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMediaDeviceHandlersRejectInvalidRequestsBeforeService(t *testing.T) {
|
||||
resourceID := uuid.NewString()
|
||||
device := deviceauth.Identity{ID: uuid.NewString(), PublicID: uuid.NewString(), TenantID: uuid.NewString(), Status: "registered"}
|
||||
authenticated := func(method, target, body string) *http.Request {
|
||||
request := httptest.NewRequest(method, target, strings.NewReader(body))
|
||||
request.SetPathValue("id", resourceID)
|
||||
return request.WithContext(deviceauth.WithIdentity(request.Context(), device))
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
handler http.Handler
|
||||
request *http.Request
|
||||
status int
|
||||
code string
|
||||
}{
|
||||
{"prepare unauthenticated", PrepareMediaUploadBatchHandler(nil), httptest.NewRequest(http.MethodPost, "/device/v2/conversations/"+resourceID+"/media-uploads", nil), http.StatusUnauthorized, "DEVICE_AUTHENTICATION_FAILED"},
|
||||
{"prepare missing idempotency", PrepareMediaUploadBatchHandler(nil), authenticated(http.MethodPost, "/device/v2/conversations/"+resourceID+"/media-uploads", `{}`), http.StatusBadRequest, "VALIDATION_FAILED"},
|
||||
{"prepare malformed body", PrepareMediaUploadBatchHandler(nil), authenticated(http.MethodPost, "/device/v2/conversations/"+resourceID+"/media-uploads", `{`), http.StatusBadRequest, "VALIDATION_FAILED"},
|
||||
{"complete unauthenticated", CompleteMediaUploadBatchHandler(nil), httptest.NewRequest(http.MethodPost, "/device/v2/media-upload-batches/"+resourceID+":complete", nil), http.StatusUnauthorized, "DEVICE_AUTHENTICATION_FAILED"},
|
||||
{"get unauthenticated", GetDeviceMediaUploadBatchHandler(nil), httptest.NewRequest(http.MethodGet, "/device/v2/media-upload-batches/"+resourceID, nil), http.StatusUnauthorized, "DEVICE_AUTHENTICATION_FAILED"},
|
||||
{"delete unauthenticated", AcknowledgeLocalMediaDeleteHandler(nil), httptest.NewRequest(http.MethodPost, "/device/v2/media/"+resourceID+":local-delete", nil), http.StatusUnauthorized, "DEVICE_AUTHENTICATION_FAILED"},
|
||||
{"delete malformed body", AcknowledgeLocalMediaDeleteHandler(nil), authenticated(http.MethodPost, "/device/v2/media/"+resourceID+":local-delete", `{`), http.StatusBadRequest, "VALIDATION_FAILED"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if strings.Contains(test.name, "malformed") {
|
||||
test.request.Header.Set("Idempotency-Key", "http-media-valid-key")
|
||||
}
|
||||
recorder := httptest.NewRecorder()
|
||||
test.handler.ServeHTTP(recorder, test.request)
|
||||
if recorder.Code != test.status || !strings.Contains(recorder.Body.String(), test.code) {
|
||||
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteMediaErrorStableMappings(t *testing.T) {
|
||||
tests := []struct {
|
||||
err error
|
||||
status int
|
||||
code string
|
||||
}{
|
||||
{media.ErrRecordingAccessDenied, http.StatusForbidden, "RECORDING_ACCESS_DENIED"},
|
||||
{media.ErrNotFound, http.StatusNotFound, "RESOURCE_NOT_FOUND"},
|
||||
{media.ErrAccessDenied, http.StatusForbidden, "UPLOAD_NOT_ALLOWED"},
|
||||
{media.ErrInvalidDeclaration, http.StatusBadRequest, "VALIDATION_FAILED"},
|
||||
{media.ErrExpired, http.StatusGone, "UPLOAD_BATCH_EXPIRED"},
|
||||
{media.ErrConflict, http.StatusConflict, "RESOURCE_STATE_CONFLICT"},
|
||||
{media.ErrLocalDeleteTooEarly, http.StatusConflict, "LOCAL_DELETE_NOT_DUE"},
|
||||
{errors.New("database unavailable"), http.StatusInternalServerError, "INTERNAL_ERROR"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
recorder := httptest.NewRecorder()
|
||||
request := httptest.NewRequest(http.MethodGet, "/api/v1/media", nil)
|
||||
writeMediaError(recorder, request, test.err)
|
||||
if recorder.Code != test.status || !strings.Contains(recorder.Body.String(), test.code) {
|
||||
t.Fatalf("error=%v status=%d body=%s", test.err, recorder.Code, recorder.Body.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user