Skip to content

Commit

Permalink
improving tests
Browse files Browse the repository at this point in the history
  • Loading branch information
oiwn committed Dec 1, 2024
1 parent 65e9d0f commit a12d396
Show file tree
Hide file tree
Showing 4 changed files with 768 additions and 19 deletions.
4 changes: 4 additions & 0 deletions capp-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ reqwest = { workspace = true, optional = true }
tokio = { workspace = true, optional = true}
tracing = { workspace = true }
rand = { workspace = true }
thiserror = { workspace = true }

backoff = { version = "0.4", optional = true, features = ["tokio"] }
regex = "1.11"
indexmap = "2.6"
url = "2.5"
serde_yaml = "0.9"

[dev-dependencies]
tempfile = "3"

[features]
http = ["dep:reqwest", "dep:tokio", "dep:backoff"]
111 changes: 92 additions & 19 deletions capp-config/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,40 @@ use std::{
path,
};

#[derive(thiserror::Error, Debug)]
pub enum ConfigError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("YAML parsing error: {0}")]
YamlParse(#[from] serde_yaml::Error),
#[error("Line parsing error: {0}")]
LineParse(String),
}

pub trait Configurable {
fn config(&self) -> &serde_yaml::Value;

// read configuration from yaml config
fn load_config(
config_file_path: impl AsRef<path::Path>,
) -> Result<serde_yaml::Value, io::Error> {
) -> Result<serde_yaml::Value, ConfigError> {
let content: String = fs::read_to_string(config_file_path)?;
let config: serde_yaml::Value = serde_yaml::from_str(&content).unwrap();
let config: serde_yaml::Value = serde_yaml::from_str(&content)?;
Ok(config)
}

/// Load Vec<String> from file with path `file path`
fn load_text_file_lines(
file_path: impl AsRef<path::Path>,
) -> Result<Vec<String>, io::Error> {
) -> Result<Vec<String>, ConfigError> {
let file = fs::File::open(file_path)?;
let lines: Vec<String> = io::BufReader::new(file)
let lines = io::BufReader::new(file)
.lines()
.map(|l| l.expect("Could not parse line"))
.collect();

.map(|l| l.map_err(|e| ConfigError::LineParse(e.to_string())))
.collect::<Result<Vec<_>, _>>()?;
Ok(lines)
}

fn load_text_file_content(
file_path: impl AsRef<path::Path>,
) -> Result<String, io::Error> {
fs::read_to_string(file_path)
}

/// Extract Value from config using dot notation i.e. "app.concurrency"
fn get_config_value(&self, key: &str) -> Option<&serde_yaml::Value> {
let keys: Vec<&str> = key.split('.').collect();
Expand Down Expand Up @@ -74,19 +77,22 @@ pub trait Configurable {
#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
use std::io::Write;
use tempfile::tempdir;

pub struct Application {
pub struct TestApp {
config: serde_yaml::Value,
user_agents: Option<Vec<String>>,
}

impl Configurable for Application {
impl Configurable for TestApp {
fn config(&self) -> &serde_yaml::Value {
&self.config
}
}

impl Application {
impl TestApp {
fn from_config(config_file_path: impl AsRef<path::Path>) -> Self {
let config = Self::load_config(config_file_path);
Self {
Expand All @@ -103,17 +109,62 @@ mod tests {
#[test]
fn test_load_config() {
let config_path = "../tests/simple_config.yml";
let app = Application::from_config(config_path);
let app = TestApp::from_config(config_path);

assert_eq!(app.config["app"]["threads"].as_u64(), Some(4));
assert_eq!(app.config()["app"]["max_queue"].as_u64(), Some(500));
assert_eq!(app.user_agents, None);
}

#[test]
fn test_load_config_valid_yaml() {
let dir = tempdir().unwrap();
let config_path = dir.path().join("config.yml");
let mut file = File::create(&config_path).unwrap();
writeln!(file, "key: value\napp:\n setting: 42").unwrap();

let config = TestApp::load_config(&config_path);
assert!(config.is_ok());
let config = config.unwrap();
assert_eq!(config["key"].as_str(), Some("value"));
assert_eq!(config["app"]["setting"].as_i64(), Some(42));
}

#[test]
fn test_load_config_invalid_yaml() {
let dir = tempdir().unwrap();
let config_path = dir.path().join("config.yml");
let mut file = File::create(&config_path).unwrap();
writeln!(file, "invalid: : yaml: content").unwrap();

let config = TestApp::load_config(&config_path);
assert!(matches!(config, Err(ConfigError::YamlParse(_))));
}

#[test]
fn test_load_text_file_lines() {
let dir = tempdir().unwrap();
let file_path = dir.path().join("test.txt");
let mut file = File::create(&file_path).unwrap();
writeln!(file, "line1\nline2\nline3").unwrap();

let lines = TestApp::load_text_file_lines(&file_path);
assert!(lines.is_ok());
let lines = lines.unwrap();
assert_eq!(lines, vec!["line1", "line2", "line3"]);
}

#[test]
fn test_get_config_value_empty_keys() {
let config_path = "../tests/simple_config.yml";
let app = TestApp::from_config(config_path);
assert_eq!(app.get_config_value(""), None);
}

#[test]
fn test_get_config_value() {
let config_path = "../tests/simple_config.yml";
let app = Application::from_config(config_path);
let app = TestApp::from_config(config_path);

assert_eq!(
app.get_config_value("logging.log_to_redis")
Expand All @@ -123,10 +174,32 @@ mod tests {
)
}

#[test]
fn test_get_config_value_recursive() {
let yaml = r#"
app:
nested:
value: 42
"#;
let config: serde_yaml::Value = serde_yaml::from_str(yaml).unwrap();
let app = TestApp {
config,
user_agents: None,
};

assert_eq!(
app.get_config_value("app.nested.value")
.and_then(|v| v.as_i64()),
Some(42)
);
assert_eq!(app.get_config_value("app.missing.value"), None);
assert_eq!(app.get_config_value("missing"), None);
}

#[test]
fn test_load_lines() {
let config_path = "../tests/simple_config.yml";
let mut app = Application::from_config(config_path);
let mut app = TestApp::from_config(config_path);
let uas_file_path = {
app.get_config_value("app.user_agents_file")
.unwrap()
Expand Down
1 change: 1 addition & 0 deletions capp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ rand = "0.8"
md5 = "0.7"
url = "2.5"
base64 = "0.22"
tempfile = "3"

[features]
http = ["dep:reqwest", "capp-config/http"]
Expand Down
671 changes: 671 additions & 0 deletions tarpaulin-report.html

Large diffs are not rendered by default.

0 comments on commit a12d396

Please sign in to comment.