feat(#1714): 前端 prepare 短路(后端 skip_transfer 命中时跳过 OSS 直传) (#1729)
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 3s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Check push changed paths (push) Successful in 9s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 26s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 30s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 28s
CI/CD Pipeline / Build Staging API Image (push) Successful in 41s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 39s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 38s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 4s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 1m54s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m16s
CI/CD Pipeline / Integration Tests (push) Successful in 2m28s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m16s
CI/CD Pipeline / Validate - Style (push) Successful in 2m51s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m10s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m31s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m32s
CI/CD Pipeline / Validate - Security (push) Successful in 5m18s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m41s
AI Code Review / AI Code Review (pull_request) Successful in 6m20s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m32s
CI/CD Pipeline / Unit Tests (push) Successful in 8m24s
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Failing after 243h31m40s
CI/CD Pipeline / CI Gate (push) Failing after 243h31m45s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 243h31m45s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Failing after 243h37m0s
CI/CD Pipeline / Build Production Web Image (push) Failing after 243h31m45s
CI/CD Pipeline / Canary Release to Production (pull_request) Failing after 243h38m36s
CI/CD Pipeline / Build Production API Image (push) Failing after 243h31m45s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 243h38m46s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 243h38m47s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Failing after 243h38m49s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 243h38m48s
CI/CD Pipeline / Retag skipped Staging API Image (push) Failing after 243h38m51s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 243h38m52s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 243h38m55s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 243h38m57s
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Failing after 243h39m39s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 243h39m40s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 243h40m7s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 243h40m9s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 243h40m8s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Failing after 243h40m9s
CI/CD Pipeline / Validate - Style (pull_request) Failing after 243h40m11s
CI/CD Pipeline / Frontend Lint (push) Failing after 243h40m11s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 243h40m12s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 243h40m13s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 243h40m13s
CI/CD Pipeline / PR Build API Image (push) Failing after 243h40m14s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 243h40m15s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 243h40m17s
CI/CD Pipeline / Deploy Production (push) Failing after 244h6m15s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 244h13m21s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Failing after 244h13m25s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 244h13m28s
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Failing after 244h14m14s
CI/CD Pipeline / Integration Tests (pull_request) Failing after 244h14m43s
CI/CD Pipeline / Validate - Security (pull_request) Failing after 244h14m45s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 244h14m47s
CI/CD Pipeline / PR Build Web Image (push) Failing after 244h14m49s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 3s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3s
CI/CD Pipeline / Check push changed paths (push) Successful in 9s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 26s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 30s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 28s
CI/CD Pipeline / Build Staging API Image (push) Successful in 41s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 39s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 38s
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 4s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 1m54s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m16s
CI/CD Pipeline / Integration Tests (push) Successful in 2m28s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m16s
CI/CD Pipeline / Validate - Style (push) Successful in 2m51s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m10s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m31s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m32s
CI/CD Pipeline / Validate - Security (push) Successful in 5m18s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 5m41s
AI Code Review / AI Code Review (pull_request) Successful in 6m20s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m32s
CI/CD Pipeline / Unit Tests (push) Successful in 8m24s
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Failing after 243h31m40s
CI/CD Pipeline / CI Gate (push) Failing after 243h31m45s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 243h31m45s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Failing after 243h37m0s
CI/CD Pipeline / Build Production Web Image (push) Failing after 243h31m45s
CI/CD Pipeline / Canary Release to Production (pull_request) Failing after 243h38m36s
CI/CD Pipeline / Build Production API Image (push) Failing after 243h31m45s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 243h38m46s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 243h38m47s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Failing after 243h38m49s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 243h38m48s
CI/CD Pipeline / Retag skipped Staging API Image (push) Failing after 243h38m51s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 243h38m52s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 243h38m55s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 243h38m57s
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Failing after 243h39m39s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 243h39m40s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 243h40m7s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 243h40m9s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 243h40m8s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Failing after 243h40m9s
CI/CD Pipeline / Validate - Style (pull_request) Failing after 243h40m11s
CI/CD Pipeline / Frontend Lint (push) Failing after 243h40m11s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 243h40m12s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 243h40m13s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 243h40m13s
CI/CD Pipeline / PR Build API Image (push) Failing after 243h40m14s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 243h40m15s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 243h40m17s
CI/CD Pipeline / Deploy Production (push) Failing after 244h6m15s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 244h13m21s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Failing after 244h13m25s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 244h13m28s
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Failing after 244h14m14s
CI/CD Pipeline / Integration Tests (pull_request) Failing after 244h14m43s
CI/CD Pipeline / Validate - Security (pull_request) Failing after 244h14m45s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 244h14m47s
CI/CD Pipeline / PR Build Web Image (push) Failing after 244h14m49s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
This commit was merged in pull request #1729.
This commit is contained in:
@@ -259,6 +259,112 @@ describe("assets API", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("uploadAssetDirect skip_transfer 短路", () => {
|
||||
it("prepare 返回 skip_transfer=true → 直接返回 duplicated,不调 transfer/complete", async () => {
|
||||
mockPost.mockImplementation((url: string) => {
|
||||
if (url === "/upload/direct/prepare") {
|
||||
return Promise.resolve({
|
||||
data: {
|
||||
upload_url: "https://oss/x",
|
||||
method: "POST",
|
||||
storage_key: "uploads/skip/y.mp4",
|
||||
expires_at: "2099",
|
||||
fields: {},
|
||||
max_size_bytes: 1e9,
|
||||
asset_id: "existing-asset",
|
||||
skip_transfer: true,
|
||||
duplicated: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
if (url === "/upload/direct/complete") {
|
||||
throw new Error("complete 不应被调用")
|
||||
}
|
||||
throw new Error("unexpected url " + url)
|
||||
})
|
||||
const putSpy = vi.spyOn(globalThis, "XMLHttpRequest")
|
||||
const file = new File(["x"], "x.mp4", { type: "video/mp4" })
|
||||
const result = await uploadAssetDirect({ file, library_id: "lib-1" })
|
||||
expect(result.duplicated).toBe(true)
|
||||
expect(result.asset_id).toBe("existing-asset")
|
||||
// complete 未被调用(mockPost 只记录 prepare,complete 若调用会抛 "不应被调用")
|
||||
const completeCalls = mockPost.mock.calls.filter(
|
||||
([u]: [string]) => u === "/upload/direct/complete",
|
||||
)
|
||||
expect(completeCalls).toHaveLength(0)
|
||||
putSpy.mockRestore()
|
||||
})
|
||||
|
||||
it("prepare 返回 skip_transfer=false → 走老流程(complete 被调用)", async () => {
|
||||
mockPost.mockImplementation((url: string) => {
|
||||
if (url === "/upload/direct/prepare") {
|
||||
return Promise.resolve({
|
||||
data: {
|
||||
upload_url: "https://oss/x",
|
||||
method: "POST",
|
||||
storage_key: "uploads/normal/y.mp4",
|
||||
expires_at: "2099",
|
||||
fields: {},
|
||||
max_size_bytes: 1e9,
|
||||
asset_id: "new-asset",
|
||||
},
|
||||
})
|
||||
}
|
||||
if (url === "/upload/direct/complete") {
|
||||
return Promise.resolve({
|
||||
data: {
|
||||
storage_key: "uploads/normal/y.mp4",
|
||||
ingest_job_id: "job-1",
|
||||
url: "https://oss/y.mp4",
|
||||
duplicated: false,
|
||||
asset_id: "new-asset",
|
||||
},
|
||||
})
|
||||
}
|
||||
throw new Error("unexpected url " + url)
|
||||
})
|
||||
// mock XMLHttpRequest:send 之后下一 tick 触发 onload 让 transfer 立即成功
|
||||
const origOpen = XMLHttpRequest.prototype.open
|
||||
const origSend = XMLHttpRequest.prototype.send
|
||||
const origSetReadyState = Object.getOwnPropertyDescriptor(
|
||||
XMLHttpRequest.prototype,
|
||||
"readyState",
|
||||
) as PropertyDescriptor | undefined
|
||||
const origStatus = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, "status")
|
||||
Object.defineProperty(XMLHttpRequest.prototype, "readyState", {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 4,
|
||||
})
|
||||
Object.defineProperty(XMLHttpRequest.prototype, "status", {
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 200,
|
||||
})
|
||||
XMLHttpRequest.prototype.open = vi.fn() as unknown as typeof origOpen
|
||||
XMLHttpRequest.prototype.send = vi.fn(function (this: XMLHttpRequest) {
|
||||
// 下一 tick 触发 onload(模拟 XHR 异步完成)
|
||||
setTimeout(() => this.onload?.(new ProgressEvent("load")), 0)
|
||||
}) as unknown as typeof origSend
|
||||
const file = new File(["x"], "x.mp4", { type: "video/mp4" })
|
||||
const result = await uploadAssetDirect({ file, library_id: "lib-1" })
|
||||
expect(result.duplicated).toBeFalsy()
|
||||
expect(result.asset_id).toBe("new-asset")
|
||||
const completeCalls = mockPost.mock.calls.filter(
|
||||
([u]: [string]) => u === "/upload/direct/complete",
|
||||
)
|
||||
expect(completeCalls).toHaveLength(1)
|
||||
XMLHttpRequest.prototype.open = origOpen
|
||||
XMLHttpRequest.prototype.send = origSend
|
||||
if (origSetReadyState) {
|
||||
Object.defineProperty(XMLHttpRequest.prototype, "readyState", origSetReadyState)
|
||||
}
|
||||
if (origStatus) {
|
||||
Object.defineProperty(XMLHttpRequest.prototype, "status", origStatus)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("getIngestJob", () => {
|
||||
it("should resolve successfully", async () => {
|
||||
await expect(getIngestJob("test-jobId")).resolves.not.toThrow()
|
||||
|
||||
Reference in New Issue
Block a user