cb15c5e0d8
Release / Check for new version (push) Has been cancelled
Release / Build macOS ARM64 (push) Has been cancelled
Release / Build macOS x64 (push) Has been cancelled
Release / Build Linux ARM64 (push) Has been cancelled
Release / Build Linux musl ARM64 (push) Has been cancelled
Release / Build Linux musl x64 (push) Has been cancelled
Release / Build Linux x64 (push) Has been cancelled
Release / Build Windows x64 (push) Has been cancelled
Release / Publish to npm (push) Has been cancelled
Release / Publish sandbox package to npm (push) Has been cancelled
Release / Create GitHub Release (push) Has been cancelled
CI / Rust (windows-latest - x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Native E2E Tests (push) Has been cancelled
CI / Windows Integration Test (push) Has been cancelled
CI / Global Install (macos-latest) (push) Has been cancelled
CI / Global Install (ubuntu-latest) (push) Has been cancelled
CI / Version Sync Check (push) Has been cancelled
CI / Rust (push) Has been cancelled
CI / Dashboard (push) Has been cancelled
CI / Sandbox Package (push) Has been cancelled
CI / Rust (macos-latest - aarch64-apple-darwin) (push) Has been cancelled
CI / Rust (macos-latest - x86_64-apple-darwin) (push) Has been cancelled
CI / Global Install (windows-latest) (push) Has been cancelled
142 lines
4.5 KiB
Rust
142 lines
4.5 KiB
Rust
//! Integration tests for `agent-browser doctor`.
|
|
//!
|
|
//! These tests spawn the real CLI binary via `env!("CARGO_BIN_EXE_*")` and
|
|
//! verify the doctor command produces sane output. They override
|
|
//! `AGENT_BROWSER_SOCKET_DIR` and `HOME` / `USERPROFILE` so the doctor
|
|
//! inspects a throwaway directory and never touches the user's real state.
|
|
|
|
use std::process::Command;
|
|
use tempfile::TempDir;
|
|
|
|
const BIN: &str = env!("CARGO_BIN_EXE_agent-browser");
|
|
|
|
fn build_doctor_cmd(tmp: &TempDir, args: &[&str]) -> Command {
|
|
let socket_dir = tmp.path().join("sockets");
|
|
let home = tmp.path().join("home");
|
|
std::fs::create_dir_all(&socket_dir).unwrap();
|
|
std::fs::create_dir_all(&home).unwrap();
|
|
|
|
let mut cmd = Command::new(BIN);
|
|
cmd.args(args)
|
|
.env("AGENT_BROWSER_SOCKET_DIR", &socket_dir)
|
|
.env("HOME", &home)
|
|
.env("USERPROFILE", &home)
|
|
// Keep the launch test's skip-logic deterministic across hosts.
|
|
.env_remove("AGENT_BROWSER_PROVIDER")
|
|
.env_remove("AGENT_BROWSER_CDP")
|
|
// Don't emit color codes into captured stdout.
|
|
.env("NO_COLOR", "1");
|
|
cmd
|
|
}
|
|
|
|
#[test]
|
|
fn doctor_offline_quick_json_emits_valid_payload() {
|
|
let tmp = TempDir::new().unwrap();
|
|
|
|
let output = build_doctor_cmd(&tmp, &["doctor", "--offline", "--quick", "--json"])
|
|
.output()
|
|
.expect("failed to invoke agent-browser doctor");
|
|
|
|
let code = output.status.code().unwrap_or(-1);
|
|
let stdout = String::from_utf8(output.stdout).expect("stdout should be utf8");
|
|
let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
|
|
|
|
// Exit code 0 (all pass) or 1 (one or more fails) are both valid outcomes;
|
|
// the doctor may legitimately report a failure on a host without Chrome.
|
|
assert!(
|
|
code == 0 || code == 1,
|
|
"unexpected exit code {}\nstdout:\n{}\nstderr:\n{}",
|
|
code,
|
|
stdout,
|
|
stderr,
|
|
);
|
|
|
|
let payload: serde_json::Value = serde_json::from_str(&stdout)
|
|
.unwrap_or_else(|e| panic!("stdout was not JSON: {}\n---\n{}", e, stdout));
|
|
|
|
assert!(payload.get("success").is_some(), "missing success field");
|
|
assert!(payload.get("summary").is_some(), "missing summary field");
|
|
assert!(payload.get("fixed").is_some(), "missing fixed field");
|
|
|
|
let summary = &payload["summary"];
|
|
assert!(summary["pass"].is_number());
|
|
assert!(summary["warn"].is_number());
|
|
assert!(summary["fail"].is_number());
|
|
|
|
let checks = payload["checks"]
|
|
.as_array()
|
|
.expect("checks should be an array");
|
|
assert!(!checks.is_empty(), "checks array should not be empty");
|
|
|
|
// Every check must have a non-empty id / category / status / message.
|
|
for c in checks {
|
|
assert!(
|
|
c["id"].as_str().is_some_and(|s| !s.is_empty()),
|
|
"check missing id: {}",
|
|
c
|
|
);
|
|
assert!(
|
|
c["category"].as_str().is_some_and(|s| !s.is_empty()),
|
|
"check missing category: {}",
|
|
c
|
|
);
|
|
let status = c["status"].as_str().expect("status should be string");
|
|
assert!(
|
|
["pass", "warn", "fail", "info"].contains(&status),
|
|
"unexpected status {:?}",
|
|
status
|
|
);
|
|
assert!(
|
|
c["message"].as_str().is_some_and(|s| !s.is_empty()),
|
|
"check missing message: {}",
|
|
c
|
|
);
|
|
}
|
|
|
|
// Check IDs must be unique now that providers / sessions / skipped-launch
|
|
// states each carry their own ID suffix.
|
|
let mut seen = std::collections::HashSet::new();
|
|
for c in checks {
|
|
let id = c["id"].as_str().unwrap();
|
|
assert!(
|
|
seen.insert(id.to_string()),
|
|
"duplicate check id in JSON output: {}\nfull payload:\n{}",
|
|
id,
|
|
stdout
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn doctor_help_describes_flags_and_examples() {
|
|
let tmp = TempDir::new().unwrap();
|
|
|
|
let output = build_doctor_cmd(&tmp, &["doctor", "--help"])
|
|
.output()
|
|
.expect("failed to invoke agent-browser doctor --help");
|
|
|
|
assert!(
|
|
output.status.success(),
|
|
"doctor --help should exit 0; got {:?}",
|
|
output.status
|
|
);
|
|
|
|
let stdout = String::from_utf8(output.stdout).expect("stdout should be utf8");
|
|
|
|
for needle in [
|
|
"agent-browser doctor",
|
|
"--offline",
|
|
"--quick",
|
|
"--fix",
|
|
"--json",
|
|
"Exit codes",
|
|
] {
|
|
assert!(
|
|
stdout.contains(needle),
|
|
"doctor --help output missing {:?}\n---\n{}",
|
|
needle,
|
|
stdout
|
|
);
|
|
}
|
|
}
|