Files
harbor-net/apps/windows-client/src-tauri/tests/proxifyre_adapter_tests.rs

208 lines
7.1 KiB
Rust

#[path = "../src/models.rs"]
mod models;
#[path = "../src/adapters/proxifyre.rs"]
mod proxifyre;
#[path = "../src/adapters/proxy_router.rs"]
mod proxy_router;
use models::{
ComponentId, ComponentState, ComponentStatus, Profile, ProfileItem, ProfileItemType, Protocol,
ProxyProtocol, Target, TargetKind,
};
use proxifyre::{ProxiFyreAdapter, ProxiFyreConfig, PROXIFYRE_OUTPUT_FILE};
use proxy_router::{ProxyRouterAdapter, ProxyRouterErrorKind, ProxyRouterRequest};
#[test]
fn generates_proxifyre_config_for_discord_external_socks5_target() {
let adapter = ProxiFyreAdapter::default();
let profiles = vec![discord_profile("home-gateway")];
let targets = vec![external_socks5_target()];
let components = vec![missing_singbox_component()];
let generated = adapter
.generate_config(ProxyRouterRequest::new(&profiles, &targets, &components))
.expect("external socks5 target should not require sing-box");
let config: ProxiFyreConfig =
serde_json::from_str(&generated.contents).expect("generated config json");
assert_eq!(generated.adapter_id, "proxifyre");
assert_eq!(generated.output_file_name, PROXIFYRE_OUTPUT_FILE);
assert_eq!(generated.enabled_profiles, 1);
assert_eq!(generated.routed_apps, 1);
assert_eq!(config.log_level, "Info");
assert!(config.bypass_lan);
assert_eq!(config.proxies.len(), 1);
assert_eq!(config.proxies[0].app_names, vec!["Discord"]);
assert_eq!(
config.proxies[0].socks5_proxy_endpoint,
"192.168.50.111:8080"
);
assert_eq!(config.proxies[0].supported_protocols, vec!["TCP", "UDP"]);
}
#[test]
fn skips_disabled_profiles_when_generating_proxifyre_config() {
let adapter = ProxiFyreAdapter::default();
let mut disabled = discord_profile("home-gateway");
disabled.enabled = false;
let profiles = vec![disabled];
let targets = vec![external_socks5_target()];
let components = Vec::new();
let generated = adapter
.generate_config(ProxyRouterRequest::new(&profiles, &targets, &components))
.expect("disabled profiles should produce empty config");
let config: ProxiFyreConfig =
serde_json::from_str(&generated.contents).expect("generated config json");
assert_eq!(generated.enabled_profiles, 0);
assert_eq!(generated.routed_apps, 0);
assert!(config.proxies.is_empty());
}
#[test]
fn includes_folder_paths_when_generating_proxifyre_config() {
let adapter = ProxiFyreAdapter::default();
let mut profile = discord_profile("home-gateway");
profile.items.push(ProfileItem {
item_type: ProfileItemType::Folder,
value: r"C:\Games\MyGame".to_string(),
recursive: true,
});
let profiles = vec![profile];
let targets = vec![external_socks5_target()];
let components = Vec::new();
let generated = adapter
.generate_config(ProxyRouterRequest::new(&profiles, &targets, &components))
.expect("folder paths should be accepted by ProxiFyre config generation");
let config: ProxiFyreConfig =
serde_json::from_str(&generated.contents).expect("generated config json");
assert_eq!(generated.routed_apps, 2);
assert_eq!(
config.proxies[0].app_names,
vec!["Discord", r"C:\Games\MyGame"]
);
}
#[test]
fn blocks_local_singbox_target_when_required_component_is_missing() {
let adapter = ProxiFyreAdapter::default();
let profiles = vec![discord_profile("local-singbox")];
let targets = vec![local_singbox_target()];
let components = Vec::new();
let error = adapter
.generate_config(ProxyRouterRequest::new(&profiles, &targets, &components))
.expect_err("local sing-box target should require installed running sing-box");
assert_eq!(error.kind, ProxyRouterErrorKind::MissingRequiredComponent);
}
#[test]
fn local_singbox_target_generates_when_required_component_is_running() {
let adapter = ProxiFyreAdapter::default();
let profiles = vec![discord_profile("local-singbox")];
let targets = vec![local_singbox_target()];
let components = vec![running_singbox_component()];
let generated = adapter
.generate_config(ProxyRouterRequest::new(&profiles, &targets, &components))
.expect("running sing-box should satisfy local target dependency");
let config: ProxiFyreConfig =
serde_json::from_str(&generated.contents).expect("generated config json");
assert_eq!(config.proxies.len(), 1);
assert_eq!(config.proxies[0].socks5_proxy_endpoint, "127.0.0.1:1080");
}
#[test]
fn rejects_http_target_because_proxifyre_adapter_is_socks5_only() {
let adapter = ProxiFyreAdapter::default();
let profiles = vec![discord_profile("office-http")];
let targets = vec![Target {
id: "office-http".to_string(),
name: "Office HTTP".to_string(),
kind: TargetKind::External,
protocol: ProxyProtocol::Http,
host: "192.168.50.111".to_string(),
port: 3128,
requires_component: None,
}];
let components = Vec::new();
let error = adapter
.generate_config(ProxyRouterRequest::new(&profiles, &targets, &components))
.expect_err("ProxiFyre should reject HTTP targets");
assert_eq!(error.kind, ProxyRouterErrorKind::UnsupportedTargetProtocol);
}
fn discord_profile(target_id: &str) -> Profile {
Profile {
id: "discord".to_string(),
name: "Discord".to_string(),
enabled: true,
target_id: target_id.to_string(),
protocols: vec![Protocol::Tcp, Protocol::Udp],
items: vec![ProfileItem {
item_type: ProfileItemType::Process,
value: "Discord".to_string(),
recursive: false,
}],
}
}
fn external_socks5_target() -> Target {
Target {
id: "home-gateway".to_string(),
name: "Home Gateway".to_string(),
kind: TargetKind::External,
protocol: ProxyProtocol::Socks5,
host: "192.168.50.111".to_string(),
port: 8080,
requires_component: None,
}
}
fn local_singbox_target() -> Target {
Target {
id: "local-singbox".to_string(),
name: "Local sing-box".to_string(),
kind: TargetKind::Local,
protocol: ProxyProtocol::Socks5,
host: "127.0.0.1".to_string(),
port: 1080,
requires_component: Some(ComponentId::Singbox),
}
}
fn missing_singbox_component() -> ComponentStatus {
ComponentStatus {
id: ComponentId::Singbox,
name: "Local sing-box".to_string(),
state: ComponentState::Missing,
installed: false,
running: false,
version: None,
path: None,
problems: vec!["Local sing-box is not installed".to_string()],
actions: vec!["Install Local sing-box".to_string()],
}
}
fn running_singbox_component() -> ComponentStatus {
ComponentStatus {
id: ComponentId::Singbox,
name: "Local sing-box".to_string(),
state: ComponentState::Running,
installed: true,
running: true,
version: Some("1.11.0".to_string()),
path: Some(r"C:\Tools\VpnProxy\sing-box\sing-box.exe".to_string()),
problems: Vec::new(),
actions: vec!["Restart".to_string(), "Stop".to_string()],
}
}