#![cfg(feature = "openapi")]
use road_runner_common::openapi::GlobalErrorResponses;
use utoipa::openapi::path::{OperationBuilder, PathItem, PathItemType};
use utoipa::openapi::content::ContentBuilder;
use utoipa::openapi::response::ResponseBuilder;
use utoipa::openapi::schema::{ObjectBuilder, Schema, SchemaType};
use utoipa::openapi::{OpenApi, RefOr};
use utoipa::Modify;
fn openapi_with_plain_200() -> OpenApi {
let mut openapi = OpenApi::new(utoipa::openapi::Info::new("test", "1.0"), utoipa::openapi::Paths::new());
let operation = OperationBuilder::new()
.response("200", ResponseBuilder::new().description("ok").build())
.build();
let path_item = PathItem::new(PathItemType::Get, operation);
openapi.paths.paths.insert("/orders".to_string(), path_item);
openapi
}
fn openapi_with_json_200(example: Option<serde_json::Value>) -> OpenApi {
let mut openapi = OpenApi::new(utoipa::openapi::Info::new("test", "1.0"), utoipa::openapi::Paths::new());
let mut content = ContentBuilder::new()
.schema(Schema::from(
ObjectBuilder::new()
.property("id", ObjectBuilder::new().schema_type(SchemaType::String).build())
.build(),
))
.build();
content.example = example;
let operation = OperationBuilder::new()
.response(
"200",
ResponseBuilder::new()
.description("ok")
.content("application/json", content)
.build(),
)
.build();
let path_item = PathItem::new(PathItemType::Get, operation);
openapi.paths.paths.insert("/orders".to_string(), path_item);
openapi
}
#[test]
fn global_error_responses_adds_schema_and_standard_errors() {
let mut openapi = openapi_with_plain_200();
GlobalErrorResponses.modify(&mut openapi);
let components = openapi.components.unwrap();
assert!(components.schemas.contains_key("ApiErrorResponse"));
let operation = openapi.paths.paths.get("/orders").unwrap().operations.get(&PathItemType::Get).unwrap();
for code in ["400", "401", "403", "404", "500", "503"] {
assert!(operation.responses.responses.contains_key(code));
}
}
#[test]
fn global_error_responses_preserves_existing_error_response() {
let mut openapi = openapi_with_plain_200();
let operation = openapi.paths.paths.get_mut("/orders").unwrap().operations.get_mut(&PathItemType::Get).unwrap();
operation.responses.responses.insert(
"404".to_string(),
ResponseBuilder::new().description("custom not found").build().into(),
);
GlobalErrorResponses.modify(&mut openapi);
let operation = openapi.paths.paths.get("/orders").unwrap().operations.get(&PathItemType::Get).unwrap();
let response = operation.responses.responses.get("404").unwrap();
let RefOr::T(response) = response else {
panic!("expected inline response");
};
assert_eq!(response.description, "custom not found");
}
#[test]
fn global_error_responses_wraps_200_json_schema_and_existing_example() {
let mut openapi = openapi_with_json_200(Some(serde_json::json!({"id": "ord-1"})));
GlobalErrorResponses.modify(&mut openapi);
let operation = openapi.paths.paths.get("/orders").unwrap().operations.get(&PathItemType::Get).unwrap();
let response = operation.responses.responses.get("200").unwrap();
let RefOr::T(response) = response else {
panic!("expected inline response");
};
let content = response.content.get("application/json").unwrap();
assert_eq!(content.example.as_ref().unwrap()["success"], true);
assert_eq!(content.example.as_ref().unwrap()["data"]["id"], "ord-1");
assert_eq!(content.example.as_ref().unwrap()["errors"], serde_json::json!([]));
}
#[test]
fn global_error_responses_wraps_200_json_schema_with_generic_example_when_missing() {
let mut openapi = openapi_with_json_200(None);
GlobalErrorResponses.modify(&mut openapi);
let operation = openapi.paths.paths.get("/orders").unwrap().operations.get(&PathItemType::Get).unwrap();
let response = operation.responses.responses.get("200").unwrap();
let RefOr::T(response) = response else {
panic!("expected inline response");
};
let content = response.content.get("application/json").unwrap();
assert_eq!(content.example.as_ref().unwrap()["success"], true);
assert_eq!(content.example.as_ref().unwrap()["data"], serde_json::Value::Null);
}