Skip to content

Commit 78215b6

Browse files
committed
feat: [#246] add GrafanaConfig domain model
1 parent a950252 commit 78215b6

File tree

3 files changed

+115
-0
lines changed

3 files changed

+115
-0
lines changed

src/domain/grafana/config.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//! Grafana configuration domain type
2+
3+
use serde::{Deserialize, Serialize};
4+
5+
use crate::shared::secrets::Password;
6+
7+
/// Grafana metrics visualization configuration
8+
///
9+
/// Configures Grafana service for displaying tracker metrics.
10+
/// Grafana requires Prometheus to be enabled for metrics visualization.
11+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
12+
pub struct GrafanaConfig {
13+
/// Grafana admin username
14+
pub admin_user: String,
15+
16+
/// Grafana admin password (should be changed in production)
17+
///
18+
/// Uses `Password` wrapper from secrecy crate for secure handling:
19+
/// - Automatic redaction in debug output (shows `[REDACTED]`)
20+
/// - Memory zeroing when the value is dropped
21+
/// - Explicit `.expose_secret()` calls required to access plaintext
22+
pub admin_password: Password,
23+
}
24+
25+
impl Default for GrafanaConfig {
26+
fn default() -> Self {
27+
Self {
28+
admin_user: "admin".to_string(),
29+
admin_password: Password::new("admin"),
30+
}
31+
}
32+
}
33+
34+
#[cfg(test)]
35+
mod tests {
36+
use super::*;
37+
38+
#[test]
39+
fn it_should_create_grafana_config_with_default_values() {
40+
let config = GrafanaConfig::default();
41+
42+
assert_eq!(config.admin_user, "admin");
43+
assert_eq!(config.admin_password.expose_secret(), "admin");
44+
}
45+
46+
#[test]
47+
fn it_should_create_grafana_config_with_custom_values() {
48+
let config = GrafanaConfig {
49+
admin_user: "custom_admin".to_string(),
50+
admin_password: Password::new("custom_pass"),
51+
};
52+
53+
assert_eq!(config.admin_user, "custom_admin");
54+
assert_eq!(config.admin_password.expose_secret(), "custom_pass");
55+
}
56+
57+
#[test]
58+
fn it_should_serialize_grafana_config_to_json() {
59+
let config = GrafanaConfig {
60+
admin_user: "admin".to_string(),
61+
admin_password: Password::new("secret123"),
62+
};
63+
64+
let json = serde_json::to_string(&config).expect("Failed to serialize");
65+
66+
assert!(json.contains("\"admin_user\":\"admin\""));
67+
assert!(json.contains("\"admin_password\":\"secret123\""));
68+
}
69+
70+
#[test]
71+
fn it_should_deserialize_grafana_config_from_json() {
72+
let json = r#"{"admin_user":"admin","admin_password":"secret123"}"#;
73+
74+
let config: GrafanaConfig = serde_json::from_str(json).expect("Failed to deserialize");
75+
76+
assert_eq!(config.admin_user, "admin");
77+
assert_eq!(config.admin_password.expose_secret(), "secret123");
78+
}
79+
80+
#[test]
81+
fn it_should_redact_password_in_debug_output() {
82+
let config = GrafanaConfig {
83+
admin_user: "admin".to_string(),
84+
admin_password: Password::new("super_secret"),
85+
};
86+
87+
let debug_output = format!("{config:?}");
88+
89+
assert!(debug_output.contains("admin_user: \"admin\""));
90+
assert!(debug_output.contains("Password(SecretBox<str>([REDACTED]"));
91+
assert!(!debug_output.contains("super_secret"));
92+
}
93+
94+
#[test]
95+
fn it_should_clone_grafana_config() {
96+
let config = GrafanaConfig {
97+
admin_user: "admin".to_string(),
98+
admin_password: Password::new("password"),
99+
};
100+
101+
let cloned = config.clone();
102+
103+
assert_eq!(cloned.admin_user, config.admin_user);
104+
assert_eq!(
105+
cloned.admin_password.expose_secret(),
106+
config.admin_password.expose_secret()
107+
);
108+
}
109+
}

src/domain/grafana/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//! Grafana metrics visualization service domain types
2+
3+
pub mod config;
4+
5+
pub use config::GrafanaConfig;

src/domain/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//! - `template` - Core template domain models and business logic
1515
1616
pub mod environment;
17+
pub mod grafana;
1718
pub mod instance_name;
1819
pub mod profile_name;
1920
pub mod prometheus;

0 commit comments

Comments
 (0)