forge_core/config/
signals.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct SignalsConfig {
20 #[serde(default = "default_true")]
22 pub enabled: bool,
23
24 #[serde(default = "default_true")]
26 pub auto_capture: bool,
27
28 #[serde(default = "default_true")]
30 pub diagnostics: bool,
31
32 #[serde(default = "default_session_timeout_mins")]
34 pub session_timeout_mins: u32,
35
36 #[serde(default = "default_retention_days")]
38 pub retention_days: u32,
39
40 #[serde(default)]
42 pub anonymize_ip: bool,
43
44 #[serde(default = "default_batch_size")]
46 pub batch_size: usize,
47
48 #[serde(default = "default_flush_interval_ms")]
50 pub flush_interval_ms: u64,
51
52 #[serde(default)]
54 pub excluded_functions: Vec<String>,
55
56 #[serde(default = "default_true")]
58 pub bot_detection: bool,
59
60 #[serde(default)]
64 pub geoip_db_path: Option<String>,
65}
66
67impl Default for SignalsConfig {
68 fn default() -> Self {
69 Self {
70 enabled: true,
71 auto_capture: true,
72 diagnostics: true,
73 session_timeout_mins: default_session_timeout_mins(),
74 retention_days: default_retention_days(),
75 anonymize_ip: false,
76 batch_size: default_batch_size(),
77 flush_interval_ms: default_flush_interval_ms(),
78 excluded_functions: Vec::new(),
79 bot_detection: true,
80 geoip_db_path: None,
81 }
82 }
83}
84
85use super::default_true;
86
87fn default_session_timeout_mins() -> u32 {
88 30
89}
90
91fn default_retention_days() -> u32 {
92 90
93}
94
95fn default_batch_size() -> usize {
96 100
97}
98
99fn default_flush_interval_ms() -> u64 {
100 5000
101}
102
103#[cfg(test)]
104#[allow(clippy::unwrap_used)]
105mod tests {
106 use super::*;
107
108 #[tokio::test]
109 async fn default_config_has_correct_values() {
110 let config = SignalsConfig::default();
111 assert!(config.enabled);
112 assert!(config.auto_capture);
113 assert!(config.diagnostics);
114 assert_eq!(config.session_timeout_mins, 30);
115 assert_eq!(config.retention_days, 90);
116 assert!(!config.anonymize_ip);
117 assert_eq!(config.batch_size, 100);
118 assert_eq!(config.flush_interval_ms, 5000);
119 assert!(config.excluded_functions.is_empty());
120 assert!(config.bot_detection);
121 }
122
123 #[tokio::test]
124 async fn deserializes_empty_toml() {
125 #[derive(Deserialize)]
126 struct Wrapper {
127 #[serde(default)]
128 signals: SignalsConfig,
129 }
130
131 let from_empty: SignalsConfig = toml::from_str("").unwrap();
132 let from_table: Wrapper = toml::from_str("[signals]").unwrap();
133
134 for config in [from_empty, from_table.signals] {
135 assert!(config.enabled);
136 assert!(config.auto_capture);
137 assert!(config.diagnostics);
138 assert_eq!(config.session_timeout_mins, 30);
139 assert_eq!(config.retention_days, 90);
140 assert!(!config.anonymize_ip);
141 assert_eq!(config.batch_size, 100);
142 assert_eq!(config.flush_interval_ms, 5000);
143 assert!(config.excluded_functions.is_empty());
144 assert!(config.bot_detection);
145 }
146 }
147
148 #[tokio::test]
149 async fn partial_override_preserves_defaults() {
150 let config: SignalsConfig = toml::from_str("enabled = false").unwrap();
151 assert!(!config.enabled);
152 assert!(config.auto_capture);
153 assert!(config.diagnostics);
154 assert_eq!(config.session_timeout_mins, 30);
155 assert_eq!(config.retention_days, 90);
156 assert!(!config.anonymize_ip);
157 assert_eq!(config.batch_size, 100);
158 assert_eq!(config.flush_interval_ms, 5000);
159 assert!(config.excluded_functions.is_empty());
160 assert!(config.bot_detection);
161 }
162
163 #[tokio::test]
164 async fn excluded_functions_from_toml() {
165 let config: SignalsConfig =
166 toml::from_str(r#"excluded_functions = ["health_check", "readiness"]"#).unwrap();
167 assert_eq!(config.excluded_functions, vec!["health_check", "readiness"]);
168 }
169
170 #[tokio::test]
171 async fn all_fields_overridden() {
172 let toml_str = r#"
173 enabled = false
174 auto_capture = false
175 diagnostics = false
176 session_timeout_mins = 60
177 retention_days = 30
178 anonymize_ip = true
179 batch_size = 500
180 flush_interval_ms = 10000
181 excluded_functions = ["ping"]
182 bot_detection = false
183 "#;
184 let config: SignalsConfig = toml::from_str(toml_str).unwrap();
185 assert!(!config.enabled);
186 assert!(!config.auto_capture);
187 assert!(!config.diagnostics);
188 assert_eq!(config.session_timeout_mins, 60);
189 assert_eq!(config.retention_days, 30);
190 assert!(config.anonymize_ip);
191 assert_eq!(config.batch_size, 500);
192 assert_eq!(config.flush_interval_ms, 10000);
193 assert_eq!(config.excluded_functions, vec!["ping"]);
194 assert!(!config.bot_detection);
195 }
196}