@@ -12,8 +12,16 @@ use sqlx::{
use std::{cmp, ops::Range, path::Path, time::Duration};
use time::{OffsetDateTime, PrimitiveDateTime};
+#[cfg(test)]
+pub type DefaultDb = Db<sqlx::Sqlite>;
+
+#[cfg(not(test))]
+pub type DefaultDb = Db<sqlx::Postgres>;
+
pub struct Db<D: sqlx::Database> {
pool: sqlx::Pool<D>,
+ #[cfg(test)]
+ background: Option<std::sync::Arc<gpui::executor::Background>>,
}
macro_rules! test_support {
@@ -23,6 +31,10 @@ macro_rules! test_support {
};
if cfg!(test) {
+ #[cfg(test)]
+ if let Some(background) = $self.background.as_ref() {
+ background.simulate_random_delay().await;
+ }
tokio::runtime::Builder::new_current_thread().enable_io().enable_time().build().unwrap().block_on(body)
} else {
body.await
@@ -30,7 +42,7 @@ macro_rules! test_support {
}};
}
-trait RowsAffected {
+pub trait RowsAffected {
fn rows_affected(&self) -> u64;
}
@@ -48,32 +60,37 @@ impl RowsAffected for sqlx::postgres::PgQueryResult {
impl Db<sqlx::Sqlite> {
#[cfg(test)]
- pub async fn sqlite(url: &str, max_connections: u32) -> Result<Self> {
+ pub async fn new(url: &str, max_connections: u32) -> Result<Self> {
let pool = sqlx::sqlite::SqlitePoolOptions::new()
.max_connections(max_connections)
.connect(url)
.await?;
- Ok(Self { pool })
+ Ok(Self {
+ pool,
+ background: None,
+ })
}
}
impl Db<sqlx::Postgres> {
- pub async fn postgres(url: &str, max_connections: u32) -> Result<Self> {
+ pub async fn new(url: &str, max_connections: u32) -> Result<Self> {
let pool = sqlx::postgres::PgPoolOptions::new()
.max_connections(max_connections)
.connect(url)
.await?;
- Ok(Self { pool })
+ Ok(Self {
+ pool,
+ #[cfg(test)]
+ background: None,
+ })
}
}
impl<D> Db<D>
where
D: sqlx::Database + sqlx::migrate::MigrateDatabase,
- for<'a> <D as sqlx::database::HasArguments<'a>>::Arguments: sqlx::IntoArguments<'a, D>,
- D: for<'a> sqlx::database::HasValueRef<'a>,
- D: for<'a> sqlx::database::HasArguments<'a>,
D::Connection: sqlx::migrate::Migrate,
+ for<'a> <D as sqlx::database::HasArguments<'a>>::Arguments: sqlx::IntoArguments<'a, D>,
for<'a> &'a mut D::Connection: sqlx::Executor<'a, Database = D>,
for<'a, 'b> &'b mut sqlx::Transaction<'a, D>: sqlx::Executor<'b, Database = D>,
D::QueryResult: RowsAffected,
@@ -452,19 +469,18 @@ where
pub async fn record_sent_invites(&self, invites: &[Invite]) -> Result<()> {
test_support!(self, {
+ let emails = invites
+ .iter()
+ .map(|s| s.email_address.as_str())
+ .collect::<Vec<_>>();
sqlx::query(
"
UPDATE signups
SET email_confirmation_sent = TRUE
- WHERE email_address = ANY ($1)
+ WHERE email_address IN (SELECT value from json_each($1))
",
)
- // .bind(
- // &invites
- // .iter()
- // .map(|s| s.email_address.as_str())
- // .collect::<Vec<_>>(),
- // )
+ .bind(&serde_json::json!(emails))
.execute(&self.pool)
.await?;
Ok(())
@@ -808,7 +824,7 @@ where
count = excluded.count
",
);
- query.build().execute(&self.pool).await?;
+ // query.build().execute(&self.pool).await?;
Ok(())
})
@@ -1604,24 +1620,6 @@ where
.await?)
})
}
-
- #[cfg(test)]
- pub async fn teardown(&self, url: &str) {
- test_support!(self, {
- use util::ResultExt;
-
- let query = "
- SELECT pg_terminate_backend(pg_stat_activity.pid)
- FROM pg_stat_activity
- WHERE pg_stat_activity.datname = current_database() AND pid <> pg_backend_pid();
- ";
- sqlx::query(query).execute(&self.pool).await.log_err();
- self.pool.close().await;
- <sqlx::Sqlite as sqlx::migrate::MigrateDatabase>::drop_database(url)
- .await
- .log_err();
- })
- }
}
macro_rules! id_type {
@@ -1833,51 +1831,37 @@ mod test {
use super::*;
use gpui::executor::Background;
use rand::prelude::*;
- use sqlx::{migrate::MigrateDatabase, Sqlite};
+ use sqlx::migrate::MigrateDatabase;
use std::sync::Arc;
pub struct TestDb {
- pub db: Option<Arc<Db<Sqlite>>>,
+ pub db: Option<Arc<DefaultDb>>,
pub url: String,
}
impl TestDb {
- #[allow(clippy::await_holding_lock)]
- pub async fn real() -> Self {
- todo!()
- // eprintln!("creating database...");
- // let start = std::time::Instant::now();
- // let mut rng = StdRng::from_entropy();
- // let url = format!("/tmp/zed-test-{}", rng.gen::<u128>());
- // Sqlite::create_database(&url).await.unwrap();
- // let db = Db::new(&url, 5).await.unwrap();
- // db.migrate(Path::new(DEFAULT_MIGRATIONS_PATH.unwrap()), false)
- // .await
- // .unwrap();
-
- // eprintln!("created database: {:?}", start.elapsed());
- // Self {
- // db: Some(Arc::new(db)),
- // url,
- // }
- }
-
- pub async fn fake(background: Arc<Background>) -> Self {
- let start = std::time::Instant::now();
+ pub async fn new(background: Arc<Background>) -> Self {
let mut rng = StdRng::from_entropy();
- let url = format!("file:db-{}?mode=memory&cache=shared", rng.gen::<u128>());
- let db = Db::sqlite(&url, 5).await.unwrap();
+ let url = format!("/tmp/zed-test-{}", rng.gen::<u128>());
+ sqlx::Sqlite::create_database(&url).await.unwrap();
+ let mut db = DefaultDb::new(&url, 5).await.unwrap();
+ db.background = Some(background);
let migrations_path = concat!(env!("CARGO_MANIFEST_DIR"), "/migrations.sqlite");
db.migrate(Path::new(migrations_path), false).await.unwrap();
-
Self {
db: Some(Arc::new(db)),
url,
}
}
- pub fn db(&self) -> &Arc<Db<Sqlite>> {
+ pub fn db(&self) -> &Arc<DefaultDb> {
self.db.as_ref().unwrap()
}
}
+
+ impl Drop for TestDb {
+ fn drop(&mut self) {
+ std::fs::remove_file(&self.url).ok();
+ }
+ }
}
@@ -6,133 +6,125 @@ use time::OffsetDateTime;
#[tokio::test(flavor = "multi_thread")]
async fn test_get_users_by_ids() {
- for test_db in [
- TestDb::real().await,
- TestDb::fake(build_background_executor()),
- ] {
- let db = test_db.db();
-
- let mut user_ids = Vec::new();
- for i in 1..=4 {
- user_ids.push(
- db.create_user(
- &format!("user{i}@example.com"),
- false,
- NewUserParams {
- github_login: format!("user{i}"),
- github_user_id: i,
- invite_count: 0,
- },
- )
- .await
- .unwrap()
- .user_id,
- );
- }
-
- assert_eq!(
- db.get_users_by_ids(user_ids.clone()).await.unwrap(),
- vec![
- User {
- id: user_ids[0],
- github_login: "user1".to_string(),
- github_user_id: Some(1),
- email_address: Some("user1@example.com".to_string()),
- admin: false,
- ..Default::default()
- },
- User {
- id: user_ids[1],
- github_login: "user2".to_string(),
- github_user_id: Some(2),
- email_address: Some("user2@example.com".to_string()),
- admin: false,
- ..Default::default()
- },
- User {
- id: user_ids[2],
- github_login: "user3".to_string(),
- github_user_id: Some(3),
- email_address: Some("user3@example.com".to_string()),
- admin: false,
- ..Default::default()
- },
- User {
- id: user_ids[3],
- github_login: "user4".to_string(),
- github_user_id: Some(4),
- email_address: Some("user4@example.com".to_string()),
- admin: false,
- ..Default::default()
- }
- ]
- );
- }
-}
+ let test_db = TestDb::new(build_background_executor()).await;
+ let db = test_db.db();
-#[tokio::test(flavor = "multi_thread")]
-async fn test_get_user_by_github_account() {
- for test_db in [
- TestDb::real().await,
- TestDb::fake(build_background_executor()),
- ] {
- let db = test_db.db();
- let user_id1 = db
- .create_user(
- "user1@example.com",
- false,
- NewUserParams {
- github_login: "login1".into(),
- github_user_id: 101,
- invite_count: 0,
- },
- )
- .await
- .unwrap()
- .user_id;
- let user_id2 = db
- .create_user(
- "user2@example.com",
+ let mut user_ids = Vec::new();
+ for i in 1..=4 {
+ user_ids.push(
+ db.create_user(
+ &format!("user{i}@example.com"),
false,
NewUserParams {
- github_login: "login2".into(),
- github_user_id: 102,
+ github_login: format!("user{i}"),
+ github_user_id: i,
invite_count: 0,
},
)
.await
.unwrap()
- .user_id;
+ .user_id,
+ );
+ }
- let user = db
- .get_user_by_github_account("login1", None)
- .await
- .unwrap()
- .unwrap();
- assert_eq!(user.id, user_id1);
- assert_eq!(&user.github_login, "login1");
- assert_eq!(user.github_user_id, Some(101));
+ assert_eq!(
+ db.get_users_by_ids(user_ids.clone()).await.unwrap(),
+ vec![
+ User {
+ id: user_ids[0],
+ github_login: "user1".to_string(),
+ github_user_id: Some(1),
+ email_address: Some("user1@example.com".to_string()),
+ admin: false,
+ ..Default::default()
+ },
+ User {
+ id: user_ids[1],
+ github_login: "user2".to_string(),
+ github_user_id: Some(2),
+ email_address: Some("user2@example.com".to_string()),
+ admin: false,
+ ..Default::default()
+ },
+ User {
+ id: user_ids[2],
+ github_login: "user3".to_string(),
+ github_user_id: Some(3),
+ email_address: Some("user3@example.com".to_string()),
+ admin: false,
+ ..Default::default()
+ },
+ User {
+ id: user_ids[3],
+ github_login: "user4".to_string(),
+ github_user_id: Some(4),
+ email_address: Some("user4@example.com".to_string()),
+ admin: false,
+ ..Default::default()
+ }
+ ]
+ );
+}
- assert!(db
- .get_user_by_github_account("non-existent-login", None)
- .await
- .unwrap()
- .is_none());
+#[tokio::test(flavor = "multi_thread")]
+async fn test_get_user_by_github_account() {
+ let test_db = TestDb::new(build_background_executor()).await;
+ let db = test_db.db();
+ let user_id1 = db
+ .create_user(
+ "user1@example.com",
+ false,
+ NewUserParams {
+ github_login: "login1".into(),
+ github_user_id: 101,
+ invite_count: 0,
+ },
+ )
+ .await
+ .unwrap()
+ .user_id;
+ let user_id2 = db
+ .create_user(
+ "user2@example.com",
+ false,
+ NewUserParams {
+ github_login: "login2".into(),
+ github_user_id: 102,
+ invite_count: 0,
+ },
+ )
+ .await
+ .unwrap()
+ .user_id;
- let user = db
- .get_user_by_github_account("the-new-login2", Some(102))
- .await
- .unwrap()
- .unwrap();
- assert_eq!(user.id, user_id2);
- assert_eq!(&user.github_login, "the-new-login2");
- assert_eq!(user.github_user_id, Some(102));
- }
+ let user = db
+ .get_user_by_github_account("login1", None)
+ .await
+ .unwrap()
+ .unwrap();
+ assert_eq!(user.id, user_id1);
+ assert_eq!(&user.github_login, "login1");
+ assert_eq!(user.github_user_id, Some(101));
+
+ assert!(db
+ .get_user_by_github_account("non-existent-login", None)
+ .await
+ .unwrap()
+ .is_none());
+
+ let user = db
+ .get_user_by_github_account("the-new-login2", Some(102))
+ .await
+ .unwrap()
+ .unwrap();
+ assert_eq!(user.id, user_id2);
+ assert_eq!(&user.github_login, "the-new-login2");
+ assert_eq!(user.github_user_id, Some(102));
}
#[tokio::test(flavor = "multi_thread")]
async fn test_worktree_extensions() {
- let test_db = TestDb::real().await;
+ let test_db = TestDb::new(build_background_executor()).await;
let db = test_db.db();
let user = db
@@ -204,7 +196,7 @@ async fn test_worktree_extensions() {
#[tokio::test(flavor = "multi_thread")]
async fn test_user_activity() {
- let test_db = TestDb::real().await;
+ let test_db = TestDb::new(build_background_executor()).await;
let db = test_db.db();
let mut user_ids = Vec::new();
@@ -447,98 +439,90 @@ async fn test_user_activity() {
#[tokio::test(flavor = "multi_thread")]
async fn test_recent_channel_messages() {
- for test_db in [
- TestDb::real().await,
- TestDb::fake(build_background_executor()),
- ] {
- let db = test_db.db();
- let user = db
- .create_user(
- "u@example.com",
- false,
- NewUserParams {
- github_login: "u".into(),
- github_user_id: 1,
- invite_count: 0,
- },
- )
- .await
- .unwrap()
- .user_id;
- let org = db.create_org("org", "org").await.unwrap();
- let channel = db.create_org_channel(org, "channel").await.unwrap();
- for i in 0..10 {
- db.create_channel_message(channel, user, &i.to_string(), OffsetDateTime::now_utc(), i)
- .await
- .unwrap();
- }
-
- let messages = db.get_channel_messages(channel, 5, None).await.unwrap();
- assert_eq!(
- messages.iter().map(|m| &m.body).collect::<Vec<_>>(),
- ["5", "6", "7", "8", "9"]
- );
-
- let prev_messages = db
- .get_channel_messages(channel, 4, Some(messages[0].id))
+ let test_db = TestDb::new(build_background_executor()).await;
+ let db = test_db.db();
+ let user = db
+ .create_user(
+ "u@example.com",
+ false,
+ NewUserParams {
+ github_login: "u".into(),
+ github_user_id: 1,
+ invite_count: 0,
+ },
+ )
+ .await
+ .unwrap()
+ .user_id;
+ let org = db.create_org("org", "org").await.unwrap();
+ let channel = db.create_org_channel(org, "channel").await.unwrap();
+ for i in 0..10 {
+ db.create_channel_message(channel, user, &i.to_string(), OffsetDateTime::now_utc(), i)
.await
.unwrap();
- assert_eq!(
- prev_messages.iter().map(|m| &m.body).collect::<Vec<_>>(),
- ["1", "2", "3", "4"]
- );
}
+
+ let messages = db.get_channel_messages(channel, 5, None).await.unwrap();
+ assert_eq!(
+ messages.iter().map(|m| &m.body).collect::<Vec<_>>(),
+ ["5", "6", "7", "8", "9"]
+ );
+
+ let prev_messages = db
+ .get_channel_messages(channel, 4, Some(messages[0].id))
+ .await
+ .unwrap();
+ assert_eq!(
+ prev_messages.iter().map(|m| &m.body).collect::<Vec<_>>(),
+ ["1", "2", "3", "4"]
+ );
}
#[tokio::test(flavor = "multi_thread")]
async fn test_channel_message_nonces() {
- for test_db in [
- TestDb::real().await,
- TestDb::fake(build_background_executor()),
- ] {
- let db = test_db.db();
- let user = db
- .create_user(
- "user@example.com",
- false,
- NewUserParams {
- github_login: "user".into(),
- github_user_id: 1,
- invite_count: 0,
- },
- )
- .await
- .unwrap()
- .user_id;
- let org = db.create_org("org", "org").await.unwrap();
- let channel = db.create_org_channel(org, "channel").await.unwrap();
+ let test_db = TestDb::new(build_background_executor()).await;
+ let db = test_db.db();
+ let user = db
+ .create_user(
+ "user@example.com",
+ false,
+ NewUserParams {
+ github_login: "user".into(),
+ github_user_id: 1,
+ invite_count: 0,
+ },
+ )
+ .await
+ .unwrap()
+ .user_id;
+ let org = db.create_org("org", "org").await.unwrap();
+ let channel = db.create_org_channel(org, "channel").await.unwrap();
- let msg1_id = db
- .create_channel_message(channel, user, "1", OffsetDateTime::now_utc(), 1)
- .await
- .unwrap();
- let msg2_id = db
- .create_channel_message(channel, user, "2", OffsetDateTime::now_utc(), 2)
- .await
- .unwrap();
- let msg3_id = db
- .create_channel_message(channel, user, "3", OffsetDateTime::now_utc(), 1)
- .await
- .unwrap();
- let msg4_id = db
- .create_channel_message(channel, user, "4", OffsetDateTime::now_utc(), 2)
- .await
- .unwrap();
+ let msg1_id = db
+ .create_channel_message(channel, user, "1", OffsetDateTime::now_utc(), 1)
+ .await
+ .unwrap();
+ let msg2_id = db
+ .create_channel_message(channel, user, "2", OffsetDateTime::now_utc(), 2)
+ .await
+ .unwrap();
+ let msg3_id = db
+ .create_channel_message(channel, user, "3", OffsetDateTime::now_utc(), 1)
+ .await
+ .unwrap();
+ let msg4_id = db
+ .create_channel_message(channel, user, "4", OffsetDateTime::now_utc(), 2)
+ .await
+ .unwrap();
- assert_ne!(msg1_id, msg2_id);
- assert_eq!(msg1_id, msg3_id);
- assert_eq!(msg2_id, msg4_id);
- }
+ assert_ne!(msg1_id, msg2_id);
+ assert_eq!(msg1_id, msg3_id);
+ assert_eq!(msg2_id, msg4_id);
}
#[tokio::test(flavor = "multi_thread")]
async fn test_create_access_tokens() {
- let test_db = TestDb::real().await;
+ let test_db = TestDb::new(build_background_executor()).await;
let db = test_db.db();
let user = db
.create_user(
@@ -582,14 +566,14 @@ async fn test_create_access_tokens() {
#[test]
fn test_fuzzy_like_string() {
- assert_eq!(RealDb::fuzzy_like_string("abcd"), "%a%b%c%d%");
- assert_eq!(RealDb::fuzzy_like_string("x y"), "%x%y%");
- assert_eq!(RealDb::fuzzy_like_string(" z "), "%z%");
+ assert_eq!(DefaultDb::fuzzy_like_string("abcd"), "%a%b%c%d%");
+ assert_eq!(DefaultDb::fuzzy_like_string("x y"), "%x%y%");
+ assert_eq!(DefaultDb::fuzzy_like_string(" z "), "%z%");
}
#[tokio::test(flavor = "multi_thread")]
async fn test_fuzzy_search_users() {
- let test_db = TestDb::real().await;
+ let test_db = TestDb::new(build_background_executor()).await;
let db = test_db.db();
for (i, github_login) in [
"California",
@@ -625,7 +609,7 @@ async fn test_fuzzy_search_users() {
&["rhode-island", "colorado", "oregon"],
);
- async fn fuzzy_search_user_names(db: &Arc<TestDb>, query: &str) -> Vec<String> {
+ async fn fuzzy_search_user_names(db: &DefaultDb, query: &str) -> Vec<String> {
db.fuzzy_search_users(query, 10)
.await
.unwrap()
@@ -637,176 +621,172 @@ async fn test_fuzzy_search_users() {
#[tokio::test(flavor = "multi_thread")]
async fn test_add_contacts() {
- for test_db in [
- TestDb::real().await,
- TestDb::fake(build_background_executor()),
- ] {
- let db = test_db.db();
-
- let mut user_ids = Vec::new();
- for i in 0..3 {
- user_ids.push(
- db.create_user(
- &format!("user{i}@example.com"),
- false,
- NewUserParams {
- github_login: format!("user{i}"),
- github_user_id: i,
- invite_count: 0,
- },
- )
- .await
- .unwrap()
- .user_id,
- );
- }
+ let test_db = TestDb::new(build_background_executor()).await;
+ let db = test_db.db();
- let user_1 = user_ids[0];
- let user_2 = user_ids[1];
- let user_3 = user_ids[2];
+ let mut user_ids = Vec::new();
+ for i in 0..3 {
+ user_ids.push(
+ db.create_user(
+ &format!("user{i}@example.com"),
+ false,
+ NewUserParams {
+ github_login: format!("user{i}"),
+ github_user_id: i,
+ invite_count: 0,
+ },
+ )
+ .await
+ .unwrap()
+ .user_id,
+ );
+ }
- // User starts with no contacts
- assert_eq!(db.get_contacts(user_1).await.unwrap(), &[]);
+ let user_1 = user_ids[0];
+ let user_2 = user_ids[1];
+ let user_3 = user_ids[2];
- // User requests a contact. Both users see the pending request.
- db.send_contact_request(user_1, user_2).await.unwrap();
- assert!(!db.has_contact(user_1, user_2).await.unwrap());
- assert!(!db.has_contact(user_2, user_1).await.unwrap());
- assert_eq!(
- db.get_contacts(user_1).await.unwrap(),
- &[Contact::Outgoing { user_id: user_2 }],
- );
- assert_eq!(
- db.get_contacts(user_2).await.unwrap(),
- &[Contact::Incoming {
- user_id: user_1,
- should_notify: true
- }]
- );
+ // User starts with no contacts
+ assert_eq!(db.get_contacts(user_1).await.unwrap(), &[]);
- // User 2 dismisses the contact request notification without accepting or rejecting.
- // We shouldn't notify them again.
- db.dismiss_contact_notification(user_1, user_2)
- .await
- .unwrap_err();
- db.dismiss_contact_notification(user_2, user_1)
- .await
- .unwrap();
- assert_eq!(
- db.get_contacts(user_2).await.unwrap(),
- &[Contact::Incoming {
- user_id: user_1,
- should_notify: false
- }]
- );
+ // User requests a contact. Both users see the pending request.
+ db.send_contact_request(user_1, user_2).await.unwrap();
+ assert!(!db.has_contact(user_1, user_2).await.unwrap());
+ assert!(!db.has_contact(user_2, user_1).await.unwrap());
+ assert_eq!(
+ db.get_contacts(user_1).await.unwrap(),
+ &[Contact::Outgoing { user_id: user_2 }],
+ );
+ assert_eq!(
+ db.get_contacts(user_2).await.unwrap(),
+ &[Contact::Incoming {
+ user_id: user_1,
+ should_notify: true
+ }]
+ );
- // User can't accept their own contact request
- db.respond_to_contact_request(user_1, user_2, true)
- .await
- .unwrap_err();
+ // User 2 dismisses the contact request notification without accepting or rejecting.
+ // We shouldn't notify them again.
+ db.dismiss_contact_notification(user_1, user_2)
+ .await
+ .unwrap_err();
+ db.dismiss_contact_notification(user_2, user_1)
+ .await
+ .unwrap();
+ assert_eq!(
+ db.get_contacts(user_2).await.unwrap(),
+ &[Contact::Incoming {
+ user_id: user_1,
+ should_notify: false
+ }]
+ );
- // User accepts a contact request. Both users see the contact.
- db.respond_to_contact_request(user_2, user_1, true)
- .await
- .unwrap();
- assert_eq!(
- db.get_contacts(user_1).await.unwrap(),
- &[Contact::Accepted {
- user_id: user_2,
- should_notify: true
- }],
- );
- assert!(db.has_contact(user_1, user_2).await.unwrap());
- assert!(db.has_contact(user_2, user_1).await.unwrap());
- assert_eq!(
- db.get_contacts(user_2).await.unwrap(),
- &[Contact::Accepted {
- user_id: user_1,
- should_notify: false,
- }]
- );
+ // User can't accept their own contact request
+ db.respond_to_contact_request(user_1, user_2, true)
+ .await
+ .unwrap_err();
- // Users cannot re-request existing contacts.
- db.send_contact_request(user_1, user_2).await.unwrap_err();
- db.send_contact_request(user_2, user_1).await.unwrap_err();
+ // User accepts a contact request. Both users see the contact.
+ db.respond_to_contact_request(user_2, user_1, true)
+ .await
+ .unwrap();
+ assert_eq!(
+ db.get_contacts(user_1).await.unwrap(),
+ &[Contact::Accepted {
+ user_id: user_2,
+ should_notify: true
+ }],
+ );
+ assert!(db.has_contact(user_1, user_2).await.unwrap());
+ assert!(db.has_contact(user_2, user_1).await.unwrap());
+ assert_eq!(
+ db.get_contacts(user_2).await.unwrap(),
+ &[Contact::Accepted {
+ user_id: user_1,
+ should_notify: false,
+ }]
+ );
- // Users can't dismiss notifications of them accepting other users' requests.
- db.dismiss_contact_notification(user_2, user_1)
- .await
- .unwrap_err();
- assert_eq!(
- db.get_contacts(user_1).await.unwrap(),
- &[Contact::Accepted {
- user_id: user_2,
- should_notify: true,
- }]
- );
+ // Users cannot re-request existing contacts.
+ db.send_contact_request(user_1, user_2).await.unwrap_err();
+ db.send_contact_request(user_2, user_1).await.unwrap_err();
- // Users can dismiss notifications of other users accepting their requests.
- db.dismiss_contact_notification(user_1, user_2)
- .await
- .unwrap();
- assert_eq!(
- db.get_contacts(user_1).await.unwrap(),
- &[Contact::Accepted {
+ // Users can't dismiss notifications of them accepting other users' requests.
+ db.dismiss_contact_notification(user_2, user_1)
+ .await
+ .unwrap_err();
+ assert_eq!(
+ db.get_contacts(user_1).await.unwrap(),
+ &[Contact::Accepted {
+ user_id: user_2,
+ should_notify: true,
+ }]
+ );
+
+ // Users can dismiss notifications of other users accepting their requests.
+ db.dismiss_contact_notification(user_1, user_2)
+ .await
+ .unwrap();
+ assert_eq!(
+ db.get_contacts(user_1).await.unwrap(),
+ &[Contact::Accepted {
+ user_id: user_2,
+ should_notify: false,
+ }]
+ );
+
+ // Users send each other concurrent contact requests and
+ // see that they are immediately accepted.
+ db.send_contact_request(user_1, user_3).await.unwrap();
+ db.send_contact_request(user_3, user_1).await.unwrap();
+ assert_eq!(
+ db.get_contacts(user_1).await.unwrap(),
+ &[
+ Contact::Accepted {
user_id: user_2,
should_notify: false,
- }]
- );
-
- // Users send each other concurrent contact requests and
- // see that they are immediately accepted.
- db.send_contact_request(user_1, user_3).await.unwrap();
- db.send_contact_request(user_3, user_1).await.unwrap();
- assert_eq!(
- db.get_contacts(user_1).await.unwrap(),
- &[
- Contact::Accepted {
- user_id: user_2,
- should_notify: false,
- },
- Contact::Accepted {
- user_id: user_3,
- should_notify: false
- }
- ]
- );
- assert_eq!(
- db.get_contacts(user_3).await.unwrap(),
- &[Contact::Accepted {
- user_id: user_1,
+ },
+ Contact::Accepted {
+ user_id: user_3,
should_notify: false
- }],
- );
+ }
+ ]
+ );
+ assert_eq!(
+ db.get_contacts(user_3).await.unwrap(),
+ &[Contact::Accepted {
+ user_id: user_1,
+ should_notify: false
+ }],
+ );
- // User declines a contact request. Both users see that it is gone.
- db.send_contact_request(user_2, user_3).await.unwrap();
- db.respond_to_contact_request(user_3, user_2, false)
- .await
- .unwrap();
- assert!(!db.has_contact(user_2, user_3).await.unwrap());
- assert!(!db.has_contact(user_3, user_2).await.unwrap());
- assert_eq!(
- db.get_contacts(user_2).await.unwrap(),
- &[Contact::Accepted {
- user_id: user_1,
- should_notify: false
- }]
- );
- assert_eq!(
- db.get_contacts(user_3).await.unwrap(),
- &[Contact::Accepted {
- user_id: user_1,
- should_notify: false
- }],
- );
- }
+ // User declines a contact request. Both users see that it is gone.
+ db.send_contact_request(user_2, user_3).await.unwrap();
+ db.respond_to_contact_request(user_3, user_2, false)
+ .await
+ .unwrap();
+ assert!(!db.has_contact(user_2, user_3).await.unwrap());
+ assert!(!db.has_contact(user_3, user_2).await.unwrap());
+ assert_eq!(
+ db.get_contacts(user_2).await.unwrap(),
+ &[Contact::Accepted {
+ user_id: user_1,
+ should_notify: false
+ }]
+ );
+ assert_eq!(
+ db.get_contacts(user_3).await.unwrap(),
+ &[Contact::Accepted {
+ user_id: user_1,
+ should_notify: false
+ }],
+ );
}
#[tokio::test(flavor = "multi_thread")]
async fn test_invite_codes() {
- let postgres = TestDb::real().await;
- let db = postgres.db();
+ let test_db = TestDb::new(build_background_executor()).await;
+ let db = test_db.db();
let NewUserResult { user_id: user1, .. } = db
.create_user(
"user1@example.com",
@@ -1000,8 +980,8 @@ async fn test_invite_codes() {
#[tokio::test(flavor = "multi_thread")]
async fn test_signups() {
- let postgres = TestDb::real().await;
- let db = postgres.db();
+ let test_db = TestDb::new(build_background_executor()).await;
+ let db = test_db.db();
// people sign up on the waitlist
for i in 0..8 {
@@ -1146,8 +1126,8 @@ async fn test_signups() {
#[tokio::test(flavor = "multi_thread")]
async fn test_metrics_id() {
- let postgres = TestDb::real().await;
- let db = postgres.db();
+ let test_db = TestDb::new(build_background_executor()).await;
+ let db = test_db.db();
let NewUserResult {
user_id: user1,