fix(app-iced): 探针与字体测试的子进程改走 platform::child::quiet(M272)

`cargo test --workspace` 在合并 tip f8d83d1 上被 child_quiet_guard 抓住两处绕开
`platform::child::quiet` 的子进程构造:

① `platform/motion.rs` 的 OS「减少动效」探针(M256 新增,Linux gsettings / macOS
   defaults)是产品代码真回归:`run()` 里裸 `Command::new(program)`。改走 `quiet(program)`。
   `quiet` 返回的就是普通 `Command`,`.spawn()` 的 `Child` 仍归 `run` 自己,所以
   **300ms 超时 + 超时 kill + wait 一个字没丢**;`OnceLock` 缓存、单调用点、不在帧路径
   这三条性质也原样保留(这次只换了构造器)。
② `fonts/tests.rs` 里重起自身 test binary 的那处同样改走 `quiet`;`.output()` 的管道
   语义不变(已实测子进程断言仍然「1 passed」)。没有往 ALLOWED_ROLES 加白。
This commit is contained in:
AskaEth committed 2026-11-12 11:28:56 +08:00
1 parent f8d83d1f77
commit 634955d323
2 files changed
+23 -3

No files matched your search

+5 -1
View File
@@ -270,10 +270,14 @@ fn evaluation_starts_no_download() {
} }
/// 用 `current_exe()` 把本 test binary 再起一次,只跑 [`resolving_fonts_never_starts_a_download`]。 /// 用 `current_exe()` 把本 test binary 再起一次,只跑 [`resolving_fonts_never_starts_a_download`]。
///
/// 子进程经 `unlucky_core::platform::child::quiet` 起(M272):仓规是全树硬约束,测试代码不是
/// 例外——这条 test binary 本身是控制台程序,父进程将来若换到 GUI 侧(或 CI 用别的方式直接跑
/// 二进制)也照样不该新建窗口。`quiet` 只动创建 flag,`.output()` 的管道语义一个字不变。
fn rerun_in_own_process() { fn rerun_in_own_process() {
let exe = std::env::current_exe().expect("取本 test binary 的路径"); let exe = std::env::current_exe().expect("取本 test binary 的路径");
let name = "fonts::tests::resolving_fonts_never_starts_a_download"; let name = "fonts::tests::resolving_fonts_never_starts_a_download";
let output = std::process::Command::new(&exe) let output = unlucky_core::platform::child::quiet(&exe)
.args(["--exact", "--nocapture", "--test-threads=1", name]) .args(["--exact", "--nocapture", "--test-threads=1", name])
.env(CHILD_ENV, "1") .env(CHILD_ENV, "1")
// 截图通道的钉子会直接替换 `status()` 的返回值(`install.rs:157` 先看它), // 截图通道的钉子会直接替换 `status()` 的返回值(`install.rs:157` 先看它),
+18 -2
View File
@@ -23,6 +23,15 @@
//! 它在 `on_boot` 跑一次;配置重载时读的是同一个缓存,不会重复 spawn)。 //! 它在 `on_boot` 跑一次;配置重载时读的是同一个缓存,不会重复 spawn)。
//! - 子进程有 [`COMMAND_TIMEOUT`] 上限:`gsettings` / `defaults` 在坏环境里会挂住, //! - 子进程有 [`COMMAND_TIMEOUT`] 上限:`gsettings` / `defaults` 在坏环境里会挂住,
//! 超时按 `Unknown` 处理并 `kill` 掉。 //! 超时按 `Unknown` 处理并 `kill` 掉。
//! - 子进程经 `unlucky_core::platform::child::quiet` 起(M272):仓规「spawn 控制台程序必须走
//! `quiet`」是全树硬约束(`crates/core/tests/child_quiet_guard.rs` 钉着),探针不是例外——
//! 唯一调用点在这里。
//!
//! ## `quiet` 不影响「可杀」
//!
//! `child::quiet` 返回的就是普通 [`std::process::Command`](Windows 上多一个
//! `CREATE_NO_WINDOW`,其它平台原样返回),`.spawn()` 拿到的 [`std::process::Child`] 仍归
//! `run` 自己,所以 **300 ms 超时 + 超时 `kill` + `wait` 一个字没丢**。
//! //!
//! | 平台 | 来源 | `unsafe` | //! | 平台 | 来源 | `unsafe` |
//! |---|---|---| //! |---|---|---|
@@ -33,6 +42,9 @@
use std::sync::OnceLock; use std::sync::OnceLock;
#[cfg(any(target_os = "linux", target_os = "macos"))]
use unlucky_core::platform::child::quiet;
/// 系统偏好:「减少动效」是否要生效。 /// 系统偏好:「减少动效」是否要生效。
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReduceMotion { pub enum ReduceMotion {
@@ -169,13 +181,17 @@ fn detect() -> ReduceMotion {
/// ///
/// 为什么自己写而不是 `Command::output()`:`output()` 会一直等到子进程退出,坏环境里(没有 /// 为什么自己写而不是 `Command::output()`:`output()` 会一直等到子进程退出,坏环境里(没有
/// session bus 的 `gsettings`)就是无限期挂住——那会让**启动**卡死,是比"没有动效"严重得多的事故。 /// session bus 的 `gsettings`)就是无限期挂住——那会让**启动**卡死,是比"没有动效"严重得多的事故。
///
/// 子进程经 [`quiet`] 起(M272,仓规硬约束)。`quiet` 只改创建 flag、返回的仍是普通
/// `std::process::Command`,所以下面这套自己写的等待循环拿得到 `Child` 句柄,**超时 `kill`
/// 照旧**——「安静」与「可杀」在这里不冲突。
#[cfg(any(target_os = "linux", target_os = "macos"))] #[cfg(any(target_os = "linux", target_os = "macos"))]
fn run(program: &str, args: &[&str]) -> Option<String> { fn run(program: &str, args: &[&str]) -> Option<String> {
use std::io::Read; use std::io::Read;
use std::process::{Command, Stdio}; use std::process::Stdio;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
let mut child = Command::new(program) let mut child = quiet(program)
.args(args) .args(args)
.stdin(Stdio::null()) .stdin(Stdio::null())
.stdout(Stdio::piped()) .stdout(Stdio::piped())