refactor(media): 资源分发 - 统一资源访问策略与云存储重定向
This commit is contained in:
1 parent
af6633047c
commit
487c34bfeb
50 files changed
+2112
-1266
No files matched your search
@@ -0,0 +1,96 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"infinite-canvas/backend/internal/assets"
|
||||
"infinite-canvas/backend/internal/model"
|
||||
"infinite-canvas/backend/internal/service"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestServeResourceDeliveryRedirectsCloudMediaWithoutWritingBody(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
router.GET("/resource", func(c *gin.Context) {
|
||||
serveResourceDelivery(c, &service.ResourceDelivery{Access: &assets.ResourceAccess{
|
||||
ResourceID: "resource-1",
|
||||
URL: "https://cdn.example.com/users/user-1/image/test.png?signature=redacted",
|
||||
Delivery: assets.DeliveryCDN,
|
||||
}}, "private, no-cache", "")
|
||||
})
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
router.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/resource", nil))
|
||||
|
||||
if recorder.Code != http.StatusTemporaryRedirect {
|
||||
t.Fatalf("status = %d, want 307", recorder.Code)
|
||||
}
|
||||
if got := recorder.Header().Get("Location"); got != "https://cdn.example.com/users/user-1/image/test.png?signature=redacted" {
|
||||
t.Fatalf("location = %q", got)
|
||||
}
|
||||
if recorder.Body.Len() != 0 {
|
||||
t.Fatalf("redirect wrote %d body bytes; platform must not send cloud media", recorder.Body.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeResourceDeliveryReturnsAccessDescriptorWithoutRedirect(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
router.GET("/resource", func(c *gin.Context) {
|
||||
serveResourceDelivery(c, &service.ResourceDelivery{Access: &assets.ResourceAccess{
|
||||
ResourceID: "resource-1",
|
||||
URL: "https://cdn.example.com/test.png",
|
||||
Delivery: assets.DeliveryCDN,
|
||||
}}, "private, no-cache", "")
|
||||
})
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
router.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/resource?access=1", nil))
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, want 200", recorder.Code)
|
||||
}
|
||||
if got := recorder.Header().Get("Cache-Control"); got != "private, no-store" {
|
||||
t.Fatalf("cache-control = %q", got)
|
||||
}
|
||||
if !strings.Contains(recorder.Body.String(), `"url":"https://cdn.example.com/test.png"`) {
|
||||
t.Fatalf("access descriptor missing from body: %s", recorder.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestServeResourceDeliveryStreamsPlatformBytesAndRangeMetadata(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
resource := &model.Resource{ID: "resource-1", MimeType: "video/mp4", UpdatedAt: time.Date(2026, time.January, 2, 3, 4, 5, 0, time.UTC)}
|
||||
router := gin.New()
|
||||
router.GET("/resource", func(c *gin.Context) {
|
||||
serveResourceDelivery(c, &service.ResourceDelivery{
|
||||
Resource: resource,
|
||||
Access: &assets.ResourceAccess{ResourceID: resource.ID, URL: "/api/resources/resource-1/file", Delivery: assets.DeliveryProxy},
|
||||
Stream: &assets.ResourceStream{Resource: resource, Body: io.NopCloser(strings.NewReader("partial-media")), StatusCode: http.StatusPartialContent, ContentLength: 13, ContentRange: "bytes 10-22/100", AcceptRanges: "bytes"},
|
||||
}, "private, no-cache", `inline; filename="video.mp4"`)
|
||||
})
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
recorder.HeaderMap = make(http.Header)
|
||||
router.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/resource", nil))
|
||||
|
||||
if recorder.Code != http.StatusPartialContent || recorder.Body.String() != "partial-media" {
|
||||
t.Fatalf("response = status %d body %q", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if recorder.Header().Get("Content-Range") != "bytes 10-22/100" || recorder.Header().Get("Accept-Ranges") != "bytes" {
|
||||
t.Fatalf("range headers missing: %#v", recorder.Header())
|
||||
}
|
||||
if recorder.Header().Get("Content-Type") != "video/mp4" {
|
||||
t.Fatalf("content-type = %q", recorder.Header().Get("Content-Type"))
|
||||
}
|
||||
if recorder.Header().Get("Content-Disposition") != `inline; filename="video.mp4"` {
|
||||
t.Fatalf("content-disposition = %q", recorder.Header().Get("Content-Disposition"))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user