test: 增加endpoint的单元测试

This commit is contained in:
shiro.lee
2024-07-05 15:45:33 +08:00
parent 9db3a04275
commit edb2016b28
2 changed files with 168 additions and 14 deletions
+166 -12
View File
@@ -9,7 +9,7 @@ use std::{collections::HashMap, path::Path, usize};
use url::{ParseError, Url}; use url::{ParseError, Url};
/// enum for endpoint type. /// enum for endpoint type.
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq, Debug)]
pub enum EndpointType { pub enum EndpointType {
/// path style endpoint type enum. /// path style endpoint type enum.
Path, Path,
@@ -44,7 +44,7 @@ pub struct Node {
} }
/// any type of endpoint. /// any type of endpoint.
#[derive(Debug, Clone)] #[derive(Debug, PartialEq, Eq)]
pub struct Endpoint { pub struct Endpoint {
pub url: url::Url, pub url: url::Url,
pub is_local: bool, pub is_local: bool,
@@ -95,8 +95,13 @@ impl TryFrom<&str> for Endpoint {
return Err(Error::from_string("invalid URL endpoint format")); return Err(Error::from_string("invalid URL endpoint format"));
} }
if is_empty_path(Path::new(url.path()).clean()) { let path = Path::new(url.path()).clean();
return Err(Error::from_string("empty or root endpoint is not supported")); if is_empty_path(&path) {
return Err(Error::from_string("empty or root path is not supported in URL endpoint"));
}
if let Some(v) = path.to_str() {
url.set_path(v)
} }
// On windows having a preceding SlashSeparator will cause problems, if the // On windows having a preceding SlashSeparator will cause problems, if the
@@ -496,7 +501,8 @@ fn url_parse_from_file_path(value: &str) -> Result<url::Url> {
// Only check if the arg is an ip address and ask for scheme since its absent. // Only check if the arg is an ip address and ask for scheme since its absent.
// localhost, example.com, any FQDN cannot be disambiguated from a regular file path such as // localhost, example.com, any FQDN cannot be disambiguated from a regular file path such as
// /mnt/export1. So we go ahead and start the rustfs server in FS modes in these cases. // /mnt/export1. So we go ahead and start the rustfs server in FS modes in these cases.
if net::is_socket_addr(value) { let addr: Vec<&str> = value.splitn(2, '/').collect();
if net::is_socket_addr(addr[0]) {
return Err(Error::from_string("invalid URL endpoint format: missing scheme http or https")); return Err(Error::from_string("invalid URL endpoint format: missing scheme http or https"));
} }
@@ -507,7 +513,7 @@ fn url_parse_from_file_path(value: &str) -> Result<url::Url> {
match Url::from_file_path(file_path) { match Url::from_file_path(file_path) {
Ok(url) => Ok(url), Ok(url) => Ok(url),
Err(_) => return Err(Error::from_string("Convert a file path into an URL failed")), Err(_) => Err(Error::from_string("Convert a file path into an URL failed")),
} }
} }
@@ -527,11 +533,12 @@ mod test {
let u2 = url::Url::parse("https://example.org/path").unwrap(); let u2 = url::Url::parse("https://example.org/path").unwrap();
let u4 = url::Url::parse("http://192.168.253.200/path").unwrap(); let u4 = url::Url::parse("http://192.168.253.200/path").unwrap();
let u6 = url::Url::parse("http://server:/path").unwrap();
let root_slash_foo = url::Url::from_file_path("/foo").unwrap(); let root_slash_foo = url::Url::from_file_path("/foo").unwrap();
let test_cases = [ let test_cases = [
TestCase { TestCase {
arg: "d:/foo", arg: "/foo",
expected_endpoint: Some(Endpoint { expected_endpoint: Some(Endpoint {
url: root_slash_foo, url: root_slash_foo,
is_local: true, is_local: true,
@@ -606,7 +613,7 @@ mod test {
arg: "http://:/path", arg: "http://:/path",
expected_endpoint: None, expected_endpoint: None,
expected_type: None, expected_type: None,
expected_err: Some(Error::from_string("invalid URL endpoint format: invalid port number")), expected_err: Some(Error::from_string("invalid URL endpoint format: empty host name")),
}, },
TestCase { TestCase {
arg: "http://:8080/path", arg: "http://:8080/path",
@@ -616,9 +623,15 @@ mod test {
}, },
TestCase { TestCase {
arg: "http://server:/path", arg: "http://server:/path",
expected_endpoint: None, expected_endpoint: Some(Endpoint {
expected_type: None, url: u6,
expected_err: Some(Error::from_string("invalid URL endpoint format: invalid port number")), is_local: false,
pool_idx: None,
set_idx: None,
disk_idx: None,
}),
expected_type: Some(EndpointType::Url),
expected_err: None,
}, },
TestCase { TestCase {
arg: "https://93.184.216.34:808080/path", arg: "https://93.184.216.34:808080/path",
@@ -648,7 +661,148 @@ mod test {
for test_case in test_cases { for test_case in test_cases {
let ret = Endpoint::try_from(test_case.arg); let ret = Endpoint::try_from(test_case.arg);
println!("{:?}", ret) if test_case.expected_err.is_none() && ret.is_err() {
panic!("{}: error: expected = <nil>, got = {:?}", test_case.arg, ret);
}
if test_case.expected_err.is_some() && ret.is_ok() {
panic!("{}: error: expected = {:?}, got = <nil>", test_case.arg, test_case.expected_err);
}
match (test_case.expected_err, ret) {
(None, Err(e)) => panic!("{}: error: expected = <nil>, got = {}", test_case.arg, e),
(None, Ok(mut ep)) => {
let _ = ep.update_is_local(9000);
if test_case.expected_type != Some(ep.get_type()) {
panic!(
"{}: type: expected = {:?}, got = {:?}",
test_case.arg,
test_case.expected_type,
ep.get_type()
);
}
assert_eq!(test_case.expected_endpoint, Some(ep), "{}: endpoint", test_case.arg);
}
(Some(e), Ok(_)) => panic!("{}: error: expected = {}, got = <nil>", test_case.arg, e),
(Some(e), Err(e2)) => {
assert_eq!(e.to_string(), e2.to_string(), "{}: error: expected = {}, got = {}", test_case.arg, e, e2)
}
}
}
}
#[test]
fn test_new_endpoints() {
let test_cases = [
(vec!["/d1", "/d2", "/d3", "/d4"], None, 1),
(
vec![
"http://localhost/d1",
"http://localhost/d2",
"http://localhost/d3",
"http://localhost/d4",
],
None,
2,
),
(
vec![
"http://example.org/d1",
"http://example.com/d1",
"http://example.net/d1",
"http://example.edu/d1",
],
None,
3,
),
(
vec![
"http://localhost/d1",
"http://localhost/d2",
"http://example.org/d1",
"http://example.org/d2",
],
None,
4,
),
(
vec![
"https://localhost:9000/d1",
"https://localhost:9001/d2",
"https://localhost:9002/d3",
"https://localhost:9003/d4",
],
None,
5,
),
// It is valid WRT endpoint list that same path is expected with different port on same server.
(
vec![
"https://127.0.0.1:9000/d1",
"https://127.0.0.1:9001/d1",
"https://127.0.0.1:9002/d1",
"https://127.0.0.1:9003/d1",
],
None,
6,
),
(vec!["d1", "d2", "d3", "d1"], Some(Error::from_string("duplicate endpoints found")), 7),
(vec!["d1", "d2", "d3", "./d1"], Some(Error::from_string("duplicate endpoints found")), 8),
(
vec![
"http://localhost/d1",
"http://localhost/d2",
"http://localhost/d1",
"http://localhost/d4",
],
Some(Error::from_string("duplicate endpoints found")),
9,
),
(
vec!["ftp://server/d1", "http://server/d2", "http://server/d3", "http://server/d4"],
Some(Error::from_string("'ftp://server/d1': invalid URL endpoint format")),
10,
),
(
vec!["d1", "http://localhost/d2", "d3", "d4"],
Some(Error::from_string("mixed style endpoints are not supported")),
11,
),
(
vec![
"http://example.org/d1",
"https://example.com/d1",
"http://example.net/d1",
"https://example.edut/d1",
],
Some(Error::from_string("mixed scheme is not supported")),
12,
),
(
vec![
"192.168.1.210:9000/tmp/dir0",
"192.168.1.210:9000/tmp/dir1",
"192.168.1.210:9000/tmp/dir2",
"192.168.110:9000/tmp/dir3",
],
Some(Error::from_string(
"'192.168.1.210:9000/tmp/dir0': invalid URL endpoint format: missing scheme http or https",
)),
13,
),
];
for test_case in test_cases {
let args: Vec<String> = test_case.0.iter().map(|v| v.to_string()).collect();
let ret = Endpoints::try_from(args.as_slice());
match (test_case.1, ret) {
(None, Err(e)) => panic!("{}: error: expected = <nil>, got = {}", test_case.2, e),
(None, Ok(_)) => {}
(Some(e), Ok(_)) => panic!("{}: error: expected = {}, got = <nil>", test_case.2, e),
(Some(e), Err(e2)) => {
assert_eq!(e.to_string(), e2.to_string(), "{}: error: expected = {}, got = {}", test_case.2, e, e2)
}
}
} }
} }
} }
+2 -2
View File
@@ -11,10 +11,10 @@ lazy_static! {
} }
/// helper for validating if the provided arg is an ip address. /// helper for validating if the provided arg is an ip address.
pub fn is_socket_addr(host: &str) -> bool { pub fn is_socket_addr(addr: &str) -> bool {
// TODO IPv6 zone information? // TODO IPv6 zone information?
host.parse::<SocketAddr>().is_ok() || host.parse::<IpAddr>().is_ok() addr.parse::<SocketAddr>().is_ok() || addr.parse::<IpAddr>().is_ok()
} }
/// checks if server_addr is valid and local host. /// checks if server_addr is valid and local host.