1use crate::sqlite::{apply_migrations, SqliteTestDb};
4use sova_core::{App, Plugin};
5use sova_db::Db;
6use sea_orm_migration::MigratorTrait;
7use std::future::Future;
8use std::pin::Pin;
9
10type InstallFn = Box<dyn FnOnce(&mut App) + Send>;
11type DbInstallFn = Box<dyn FnOnce(&mut App, String) + Send>;
12type MigrateFn = Box<dyn FnOnce(&str) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send>;
13
14pub struct TestApp;
16
17impl TestApp {
18 pub fn builder() -> TestAppBuilder {
19 TestAppBuilder {
20 migrate: None,
21 install_db: None,
22 plugins: Vec::new(),
23 env: Vec::new(),
24 }
25 }
26}
27
28pub struct TestAppBuilder {
29 migrate: Option<MigrateFn>,
30 install_db: Option<DbInstallFn>,
31 plugins: Vec<InstallFn>,
32 env: Vec<(String, String)>,
33}
34
35impl TestAppBuilder {
36 pub fn migrator<M: MigratorTrait + Send + Sync + 'static>(mut self) -> Self {
39 self.migrate = Some(Box::new(|url| {
40 let url = url.to_string();
41 Box::pin(async move {
42 apply_migrations::<M>(&url).await;
43 })
44 }));
45 self.install_db = Some(Box::new(|app, url| {
46 app.install(Db::from_env().url(url).migrations::<M>());
47 }));
48 self
49 }
50
51 pub fn env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
53 self.env.push((key.into(), value.into()));
54 self
55 }
56
57 pub fn install<P: Plugin + Send + 'static>(mut self, plugin: P) -> Self {
59 self.plugins.push(Box::new(move |app| {
60 app.install(plugin);
61 }));
62 self
63 }
64
65 pub fn configure<F>(mut self, f: F) -> Self
67 where
68 F: FnOnce(&mut App) + Send + 'static,
69 {
70 self.plugins.push(Box::new(f));
71 self
72 }
73
74 pub async fn build(self) -> (SqliteTestDb, App) {
76 let db = SqliteTestDb::create();
77 let url = db.url().to_string();
78 if let Some(migrate) = self.migrate {
79 migrate(&url).await;
80 }
81 for (k, v) in &self.env {
82 std::env::set_var(k, v);
83 }
84 std::env::set_var("DATABASE_URL", &url);
86 let mut app = App::new();
87 if let Some(install_db) = self.install_db {
88 install_db(&mut app, url);
89 }
90 for install in self.plugins {
91 install(&mut app);
92 }
93 app.run_startup().await.expect("run_startup");
94 (db, app)
95 }
96}