mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-31 17:28:12 +00:00
test: add net tet
This commit is contained in:
+2
-3
@@ -17,6 +17,8 @@ async-trait.workspace = true
|
|||||||
tracing.workspace = true
|
tracing.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
|
time.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
url = "2.5.2"
|
url = "2.5.2"
|
||||||
uuid = { version = "1.8.0", features = ["v4", "fast-rng", "serde"] }
|
uuid = { version = "1.8.0", features = ["v4", "fast-rng", "serde"] }
|
||||||
reed-solomon-erasure = "6.0.0"
|
reed-solomon-erasure = "6.0.0"
|
||||||
@@ -25,15 +27,12 @@ lazy_static = "1.5.0"
|
|||||||
regex = "1.10.5"
|
regex = "1.10.5"
|
||||||
netif = "0.1.6"
|
netif = "0.1.6"
|
||||||
tracing-error = "0.2.0"
|
tracing-error = "0.2.0"
|
||||||
serde_json.workspace = true
|
|
||||||
path-absolutize = "3.1.1"
|
path-absolutize = "3.1.1"
|
||||||
time.workspace = true
|
|
||||||
rmp-serde = "1.3.0"
|
rmp-serde = "1.3.0"
|
||||||
tokio-util = { version = "0.7.11", features = ["io"] }
|
tokio-util = { version = "0.7.11", features = ["io"] }
|
||||||
s3s = "0.10.0"
|
s3s = "0.10.0"
|
||||||
crc32fast = "1.4.2"
|
crc32fast = "1.4.2"
|
||||||
siphasher = "1.0.1"
|
siphasher = "1.0.1"
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
|
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
|
||||||
|
|||||||
@@ -500,3 +500,145 @@ impl EndpointServerPools {
|
|||||||
nodes
|
nodes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new_endpoint() {
|
||||||
|
#[derive(Default)]
|
||||||
|
struct TestCase<'a> {
|
||||||
|
arg: &'a str,
|
||||||
|
expected_endpoint: Option<Endpoint>,
|
||||||
|
expected_type: Option<EndpointType>,
|
||||||
|
expected_err: Option<Error>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let u2 = url::Url::parse("https://example.org/path").unwrap();
|
||||||
|
let u4 = url::Url::parse("http://192.168.253.200/path").unwrap();
|
||||||
|
let root_slash_foo = url::Url::from_file_path("d:/foo").unwrap();
|
||||||
|
|
||||||
|
let test_cases = [
|
||||||
|
TestCase {
|
||||||
|
arg: "d:/foo",
|
||||||
|
expected_endpoint: Some(Endpoint {
|
||||||
|
url: root_slash_foo,
|
||||||
|
is_local: true,
|
||||||
|
pool_idx: None,
|
||||||
|
set_idx: None,
|
||||||
|
disk_idx: None,
|
||||||
|
}),
|
||||||
|
expected_type: Some(EndpointType::Path),
|
||||||
|
expected_err: None,
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "https://example.org/path",
|
||||||
|
expected_endpoint: Some(Endpoint {
|
||||||
|
url: u2,
|
||||||
|
is_local: false,
|
||||||
|
pool_idx: None,
|
||||||
|
set_idx: None,
|
||||||
|
disk_idx: None,
|
||||||
|
}),
|
||||||
|
expected_type: Some(EndpointType::Url),
|
||||||
|
expected_err: None,
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "http://192.168.253.200/path",
|
||||||
|
expected_endpoint: Some(Endpoint {
|
||||||
|
url: u4,
|
||||||
|
is_local: false,
|
||||||
|
pool_idx: None,
|
||||||
|
set_idx: None,
|
||||||
|
disk_idx: None,
|
||||||
|
}),
|
||||||
|
expected_type: Some(EndpointType::Url),
|
||||||
|
expected_err: None,
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("empty or root endpoint is not supported")),
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "/",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("empty or root endpoint is not supported")),
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "\\",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("empty or root endpoint is not supported")),
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "c://foo",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("invalid URL endpoint format")),
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "ftp://foo",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("invalid URL endpoint format")),
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "http://server/path?location",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("invalid URL endpoint format")),
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "http://:/path",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("invalid URL endpoint format: invalid port number")),
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "http://:8080/path",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("invalid URL endpoint format: empty host name")),
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "http://server:/path",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("invalid URL endpoint format: invalid port number")),
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "https://93.184.216.34:808080/path",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("invalid URL endpoint format: port number must be between 1 to 65535")),
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "http://server:8080//",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("empty or root path is not supported in URL endpoint")),
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "http://server:8080/",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("empty or root path is not supported in URL endpoint")),
|
||||||
|
},
|
||||||
|
TestCase {
|
||||||
|
arg: "192.168.1.210:9000",
|
||||||
|
expected_endpoint: None,
|
||||||
|
expected_type: None,
|
||||||
|
expected_err: Some(Error::from_string("invalid URL endpoint format: missing scheme http or https")),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for test_case in test_cases {
|
||||||
|
let ret = Endpoint::try_from(test_case.arg);
|
||||||
|
println!("{:?}", ret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+40
-18
@@ -1,12 +1,19 @@
|
|||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
net::{IpAddr, SocketAddr, ToSocketAddrs},
|
net::{IpAddr, SocketAddr, ToSocketAddrs},
|
||||||
};
|
};
|
||||||
use url::Host;
|
use url::Host;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref LOCAL_IPS: Vec<IpAddr> = must_get_local_ips().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
/// 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(host: &str) -> bool {
|
||||||
|
// TODO IPv6 zone information?
|
||||||
|
|
||||||
host.parse::<SocketAddr>().is_ok() || host.parse::<IpAddr>().is_ok()
|
host.parse::<SocketAddr>().is_ok() || host.parse::<IpAddr>().is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +37,7 @@ pub fn check_local_server_addr(server_addr: &str) -> Result<SocketAddr> {
|
|||||||
SocketAddr::V6(a) => Host::Ipv6(*a.ip()),
|
SocketAddr::V6(a) => Host::Ipv6(*a.ip()),
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_local_host(host, 0, 0).is_ok() {
|
if is_local_host(host, 0, 0)? {
|
||||||
return Ok(a);
|
return Ok(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,22 +45,10 @@ pub fn check_local_server_addr(server_addr: &str) -> Result<SocketAddr> {
|
|||||||
Err(Error::from_string("host in server address should be this server"))
|
Err(Error::from_string("host in server address should be this server"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_host_port(s: &str) -> Result<(String, u16)> {
|
|
||||||
let parts: Vec<&str> = s.split(':').collect();
|
|
||||||
if parts.len() == 2 {
|
|
||||||
if let Ok(port) = parts[1].parse::<u16>() {
|
|
||||||
return Ok((parts[0].to_string(), port));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(Error::from_string("Invalid address format or port number"))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// checks if the given parameter correspond to one of
|
/// checks if the given parameter correspond to one of
|
||||||
/// the local IP of the current machine
|
/// the local IP of the current machine
|
||||||
pub fn is_local_host(host: Host<&str>, port: u16, local_port: u16) -> Result<bool> {
|
pub fn is_local_host(host: Host<&str>, port: u16, local_port: u16) -> Result<bool> {
|
||||||
let local_ips = must_get_local_ips();
|
let local_set: HashSet<IpAddr> = LOCAL_IPS.iter().copied().collect();
|
||||||
|
|
||||||
let local_set: HashSet<IpAddr> = local_ips.into_iter().collect();
|
|
||||||
let is_local_host = match host {
|
let is_local_host = match host {
|
||||||
Host::Domain(domain) => {
|
Host::Domain(domain) => {
|
||||||
let ips = match (domain, 0).to_socket_addrs().map(|v| v.map(|v| v.ip()).collect::<Vec<_>>()) {
|
let ips = match (domain, 0).to_socket_addrs().map(|v| v.map(|v| v.ip()).collect::<Vec<_>>()) {
|
||||||
@@ -75,10 +70,10 @@ pub fn is_local_host(host: Host<&str>, port: u16, local_port: u16) -> Result<boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// returns IPs of local interface
|
/// returns IPs of local interface
|
||||||
fn must_get_local_ips() -> Vec<IpAddr> {
|
fn must_get_local_ips() -> Result<Vec<IpAddr>> {
|
||||||
match netif::up() {
|
match netif::up() {
|
||||||
Ok(up) => up.map(|x| x.address().to_owned()).collect(),
|
Ok(up) => Ok(up.map(|x| x.address().to_owned()).collect()),
|
||||||
Err(_) => vec![],
|
Err(err) => Err(Error::from_string(format!("Unable to get IP addresses of this host: {}", err))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,9 +101,36 @@ mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_check_local_server_addr() {
|
||||||
|
let test_cases = [
|
||||||
|
(":54321", Ok(())),
|
||||||
|
("localhost:54321", Ok(())),
|
||||||
|
("0.0.0.0:9000", Ok(())),
|
||||||
|
(":0", Ok(())),
|
||||||
|
("localhost", Err(Error::from_string("invalid socket address"))),
|
||||||
|
("", Err(Error::from_string("invalid socket address"))),
|
||||||
|
(
|
||||||
|
"example.org:54321",
|
||||||
|
Err(Error::from_string("host in server address should be this server")),
|
||||||
|
),
|
||||||
|
(":-10", Err(Error::from_string("invalid port value"))),
|
||||||
|
];
|
||||||
|
|
||||||
|
for test_case in test_cases {
|
||||||
|
let ret = check_local_server_addr(test_case.0);
|
||||||
|
if test_case.1.is_ok() && ret.is_err() {
|
||||||
|
panic!("{}: error: expected = <nil>, got = {:?}", test_case.0, ret);
|
||||||
|
}
|
||||||
|
if test_case.1.is_err() && ret.is_ok() {
|
||||||
|
panic!("{}: error: expected = {:?}, got = <nil>", test_case.0, test_case.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_must_get_local_ips() {
|
fn test_must_get_local_ips() {
|
||||||
let local_ips = must_get_local_ips();
|
let local_ips = must_get_local_ips().unwrap();
|
||||||
let local_set: HashSet<IpAddr> = local_ips.into_iter().collect();
|
let local_set: HashSet<IpAddr> = local_ips.into_iter().collect();
|
||||||
|
|
||||||
assert!(local_set.contains(&IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))));
|
assert!(local_set.contains(&IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))));
|
||||||
|
|||||||
Reference in New Issue
Block a user