From 9d738fb3f5295a68910019974eff35e880139783 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 7 Feb 2022 23:17:50 +0100 Subject: [PATCH] Fix default config (#491) The default configuration was broken since the introduction of caching and specifically `max_cache_age`. This fixes deserialization and config merging for the case where this key is missing from the config. --- fixtures/configs/cache.toml | 2 ++ fixtures/configs/empty.toml | 0 fixtures/configs/invalid.toml | 1 + lychee-bin/src/options.rs | 24 ++++++++----- lychee-bin/tests/cli.rs | 65 +++++++++++++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 fixtures/configs/cache.toml create mode 100644 fixtures/configs/empty.toml create mode 100644 fixtures/configs/invalid.toml diff --git a/fixtures/configs/cache.toml b/fixtures/configs/cache.toml new file mode 100644 index 0000000..6d771e2 --- /dev/null +++ b/fixtures/configs/cache.toml @@ -0,0 +1,2 @@ +cache = true +max_age = "1d" diff --git a/fixtures/configs/empty.toml b/fixtures/configs/empty.toml new file mode 100644 index 0000000..e69de29 diff --git a/fixtures/configs/invalid.toml b/fixtures/configs/invalid.toml new file mode 100644 index 0000000..b1cd4c8 --- /dev/null +++ b/fixtures/configs/invalid.toml @@ -0,0 +1 @@ +max_age = 42my diff --git a/lychee-bin/src/options.rs b/lychee-bin/src/options.rs index e5bb551..8a35923 100644 --- a/lychee-bin/src/options.rs +++ b/lychee-bin/src/options.rs @@ -11,12 +11,15 @@ use structopt::StructOpt; pub(crate) const LYCHEE_IGNORE_FILE: &str = ".lycheeignore"; pub(crate) const LYCHEE_CACHE_FILE: &str = ".lycheecache"; -const METHOD: &str = "get"; -const MAX_CONCURRENCY: usize = 128; +const DEFAULT_METHOD: &str = "get"; +const DEFAULT_MAX_CACHE_AGE: &str = "1d"; +const DEFAULT_MAX_CONCURRENCY: usize = 128; // this exists because structopt requires `&str` type values for defaults +// whereas serde expects owned `String` types // (we can't use e.g. `TIMEOUT` or `timeout()` which gets created for serde) -const MAX_CONCURRENCY_STR: &str = concatcp!(MAX_CONCURRENCY); +const MAX_CONCURRENCY_STR: &str = concatcp!(DEFAULT_MAX_CONCURRENCY); +const MAX_CACHE_AGE_STR: &str = concatcp!(DEFAULT_MAX_CACHE_AGE); const MAX_REDIRECTS_STR: &str = concatcp!(DEFAULT_MAX_REDIRECTS); const MAX_RETRIES_STR: &str = concatcp!(DEFAULT_MAX_RETRIES); const STRUCTOPT_HELP_MSG_CACHE: &str = formatcp!( @@ -74,10 +77,11 @@ macro_rules! default_function { default_function! { max_redirects: usize = DEFAULT_MAX_REDIRECTS; max_retries: u64 = DEFAULT_MAX_RETRIES; - max_concurrency: usize = MAX_CONCURRENCY; + max_concurrency: usize = DEFAULT_MAX_CONCURRENCY; + max_cache_age: Duration = humantime::parse_duration(DEFAULT_MAX_CACHE_AGE).unwrap(); user_agent: String = DEFAULT_USER_AGENT.to_string(); timeout: usize = DEFAULT_TIMEOUT; - method: String = METHOD.to_string(); + method: String = DEFAULT_METHOD.to_string(); } // Macro for merging configuration values @@ -152,8 +156,9 @@ pub(crate) struct Config { #[structopt( long, parse(try_from_str = humantime::parse_duration), - default_value = "1d" + default_value = &MAX_CACHE_AGE_STR )] + #[serde(default = "max_cache_age")] pub(crate) max_cache_age: Duration, /// Don't perform any link checking. @@ -261,7 +266,7 @@ pub(crate) struct Config { /// Request method // Using `-X` as a short param similar to curl - #[structopt(short = "X", long, default_value = METHOD)] + #[structopt(short = "X", long, default_value = DEFAULT_METHOD)] #[serde(default = "method")] pub(crate) method: String, @@ -339,7 +344,8 @@ impl Config { no_progress: false; max_redirects: DEFAULT_MAX_REDIRECTS; max_retries: DEFAULT_MAX_RETRIES; - max_concurrency: MAX_CONCURRENCY; + max_concurrency: DEFAULT_MAX_CONCURRENCY; + max_cache_age: humantime::parse_duration(DEFAULT_MAX_CACHE_AGE).unwrap(); threads: None; user_agent: DEFAULT_USER_AGENT; insecure: false; @@ -355,7 +361,7 @@ impl Config { headers: Vec::::new(); accept: None; timeout: DEFAULT_TIMEOUT; - method: METHOD; + method: DEFAULT_METHOD; base: None; basic_auth: None; github_token: None; diff --git a/lychee-bin/tests/cli.rs b/lychee-bin/tests/cli.rs index 1852df5..de1e20e 100644 --- a/lychee-bin/tests/cli.rs +++ b/lychee-bin/tests/cli.rs @@ -498,6 +498,71 @@ mod cli { Ok(()) } + #[tokio::test] + async fn test_example_config() -> Result<()> { + let mock_server = mock_server!(StatusCode::OK); + let mut cmd = main_command(); + cmd.arg("--config") + .arg("lychee.example.toml") + .arg("-") + .write_stdin(mock_server.uri()) + .env_clear() + .assert() + .success() + .stdout(contains("1 Total")) + .stdout(contains("1 OK")); + + Ok(()) + } + + #[tokio::test] + async fn test_empty_config() -> Result<()> { + let mock_server = mock_server!(StatusCode::OK); + let config = fixtures_path().join("configs").join("empty.toml"); + let mut cmd = main_command(); + cmd.arg("--config") + .arg(config) + .arg("-") + .write_stdin(mock_server.uri()) + .env_clear() + .assert() + .success() + .stdout(contains("1 Total")) + .stdout(contains("1 OK")); + + Ok(()) + } + + #[tokio::test] + async fn test_cache_config() -> Result<()> { + let mock_server = mock_server!(StatusCode::OK); + let config = fixtures_path().join("configs").join("cache.toml"); + let mut cmd = main_command(); + cmd.arg("--config") + .arg(config) + .arg("-") + .write_stdin(mock_server.uri()) + .env_clear() + .assert() + .success() + .stdout(contains("1 Total")) + .stdout(contains("1 OK")); + + Ok(()) + } + + #[tokio::test] + async fn test_invalid_config() { + let config = fixtures_path().join("configs").join("invalid.toml"); + let mut cmd = main_command(); + cmd.arg("--config") + .arg(config) + .arg("-") + .env_clear() + .assert() + .failure(); + } + #[test] fn test_lycheeignore_file() -> Result<()> { let mut cmd = main_command();