-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow partial overrides of all configs
The app config defines defaults for a lot of things. However, if the user provides a field, sometimes that means the defaults for the rest of that sub-config don’t use the default and need to be set by the user. This is especially difficult to work around for fields that re-use the same struct. Refactor how the app config fields that share a common struct are contructed to provide a different default for each use of the struct, while still allowing the user to partially override individual fields of the config. Also, add tests for all (most?) of the app config to ensure this behavior is not broken in the future. Closes #152
- Loading branch information
1 parent
31b1828
commit 1d3a719
Showing
52 changed files
with
1,950 additions
and
441 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
[app] | ||
name = "Minimal Example" | ||
|
||
[tracing] | ||
level = "debug" | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
use crate::util::serde_util::UriOrString; | ||
use serde_derive::{Deserialize, Serialize}; | ||
use validator::Validate; | ||
|
||
#[derive(Debug, Clone, Validate, Serialize, Deserialize)] | ||
#[serde(rename_all = "kebab-case")] | ||
pub struct Auth { | ||
#[validate(nested)] | ||
pub jwt: Jwt, | ||
} | ||
|
||
#[derive(Debug, Clone, Validate, Serialize, Deserialize)] | ||
#[serde(rename_all = "kebab-case")] | ||
pub struct Jwt { | ||
pub secret: String, | ||
#[serde(default)] | ||
#[validate(nested)] | ||
pub claims: JwtClaims, | ||
} | ||
|
||
#[derive(Debug, Clone, Default, Validate, Serialize, Deserialize)] | ||
#[serde(rename_all = "kebab-case", default)] | ||
pub struct JwtClaims { | ||
// Todo: Default to the server URL? | ||
#[serde(default)] | ||
pub audience: Vec<UriOrString>, | ||
/// Claim names to require, in addition to the default-required `exp` claim. | ||
#[serde(default)] | ||
pub required_claims: Vec<String>, | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use crate::util::test_util::TestCase; | ||
use insta::assert_toml_snapshot; | ||
use rstest::{fixture, rstest}; | ||
|
||
#[fixture] | ||
#[cfg_attr(coverage_nightly, coverage(off))] | ||
fn case() -> TestCase { | ||
Default::default() | ||
} | ||
|
||
#[rstest] | ||
#[case( | ||
r#" | ||
[jwt] | ||
secret = "foo" | ||
"# | ||
)] | ||
#[case( | ||
r#" | ||
[jwt] | ||
secret = "foo" | ||
[jwt.claims] | ||
audience = ["bar"] | ||
"# | ||
)] | ||
#[case( | ||
r#" | ||
[jwt] | ||
secret = "foo" | ||
[jwt.claims] | ||
required-claims = ["baz"] | ||
"# | ||
)] | ||
#[case( | ||
r#" | ||
[jwt] | ||
secret = "foo" | ||
[jwt.claims] | ||
audience = ["bar"] | ||
required-claims = ["baz"] | ||
"# | ||
)] | ||
#[cfg_attr(coverage_nightly, coverage(off))] | ||
fn auth(_case: TestCase, #[case] config: &str) { | ||
let auth: Auth = toml::from_str(config).unwrap(); | ||
|
||
assert_toml_snapshot!(auth); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/config/auth/snapshots/roadster__config__auth__tests__auth@case_1.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
source: src/config/auth/mod.rs | ||
expression: auth | ||
--- | ||
[jwt] | ||
secret = 'foo' | ||
|
||
[jwt.claims] | ||
audience = [] | ||
required-claims = [] |
10 changes: 10 additions & 0 deletions
10
src/config/auth/snapshots/roadster__config__auth__tests__auth@case_2.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
source: src/config/auth/mod.rs | ||
expression: auth | ||
--- | ||
[jwt] | ||
secret = 'foo' | ||
|
||
[jwt.claims] | ||
audience = ['bar'] | ||
required-claims = [] |
10 changes: 10 additions & 0 deletions
10
src/config/auth/snapshots/roadster__config__auth__tests__auth@case_3.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
source: src/config/auth/mod.rs | ||
expression: auth | ||
--- | ||
[jwt] | ||
secret = 'foo' | ||
|
||
[jwt.claims] | ||
audience = [] | ||
required-claims = ['baz'] |
10 changes: 10 additions & 0 deletions
10
src/config/auth/snapshots/roadster__config__auth__tests__auth@case_4.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
source: src/config/auth/mod.rs | ||
expression: auth | ||
--- | ||
[jwt] | ||
secret = 'foo' | ||
|
||
[jwt.claims] | ||
audience = ['bar'] | ||
required-claims = ['baz'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
use serde_derive::{Deserialize, Serialize}; | ||
use serde_with::serde_as; | ||
use std::time::Duration; | ||
use url::Url; | ||
use validator::Validate; | ||
|
||
#[serde_as] | ||
#[derive(Debug, Clone, Validate, Serialize, Deserialize)] | ||
#[serde(rename_all = "kebab-case")] | ||
pub struct Database { | ||
/// This can be overridden with an environment variable, e.g. `ROADSTER.DATABASE.URI=postgres://example:example@example:1234/example_app` | ||
pub uri: Url, | ||
/// Whether to automatically apply migrations during the app's start up. Migrations can also | ||
/// be manually performed via the `roadster migration [COMMAND]` CLI command. | ||
pub auto_migrate: bool, | ||
#[serde(default = "Database::default_connect_timeout")] | ||
#[serde_as(as = "serde_with::DurationMilliSeconds")] | ||
pub connect_timeout: Duration, | ||
#[serde(default = "Database::default_acquire_timeout")] | ||
#[serde_as(as = "serde_with::DurationMilliSeconds")] | ||
pub acquire_timeout: Duration, | ||
#[serde_as(as = "Option<serde_with::DurationSeconds>")] | ||
pub idle_timeout: Option<Duration>, | ||
#[serde_as(as = "Option<serde_with::DurationSeconds>")] | ||
pub max_lifetime: Option<Duration>, | ||
#[serde(default)] | ||
pub min_connections: u32, | ||
pub max_connections: u32, | ||
} | ||
|
||
impl Database { | ||
fn default_connect_timeout() -> Duration { | ||
Duration::from_millis(1000) | ||
} | ||
|
||
fn default_acquire_timeout() -> Duration { | ||
Duration::from_millis(1000) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod deserialize_tests { | ||
use super::*; | ||
use crate::util::test_util::TestCase; | ||
use insta::assert_toml_snapshot; | ||
use rstest::{fixture, rstest}; | ||
|
||
#[fixture] | ||
#[cfg_attr(coverage_nightly, coverage(off))] | ||
fn case() -> TestCase { | ||
Default::default() | ||
} | ||
|
||
#[rstest] | ||
#[case( | ||
r#" | ||
uri = "https://example.com:1234" | ||
auto-migrate = true | ||
max-connections = 1 | ||
"# | ||
)] | ||
#[case( | ||
r#" | ||
uri = "https://example.com:1234" | ||
auto-migrate = true | ||
max-connections = 1 | ||
connect-timeout = 1000 | ||
acquire-timeout = 2000 | ||
idle-timeout = 3000 | ||
max-lifetime = 4000 | ||
"# | ||
)] | ||
#[cfg_attr(coverage_nightly, coverage(off))] | ||
fn sidekiq(_case: TestCase, #[case] config: &str) { | ||
let database: Database = toml::from_str(config).unwrap(); | ||
|
||
assert_toml_snapshot!(database); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,7 @@ | ||
pub mod app_config; | ||
pub mod auth; | ||
#[cfg(feature = "db-sql")] | ||
pub mod database; | ||
pub mod environment; | ||
pub mod service; | ||
pub mod tracing; |
Oops, something went wrong.