use memory databases for e2e tests
This commit is contained in:
+8
-1
@@ -42,6 +42,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.init();
|
||||
|
||||
let database_path = env::var("DATABASE_PATH").unwrap_or_else(|_| "sustenance.db".into());
|
||||
let database_in_memory = env::var("DATABASE_IN_MEMORY")
|
||||
.map(|value| value == "1" || value.eq_ignore_ascii_case("true"))
|
||||
.unwrap_or(false);
|
||||
let bind_address = env::var("BIND_ADDRESS").unwrap_or_else(|_| "127.0.0.1:3000".into());
|
||||
// For loopback hosts, advertise `localhost` so WebAuthn works locally (browsers
|
||||
// reject IP addresses as RP IDs). Access the app via http://localhost:PORT.
|
||||
@@ -69,7 +72,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
};
|
||||
|
||||
// Build the adapters (ports) and wire them into application services.
|
||||
let db = SqliteDatabase::open(&database_path).await?;
|
||||
let db = if database_in_memory {
|
||||
SqliteDatabase::open_in_memory().await?
|
||||
} else {
|
||||
SqliteDatabase::open(&database_path).await?
|
||||
};
|
||||
let users: Arc<dyn UserRepository> = Arc::new(SqliteUserRepository);
|
||||
let sessions: Arc<dyn SessionRepository> = Arc::new(SqliteSessionRepository);
|
||||
let lists: Arc<dyn ListRepository> = Arc::new(SqliteListRepository);
|
||||
|
||||
+20
-14
@@ -39,26 +39,32 @@ impl SqliteDatabase {
|
||||
Ok(Self { pool })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// Opens an in-memory database. Every connection in the pool shares the same
|
||||
/// in-memory database via a named shared-cache database, so the schema and
|
||||
/// data are visible across the whole pool. Nothing is persisted to disk.
|
||||
pub async fn open_in_memory() -> DomainResult<Self> {
|
||||
// A pool of `:memory:` connections would each get a separate database,
|
||||
// so use a unique temporary file that shares the schema across the pool.
|
||||
// A plain `:memory:` database is private to each connection, so a pool
|
||||
// would get a separate database per connection. Use a uniquely-named
|
||||
// shared-cache in-memory database instead so the whole pool shares one.
|
||||
//
|
||||
// The name must be unique per call: shared-cache in-memory databases are
|
||||
// keyed by name, so two calls with the same name within a process would
|
||||
// resolve to the same database and share state. This matters for the
|
||||
// unit tests, which run many `open_in_memory()` calls in parallel within
|
||||
// a single process and need isolation from each other. The counter makes
|
||||
// each call unique. (Shared-cache and in-memory databases are per-process,
|
||||
// so there is no cross-process collision to guard against.)
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
static COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||
let unique = COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
let path = std::env::temp_dir().join(format!(
|
||||
"sustenance-test-{}-{}-{}.db",
|
||||
std::process::id(),
|
||||
now(),
|
||||
unique
|
||||
));
|
||||
let path = path.to_str().unwrap();
|
||||
let filename = format!("file:sustenance-in-memory-{}", unique);
|
||||
let options = SqliteConnectOptions::new()
|
||||
.filename(path)
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)
|
||||
.filename(filename)
|
||||
.in_memory(true)
|
||||
.shared_cache(true)
|
||||
.journal_mode(sqlx::sqlite::SqliteJournalMode::Memory)
|
||||
.foreign_keys(true)
|
||||
.busy_timeout(std::time::Duration::from_secs(5))
|
||||
.create_if_missing(true);
|
||||
.busy_timeout(std::time::Duration::from_secs(5));
|
||||
let pool = SqlitePool::connect_with(options).await.map_err(db_error)?;
|
||||
MIGRATOR.run(&pool).await.map_err(migrate_error)?;
|
||||
seed_default_categories(&pool).await?;
|
||||
|
||||
Reference in New Issue
Block a user