1use std::collections::HashMap;
4use std::sync::Arc;
5use std::time::Duration;
6
7use crate::utils::Time;
8use async_trait::async_trait;
9use chrono::{DateTime, Utc};
10use serde::{Deserialize, Serialize};
11use serde_json::Value;
12use tokio::sync::{broadcast, RwLock};
13use uuid::Uuid;
14
15use crate::error::{Error, Result};
16use crate::manager::{ManagedState, Manager, ManagerStatus, PlatformRequirements};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
20pub enum ConfigurationTier {
21 System, Global, User, Local, Runtime, }
27
28impl ConfigurationTier {
29 pub fn all_tiers() -> Vec<Self> {
31 vec![
32 Self::System,
33 Self::Global,
34 Self::User,
35 Self::Local,
36 Self::Runtime,
37 ]
38 }
39
40 pub fn precedence(&self) -> u8 {
42 match self {
43 Self::System => 0,
44 Self::Global => 1,
45 Self::User => 2,
46 Self::Local => 3,
47 Self::Runtime => 4,
48 }
49 }
50}
51
52#[cfg(not(target_arch = "wasm32"))]
54#[async_trait]
55pub trait ConfigStore: Send + Sync {
56 async fn get(&self, key: &str) -> Result<Option<Value>>;
57 async fn set(&self, key: &str, value: Value) -> Result<()>;
58 async fn delete(&self, key: &str) -> Result<()>;
59 async fn list_keys(&self, prefix: &str) -> Result<Vec<String>>;
60 async fn watch(&self, key: &str) -> Result<ConfigWatcher>;
61 fn tier(&self) -> ConfigurationTier;
62}
63
64#[cfg(target_arch = "wasm32")]
65#[async_trait(?Send)]
66pub trait ConfigStore: Sync {
67 async fn get(&self, key: &str) -> Result<Option<Value>>;
68 async fn set(&self, key: &str, value: Value) -> Result<()>;
69 async fn delete(&self, key: &str) -> Result<()>;
70 async fn list_keys(&self, prefix: &str) -> Result<Vec<String>>;
71 async fn watch(&self, key: &str) -> Result<ConfigWatcher>;
72 fn tier(&self) -> ConfigurationTier;
73}
74
75pub struct ConfigWatcher {
77 receiver: broadcast::Receiver<ConfigChangeEvent>,
78}
79
80impl ConfigWatcher {
81 pub fn new(receiver: broadcast::Receiver<ConfigChangeEvent>) -> Self {
82 Self { receiver }
83 }
84
85 pub async fn recv(&mut self) -> Result<ConfigChangeEvent> {
86 self.receiver
87 .recv()
88 .await
89 .map_err(|_| Error::config("Config watch channel closed"))
90 }
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct ConfigChangeEvent {
96 pub key: String,
97 pub value: Option<Value>,
98 pub old_value: Option<Value>,
99 pub tier: ConfigurationTier,
100 pub timestamp: DateTime<Utc>,
101 pub source: String,
102 pub correlation_id: Option<Uuid>,
103}
104
105pub struct ConfigMerger {
107 }
109
110impl Default for ConfigMerger {
111 fn default() -> Self {
112 Self::new()
113 }
114}
115
116fn merge_values(base: Value, override_value: Value) -> Value {
117 match (base, override_value) {
118 (base, Value::Null) => base,
120
121 (Value::Null, override_val) => override_val,
123
124 (Value::Object(mut base_obj), Value::Object(override_obj)) => {
126 for (key, value) in override_obj {
127 match base_obj.get(&key) {
128 Some(base_value) => {
129 base_obj.insert(key, merge_values(base_value.clone(), value));
130 }
131 None => {
132 base_obj.insert(key, value);
133 }
134 }
135 }
136 Value::Object(base_obj)
137 }
138
139 (_, Value::Array(override_arr)) => Value::Array(override_arr),
141
142 (_, override_val) => override_val,
144 }
145}
146
147impl ConfigMerger {
148 pub fn new() -> Self {
149 Self {}
150 }
151
152 pub fn merge(&self, values: Vec<(ConfigurationTier, Value)>) -> Value {
154 if values.is_empty() {
155 return Value::Null;
156 }
157
158 let mut sorted_values = values;
160 sorted_values.sort_by_key(|(tier, _)| tier.precedence());
161
162 let mut result = sorted_values[0].1.clone();
164
165 for (_, value) in sorted_values.into_iter().skip(1) {
167 result = merge_values(result, value);
168 }
169
170 result
171 }
172}
173
174pub struct ConfigChangeDetector {
176 previous_values: HashMap<String, Value>,
177 change_sender: broadcast::Sender<ConfigChangeEvent>,
178}
179
180impl Default for ConfigChangeDetector {
181 fn default() -> Self {
182 Self::new()
183 }
184}
185
186impl ConfigChangeDetector {
187 pub fn new() -> Self {
188 let (change_sender, _) = broadcast::channel(1000);
189 Self {
190 previous_values: HashMap::new(),
191 change_sender,
192 }
193 }
194
195 pub fn subscribe(&self) -> broadcast::Receiver<ConfigChangeEvent> {
196 self.change_sender.subscribe()
197 }
198
199 pub fn detect_change(
200 &mut self,
201 key: &str,
202 new_value: &Value,
203 tier: ConfigurationTier,
204 source: &str,
205 ) {
206 let old_value = self.previous_values.get(key).cloned();
207
208 if old_value.as_ref() != Some(new_value) {
209 let change_event = ConfigChangeEvent {
210 key: key.to_string(),
211 value: Some(new_value.clone()),
212 old_value,
213 tier,
214 timestamp: Time::now(),
215 source: source.to_string(),
216 correlation_id: None,
217 };
218
219 let _ = self.change_sender.send(change_event);
220 self.previous_values
221 .insert(key.to_string(), new_value.clone());
222 }
223 }
224}
225
226pub struct ConfigSyncManager {
228 #[allow(dead_code)]
229 sync_interval: Duration,
230 last_sync: RwLock<DateTime<Utc>>,
231 sync_enabled: bool,
232}
233
234impl ConfigSyncManager {
235 pub fn new(sync_interval: Duration) -> Self {
236 Self {
237 sync_interval,
238 last_sync: RwLock::new(Time::now()),
239 sync_enabled: true,
240 }
241 }
242
243 pub async fn sync_with_server(&self, _store: &dyn ConfigStore) -> Result<()> {
244 if !self.sync_enabled {
245 return Ok(());
246 }
247
248 *self.last_sync.write().await = Time::now();
250 Ok(())
251 }
252
253 pub async fn last_sync_time(&self) -> DateTime<Utc> {
254 *self.last_sync.read().await
255 }
256}
257
258pub struct ValidationRuleSet {
260 rules: HashMap<String, Vec<ValidationRule>>,
261}
262
263#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct ValidationRule {
266 pub rule_type: ValidationRuleType,
267 pub message: String,
268 pub severity: ValidationSeverity,
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize)]
272pub enum ValidationRuleType {
273 Required,
274 Type(String),
275 Range { min: f64, max: f64 },
276 Length { min: usize, max: usize },
277 Pattern(String),
278 Enum(Vec<String>),
279 Custom(String),
280}
281
282#[derive(Debug, Clone, Serialize, Deserialize)]
283pub enum ValidationSeverity {
284 Error,
285 Warning,
286 Info,
287}
288
289impl Default for ValidationRuleType {
290 fn default() -> Self {
291 Self::Required
292 }
293}
294
295impl Default for ValidationRuleSet {
296 fn default() -> Self {
297 Self::new()
298 }
299}
300
301impl ValidationRuleSet {
302 pub fn new() -> Self {
303 Self {
304 rules: HashMap::new(),
305 }
306 }
307
308 pub fn add_rule(&mut self, key: String, rule: ValidationRule) {
309 self.rules.entry(key).or_default().push(rule);
310 }
311
312 pub fn validate(&self, key: &str, value: &Value) -> Vec<ValidationError> {
313 let mut errors = Vec::new();
314
315 if let Some(rules) = self.rules.get(key) {
316 for rule in rules {
317 if let Some(error) = self.validate_rule(key, value, rule) {
318 errors.push(error);
319 }
320 }
321 }
322
323 errors
324 }
325
326 fn validate_rule(
327 &self,
328 key: &str,
329 value: &Value,
330 rule: &ValidationRule,
331 ) -> Option<ValidationError> {
332 let is_valid = match &rule.rule_type {
333 ValidationRuleType::Required => !value.is_null(),
334 ValidationRuleType::Type(expected_type) => self.check_type(value, expected_type),
335 ValidationRuleType::Range { min, max } => self.check_range(value, *min, *max),
336 ValidationRuleType::Length { min, max } => self.check_length(value, *min, *max),
337 ValidationRuleType::Pattern(pattern) => self.check_pattern(value, pattern),
338 ValidationRuleType::Enum(options) => self.check_enum(value, options),
339 ValidationRuleType::Custom(_) => true, };
341
342 if !is_valid {
343 Some(ValidationError {
344 key: key.to_string(),
345 message: rule.message.clone(),
346 severity: rule.severity.clone(),
347 rule_type: rule.rule_type.clone(),
348 })
349 } else {
350 None
351 }
352 }
353
354 fn check_type(&self, value: &Value, expected_type: &str) -> bool {
355 match expected_type {
356 "string" => value.is_string(),
357 "number" => value.is_number(),
358 "boolean" => value.is_boolean(),
359 "array" => value.is_array(),
360 "object" => value.is_object(),
361 _ => true,
362 }
363 }
364
365 fn check_range(&self, value: &Value, min: f64, max: f64) -> bool {
366 if let Some(num) = value.as_f64() {
367 num >= min && num <= max
368 } else {
369 false
370 }
371 }
372
373 fn check_length(&self, value: &Value, min: usize, max: usize) -> bool {
374 let length = if let Some(s) = value.as_str() {
375 s.len()
376 } else if let Some(arr) = value.as_array() {
377 arr.len()
378 } else if let Some(obj) = value.as_object() {
379 obj.len()
380 } else {
381 return false;
382 };
383
384 length >= min && length <= max
385 }
386
387 fn check_pattern(&self, value: &Value, _pattern: &str) -> bool {
388 value.is_string()
390 }
391
392 fn check_enum(&self, value: &Value, options: &[String]) -> bool {
393 if let Some(s) = value.as_str() {
394 options.contains(&s.to_string())
395 } else {
396 false
397 }
398 }
399}
400
401#[derive(Debug, Clone, Serialize, Deserialize)]
403pub struct ValidationError {
404 pub key: String,
405 pub message: String,
406 pub severity: ValidationSeverity,
407 pub rule_type: ValidationRuleType,
408}
409
410pub struct TieredConfigManager {
412 state: ManagedState,
413 stores: HashMap<ConfigurationTier, Box<dyn ConfigStore>>,
414 merger: ConfigMerger,
415 sync_manager: Option<ConfigSyncManager>,
416 change_detector: ConfigChangeDetector,
417 validation_rules: ValidationRuleSet,
418 cache: Arc<RwLock<HashMap<String, Value>>>,
419 cache_ttl: Duration,
420}
421
422impl std::fmt::Debug for TieredConfigManager {
423 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
424 f.debug_struct("TieredConfigManager")
425 .field("stores", &self.stores.len())
426 .field("cache_ttl", &self.cache_ttl)
427 .finish()
428 }
429}
430
431impl Default for TieredConfigManager {
432 fn default() -> Self {
433 Self::new()
434 }
435}
436
437impl TieredConfigManager {
438 pub fn new() -> Self {
440 Self {
441 state: ManagedState::new(Uuid::new_v4(), "tiered_config_manager"),
442 stores: HashMap::new(),
443 merger: ConfigMerger::new(),
444 sync_manager: Some(ConfigSyncManager::new(Duration::from_secs(300))), change_detector: ConfigChangeDetector::new(),
446 validation_rules: ValidationRuleSet::new(),
447 cache: Arc::new(RwLock::new(HashMap::new())),
448 cache_ttl: Duration::from_secs(60),
449 }
450 }
451
452 pub fn add_store(&mut self, tier: ConfigurationTier, store: Box<dyn ConfigStore>) {
454 self.stores.insert(tier, store);
455 }
456
457 pub async fn get<T>(&self, key: &str) -> Result<Option<T>>
459 where
460 T: for<'de> Deserialize<'de>,
461 {
462 if let Some(cached_value) = self.cache.read().await.get(key) {
464 return Ok(Some(serde_json::from_value(cached_value.clone()).map_err(
465 |e| Error::config(format!("Deserialization failed: {e}")),
466 )?));
467 }
468
469 let mut tier_values = Vec::new();
471
472 for tier in ConfigurationTier::all_tiers() {
473 if let Some(store) = self.stores.get(&tier) {
474 if let Some(value) = store.get(key).await? {
475 tier_values.push((tier, value));
476 }
477 }
478 }
479
480 if tier_values.is_empty() {
481 return Ok(None);
482 }
483
484 let merged_value = self.merger.merge(tier_values);
486
487 self.cache
489 .write()
490 .await
491 .insert(key.to_string(), merged_value.clone());
492
493 let result: T = serde_json::from_value(merged_value)
495 .map_err(|_e| Error::config("Failed to deserialize merged value"))?;
496 Ok(Some(result))
497 }
498
499 pub async fn set(&mut self, key: &str, value: Value, tier: ConfigurationTier) -> Result<()> {
501 let validation_errors = self.validation_rules.validate(key, &value);
503 if validation_errors
504 .iter()
505 .any(|e| matches!(e.severity, ValidationSeverity::Error))
506 {
507 return Err(Error::config(format!(
508 "Validation failed for key '{}': {:?}",
509 key, validation_errors
510 )));
511 }
512
513 let store = self
515 .stores
516 .get(&tier)
517 .ok_or_else(|| Error::config(format!("No store configured for tier {:?}", tier)))?;
518
519 store.set(key, value.clone()).await?;
521
522 self.cache.write().await.remove(key);
524
525 self.change_detector
527 .detect_change(key, &value, tier, "tiered_config_manager");
528
529 Ok(())
530 }
531
532 pub async fn delete(&self, key: &str, tier: ConfigurationTier) -> Result<()> {
534 let store = self
535 .stores
536 .get(&tier)
537 .ok_or_else(|| Error::config(format!("No store configured for tier {:?}", tier)))?;
538
539 store.delete(key).await?;
540
541 self.cache.write().await.remove(key);
543
544 Ok(())
545 }
546
547 pub async fn list_keys(&self, prefix: &str) -> Result<Vec<String>> {
549 let mut all_keys = std::collections::HashSet::new();
550
551 for store in self.stores.values() {
552 let keys = store.list_keys(prefix).await?;
553 all_keys.extend(keys);
554 }
555
556 Ok(all_keys.into_iter().collect())
557 }
558
559 pub fn subscribe_to_changes(&self) -> broadcast::Receiver<ConfigChangeEvent> {
561 self.change_detector.subscribe()
562 }
563
564 pub fn add_validation_rule(&mut self, key: String, rule: ValidationRule) {
566 self.validation_rules.add_rule(key, rule);
567 }
568
569 pub async fn validate_all(&self) -> Result<Vec<ValidationError>> {
571 let mut all_errors = Vec::new();
572
573 for store in self.stores.values() {
574 let keys = store.list_keys("").await?;
575 for key in keys {
576 if let Some(value) = store.get(&key).await? {
577 let errors = self.validation_rules.validate(&key, &value);
578 all_errors.extend(errors);
579 }
580 }
581 }
582
583 Ok(all_errors)
584 }
585
586 pub async fn clear_cache(&self) {
588 self.cache.write().await.clear();
589 }
590
591 pub async fn sync(&self) -> Result<()> {
593 if let Some(sync_manager) = &self.sync_manager {
594 for store in self.stores.values() {
595 sync_manager.sync_with_server(store.as_ref()).await?;
596 }
597 }
598 Ok(())
599 }
600}
601
602#[cfg(not(target_arch = "wasm32"))]
604#[async_trait]
605impl Manager for TieredConfigManager {
606 fn name(&self) -> &str {
607 "tiered_config_manager"
608 }
609
610 fn id(&self) -> Uuid {
611 self.state.id()
612 }
613
614 async fn initialize(&mut self) -> Result<()> {
615 self.state
616 .set_state(crate::manager::ManagerState::Initializing)
617 .await;
618 self.state
619 .set_state(crate::manager::ManagerState::Running)
620 .await;
621 Ok(())
622 }
623
624 async fn shutdown(&mut self) -> Result<()> {
625 self.state
626 .set_state(crate::manager::ManagerState::ShuttingDown)
627 .await;
628 let _ = self.sync().await;
629 self.state
630 .set_state(crate::manager::ManagerState::Shutdown)
631 .await;
632 Ok(())
633 }
634
635 async fn status(&self) -> ManagerStatus {
636 let mut status = self.state.status().await;
637 status.add_metadata("stores_count", Value::from(self.stores.len()));
638 status.add_metadata("cache_size", Value::from(self.cache.read().await.len()));
639 status.add_metadata("cache_ttl_seconds", Value::from(self.cache_ttl.as_secs()));
640 if let Some(sync_manager) = &self.sync_manager {
641 status.add_metadata(
642 "last_sync",
643 Value::String(sync_manager.last_sync_time().await.to_rfc3339()),
644 );
645 }
646 status
647 }
648
649 fn supports_runtime_reload(&self) -> bool {
650 true
651 }
652
653 async fn reload_config(&mut self, config: serde_json::Value) -> Result<()> {
654 if let serde_json::Value::Object(config_obj) = config {
655 for (key, value) in config_obj {
656 self.set(&key, value, ConfigurationTier::Runtime).await?;
657 }
658 }
659 Ok(())
660 }
661
662 fn platform_requirements(&self) -> PlatformRequirements {
663 PlatformRequirements {
664 requires_filesystem: true,
665 requires_network: true,
666 requires_database: false,
667 requires_native_apis: false,
668 minimum_permissions: vec!["config.read".to_string(), "config.write".to_string()],
669 }
670 }
671}
672
673#[cfg(target_arch = "wasm32")]
674#[async_trait(?Send)]
675impl Manager for TieredConfigManager {
676 fn name(&self) -> &str {
677 "tiered_config_manager"
678 }
679
680 fn id(&self) -> Uuid {
681 self.state.id()
682 }
683
684 async fn initialize(&mut self) -> Result<()> {
685 self.state
686 .set_state(crate::manager::ManagerState::Initializing)
687 .await;
688 self.state
689 .set_state(crate::manager::ManagerState::Running)
690 .await;
691 Ok(())
692 }
693
694 async fn shutdown(&mut self) -> Result<()> {
695 self.state
696 .set_state(crate::manager::ManagerState::ShuttingDown)
697 .await;
698 let _ = self.sync().await;
699 self.state
700 .set_state(crate::manager::ManagerState::Shutdown)
701 .await;
702 Ok(())
703 }
704
705 async fn status(&self) -> ManagerStatus {
706 let mut status = self.state.status().await;
707 status.add_metadata("stores_count", Value::from(self.stores.len()));
708 status.add_metadata("cache_size", Value::from(self.cache.read().await.len()));
709 status.add_metadata("cache_ttl_seconds", Value::from(self.cache_ttl.as_secs()));
710 if let Some(sync_manager) = &self.sync_manager {
711 status.add_metadata(
712 "last_sync",
713 Value::String(sync_manager.last_sync_time().await.to_rfc3339()),
714 );
715 }
716 status
717 }
718
719 fn supports_runtime_reload(&self) -> bool {
720 true
721 }
722
723 async fn reload_config(&mut self, config: serde_json::Value) -> Result<()> {
724 if let serde_json::Value::Object(config_obj) = config {
725 for (key, value) in config_obj {
726 self.set(&key, value, ConfigurationTier::Runtime).await?;
727 }
728 }
729 Ok(())
730 }
731
732 fn platform_requirements(&self) -> PlatformRequirements {
733 PlatformRequirements {
734 requires_filesystem: true,
735 requires_network: true,
736 requires_database: false,
737 requires_native_apis: false,
738 minimum_permissions: vec!["config.read".to_string(), "config.write".to_string()],
739 }
740 }
741}
742
743pub struct MemoryConfigStore {
745 tier: ConfigurationTier,
746 data: Arc<RwLock<HashMap<String, Value>>>,
747 change_sender: broadcast::Sender<ConfigChangeEvent>,
748}
749
750impl MemoryConfigStore {
751 pub fn new(tier: ConfigurationTier) -> Self {
752 let (change_sender, _) = broadcast::channel(100);
753 Self {
754 tier,
755 data: Arc::new(RwLock::new(HashMap::new())),
756 change_sender,
757 }
758 }
759}
760
761#[cfg(not(target_arch = "wasm32"))]
763#[async_trait]
764impl ConfigStore for MemoryConfigStore {
765 async fn get(&self, key: &str) -> Result<Option<Value>> {
766 Ok(self.data.read().await.get(key).cloned())
767 }
768
769 async fn set(&self, key: &str, value: Value) -> Result<()> {
770 let old_value = self
771 .data
772 .write()
773 .await
774 .insert(key.to_string(), value.clone());
775
776 let change_event = ConfigChangeEvent {
777 key: key.to_string(),
778 value: Some(value),
779 old_value,
780 tier: self.tier,
781 timestamp: Time::now(),
782 source: "memory_store".to_string(),
783 correlation_id: None,
784 };
785
786 let _ = self.change_sender.send(change_event);
787 Ok(())
788 }
789
790 async fn delete(&self, key: &str) -> Result<()> {
791 self.data.write().await.remove(key);
792 Ok(())
793 }
794
795 async fn list_keys(&self, prefix: &str) -> Result<Vec<String>> {
796 let data = self.data.read().await;
797 let keys: Vec<String> = data
798 .keys()
799 .filter(|k| k.starts_with(prefix))
800 .cloned()
801 .collect();
802 Ok(keys)
803 }
804
805 async fn watch(&self, _key: &str) -> Result<ConfigWatcher> {
806 Ok(ConfigWatcher::new(self.change_sender.subscribe()))
807 }
808
809 fn tier(&self) -> ConfigurationTier {
810 self.tier
811 }
812}
813
814#[cfg(target_arch = "wasm32")]
815#[async_trait(?Send)]
816impl ConfigStore for MemoryConfigStore {
817 async fn get(&self, key: &str) -> Result<Option<Value>> {
818 Ok(self.data.read().await.get(key).cloned())
819 }
820
821 async fn set(&self, key: &str, value: Value) -> Result<()> {
822 let old_value = self
823 .data
824 .write()
825 .await
826 .insert(key.to_string(), value.clone());
827
828 let change_event = ConfigChangeEvent {
829 key: key.to_string(),
830 value: Some(value),
831 old_value,
832 tier: self.tier,
833 timestamp: Time::now(),
834 source: "memory_store".to_string(),
835 correlation_id: None,
836 };
837
838 let _ = self.change_sender.send(change_event);
839 Ok(())
840 }
841
842 async fn delete(&self, key: &str) -> Result<()> {
843 self.data.write().await.remove(key);
844 Ok(())
845 }
846
847 async fn list_keys(&self, prefix: &str) -> Result<Vec<String>> {
848 let data = self.data.read().await;
849 let keys: Vec<String> = data
850 .keys()
851 .filter(|k| k.starts_with(prefix))
852 .cloned()
853 .collect();
854 Ok(keys)
855 }
856
857 async fn watch(&self, _key: &str) -> Result<ConfigWatcher> {
858 Ok(ConfigWatcher::new(self.change_sender.subscribe()))
859 }
860
861 fn tier(&self) -> ConfigurationTier {
862 self.tier
863 }
864}
865
866#[cfg(test)]
867mod tests {
868 use super::*;
869
870 #[tokio::test]
871 async fn test_config_merging() {
872 let merger = ConfigMerger::new();
873
874 let base = serde_json::json!({
875 "app": {
876 "name": "Test App",
877 "version": "1.0.0"
878 },
879 "features": {
880 "feature1": true
881 }
882 });
883
884 let override_val = serde_json::json!({
885 "app": {
886 "version": "1.1.0"
887 },
888 "features": {
889 "feature2": true
890 }
891 });
892
893 let values = vec![
894 (ConfigurationTier::System, base),
895 (ConfigurationTier::User, override_val),
896 ];
897
898 let merged = merger.merge(values);
899
900 assert_eq!(merged["app"]["name"], "Test App");
901 assert_eq!(merged["app"]["version"], "1.1.0");
902 assert_eq!(merged["features"]["feature1"], true);
903 assert_eq!(merged["features"]["feature2"], true);
904 }
905
906 #[tokio::test]
907 async fn test_tiered_config_manager() {
908 let mut manager = TieredConfigManager::new();
909
910 manager.add_store(
912 ConfigurationTier::System,
913 Box::new(MemoryConfigStore::new(ConfigurationTier::System)),
914 );
915 manager.add_store(
916 ConfigurationTier::User,
917 Box::new(MemoryConfigStore::new(ConfigurationTier::User)),
918 );
919
920 manager
922 .set(
923 "app.name",
924 Value::String("System App".to_string()),
925 ConfigurationTier::System,
926 )
927 .await
928 .unwrap();
929 manager
930 .set(
931 "app.name",
932 Value::String("User App".to_string()),
933 ConfigurationTier::User,
934 )
935 .await
936 .unwrap();
937
938 let app_name: Option<String> = manager.get("app.name").await.unwrap();
940 assert_eq!(app_name, Some("User App".to_string()));
941 }
942
943 #[test]
944 fn test_validation_rules() {
945 let mut rule_set = ValidationRuleSet::new();
946
947 rule_set.add_rule(
948 "app.port".to_string(),
949 ValidationRule {
950 rule_type: ValidationRuleType::Range {
951 min: 1.0,
952 max: 65535.0,
953 },
954 message: "Port must be between 1 and 65535".to_string(),
955 severity: ValidationSeverity::Error,
956 },
957 );
958
959 let valid_errors =
961 rule_set.validate("app.port", &Value::Number(serde_json::Number::from(8080)));
962 assert!(valid_errors.is_empty());
963
964 let invalid_errors =
966 rule_set.validate("app.port", &Value::Number(serde_json::Number::from(70000)));
967 assert!(!invalid_errors.is_empty());
968 }
969}