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
61impl Default for SignalsConfig {
62 fn default() -> Self {
63 Self {
64 enabled: true,
65 auto_capture: true,
66 diagnostics: true,
67 session_timeout_mins: default_session_timeout_mins(),
68 retention_days: default_retention_days(),
69 anonymize_ip: false,
70 batch_size: default_batch_size(),
71 flush_interval_ms: default_flush_interval_ms(),
72 excluded_functions: Vec::new(),
73 bot_detection: true,
74 }
75 }
76}
77
78use super::default_true;
79
80fn default_session_timeout_mins() -> u32 {
81 30
82}
83
84fn default_retention_days() -> u32 {
85 90
86}
87
88fn default_batch_size() -> usize {
89 100
90}
91
92fn default_flush_interval_ms() -> u64 {
93 5000
94}
95
96#[cfg(test)]
97#[allow(clippy::unwrap_used)]
98mod tests {
99 use super::*;
100
101 #[tokio::test]
102 async fn default_config_has_correct_values() {
103 let config = SignalsConfig::default();
104 assert!(config.enabled);
105 assert!(config.auto_capture);
106 assert!(config.diagnostics);
107 assert_eq!(config.session_timeout_mins, 30);
108 assert_eq!(config.retention_days, 90);
109 assert!(!config.anonymize_ip);
110 assert_eq!(config.batch_size, 100);
111 assert_eq!(config.flush_interval_ms, 5000);
112 assert!(config.excluded_functions.is_empty());
113 assert!(config.bot_detection);
114 }
115
116 #[tokio::test]
117 async fn deserializes_empty_toml() {
118 #[derive(Deserialize)]
119 struct Wrapper {
120 #[serde(default)]
121 signals: SignalsConfig,
122 }
123
124 let from_empty: SignalsConfig = toml::from_str("").unwrap();
125 let from_table: Wrapper = toml::from_str("[signals]").unwrap();
126
127 for config in [from_empty, from_table.signals] {
128 assert!(config.enabled);
129 assert!(config.auto_capture);
130 assert!(config.diagnostics);
131 assert_eq!(config.session_timeout_mins, 30);
132 assert_eq!(config.retention_days, 90);
133 assert!(!config.anonymize_ip);
134 assert_eq!(config.batch_size, 100);
135 assert_eq!(config.flush_interval_ms, 5000);
136 assert!(config.excluded_functions.is_empty());
137 assert!(config.bot_detection);
138 }
139 }
140
141 #[tokio::test]
142 async fn partial_override_preserves_defaults() {
143 let config: SignalsConfig = toml::from_str("enabled = false").unwrap();
144 assert!(!config.enabled);
145 assert!(config.auto_capture);
146 assert!(config.diagnostics);
147 assert_eq!(config.session_timeout_mins, 30);
148 assert_eq!(config.retention_days, 90);
149 assert!(!config.anonymize_ip);
150 assert_eq!(config.batch_size, 100);
151 assert_eq!(config.flush_interval_ms, 5000);
152 assert!(config.excluded_functions.is_empty());
153 assert!(config.bot_detection);
154 }
155
156 #[tokio::test]
157 async fn excluded_functions_from_toml() {
158 let config: SignalsConfig =
159 toml::from_str(r#"excluded_functions = ["health_check", "readiness"]"#).unwrap();
160 assert_eq!(config.excluded_functions, vec!["health_check", "readiness"]);
161 }
162
163 #[tokio::test]
164 async fn all_fields_overridden() {
165 let toml_str = r#"
166 enabled = false
167 auto_capture = false
168 diagnostics = false
169 session_timeout_mins = 60
170 retention_days = 30
171 anonymize_ip = true
172 batch_size = 500
173 flush_interval_ms = 10000
174 excluded_functions = ["ping"]
175 bot_detection = false
176 "#;
177 let config: SignalsConfig = toml::from_str(toml_str).unwrap();
178 assert!(!config.enabled);
179 assert!(!config.auto_capture);
180 assert!(!config.diagnostics);
181 assert_eq!(config.session_timeout_mins, 60);
182 assert_eq!(config.retention_days, 30);
183 assert!(config.anonymize_ip);
184 assert_eq!(config.batch_size, 500);
185 assert_eq!(config.flush_interval_ms, 10000);
186 assert_eq!(config.excluded_functions, vec!["ping"]);
187 assert!(!config.bot_detection);
188 }
189}