use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use crate::application::traits::RepositoryProvider;
use crate::domain::environment::repository::EnvironmentRepository;
use crate::infrastructure::persistence::filesystem::file_environment_repository::FileEnvironmentRepository;
#[derive(Clone)]
pub struct FileRepositoryFactory {
lock_timeout: Duration,
}
impl FileRepositoryFactory {
#[must_use]
pub fn new(lock_timeout: Duration) -> Self {
Self { lock_timeout }
}
#[must_use]
pub fn create(&self, data_dir: PathBuf) -> Arc<dyn EnvironmentRepository + Send + Sync> {
let repository =
FileEnvironmentRepository::new(data_dir).with_lock_timeout(self.lock_timeout);
Arc::new(repository)
}
}
impl RepositoryProvider for FileRepositoryFactory {
fn create(&self, data_dir: PathBuf) -> Arc<dyn EnvironmentRepository + Send + Sync> {
FileRepositoryFactory::create(self, data_dir)
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
#[test]
fn it_should_create_file_repository_factory_with_timeout() {
let timeout = Duration::from_secs(30);
let factory = FileRepositoryFactory::new(timeout);
assert_eq!(factory.lock_timeout, timeout);
}
#[test]
fn it_should_create_repository_with_specific_data_dir() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let factory = FileRepositoryFactory::new(Duration::from_secs(10));
let data_dir = temp_dir.path().join("production");
let _repo = factory.create(data_dir);
}
#[test]
fn it_should_create_multiple_repositories_from_same_factory() {
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let factory = FileRepositoryFactory::new(Duration::from_secs(10));
let prod_dir = temp_dir.path().join("production");
let staging_dir = temp_dir.path().join("staging");
let _repo1 = factory.create(prod_dir);
let _repo2 = factory.create(staging_dir);
}
#[test]
fn it_should_be_clonable() {
let factory = FileRepositoryFactory::new(Duration::from_secs(30));
let factory_clone = factory.clone();
assert_eq!(factory.lock_timeout, factory_clone.lock_timeout);
}
#[test]
fn it_should_create_repository_that_can_save_and_load_environment() {
use crate::adapters::ssh::SshCredentials;
#[allow(unused_imports)] use crate::domain::environment::repository::EnvironmentRepository;
use crate::domain::environment::{Environment, EnvironmentName};
use crate::domain::provider::{LxdConfig, ProviderConfig};
use crate::domain::ProfileName;
use crate::shared::Username;
let temp_dir = TempDir::new().expect("Failed to create temp dir");
let factory = FileRepositoryFactory::new(Duration::from_secs(10));
let env_name =
EnvironmentName::new("test-env".to_string()).expect("Valid environment name");
let ssh_credentials = SshCredentials::new(
temp_dir.path().join("test_key"),
temp_dir.path().join("test_key.pub"),
Username::new("test_user").expect("Valid username"),
);
let provider_config = ProviderConfig::Lxd(LxdConfig {
profile_name: ProfileName::new(format!("lxd-{}", env_name.as_str())).unwrap(),
});
let environment = Environment::new(
env_name.clone(),
provider_config,
ssh_credentials,
22,
chrono::Utc::now(),
);
let repo = factory.create(temp_dir.path().to_path_buf());
let env_state = environment.into_any();
repo.save(&env_state).expect("Should save successfully");
let loaded = repo
.load(&env_name)
.expect("Should load successfully")
.expect("Environment should exist");
assert_eq!(loaded.name(), &env_name);
}
}