fix(m168): 复审 r1 五项 —— 修红的 integration target、独立失败域、整体时限
复审 r1(p1-1/fix-then-merge)五项全改:
1. **p1-1 CI 会红的 4 条 integration test**(`crates/core/tests/setting/`,我上一轮只跑了 `--lib`,
scope 漏掉了覆盖 schema 版本号的目录式 target):
- `java_install_keys` / `isolation_keys` / `appearance_keys`:版本断言 1.6.0 → 1.7.0(M168 的
`ui.font_cdn`),并写明「每加一批键推一次 minor 是纪律」。
- `update_keys::a_read_only_launcher_config_never_retires_the_legacy_file`:夹具从**写死
1.7.0** 改成 `launcher_version().minor + 1` 经 `SchemaRef::url()` 生成。写死数字的版本一推
这条守卫就变成「同版本」⇒ 文件可写 ⇒ 迁移真的执行 ⇒ 旧文件被退役,而断言还绿着(用户数据
守卫静默失效)。相对推导不会过期。
2. **p2-1 备用镜像不备用**:`cdn` 与 `fastly` 同属 Fastly(都 CNAME 到 jsdelivr.map.fastly.net),
换掉。现在首选 `gcore.jsdelivr.net`(Cloudflare,独立失败域),二选 `cdn.jsdelivr.net`
(Fastly)。注释里放了实测表(本机 + 复审机两份数据、字节数、sha256、IPv6 慢路径),
并写清排序依据(Fastly 侧 IPv6 实测 67 KB/s ⇒ 丢掉 4 分钟;Cloudflare 侧两次都完整下完)。
3. **p2-2 整体时限**:`core::download::font` 新增 `ATTEMPT_DEADLINE = 90 s` /
`TOTAL_DEADLINE = 180 s`,落在本模块自己的候选循环里(不动引擎全体语义):每次尝试
`min(单次上限, 剩余总预算)`,超时归 `Network` 档。新增守卫
`a_trickling_connection_is_cut_by_the_deadline`(回环服务端每 100 ms 挤 1 字节、预算 300 ms)。
顺带修掉一个真 bug:`tokio::time::timeout` 在运行时外构造会 panic(5 条既有用例当场抓到),
现在整段包进 `block_on(async { … })`。UI 文案改成「网络不通或太慢(超时)」,不校验失败混。
4. **p2-3 说 `Source::PendingPin` 的两处**:`fonts/cjk.rs` 的模块文档已改;`ui/lang.rs::log_cjk`
那句「D28 的下载通道还是 PendingPin」(在下载已发起之后打印,等于当面否定本功能)改成
「已按 D28 发起下载,见 [font] cjk-download … 与设置页那一行」。全仓再扫,只剩注释里的历史说明。
5. **p2-4 假守卫**:判据抽成纯函数 `install::plan(strategy, current) -> Step`(`Skip` / `Apply` /
`Start`),`after_probe` 只执行。旧的空转用例换成打真判据的打表用例;变异证明:删掉
`Skip` 那一臂 ⇒ `a_started_or_finished_install_is_not_restarted` 红(已实跑)。
次要项也一并处理:`from_cache` 改成**本次是否真的命中缓存**(`CdnFetcher::was_cached()`,
`has_cached()` 降级为诊断字段 `cache_present=`);`FontSpec` 的 URL 口径收紧为「非回环必须
https」(`is_acceptable_url` + 守卫);`ui.font_cdn` 写进状态行 hint;文档里的 17.0 MB → 16.9 MB。
`download/font.rs` 拆出 `font/spec.rs` 守 400 行。
验证(这台机器上单个 800 MB 测试 exe 链接要 10 分钟,链接期间文件被 Defender 扫描,故耗时很长):
- `cargo test -p unlucky-core --all-targets` → **1188 passed / 0 failed**(16 个 target,含
`setting` 那个 115 条、上一轮红 4 条的 integration target)
- `cargo test -p unlucky-i18n` → 31 passed / 0 failed
- `cargo test -p unlucky-app-iced --lib` → 685 passed / 0 failed
- `cargo clippy -p unlucky-i18n -p unlucky-core -p unlucky-app-iced --all-targets -- -D warnings` → 干净
- `cargo fmt --all -- --check` → 干净;全仓受检文件行数最大 388(<400)
This commit is contained in:
1 parent
449ded2cb7
commit
875b792206
17 files changed
+512
-170
No files matched your search
@@ -131,8 +131,8 @@ fn appearance_keys_are_all_ai_writable_and_registered() {
|
||||
fn schema_registration_shape_is_right() {
|
||||
assert_eq!(
|
||||
launcher_version().minor,
|
||||
6,
|
||||
"1.6.0 登记 M161 的自更新两键(update.auto_check / update.channel)"
|
||||
7,
|
||||
"1.7.0 登记 M168 的 ui.font_cdn(1.6.0 是 M161 的自更新两键)"
|
||||
);
|
||||
let schema = launcher_schema();
|
||||
assert_eq!(
|
||||
|
||||
@@ -128,10 +128,9 @@ fn overrides_key_is_an_enum_whitelist() {
|
||||
|
||||
#[test]
|
||||
fn schema_versions_register_the_new_keys_without_migration() {
|
||||
// 1.6.0 登记 M161 的自更新两键(`update.auto_check` / `update.channel`;
|
||||
// 1.5.0 = M116 窗口圆角,1.4.0 = M91 外观下层三键,1.3.0 = D17「外观(高级)」,
|
||||
// 1.2.0 = D23 的 JDK 落点/优先级键)。
|
||||
assert_eq!(launcher_version(), SchemaVersion::new(1, 6, 0));
|
||||
// 1.7.0 登记 M168 的 `ui.font_cdn`(1.6.0 登记 M161 的自更新两键,1.5.0 = M116 窗口圆角,
|
||||
// 1.4.0 = M91 外观下层三键,1.3.0 = D17「外观(高级)」,1.2.0 = D23 的 JDK 落点/优先级键)。
|
||||
assert_eq!(launcher_version(), SchemaVersion::new(1, 7, 0));
|
||||
assert_eq!(instance_version(), SchemaVersion::new(1, 1, 0));
|
||||
assert_eq!(launcher_schema().id(), SchemaId::LAUNCHER);
|
||||
// major 仍是 1:迁移链(按 major 走)不需要新步骤,老文件缺键即默认值。
|
||||
|
||||
@@ -66,8 +66,10 @@ fn install_root_accepts_a_path_and_keeps_empty_as_unset() {
|
||||
|
||||
#[test]
|
||||
fn schema_version_bumps_minor_only_so_no_migration_step_is_needed() {
|
||||
// 1.6.0 = M161 的自更新两键(此前 1.5.0 是 M116 窗口圆角)。
|
||||
assert_eq!(launcher_version(), SchemaVersion::new(1, 6, 0));
|
||||
// 1.7.0 = M168 的中文字体下载地址覆盖键(`ui.font_cdn`;此前 1.6.0 是 M161 的自更新两键,
|
||||
// 1.5.0 是 M116 窗口圆角)。每加一批键推一次 minor 是**纪律**,不是巧合:
|
||||
// 老版本读新文件会判 `ReadOnlyPreserveSchema`,所以版本号本身就是「新键存在」的对外声明。
|
||||
assert_eq!(launcher_version(), SchemaVersion::new(1, 7, 0));
|
||||
assert_eq!(
|
||||
launcher_version().major,
|
||||
1,
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
|
||||
use serde_json::json;
|
||||
use unlucky_core::setting::document::{RenderMode, SettingDocument};
|
||||
use unlucky_core::setting::keys::launcher_schema;
|
||||
use unlucky_core::setting::keys::update::UPDATE_CHANNELS;
|
||||
use unlucky_core::setting::keys::{launcher_schema, launcher_version};
|
||||
use unlucky_core::setting::schema::{SchemaId, SchemaRef, SchemaVersion};
|
||||
use unlucky_core::setting::spec::{Sensitivity, ValueKind};
|
||||
use unlucky_core::setting::store::SettingStore;
|
||||
use unlucky_core::setting::update_prefs::{
|
||||
@@ -286,16 +287,32 @@ fn the_receipt_gate_skips_a_replayed_source_byte_for_byte() {
|
||||
|
||||
/// **`Refused`:主配置不可写时不动旧文件**(唯一有用户数据风险的分支)。
|
||||
///
|
||||
/// 造法:主配置的 `$schema` 写成**更高的 minor**(1.7.0 > 1.6.0)⇒ `SchemaCompat` 判
|
||||
/// `ReadOnlyPreserveSchema` ⇒ `FileAccess::ReadOnly` ⇒ `can_save()` false。
|
||||
/// 造法:主配置的 `$schema` 写成**比当前更高的 minor**(`launcher_version().minor + 1`)⇒
|
||||
/// `SchemaCompat` 判 `ReadOnlyPreserveSchema` ⇒ `FileAccess::ReadOnly` ⇒ `can_save()` false。
|
||||
///
|
||||
/// **这里刻意不写死数字**(M168 复审 p1-1):上一版把「更高」写成了字面量 `1.7.0`,于是
|
||||
/// `launcher_version()` 一推到 1.7.0 这个夹具就变成「同版本」——文件可写 ⇒ 迁移真的执行 ⇒
|
||||
/// 旧文件被退役,`Refused` 分支再也走不到,而**断言还在,绿着**:一条守护用户数据的用例
|
||||
/// 就这样静默失效了。相对推导(current + 1)不会过期,版本往后推多少次它都还是「更高一档」。
|
||||
/// 抓得住:把「写不进去」当成「迁完了」(旧文件被改名,用户的值两边都没有了)。
|
||||
#[test]
|
||||
fn a_read_only_launcher_config_never_retires_the_legacy_file() {
|
||||
// 比当前更高一档的 minor:`SchemaRef::url()` 是 `$schema` 的唯一产地,不手拼字符串。
|
||||
let newer = SchemaRef {
|
||||
id: SchemaId::LAUNCHER,
|
||||
version: SchemaVersion::new(
|
||||
launcher_version().major,
|
||||
launcher_version().minor + 1,
|
||||
launcher_version().patch,
|
||||
),
|
||||
};
|
||||
let newer_schema = newer.url();
|
||||
|
||||
let temp = TempDir::new("m161-refused");
|
||||
temp.write(
|
||||
"config/launcher.json",
|
||||
&json!({
|
||||
"$schema": "https://schemas.unlucky-launcher.dev/ull/launcher/1.7.0",
|
||||
"$schema": newer_schema,
|
||||
"schemaVersion": 1
|
||||
})
|
||||
.to_string(),
|
||||
@@ -323,9 +340,9 @@ fn a_read_only_launcher_config_never_retires_the_legacy_file() {
|
||||
);
|
||||
// 不写收据(没迁成就不该有收据)。
|
||||
assert!(!temp.exists(&format!("config/{RECEIPT_FILE}")));
|
||||
// 主配置一个字都没改(还是那份 1.7.0)。
|
||||
// 主配置一个字都没改(还是那份「更高 minor」的 `$schema`)。
|
||||
let text = temp.read("config/launcher.json");
|
||||
assert!(text.contains("1.7.0"), "{text}");
|
||||
assert!(text.contains(&newer_schema), "主配置被改了:{text}");
|
||||
assert!(!text.contains("auto_check"), "只读文件不许被写:{text}");
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user