From 9088be360f7f06e94fbfd2c487ee384dc653cdbc Mon Sep 17 00:00:00 2001 From: saas-backend-agent Date: Sun, 6 Sep 2026 12:23:28 +0800 Subject: [PATCH] =?UTF-8?q?test(#1714):=20=E8=A1=A5=20prepare=20=E5=8E=BB?= =?UTF-8?q?=E9=87=8D=E8=BE=B9=E7=95=8C=E5=88=86=E6=94=AF=E2=80=94=E2=80=94?= =?UTF-8?q?=E9=A2=84=E5=BB=BA=E5=A4=B1=E8=B4=A5=E9=99=8D=E7=BA=A7=E3=80=81?= =?UTF-8?q?update=E5=BC=82=E5=B8=B8=E5=90=9E=E6=8E=89=E3=80=81PROCESSING?= =?UTF-8?q?=20hash=E4=B8=8D=E5=90=8C=E8=B7=B3=E8=BF=87/=E7=9B=B8=E5=90=8C?= =?UTF-8?q?=E5=91=BD=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/unit/test_prepare_dedup_1714.py | 100 ++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/tests/unit/test_prepare_dedup_1714.py b/tests/unit/test_prepare_dedup_1714.py index acc96df97..cb0ad9ff8 100644 --- a/tests/unit/test_prepare_dedup_1714.py +++ b/tests/unit/test_prepare_dedup_1714.py @@ -369,3 +369,103 @@ def test_create_pending_asset_creates_when_no_match(): assert result.file_hash == "newhash" assert result.client_upload_id == "newcuid" assert repo.saved == 1 + + +# --------------------------------------------------------------------------- +# 兜底去重:PROCESSING 占位 hash 不同时跳过 +# --------------------------------------------------------------------------- + + +def test_filename_fallback_skips_processing_with_different_hash(): + """PROCESSING/UPLOADING 占位记录仅当 hash 一致(或占位无 hash)才命中;hash 不同跳过。""" + repo = _FakeAssetRepo() + repo.create(_make_pending(id="p1", file_hash="oldhash")) + repo.find_recent_active_by_library_and_name = lambda **kw: repo.assets["p1"] + result = upload_route._find_duplicate_asset( + repo, + library_id="lib-1", + file_hash="differenthash", # 新上传内容不同 + client_upload_id="", + filename="test.mp4", + file_size=1024, + ) + assert result is None + + +def test_filename_fallback_matches_processing_with_same_hash(): + """PROCESSING 占位 hash 与请求一致时命中(重试场景)。""" + repo = _FakeAssetRepo() + repo.create(_make_pending(id="p1", file_hash="samehash")) + repo.find_recent_active_by_library_and_name = lambda **kw: repo.assets["p1"] + result = upload_route._find_duplicate_asset( + repo, + library_id="lib-1", + file_hash="samehash", + client_upload_id="", + filename="test.mp4", + file_size=1024, + ) + assert result is not None + assert result.id == "p1" + + +# --------------------------------------------------------------------------- +# prepare 预建失败降级:不阻塞签名 +# --------------------------------------------------------------------------- + + +@pytest.mark.asyncio +async def test_prepare_pending_asset_create_failure_degrades_gracefully(): + """预建 asset 抛异常时,prepare 仍正常返回签名(duplicated=False, asset_id 空)。""" + + class _BrokenRepo(_FakeAssetRepo): + def create(self, asset): + raise RuntimeError("db down") + + repo = _BrokenRepo() + req = SimpleNamespace( + project_id="p-1", + library_id="lib-1", + filename="test.mp4", + content_type="video/mp4", + file_size=1024, + file_hash="abc123", + client_upload_id="cuid-1", + ) + resp = await upload_route.prepare_direct_upload( + request=req, + authenticated_user=_user(), + project_repository=_StubProjectRepo(_FIXTURE_PROJECT), + asset_library_repository=_StubLibraryRepo(_FIXTURE_LIBRARY), + asset_repository=repo, + storage_service=_storage(), + ) + assert resp.duplicated is False + assert resp.skip_transfer is False + assert resp.asset_id == "" # 预建失败,降级无 asset_id + assert resp.upload_url != "" # 签名仍正常返回 + + +def test_create_pending_asset_update_failure_swallowed(): + """复用占位记录时字段补齐 update 抛异常被吞掉,不阻塞返回。""" + + class _UpdateBrokenRepo(_FakeAssetRepo): + def update(self, asset): + raise RuntimeError("db down") + + repo = _UpdateBrokenRepo() + repo.create(_make_pending(file_hash="abc123", client_upload_id="", id="p1")) + result = upload_route._create_pending_asset( + asset_repository=repo, + project_id="p-1", + library_id="lib-1", + storage_key="uploads/new/test.mp4", + filename="test.mp4", + mime_type="video/mp4", + user_id="user-1", + file_hash="abc123", + client_upload_id="cuid-new", + file_size=1024, + ) + assert result.id == "p1" # 仍复用,不抛异常 + assert repo.saved == 1