diff --git a/examples/minimal/server.toml b/examples/minimal/server.toml index 1eec033..36396c9 100644 --- a/examples/minimal/server.toml +++ b/examples/minimal/server.toml @@ -4,4 +4,3 @@ default_token = "123" [server.services.foo1] bind_addr = "0.0.0.0:5202" - diff --git a/examples/tls/server.toml b/examples/tls/server.toml index 4dff570..5b0d456 100644 --- a/examples/tls/server.toml +++ b/examples/tls/server.toml @@ -10,4 +10,3 @@ pkcs12_password = "1234" [server.services.foo1] bind_addr = "0.0.0.0:5202" - diff --git a/examples/unified/config.toml b/examples/unified/config.toml new file mode 100644 index 0000000..0eda1f7 --- /dev/null +++ b/examples/unified/config.toml @@ -0,0 +1,15 @@ +# rathole configuration can put in one file as long as running mode is specified via cli + +[client] +remote_addr = "localhost:2333" +default_token = "123" + +[client.services.foo1] +local_addr = "127.0.0.1:80" + +[server] +bind_addr = "0.0.0.0:2333" +default_token = "123" + +[server.services.foo1] +bind_addr = "0.0.0.0:5202" diff --git a/src/config.rs b/src/config.rs index 2b844be..33c1547 100644 --- a/src/config.rs +++ b/src/config.rs @@ -169,21 +169,150 @@ impl Config { #[cfg(test)] mod tests { use super::*; - use std::fs; + use std::{fs, path::PathBuf}; use anyhow::Result; + fn list_config_files>(root: T) -> Result> { + let mut files = Vec::new(); + for entry in fs::read_dir(root)? { + let entry = entry?; + let path = entry.path(); + if path.is_file() { + files.push(path); + } else if path.is_dir() { + files.append(&mut list_config_files(path)?); + } + } + Ok(files) + } + + fn get_all_example_config() -> Result> { + Ok(list_config_files("./examples")? + .into_iter() + .filter(|x| x.ends_with(".toml")) + .collect()) + } + #[test] - fn test_mimic_client_config() -> Result<()> { - let s = fs::read_to_string("./example/minimal/client.toml").unwrap(); - Config::from_str(&s)?; + fn test_example_config() -> Result<()> { + let paths = get_all_example_config()?; + for p in paths { + let s = fs::read_to_string(p)?; + Config::from_str(&s)?; + } Ok(()) } #[test] - fn test_mimic_server_config() -> Result<()> { - let s = fs::read_to_string("./example/minimal/server.toml").unwrap(); - Config::from_str(&s)?; + fn test_valid_config() -> Result<()> { + let paths = list_config_files("tests/config_test/valid_config")?; + for p in paths { + let s = fs::read_to_string(p)?; + Config::from_str(&s)?; + } + Ok(()) + } + + #[test] + fn test_invalid_config() -> Result<()> { + let paths = list_config_files("tests/config_test/invalid_config")?; + for p in paths { + let s = fs::read_to_string(p)?; + assert!(Config::from_str(&s).is_err()); + } + Ok(()) + } + + #[test] + fn test_validate_server_config() -> Result<()> { + let mut cfg = ServerConfig::default(); + + cfg.services.insert( + "foo1".into(), + ServerServiceConfig { + name: "foo1".into(), + bind_addr: "127.0.0.1:80".into(), + token: None, + }, + ); + + // Missing the token + assert!(Config::validate_server_config(&mut cfg).is_err()); + + // Use the default token + cfg.default_token = Some("123".into()); + assert!(Config::validate_server_config(&mut cfg).is_ok()); + assert_eq!( + cfg.services + .get("foo1") + .as_ref() + .unwrap() + .token + .as_ref() + .unwrap(), + "123" + ); + + // The default token won't override the service token + cfg.services.get_mut("foo1").unwrap().token = Some("4".into()); + assert!(Config::validate_server_config(&mut cfg).is_ok()); + assert_eq!( + cfg.services + .get("foo1") + .as_ref() + .unwrap() + .token + .as_ref() + .unwrap(), + "4" + ); + Ok(()) + } + + #[test] + fn test_validate_client_config() -> Result<()> { + let mut cfg = ClientConfig::default(); + + cfg.services.insert( + "foo1".into(), + ClientServiceConfig { + name: "foo1".into(), + local_addr: "127.0.0.1:80".into(), + token: None, + }, + ); + + // Missing the token + assert!(Config::validate_client_config(&mut cfg).is_err()); + + // Use the default token + cfg.default_token = Some("123".into()); + assert!(Config::validate_client_config(&mut cfg).is_ok()); + assert_eq!( + cfg.services + .get("foo1") + .as_ref() + .unwrap() + .token + .as_ref() + .unwrap(), + "123" + ); + + // The default token won't override the service token + cfg.services.get_mut("foo1").unwrap().token = Some("4".into()); + assert!(Config::validate_client_config(&mut cfg).is_ok()); + assert_eq!( + cfg.services + .get("foo1") + .as_ref() + .unwrap() + .token + .as_ref() + .unwrap(), + "4" + ); Ok(()) } } diff --git a/tests/config_test/invalid_config/missing_tls_client.toml b/tests/config_test/invalid_config/missing_tls_client.toml new file mode 100644 index 0000000..8251b49 --- /dev/null +++ b/tests/config_test/invalid_config/missing_tls_client.toml @@ -0,0 +1,9 @@ +[client] +remote_addr = "example.com:2333" + +[client.transport] +type = "tls" + +[client.services.service1] +token = "whatever" +local_addr = "127.0.0.1:1081" diff --git a/tests/config_test/invalid_config/missing_tls_server.toml b/tests/config_test/invalid_config/missing_tls_server.toml new file mode 100644 index 0000000..2d017fe --- /dev/null +++ b/tests/config_test/invalid_config/missing_tls_server.toml @@ -0,0 +1,11 @@ +[server] +bind_addr = "0.0.0.0:2333" + +[server.transport] +type = "tls" +[server.transport.tls] +pkcs12_password = "password" + +[server.services.service1] +token = "whatever" +bind_addr = "0.0.0.0:8081" diff --git a/tests/config_test/invalid_config/missing_tls_server2.toml b/tests/config_test/invalid_config/missing_tls_server2.toml new file mode 100644 index 0000000..9dc8669 --- /dev/null +++ b/tests/config_test/invalid_config/missing_tls_server2.toml @@ -0,0 +1,9 @@ +[server] +bind_addr = "0.0.0.0:2333" + +[server.transport] +type = "tls" + +[server.services.service1] +token = "whatever" +bind_addr = "0.0.0.0:8081" diff --git a/tests/config_test/valid_config/full.toml b/tests/config_test/valid_config/full.toml new file mode 100644 index 0000000..804d83d --- /dev/null +++ b/tests/config_test/valid_config/full.toml @@ -0,0 +1,33 @@ +[client] +remote_addr = "example.com:2333" +default_token = "default_token_if_not_specify" + +[client.transport] +type = "tcp" +[client.transport.tls] +trusted_root = "ca.pem" +hostname = "example.com" + +[client.services.service1] +token = "whatever" +local_addr = "127.0.0.1:1081" + +[client.services.service2] +local_addr = "127.0.0.1:1082" + +[server] +bind_addr = "0.0.0.0:2333" +default_token = "default_token_if_not_specify" + +[server.transport] +type = "tls" +[server.transport.tls] +pkcs12 = "identify.pfx" +pkcs12_password = "password" + +[server.services.service1] +token = "whatever" +bind_addr = "0.0.0.0:8081" + +[server.services.service2] +bind_addr = "0.0.0.1:8082"