mod context;
mod handlers;
mod testdb;
mod tracing;
pub mod utils;
pub use context::*;
pub use handlers::*;
pub use testdb::*;
pub use tracing::*;
pub use utils::*;
use std::{fmt::Debug, pin::Pin};
#[derive(Clone)]
pub struct TestContext<DB>
where
DB: DatabaseBackend + Send + Sync + Debug + 'static,
{
pub db: TestDatabaseInstance<DB>,
}
impl<DB> Debug for TestContext<DB>
where
DB: DatabaseBackend + Send + Sync + Debug + 'static,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "TestContext {{ db: {:?} }}", self.db.db_name)
}
}
impl<DB> TestContext<DB>
where
DB: DatabaseBackend + Send + Sync + Debug + 'static,
{
pub fn new(db: TestDatabaseInstance<DB>) -> Self {
Self { db }
}
}
pub mod tests {
pub mod mock {
use async_trait::async_trait;
use std::fmt::Debug;
use crate::{
DatabaseBackend, DatabaseConfig, DatabaseName, DatabasePool, TestDatabaseConnection,
};
#[derive(Debug, Clone)]
pub struct MockConnection;
impl TestDatabaseConnection for MockConnection {
fn connection_string(&self) -> String {
"mock://test".to_string()
}
}
#[derive(Debug, Clone)]
pub struct MockPool;
#[async_trait]
impl DatabasePool for MockPool {
type Connection = MockConnection;
type Error = MockError;
async fn acquire(&self) -> Result<Self::Connection, Self::Error> {
Ok(MockConnection)
}
async fn release(&self, _conn: Self::Connection) -> Result<(), Self::Error> {
Ok(())
}
fn connection_string(&self) -> String {
"mock://test".to_string()
}
}
#[derive(Debug, Clone)]
pub struct MockError(pub String);
impl std::fmt::Display for MockError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "MockError: {}", self.0)
}
}
impl std::error::Error for MockError {}
impl From<String> for MockError {
fn from(s: String) -> Self {
MockError(s)
}
}
#[derive(Debug, Clone, Default)]
pub struct MockBackend;
#[async_trait]
impl DatabaseBackend for MockBackend {
type Connection = MockConnection;
type Pool = MockPool;
type Error = MockError;
async fn new(_config: DatabaseConfig) -> Result<Self, Self::Error> {
Ok(Self)
}
async fn connect(&self, _name: &DatabaseName) -> Result<Self::Connection, Self::Error> {
Ok(MockConnection)
}
async fn connect_with_string(
&self,
_connection_string: &str,
) -> Result<Self::Connection, Self::Error> {
Ok(MockConnection)
}
async fn create_pool(
&self,
_name: &DatabaseName,
_config: &DatabaseConfig,
) -> Result<Self::Pool, Self::Error> {
Ok(MockPool)
}
async fn create_database(
&self,
_pool: &Self::Pool,
_name: &DatabaseName,
) -> Result<(), Self::Error> {
Ok(())
}
fn drop_database(&self, name: &DatabaseName) -> Result<(), Self::Error> {
tracing::info!("Mock dropping database: {}", name);
Ok(())
}
fn connection_string(&self, _name: &DatabaseName) -> String {
"mock://database".to_string()
}
}
}
}
pub async fn with_connection<B, F, R, E>(
backend: B,
name: &DatabaseName,
operation: F,
) -> Result<R, B::Error>
where
B: DatabaseBackend,
F: FnOnce(&B::Connection) -> Pin<Box<dyn Future<Output = Result<R, E>> + Send>> + Send,
E: std::error::Error + Send + Sync + 'static,
B::Error: From<E>,
{
let conn = backend.connect(name).await?;
let result = operation(&conn).await.map_err(|e| B::Error::from(e))?;
Ok(result)
}
pub async fn with_connection_string<B, F, R, E>(
backend: B,
connection_string: &str,
operation: F,
) -> Result<R, B::Error>
where
B: DatabaseBackend,
F: FnOnce(&B::Connection) -> Pin<Box<dyn Future<Output = Result<R, E>> + Send>> + Send,
E: std::error::Error + Send + Sync + 'static,
B::Error: From<E>,
{
let conn = backend.connect_with_string(connection_string).await?;
let result = operation(&conn).await.map_err(|e| B::Error::from(e))?;
Ok(result)
}