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.
This commit is contained in:
Matthias 2022-02-07 23:17:50 +01:00 committed by GitHub
parent d8305f7f53
commit 9d738fb3f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 83 additions and 9 deletions

2
fixtures/configs/cache.toml vendored Normal file
View file

@ -0,0 +1,2 @@
cache = true
max_age = "1d"

0
fixtures/configs/empty.toml vendored Normal file
View file

1
fixtures/configs/invalid.toml vendored Normal file
View file

@ -0,0 +1 @@
max_age = 42my

View file

@ -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::<String>::new();
accept: None;
timeout: DEFAULT_TIMEOUT;
method: METHOD;
method: DEFAULT_METHOD;
base: None;
basic_auth: None;
github_token: None;

View file

@ -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();