0

I am looking to test my /signup endpoint of my application. This endpoint will fail if an email already exists. My test gets a success the first time, but after that it fails. Indicating that the database is saving the response. Below is my code:

#[macro_use] extern crate rocket;
use sqlx::mysql::MySqlPool;
use rocket::serde::{json::Json};
use rocket::response::status;
use rocket::http::Status;
use crate::schemas::Signup;

pub mod schemas;

#[cfg(test)] mod tests;


#[post("/signup", format = "application/json", data="<task>")]
async fn signup(pool: &rocket::State<MySqlPool>, task: Json<Signup<'_>>) -> status::Custom<String> {
    println!("New user. Username: {}, Password: {}", task.email, task.password);
    match sqlx::query("INSERT INTO user(email, username, password) VALUES (?, ?, ?)")
        .bind(task.email)
        .bind(task.username)
        .bind(task.password)
        .execute(&**pool)
        .await {
            Err(_) => status::Custom(Status::BadRequest, "Could not add user to database".to_string()),
            Ok(_) => status::Custom(Status::Accepted,"Successfully created a new account.".to_string()),
        }
}

#[launch]
async fn rocket() -> _ {
    let database_url = "mysql://root:root@localhost:3306/dynamicapi?charset=utf8mb4";
    let pool = MySqlPool::connect(database_url)
        .await
        .expect("Failed to connect to database");

    rocket::build()
       .mount("/", routes![signup])
       .manage::<MySqlPool>(pool)
}

#[cfg(test)]
mod test {
    use rocket::http::ContentType;
    use rocket::local::asynchronous::Client;

    async fn get_client() -> Client {
                Client::tracked(super::rocket().await).await
                                        .expect("valid `Rocket`")

    }

    // #[rocket::async_test]
        #[sqlx::test]
    async fn signup_post() {
        let client = get_client().await;
        let response = client.post("/signup")
            .header(ContentType::JSON)
                        .body(r##"{
                                "email": "j.doe@m.com",
                                "username": "bigjose400",
                                "password": "123456"
                        }"##)
            .dispatch().await;
        assert_eq!(response.status().code, 202);
    }
}

I tried using the documentation for sqlx_test, however; this does not seem to be working. How can I integrate a temporary database that resets after each test?

Update: I now understand that I need to call the test like this to get the test database:

        #[sqlx::test]
    async fn signup_post(pool: MySqlPool) {

However, now my issue is getting this test database pool into the state of rocket.

Colin99d
  • 3
  • 1
  • 4

2 Answers2

0

For now I fixed this by using if cfg!(test) to see if the program is being run in test mode. If so I change database_url to be that of my test database, and then I call a function to drop all rows from any tables changed by each test.

Colin99d
  • 3
  • 1
  • 4
0

checkout this blogpost. The trick is to use async fn(PoolOptions<DB>, impl ConnectOptions<DB>) -> Ret to get the connection details instead of the connection itself, and use those details to create a custom figment and pass it to a new rocket instance.

madoke
  • 873
  • 11
  • 25