use std::collections::HashMap;
use std::sync::Arc;
use crate::provider::CloudProvider;
#[derive(Default, Debug)]
pub struct ProviderRegistry {
providers: HashMap<String, Arc<dyn CloudProvider>>,
}
impl ProviderRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
providers: HashMap::with_capacity(capacity),
}
}
pub fn register(&mut self, name: impl Into<String>, provider: Arc<dyn CloudProvider>) {
self.providers.insert(name.into(), provider);
}
pub fn register_boxed(&mut self, name: impl Into<String>, provider: Box<dyn CloudProvider>) {
self.register(name, Arc::from(provider));
}
pub fn get(&self, name: &str) -> Option<Arc<dyn CloudProvider>> {
self.providers.get(name).cloned()
}
pub fn list_names(&self) -> Vec<String> {
self.providers.keys().cloned().collect()
}
pub fn is_empty(&self) -> bool {
self.providers.is_empty()
}
pub fn len(&self) -> usize {
self.providers.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
use wami_core::error::Result;
#[derive(Debug)]
struct DummyProvider;
impl CloudProvider for DummyProvider {
fn name(&self) -> &str {
"dummy"
}
fn generate_resource_identifier(
&self,
_resource_type: crate::provider::ResourceType,
_account_id: &str,
_path: &str,
name: &str,
) -> String {
name.to_string()
}
fn generate_resource_id(&self, _resource_type: crate::provider::ResourceType) -> String {
"id".to_string()
}
fn resource_limits(&self) -> &crate::provider::ResourceLimits {
static LIMITS: crate::provider::ResourceLimits = crate::provider::ResourceLimits {
max_access_keys_per_user: 2,
max_signing_certificates_per_user: 2,
max_service_credentials_per_user_per_service: 2,
max_tags_per_resource: 50,
max_mfa_devices_per_user: 8,
session_duration_min: 3600,
session_duration_max: 43200,
};
&LIMITS
}
fn validate_service_name(&self, _service: &str) -> Result<()> {
Ok(())
}
fn validate_path(&self, _path: &str) -> Result<()> {
Ok(())
}
fn generate_service_linked_role_name(
&self,
service_name: &str,
_custom_suffix: Option<&str>,
) -> String {
service_name.to_string()
}
fn generate_service_linked_role_path(&self, _service_name: &str) -> String {
String::new()
}
}
#[test]
fn register_and_get_provider() {
let mut registry = ProviderRegistry::new();
let provider = Arc::new(DummyProvider);
registry.register("dummy", provider.clone());
let fetched = registry.get("dummy").expect("provider not found");
assert_eq!(fetched.name(), "dummy");
assert_eq!(
fetched.generate_resource_identifier(
crate::provider::ResourceType::User,
"",
"",
"alice"
),
"alice"
);
}
#[test]
fn list_names_returns_registered_providers() {
let mut registry = ProviderRegistry::new();
registry.register("one", Arc::new(DummyProvider));
registry.register("two", Arc::new(DummyProvider));
let mut names = registry.list_names();
names.sort();
assert_eq!(names, vec!["one".to_string(), "two".to_string()]);
assert_eq!(registry.len(), 2);
}
#[test]
fn register_boxed_provider() {
let mut registry = ProviderRegistry::new();
registry.register_boxed("dummy", Box::new(DummyProvider));
assert!(registry.get("dummy").is_some());
}
#[test]
fn a_registry_reports_emptiness_and_honours_a_capacity_hint() {
let empty = ProviderRegistry::new();
assert!(empty.is_empty());
assert_eq!(empty.len(), 0);
let mut sized = ProviderRegistry::with_capacity(8);
assert!(sized.is_empty());
sized.register(
"aws",
std::sync::Arc::new(crate::provider::aws::AwsProvider::default()),
);
assert!(!sized.is_empty());
assert_eq!(sized.len(), 1);
}
}