mod common;
use axum::{
body::Body,
http::{Request, StatusCode},
};
use tower::ServiceExt; use serde_json::json;
use person_service::{
models::Person,
api::ApiResponse,
};
#[tokio::test]
async fn test_health_check() {
let app = common::create_test_router().await;
let response = app
.oneshot(
Request::builder()
.uri("/api/v1/health")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
.await
.unwrap();
let body_str = String::from_utf8(body.to_vec()).unwrap();
assert!(body_str.contains("healthy"));
assert!(body_str.contains("person-service"));
}
#[tokio::test]
async fn test_create_person() {
let app = common::create_test_router().await;
let family_name = common::unique_person_name("Create");
let person_json = json!({
"id": "00000000-0000-0000-0000-000000000000",
"name": {
"use": "official",
"family": family_name,
"given": ["Integration", "Test"]
},
"birth_date": "1990-05-15",
"gender": "female"
});
let response = app
.oneshot(
Request::builder()
.method("POST")
.uri("/api/v1/persons")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_vec(&person_json).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::CREATED);
let body = axum::body::to_bytes(response.into_body(), usize::MAX)
.await
.unwrap();
let api_response: ApiResponse<Person> = serde_json::from_slice(&body).unwrap();
assert!(api_response.success);
let person = api_response.data.unwrap();
assert_eq!(person.name.family, family_name);
assert_eq!(person.name.given, vec!["Integration", "Test"]);
assert!(person.id.to_string() != "00000000-0000-0000-0000-000000000000");
}
#[tokio::test]
async fn test_create_and_get_person() {
let app = common::create_test_router().await;
let family_name = common::unique_person_name("CreateGet");
let person_json = json!({
"id": "00000000-0000-0000-0000-000000000000",
"name": {
"use": "official",
"family": family_name,
"given": ["Get", "Test"]
},
"birth_date": "1985-03-20",
"gender": "male"
});
let create_response = app
.clone()
.oneshot(
Request::builder()
.method("POST")
.uri("/api/v1/persons")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_vec(&person_json).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(create_response.status(), StatusCode::CREATED);
let create_body = axum::body::to_bytes(create_response.into_body(), usize::MAX)
.await
.unwrap();
let create_api_response: ApiResponse<Person> = serde_json::from_slice(&create_body).unwrap();
let created_person = create_api_response.data.unwrap();
let person_id = created_person.id;
let get_response = app
.oneshot(
Request::builder()
.uri(&format!("/api/v1/persons/{}", person_id))
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(get_response.status(), StatusCode::OK);
let get_body = axum::body::to_bytes(get_response.into_body(), usize::MAX)
.await
.unwrap();
let get_api_response: ApiResponse<Person> = serde_json::from_slice(&get_body).unwrap();
assert!(get_api_response.success);
let retrieved_person = get_api_response.data.unwrap();
assert_eq!(retrieved_person.id, person_id);
assert_eq!(retrieved_person.name.family, family_name);
}
#[tokio::test]
async fn test_update_person() {
let app = common::create_test_router().await;
let family_name = common::unique_person_name("Update");
let person_json = json!({
"id": "00000000-0000-0000-0000-000000000000",
"name": {
"use": "official",
"family": family_name,
"given": ["Update"]
},
"birth_date": "1975-11-10",
"gender": "other"
});
let create_response = app
.clone()
.oneshot(
Request::builder()
.method("POST")
.uri("/api/v1/persons")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_vec(&person_json).unwrap()))
.unwrap(),
)
.await
.unwrap();
let create_body = axum::body::to_bytes(create_response.into_body(), usize::MAX)
.await
.unwrap();
let create_api_response: ApiResponse<Person> = serde_json::from_slice(&create_body).unwrap();
let mut person = create_api_response.data.unwrap();
person.name.given = vec!["Update".to_string(), "Modified".to_string()];
let update_response = app
.oneshot(
Request::builder()
.method("PUT")
.uri(&format!("/api/v1/persons/{}", person.id))
.header("content-type", "application/json")
.body(Body::from(serde_json::to_vec(&person).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(update_response.status(), StatusCode::OK);
let update_body = axum::body::to_bytes(update_response.into_body(), usize::MAX)
.await
.unwrap();
let update_api_response: ApiResponse<Person> = serde_json::from_slice(&update_body).unwrap();
let updated_person = update_api_response.data.unwrap();
assert_eq!(updated_person.name.given, vec!["Update", "Modified"]);
}
#[tokio::test]
async fn test_delete_person() {
let app = common::create_test_router().await;
let family_name = common::unique_person_name("Delete");
let person_json = json!({
"id": "00000000-0000-0000-0000-000000000000",
"name": {
"use": "official",
"family": family_name,
"given": ["Delete"]
},
"birth_date": "1988-07-25",
"gender": "unknown"
});
let create_response = app
.clone()
.oneshot(
Request::builder()
.method("POST")
.uri("/api/v1/persons")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_vec(&person_json).unwrap()))
.unwrap(),
)
.await
.unwrap();
let create_body = axum::body::to_bytes(create_response.into_body(), usize::MAX)
.await
.unwrap();
let create_api_response: ApiResponse<Person> = serde_json::from_slice(&create_body).unwrap();
let person = create_api_response.data.unwrap();
let delete_response = app
.clone()
.oneshot(
Request::builder()
.method("DELETE")
.uri(&format!("/api/v1/persons/{}", person.id))
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(delete_response.status(), StatusCode::NO_CONTENT);
let get_response = app
.oneshot(
Request::builder()
.uri(&format!("/api/v1/persons/{}", person.id))
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(get_response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_search_persons() {
let app = common::create_test_router().await;
let family_name = common::unique_person_name("Search");
let person_json = json!({
"id": "00000000-0000-0000-0000-000000000000",
"name": {
"use": "official",
"family": family_name,
"given": ["Searchable"]
},
"birth_date": "1992-04-18",
"gender": "female"
});
let create_response = app
.clone()
.oneshot(
Request::builder()
.method("POST")
.uri("/api/v1/persons")
.header("content-type", "application/json")
.body(Body::from(serde_json::to_vec(&person_json).unwrap()))
.unwrap(),
)
.await
.unwrap();
assert_eq!(create_response.status(), StatusCode::CREATED);
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
let search_response = app
.oneshot(
Request::builder()
.uri(&format!("/api/v1/persons/search?q={}&limit=10", family_name))
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(search_response.status(), StatusCode::OK);
let search_body = axum::body::to_bytes(search_response.into_body(), usize::MAX)
.await
.unwrap();
let body_str = String::from_utf8(search_body.to_vec()).unwrap();
assert!(body_str.contains(&family_name));
}
#[tokio::test]
async fn test_get_person_not_found() {
let app = common::create_test_router().await;
let response = app
.oneshot(
Request::builder()
.uri("/api/v1/persons/00000000-0000-0000-0000-000000000001")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}