2017-05-26 23:44:53 +00:00
|
|
|
extern crate parking_lot;
|
|
|
|
extern crate rand;
|
|
|
|
|
|
|
|
use super::task::Task;
|
|
|
|
use self::parking_lot::Mutex;
|
2018-07-25 15:01:29 +00:00
|
|
|
use self::rand::{Rng, thread_rng, distributions::Alphanumeric};
|
2017-05-26 23:44:53 +00:00
|
|
|
|
2017-06-06 20:41:04 +00:00
|
|
|
use rocket::local::Client;
|
2017-05-26 23:44:53 +00:00
|
|
|
use rocket::http::{Status, ContentType};
|
|
|
|
|
|
|
|
// We use a lock to synchronize between tests so DB operations don't collide.
|
|
|
|
// For now. In the future, we'll have a nice way to run each test in a DB
|
|
|
|
// transaction so we can regain concurrency.
|
|
|
|
static DB_LOCK: Mutex<()> = Mutex::new(());
|
|
|
|
|
|
|
|
macro_rules! run_test {
|
2017-06-06 20:41:04 +00:00
|
|
|
(|$client:ident, $conn:ident| $block:expr) => ({
|
2017-05-26 23:44:53 +00:00
|
|
|
let _lock = DB_LOCK.lock();
|
2018-12-30 21:52:08 +00:00
|
|
|
let rocket = super::rocket();
|
|
|
|
let db = super::DbConn::get_one(&rocket);
|
2017-06-06 20:41:04 +00:00
|
|
|
let $client = Client::new(rocket).expect("Rocket client");
|
2017-05-26 23:44:53 +00:00
|
|
|
let $conn = db.expect("failed to get database connection for testing");
|
2018-12-30 21:52:08 +00:00
|
|
|
assert!(Task::delete_all(&$conn), "failed to delete all tasks for testing");
|
|
|
|
|
2017-05-26 23:44:53 +00:00
|
|
|
$block
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_insertion_deletion() {
|
2017-06-06 20:41:04 +00:00
|
|
|
run_test!(|client, conn| {
|
2017-05-26 23:44:53 +00:00
|
|
|
// Get the tasks before making changes.
|
|
|
|
let init_tasks = Task::all(&conn);
|
|
|
|
|
|
|
|
// Issue a request to insert a new task.
|
2017-06-06 20:41:04 +00:00
|
|
|
client.post("/todo")
|
2017-05-26 23:44:53 +00:00
|
|
|
.header(ContentType::Form)
|
2017-06-06 20:41:04 +00:00
|
|
|
.body("description=My+first+task")
|
|
|
|
.dispatch();
|
2017-05-26 23:44:53 +00:00
|
|
|
|
|
|
|
// Ensure we have one more task in the database.
|
|
|
|
let new_tasks = Task::all(&conn);
|
|
|
|
assert_eq!(new_tasks.len(), init_tasks.len() + 1);
|
|
|
|
|
|
|
|
// Ensure the task is what we expect.
|
|
|
|
assert_eq!(new_tasks[0].description, "My first task");
|
|
|
|
assert_eq!(new_tasks[0].completed, false);
|
|
|
|
|
|
|
|
// Issue a request to delete the task.
|
|
|
|
let id = new_tasks[0].id.unwrap();
|
2017-06-06 20:41:04 +00:00
|
|
|
client.delete(format!("/todo/{}", id)).dispatch();
|
2017-05-26 23:44:53 +00:00
|
|
|
|
|
|
|
// Ensure it's gone.
|
|
|
|
let final_tasks = Task::all(&conn);
|
|
|
|
assert_eq!(final_tasks.len(), init_tasks.len());
|
2017-05-27 00:12:57 +00:00
|
|
|
if final_tasks.len() > 0 {
|
|
|
|
assert_ne!(final_tasks[0].description, "My first task");
|
|
|
|
}
|
2017-05-26 23:44:53 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_toggle() {
|
2017-06-06 20:41:04 +00:00
|
|
|
run_test!(|client, conn| {
|
2017-05-26 23:44:53 +00:00
|
|
|
// Issue a request to insert a new task; ensure it's not yet completed.
|
2017-06-06 20:41:04 +00:00
|
|
|
client.post("/todo")
|
2017-05-26 23:44:53 +00:00
|
|
|
.header(ContentType::Form)
|
2017-06-06 20:41:04 +00:00
|
|
|
.body("description=test_for_completion")
|
|
|
|
.dispatch();
|
2017-05-26 23:44:53 +00:00
|
|
|
|
|
|
|
let task = Task::all(&conn)[0].clone();
|
|
|
|
assert_eq!(task.completed, false);
|
|
|
|
|
|
|
|
// Issue a request to toggle the task; ensure it is completed.
|
2017-06-06 20:41:04 +00:00
|
|
|
client.put(format!("/todo/{}", task.id.unwrap())).dispatch();
|
2017-05-26 23:44:53 +00:00
|
|
|
assert_eq!(Task::all(&conn)[0].completed, true);
|
|
|
|
|
|
|
|
// Issue a request to toggle the task; ensure it's not completed again.
|
2017-06-06 20:41:04 +00:00
|
|
|
client.put(format!("/todo/{}", task.id.unwrap())).dispatch();
|
2017-05-26 23:44:53 +00:00
|
|
|
assert_eq!(Task::all(&conn)[0].completed, false);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_many_insertions() {
|
|
|
|
const ITER: usize = 100;
|
|
|
|
|
|
|
|
let mut rng = thread_rng();
|
2017-06-06 20:41:04 +00:00
|
|
|
run_test!(|client, conn| {
|
2017-05-26 23:44:53 +00:00
|
|
|
// Get the number of tasks initially.
|
|
|
|
let init_num = Task::all(&conn).len();
|
|
|
|
let mut descs = Vec::new();
|
|
|
|
|
|
|
|
for i in 0..ITER {
|
|
|
|
// Issue a request to insert a new task with a random description.
|
2018-07-25 15:01:29 +00:00
|
|
|
let desc: String = rng.sample_iter(&Alphanumeric).take(12).collect();
|
2017-06-06 20:41:04 +00:00
|
|
|
client.post("/todo")
|
2017-05-26 23:44:53 +00:00
|
|
|
.header(ContentType::Form)
|
2017-06-06 20:41:04 +00:00
|
|
|
.body(format!("description={}", desc))
|
|
|
|
.dispatch();
|
2017-05-26 23:44:53 +00:00
|
|
|
|
|
|
|
// Record the description we choose for this iteration.
|
|
|
|
descs.insert(0, desc);
|
|
|
|
|
|
|
|
// Ensure the task was inserted properly and all other tasks remain.
|
|
|
|
let tasks = Task::all(&conn);
|
|
|
|
assert_eq!(tasks.len(), init_num + i + 1);
|
|
|
|
|
|
|
|
for j in 0..i {
|
|
|
|
assert_eq!(descs[j], tasks[j].description);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bad_form_submissions() {
|
2017-06-06 20:41:04 +00:00
|
|
|
run_test!(|client, _conn| {
|
2017-05-26 23:44:53 +00:00
|
|
|
// Submit an empty form. We should get a 422 but no flash error.
|
2017-06-06 20:41:04 +00:00
|
|
|
let res = client.post("/todo")
|
|
|
|
.header(ContentType::Form)
|
|
|
|
.dispatch();
|
|
|
|
|
2017-05-26 23:44:53 +00:00
|
|
|
let mut cookies = res.headers().get("Set-Cookie");
|
2017-06-06 20:41:04 +00:00
|
|
|
assert_eq!(res.status(), Status::UnprocessableEntity);
|
2017-05-26 23:44:53 +00:00
|
|
|
assert!(!cookies.any(|value| value.contains("error")));
|
|
|
|
|
2017-06-06 20:41:04 +00:00
|
|
|
// Submit a form with an empty description. We look for 'error' in the
|
|
|
|
// cookies which corresponds to flash message being set as an error.
|
|
|
|
let res = client.post("/todo")
|
2017-05-26 23:44:53 +00:00
|
|
|
.header(ContentType::Form)
|
2017-06-06 20:41:04 +00:00
|
|
|
.body("description=")
|
|
|
|
.dispatch();
|
2017-05-26 23:44:53 +00:00
|
|
|
|
|
|
|
let mut cookies = res.headers().get("Set-Cookie");
|
|
|
|
assert!(cookies.any(|value| value.contains("error")));
|
|
|
|
|
|
|
|
// Submit a form without a description. Expect a 422 but no flash error.
|
2017-06-06 20:41:04 +00:00
|
|
|
let res = client.post("/todo")
|
2017-05-26 23:44:53 +00:00
|
|
|
.header(ContentType::Form)
|
2017-06-06 20:41:04 +00:00
|
|
|
.body("evil=smile")
|
|
|
|
.dispatch();
|
|
|
|
|
2017-05-26 23:44:53 +00:00
|
|
|
let mut cookies = res.headers().get("Set-Cookie");
|
2017-06-06 20:41:04 +00:00
|
|
|
assert_eq!(res.status(), Status::UnprocessableEntity);
|
2017-05-26 23:44:53 +00:00
|
|
|
assert!(!cookies.any(|value| value.contains("error")));
|
|
|
|
})
|
|
|
|
}
|