diff --git a/Cargo.lock b/Cargo.lock index 11c9d229c8..1e9d43b2c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5850,6 +5850,7 @@ dependencies = [ "tide-compress", "time 0.2.25", "toml", + "util", "zed", ] diff --git a/crates/editor/src/test.rs b/crates/editor/src/test.rs index f4622d1f6e..67622db83f 100644 --- a/crates/editor/src/test.rs +++ b/crates/editor/src/test.rs @@ -1,6 +1,7 @@ #[cfg(test)] #[ctor::ctor] fn init_logger() { - // std::env::set_var("RUST_LOG", "info"); - env_logger::init(); + if std::env::var("RUST_LOG").is_ok() { + env_logger::init(); + } } diff --git a/crates/gpui/src/test.rs b/crates/gpui/src/test.rs index b4b4e621ac..af6430d36c 100644 --- a/crates/gpui/src/test.rs +++ b/crates/gpui/src/test.rs @@ -18,9 +18,9 @@ use crate::{ #[cfg(test)] #[ctor::ctor] fn init_logger() { - env_logger::builder() - .filter_level(log::LevelFilter::Info) - .init(); + if std::env::var("RUST_LOG").is_ok() { + env_logger::init(); + } } pub fn run_test( diff --git a/crates/language/src/tests.rs b/crates/language/src/tests.rs index 25f58cdb42..1cede148de 100644 --- a/crates/language/src/tests.rs +++ b/crates/language/src/tests.rs @@ -17,8 +17,9 @@ use util::test::Network; #[cfg(test)] #[ctor::ctor] fn init_logger() { - // std::env::set_var("RUST_LOG", "info"); - env_logger::init(); + if std::env::var("RUST_LOG").is_ok() { + env_logger::init(); + } } #[test] diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index f0bf4b47cb..e9f9afd3fb 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -562,7 +562,7 @@ impl FakeLanguageServer { request.params, ); } else { - println!( + log::info!( "skipping message in fake language server {:?}", std::str::from_utf8(&self.buffer) ); diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index 2ce5a6342d..a4357415da 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -61,6 +61,7 @@ gpui = { path = "../gpui" } zed = { path = "../zed", features = ["test-support"] } ctor = "0.1" env_logger = "0.8" +util = { path = "../util" } lazy_static = "1.4" serde_json = { version = "1.0.64", features = ["preserve_order"] } diff --git a/crates/server/src/db.rs b/crates/server/src/db.rs index f71f40efd0..a48673f30f 100644 --- a/crates/server/src/db.rs +++ b/crates/server/src/db.rs @@ -526,68 +526,120 @@ pub struct ChannelMessage { #[cfg(test)] pub mod tests { use super::*; + use lazy_static::lazy_static; + use parking_lot::Mutex; use rand::prelude::*; use sqlx::{ migrate::{MigrateDatabase, Migrator}, Postgres, }; - use std::path::Path; + use std::{ + mem, + path::Path, + sync::atomic::{AtomicUsize, Ordering::SeqCst}, + }; + use util::ResultExt as _; pub struct TestDb { - pub db: Db, + pub db: Option, pub name: String, pub url: String, } + lazy_static! { + static ref DB_POOL: Mutex> = Default::default(); + static ref DB_COUNT: AtomicUsize = Default::default(); + } + impl TestDb { pub fn new() -> Self { - // Enable tests to run in parallel by serializing the creation of each test database. - lazy_static::lazy_static! { - static ref DB_CREATION: std::sync::Mutex<()> = std::sync::Mutex::new(()); - } - - let mut rng = StdRng::from_entropy(); - let name = format!("zed-test-{}", rng.gen::()); - let url = format!("postgres://postgres@localhost/{}", name); - let migrations_path = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/migrations")); - let db = block_on(async { - { - let _lock = DB_CREATION.lock(); + DB_COUNT.fetch_add(1, SeqCst); + let mut pool = DB_POOL.lock(); + if let Some(db) = pool.pop() { + db.truncate(); + db + } else { + let mut rng = StdRng::from_entropy(); + let name = format!("zed-test-{}", rng.gen::()); + let url = format!("postgres://postgres@localhost/{}", name); + let migrations_path = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/migrations")); + let db = block_on(async { Postgres::create_database(&url) .await .expect("failed to create test db"); - } - let mut db = Db::new(&url, 5).await.unwrap(); - db.test_mode = true; - let migrator = Migrator::new(migrations_path).await.unwrap(); - migrator.run(&db.pool).await.unwrap(); - db - }); + let mut db = Db::new(&url, 5).await.unwrap(); + db.test_mode = true; + let migrator = Migrator::new(migrations_path).await.unwrap(); + migrator.run(&db.pool).await.unwrap(); + db + }); - Self { db, name, url } + Self { + db: Some(db), + name, + url, + } + } } pub fn db(&self) -> &Db { - &self.db + self.db.as_ref().unwrap() + } + + fn truncate(&self) { + block_on(async { + let query = " + SELECT tablename FROM pg_tables + WHERE schemaname = 'public'; + "; + let table_names = sqlx::query_scalar::<_, String>(query) + .fetch_all(&self.db().pool) + .await + .unwrap(); + sqlx::query(&format!( + "TRUNCATE TABLE {} RESTART IDENTITY", + table_names.join(", ") + )) + .execute(&self.db().pool) + .await + .unwrap(); + }) + } + + async fn teardown(mut self) -> Result<()> { + let db = self.db.take().unwrap(); + let query = " + SELECT pg_terminate_backend(pg_stat_activity.pid) + FROM pg_stat_activity + WHERE pg_stat_activity.datname = '{}' AND pid <> pg_backend_pid(); + "; + sqlx::query(query) + .bind(&self.name) + .execute(&db.pool) + .await?; + db.pool.close().await; + Postgres::drop_database(&self.url).await?; + Ok(()) } } impl Drop for TestDb { fn drop(&mut self) { - block_on(async { - let query = " - SELECT pg_terminate_backend(pg_stat_activity.pid) - FROM pg_stat_activity - WHERE pg_stat_activity.datname = '{}' AND pid <> pg_backend_pid(); - "; - sqlx::query(query) - .bind(&self.name) - .execute(&self.db.pool) - .await - .unwrap(); - self.db.pool.close().await; - Postgres::drop_database(&self.url).await.unwrap(); - }); + if let Some(db) = self.db.take() { + DB_POOL.lock().push(TestDb { + db: Some(db), + name: mem::take(&mut self.name), + url: mem::take(&mut self.url), + }); + if DB_COUNT.fetch_sub(1, SeqCst) == 1 { + block_on(async move { + let mut pool = DB_POOL.lock(); + for db in pool.drain(..) { + db.teardown().await.log_err(); + } + }); + } + } } } diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index ee2fb6a94d..8314bec3db 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -1244,11 +1244,12 @@ mod tests { #[cfg(test)] #[ctor::ctor] fn init_logger() { - // std::env::set_var("RUST_LOG", "info"); - env_logger::init(); + if std::env::var("RUST_LOG").is_ok() { + env_logger::init(); + } } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_share_project(mut cx_a: TestAppContext, mut cx_b: TestAppContext) { let (window_b, _) = cx_b.add_window(|_| EmptyView); let lang_registry = Arc::new(LanguageRegistry::new()); @@ -1387,7 +1388,7 @@ mod tests { .await; } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_unshare_project(mut cx_a: TestAppContext, mut cx_b: TestAppContext) { let lang_registry = Arc::new(LanguageRegistry::new()); let fs = Arc::new(FakeFs::new(cx_a.background())); @@ -1484,7 +1485,7 @@ mod tests { .unwrap(); } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_propagate_saves_and_fs_changes( mut cx_a: TestAppContext, mut cx_b: TestAppContext, @@ -1674,7 +1675,7 @@ mod tests { .await; } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_buffer_conflict_after_save(mut cx_a: TestAppContext, mut cx_b: TestAppContext) { cx_a.foreground().forbid_parking(); let lang_registry = Arc::new(LanguageRegistry::new()); @@ -1767,7 +1768,7 @@ mod tests { }); } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_buffer_reloading(mut cx_a: TestAppContext, mut cx_b: TestAppContext) { cx_a.foreground().forbid_parking(); let lang_registry = Arc::new(LanguageRegistry::new()); @@ -1929,7 +1930,7 @@ mod tests { buffer_b.condition(&cx_b, |buf, _| buf.text() == text).await; } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_leaving_worktree_while_opening_buffer( mut cx_a: TestAppContext, mut cx_b: TestAppContext, @@ -2007,7 +2008,7 @@ mod tests { .await; } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_peer_disconnection(mut cx_a: TestAppContext, mut cx_b: TestAppContext) { cx_a.foreground().forbid_parking(); let lang_registry = Arc::new(LanguageRegistry::new()); @@ -2078,7 +2079,7 @@ mod tests { .await; } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_collaborating_with_diagnostics( mut cx_a: TestAppContext, mut cx_b: TestAppContext, @@ -2302,7 +2303,7 @@ mod tests { }); } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_collaborating_with_completion( mut cx_a: TestAppContext, mut cx_b: TestAppContext, @@ -2527,7 +2528,7 @@ mod tests { ); } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_formatting_buffer(mut cx_a: TestAppContext, mut cx_b: TestAppContext) { cx_a.foreground().forbid_parking(); let mut lang_registry = Arc::new(LanguageRegistry::new()); @@ -2631,7 +2632,7 @@ mod tests { ); } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_definition(mut cx_a: TestAppContext, mut cx_b: TestAppContext) { cx_a.foreground().forbid_parking(); let mut lang_registry = Arc::new(LanguageRegistry::new()); @@ -2788,7 +2789,7 @@ mod tests { .await; } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_open_buffer_while_getting_definition_pointing_to_it( mut cx_a: TestAppContext, mut cx_b: TestAppContext, @@ -2902,7 +2903,7 @@ mod tests { assert_eq!(definitions[0].target_buffer, buffer_b2); } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_basic_chat(mut cx_a: TestAppContext, mut cx_b: TestAppContext) { cx_a.foreground().forbid_parking(); @@ -3042,7 +3043,7 @@ mod tests { .await; } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_chat_message_validation(mut cx_a: TestAppContext) { cx_a.foreground().forbid_parking(); @@ -3102,7 +3103,7 @@ mod tests { ); } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_chat_reconnection(mut cx_a: TestAppContext, mut cx_b: TestAppContext) { cx_a.foreground().forbid_parking(); @@ -3314,7 +3315,7 @@ mod tests { .await; } - #[gpui::test] + #[gpui::test(iterations = 10)] async fn test_contacts( mut cx_a: TestAppContext, mut cx_b: TestAppContext, diff --git a/crates/text/src/tests.rs b/crates/text/src/tests.rs index e45011c4ac..ad0cc7aa30 100644 --- a/crates/text/src/tests.rs +++ b/crates/text/src/tests.rs @@ -12,8 +12,9 @@ use util::test::Network; #[cfg(test)] #[ctor::ctor] fn init_logger() { - // std::env::set_var("RUST_LOG", "info"); - env_logger::init(); + if std::env::var("RUST_LOG").is_ok() { + env_logger::init(); + } } #[test] diff --git a/crates/zed/src/test.rs b/crates/zed/src/test.rs index a365fdc6f4..5bf43b555f 100644 --- a/crates/zed/src/test.rs +++ b/crates/zed/src/test.rs @@ -12,7 +12,9 @@ use workspace::Settings; #[cfg(test)] #[ctor::ctor] fn init_logger() { - env_logger::init(); + if std::env::var("RUST_LOG").is_ok() { + env_logger::init(); + } } pub fn test_app_state(cx: &mut MutableAppContext) -> Arc {