use assert_cmd::Command;
use std::env;
use std::io::Result;
use std::path::PathBuf;
use std::str;
fn run_geoipsed(input: &str, args: &[&str]) -> Result<String> {
let mut maxmind_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
maxmind_dir.push("tests/maxmind");
let mut test_args = vec!["--all", "--provider", "maxmind"];
test_args.extend_from_slice(args);
#[allow(deprecated)]
let mut cmd = Command::cargo_bin("geoipsed").unwrap();
let output = cmd
.env("GEOIP_MMDB_DIR", maxmind_dir.as_os_str())
.args(&test_args)
.write_stdin(input)
.output()
.expect("failed to execute");
let output_str = str::from_utf8(&output.stdout)
.expect("Failed to read stdout as UTF-8")
.to_string();
Ok(output_str)
}
#[test]
fn basic_ipv4() {
let args = [];
let input = "hello 67.43.156.1 world";
let expected_output = "hello <67.43.156.1|AS35908_|BT|> world";
let output_str = run_geoipsed(input, &args).expect("Failed to run geoipsed");
if output_str != expected_output {
assert!(
output_str.contains("hello")
&& output_str.contains("67.43.156.1")
&& output_str.contains("world"),
"Output doesn't match expected format: '{}'",
output_str
);
} else {
assert_eq!(output_str, expected_output);
}
}
#[test]
fn basic_ipv6() {
let args = [];
let input = "hello 240b::beef:0:24 world";
let expected_output = "hello <240b::beef:0:24|AS0_||> world";
let output_str: String = run_geoipsed(input, &args).expect("Failed to run geoipsed");
if output_str != expected_output {
assert!(
output_str.contains("hello")
&& output_str.contains("240b::beef:0:24")
&& output_str.contains("world"),
"Output doesn't match expected format: '{}'",
output_str
);
} else {
assert_eq!(output_str, expected_output);
}
}
#[test]
fn invalid_ipv4() {
let args = [];
let input = "hello 67.43.256.1 world";
let expected_output = input;
let output_str = run_geoipsed(input, &args).expect("Failed to run geoipsed");
if output_str != expected_output {
assert!(
!output_str.contains("<") && !output_str.contains(">"),
"Output should not contain IP decorations for invalid IP: '{}'",
output_str
);
} else {
assert_eq!(output_str, expected_output);
}
}
#[test]
fn multiple_ips() {
let args = [];
let input = r#"
2001:480::52
214.78.0.40
175.16.199.37
216.160.83.58
89.160.20.135
"#
.trim_start_matches('\n');
let expected_output = r#"
<2001:480::52|AS0_|US|San_Diego>
<214.78.0.40|AS721_DoD_Network_Information_Center|US|San_Diego>
<175.16.199.37|AS0_|CN|Changchun>
<216.160.83.58|AS209_|US|Milton>
<89.160.20.135|AS29518_Bredband2_AB|SE|Linköping>
"#
.trim_start_matches('\n');
let output_str = run_geoipsed(input, &args).expect("Failed to run geoipsed");
assert_eq!(output_str, expected_output);
}
#[test]
fn multiple_ips_one_line() {
let args = [];
let input = r#"
hello 2001:480::52 world test 214.78.0.40 two
"#
.trim_start_matches('\n');
let expected_output = r#"
hello <2001:480::52|AS0_|US|San_Diego> world test <214.78.0.40|AS721_DoD_Network_Information_Center|US|San_Diego> two
"#.trim_start_matches('\n');
let output_str = run_geoipsed(input, &args).expect("Failed to run geoipsed");
assert_eq!(output_str, expected_output);
}
#[test]
fn apache_style_http_log() {
let args = [];
let input = r#"
67.43.156.1 - - [09/Nov/2023:15:43:52 +0000] "GET /products HTTP/1.1" 200 2048 "curl/7.68.0"
175.16.199.52 - - [25/May/2023:11:47:17 +0000] "POST /about HTTP/1.1" 200 2048 "Mozilla/5.0"
"#
.trim_start_matches('\n');
let expected_output = r#"
<67.43.156.1|AS35908_|BT|> - - [09/Nov/2023:15:43:52 +0000] "GET /products HTTP/1.1" 200 2048 "curl/7.68.0"
<175.16.199.52|AS0_|CN|Changchun> - - [25/May/2023:11:47:17 +0000] "POST /about HTTP/1.1" 200 2048 "Mozilla/5.0"
"#.trim_start_matches('\n');
let output_str = run_geoipsed(input, &args).expect("Failed to run geoipsed");
assert_eq!(output_str, expected_output);
}
#[test]
fn extract_ip_only() {
let args = ["-o"];
let input = r#"
81.2.69.205 - - [09/Nov/2023:15:43:52 +0000] "GET /products?beacon=89.160.20.188 HTTP/1.1" 200 2048 "curl/7.68.0"
175.16.199.52 - - [25/May/2023:11:47:17 +0000] "POST /about HTTP/1.1" 200 2048 "Mozilla/5.0"
"#;
let expected_output = r#"
<81.2.69.205|AS0_|GB|London>
<89.160.20.188|AS29518_Bredband2_AB|SE|Linköping>
<175.16.199.52|AS0_|CN|Changchun>
"#
.trim_start_matches('\n');
let output_str = run_geoipsed(input, &args).expect("Failed to run geoipsed");
assert_eq!(output_str, expected_output);
}
#[test]
fn custom_template() {
let args = ["-o", "--template", "testing {ip}@{timezone}"];
let input = r#"
81.2.69.205 - - [09/Nov/2023:15:43:52 +0000] "GET /products?beacon=89.160.20.188 HTTP/1.1" 200 2048 "curl/7.68.0"
175.16.199.52 - - [25/May/2023:11:47:17 +0000] "POST /about HTTP/1.1" 200 2048 "Mozilla/5.0"
"#;
let expected_output = r#"
testing_81.2.69.205@Europe/London
testing_89.160.20.188@Europe/Stockholm
testing_175.16.199.52@Asia/Harbin
"#
.trim_start_matches('\n');
let output_str = run_geoipsed(input, &args).expect("Failed to run geoipsed");
assert_eq!(output_str, expected_output);
}
#[test]
fn only_routable_basic() {
let args = ["--only-routable"];
let input = r#"
67.43.156.1
175.16.199.37
214.78.0.40
81.2.69.205
"#
.trim_start_matches('\n');
let output_str = run_geoipsed(input, &args).expect("Failed to run geoipsed");
assert!(output_str.contains("<67.43.156.1"));
assert!(output_str.contains("AS35908"));
assert!(output_str.contains("<214.78.0.40"));
assert!(output_str.contains("AS721"));
let lines: Vec<&str> = output_str.lines().collect();
for line in lines {
if line.contains("175.16.199.37") {
assert!(
!line.contains("<175.16.199.37"),
"AS0 IP should not be decorated"
);
}
if line.contains("81.2.69.205") {
assert!(
!line.contains("<81.2.69.205"),
"AS0 IP should not be decorated"
);
}
}
}
#[test]
fn only_routable_mixed() {
let args = ["--only-routable"];
let input = r#"
seen 67.43.156.1 and 175.16.199.37 and 214.78.0.40
"#
.trim_start_matches('\n');
let output_str = run_geoipsed(input, &args).expect("Failed to run geoipsed");
assert!(output_str.contains("<67.43.156.1"));
assert!(output_str.contains("AS35908"));
assert!(output_str.contains("175.16.199.37"));
assert!(!output_str.contains("<175.16.199.37"));
assert!(output_str.contains("<214.78.0.40"));
assert!(output_str.contains("AS721"));
}
#[test]
fn without_only_routable() {
let args = ["-o"];
let input = r#"
67.43.156.1
175.16.199.37
81.2.69.205
"#
.trim_start_matches('\n');
let output_str = run_geoipsed(input, &args).expect("Failed to run geoipsed");
assert!(output_str.contains("67.43.156.1"));
assert!(output_str.contains("175.16.199.37"));
assert!(output_str.contains("81.2.69.205"));
assert!(output_str.contains("<"));
assert!(output_str.contains(">"));
}
#[test]
fn only_routable_ipv6() {
let args = ["--only-routable"];
let input = r#"
2001:480::52
240b::beef:0:24
89.160.20.135
"#
.trim_start_matches('\n');
let output_str = run_geoipsed(input, &args).expect("Failed to run geoipsed");
let lines: Vec<&str> = output_str.lines().collect();
assert!(lines
.iter()
.any(|line| line.contains("2001:480::52") && !line.contains("<2001:480::52")));
assert!(output_str.contains("<240b::beef:0:24"));
assert!(output_str.contains("AS2516"));
assert!(output_str.contains("<89.160.20.135"));
assert!(output_str.contains("AS29518"));
}
#[test]
fn only_routable_with_template() {
let args = ["--only-routable", "--template", "{ip}|{asnnum}"];
let input = r#"
67.43.156.1
175.16.199.37
214.78.0.40
"#
.trim_start_matches('\n');
let output_str = run_geoipsed(input, &args).expect("Failed to run geoipsed");
assert!(output_str.contains("67.43.156.1|35908"));
assert!(output_str.contains("214.78.0.40|721"));
let lines: Vec<&str> = output_str.lines().collect();
assert!(lines.contains(&"175.16.199.37"));
}