tests.rs

  1mod buffer_tests;
  2mod db_tests;
  3mod feature_flag_tests;
  4
  5use super::*;
  6use gpui::executor::Background;
  7use parking_lot::Mutex;
  8use sea_orm::ConnectionTrait;
  9use sqlx::migrate::MigrateDatabase;
 10use std::sync::Arc;
 11
 12pub struct TestDb {
 13    pub db: Option<Arc<Database>>,
 14    pub connection: Option<sqlx::AnyConnection>,
 15}
 16
 17impl TestDb {
 18    pub fn sqlite(background: Arc<Background>) -> Self {
 19        let url = format!("sqlite::memory:");
 20        let runtime = tokio::runtime::Builder::new_current_thread()
 21            .enable_io()
 22            .enable_time()
 23            .build()
 24            .unwrap();
 25
 26        let mut db = runtime.block_on(async {
 27            let mut options = ConnectOptions::new(url);
 28            options.max_connections(5);
 29            let db = Database::new(options, Executor::Deterministic(background))
 30                .await
 31                .unwrap();
 32            let sql = include_str!(concat!(
 33                env!("CARGO_MANIFEST_DIR"),
 34                "/migrations.sqlite/20221109000000_test_schema.sql"
 35            ));
 36            db.pool
 37                .execute(sea_orm::Statement::from_string(
 38                    db.pool.get_database_backend(),
 39                    sql.into(),
 40                ))
 41                .await
 42                .unwrap();
 43            db
 44        });
 45
 46        db.runtime = Some(runtime);
 47
 48        Self {
 49            db: Some(Arc::new(db)),
 50            connection: None,
 51        }
 52    }
 53
 54    pub fn postgres(background: Arc<Background>) -> Self {
 55        static LOCK: Mutex<()> = Mutex::new(());
 56
 57        let _guard = LOCK.lock();
 58        let mut rng = StdRng::from_entropy();
 59        let url = format!(
 60            "postgres://postgres@localhost/zed-test-{}",
 61            rng.gen::<u128>()
 62        );
 63        let runtime = tokio::runtime::Builder::new_current_thread()
 64            .enable_io()
 65            .enable_time()
 66            .build()
 67            .unwrap();
 68
 69        let mut db = runtime.block_on(async {
 70            sqlx::Postgres::create_database(&url)
 71                .await
 72                .expect("failed to create test db");
 73            let mut options = ConnectOptions::new(url);
 74            options
 75                .max_connections(5)
 76                .idle_timeout(Duration::from_secs(0));
 77            let db = Database::new(options, Executor::Deterministic(background))
 78                .await
 79                .unwrap();
 80            let migrations_path = concat!(env!("CARGO_MANIFEST_DIR"), "/migrations");
 81            db.migrate(Path::new(migrations_path), false).await.unwrap();
 82            db
 83        });
 84
 85        db.runtime = Some(runtime);
 86
 87        Self {
 88            db: Some(Arc::new(db)),
 89            connection: None,
 90        }
 91    }
 92
 93    pub fn db(&self) -> &Arc<Database> {
 94        self.db.as_ref().unwrap()
 95    }
 96}
 97
 98#[macro_export]
 99macro_rules! test_both_dbs {
100    ($test_name:ident, $postgres_test_name:ident, $sqlite_test_name:ident) => {
101        #[gpui::test]
102        async fn $postgres_test_name() {
103            let test_db = crate::db::TestDb::postgres(
104                gpui::executor::Deterministic::new(0).build_background(),
105            );
106            $test_name(test_db.db()).await;
107        }
108
109        #[gpui::test]
110        async fn $sqlite_test_name() {
111            let test_db =
112                crate::db::TestDb::sqlite(gpui::executor::Deterministic::new(0).build_background());
113            $test_name(test_db.db()).await;
114        }
115    };
116}
117
118impl Drop for TestDb {
119    fn drop(&mut self) {
120        let db = self.db.take().unwrap();
121        if let sea_orm::DatabaseBackend::Postgres = db.pool.get_database_backend() {
122            db.runtime.as_ref().unwrap().block_on(async {
123                use util::ResultExt;
124                let query = "
125                        SELECT pg_terminate_backend(pg_stat_activity.pid)
126                        FROM pg_stat_activity
127                        WHERE
128                            pg_stat_activity.datname = current_database() AND
129                            pid <> pg_backend_pid();
130                    ";
131                db.pool
132                    .execute(sea_orm::Statement::from_string(
133                        db.pool.get_database_backend(),
134                        query.into(),
135                    ))
136                    .await
137                    .log_err();
138                sqlx::Postgres::drop_database(db.options.get_url())
139                    .await
140                    .log_err();
141            })
142        }
143    }
144}