-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1892 from Kobzol/db-tests
Add simple test infrastructure for testing DB queries
- Loading branch information
Showing
8 changed files
with
190 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#[cfg(test)] | ||
mod tests { | ||
use crate::handlers::assign::filter_by_capacity; | ||
use crate::tests::run_test; | ||
use std::collections::HashSet; | ||
|
||
#[tokio::test] | ||
async fn find_reviewers_no_review_prefs() { | ||
run_test(|ctx| async move { | ||
ctx.add_user("usr1", 1).await; | ||
ctx.add_user("usr2", 1).await; | ||
let _users = | ||
filter_by_capacity(ctx.db_client(), &candidates(&["usr1", "usr2"])).await?; | ||
// FIXME: this test fails, because the query is wrong | ||
// check_users(users, &["usr1", "usr2"]); | ||
Ok(ctx) | ||
}) | ||
.await; | ||
} | ||
|
||
fn candidates(users: &[&'static str]) -> HashSet<&'static str> { | ||
users.into_iter().copied().collect() | ||
} | ||
|
||
fn check_users(users: HashSet<String>, expected: &[&'static str]) { | ||
let mut users: Vec<String> = users.into_iter().collect(); | ||
users.sort(); | ||
assert_eq!(users, expected); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
use crate::db; | ||
use crate::db::make_client; | ||
use crate::db::notifications::record_username; | ||
use std::future::Future; | ||
use tokio_postgres::Config; | ||
|
||
/// Represents a connection to a Postgres database that can be | ||
/// used in integration tests to test logic that interacts with | ||
/// a database. | ||
pub struct TestContext { | ||
client: tokio_postgres::Client, | ||
db_name: String, | ||
original_db_url: String, | ||
conn_handle: tokio::task::JoinHandle<()>, | ||
} | ||
|
||
impl TestContext { | ||
async fn new(db_url: &str) -> Self { | ||
let mut config: Config = db_url.parse().expect("Cannot parse connection string"); | ||
|
||
// Create a new database that will be used for this specific test | ||
let client = make_client(&db_url) | ||
.await | ||
.expect("Cannot connect to database"); | ||
let db_name = format!("db{}", uuid::Uuid::new_v4().to_string().replace("-", "")); | ||
client | ||
.execute(&format!("CREATE DATABASE {db_name}"), &[]) | ||
.await | ||
.expect("Cannot create database"); | ||
drop(client); | ||
|
||
// We need to connect to the database against, because Postgres doesn't allow | ||
// changing the active database mid-connection. | ||
config.dbname(&db_name); | ||
let (mut client, connection) = config | ||
.connect(tokio_postgres::NoTls) | ||
.await | ||
.expect("Cannot connect to the newly created database"); | ||
let conn_handle = tokio::spawn(async move { | ||
connection.await.unwrap(); | ||
}); | ||
|
||
db::run_migrations(&mut client) | ||
.await | ||
.expect("Cannot run database migrations"); | ||
Self { | ||
client, | ||
db_name, | ||
original_db_url: db_url.to_string(), | ||
conn_handle, | ||
} | ||
} | ||
|
||
pub fn db_client(&self) -> &tokio_postgres::Client { | ||
&self.client | ||
} | ||
|
||
pub async fn add_user(&self, name: &str, id: u64) { | ||
record_username(&self.client, id, name) | ||
.await | ||
.expect("Cannot create user"); | ||
} | ||
|
||
async fn finish(self) { | ||
// Cleanup the test database | ||
// First, we need to stop using the database | ||
drop(self.client); | ||
self.conn_handle.await.unwrap(); | ||
|
||
// Then we need to connect to the default database and drop our test DB | ||
let client = make_client(&self.original_db_url) | ||
.await | ||
.expect("Cannot connect to database"); | ||
client | ||
.execute(&format!("DROP DATABASE {}", self.db_name), &[]) | ||
.await | ||
.unwrap(); | ||
} | ||
} | ||
|
||
pub async fn run_test<F, Fut>(f: F) | ||
where | ||
F: FnOnce(TestContext) -> Fut, | ||
Fut: Future<Output = anyhow::Result<TestContext>>, | ||
{ | ||
if let Ok(db_url) = std::env::var("TEST_DB_URL") { | ||
let ctx = TestContext::new(&db_url).await; | ||
let ctx = f(ctx).await.expect("Test failed"); | ||
ctx.finish().await; | ||
} else { | ||
eprintln!("Skipping test because TEST_DB_URL was not passed"); | ||
} | ||
} |