steid

@jamesgill /

2.4 KBCode·Blame·Raw
0d12f7dfeat: config from env and SQLite pool in app context1mo
1use std::path::PathBuf;
2
3use serde::Deserialize;
4
5/// Application configuration, read from `STEID_`-prefixed environment variables.
6///
7/// The bind address is deliberately absent: Topcoat owns it via `HOST` and `PORT`.
8#[derive(Debug, Clone, Deserialize)]
9pub struct AppConfig {
10 /// SQLite connection string. Needs `mode=rwc` to create the file on first boot.
11 #[serde(default = "default_database_url")]
12 pub database_url: String,
13
14 /// Root directory for bare git repositories, laid out as `{data_dir}/{org}/{repo}.git`.
15 ///
16 /// Unread until Milestone 2 introduces `GitStorage`; carried now so the config
17 /// surface matches the documented environment.
18 #[allow(dead_code)]
19 #[serde(default = "default_data_dir")]
20 pub data_dir: PathBuf,
21}
22
23fn default_database_url() -> String {
24 "sqlite:steid.db?mode=rwc".to_owned()
25}
26
27fn default_data_dir() -> PathBuf {
28 PathBuf::from("./data")
29}
30
31impl AppConfig {
32 /// Loads configuration from the environment, applying defaults for anything unset.
33 pub fn from_env() -> Result<Self, envy::Error> {
34 envy::prefixed("STEID_").from_env()
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 /// Builds a config from an explicit iterator rather than the process environment,
43 /// so tests don't race on shared global state.
44 fn from_pairs(pairs: &[(&str, &str)]) -> Result<AppConfig, envy::Error> {
45 envy::prefixed("STEID_")
46 .from_iter(pairs.iter().map(|(k, v)| ((*k).to_owned(), (*v).to_owned())))
47 }
48
49 #[test]
50 fn applies_defaults_when_environment_is_empty() {
51 let config = from_pairs(&[]).expect("defaults should satisfy every field");
52
53 assert_eq!(config.database_url, "sqlite:steid.db?mode=rwc");
54 assert_eq!(config.data_dir, PathBuf::from("./data"));
55 }
56
57 #[test]
58 fn reads_prefixed_variables() {
59 let config = from_pairs(&[
60 ("STEID_DATABASE_URL", "sqlite:custom.db?mode=rwc"),
61 ("STEID_DATA_DIR", "/srv/steid/repos"),
62 ])
63 .expect("explicit values should parse");
64
65 assert_eq!(config.database_url, "sqlite:custom.db?mode=rwc");
66 assert_eq!(config.data_dir, PathBuf::from("/srv/steid/repos"));
67 }
68
69 #[test]
70 fn ignores_unprefixed_variables() {
71 let config = from_pairs(&[("DATA_DIR", "/should/be/ignored")])
72 .expect("unprefixed keys should not interfere");
73
74 assert_eq!(config.data_dir, PathBuf::from("./data"));
75 }
76}