sklears_compose/modular_framework/
registry_system.rs

1//! Component Registry System
2//!
3//! This module provides comprehensive component registration, discovery, and lookup
4//! capabilities including hierarchical registries, plugin management, version control,
5//! and runtime component introspection for dynamic system composition.
6
7use 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
19/// Global component registry for system-wide component management
20///
21/// Provides centralized registration, discovery, and lifecycle management of
22/// components with support for hierarchical organization, version control,
23/// and dynamic loading capabilities.
24pub struct GlobalComponentRegistry {
25    /// Component factories by type and version
26    factories: Arc<RwLock<BTreeMap<String, BTreeMap<String, Arc<dyn ComponentFactory>>>>>,
27    /// Active component instances
28    active_components: Arc<RwLock<HashMap<String, Arc<RwLock<Box<dyn PluggableComponent>>>>>>,
29    /// Component metadata cache
30    metadata_cache: Arc<RwLock<HashMap<String, ComponentRegistrationMetadata>>>,
31    /// Plugin directories for dynamic loading
32    plugin_directories: Arc<RwLock<Vec<PathBuf>>>,
33    /// Registry configuration
34    config: RegistryConfiguration,
35    /// Registration hooks
36    hooks: Arc<RwLock<RegistryHooks>>,
37    /// Registry statistics
38    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    /// Create a new global component registry
63    #[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    /// Register a component factory with version
77    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        // Validate version format
88        self.validate_version(version)?;
89
90        // Check if already registered and if overrides are allowed
91        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        // Execute pre-registration hooks
100        let hooks = self.hooks.read().unwrap();
101        for hook in &hooks.pre_registration {
102            hook(component_type, version, &factory)?;
103        }
104
105        // Register the factory
106        factories
107            .entry(component_type.to_string())
108            .or_default()
109            .insert(version.to_string(), factory.clone());
110
111        // Cache metadata
112        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        // Update statistics
124        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        // Execute post-registration hooks
132        for hook in &hooks.post_registration {
133            hook(component_type, version, &factory)?;
134        }
135
136        Ok(())
137    }
138
139    /// Register a component factory (latest version)
140    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    /// Create a component instance with specific version
150    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        // Update statistics
171        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    /// Create a component instance (latest version)
182    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    /// Register active component instance
204    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    /// Get active component instance
225    #[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    /// Unregister active component instance
235    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    /// Discover available component types
250    #[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    /// Query components by capability
280    #[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    /// Query components by dependency
311    #[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    /// Add plugin directory for dynamic loading
337    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    /// Load plugins from registered directories
354    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    /// Get registry statistics
374    #[must_use]
375    pub fn get_statistics(&self) -> RegistryStatistics {
376        let stats = self.stats.lock().unwrap();
377        stats.clone()
378    }
379
380    /// Configure registry hooks
381    pub fn configure_hooks(&self, hooks: RegistryHooks) {
382        let mut current_hooks = self.hooks.write().unwrap();
383        *current_hooks = hooks;
384    }
385
386    /// Validate component version format
387    fn validate_version(&self, version: &str) -> SklResult<()> {
388        if !self.config.enable_version_validation {
389            return Ok(());
390        }
391
392        // Simple semantic version validation (major.minor.patch)
393        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    /// Extract capabilities from factory
412    fn extract_capabilities(
413        &self,
414        factory: &Arc<dyn ComponentFactory>,
415    ) -> SklResult<Vec<ComponentCapability>> {
416        // This would typically introspect the factory to extract capabilities
417        // For now, we'll return empty list as capabilities are defined by components
418        Ok(Vec::new())
419    }
420
421    /// Extract dependencies from factory
422    fn extract_dependencies(
423        &self,
424        factory: &Arc<dyn ComponentFactory>,
425    ) -> SklResult<Vec<ComponentDependency>> {
426        // This would typically introspect the factory to extract dependencies
427        // For now, we'll return empty list as dependencies are defined by components
428        Ok(Vec::new())
429    }
430
431    /// Load plugins from a specific directory
432    fn load_plugins_from_directory(&self, directory: &PathBuf) -> SklResult<Vec<PluginLoadResult>> {
433        // Plugin loading would typically involve dynamic library loading
434        // This is a placeholder implementation
435        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/// Component registration metadata
449#[derive(Debug, Clone)]
450pub struct ComponentRegistrationMetadata {
451    /// Component type name
452    pub component_type: String,
453    /// Component version
454    pub version: String,
455    /// Factory metadata
456    pub factory_metadata: FactoryMetadata,
457    /// Registration timestamp
458    pub registration_time: std::time::SystemTime,
459    /// Supported capabilities
460    pub supported_capabilities: Vec<ComponentCapability>,
461    /// Dependency requirements
462    pub dependency_requirements: Vec<ComponentDependency>,
463}
464
465/// Component type information
466#[derive(Debug, Clone, Serialize, Deserialize)]
467pub struct ComponentTypeInfo {
468    /// Component type name
469    pub component_type: String,
470    /// Available versions
471    pub available_versions: Vec<ComponentVersionInfo>,
472    /// Latest version
473    pub latest_version: Option<String>,
474}
475
476/// Component version information
477#[derive(Debug, Clone, Serialize, Deserialize)]
478pub struct ComponentVersionInfo {
479    /// Version string
480    pub version: String,
481    /// Supported capabilities
482    pub capabilities: Vec<ComponentCapability>,
483    /// Dependencies
484    pub dependencies: Vec<ComponentDependency>,
485    /// Registration timestamp
486    pub registration_time: std::time::SystemTime,
487}
488
489/// Component query result
490#[derive(Debug, Clone)]
491pub struct ComponentQuery {
492    /// Component type
493    pub component_type: String,
494    /// Version
495    pub version: String,
496    /// Matching capabilities
497    pub matching_capabilities: Vec<ComponentCapability>,
498}
499
500/// Registry configuration
501#[derive(Debug, Clone)]
502pub struct RegistryConfiguration {
503    /// Allow factory overrides
504    pub allow_factory_overrides: bool,
505    /// Allow instance overrides
506    pub allow_instance_overrides: bool,
507    /// Enable version validation
508    pub enable_version_validation: bool,
509    /// Maximum registered factories
510    pub max_registered_factories: Option<usize>,
511    /// Maximum active components
512    pub max_active_components: Option<usize>,
513    /// Enable plugin auto-discovery
514    pub enable_plugin_auto_discovery: bool,
515    /// Plugin discovery interval
516    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/// Plugin loading result
534#[derive(Debug, Clone)]
535pub struct PluginLoadResult {
536    /// Plugin path
537    pub plugin_path: PathBuf,
538    /// Load success status
539    pub success: bool,
540    /// Error message if failed
541    pub error: Option<String>,
542    /// List of loaded component types
543    pub loaded_components: Vec<String>,
544}
545
546/// Registry hooks for extensibility
547pub struct RegistryHooks {
548    /// Pre-registration hooks
549    pub pre_registration:
550        Vec<Box<dyn Fn(&str, &str, &Arc<dyn ComponentFactory>) -> SklResult<()> + Send + Sync>>,
551    /// Post-registration hooks
552    pub post_registration:
553        Vec<Box<dyn Fn(&str, &str, &Arc<dyn ComponentFactory>) -> SklResult<()> + Send + Sync>>,
554    /// Pre-creation hooks
555    pub pre_creation: Vec<Box<dyn Fn(&str, &ComponentConfig) -> SklResult<()> + Send + Sync>>,
556    /// Post-creation hooks
557    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/// Registry statistics
597#[derive(Debug, Clone)]
598pub struct RegistryStatistics {
599    /// Total registered factories
600    pub total_registered_factories: u64,
601    /// Total components created
602    pub total_components_created: u64,
603    /// Total active components
604    pub total_active_components: u64,
605    /// Registrations by type
606    pub registrations_by_type: HashMap<String, u64>,
607    /// Creations by type
608    pub creations_by_type: HashMap<String, u64>,
609    /// Registry startup time
610    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    /// Get registry uptime
627    #[must_use]
628    pub fn uptime(&self) -> std::time::Duration {
629        self.startup_time.elapsed()
630    }
631
632    /// Get most popular component type by registrations
633    #[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    /// Get most popular component type by creations
642    #[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/// Registry errors
652#[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    /// Mock component for testing
705    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    /// Mock factory for testing
809    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
832            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        // Adding the same directory again should not cause issues
931        let result2 = registry.add_plugin_directory(temp_dir);
932        assert!(result2.is_ok());
933    }
934}