fix(core): bmclapi 库镜像补 /maven;install 进度行改说实话
D1(high):mirrors.json 的 bmclapi-libraries 少了 inject,官方
libraries.minecraft.net/<path> 被重写成镜像根 + <path>(BMCLAPI 的 maven 仓库挂在
/maven 下),实测 70/70 个库全 404、全部回落官方源(单请求 EMA 6.3 s)。本轮实测:
guava:32.1.2-jre 无 /maven → 404 / 9 B;带 /maven → 200(2 次 302)/ 3041591 B,
sha1 与官方逐字节一致。补法与 bmclapi-assets-objects 的 /assets 同一机制(inject),
不把 /maven 拼进 to(to 是镜像根)。
守卫两道,抓不同的东西:
- 形态:凡 from 指向 maven 仓库的规则,to+inject 必须以 /maven 结尾(并点名覆盖的
5 条规则 id,删/改名都会红);
- 行为:4 个真实官方 maven 根展开后必须逐字等于 /maven/<子路径>。
原有 prefix_rule_preserves_sub_path 的期望值曾把 D1 的 bug 钉成期望,一并改正。
变异(删掉 inject)实测三条同时红,恢复后 mirrors 14 passed。
D11(low):进度回调只累加「处理到第几个文件」,还打「下载 {done}/{total}」,
重装同版本(全部已就绪)时会连打 3961 行「下载」而一个字节都没下。拆出
install/progress.rs:计数全部来自 FileOutcome.status(Downloaded/Skipped/Failed),
下载数为 0 时人读行不出现「下载」二字(改说「已就绪 d/t(跳过 N 个)」),--json 的
progress 事件补 downloaded/skipped/failed。用例构造 96 个全 Skipped ⇒ 断言每行都不含
「下载」且末行为「已就绪 96/96(跳过 96 个)」;变异(退回旧文本)实测红。
其它镜像表(assets / jar / version_manifest / 索引 / fabric / forge)的 inject 形状
实测一致,另有 liteloader 目标路径 404、quilt maven 无规则两条【不同类】观察,
不在本轮范围,报告里交回 tower。
This commit is contained in:
1 parent
391ebf88b7
commit
d8ca411117
8 files changed
+414
-81
No files matched your search
@@ -117,7 +117,8 @@
|
||||
{
|
||||
"id": "bmclapi-libraries",
|
||||
"from": "https://libraries.minecraft.net",
|
||||
"to": "https://bmclapi2.bangbang93.com"
|
||||
"to": "https://bmclapi2.bangbang93.com",
|
||||
"inject": "/maven"
|
||||
},
|
||||
{
|
||||
"id": "bmclapi-assets-objects",
|
||||
|
||||
@@ -30,15 +30,115 @@ fn prefix_rule_preserves_sub_path() {
|
||||
.expect("libraries 规则缺失");
|
||||
let candidate = rule.apply(LIBRARIES_URL).expect("重写失败");
|
||||
assert_eq!(candidate.source, "bmclapi");
|
||||
// 子路径逐字保留(`/maven` 是镜像侧的固定前缀,不属于子路径)。
|
||||
//
|
||||
// M210/D1:这条断言此前写的是「换成 `https://bmclapi2.bangbang93.com` 就完事」,等于把
|
||||
// **丢 inject 的 bug 钉成了期望**——实测 70/70 个库 404(无 `/maven` 回 404 + 9 B,
|
||||
// 带 `/maven` 回 200、sha1 与官方逐字节一致)。现在把 `/maven` 写进期望值。
|
||||
assert_eq!(
|
||||
candidate.url,
|
||||
LIBRARIES_URL.replace(
|
||||
"https://libraries.minecraft.net",
|
||||
"https://bmclapi2.bangbang93.com"
|
||||
"https://bmclapi2.bangbang93.com/maven"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// **守卫(M210/D1)**:每一条「给 libraries 用」的镜像规则,镜像前缀都必须带 `/maven`。
|
||||
///
|
||||
/// 官方库域名(`libraries.minecraft.net`)与各 loader 的 maven 在 BMCLAPI 上统一挂在 `/maven`
|
||||
/// 下;`apply()` 是纯前缀替换,`to` 里少了这一段就会把 `com/google/guava/...` 直接拼到镜像根上。
|
||||
///
|
||||
/// 抓得住:删掉/改错任一条库镜像规则的 `inject`(本用例对 `bmclapi-libraries` 的变异会红)。
|
||||
/// 抓不住:`/maven` **写歪**(如 `/maven2`、`/maven/` 之外的等价路径)只能靠行为用例
|
||||
/// [`library_urls_expand_to_the_maven_subpath_on_bmclapi`];路径结构本就不同的镜像表(资源对象走
|
||||
/// `/assets`、元数据走 `/fabric-meta`)不在此判据内;新增但 `from` 不像 maven 仓库的库镜像也不在此列。
|
||||
#[test]
|
||||
fn every_library_mirror_rule_carries_the_maven_segment() {
|
||||
let table = MirrorTable::builtin();
|
||||
// 判据:「给 libraries 用」= `from` 指向 maven 仓库(host/路径里带 maven,或就是 Mojang 库域名)。
|
||||
// 新增一条库镜像规则时这条自动纳入,不必改测试。
|
||||
fn serves_maven(from: &str) -> bool {
|
||||
host_of(from).unwrap_or_default().contains("maven")
|
||||
|| from.contains("maven")
|
||||
|| host_of(from) == Some("libraries.minecraft.net")
|
||||
}
|
||||
// 判据覆盖的规则 id(内置表里就是这 5 条;`bmclapi-liteloader` 的 `from` 不像 maven 仓库,不在列,
|
||||
// 它指向的镜像路径另有一个「镜像上不存在」的观察,见 M210 报告的 §5)。
|
||||
const EXPECTED: [&str; 5] = [
|
||||
"bmclapi-libraries",
|
||||
"bmclapi-forge-maven",
|
||||
"bmclapi-forge-maven-net",
|
||||
"bmclapi-neoforge",
|
||||
"bmclapi-fabric-maven",
|
||||
];
|
||||
let mut checked: Vec<&str> = Vec::new();
|
||||
for rule in table.rules.iter().filter(|rule| serves_maven(&rule.from)) {
|
||||
let prefix = format!("{}{}", rule.to, rule.inject);
|
||||
assert!(
|
||||
prefix.ends_with("/maven"),
|
||||
"规则 {} 的镜像前缀 `{prefix}` 少了 `/maven`:官方 `{}` 在镜像上挂在 `/maven/` 下,\
|
||||
丢了它整张表 404(M210/D1)",
|
||||
rule.id,
|
||||
rule.from
|
||||
);
|
||||
checked.push(rule.id.as_str());
|
||||
}
|
||||
// 判据失效(规则被改名/改形/删掉)时这里红:期望的规则一条都不能漏。
|
||||
for expected in EXPECTED {
|
||||
assert!(
|
||||
checked.contains(&expected),
|
||||
"库镜像规则 {expected} 没被形态判据覆盖到(被改名/改形/删掉了?):{checked:?}"
|
||||
);
|
||||
}
|
||||
// 多出来的(新增 maven 规则)也得登记进 EXPECTED,否则说明它绕过了这道判据的意图审查。
|
||||
assert_eq!(
|
||||
checked.len(),
|
||||
EXPECTED.len(),
|
||||
"库镜像规则数与预期不符(新增/删除了规则?):{checked:?}"
|
||||
);
|
||||
}
|
||||
|
||||
/// **行为守卫(M210/D1)**:真实库 URL 展开后必须落在镜像的 `/maven/<子路径>` 上。
|
||||
///
|
||||
/// 与上一条互为补充:那条看规则形态,这条看用户实际会请求到的 URL。
|
||||
/// 抓得住:`inject` 丢失、`to` 里手写 `/maven` 被删、或 `from`/`to` 被改成拼不出 `/maven` 的形态。
|
||||
/// 抓不住:只覆盖这 4 个官方 maven 根(各处未必都写全);镜像侧真实可达性(要网络,留给 e2e)。
|
||||
#[test]
|
||||
fn library_urls_expand_to_the_maven_subpath_on_bmclapi() {
|
||||
let table = MirrorTable::builtin();
|
||||
let region = RegionProfile::mirror_first(0);
|
||||
let cases = [
|
||||
(
|
||||
LIBRARIES_URL,
|
||||
"https://bmclapi2.bangbang93.com/maven/com/google/guava/guava/32.0.0/guava-32.0.0.jar",
|
||||
),
|
||||
(
|
||||
"https://maven.fabricmc.net/net/fabricmc/fabric-loader/0.15.11/fabric-loader-0.15.11.jar",
|
||||
"https://bmclapi2.bangbang93.com/maven/net/fabricmc/fabric-loader/0.15.11/fabric-loader-0.15.11.jar",
|
||||
),
|
||||
(
|
||||
"https://maven.minecraftforge.net/net/minecraftforge/forge/1.20.1-47.2.0/forge-1.20.1-47.2.0-installer.jar",
|
||||
"https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/1.20.1-47.2.0/forge-1.20.1-47.2.0-installer.jar",
|
||||
),
|
||||
(
|
||||
"https://maven.neoforged.net/releases/net/neoforged/neoforge/21.1.80/neoforge-21.1.80-installer.jar",
|
||||
"https://bmclapi2.bangbang93.com/maven/net/neoforged/neoforge/21.1.80/neoforge-21.1.80-installer.jar",
|
||||
),
|
||||
];
|
||||
for (official, expected) in cases {
|
||||
let candidates = table.expand(official, ResourceKind::Library, ®ion);
|
||||
let mirror = candidates
|
||||
.iter()
|
||||
.find(|candidate| candidate.source == "bmclapi")
|
||||
.unwrap_or_else(|| panic!("{official} 没有 bmclapi 候选:{candidates:?}"));
|
||||
assert_eq!(
|
||||
mirror.url, expected,
|
||||
"库镜像 URL 形状不对(官方 {official})"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn asset_rule_injects_path_prefix() {
|
||||
let table = MirrorTable::builtin();
|
||||
|
||||
Reference in new issue
Block a user