db.rs (2771B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2025, 2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 use std::{ 18 path::Path, 19 str::FromStr as _, 20 sync::{ 21 OnceLock, 22 atomic::{AtomicUsize, Ordering}, 23 }, 24 }; 25 26 use sqlx::{ 27 PgPool, 28 postgres::{PgConnectOptions, PgPoolOptions}, 29 }; 30 use taler_api::config::DbCfg; 31 use taler_common::{ 32 config::{Config, parser::ConfigSource}, 33 db::{dbinit, pool}, 34 }; 35 36 use crate::setup_tracing; 37 38 pub async fn db_test_setup(src: ConfigSource) -> PgPool { 39 let cfg = Config::from_file(src, None::<&str>).unwrap(); 40 let name = format!("{}db-postgres", src.component_name); 41 let sect = cfg.section(&name); 42 let db_cfg = DbCfg::parse(sect).unwrap(); 43 db_test_setup_manual(db_cfg.sql_dir.as_ref(), src.component_name).await 44 } 45 46 pub async fn db_test_setup_manual(sql_dir: &Path, component_name: &str) -> PgPool { 47 setup_tracing(); 48 let cfg = test_db().await; 49 let pool = pool(cfg, &component_name.replace("-", "_")).await.unwrap(); 50 let mut conn = pool.acquire().await.unwrap(); 51 52 dbinit(&mut conn, sql_dir, component_name, true) 53 .await 54 .unwrap(); 55 pool 56 } 57 58 static MASTER_POOL: OnceLock<PgPool> = OnceLock::new(); 59 60 const DB: &str = "postgres:///taler_rust_check"; 61 static NB_DB: AtomicUsize = AtomicUsize::new(0); 62 63 async fn test_db() -> PgConnectOptions { 64 let master = MASTER_POOL.get_or_init(|| { 65 PgPoolOptions::new() 66 .max_connections(20) 67 .test_before_acquire(false) 68 .after_release(|_conn, _| Box::pin(async move { Ok(false) })) 69 .connect_lazy(DB) 70 .expect("pg pool") 71 }); 72 let idx = NB_DB.fetch_add(1, Ordering::Relaxed); 73 // Cleanup test db 74 let name = format!("taler_rust_test_{idx}"); 75 let mut conn = master.acquire().await.unwrap(); 76 sqlx::raw_sql(&format!("DROP DATABASE IF EXISTS {name}")) 77 .execute(&mut *conn) 78 .await 79 .unwrap(); 80 sqlx::raw_sql(&format!("CREATE DATABASE {name}")) 81 .execute(&mut *conn) 82 .await 83 .unwrap(); 84 drop(conn); 85 PgConnectOptions::from_str(&format!("postgresql:/{name}")).unwrap() 86 }