🚧 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()]),
)
.await
.unwrap_or_error(|e| DbErr::Custom(e.message()))
.map(|_| ())
}

View file

@ -1,7 +1,8 @@
use crate::core::action::add_action;
use crate::core::module::ModuleRef;
use crate::core::theme::all::THEMES;
use crate::{service, trace, LazyStatic};
use crate::locale::L10n;
use crate::{service, trace, LazyStatic, ResultExt};
#[cfg(feature = "database")]
use crate::db::*;
@ -109,6 +110,7 @@ pub fn init_modules() {
#[cfg(feature = "database")]
pub fn run_migrations() {
if let Some(dbconn) = &*DBCONN {
run_now({
struct Migrator;
impl MigratorTrait for Migrator {
@ -120,9 +122,9 @@ pub fn run_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({
struct Migrator;
@ -135,9 +137,10 @@ pub fn run_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 ******************************************************************************

View file

@ -1,5 +1,7 @@
//! Acceso unificado y normalizado a base de datos.
use crate::locale::L10n;
use crate::result::{SafeResult, TraceErr};
use crate::{config, trace, LazyStatic, ResultExt};
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) 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!(
"Connecting to database \"{}\" using a pool of {} connections",
&config::SETTINGS.database.db_name,
@ -61,46 +64,88 @@ pub(crate) static DBCONN: LazyStatic<DbConn> = LazyStatic::new(|| {
}
};
Some(
run_now(Database::connect::<ConnectOptions>({
let mut db_opt = ConnectOptions::new(db_uri.to_string());
db_opt.max_connections(config::SETTINGS.database.max_pool_size);
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) -> Result<Vec<QueryResult>, DbErr> {
DBCONN
pub async fn query<Q: QueryStatementWriter>(stmt: &mut Q) -> SafeResult<Option<Vec<QueryResult>>> {
match &*DBCONN {
Some(dbconn) => {
let dbbackend = dbconn.get_database_backend();
match dbconn
.query_all(Statement::from_string(
*DBBACKEND,
match *DBBACKEND {
dbbackend,
match dbbackend {
DatabaseBackend::MySql => stmt.to_string(MysqlQueryBuilder),
DatabaseBackend::Postgres => stmt.to_string(PostgresQueryBuilder),
DatabaseBackend::Sqlite => stmt.to_string(SqliteQueryBuilder),
},
))
.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> {
DBCONN
pub async fn exec<Q: QueryStatementWriter>(stmt: &mut Q) -> SafeResult<Option<QueryResult>> {
match &*DBCONN {
Some(dbconn) => {
let dbbackend = dbconn.get_database_backend();
match dbconn
.query_one(Statement::from_string(
*DBBACKEND,
match *DBBACKEND {
dbbackend,
match dbbackend {
DatabaseBackend::MySql => stmt.to_string(MysqlQueryBuilder),
DatabaseBackend::Postgres => stmt.to_string(PostgresQueryBuilder),
DatabaseBackend::Sqlite => stmt.to_string(SqliteQueryBuilder),
},
))
.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> {
DBCONN
.execute(Statement::from_string(*DBBACKEND, stmt))
pub async fn exec_raw(stmt: String) -> SafeResult<Option<ExecResult>> {
match &*DBCONN {
Some(dbconn) => {
let dbbackend = dbconn.get_database_backend();
match dbconn
.execute(Statement::from_string(dbbackend, stmt))
.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)

View file

@ -2,3 +2,7 @@
# ERRORS.
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.
# 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> {
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 {
let message = trace.message();
trace::warn!(message);
@ -21,6 +39,8 @@ impl<T> TraceErr<T> {
TraceErr { message, fallback }
}
// TraceErr GETTERS.
pub fn message(self) -> String {
self.message
}
@ -36,10 +56,22 @@ pub enum 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 {
match self {
SafeResult::Ok(result) => result,
SafeResult::Err(trace) => trace.fallback(),
SafeResult::Ok(r) => r,
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 _resp = service::test::call_service(&app, req).await;
// assert_eq!("OK", "OK");
// assert_eq!("OK", "OK");
}