Files
ZacharyZhang-NY a02b555e66 docs(comments): rewrite comments across all crates to the guidelines
Sweep every first-party crate source (1956 .rs files) to the project comment
guidelines: delete redundant restatements, decorative banners, change
narration, and end-of-line comments; keep and tighten the crucial ones
(invariants, bug rationale, SAFETY blocks, ported-source attribution).

No functional code changed. Every edit is proven comment-only against the
prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a
separate doctest-fence check. Where removing a comment made rustfmt or clippy
want to re-lay-out adjacent code, the minimal triggering comment is restored so
code tokens stay byte-identical.

Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy
--workspace --all-targets (0 warnings).

Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for
these guidelines (flags banners, end-of-line comments, change narration, and
commented-out code).
2026-07-23 16:55:39 -04:00

493 lines
17 KiB
Rust

//! End-to-end tests for the production update flows (`check_update_status`,
//! `ensure_latest_on_disk`, `run_update`, `run_update_if_available`) against
//! a GitHub-Releases-shaped [`common::artifact_server::ArtifactServer`],
//! injected via the `KIGI_UPDATE_BASE_URL` override that
//! `kigi_env::update_base_url()` honors.
//!
//! Three invariant families:
//!
//! 1. **Convergence**: a binary already on disk (installed by another
//! process) is never downloaded a second time, but stale runners still
//! get the relaunch/report signal.
//! 2. **Status**: `kigi update --check` reports upgrades only, surfaces
//! fetch errors in the `error` field, and never advertises downgrades.
//! 3. **Race integrity**: concurrent installers — even for different
//! versions — never leave a corrupt active binary.
//!
//! Everything here is `#[serial]`: KIGI_SHARE_DIR, KIGI_UPDATE_BASE_URL and
//! KIGI_TEST_VERSION are process-global.
#![cfg(unix)]
mod common;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use serial_test::serial;
use common::artifact_server::ArtifactServer;
use common::{
can_exec_shell_scripts, host_platform, make_update_config, reset_home, set_test_version,
set_update_base, small_good_artifact, test_home,
};
use kigi_update::auto_update::{
UpdateRunMode, check_update_status, ensure_latest_on_disk, install_internal_from_base,
run_update, run_update_if_available,
};
use kigi_update::version::installed_on_disk_version;
/// Lay down a managed-install layout in the test KIGI_SHARE_DIR:
/// `bin/kigi -> ../downloads/kigi-<version>-<platform>` (what the installer
/// produces; the canonical link the disk-version probe reads).
fn fake_managed_install(version: &str) {
let home = test_home();
let downloads = home.join("downloads");
let bin = home.join("bin");
std::fs::create_dir_all(&downloads).unwrap();
std::fs::create_dir_all(&bin).unwrap();
let name = format!("kigi-{version}-{}", host_platform());
std::fs::write(downloads.join(&name), small_good_artifact()).unwrap();
std::fs::set_permissions(
downloads.join(&name),
std::fs::Permissions::from_mode(0o755),
)
.unwrap();
let _ = std::fs::remove_file(bin.join("kigi"));
std::os::unix::fs::symlink(Path::new("../downloads").join(&name), bin.join("kigi")).unwrap();
}
/// Assert the active `~/.kigi/bin/kigi` resolves to the expected versioned
/// binary, actually runs, and has exactly the expected content (the content
/// check is what catches a cross-racer temp-file corruption).
fn assert_active_binary(home: &Path, version: &str, platform: &str, expected_content: &[u8]) {
let link = home.join("bin").join("kigi");
assert!(link.is_symlink(), "kigi must be a symlink");
let resolved = dunce::canonicalize(&link)
.unwrap_or_else(|e| panic!("active kigi symlink does not resolve: {e}"));
assert_eq!(
resolved.file_name().unwrap().to_string_lossy(),
format!("kigi-{version}-{platform}"),
"active kigi must be the expected version"
);
assert_eq!(
std::fs::read(&resolved).unwrap(),
expected_content,
"active binary content must be exactly the served artifact (no \
partial/interleaved writes from a racing updater)"
);
let ran_ok = std::process::Command::new(&resolved)
.arg("--version")
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false);
assert!(ran_ok, "active kigi must pass the smoke-test");
}
fn setup(server: &ArtifactServer, latest: &str, running: &str) {
let _ = test_home();
reset_home();
server.set_latest(latest);
set_update_base(&server.base());
set_test_version(running);
}
// Convergence: ensure_latest_on_disk downloads once, then every subsequent
// pass (the leader's hourly re-entry) converges without re-downloading.
#[tokio::test]
#[serial]
async fn ensure_latest_downloads_once_then_converges_without_redownload() {
if !can_exec_shell_scripts() {
eprintln!("skipping: shell scripts cannot execute in this sandbox");
return;
}
let server = ArtifactServer::start(small_good_artifact());
setup(&server, "0.2.7", "0.2.5");
let cfg = make_update_config("stable");
// Pass 1: disk is empty → downloads and installs.
let first = ensure_latest_on_disk(&cfg).await.unwrap();
assert_eq!(first.installed.as_deref(), Some("0.2.7"));
assert!(first.relaunch_needed, "running 0.2.5 < disk 0.2.7");
assert_eq!(server.request_count(), 1, "first pass downloads");
assert_eq!(installed_on_disk_version().as_deref(), Some("0.2.7"));
// Pass 2 (the pre-fix hourly re-download): disk already current →
// no download, but the stale running process still gets the relaunch
// signal.
let second = ensure_latest_on_disk(&cfg).await.unwrap();
assert_eq!(second.installed, None, "second pass must not re-download");
assert!(second.relaunch_needed, "still running 0.2.5 < disk 0.2.7");
assert_eq!(
server.request_count(),
1,
"hourly re-entry must not download again"
);
}
#[tokio::test]
#[serial]
async fn run_update_skips_download_when_disk_already_current() {
if !can_exec_shell_scripts() {
eprintln!("skipping: shell scripts cannot execute in this sandbox");
return;
}
let server = ArtifactServer::start(small_good_artifact());
setup(&server, "0.2.7", "0.2.5");
// Another process (TUI background download) already installed 0.2.7.
fake_managed_install("0.2.7");
let mut cfg = make_update_config("stable");
let result = run_update(false, None, None, &mut cfg).await.unwrap();
assert_eq!(
result.as_deref(),
Some("0.2.7"),
"run_update must still report the on-disk target so the caller \
signals stale leaders to relaunch"
);
assert_eq!(
server.request_count(),
0,
"a binary someone else installed must not be downloaded again"
);
}
#[tokio::test]
#[serial]
async fn run_update_force_still_redownloads_when_disk_current() {
if !can_exec_shell_scripts() {
eprintln!("skipping: shell scripts cannot execute in this sandbox");
return;
}
let server = ArtifactServer::start(small_good_artifact());
setup(&server, "0.2.7", "0.2.7");
fake_managed_install("0.2.7");
let mut cfg = make_update_config("stable");
let result = run_update(true, None, None, &mut cfg).await.unwrap();
assert_eq!(result.as_deref(), Some("0.2.7"));
assert_eq!(
server.request_count(),
1,
"--force must bypass the disk-current skip and reinstall"
);
}
#[tokio::test]
#[serial]
async fn run_update_rolls_back_when_latest_moved_backwards() {
// Release rollback: the latest release points BELOW the on-disk install
// (a bad release was deleted). The internal installer is authoritative,
// so run_update must converge the disk down to it.
if !can_exec_shell_scripts() {
eprintln!("skipping: shell scripts cannot execute in this sandbox");
return;
}
let server = ArtifactServer::start(small_good_artifact());
setup(&server, "0.2.5", "0.2.7");
fake_managed_install("0.2.7");
let mut cfg = make_update_config("stable");
let result = run_update(false, None, None, &mut cfg).await.unwrap();
assert_eq!(
result.as_deref(),
Some("0.2.5"),
"rollback target installed"
);
assert_eq!(installed_on_disk_version().as_deref(), Some("0.2.5"));
assert_eq!(server.request_count(), 1);
}
// Disk-version probe
#[tokio::test]
#[serial]
async fn disk_probe_preserves_prerelease_versions() {
let _ = test_home();
reset_home();
// An alpha install must read back as the full pre-release version —
// truncating to "0.1.220" would mask the alpha → stable update.
fake_managed_install("0.1.220-alpha.4");
assert_eq!(
installed_on_disk_version().as_deref(),
Some("0.1.220-alpha.4")
);
}
#[tokio::test]
#[serial]
async fn disk_probe_rejects_dangling_symlink() {
// If the symlink survives but its target binary was deleted (manual
// ~/.kigi/downloads cleanup), the probe must report None — otherwise
// every updater would claim "already up to date" forever while no
// runnable binary exists, and nothing would ever repair the install.
let home = test_home();
reset_home();
let platform = host_platform();
fake_managed_install("0.2.7");
assert_eq!(installed_on_disk_version().as_deref(), Some("0.2.7"));
std::fs::remove_file(
home.join("downloads")
.join(format!("kigi-0.2.7-{platform}")),
)
.unwrap();
assert_eq!(
installed_on_disk_version(),
None,
"a dangling symlink must not report an installed version"
);
}
#[tokio::test]
#[serial]
async fn ensure_latest_repairs_dangling_symlink_by_downloading() {
if !can_exec_shell_scripts() {
eprintln!("skipping: shell scripts cannot execute in this sandbox");
return;
}
// Dangling symlink + stale running process: the probe returns None, so
// the decision falls back to the running version and the download runs,
// repairing the install instead of wedging on "already up to date".
let server = ArtifactServer::start(small_good_artifact());
setup(&server, "0.2.7", "0.2.5");
let home = test_home();
let platform = host_platform();
fake_managed_install("0.2.7");
std::fs::remove_file(
home.join("downloads")
.join(format!("kigi-0.2.7-{platform}")),
)
.unwrap();
let cfg = make_update_config("stable");
let outcome = ensure_latest_on_disk(&cfg).await.unwrap();
assert_eq!(
outcome.installed.as_deref(),
Some("0.2.7"),
"dangling symlink must be repaired by an actual download"
);
assert_eq!(server.request_count(), 1);
assert_eq!(
installed_on_disk_version().as_deref(),
Some("0.2.7"),
"probe healthy again after the repair install"
);
}
// check_update_status (`kigi update --check`)
#[tokio::test]
#[serial]
async fn check_status_reports_update_when_release_is_newer() {
let server = ArtifactServer::start(small_good_artifact());
setup(&server, "0.2.7", "0.2.5");
let cfg = make_update_config("stable");
let status = check_update_status(&cfg).await;
assert_eq!(status.current_version, "0.2.5");
assert_eq!(status.latest_version.as_deref(), Some("0.2.7"));
assert!(status.update_available);
assert_eq!(status.installer.as_deref(), Some("internal"));
assert_eq!(status.error, None);
}
#[tokio::test]
#[serial]
async fn check_status_never_reports_downgrade_as_update() {
// --check reports upgrades only; a rolled-back release is not advertised
// (auto-update converges separately).
let server = ArtifactServer::start(small_good_artifact());
setup(&server, "0.2.5", "0.2.7");
let cfg = make_update_config("stable");
let status = check_update_status(&cfg).await;
assert_eq!(status.latest_version.as_deref(), Some("0.2.5"));
assert!(!status.update_available, "downgrade must not be advertised");
assert_eq!(status.error, None);
}
#[tokio::test]
#[serial]
async fn check_status_surfaces_fetch_error_in_error_field() {
// Point the updater at a dead endpoint (bound then dropped port →
// connection refused). The status must carry the error rather than
// pretending "up to date".
let _ = test_home();
reset_home();
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
let port = listener.local_addr().unwrap().port();
drop(listener);
set_update_base(&format!("http://127.0.0.1:{port}/releases"));
set_test_version("0.2.5");
let cfg = make_update_config("stable");
let status = check_update_status(&cfg).await;
assert!(!status.update_available);
assert_eq!(status.latest_version, None);
let err = status.error.as_deref().expect("error must be surfaced");
assert!(!err.is_empty());
// And it serializes into the --json contract.
let v = serde_json::to_value(&status).unwrap();
assert!(v["error"].is_string());
assert_eq!(v["updateAvailable"], false);
}
#[tokio::test]
#[serial]
async fn check_status_unsupported_channel_reports_error() {
let server = ArtifactServer::start(small_good_artifact());
setup(&server, "0.2.7", "0.2.5");
let cfg = make_update_config("beta");
let status = check_update_status(&cfg).await;
assert!(!status.update_available);
let err = status.error.as_deref().expect("channel error surfaced");
assert!(
err.contains("Unsupported release channel 'beta'"),
"err: {err}"
);
}
// run_update_if_available — the auto-update opt-out gate.
#[tokio::test]
#[serial]
async fn run_update_if_available_respects_auto_update_false() {
// With cli.auto_update = false persisted, the startup check must return
// without ever touching the network (the update base points at a dead
// port — any fetch would error, any download would install).
let _ = test_home();
reset_home();
std::fs::write(
test_home().join("config.toml"),
"[cli]\nauto_update = false\n",
)
.unwrap();
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
let port = listener.local_addr().unwrap().port();
drop(listener);
set_update_base(&format!("http://127.0.0.1:{port}/releases"));
set_test_version("0.1.0");
let cfg = make_update_config("stable");
let ran = run_update_if_available(UpdateRunMode::Blocking, false, &cfg)
.await
.unwrap();
assert!(!ran, "auto_update=false must suppress the update entirely");
}
// Race integrity: the accepted same-instant race must stay harmless. Two (or
// three) installers running concurrently — even for DIFFERENT versions —
// must never leave a corrupt active binary.
async fn run_concurrent_installs(
server: &ArtifactServer,
versions: &[&str],
) -> Vec<anyhow::Result<()>> {
let base = server.base();
let mut tasks = Vec::new();
for version in versions {
let base = base.clone();
let version = version.to_string();
tasks.push(tokio::spawn(async move {
let cfg = make_update_config("stable");
install_internal_from_base(Some(&version), &cfg, &base).await
}));
}
let mut results = Vec::new();
for t in tasks {
results.push(t.await.expect("install task must not panic"));
}
results
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn concurrent_same_version_installs_leave_valid_active_binary() {
if !can_exec_shell_scripts() {
eprintln!("skipping: shell scripts cannot execute in this sandbox");
return;
}
let home = test_home();
reset_home();
let platform = host_platform();
let artifact = small_good_artifact();
let server = ArtifactServer::start(artifact.clone());
// Hold responses open so the racers genuinely overlap mid-download.
server.set_slow(true);
let results = run_concurrent_installs(&server, &["0.1.181", "0.1.181", "0.1.181"]).await;
for r in results {
r.expect("every racing install must succeed (atomic swap, last writer wins)");
}
// Lock-free model: concurrent racers may each download (accepted waste);
// the invariant is integrity, not the count.
assert!(server.request_count() >= 1);
assert_active_binary(home, "0.1.181", &platform, &artifact);
}
#[tokio::test(flavor = "multi_thread")]
#[serial]
async fn concurrent_different_version_installs_do_not_corrupt_each_other() {
if !can_exec_shell_scripts() {
eprintln!("skipping: shell scripts cannot execute in this sandbox");
return;
}
let home = test_home();
reset_home();
let platform = host_platform();
let artifact = small_good_artifact();
let server = ArtifactServer::start(artifact.clone());
server.set_slow(true);
let results = run_concurrent_installs(&server, &["0.1.181", "0.1.182"]).await;
for r in results {
r.expect("both racing installs must succeed");
}
// Both versioned binaries must exist with full, uncorrupted content.
for version in ["0.1.181", "0.1.182"] {
let path = home
.join("downloads")
.join(format!("kigi-{version}-{platform}"));
assert_eq!(
std::fs::read(&path).unwrap(),
artifact,
"binary {version} must contain exactly the served artifact"
);
}
// The active symlink points at whichever racer swapped last; it must
// resolve and run regardless.
let resolved = dunce::canonicalize(home.join("bin").join("kigi")).unwrap();
assert_eq!(std::fs::read(&resolved).unwrap(), artifact);
let name = resolved.file_name().unwrap().to_string_lossy().to_string();
assert!(
!name.contains(".tmp"),
"active kigi must never be a temp file: {name}"
);
// No stray shared temp file left behind (a with_extension-style
// collision name).
assert!(
!home.join("downloads").join("kigi-0.1.tmp").exists(),
"the shared-temp-name collision must not exist"
);
}