use std::{
net::IpAddr,
path::{Path, PathBuf},
str::FromStr,
};
use crate::traits::ToHostname;
use crate::utils::domain_or_default;
#[test]
fn test_parse_member_name() {
use crate::utils::parse_member_name;
let actual_domains: &mut Vec<Option<&str>> =
&mut vec!["tld", "domain", "zerotier", "test.subdomain"]
.iter()
.map(|s| Some(*s))
.collect::<Vec<Option<&str>>>();
actual_domains.push(None);
for domain in actual_domains {
let domain_name = domain_or_default(*domain).unwrap().clone();
assert_eq!(parse_member_name(None, domain_name.clone()), None);
for name in ["islay", "ALL-CAPS", "Capitalized", "with.dots"] {
assert_eq!(
parse_member_name(Some(name.to_string()), domain_name.clone()),
Some(name.to_fqdn(domain_name.clone()).unwrap()),
"{}",
name,
);
}
for bad_name in [".", "!", "arghle."] {
assert_eq!(
parse_member_name(Some(bad_name.to_string()), domain_name.clone()),
None,
"{}",
bad_name,
);
}
for (orig, translated) in [("Erik's laptop", "eriks-laptop"), ("!foo", "foo")] {
assert_eq!(
parse_member_name(Some(orig.to_string()), domain_name.clone()),
Some(translated.to_fqdn(domain_name.clone()).unwrap()),
"{}",
orig,
);
}
}
}
#[test]
fn test_parse_ip_from_cidr() {
use crate::utils::parse_ip_from_cidr;
let results = vec![
("192.168.12.1/16", "192.168.12.1"),
("10.0.0.0/8", "10.0.0.0"),
("fe80::abcd/128", "fe80::abcd"),
];
for (cidr, ip) in results {
assert_eq!(
parse_ip_from_cidr(String::from(cidr)),
IpAddr::from_str(ip).unwrap(),
"{}",
cidr
);
}
}
#[test]
fn test_domain_or_default() {
use crate::utils::{domain_or_default, DOMAIN_NAME};
use std::str::FromStr;
use trust_dns_server::client::rr::Name;
assert_eq!(
domain_or_default(None).unwrap(),
Name::from_str(DOMAIN_NAME).unwrap()
);
assert_eq!(
domain_or_default(Some("zerotier")).unwrap(),
Name::from_str("zerotier").unwrap()
);
assert_eq!(
domain_or_default(Some("zerotier.tld")).unwrap(),
Name::from_str("zerotier.tld").unwrap()
);
for bad in ["bad.", "~", "!", ".", ""] {
assert!(domain_or_default(Some(bad)).is_err(), "{}", bad);
}
}
#[test]
fn test_central_token() {
use crate::utils::central_token;
assert!(central_token(None).is_err());
std::env::set_var("ZEROTIER_CENTRAL_TOKEN", "abcdef");
assert_eq!(central_token(None).unwrap(), "abcdef");
let hosts = std::fs::read_to_string("/etc/hosts").unwrap();
let token = central_token(Some(Path::new("/etc/hosts")));
assert!(token.is_ok());
assert_eq!(token.unwrap(), hosts.trim());
}
#[test]
#[should_panic]
fn test_central_token_panic() {
use crate::utils::central_token;
central_token(Some(Path::new("/nonexistent"))).unwrap();
}
#[test]
#[cfg(target_os = "linux")]
fn test_supervise_systemd_green() {
use std::path::PathBuf;
let table = vec![
(
"basic",
crate::supervise::Properties {
binpath: String::from("zeronsd"),
network: String::from("1234567891011121"),
token: PathBuf::from("/proc/cpuinfo"),
..Default::default()
},
),
(
"with-filled-in-properties",
crate::supervise::Properties {
binpath: String::from("zeronsd"),
network: String::from("1234567891011121"),
token: PathBuf::from("/proc/cpuinfo"),
domain: Some(String::from("zerotier")),
authtoken: Some(PathBuf::from("/var/lib/zerotier-one/authtoken.secret")),
hosts_file: Some(PathBuf::from("/etc/hosts")),
wildcard_names: true,
distro: None,
..Default::default()
},
),
];
let write = match std::env::var("WRITE_FIXTURES") {
Ok(var) => var != "",
Err(_) => false,
};
if write {
eprintln!("Write mode: not testing, but updating unit files")
}
for (name, mut props) in table {
let path = std::path::PathBuf::from(format!("testdata/supervise/systemd/{}.unit", name));
if !write {
let path = path.canonicalize();
let expected = std::fs::read_to_string(path.unwrap());
let testing = props.supervise_template();
assert_eq!(testing.unwrap(), expected.unwrap(), "{}", name);
} else {
assert!(props.validate().is_ok(), "{}", name);
let template = props.supervise_template();
assert!(template.is_ok(), "{}", name);
assert!(
std::fs::write(path, props.supervise_template().unwrap()).is_ok(),
"{}",
name
);
}
}
}
#[test]
#[cfg(target_os = "linux")]
fn test_supervise_systemd_red() {
use std::path::PathBuf;
let table = vec![
(
"bad network",
crate::supervise::Properties {
binpath: String::from("zeronsd"),
network: String::from("123456789101112"),
token: PathBuf::from("/proc/cpuinfo"),
..Default::default()
},
),
(
"bad token (no file)",
crate::supervise::Properties {
binpath: String::from("zeronsd"),
network: String::from("1234567891011121"),
token: PathBuf::from("~"),
..Default::default()
},
),
(
"bad token (dir)",
crate::supervise::Properties {
binpath: String::from("zeronsd"),
network: String::from("1234567891011121"),
token: PathBuf::from("."),
..Default::default()
},
),
(
"bad hosts (no file)",
crate::supervise::Properties {
binpath: String::from("zeronsd"),
network: String::from("1234567891011121"),
token: PathBuf::from("/proc/cpuinfo"),
hosts_file: Some(PathBuf::from("~")),
..Default::default()
},
),
(
"bad hosts (dir)",
crate::supervise::Properties {
binpath: String::from("zeronsd"),
network: String::from("1234567891011121"),
token: PathBuf::from("/proc/cpuinfo"),
hosts_file: Some(PathBuf::from(".")),
..Default::default()
},
),
(
"bad authtoken (no file)",
crate::supervise::Properties {
binpath: String::from("zeronsd"),
network: String::from("1234567891011121"),
token: PathBuf::from("/proc/cpuinfo"),
authtoken: Some(PathBuf::from("~")),
..Default::default()
},
),
(
"bad authtoken (dir)",
crate::supervise::Properties {
binpath: String::from("zeronsd"),
network: String::from("1234567891011121"),
token: PathBuf::from("/proc/cpuinfo"),
authtoken: Some(PathBuf::from(".")),
..Default::default()
},
),
(
"bad domain (empty string)",
crate::supervise::Properties {
binpath: String::from("zeronsd"),
network: String::from("1234567891011121"),
token: PathBuf::from("/proc/cpuinfo"),
domain: Some(String::from("")),
..Default::default()
},
),
(
"bad domain (invalid)",
crate::supervise::Properties {
binpath: String::from("zeronsd"),
network: String::from("1234567891011121"),
token: PathBuf::from("/proc/cpuinfo"),
domain: Some(String::from("-")),
..Default::default()
},
),
];
for (name, mut props) in table {
assert!(props.validate().is_err(), "{}", name);
}
}
#[test]
fn test_parse_hosts() {
use crate::hosts::parse_hosts;
use std::net::IpAddr;
use std::str::FromStr;
use trust_dns_resolver::Name;
let domain = &Name::from_str("zombocom").unwrap();
for path in std::fs::read_dir(crate::utils::TEST_HOSTS_DIR)
.unwrap()
.into_iter()
.map(|p| p.unwrap())
{
if path.metadata().unwrap().is_file() {
eprintln!("Testing: {}", path.path().display());
let res = parse_hosts(Some(path.path()), domain.clone());
assert!(res.is_ok(), "{}", path.path().display());
let mut table = res.unwrap();
assert_eq!(
table
.remove(&IpAddr::from_str("127.0.0.1").unwrap())
.unwrap()
.first()
.unwrap(),
&Name::from_str("localhost")
.unwrap()
.append_domain(domain)
.unwrap(),
"{}",
path.path().display(),
);
assert_eq!(
table
.remove(&IpAddr::from_str("::1").unwrap())
.unwrap()
.first()
.unwrap(),
&Name::from_str("localhost")
.unwrap()
.append_domain(domain)
.unwrap(),
"{}",
path.path().display(),
);
let mut accounted = vec!["islay.localdomain", "islay"]
.into_iter()
.map(|s| Name::from_str(s).unwrap().append_domain(domain).unwrap());
for name in table
.remove(&IpAddr::from_str("127.0.1.1").unwrap())
.unwrap()
{
assert!(accounted.any(|s| s.eq(&name)));
}
}
}
}
#[test]
fn test_parse_hosts_duplicate() {
use crate::hosts::parse_hosts;
use trust_dns_resolver::Name;
let domain = Name::from_str("zombocom").unwrap();
let res = parse_hosts(
Some(PathBuf::from("testdata/hosts-files/duplicates")),
domain.clone(),
);
assert!(res.is_ok());
let table = res.unwrap();
let result = table.get(&IpAddr::from_str("10.147.20.216").unwrap());
assert!(result.is_some());
let result = result.unwrap();
assert!(result.contains(
&Name::from_str("hostname1")
.unwrap()
.append_domain(&domain)
.unwrap()
));
assert!(result.contains(
&Name::from_str("hostname2.corp")
.unwrap()
.append_domain(&domain)
.unwrap()
));
}