🚧 Prevent database errors in test cases

This commit is contained in:
Manuel Cillero 2023-10-26 13:25:17 +02:00
parent d7762a10fa
commit 46ccbc10eb
7 changed files with 194 additions and 105 deletions

View file

@ -60,6 +60,7 @@ impl MigrationTrait for Migration {
.values_panic(vec!["administrator".into(), "3".into()]), .values_panic(vec!["administrator".into(), "3".into()]),
) )
.await .await
.unwrap_or_error(|e| DbErr::Custom(e.message()))
.map(|_| ()) .map(|_| ())
} }

View file

@ -1,7 +1,8 @@
use crate::core::action::add_action; use crate::core::action::add_action;
use crate::core::module::ModuleRef; use crate::core::module::ModuleRef;
use crate::core::theme::all::THEMES; use crate::core::theme::all::THEMES;
use crate::{service, trace, LazyStatic}; use crate::locale::L10n;
use crate::{service, trace, LazyStatic, ResultExt};
#[cfg(feature = "database")] #[cfg(feature = "database")]
use crate::db::*; use crate::db::*;
@ -109,6 +110,7 @@ pub fn init_modules() {
#[cfg(feature = "database")] #[cfg(feature = "database")]
pub fn run_migrations() { pub fn run_migrations() {
if let Some(dbconn) = &*DBCONN {
run_now({ run_now({
struct Migrator; struct Migrator;
impl MigratorTrait for Migrator { impl MigratorTrait for Migrator {
@ -120,9 +122,9 @@ pub fn run_migrations() {
migrations migrations
} }
} }
Migrator::up(SchemaManagerConnection::Connection(&DBCONN), None) Migrator::up(SchemaManagerConnection::Connection(dbconn), None)
}) })
.unwrap(); .expect_or_log(L10n::l("db_migration_fail").message().as_str());
run_now({ run_now({
struct Migrator; struct Migrator;
@ -135,9 +137,10 @@ pub fn run_migrations() {
migrations migrations
} }
} }
Migrator::down(SchemaManagerConnection::Connection(&DBCONN), None) Migrator::down(SchemaManagerConnection::Connection(dbconn), None)
}) })
.unwrap(); .expect_or_log(L10n::l("db_migration_fail").message().as_str());
}
} }
// CONFIGURE SERVICES ****************************************************************************** // CONFIGURE SERVICES ******************************************************************************

View file

@ -1,5 +1,7 @@
//! Acceso unificado y normalizado a base de datos. //! Acceso unificado y normalizado a base de datos.
use crate::locale::L10n;
use crate::result::{SafeResult, TraceErr};
use crate::{config, trace, LazyStatic, ResultExt}; use crate::{config, trace, LazyStatic, ResultExt};
pub use url::Url as DbUri; pub use url::Url as DbUri;
@ -10,7 +12,8 @@ use sea_orm::{ConnectOptions, ConnectionTrait, Database, DatabaseBackend, Statem
pub(crate) use futures::executor::block_on as run_now; pub(crate) use futures::executor::block_on as run_now;
pub(crate) static DBCONN: LazyStatic<DbConn> = LazyStatic::new(|| { pub(crate) static DBCONN: LazyStatic<Option<DbConn>> = LazyStatic::new(|| {
if !config::SETTINGS.database.db_name.trim().is_empty() {
trace::info!( trace::info!(
"Connecting to database \"{}\" using a pool of {} connections", "Connecting to database \"{}\" using a pool of {} connections",
&config::SETTINGS.database.db_name, &config::SETTINGS.database.db_name,
@ -61,46 +64,88 @@ pub(crate) static DBCONN: LazyStatic<DbConn> = LazyStatic::new(|| {
} }
}; };
Some(
run_now(Database::connect::<ConnectOptions>({ run_now(Database::connect::<ConnectOptions>({
let mut db_opt = ConnectOptions::new(db_uri.to_string()); let mut db_opt = ConnectOptions::new(db_uri.to_string());
db_opt.max_connections(config::SETTINGS.database.max_pool_size); db_opt.max_connections(config::SETTINGS.database.max_pool_size);
db_opt db_opt
})) }))
.expect_or_log("Failed to connect to database") .expect_or_log(L10n::l("db_connection_fail").message().as_str()),
)
} else {
None
}
}); });
static DBBACKEND: LazyStatic<DatabaseBackend> = LazyStatic::new(|| DBCONN.get_database_backend()); pub async fn query<Q: QueryStatementWriter>(stmt: &mut Q) -> SafeResult<Option<Vec<QueryResult>>> {
match &*DBCONN {
pub async fn query<Q: QueryStatementWriter>(stmt: &mut Q) -> Result<Vec<QueryResult>, DbErr> { Some(dbconn) => {
DBCONN let dbbackend = dbconn.get_database_backend();
match dbconn
.query_all(Statement::from_string( .query_all(Statement::from_string(
*DBBACKEND, dbbackend,
match *DBBACKEND { match dbbackend {
DatabaseBackend::MySql => stmt.to_string(MysqlQueryBuilder), DatabaseBackend::MySql => stmt.to_string(MysqlQueryBuilder),
DatabaseBackend::Postgres => stmt.to_string(PostgresQueryBuilder), DatabaseBackend::Postgres => stmt.to_string(PostgresQueryBuilder),
DatabaseBackend::Sqlite => stmt.to_string(SqliteQueryBuilder), DatabaseBackend::Sqlite => stmt.to_string(SqliteQueryBuilder),
}, },
)) ))
.await .await
{
Ok(result) => SafeResult::Ok(Some(result)),
Err(e) => SafeResult::Err(TraceErr::error(L10n::n(e.to_string()), None)),
}
}
None => SafeResult::Err(TraceErr::trace(
L10n::l("db_connection_not_initialized"),
None,
)),
}
} }
pub async fn exec<Q: QueryStatementWriter>(stmt: &mut Q) -> Result<Option<QueryResult>, DbErr> { pub async fn exec<Q: QueryStatementWriter>(stmt: &mut Q) -> SafeResult<Option<QueryResult>> {
DBCONN match &*DBCONN {
Some(dbconn) => {
let dbbackend = dbconn.get_database_backend();
match dbconn
.query_one(Statement::from_string( .query_one(Statement::from_string(
*DBBACKEND, dbbackend,
match *DBBACKEND { match dbbackend {
DatabaseBackend::MySql => stmt.to_string(MysqlQueryBuilder), DatabaseBackend::MySql => stmt.to_string(MysqlQueryBuilder),
DatabaseBackend::Postgres => stmt.to_string(PostgresQueryBuilder), DatabaseBackend::Postgres => stmt.to_string(PostgresQueryBuilder),
DatabaseBackend::Sqlite => stmt.to_string(SqliteQueryBuilder), DatabaseBackend::Sqlite => stmt.to_string(SqliteQueryBuilder),
}, },
)) ))
.await .await
{
Ok(result) => SafeResult::Ok(result),
Err(e) => SafeResult::Err(TraceErr::error(L10n::n(e.to_string()), None)),
}
}
None => SafeResult::Err(TraceErr::trace(
L10n::l("db_connection_not_initialized"),
None,
)),
}
} }
pub async fn exec_raw(stmt: String) -> Result<ExecResult, DbErr> { pub async fn exec_raw(stmt: String) -> SafeResult<Option<ExecResult>> {
DBCONN match &*DBCONN {
.execute(Statement::from_string(*DBBACKEND, stmt)) Some(dbconn) => {
let dbbackend = dbconn.get_database_backend();
match dbconn
.execute(Statement::from_string(dbbackend, stmt))
.await .await
{
Ok(result) => SafeResult::Ok(Some(result)),
Err(e) => SafeResult::Err(TraceErr::error(L10n::n(e.to_string()), None)),
}
}
None => SafeResult::Err(TraceErr::trace(
L10n::l("db_connection_not_initialized"),
None,
)),
}
} }
// El siguiente módulo migration es una versión simplificada del módulo sea_orm_migration (v0.11.3) // El siguiente módulo migration es una versión simplificada del módulo sea_orm_migration (v0.11.3)

View file

@ -2,3 +2,7 @@
# ERRORS. # ERRORS.
language_set_failure = Failed to set language. Unicode Language Identifier "{$language}" is not accepted. Using "en-US", check the settings file language_set_failure = Failed to set language. Unicode Language Identifier "{$language}" is not accepted. Using "en-US", check the settings file
db_connection_fail = Failed to connect to database
db_connection_not_initialized = Database connection not initialized
db_migration_fail = Database update failed

View file

@ -1,4 +1,8 @@
# DEBUG. # DEBUG.
# ERRORS. # ERRORS.
language_set_failure = Error al establecer idioma. El Identificador de Lenguaje Unicode "{$language}" no es válido. Se usará "en-US". Comprobar archivo de configuración language_set_failure = Fallo al asignar idioma. El Identificador de Lenguaje Unicode "{$language}" no es válido. Se usará "en-US". Comprobar archivo de configuración
db_connection_fail = Fallo al conectar con la base de datos
db_connection_not_initialized = Conexión a la base de datos no inicializada
db_migration_fail = Fallo en la actualización de la base de datos

View file

@ -9,6 +9,24 @@ pub struct TraceErr<T> {
} }
impl<T> TraceErr<T> { impl<T> TraceErr<T> {
pub fn trace(trace: L10n, fallback: T) -> Self {
let message = trace.message();
trace::trace!(message);
TraceErr { message, fallback }
}
pub fn debug(trace: L10n, fallback: T) -> Self {
let message = trace.message();
trace::debug!(message);
TraceErr { message, fallback }
}
pub fn info(trace: L10n, fallback: T) -> Self {
let message = trace.message();
trace::info!(message);
TraceErr { message, fallback }
}
pub fn warn(trace: L10n, fallback: T) -> Self { pub fn warn(trace: L10n, fallback: T) -> Self {
let message = trace.message(); let message = trace.message();
trace::warn!(message); trace::warn!(message);
@ -21,6 +39,8 @@ impl<T> TraceErr<T> {
TraceErr { message, fallback } TraceErr { message, fallback }
} }
// TraceErr GETTERS.
pub fn message(self) -> String { pub fn message(self) -> String {
self.message self.message
} }
@ -36,10 +56,22 @@ pub enum SafeResult<T> {
} }
impl<T> SafeResult<T> { impl<T> SafeResult<T> {
#[inline]
pub fn unwrap_or_error<F, E>(self, f: F) -> Result<T, E>
where
F: FnOnce(TraceErr<T>) -> E,
{
match self {
SafeResult::Ok(r) => Ok(r),
SafeResult::Err(e) => Err(f(e)),
}
}
#[inline]
pub fn unwrap_or_fallback(self) -> T { pub fn unwrap_or_fallback(self) -> T {
match self { match self {
SafeResult::Ok(result) => result, SafeResult::Ok(r) => r,
SafeResult::Err(trace) => trace.fallback(), SafeResult::Err(e) => e.fallback(),
} }
} }
} }

View file

@ -16,5 +16,5 @@ async fn health_check_works() {
let req = service::test::TestRequest::get().uri("/").to_request(); let req = service::test::TestRequest::get().uri("/").to_request();
let _resp = service::test::call_service(&app, req).await; let _resp = service::test::call_service(&app, req).await;
// assert_eq!("OK", "OK"); // assert_eq!("OK", "OK");
} }