diff --git a/lib/examples/rocket/Cargo.toml b/lib/examples/rocket/Cargo.toml index 30514fa3..b7279381 100644 --- a/lib/examples/rocket/Cargo.toml +++ b/lib/examples/rocket/Cargo.toml @@ -7,7 +7,7 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rocket = { version = "0.5.0-rc.2", features = ["json"] } -surrealdb = { path = "../.." ,features = ["kv-mem"]} +rocket = { version = "0.5.0", features = ["json"] } +surrealdb = { path = "../..", features = ["kv-mem"]} serde_json = "1.0" thiserror = "1.0.50" diff --git a/lib/examples/rocket/src/lib.rs b/lib/examples/rocket/src/lib.rs index 4385f6c1..db1857a7 100644 --- a/lib/examples/rocket/src/lib.rs +++ b/lib/examples/rocket/src/lib.rs @@ -1,7 +1,6 @@ mod error; pub mod person; -use rocket::serde::{Deserialize, Serialize}; use rocket::{routes, Build}; use std::env; use surrealdb::engine::any; @@ -10,12 +9,6 @@ use surrealdb::opt::auth::Root; use surrealdb::opt::Config; use surrealdb::Surreal; -#[derive(Serialize, Deserialize)] -#[serde(crate = "rocket::serde")] -pub struct Person { - name: String, -} - pub type Db = Surreal; pub async fn create_db_connection() -> Result> { @@ -36,7 +29,14 @@ pub fn router(db_conn: Surreal) -> rocket::Rocket { rocket::build() .mount( "/", - routes![person::create, person::read, person::update, person::delete, person::list], + routes![ + person::create, + person::read, + person::update, + person::delete, + person::list, + person::delete_all + ], ) .manage(db_conn) } diff --git a/lib/examples/rocket/src/main.rs b/lib/examples/rocket/src/main.rs index f8795ec4..8cfcf059 100644 --- a/lib/examples/rocket/src/main.rs +++ b/lib/examples/rocket/src/main.rs @@ -4,7 +4,7 @@ extern crate rocket; use rocket_example::{create_db_connection, router}; #[launch] -async fn rocket() -> _ { +pub async fn rocket() -> _ { let db_conn = create_db_connection().await.unwrap(); router(db_conn) } diff --git a/lib/examples/rocket/src/person.rs b/lib/examples/rocket/src/person.rs index 63e30ab1..af0caa34 100644 --- a/lib/examples/rocket/src/person.rs +++ b/lib/examples/rocket/src/person.rs @@ -5,10 +5,11 @@ use rocket::serde::{json::Json, Deserialize, Serialize}; use rocket::State; use rocket::{delete, get, post, put}; -#[derive(Deserialize, Serialize)] +#[derive(Deserialize, Serialize, Debug)] #[serde(crate = "rocket::serde")] pub struct Person { - name: String, + // pub id: Option, + pub name: String, } const PERSON: &str = "person"; @@ -35,6 +36,16 @@ pub async fn delete(db: &State, id: String) -> Result>, .map(Json) } +//delete_all +// curl -X DELETE http://localhost:8080/persons +#[delete("/persons")] +pub async fn delete_all(db: &State) -> Result>, Custom> { + db.delete(PERSON) + .await + .map_err(|e| Custom(Status::InternalServerError, e.to_string())) + .map(Json) +} + // curl -X GET http://localhost:8080/person/1 #[get("/person/")] pub async fn read(db: &State, id: String) -> Result>, Custom> { diff --git a/lib/examples/rocket/tests/integration_test.rs b/lib/examples/rocket/tests/integration_test.rs new file mode 100644 index 00000000..d141b16d --- /dev/null +++ b/lib/examples/rocket/tests/integration_test.rs @@ -0,0 +1,130 @@ +use rocket::http::{ContentType, Status}; +use rocket::local::asynchronous::Client; +use rocket_example::create_db_connection; +use rocket_example::person::Person; +use rocket_example::router; + +macro_rules! run_test { + (|$client:ident| $block:expr) => {{ + rocket::async_test(async move { + let db_conn = create_db_connection().await.unwrap(); + let $client = Client::tracked(router(db_conn)).await.unwrap(); + $block + }); + }}; +} + +async fn query_persons(client: &Client) -> Vec { + let response = client.get("/people").dispatch().await; + assert_eq!(response.status(), Status::Ok); + let body = response.into_string().await.unwrap(); + serde_json::from_str(&body).unwrap() +} + +async fn read_person(client: &Client, id: i32) -> Person { + let response = client.get(format!("/person/{}", id)).dispatch().await; + assert_eq!(response.status(), Status::Ok); + let body = response.into_string().await.unwrap(); + serde_json::from_str(&body).unwrap() +} + +async fn update_person(client: &Client, id: i32, new_name: &str) { + let response = client + .put(format!("/person/{}", id)) + .header(ContentType::JSON) + .body(format!(r#"{{"name":"{}"}}"#, new_name)) + .dispatch() + .await; + assert_eq!(response.status(), Status::Ok); +} + +async fn delete_person(client: &Client, id: i32) { + let response = client.delete(format!("/person/{}", id)).dispatch().await; + assert_eq!(response.status(), Status::Ok); +} + +async fn delete_all_persons(client: &Client) { + let response = client.delete("/persons").dispatch().await; + assert_eq!(response.status(), Status::Ok); +} + +#[test] +fn test_read_person() { + run_test!(|client| { + // Insert a person to ensure the database is not empty. + let john_id = 1; + client + .post(format!("/person/{}", john_id)) + .header(ContentType::JSON) + .body(r#"{"name":"John Doe"}"#) + .dispatch() + .await; + + // Read the inserted person's data. + let person_response = client.get(format!("/person/{}", john_id)).dispatch().await; + assert_eq!(person_response.status(), Status::Ok); + let person_data: Option = + serde_json::from_str(&person_response.into_string().await.unwrap()).unwrap(); + + // Verify that the data matches what was inserted. + assert!(person_data.is_some()); + let person = person_data.unwrap(); + assert_eq!(person.name, "John Doe"); + + // Cleanup + delete_person(&client, john_id).await; + }); +} + +#[test] +fn test_update_person() { + run_test!(|client| { + let john_id = 1; + + // Update John Doe to Jane Doe + update_person(&client, john_id, "Jane Doe").await; + + // Verify update + let updated_person = read_person(&client, john_id).await; + assert_eq!(updated_person.name, "Jane Doe"); + + // Cleanup + delete_person(&client, john_id).await; + }); +} + +#[test] +fn test_insertion_deletion() { + run_test!(|client| { + // Get the person before making changes. + let init_persons = query_persons(&client).await; + let john_id = 1; + // Issue a request to insert a new person. + client + .post(format!("/person/{}", john_id)) + .header(ContentType::JSON) + .body(r#"{"name":"John Doe"}"#) + .dispatch() + .await; + + // Ensure we have one more person in the database. + let new_persons = query_persons(&client).await; + assert_eq!(new_persons.len(), init_persons.len() + 1); + + // Ensure the person is what we expect. + let john = &new_persons[0]; + assert_eq!(john.name, "John Doe"); + + // Issue a request to delete the person. + delete_person(&client, john_id).await; + + // Ensure it's gone. + let final_persons = query_persons(&client).await; + assert_eq!(final_persons.len(), init_persons.len()); + if !final_persons.is_empty() { + assert_ne!(final_persons[0].name, "John Doe"); + } + + delete_all_persons(&client).await; + }); +}