use bsql::Pool;
fn pool() -> Pool {
Pool::connect("postgres://bsql:bsql@localhost/bsql_test")
.expect("Failed to connect to test database. Is PostgreSQL running?")
}
#[test]
fn singleflight_fetch_one_works() {
let pool = pool();
let id = 1i32;
let user = bsql::query!("SELECT id, login FROM users WHERE id = $id: i32")
.fetch_one(&pool)
.unwrap();
let r = user.get().unwrap();
assert_eq!(r.id, 1);
assert_eq!(r.login, "alice");
}
#[test]
fn singleflight_fetch_all_works() {
let pool = pool();
let users = bsql::query!("SELECT id, login FROM users ORDER BY id")
.fetch_all(&pool)
.unwrap();
assert!(users.len() >= 2);
assert_eq!(users[0].login, "alice");
}
#[test]
fn concurrent_identical_queries_all_succeed() {
use std::sync::Arc;
let pool = Arc::new(pool());
let mut handles = Vec::new();
for _ in 0..10 {
let pool = Arc::clone(&pool);
handles.push(std::thread::spawn(move || {
bsql::query!("SELECT id, login FROM users ORDER BY id").fetch_all(pool.as_ref())
}));
}
for handle in handles {
let users = handle.join().expect("thread panicked").unwrap();
assert!(users.len() >= 2);
assert_eq!(users[0].login, "alice");
}
}
#[test]
fn parameterized_query_works_with_singleflight() {
let pool = pool();
let id = 1i32;
let user = bsql::query!("SELECT id, login FROM users WHERE id = $id: i32")
.fetch_one(&pool)
.unwrap();
assert_eq!(user.get().unwrap().id, 1);
let id = 2i32;
let user = bsql::query!("SELECT id, login FROM users WHERE id = $id: i32")
.fetch_one(&pool)
.unwrap();
assert_eq!(user.get().unwrap().id, 2);
}
#[test]
fn transaction_queries_are_not_coalesced() {
let pool = pool();
let txn = pool.begin().unwrap();
let users = bsql::query!("SELECT id, login FROM users ORDER BY id")
.fetch_all(&txn)
.unwrap();
assert!(users.len() >= 2);
txn.rollback().unwrap();
}
#[test]
fn pool_connection_queries_not_coalesced() {
let pool = pool();
let conn = pool.acquire().unwrap();
let users = bsql::query!("SELECT id, login FROM users ORDER BY id")
.fetch_all(&conn)
.unwrap();
assert!(users.len() >= 2);
}
#[test]
fn execute_not_affected_by_singleflight() {
let pool = pool();
let desc = "singleflight-test-desc";
let id = 1i32;
let affected = bsql::query!("UPDATE tickets SET description = $desc: &str WHERE id = $id: i32")
.execute(&pool)
.unwrap();
assert_eq!(affected, 1);
}
#[test]
fn queries_work_after_concurrent_burst() {
use std::sync::Arc;
let pool = Arc::new(pool());
let mut handles = Vec::new();
for _ in 0..20 {
let pool = Arc::clone(&pool);
handles.push(std::thread::spawn(move || {
bsql::query!("SELECT id, login FROM users ORDER BY id").fetch_all(pool.as_ref())
}));
}
for handle in handles {
let result = handle.join().expect("thread panicked");
if let Ok(users) = &result {
assert!(users.len() >= 2);
}
}
let id = 1i32;
let user = bsql::query!("SELECT id, login FROM users WHERE id = $id: i32")
.fetch_one(pool.as_ref())
.unwrap();
let r = user.get().unwrap();
assert_eq!(r.id, 1);
assert_eq!(r.login, "alice");
}
#[test]
fn singleflight_fetch_optional_works() {
let pool = pool();
let id = 1i32;
let user = bsql::query!("SELECT id, login FROM users WHERE id = $id: i32")
.fetch_optional(&pool)
.unwrap();
assert!(user.is_some());
assert_eq!(user.unwrap().get().unwrap().login, "alice");
}
#[test]
fn different_queries_are_independent() {
use std::sync::Arc;
let pool = Arc::new(pool());
let pool1 = Arc::clone(&pool);
let h1 = std::thread::spawn(move || {
bsql::query!("SELECT id, login FROM users ORDER BY id").fetch_all(pool1.as_ref())
});
let pool2 = Arc::clone(&pool);
let h2 = std::thread::spawn(move || {
bsql::query!("SELECT id FROM tickets ORDER BY id").fetch_all(pool2.as_ref())
});
let users = h1.join().expect("thread panicked").unwrap();
let tickets = h2.join().expect("thread panicked").unwrap();
assert!(users.len() >= 2);
assert!(!tickets.is_empty());
}