use std::{error::Error, sync::Arc}; use async_trait::async_trait; use testcontainers::{ GenericImage, ImageExt, core::{IntoContainerPort, WaitFor}, runners::AsyncRunner, }; use crate::{ ConfigInfoType, containers::{ UnStartedContainer, db::{ ContainerizedDBInfo, DBConfigInfoType, DBInfo, config::{DatabaseContainerConfig, OptionalContainerConfig}, }, }, }; pub fn get_default_config() -> DatabaseContainerConfig { DatabaseContainerConfig { container_name: "yanpm-postgres".to_string(), database_name: "postgres".to_string(), user: "postgres".to_string(), password: "postgres".to_string(), image: "postgres".to_string(), tag: "16-alpine".to_string(), } } pub struct PostgreSQLContainer { pub config: DatabaseContainerConfig, } #[async_trait] impl DBInfo for PostgreSQLContainer { async fn get_db_container_config_info(&self) -> DBConfigInfoType { let pg_container = self .get_unstarted_container() .unwrap() .await .expect("Failed to start PostgreSQL container"); let pg_host = pg_container.get_host().await.expect("Failed to get host"); let pg_host_port = pg_container .get_host_port_ipv4(5432.tcp()) .await .expect("Failed to get host port"); let pg_url = format!( "postgres://{}:{}@{}:{}/{}", self.config.user, self.config.password, pg_host, pg_host_port, self.config.database_name ); ConfigInfoType::Containerized(ContainerizedDBInfo { db_type: crate::containers::db::DBType::PostgreSQL, container: Arc::new(pg_container), container_name: self.config.container_name.clone(), database_name: self.config.database_name.clone(), host: pg_host, port: pg_host_port, url: pg_url, user: self.config.user.clone(), password: self.config.password.clone(), }) } async fn new(user_default_config: Option) -> Self where Self: Sized, { let default_config = get_default_config(); let config = user_default_config .unwrap_or_default() .fill_with(&default_config); PostgreSQLContainer { config: config.clone(), } } fn get_unstarted_container(&self) -> Result> { Ok( GenericImage::new(self.config.image.clone(), self.config.tag.clone()) .with_exposed_port(5432.tcp()) .with_wait_for(WaitFor::message_on_stderr( "database system is ready to accept connections", )) .with_container_name(self.config.container_name.clone()) .with_env_var("POSTGRES_USER", self.config.user.clone()) .with_env_var("POSTGRES_PASSWORD", self.config.password.clone()) .start(), ) } }