Update: 将子项目从 submodule 转为完整内容

- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用
- 添加所有子项目的完整源代码
- 保留原始 .git 为 .git.bak 备份
This commit is contained in:
freedak
2026-07-04 19:20:46 +08:00
parent 54d6465fa7
commit f7a720204a
3360 changed files with 802660 additions and 3 deletions
@@ -0,0 +1,166 @@
//! **P2 D2navigate settle 升级端到端集成**`#[ignore]`,本机/打包 chrome)。
//!
//! 验证 D2 的成熟导航判定(DESIGN §12 + 裁决⑤):
//! - 普通页 navigate → load_state 达 Load/NetworkIdle(视页面是否真静默)。
//! - networkidle 永不空闲页(长轮询)→ networkidle 短 cap~4s)降级返 Load**不卡 30s**。
//! - SPA history.pushState 软导航 → navigatedWithinDocument 降级判定(不重新等 load)。
//! - 真站(HTTP)→ http_status==200 填充;redirect 用 URL-normalize 不误判 trailing-slash。
//!
//! 复用 `tests/common` 的 `build_backend_for_fixture`(勿再复制契约母本)。
//!
//! 手动跑(本机 Windows 有系统 Chrome):
//! set NOMIFUN_CHROME_BINARY=...\chrome.exe
//! cargo nextest run -p nomi-browser-engine --run-ignored all -E 'test(nav)'
//! 跑完核对任务管理器无残留 chromeBuilder kill_on_drop 应自动清)。
//!
//! 真实结果(本机首跑会 eprintln 出 load_state/http_status/耗时——填回任务汇报)。
use std::time::Instant;
use nomi_browser_engine::{BrowserEngine, LoadState};
mod common;
/// 普通 file:// 页 navigatesettle 阶梯走通,load_state 达 Loadfile:// 无 HTTP 故 http_status
/// 可能为 None),耗时远小于 30s 总超时。act-c1.html 是静态页(脚本只挂事件,无持续网络)→ 应在
/// networkidle 短 cap 内达到 NetworkIdle,或至少 Load。
#[tokio::test]
#[ignore = "需本机/打包 chromeset NOMIFUN_CHROME_BINARY 后 --run-ignored all"]
async fn nav_normal_page_reaches_load_or_networkidle() {
let backend = common::build_backend_for_fixture("nav-normal").await;
let t0 = Instant::now();
let nav = backend
.navigate(&common::fixture_url("act-c1.html"), false)
.await
.expect("navigate act-c1.html");
let elapsed = t0.elapsed();
eprintln!(
"=== nav_normal_page === final_url={} http_status={:?} redirected={} load_state={} elapsed={:?}",
nav.final_url, nav.http_status, nav.redirected, nav.load_state, elapsed
);
// 静态页:应达 Load 或 NetworkIdle(不会停在 commit/DCL——本页极快)。
assert!(
matches!(nav.load_state, LoadState::Load | LoadState::NetworkIdle),
"static page should reach Load/NetworkIdle, got {}",
nav.load_state
);
// file:// 自身不算 redirect(归一化比较:请求 url == final url)。
assert!(!nav.redirected, "file:// self-nav must not be flagged redirect");
// 整个 navigate 应远小于 30s(即便 networkidle cap 触发也只 +4s)。
assert!(
elapsed.as_secs() < 15,
"navigate took too long ({elapsed:?}); networkidle cap must not blow up nav timeout"
);
}
/// networkidle 永不空闲页(长轮询 fixture):networkidle 短 cap~4s)到点降级返 Load**绝不**卡到
/// 30s。这是裁决⑤ 的核心不变量——长轮询/SSE/WS 站永不 idle 也不能拖垮 navigate。
#[tokio::test]
#[ignore = "需本机/打包 chromeset NOMIFUN_CHROME_BINARY 后 --run-ignored all"]
async fn nav_never_idle_page_degrades_to_load_within_cap() {
let backend = common::build_backend_for_fixture("nav-never-idle").await;
let t0 = Instant::now();
let nav = backend
.navigate(&common::fixture_url("never-idle.html"), false)
.await
.expect("navigate never-idle.html");
let elapsed = t0.elapsed();
eprintln!(
"=== nav_never_idle === load_state={} elapsed={:?} (networkidle cap degrade expected)",
nav.load_state, elapsed
);
// 永不空闲 → networkidle 等不到 → 降级返 Load(良性,不报错)。
assert_eq!(
nav.load_state,
LoadState::Load,
"never-idle page must degrade to Load (not NetworkIdle)"
);
// 关键不变量:cap 独立,总耗时 ~ load + 4s cap,远小于 30s。给宽松上限 20s 防慢机器 flaky,
// 但必须显著小于 30s 才能证明「cap 没并入 nav 超时」。
assert!(
elapsed.as_secs() < 20,
"networkidle cap must be independent of 30s nav timeout; elapsed={elapsed:?}"
);
}
/// SPA 软导航:本 fixture load 后自动 history.pushState 改 URLnavigatedWithinDocument,无新文档)。
/// navigate 应识别软导航降级路径(不重新等 load 超时),良性返回成功。
///
/// 注意:navigate 的初始文档 load 与之后的软导航是两件事——navigate 返回时通常已达 Load(初始文档
/// 的 load 先到)。本测试主要验证「不报错、final_url 反映软导航后的 URL(若软导航在 navigate 返回
/// 前发生)」+ 不卡死。软导航的「不重新等 load」降级路径在 run_settle 内(若软导航先于 load 到达)。
#[tokio::test]
#[ignore = "需本机/打包 chromeset NOMIFUN_CHROME_BINARY 后 --run-ignored all"]
async fn nav_spa_soft_navigation_is_benign() {
let backend = common::build_backend_for_fixture("nav-spa").await;
let t0 = Instant::now();
let nav = backend
.navigate(&common::fixture_url("spa-softnav.html"), false)
.await
.expect("navigate spa-softnav.html");
let elapsed = t0.elapsed();
eprintln!(
"=== nav_spa === final_url={} load_state={} redirected={} elapsed={:?}",
nav.final_url, nav.load_state, nav.redirected, elapsed
);
// 软导航是良性态:navigate 成功(不 Err),不卡死。
assert!(
elapsed.as_secs() < 15,
"SPA nav must not hang on load timeout; elapsed={elapsed:?}"
);
// load_state 至少达 DOMContentLoadedDOM 已构建);多数情况达 Load(初始文档 load 先到)。
assert!(
matches!(
nav.load_state,
LoadState::DomContentLoaded | LoadState::Load | LoadState::NetworkIdle
),
"SPA page should reach at least DOMContentLoaded, got {}",
nav.load_state
);
}
/// 真站(HTTP):http_status==200 填充 + redirect URL-normalize 不误判。仅当设了
/// `NOMIFUN_NAV_HTTP_TEST=1`(避免离线环境 flaky)才真跑——否则 eprintln 跳过原因后返回。
///
/// 用 https://example.com(稳定、无重定向、明确 200)。验证:
/// - http_status == Some(200)D2 从主帧 Document responseReceived 取到)。
/// - example.com → example.com/trailing-slash)归一化后**不**算 redirect(裸 != 会误报)。
#[tokio::test]
#[ignore = "需本机/打包 chrome + 网络:set NOMIFUN_CHROME_BINARY + NOMIFUN_NAV_HTTP_TEST=1 后 --run-ignored all"]
async fn nav_http_status_and_redirect_normalize() {
if std::env::var("NOMIFUN_NAV_HTTP_TEST").ok().as_deref() != Some("1") {
eprintln!("=== nav_http_status === SKIPPED (set NOMIFUN_NAV_HTTP_TEST=1 to run online)");
return;
}
let backend = common::build_backend_for_fixture("nav-http").await;
let t0 = Instant::now();
let nav = backend
.navigate("https://example.com", false)
.await
.expect("navigate example.com");
let elapsed = t0.elapsed();
eprintln!(
"=== nav_http_status === final_url={} http_status={:?} redirected={} load_state={} elapsed={:?}",
nav.final_url, nav.http_status, nav.redirected, nav.load_state, elapsed
);
assert_eq!(nav.http_status, Some(200), "example.com should return HTTP 200");
// example.com → example.com/(浏览器补 trailing slash):归一化比较**不**算 redirect。
assert!(
!nav.redirected,
"trailing-slash difference must not be flagged as redirect (URL-normalize), final_url={}",
nav.final_url
);
assert!(nav.final_url.contains("example.com"));
}