Created
August 23, 2019 00:36
-
-
Save SnoozeTime/b6c671f609df10a5f2441227a73a95e8 to your computer and use it in GitHub Desktop.
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
use diesel::pg::PgConnection; | |
use diesel::prelude::*; | |
use diesel_migrations::embed_migrations; | |
use std::default::Default; | |
use actix_web::dev::Server; | |
use mycrate::app; | |
use mycrate::app::AppConfig; | |
use std::sync::mpsc; | |
use std::thread; | |
embed_migrations!(); | |
pub struct TestContext { | |
db_name: String, | |
base_url: String, | |
} | |
impl Drop for TestContext { | |
/// Drop will delete the database for the current test. | |
fn drop(&mut self) { | |
let postgres_url = format!("{}/postgres", self.base_url); | |
let conn = | |
PgConnection::establish(&postgres_url).expect("Cannot connect to postgres database."); | |
let revoke = format!("REVOKE CONNECT ON DATABASE {} FROM public;", self.db_name); | |
diesel::sql_query(revoke.as_str()).execute(&conn).unwrap(); | |
let disconnect_users = format!( | |
"SELECT pg_terminate_backend(pid) | |
FROM pg_stat_activity | |
WHERE datname = '{}';", | |
self.db_name | |
); | |
diesel::sql_query(disconnect_users.as_str()) | |
.execute(&conn) | |
.unwrap(); | |
let query = diesel::sql_query(format!("DROP DATABASE {}", self.db_name).as_str()); | |
query | |
.execute(&conn) | |
.expect(&format!("Couldn't drop database {}", self.db_name)); | |
} | |
} | |
impl TestContext { | |
/// Creates new test context for my local db :) | |
pub fn local(db_name: &str) -> Self { | |
TestContext::new("postgres://postgres:example@127.0.0.1", db_name) | |
} | |
/// Will set up a database for a test. | |
/// This will return a TestContext that will tear down the | |
/// database once the test is over. | |
pub fn new(base_url: &str, db_name: &str) -> Self { | |
// First, connect to postgres db to be able to create our test | |
// database. | |
let postgres_url = format!("{}/postgres", base_url); | |
let conn = | |
PgConnection::establish(&postgres_url).expect("Cannot connect to postgres database."); | |
// Create a new database for the test | |
let query = diesel::sql_query(format!("CREATE DATABASE {}", db_name).as_str()); | |
query | |
.execute(&conn) | |
.expect(format!("Could not create database {}", db_name).as_str()); | |
// Now we can connect to the database and run the migrations | |
let conn = PgConnection::establish(&format!("{}/{}", base_url, db_name)) | |
.expect(&format!("Cannot connect to {} database", db_name)); | |
embedded_migrations::run(&conn); | |
let ctx = TestContext { | |
db_name: db_name.to_string(), | |
base_url: base_url.to_string(), | |
}; | |
ctx | |
} | |
} | |
pub fn get_conn(ctx: &TestContext) -> PgConnection { | |
let database_url = format!("{}/{}", ctx.base_url, ctx.db_name); | |
let conn = | |
PgConnection::establish(&database_url).expect("Cannot establish connection with database"); | |
conn | |
} | |
use std::net::{Ipv4Addr, SocketAddrV4, TcpListener}; | |
/// Utility method to find a port available for testing. | |
/// | |
/// Would it work with multiple threads for testing? | |
/// or race condition? | |
fn find_free_port() -> u16 { | |
let loopback = Ipv4Addr::new(127, 0, 0, 1); | |
// 0 to ask the OS for a free port. | |
let socket = SocketAddrV4::new(loopback, 0); | |
let listener = TcpListener::bind(socket).unwrap(); | |
let port = listener.local_addr().unwrap().port(); | |
port | |
} | |
pub fn start_server(db_name: &str) -> (Server, u16) { | |
let port = find_free_port(); | |
let mut app_config = AppConfig::default(); | |
app_config.port = port; | |
let (tx, rx) = mpsc::channel(); | |
let database_url = format!("postgres://postgres:example@127.0.0.1/{}", db_name); | |
app_config.database_url = database_url; | |
app_config.secure = false; | |
app_config.enable_csrf = false; | |
// First, start the server | |
thread::spawn(move || { | |
let sys = actix_rt::System::new(""); | |
let server: Server = app::create_server(app_config); | |
// send the address so that we can stop! | |
tx.send(server.clone()).unwrap(); | |
sys.run(); | |
println!("Finished running"); | |
}); | |
(rx.recv().unwrap(), port) | |
} | |
pub fn get_url(port: u16, endpoint: &str) -> String { | |
format!("http://localhost:{}/{}", port, endpoint) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment