139 lines
4.9 KiB
Rust
139 lines
4.9 KiB
Rust
#[path = "../src/component_detection.rs"]
|
|
mod component_detection;
|
|
#[path = "../src/models.rs"]
|
|
mod models;
|
|
#[path = "../src/process.rs"]
|
|
mod process;
|
|
#[path = "../src/singbox_service.rs"]
|
|
mod singbox_service;
|
|
|
|
use component_detection::DetectedSingBox;
|
|
use singbox_service::{
|
|
build_singbox_setup_status, ensure_safe_singbox_install_dir, parse_service_command_output,
|
|
service_control_script, SingBoxServiceAction,
|
|
};
|
|
use std::path::{Path, PathBuf};
|
|
#[cfg(windows)]
|
|
use std::process::Command as ProcessCommand;
|
|
|
|
#[test]
|
|
fn setup_status_reports_missing_items_when_singbox_is_absent() {
|
|
let status = build_singbox_setup_status(None);
|
|
|
|
assert!(!status.ready);
|
|
assert_eq!(status.missing_count, 3);
|
|
assert_eq!(status.items[0].id, "sing-box-binary");
|
|
assert!(status.items[0].details.contains("SagerNet/sing-box"));
|
|
assert_eq!(status.items[1].id, "winsw-wrapper");
|
|
assert!(status.items[1].details.contains("winsw/winsw"));
|
|
assert_eq!(status.items[2].id, "windows-service");
|
|
}
|
|
|
|
#[test]
|
|
fn setup_status_reports_ready_when_binary_wrapper_and_service_exist() {
|
|
let detected = detected_singbox(true, true, true);
|
|
let status = build_singbox_setup_status(Some(&detected));
|
|
|
|
assert!(status.ready);
|
|
assert_eq!(status.missing_count, 0);
|
|
assert!(status.items.iter().all(|item| item.installed));
|
|
}
|
|
|
|
#[test]
|
|
fn parses_last_json_service_command_output_line() {
|
|
let output = br#"
|
|
noise
|
|
{"success":true,"code":"started","serviceName":"ProxyWardenSingBox","status":"Running","processId":42}
|
|
"#;
|
|
let parsed = parse_service_command_output(output).expect("service json should parse");
|
|
|
|
assert!(parsed.success);
|
|
assert_eq!(parsed.code, "started");
|
|
assert_eq!(parsed.service_name, Some("ProxyWardenSingBox".to_string()));
|
|
assert_eq!(parsed.status, Some("Running".to_string()));
|
|
assert_eq!(parsed.process_id, Some(42));
|
|
}
|
|
|
|
#[test]
|
|
fn safe_install_dir_allows_only_proxywarden_singbox_folder() {
|
|
assert!(
|
|
ensure_safe_singbox_install_dir(Path::new(r"C:\Program Files\ProxyWarden\sing-box"))
|
|
.is_ok()
|
|
);
|
|
assert!(ensure_safe_singbox_install_dir(Path::new(r"C:\Windows")).is_err());
|
|
assert!(ensure_safe_singbox_install_dir(Path::new(r"C:\Program Files\sing-box")).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn service_control_script_targets_named_service_and_action() {
|
|
let script = service_control_script(
|
|
SingBoxServiceAction::Start,
|
|
"ProxyWardenSingBox",
|
|
None,
|
|
None,
|
|
);
|
|
|
|
assert!(script.contains("$serviceName = 'ProxyWardenSingBox'"));
|
|
assert!(script.contains("$action = 'start'"));
|
|
assert!(script.contains("ConvertTo-Json -Compress"));
|
|
}
|
|
|
|
#[test]
|
|
fn service_control_script_syncs_generated_config_before_start() {
|
|
let source = Path::new(r"C:\ProgramData\ProxyWarden\generated\sing-box-config.json");
|
|
let target = Path::new(r"C:\Program Files\ProxyWarden\sing-box\config.json");
|
|
let script = service_control_script(
|
|
SingBoxServiceAction::Start,
|
|
"ProxyWardenSingBox",
|
|
Some(source),
|
|
Some(target),
|
|
);
|
|
|
|
assert!(script.contains(
|
|
"$configSource = 'C:\\ProgramData\\ProxyWarden\\generated\\sing-box-config.json'"
|
|
));
|
|
assert!(
|
|
script.contains("$configTarget = 'C:\\Program Files\\ProxyWarden\\sing-box\\config.json'")
|
|
);
|
|
assert!(script.contains("Copy-Item -LiteralPath $configSource"));
|
|
assert!(script.contains("'config_sync_failed'"));
|
|
}
|
|
|
|
#[test]
|
|
#[cfg(windows)]
|
|
fn install_singbox_script_parses_as_powershell() {
|
|
let script_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
|
.join("..")
|
|
.join("scripts")
|
|
.join("install-singbox.ps1");
|
|
let escaped_path = script_path.display().to_string().replace('\'', "''");
|
|
let parser = format!(
|
|
"$tokens = $null; $errors = $null; [System.Management.Automation.Language.Parser]::ParseFile('{escaped_path}', [ref]$tokens, [ref]$errors) | Out-Null; if ($errors.Count -gt 0) {{ $errors | ForEach-Object {{ $_.Message }}; exit 1 }}"
|
|
);
|
|
let output = ProcessCommand::new("powershell")
|
|
.args(["-NoProfile", "-NonInteractive", "-Command", &parser])
|
|
.output()
|
|
.expect("powershell parser should run");
|
|
|
|
assert!(
|
|
output.status.success(),
|
|
"install-singbox.ps1 should parse\nstdout:\n{}\nstderr:\n{}",
|
|
String::from_utf8_lossy(&output.stdout),
|
|
String::from_utf8_lossy(&output.stderr),
|
|
);
|
|
}
|
|
|
|
fn detected_singbox(binary_exists: bool, wrapper_exists: bool, running: bool) -> DetectedSingBox {
|
|
DetectedSingBox {
|
|
install_dir: PathBuf::from(r"C:\Program Files\ProxyWarden\sing-box"),
|
|
executable_path: PathBuf::from(r"C:\Program Files\ProxyWarden\sing-box\sing-box.exe"),
|
|
wrapper_path: PathBuf::from(
|
|
r"C:\Program Files\ProxyWarden\sing-box\ProxyWardenSingBox.exe",
|
|
),
|
|
binary_exists,
|
|
wrapper_exists,
|
|
running,
|
|
service_name: "ProxyWardenSingBox".to_string(),
|
|
}
|
|
}
|