Skip to content

Commit be38720

Browse files
authored
Refactor configuration module to use confique for environment variable management (#267)
* Refactor configuration module to use confique for environment variable management * Fixed health check tests - Updated the health check test setup to use the provided configuration directly instead of cloning it. - Added a new test for health check success timing to validate the behavior with an increased timeout. - Enhanced logging setup for better visibility during test execution.
1 parent 0e3c3ea commit be38720

File tree

6 files changed

+145
-336
lines changed

6 files changed

+145
-336
lines changed

pdp-server/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ watchdog = { path = "../watchdog" }
1111
async-trait = "0.1.88"
1212
axum = "0.8.3"
1313
chrono = "0.4.40"
14-
config = "0.15.11"
14+
confique = { version = "0.3.0", features = ["toml"] }
1515
env_logger = "0.11.8"
1616
http = "1.3.1"
1717
log = "0.4.27"

pdp-server/src/api/health/handlers.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ mod test {
384384

385385
let mut config = crate::config::PDPConfig::for_test_with_mocks(&horizon_mock, &opa_mock);
386386
config.healthcheck_timeout = 0.5;
387-
let fixture = TestFixture::with_config(config.clone(), opa_mock, horizon_mock).await;
387+
let fixture = TestFixture::with_config(config, opa_mock, horizon_mock).await;
388388

389389
let start_time = Instant::now();
390390
let response_with_cache = fixture.get("/health?check_cache=true").await;
@@ -428,9 +428,16 @@ mod test {
428428
"Concurrent check took too long: {:?}",
429429
duration_with_cache
430430
);
431+
}
431432

432-
config.healthcheck_timeout = 2.0;
433+
#[tokio::test]
434+
async fn test_health_check_success_timing() {
435+
TestFixture::setup_logger(LevelFilter::Info);
433436
let (horizon_mock_success, opa_mock_success) = setup_healthy_mocks().await;
437+
438+
let mut config =
439+
crate::config::PDPConfig::for_test_with_mocks(&horizon_mock_success, &opa_mock_success);
440+
config.healthcheck_timeout = 2.0;
434441
let fixture_success =
435442
TestFixture::with_config(config, opa_mock_success, horizon_mock_success).await;
436443

pdp-server/src/config/cache.rs

Lines changed: 10 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use confique::Config;
12
use serde::Deserialize;
23

34
/// Specifies which cache store implementation to use
@@ -12,115 +13,37 @@ pub enum CacheStore {
1213
}
1314

1415
/// Configuration for the caching subsystem
15-
#[derive(Debug, Deserialize, Clone)]
16+
#[derive(Debug, Config, Clone, Default)]
1617
pub struct CacheConfig {
1718
/// Cache TTL in seconds (default: 1 hour)
18-
#[serde(default)]
19+
#[config(env = "PDP_CACHE_TTL", default = 3600)]
1920
pub ttl: u32,
2021

2122
/// Cache store type: "in-memory", "redis", or null (default)
22-
#[serde(default)]
23+
#[config(env = "PDP_CACHE_STORE", default = "none")]
2324
pub store: CacheStore,
2425

2526
/// In-memory cache specific configuration
26-
#[serde(default)]
27+
#[config(nested)]
2728
pub memory: InMemoryConfig,
2829

2930
/// Redis cache specific configuration
30-
#[serde(default)]
31+
#[config(nested)]
3132
pub redis: RedisConfig,
3233
}
3334

34-
impl Default for CacheConfig {
35-
fn default() -> Self {
36-
Self {
37-
ttl: 3600, // 1 hour
38-
store: CacheStore::None,
39-
memory: InMemoryConfig::default(),
40-
redis: RedisConfig::default(),
41-
}
42-
}
43-
}
44-
45-
impl CacheConfig {
46-
/// Creates a new configuration from environment variables
47-
pub fn from_env(config: &Self) -> Self {
48-
// Start with the provided configuration
49-
let mut result = config.clone();
50-
51-
// Apply TTL environment variable
52-
if let Ok(ttl) = std::env::var("PDP_CACHE_TTL") {
53-
if let Ok(parsed) = ttl.parse::<u32>() {
54-
result.ttl = parsed;
55-
}
56-
}
57-
58-
// Apply store type from environment
59-
result.store = match std::env::var("PDP_CACHE_STORE").as_deref() {
60-
Ok("in-memory") => CacheStore::InMemory,
61-
Ok("redis") => CacheStore::Redis,
62-
Ok("none") => CacheStore::None,
63-
_ => result.store.clone(), // Keep existing value if not specified
64-
};
65-
66-
// Apply sub-configurations from environment
67-
result.memory = InMemoryConfig::from_env(&result.memory);
68-
result.redis = RedisConfig::from_env(&result.redis);
69-
70-
result
71-
}
72-
}
73-
7435
/// In-memory cache configuration options
75-
#[derive(Debug, Deserialize, Clone)]
36+
#[derive(Debug, Config, Clone, Default)]
7637
pub struct InMemoryConfig {
7738
/// Maximum capacity in MiB (default: 128 MiB)
78-
#[serde(default)]
39+
#[config(env = "PDP_CACHE_MEMORY_CAPACITY", default = 128)]
7940
pub capacity: usize,
8041
}
8142

82-
impl Default for InMemoryConfig {
83-
fn default() -> Self {
84-
Self {
85-
capacity: 128, // 128 MiB
86-
}
87-
}
88-
}
89-
90-
impl InMemoryConfig {
91-
/// Creates a new configuration from environment variables
92-
pub fn from_env(config: &Self) -> Self {
93-
// Start with the provided configuration
94-
let mut result = config.clone();
95-
96-
if let Ok(capacity) = std::env::var("PDP_CACHE_MEMORY_CAPACITY") {
97-
if let Ok(parsed) = capacity.parse::<usize>() {
98-
result.capacity = parsed;
99-
}
100-
}
101-
102-
result
103-
}
104-
}
105-
10643
/// Redis cache configuration options
107-
#[derive(Debug, Deserialize, Clone, Default)]
44+
#[derive(Debug, Config, Clone, Default)]
10845
pub struct RedisConfig {
10946
/// Redis connection string
110-
#[serde(default)]
47+
#[config(env = "PDP_CACHE_REDIS_URL", default = "")]
11148
pub url: String,
11249
}
113-
114-
impl RedisConfig {
115-
/// Creates a new configuration from environment variables
116-
pub fn from_env(config: &Self) -> Self {
117-
// Start with the provided configuration
118-
let mut result = config.clone();
119-
120-
if let Ok(url) = std::env::var("PDP_CACHE_REDIS_URL") {
121-
result.url = url;
122-
}
123-
124-
result
125-
}
126-
}

pdp-server/src/config/horizon.rs

Lines changed: 12 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,49 @@
1-
use serde::Deserialize;
1+
use confique::Config;
22

33
/// Configuration for the Horizon service
4-
#[derive(Debug, Deserialize, Clone)]
4+
#[derive(Debug, Config, Clone, Default)]
55
pub struct HorizonConfig {
66
/// Horizon service hostname (default: 0.0.0.0)
7-
#[serde(default)]
7+
#[config(env = "PDP_HORIZON_HOST", default = "0.0.0.0")]
88
pub host: String,
99

1010
/// Horizon service port (default: 7001)
11-
#[serde(default)]
11+
#[config(env = "PDP_HORIZON_PORT", default = 7001)]
1212
pub port: u16,
1313

1414
/// The timeout for Horizon client queries in seconds (default: 60)
15-
#[serde(default)]
15+
#[config(env = "PDP_HORIZON_CLIENT_TIMEOUT", default = 60)]
1616
pub client_timeout: u64,
1717

1818
/// Python interpreter path for running Horizon (default: python3)
19-
#[serde(default)]
19+
#[config(env = "PDP_HORIZON_PYTHON_PATH", default = "python3")]
2020
pub python_path: String,
2121

2222
/// Health check endpoint timeout in seconds (default: 1)
23-
#[serde(default)]
23+
#[config(env = "PDP_HORIZON_HEALTH_CHECK_TIMEOUT", default = 1)]
2424
pub health_check_timeout: u64,
2525

2626
/// Interval between health checks in seconds (default: 5)
27-
#[serde(default)]
27+
#[config(env = "PDP_HORIZON_HEALTH_CHECK_INTERVAL", default = 5)]
2828
pub health_check_interval: u64,
2929

3030
/// Number of consecutive health check failures before restarting (default: 12)
31-
#[serde(default)]
31+
#[config(env = "PDP_HORIZON_HEALTH_CHECK_FAILURE_THRESHOLD", default = 12)]
3232
pub health_check_failure_threshold: u32,
3333

3434
/// Initial delay before starting health checks in seconds (default: 5)
35-
#[serde(default)]
35+
#[config(env = "PDP_HORIZON_STARTUP_DELAY", default = 5)]
3636
pub startup_delay: u64,
3737

3838
/// Interval between service restart attempts in seconds (default: 1)
39-
#[serde(default)]
39+
#[config(env = "PDP_HORIZON_RESTART_INTERVAL", default = 1)]
4040
pub restart_interval: u64,
4141

4242
/// Service termination timeout in seconds (default: 30)
43-
#[serde(default)]
43+
#[config(env = "PDP_HORIZON_TERMINATION_TIMEOUT", default = 30)]
4444
pub termination_timeout: u64,
4545
}
4646

47-
impl Default for HorizonConfig {
48-
fn default() -> Self {
49-
Self {
50-
host: "0.0.0.0".to_string(),
51-
port: 7001,
52-
client_timeout: 60,
53-
python_path: "python3".to_string(),
54-
health_check_timeout: 1,
55-
health_check_interval: 5,
56-
health_check_failure_threshold: 12,
57-
startup_delay: 5,
58-
restart_interval: 1,
59-
termination_timeout: 30,
60-
}
61-
}
62-
}
63-
6447
impl HorizonConfig {
6548
/// Returns a properly formatted URL to the Horizon service with the given path
6649
pub fn get_url<S: Into<String>>(&self, path: S) -> String {
@@ -71,69 +54,4 @@ impl HorizonConfig {
7154
format!("http://{}:{}/{}", self.host, self.port, path)
7255
}
7356
}
74-
75-
/// Creates a new configuration from environment variables
76-
pub fn from_env(config: &Self) -> Self {
77-
// Start with the provided configuration
78-
let mut result = config.clone();
79-
80-
// Apply environment variable overrides for horizon configuration
81-
if let Ok(host) = std::env::var("PDP_HORIZON_HOST") {
82-
result.host = host;
83-
}
84-
85-
if let Ok(port) = std::env::var("PDP_HORIZON_PORT") {
86-
if let Ok(parsed) = port.parse::<u16>() {
87-
result.port = parsed;
88-
}
89-
}
90-
91-
if let Ok(python_path) = std::env::var("PDP_HORIZON_PYTHON_PATH") {
92-
result.python_path = python_path;
93-
}
94-
95-
if let Ok(timeout) = std::env::var("PDP_HORIZON_CLIENT_TIMEOUT") {
96-
if let Ok(parsed) = timeout.parse::<u64>() {
97-
result.client_timeout = parsed;
98-
}
99-
}
100-
101-
if let Ok(timeout) = std::env::var("PDP_HORIZON_HEALTH_CHECK_TIMEOUT") {
102-
if let Ok(parsed) = timeout.parse::<u64>() {
103-
result.health_check_timeout = parsed;
104-
}
105-
}
106-
107-
if let Ok(interval) = std::env::var("PDP_HORIZON_HEALTH_CHECK_INTERVAL") {
108-
if let Ok(parsed) = interval.parse::<u64>() {
109-
result.health_check_interval = parsed;
110-
}
111-
}
112-
113-
if let Ok(threshold) = std::env::var("PDP_HORIZON_HEALTH_CHECK_FAILURE_THRESHOLD") {
114-
if let Ok(parsed) = threshold.parse::<u32>() {
115-
result.health_check_failure_threshold = parsed;
116-
}
117-
}
118-
119-
if let Ok(delay) = std::env::var("PDP_HORIZON_STARTUP_DELAY") {
120-
if let Ok(parsed) = delay.parse::<u64>() {
121-
result.startup_delay = parsed;
122-
}
123-
}
124-
125-
if let Ok(interval) = std::env::var("PDP_HORIZON_RESTART_INTERVAL") {
126-
if let Ok(parsed) = interval.parse::<u64>() {
127-
result.restart_interval = parsed;
128-
}
129-
}
130-
131-
if let Ok(timeout) = std::env::var("PDP_HORIZON_TERMINATION_TIMEOUT") {
132-
if let Ok(parsed) = timeout.parse::<u64>() {
133-
result.termination_timeout = parsed;
134-
}
135-
}
136-
137-
result
138-
}
13957
}

0 commit comments

Comments
 (0)