fix(sync): 移除多线程下载并补齐staging复用回归

This commit is contained in:
2026-07-24 10:34:58 +08:00
parent 3f5d2a8da7
commit a729615a48
11 changed files with 173 additions and 257 deletions
@@ -330,6 +330,75 @@ fn official_update_second_run_audits_existing_resources_before_reuse() {
assert!(version_state.in_progress_version.is_none());
}
#[test]
fn official_update_reuses_failed_staging_after_interrupted_download() {
let harness = TestHarness::new();
let bootstrap = harness.fetch_bootstrap();
let fetcher = harness.fetcher();
let server_info_url = bootstrap
.game_main_config
.server_info_data_url
.as_ref()
.unwrap()
.clone();
let server_info_bytes = fetcher.fetch_bytes(&server_info_url).unwrap();
let server_info = YostarJpServerInfo::from_slice(&server_info_bytes).unwrap();
let discovery = server_info
.discovery_plan(
bootstrap
.game_main_config
.default_connection_group
.as_deref()
.unwrap(),
&bootstrap.game_config.game_latest_version,
&verified_official_platforms(),
)
.unwrap();
let inventory = fetch_platform_inventory(&fetcher, &discovery);
let plan = build_official_pull_plan_from_platform_inventory(discovery, inventory);
let all_urls = plan.all_urls().unwrap();
let resume_url = all_urls
.iter()
.find(|url| url.ends_with("/Windows_PatchPack/catalog_StandaloneWindows64.zip"))
.expect("fixture plan should contain Windows addressables catalog zip")
.clone();
let resources_assets_path = harness.temp.path().join("resources.assets");
let zip_fixture = harness.temp.path().join("downloaded.zip");
let curl_failure_state = harness.temp.path().join("curl-failure.state");
write_executable(
&harness.curl_script,
&official_curl_script(
&harness.curl_log,
&zip_fixture,
&resources_assets_path,
fs::metadata(&resources_assets_path).unwrap().len() as usize,
TEST_LAUNCHER_MANIFEST_SOURCE,
Some(&curl_failure_state),
),
);
let config = harness.sync_config("failed-staging-output");
let first_error = OfficialUpdateService::new().run(&config).unwrap_err();
assert!(first_error.to_string().contains("quarantine"));
assert!(first_error.to_string().contains("simulated failure"));
let first_log = fs::read_to_string(&harness.curl_log).unwrap();
assert!(first_log.contains(&resume_url));
let report = OfficialUpdateService::new().run(&config).unwrap();
assert_eq!(report.update_status, OfficialUpdateStatus::Downloaded);
let second_log = fs::read_to_string(&harness.curl_log).unwrap();
assert_eq!(second_log.matches(&resume_url).count(), 1);
let version_state = read_version_state(&report.version_state_path)
.unwrap()
.unwrap();
assert!(version_state.failed_versions.is_empty());
assert!(version_state.in_progress_version.is_none());
assert!(version_state.current_completed_version.is_some());
}
struct TestHarness {
temp: TempDir,
curl_script: std::path::PathBuf,
@@ -362,6 +431,7 @@ impl TestHarness {
&resources_assets_path,
resources_assets.len(),
manifest_source,
None,
),
);
@@ -478,11 +548,16 @@ fn official_curl_script(
resources_assets_fixture: &Path,
resources_assets_size: usize,
manifest_source: &str,
failure_state: Option<&Path>,
) -> String {
let failure_state = failure_state
.map(shell_quote)
.unwrap_or_else(|| "''".to_string());
format!(
r#"#!/usr/bin/env bash
set -euo pipefail
log={}
failure_state={failure_state}
printf '%s\n' "$*" >> "$log"
output=""
url=""
@@ -522,6 +597,23 @@ emit_resources_assets_fixture() {{
cp {} "$output"
}}
maybe_fail_once() {{
if [[ -z "$failure_state" ]]; then
return 0
fi
local attempt=0
if [[ -f "$failure_state" ]]; then
attempt="$(cat "$failure_state")"
fi
attempt=$((attempt + 1))
mkdir -p "$(dirname "$failure_state")"
printf '%s' "$attempt" > "$failure_state"
if [[ "$attempt" -le 3 ]]; then
echo "simulated failure for $url attempt=$attempt" >&2
exit 22
fi
}}
if [[ "$url" == "https://api-launcher-jp.yo-star.com/api/launcher/game/config" ]]; then
cat <<'JSON'
{{"code":200,"message":"ok","data":{{"game_latest_version":"{launcher_latest_version}","game_latest_file_path":"{launcher_latest_file_path}"}}}}
@@ -573,6 +665,7 @@ elif [[ "$url" == "{addressables_root}/MediaResources/Catalog/MediaCatalog.bytes
elif [[ "$url" == "{addressables_root}/MediaResources/Catalog/MediaCatalog.hash" ]]; then
emit_text "{android_media_catalog_hash}"
elif [[ -n "$output" && "$url" == "{addressables_root}/"* ]]; then
maybe_fail_once
filename="${{url##*/}}"
if [[ "$filename" == *.zip ]]; then
emit_zip_fixture
@@ -604,6 +697,7 @@ fi
windows_media_catalog_hash = xxhash32(b"GameData\\Audio\\VOC_JP\\JP_Airi_Win.zip"),
android_bundle_catalog_hash = xxhash32(b"FullPatch_001.zip"),
android_media_catalog_hash = xxhash32(b"GameData\\Audio\\VOC_JP\\JP_Airi_Android.zip"),
failure_state = failure_state,
)
}