1use serde::{Deserialize, Serialize};
8use sklears_core::error::{Result as SklResult, SklearsError};
9use std::collections::{BTreeMap, HashMap};
10use std::path::PathBuf;
11use std::sync::{Arc, Mutex, RwLock};
12use thiserror::Error;
13
14use super::component_framework::{
15 ComponentCapability, ComponentConfig, ComponentDependency, ComponentFactory, FactoryMetadata,
16 PluggableComponent,
17};
18
19pub struct GlobalComponentRegistry {
25 factories: Arc<RwLock<BTreeMap<String, BTreeMap<String, Arc<dyn ComponentFactory>>>>>,
27 active_components: Arc<RwLock<HashMap<String, Arc<RwLock<Box<dyn PluggableComponent>>>>>>,
29 metadata_cache: Arc<RwLock<HashMap<String, ComponentRegistrationMetadata>>>,
31 plugin_directories: Arc<RwLock<Vec<PathBuf>>>,
33 config: RegistryConfiguration,
35 hooks: Arc<RwLock<RegistryHooks>>,
37 stats: Arc<Mutex<RegistryStatistics>>,
39}
40
41impl std::fmt::Debug for GlobalComponentRegistry {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 f.debug_struct("GlobalComponentRegistry")
44 .field("factories", &"[factories: <RwLock>]".to_string())
45 .field(
46 "active_components",
47 &"[active_components: <RwLock>]".to_string(),
48 )
49 .field("metadata_cache", &"[metadata_cache: <RwLock>]".to_string())
50 .field(
51 "plugin_directories",
52 &"[plugin_directories: <RwLock>]".to_string(),
53 )
54 .field("config", &self.config)
55 .field("hooks", &"[hooks: <RwLock>]".to_string())
56 .field("stats", &"[stats: <Mutex>]".to_string())
57 .finish()
58 }
59}
60
61impl GlobalComponentRegistry {
62 #[must_use]
64 pub fn new() -> Self {
65 Self {
66 factories: Arc::new(RwLock::new(BTreeMap::new())),
67 active_components: Arc::new(RwLock::new(HashMap::new())),
68 metadata_cache: Arc::new(RwLock::new(HashMap::new())),
69 plugin_directories: Arc::new(RwLock::new(Vec::new())),
70 config: RegistryConfiguration::default(),
71 hooks: Arc::new(RwLock::new(RegistryHooks::new())),
72 stats: Arc::new(Mutex::new(RegistryStatistics::new())),
73 }
74 }
75
76 pub fn register_factory_versioned(
78 &self,
79 component_type: &str,
80 version: &str,
81 factory: Arc<dyn ComponentFactory>,
82 ) -> SklResult<()> {
83 let mut factories = self.factories.write().unwrap();
84 let mut metadata_cache = self.metadata_cache.write().unwrap();
85 let mut stats = self.stats.lock().unwrap();
86
87 self.validate_version(version)?;
89
90 if let Some(versions) = factories.get(component_type) {
92 if versions.contains_key(version) && !self.config.allow_factory_overrides {
93 return Err(SklearsError::InvalidInput(format!(
94 "Factory for component type {component_type} version {version} already registered"
95 )));
96 }
97 }
98
99 let hooks = self.hooks.read().unwrap();
101 for hook in &hooks.pre_registration {
102 hook(component_type, version, &factory)?;
103 }
104
105 factories
107 .entry(component_type.to_string())
108 .or_default()
109 .insert(version.to_string(), factory.clone());
110
111 let metadata = ComponentRegistrationMetadata {
113 component_type: component_type.to_string(),
114 version: version.to_string(),
115 factory_metadata: factory.factory_metadata(),
116 registration_time: std::time::SystemTime::now(),
117 supported_capabilities: self.extract_capabilities(&factory)?,
118 dependency_requirements: self.extract_dependencies(&factory)?,
119 };
120
121 metadata_cache.insert(format!("{component_type}:{version}"), metadata);
122
123 stats.total_registered_factories += 1;
125 stats
126 .registrations_by_type
127 .entry(component_type.to_string())
128 .and_modify(|e| *e += 1)
129 .or_insert(1);
130
131 for hook in &hooks.post_registration {
133 hook(component_type, version, &factory)?;
134 }
135
136 Ok(())
137 }
138
139 pub fn register_factory(
141 &self,
142 component_type: &str,
143 factory: Arc<dyn ComponentFactory>,
144 ) -> SklResult<()> {
145 let version = factory.factory_metadata().version;
146 self.register_factory_versioned(component_type, &version, factory)
147 }
148
149 pub fn create_component_versioned(
151 &self,
152 component_type: &str,
153 version: &str,
154 config: &ComponentConfig,
155 ) -> SklResult<Box<dyn PluggableComponent>> {
156 let factories = self.factories.read().unwrap();
157 let mut stats = self.stats.lock().unwrap();
158
159 let factory = factories
160 .get(component_type)
161 .and_then(|versions| versions.get(version))
162 .ok_or_else(|| {
163 SklearsError::InvalidInput(format!(
164 "Component type {component_type} version {version} not registered"
165 ))
166 })?;
167
168 let component = factory.create_component(config)?;
169
170 stats.total_components_created += 1;
172 stats
173 .creations_by_type
174 .entry(component_type.to_string())
175 .and_modify(|e| *e += 1)
176 .or_insert(1);
177
178 Ok(component)
179 }
180
181 pub fn create_component(
183 &self,
184 component_type: &str,
185 config: &ComponentConfig,
186 ) -> SklResult<Box<dyn PluggableComponent>> {
187 let factories = self.factories.read().unwrap();
188
189 let latest_version = factories
190 .get(component_type)
191 .and_then(|versions| versions.keys().last())
192 .ok_or_else(|| {
193 SklearsError::InvalidInput(format!(
194 "Component type {component_type} not registered"
195 ))
196 })?
197 .clone();
198
199 drop(factories);
200 self.create_component_versioned(component_type, &latest_version, config)
201 }
202
203 pub fn register_active_component(
205 &self,
206 component_id: &str,
207 component: Box<dyn PluggableComponent>,
208 ) -> SklResult<()> {
209 let mut active_components = self.active_components.write().unwrap();
210 let mut stats = self.stats.lock().unwrap();
211
212 if active_components.contains_key(component_id) && !self.config.allow_instance_overrides {
213 return Err(SklearsError::InvalidInput(format!(
214 "Component instance {component_id} already registered"
215 )));
216 }
217
218 active_components.insert(component_id.to_string(), Arc::new(RwLock::new(component)));
219
220 stats.total_active_components += 1;
221 Ok(())
222 }
223
224 #[must_use]
226 pub fn get_active_component(
227 &self,
228 component_id: &str,
229 ) -> Option<Arc<RwLock<Box<dyn PluggableComponent>>>> {
230 let active_components = self.active_components.read().unwrap();
231 active_components.get(component_id).cloned()
232 }
233
234 pub fn unregister_active_component(&self, component_id: &str) -> SklResult<()> {
236 let mut active_components = self.active_components.write().unwrap();
237 let mut stats = self.stats.lock().unwrap();
238
239 if active_components.remove(component_id).is_some() {
240 stats.total_active_components -= 1;
241 Ok(())
242 } else {
243 Err(SklearsError::InvalidInput(format!(
244 "Component instance {component_id} not found"
245 )))
246 }
247 }
248
249 #[must_use]
251 pub fn discover_component_types(&self) -> Vec<ComponentTypeInfo> {
252 let factories = self.factories.read().unwrap();
253 let metadata_cache = self.metadata_cache.read().unwrap();
254
255 let mut types = Vec::new();
256 for (component_type, versions) in factories.iter() {
257 let mut version_info = Vec::new();
258 for version in versions.keys() {
259 if let Some(metadata) = metadata_cache.get(&format!("{component_type}:{version}")) {
260 version_info.push(ComponentVersionInfo {
261 version: version.clone(),
262 capabilities: metadata.supported_capabilities.clone(),
263 dependencies: metadata.dependency_requirements.clone(),
264 registration_time: metadata.registration_time,
265 });
266 }
267 }
268
269 types.push(ComponentTypeInfo {
270 component_type: component_type.clone(),
271 available_versions: version_info,
272 latest_version: versions.keys().last().cloned(),
273 });
274 }
275
276 types
277 }
278
279 #[must_use]
281 pub fn query_components_by_capability(&self, capability: &str) -> Vec<ComponentQuery> {
282 let metadata_cache = self.metadata_cache.read().unwrap();
283 let mut results = Vec::new();
284
285 for (key, metadata) in metadata_cache.iter() {
286 if metadata
287 .supported_capabilities
288 .iter()
289 .any(|cap| cap.name == capability)
290 {
291 let parts: Vec<&str> = key.split(':').collect();
292 if parts.len() == 2 {
293 results.push(ComponentQuery {
294 component_type: parts[0].to_string(),
295 version: parts[1].to_string(),
296 matching_capabilities: metadata
297 .supported_capabilities
298 .iter()
299 .filter(|cap| cap.name == capability)
300 .cloned()
301 .collect(),
302 });
303 }
304 }
305 }
306
307 results
308 }
309
310 #[must_use]
312 pub fn query_components_by_dependency(&self, dependency_type: &str) -> Vec<ComponentQuery> {
313 let metadata_cache = self.metadata_cache.read().unwrap();
314 let mut results = Vec::new();
315
316 for (key, metadata) in metadata_cache.iter() {
317 if metadata
318 .dependency_requirements
319 .iter()
320 .any(|dep| dep.component_type == dependency_type)
321 {
322 let parts: Vec<&str> = key.split(':').collect();
323 if parts.len() == 2 {
324 results.push(ComponentQuery {
325 component_type: parts[0].to_string(),
326 version: parts[1].to_string(),
327 matching_capabilities: Vec::new(),
328 });
329 }
330 }
331 }
332
333 results
334 }
335
336 pub fn add_plugin_directory(&self, path: PathBuf) -> SklResult<()> {
338 let mut plugin_directories = self.plugin_directories.write().unwrap();
339
340 if !path.exists() {
341 return Err(SklearsError::InvalidInput(format!(
342 "Plugin directory does not exist: {path:?}"
343 )));
344 }
345
346 if !plugin_directories.contains(&path) {
347 plugin_directories.push(path);
348 }
349
350 Ok(())
351 }
352
353 pub fn load_plugins(&self) -> SklResult<Vec<PluginLoadResult>> {
355 let plugin_directories = self.plugin_directories.read().unwrap();
356 let mut results = Vec::new();
357
358 for directory in plugin_directories.iter() {
359 match self.load_plugins_from_directory(directory) {
360 Ok(mut dir_results) => results.append(&mut dir_results),
361 Err(e) => results.push(PluginLoadResult {
362 plugin_path: directory.clone(),
363 success: false,
364 error: Some(format!("Failed to load from directory: {e}")),
365 loaded_components: Vec::new(),
366 }),
367 }
368 }
369
370 Ok(results)
371 }
372
373 #[must_use]
375 pub fn get_statistics(&self) -> RegistryStatistics {
376 let stats = self.stats.lock().unwrap();
377 stats.clone()
378 }
379
380 pub fn configure_hooks(&self, hooks: RegistryHooks) {
382 let mut current_hooks = self.hooks.write().unwrap();
383 *current_hooks = hooks;
384 }
385
386 fn validate_version(&self, version: &str) -> SklResult<()> {
388 if !self.config.enable_version_validation {
389 return Ok(());
390 }
391
392 let parts: Vec<&str> = version.split('.').collect();
394 if parts.len() != 3 {
395 return Err(SklearsError::InvalidInput(format!(
396 "Invalid version format: {version}"
397 )));
398 }
399
400 for part in parts {
401 if part.parse::<u32>().is_err() {
402 return Err(SklearsError::InvalidInput(format!(
403 "Invalid version format: {version}"
404 )));
405 }
406 }
407
408 Ok(())
409 }
410
411 fn extract_capabilities(
413 &self,
414 factory: &Arc<dyn ComponentFactory>,
415 ) -> SklResult<Vec<ComponentCapability>> {
416 Ok(Vec::new())
419 }
420
421 fn extract_dependencies(
423 &self,
424 factory: &Arc<dyn ComponentFactory>,
425 ) -> SklResult<Vec<ComponentDependency>> {
426 Ok(Vec::new())
429 }
430
431 fn load_plugins_from_directory(&self, directory: &PathBuf) -> SklResult<Vec<PluginLoadResult>> {
433 let mut results = Vec::new();
436
437 results.push(PluginLoadResult {
438 plugin_path: directory.clone(),
439 success: true,
440 error: None,
441 loaded_components: Vec::new(),
442 });
443
444 Ok(results)
445 }
446}
447
448#[derive(Debug, Clone)]
450pub struct ComponentRegistrationMetadata {
451 pub component_type: String,
453 pub version: String,
455 pub factory_metadata: FactoryMetadata,
457 pub registration_time: std::time::SystemTime,
459 pub supported_capabilities: Vec<ComponentCapability>,
461 pub dependency_requirements: Vec<ComponentDependency>,
463}
464
465#[derive(Debug, Clone, Serialize, Deserialize)]
467pub struct ComponentTypeInfo {
468 pub component_type: String,
470 pub available_versions: Vec<ComponentVersionInfo>,
472 pub latest_version: Option<String>,
474}
475
476#[derive(Debug, Clone, Serialize, Deserialize)]
478pub struct ComponentVersionInfo {
479 pub version: String,
481 pub capabilities: Vec<ComponentCapability>,
483 pub dependencies: Vec<ComponentDependency>,
485 pub registration_time: std::time::SystemTime,
487}
488
489#[derive(Debug, Clone)]
491pub struct ComponentQuery {
492 pub component_type: String,
494 pub version: String,
496 pub matching_capabilities: Vec<ComponentCapability>,
498}
499
500#[derive(Debug, Clone)]
502pub struct RegistryConfiguration {
503 pub allow_factory_overrides: bool,
505 pub allow_instance_overrides: bool,
507 pub enable_version_validation: bool,
509 pub max_registered_factories: Option<usize>,
511 pub max_active_components: Option<usize>,
513 pub enable_plugin_auto_discovery: bool,
515 pub plugin_discovery_interval: std::time::Duration,
517}
518
519impl Default for RegistryConfiguration {
520 fn default() -> Self {
521 Self {
522 allow_factory_overrides: false,
523 allow_instance_overrides: false,
524 enable_version_validation: true,
525 max_registered_factories: None,
526 max_active_components: None,
527 enable_plugin_auto_discovery: false,
528 plugin_discovery_interval: std::time::Duration::from_secs(60),
529 }
530 }
531}
532
533#[derive(Debug, Clone)]
535pub struct PluginLoadResult {
536 pub plugin_path: PathBuf,
538 pub success: bool,
540 pub error: Option<String>,
542 pub loaded_components: Vec<String>,
544}
545
546pub struct RegistryHooks {
548 pub pre_registration:
550 Vec<Box<dyn Fn(&str, &str, &Arc<dyn ComponentFactory>) -> SklResult<()> + Send + Sync>>,
551 pub post_registration:
553 Vec<Box<dyn Fn(&str, &str, &Arc<dyn ComponentFactory>) -> SklResult<()> + Send + Sync>>,
554 pub pre_creation: Vec<Box<dyn Fn(&str, &ComponentConfig) -> SklResult<()> + Send + Sync>>,
556 pub post_creation:
558 Vec<Box<dyn Fn(&str, &Box<dyn PluggableComponent>) -> SklResult<()> + Send + Sync>>,
559}
560
561impl RegistryHooks {
562 #[must_use]
563 pub fn new() -> Self {
564 Self {
565 pre_registration: Vec::new(),
566 post_registration: Vec::new(),
567 pre_creation: Vec::new(),
568 post_creation: Vec::new(),
569 }
570 }
571}
572
573impl std::fmt::Debug for RegistryHooks {
574 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
575 f.debug_struct("RegistryHooks")
576 .field(
577 "pre_registration",
578 &format!("<{} hooks>", self.pre_registration.len()),
579 )
580 .field(
581 "post_registration",
582 &format!("<{} hooks>", self.post_registration.len()),
583 )
584 .field(
585 "pre_creation",
586 &format!("<{} hooks>", self.pre_creation.len()),
587 )
588 .field(
589 "post_creation",
590 &format!("<{} hooks>", self.post_creation.len()),
591 )
592 .finish()
593 }
594}
595
596#[derive(Debug, Clone)]
598pub struct RegistryStatistics {
599 pub total_registered_factories: u64,
601 pub total_components_created: u64,
603 pub total_active_components: u64,
605 pub registrations_by_type: HashMap<String, u64>,
607 pub creations_by_type: HashMap<String, u64>,
609 pub startup_time: std::time::Instant,
611}
612
613impl RegistryStatistics {
614 #[must_use]
615 pub fn new() -> Self {
616 Self {
617 total_registered_factories: 0,
618 total_components_created: 0,
619 total_active_components: 0,
620 registrations_by_type: HashMap::new(),
621 creations_by_type: HashMap::new(),
622 startup_time: std::time::Instant::now(),
623 }
624 }
625
626 #[must_use]
628 pub fn uptime(&self) -> std::time::Duration {
629 self.startup_time.elapsed()
630 }
631
632 #[must_use]
634 pub fn most_registered_type(&self) -> Option<String> {
635 self.registrations_by_type
636 .iter()
637 .max_by_key(|(_, count)| *count)
638 .map(|(type_name, _)| type_name.clone())
639 }
640
641 #[must_use]
643 pub fn most_created_type(&self) -> Option<String> {
644 self.creations_by_type
645 .iter()
646 .max_by_key(|(_, count)| *count)
647 .map(|(type_name, _)| type_name.clone())
648 }
649}
650
651#[derive(Debug, Error)]
653pub enum RegistryError {
654 #[error("Component type not found: {0}")]
655 ComponentTypeNotFound(String),
656
657 #[error("Component version not found: {component_type}:{version}")]
658 ComponentVersionNotFound {
659 component_type: String,
660 version: String,
661 },
662
663 #[error("Component already registered: {0}")]
664 ComponentAlreadyRegistered(String),
665
666 #[error("Plugin loading failed: {0}")]
667 PluginLoadingFailed(String),
668
669 #[error("Registry capacity exceeded: {0}")]
670 CapacityExceeded(String),
671
672 #[error("Version validation failed: {0}")]
673 VersionValidationFailed(String),
674}
675
676impl Default for GlobalComponentRegistry {
677 fn default() -> Self {
678 Self::new()
679 }
680}
681
682impl Default for RegistryHooks {
683 fn default() -> Self {
684 Self::new()
685 }
686}
687
688impl Default for RegistryStatistics {
689 fn default() -> Self {
690 Self::new()
691 }
692}
693
694#[allow(non_snake_case)]
695#[cfg(test)]
696mod tests {
697 use super::*;
698 use crate::modular_framework::component_framework::{ComponentEvent, FactoryMetadata};
699 use crate::modular_framework::{
700 ComponentCapability, ComponentDependency, ComponentMetrics, ComponentState, HealthStatus,
701 };
702 use std::any::Any;
703
704 struct MockComponent {
706 id: String,
707 component_type: String,
708 state: ComponentState,
709 metrics: ComponentMetrics,
710 }
711
712 impl MockComponent {
713 fn new(id: &str, component_type: &str) -> Self {
714 Self {
715 id: id.to_string(),
716 component_type: component_type.to_string(),
717 state: ComponentState::Created,
718 metrics: ComponentMetrics::new(),
719 }
720 }
721 }
722
723 impl PluggableComponent for MockComponent {
724 fn initialize(&mut self, _config: &ComponentConfig) -> SklResult<()> {
725 self.state = ComponentState::Ready;
726 Ok(())
727 }
728
729 fn start(&mut self) -> SklResult<()> {
730 self.state = ComponentState::Running;
731 Ok(())
732 }
733
734 fn stop(&mut self) -> SklResult<()> {
735 self.state = ComponentState::Stopped;
736 Ok(())
737 }
738
739 fn pause(&mut self) -> SklResult<()> {
740 self.state = ComponentState::Paused;
741 Ok(())
742 }
743
744 fn resume(&mut self) -> SklResult<()> {
745 self.state = ComponentState::Running;
746 Ok(())
747 }
748
749 fn component_id(&self) -> &str {
750 &self.id
751 }
752
753 fn component_type(&self) -> &str {
754 &self.component_type
755 }
756
757 fn version(&self) -> &str {
758 "1.0.0"
759 }
760
761 fn current_state(&self) -> ComponentState {
762 self.state.clone()
763 }
764
765 fn health_check(&self) -> SklResult<HealthStatus> {
766 Ok(HealthStatus::Healthy)
767 }
768
769 fn capabilities(&self) -> Vec<ComponentCapability> {
770 vec![ComponentCapability {
771 name: "test_capability".to_string(),
772 description: "Test capability".to_string(),
773 required_config: vec![],
774 optional_config: vec![],
775 version: "1.0.0".to_string(),
776 }]
777 }
778
779 fn dependencies(&self) -> Vec<ComponentDependency> {
780 vec![]
781 }
782
783 fn validate_config(&self, _config: &ComponentConfig) -> SklResult<()> {
784 Ok(())
785 }
786
787 fn get_metrics(&self) -> ComponentMetrics {
788 self.metrics.clone()
789 }
790
791 fn handle_event(&mut self, _event: &ComponentEvent) -> SklResult<()> {
792 Ok(())
793 }
794
795 fn clone_component(&self) -> Box<dyn PluggableComponent> {
796 Box::new(MockComponent::new(&self.id, &self.component_type))
797 }
798
799 fn as_any(&self) -> &dyn Any {
800 self
801 }
802
803 fn as_any_mut(&mut self) -> &mut dyn Any {
804 self
805 }
806 }
807
808 struct MockFactory;
810
811 impl ComponentFactory for MockFactory {
812 fn create_component(
813 &self,
814 config: &ComponentConfig,
815 ) -> SklResult<Box<dyn PluggableComponent>> {
816 Ok(Box::new(MockComponent::new(
817 &config.component_id,
818 &config.component_type,
819 )))
820 }
821
822 fn supported_types(&self) -> Vec<String> {
823 vec!["mock_component".to_string()]
824 }
825
826 fn validate_config(&self, _config: &ComponentConfig) -> SklResult<()> {
827 Ok(())
828 }
829
830 fn factory_metadata(&self) -> FactoryMetadata {
831 FactoryMetadata {
833 name: "MockFactory".to_string(),
834 version: "1.0.0".to_string(),
835 supported_types: vec!["mock_component".to_string()],
836 description: "Mock factory for testing".to_string(),
837 }
838 }
839 }
840
841 #[test]
842 fn test_registry_creation() {
843 let registry = GlobalComponentRegistry::new();
844 let stats = registry.get_statistics();
845 assert_eq!(stats.total_registered_factories, 0);
846 assert_eq!(stats.total_components_created, 0);
847 }
848
849 #[test]
850 fn test_factory_registration() {
851 let registry = GlobalComponentRegistry::new();
852 let factory = Arc::new(MockFactory);
853
854 let result = registry.register_factory_versioned("test_component", "1.0.0", factory);
855 assert!(result.is_ok());
856
857 let stats = registry.get_statistics();
858 assert_eq!(stats.total_registered_factories, 1);
859 }
860
861 #[test]
862 fn test_component_creation() {
863 let registry = GlobalComponentRegistry::new();
864 let factory = Arc::new(MockFactory);
865
866 registry
867 .register_factory_versioned("test_component", "1.0.0", factory)
868 .unwrap();
869
870 let config = ComponentConfig::new("test_instance", "test_component");
871 let component = registry.create_component_versioned("test_component", "1.0.0", &config);
872
873 assert!(component.is_ok());
874 let stats = registry.get_statistics();
875 assert_eq!(stats.total_components_created, 1);
876 }
877
878 #[test]
879 fn test_component_discovery() {
880 let registry = GlobalComponentRegistry::new();
881 let factory = Arc::new(MockFactory);
882
883 registry
884 .register_factory_versioned("test_component", "1.0.0", factory)
885 .unwrap();
886
887 let types = registry.discover_component_types();
888 assert_eq!(types.len(), 1);
889 assert_eq!(types[0].component_type, "test_component");
890 assert_eq!(types[0].latest_version, Some("1.0.0".to_string()));
891 }
892
893 #[test]
894 fn test_version_validation() {
895 let registry = GlobalComponentRegistry::new();
896
897 assert!(registry.validate_version("1.0.0").is_ok());
898 assert!(registry.validate_version("10.20.30").is_ok());
899 assert!(registry.validate_version("1.0").is_err());
900 assert!(registry.validate_version("1.0.0.0").is_err());
901 assert!(registry.validate_version("1.a.0").is_err());
902 }
903
904 #[test]
905 fn test_active_component_management() {
906 let registry = GlobalComponentRegistry::new();
907 let component = Box::new(MockComponent::new("test", "mock"));
908
909 let result = registry.register_active_component("test_instance", component);
910 assert!(result.is_ok());
911
912 let retrieved = registry.get_active_component("test_instance");
913 assert!(retrieved.is_some());
914
915 let unregister_result = registry.unregister_active_component("test_instance");
916 assert!(unregister_result.is_ok());
917
918 let retrieved_after = registry.get_active_component("test_instance");
919 assert!(retrieved_after.is_none());
920 }
921
922 #[test]
923 fn test_plugin_directory_management() {
924 let registry = GlobalComponentRegistry::new();
925 let temp_dir = std::env::temp_dir();
926
927 let result = registry.add_plugin_directory(temp_dir.clone());
928 assert!(result.is_ok());
929
930 let result2 = registry.add_plugin_directory(temp_dir);
932 assert!(result2.is_ok());
933 }
934}