"""服务端分发产物生成测试。""" import plistlib from unittest.mock import patch from backend.services.distribution import ( _artifact_stem, delete_published_artifacts, _write_distribution_files, _write_download_page, _write_manifest, publish_ipa, ) def test_distribution_artifact_name_contains_sanitized_branch(): assert _artifact_stem({"APPID": "100", "VERSION": "2.0.0.0", "SOURCE_BRANCH": "feature/pay-v2", "BUILD_TYPE": "Ad_Hoc"}) == "100_2_0_0_0_feature_pay-v2_adhoc" assert _artifact_stem({"APPID": "100", "VERSION": "2.0.0.0"}) == "100_2_0_0_0" def test_distribution_files_use_current_service_config(tmp_path): ipa = tmp_path / "source.ipa" ipa.write_bytes(b"ipa") config = { "APPID": "100", "VERSION": "2.0.0", "APPID_NAME": "Test App", "BUNDLE_ID": "com.example.test", } ipa_file, manifest, html = _write_distribution_files(config, ipa, tmp_path / "distribution") _write_manifest(config, manifest, "https://files.example.com/app.ipa") _write_download_page(config, html, "https://files.example.com/app.plist") with manifest.open("rb") as f: plist = plistlib.load(f) assert ipa_file.read_bytes() == b"ipa" assert plist["items"][0]["metadata"]["bundle-identifier"] == "com.example.test" assert "itms-services://" in html.read_text(encoding="utf-8") def test_app_store_distribution_uploads_only_ipa(tmp_path): ipa = tmp_path / "source.ipa" ipa.write_bytes(b"app-store-ipa") config = { "APPID": "100", "VERSION": "2.0.0", "BUILD_TYPE": "App_Store", "SOURCE_BRANCH": "main", "OSS_FLODER": "readoor", "_upload_config": {"mode": "oss", "oss": {}}, } with patch( "backend.services.distribution._upload_oss", return_value={".ipa": "https://files.example.com/readoor/iOS/100_2_0_0_main_appstore.ipa"}, ) as upload: download_url, qr_path = publish_ipa(config, ipa, tmp_path / "build") uploaded_files = upload.call_args.args[1] assert len(uploaded_files) == 1 assert uploaded_files[0][0].suffix == ".ipa" assert download_url.endswith("100_2_0_0_main_appstore.ipa") assert qr_path == "" def test_adhoc_distribution_uploads_qrcode(tmp_path): ipa = tmp_path / "source.ipa" ipa.write_bytes(b"ad-hoc-ipa") config = { "APPID": "100", "VERSION": "2.0.0", "BUILD_TYPE": "Ad_Hoc", "SOURCE_BRANCH": "dev", "OSS_FLODER": "readoor", "_upload_config": {"mode": "oss", "oss": {}}, } def upload_files(_upload_config, files): local_path, remote_path = files[0] return {local_path.suffix: f"https://files.example.com/{remote_path}"} with patch("backend.services.distribution._upload_oss", side_effect=upload_files) as upload: download_url, qr_url = publish_ipa(config, ipa, tmp_path / "build") assert download_url.endswith("100_2_0_0_dev_adhoc.html") assert qr_url.endswith("100_2_0_0_dev_adhoc.png") assert [call.args[1][0][0].suffix for call in upload.call_args_list] == [ ".ipa", ".plist", ".html", ".png", ] def test_delete_adhoc_artifacts_deletes_all_remote_files(): config = {"APPID": "100", "VERSION": "2.0.0.0", "SOURCE_BRANCH": "main", "BUILD_TYPE": "Ad_Hoc", "OSS_FLODER": "readoor"} with patch("backend.services.distribution._delete_oss") as delete: delete_published_artifacts(config, {"mode": "oss", "oss": {}}) assert delete.call_args.args[1] == [ "readoor/iOS/100_2_0_0_0_main_adhoc.ipa", "readoor/iOS/100_2_0_0_0_main_adhoc.plist", "readoor/iOS/100_2_0_0_0_main_adhoc.html", "readoor/iOS/100_2_0_0_0_main_adhoc.png", ] def test_delete_uses_saved_url_for_legacy_artifact_name(): # 旧任务已有 SOURCE_BRANCH 快照,但上传时仍采用未带分支的旧命名。 # 不能再根据当前命名规则推算,否则 OSS 会对不存在的键返回成功。 config = { "APPID": "100", "VERSION": "2.0.0.0", "SOURCE_BRANCH": "main", "BUILD_TYPE": "Ad_Hoc", "OSS_FLODER": "readoor", } with patch("backend.services.distribution._delete_oss") as delete: delete_published_artifacts( config, {"mode": "oss", "oss": {"base_url": "https://files.example.com"}}, "https://files.example.com/readoor/iOS/100_2_0_0_0.html", ) assert delete.call_args.args[1] == [ "readoor/iOS/100_2_0_0_0.ipa", "readoor/iOS/100_2_0_0_0.plist", "readoor/iOS/100_2_0_0_0.html", "readoor/iOS/100_2_0_0_0.png", ]