4b76deaa60
Red Bear OS Team
382 lines
12 KiB
Rust
382 lines
12 KiB
Rust
use std::fs;
|
|
use std::path::PathBuf;
|
|
use std::process::Command;
|
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
|
|
use redbear_netctl_console::backend::{
|
|
ConsoleBackend, FsBackend, IpMode, Profile, RuntimePaths, SecurityKind,
|
|
};
|
|
|
|
fn temp_root(prefix: &str) -> PathBuf {
|
|
let stamp = SystemTime::now()
|
|
.duration_since(UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_nanos();
|
|
let path = std::env::temp_dir().join(format!("{prefix}-{stamp}"));
|
|
fs::create_dir_all(&path).unwrap();
|
|
path
|
|
}
|
|
|
|
fn run_netctl(
|
|
args: &[&str],
|
|
profile_dir: &PathBuf,
|
|
wifictl_root: &PathBuf,
|
|
netcfg_root: &PathBuf,
|
|
) -> String {
|
|
let output = Command::new(env!("CARGO_BIN_EXE_redbear-netctl"))
|
|
.args(args)
|
|
.env("REDBEAR_NETCTL_PROFILE_DIR", profile_dir)
|
|
.env("REDBEAR_WIFICTL_ROOT", wifictl_root)
|
|
.env("REDBEAR_NETCFG_ROOT", netcfg_root)
|
|
.env("REDBEAR_DHCPD_CMD", "/usr/bin/true")
|
|
.output()
|
|
.unwrap();
|
|
|
|
assert!(
|
|
output.status.success(),
|
|
"command {:?} failed: {}",
|
|
args,
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
|
|
String::from_utf8(output.stdout).unwrap()
|
|
}
|
|
|
|
fn console_runtime_paths(
|
|
profile_dir: &PathBuf,
|
|
wifictl_root: &PathBuf,
|
|
netcfg_root: &PathBuf,
|
|
dhcpd_command: &str,
|
|
) -> RuntimePaths {
|
|
RuntimePaths {
|
|
profile_dir: profile_dir.clone(),
|
|
active_profile_path: profile_dir.join("active"),
|
|
wifictl_root: wifictl_root.clone(),
|
|
netcfg_root: netcfg_root.clone(),
|
|
dhcpd_command: dhcpd_command.to_string(),
|
|
dhcp_wait_timeout: std::time::Duration::from_millis(500),
|
|
dhcp_poll_interval: std::time::Duration::from_millis(10),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn cli_start_wifi_profile_writes_connect_path() {
|
|
let profile_dir = temp_root("rbos-netctl-cli-profiles");
|
|
let wifictl_root = temp_root("rbos-netctl-cli-wifictl");
|
|
let netcfg_root = temp_root("rbos-netctl-cli-netcfg");
|
|
fs::create_dir_all(wifictl_root.join("ifaces/wlan0")).unwrap();
|
|
fs::create_dir_all(netcfg_root.join("ifaces/wlan0/addr")).unwrap();
|
|
fs::write(
|
|
netcfg_root.join("ifaces/wlan0/addr/list"),
|
|
"Not configured\n",
|
|
)
|
|
.unwrap();
|
|
|
|
fs::write(
|
|
profile_dir.join("wifi-dhcp"),
|
|
"Description='Wi-Fi'\nInterface=wlan0\nConnection=wifi\nSSID='demo'\nSecurity=wpa2-psk\nKey='secret'\nIP=dhcp\n",
|
|
)
|
|
.unwrap();
|
|
|
|
fs::write(wifictl_root.join("ifaces/wlan0/status"), "connected\n").unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/link-state"),
|
|
"link=connected\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/firmware-status"),
|
|
"firmware=present\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/transport-status"),
|
|
"transport=active\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/transport-init-status"),
|
|
"transport_init=ok\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/activation-status"),
|
|
"activation=ok\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/connect-result"),
|
|
"connect_result=bounded-associated ssid=demo security=wpa2-psk\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/disconnect-result"),
|
|
"disconnect_result=bounded-disconnected\n",
|
|
)
|
|
.unwrap();
|
|
|
|
let dhcp_log = profile_dir.join("dhcp.log");
|
|
let dhcp_script = profile_dir.join("fake-dhcpd.sh");
|
|
fs::write(
|
|
&dhcp_script,
|
|
format!(
|
|
"#!/usr/bin/env bash\nset -euo pipefail\nprintf '%s\\n' \"$1\" > '{}'\nprintf '10.0.0.44/24\\n' > '{}/ifaces/wlan0/addr/list'\n",
|
|
dhcp_log.display(),
|
|
netcfg_root.display()
|
|
),
|
|
)
|
|
.unwrap();
|
|
#[cfg(unix)]
|
|
{
|
|
use std::os::unix::fs::PermissionsExt;
|
|
let mut perms = fs::metadata(&dhcp_script).unwrap().permissions();
|
|
perms.set_mode(0o755);
|
|
fs::set_permissions(&dhcp_script, perms).unwrap();
|
|
}
|
|
|
|
let output = Command::new(env!("CARGO_BIN_EXE_redbear-netctl"))
|
|
.args(["start", "wifi-dhcp"])
|
|
.env("REDBEAR_NETCTL_PROFILE_DIR", &profile_dir)
|
|
.env("REDBEAR_WIFICTL_ROOT", &wifictl_root)
|
|
.env("REDBEAR_NETCFG_ROOT", &netcfg_root)
|
|
.env("REDBEAR_DHCPD_CMD", &dhcp_script)
|
|
.env("REDBEAR_DHCPD_WAIT_MS", "500")
|
|
.env("REDBEAR_DHCPD_POLL_MS", "10")
|
|
.output()
|
|
.unwrap();
|
|
assert!(
|
|
output.status.success(),
|
|
"command {:?} failed: {}",
|
|
["start", "wifi-dhcp"],
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
let started = String::from_utf8(output.stdout).unwrap();
|
|
assert!(started.contains("started wifi-dhcp"));
|
|
assert_eq!(fs::read_to_string(&dhcp_log).unwrap(), "wlan0\n");
|
|
assert_eq!(
|
|
fs::read_to_string(netcfg_root.join("ifaces/wlan0/addr/list")).unwrap(),
|
|
"10.0.0.44/24\n"
|
|
);
|
|
assert_eq!(
|
|
fs::read_to_string(wifictl_root.join("ifaces/wlan0/ssid")).unwrap(),
|
|
"demo\n"
|
|
);
|
|
assert_eq!(
|
|
fs::read_to_string(wifictl_root.join("ifaces/wlan0/security")).unwrap(),
|
|
"wpa2-psk\n"
|
|
);
|
|
assert_eq!(
|
|
fs::read_to_string(wifictl_root.join("ifaces/wlan0/key")).unwrap(),
|
|
"secret\n"
|
|
);
|
|
assert_eq!(
|
|
fs::read_to_string(wifictl_root.join("ifaces/wlan0/prepare")).unwrap(),
|
|
"1\n"
|
|
);
|
|
assert_eq!(
|
|
fs::read_to_string(wifictl_root.join("ifaces/wlan0/init-transport")).unwrap(),
|
|
"1\n"
|
|
);
|
|
assert_eq!(
|
|
fs::read_to_string(wifictl_root.join("ifaces/wlan0/activate-nic")).unwrap(),
|
|
"1\n"
|
|
);
|
|
assert_eq!(
|
|
fs::read_to_string(wifictl_root.join("ifaces/wlan0/connect")).unwrap(),
|
|
"1\n"
|
|
);
|
|
|
|
let status = run_netctl(
|
|
&["status", "wifi-dhcp"],
|
|
&profile_dir,
|
|
&wifictl_root,
|
|
&netcfg_root,
|
|
);
|
|
assert!(status.contains("address=10.0.0.44/24"));
|
|
assert!(status.contains("wifi_status=connected"));
|
|
assert!(status.contains("connect_result=bounded-associated ssid=demo security=wpa2-psk"));
|
|
assert!(status.contains("disconnect_result=bounded-disconnected"));
|
|
|
|
let stopped = run_netctl(
|
|
&["stop", "wifi-dhcp"],
|
|
&profile_dir,
|
|
&wifictl_root,
|
|
&netcfg_root,
|
|
);
|
|
assert!(stopped.contains("stopped wifi-dhcp"));
|
|
assert_eq!(
|
|
fs::read_to_string(wifictl_root.join("ifaces/wlan0/disconnect")).unwrap(),
|
|
"1\n"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn cli_status_reports_pending_wifi_link_honestly() {
|
|
let profile_dir = temp_root("rbos-netctl-cli-pending-profiles");
|
|
let wifictl_root = temp_root("rbos-netctl-cli-pending-wifictl");
|
|
let netcfg_root = temp_root("rbos-netctl-cli-pending-netcfg");
|
|
fs::create_dir_all(wifictl_root.join("ifaces/wlan0")).unwrap();
|
|
fs::create_dir_all(netcfg_root.join("ifaces/wlan0/addr")).unwrap();
|
|
fs::write(
|
|
profile_dir.join("wifi-open-bounded"),
|
|
"Description='Wi-Fi bounded'\nInterface=wlan0\nConnection=wifi\nSSID='demo'\nSecurity=wpa2-psk\nKey='secret'\nIP=bounded\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(profile_dir.join("active"), "wifi-open-bounded\n").unwrap();
|
|
|
|
fs::write(wifictl_root.join("ifaces/wlan0/status"), "associating\n").unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/link-state"),
|
|
"link=associating\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/firmware-status"),
|
|
"firmware=present\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/transport-status"),
|
|
"transport=active\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/transport-init-status"),
|
|
"transport_init=ok\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/activation-status"),
|
|
"activation=ok\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/connect-result"),
|
|
"connect_result=host-bounded-pending ssid=demo security=wpa2-psk\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/disconnect-result"),
|
|
"disconnect_result=bounded-disconnected\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
netcfg_root.join("ifaces/wlan0/addr/list"),
|
|
"Not configured\n",
|
|
)
|
|
.unwrap();
|
|
|
|
let status = run_netctl(
|
|
&["status", "wifi-open-bounded"],
|
|
&profile_dir,
|
|
&wifictl_root,
|
|
&netcfg_root,
|
|
);
|
|
assert!(status.contains("wifi_status=associating"));
|
|
assert!(status.contains("link_state=link=associating"));
|
|
assert!(status.contains("connect_result=host-bounded-pending ssid=demo security=wpa2-psk"));
|
|
}
|
|
|
|
#[test]
|
|
fn cli_start_consumes_console_written_wifi_profile() {
|
|
let profile_dir = temp_root("rbos-netctl-cli-console-profile");
|
|
let wifictl_root = temp_root("rbos-netctl-cli-console-wifictl");
|
|
let netcfg_root = temp_root("rbos-netctl-cli-console-netcfg");
|
|
fs::create_dir_all(wifictl_root.join("ifaces/wlan0")).unwrap();
|
|
fs::create_dir_all(netcfg_root.join("ifaces/wlan0/addr")).unwrap();
|
|
fs::write(
|
|
netcfg_root.join("ifaces/wlan0/addr/list"),
|
|
"Not configured\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(wifictl_root.join("ifaces/wlan0/status"), "associating\n").unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/link-state"),
|
|
"link=associating\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/transport-init-status"),
|
|
"transport_init=ok\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/activation-status"),
|
|
"activation=ok\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/connect-result"),
|
|
"connect_result=host-bounded-pending ssid=console-demo security=wpa2-psk\n",
|
|
)
|
|
.unwrap();
|
|
fs::write(
|
|
wifictl_root.join("ifaces/wlan0/disconnect-result"),
|
|
"disconnect_result=not-run\n",
|
|
)
|
|
.unwrap();
|
|
|
|
let console_backend = FsBackend::new(console_runtime_paths(
|
|
&profile_dir,
|
|
&wifictl_root,
|
|
&netcfg_root,
|
|
"/usr/bin/true",
|
|
));
|
|
let profile = Profile {
|
|
name: "wifi-console-bounded".to_string(),
|
|
description: "Console written Wi-Fi profile".to_string(),
|
|
interface: "wlan0".to_string(),
|
|
ssid: "console-demo".to_string(),
|
|
security: SecurityKind::Wpa2Psk,
|
|
key: "secret".to_string(),
|
|
ip_mode: IpMode::Bounded,
|
|
address: String::new(),
|
|
gateway: String::new(),
|
|
dns: String::new(),
|
|
};
|
|
console_backend.save_profile(&profile).unwrap();
|
|
|
|
let output = Command::new(env!("CARGO_BIN_EXE_redbear-netctl"))
|
|
.args(["start", "wifi-console-bounded"])
|
|
.env("REDBEAR_NETCTL_PROFILE_DIR", &profile_dir)
|
|
.env("REDBEAR_WIFICTL_ROOT", &wifictl_root)
|
|
.env("REDBEAR_NETCFG_ROOT", &netcfg_root)
|
|
.env("REDBEAR_DHCPD_CMD", "/usr/bin/true")
|
|
.output()
|
|
.unwrap();
|
|
assert!(
|
|
output.status.success(),
|
|
"command {:?} failed: {}",
|
|
["start", "wifi-console-bounded"],
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
|
|
let started = String::from_utf8(output.stdout).unwrap();
|
|
assert!(started.contains("started wifi-console-bounded"));
|
|
assert_eq!(
|
|
fs::read_to_string(wifictl_root.join("ifaces/wlan0/ssid")).unwrap(),
|
|
"console-demo\n"
|
|
);
|
|
assert_eq!(
|
|
fs::read_to_string(wifictl_root.join("ifaces/wlan0/security")).unwrap(),
|
|
"wpa2-psk\n"
|
|
);
|
|
assert_eq!(
|
|
fs::read_to_string(wifictl_root.join("ifaces/wlan0/key")).unwrap(),
|
|
"secret\n"
|
|
);
|
|
|
|
let status = run_netctl(
|
|
&["status", "wifi-console-bounded"],
|
|
&profile_dir,
|
|
&wifictl_root,
|
|
&netcfg_root,
|
|
);
|
|
assert!(status.contains("profile=wifi-console-bounded"));
|
|
assert!(status.contains("wifi_status=associating"));
|
|
assert!(status.contains("link_state=link=associating"));
|
|
assert!(
|
|
status.contains("connect_result=host-bounded-pending ssid=console-demo security=wpa2-psk")
|
|
);
|
|
}
|