use super::*;
#[ntex::test]
async fn files_upload_serve_and_land_in_a_file_field() {
let db = TempDatabase::create("storage").await;
let root = temp_dir("storage");
write_files(
&root,
&[
(
"main.toml",
&format!(
r#"
[server]
base_path = "/api"
[database]
url = "{}"
[storage]
backend = "local"
dir = "uploads"
max_size_mb = 1
allowed_types = ["image/*", "application/pdf"]
"#,
db.url
),
),
(
"models/brand.toml",
r#"
[resource]
name = "brand"
scope = "global"
[permissions]
list = "public"
read = "public"
create = "authenticated"
update = "authenticated"
[fields.name]
type = "string"
required = true
[fields.logo]
type = "file"
"#,
),
],
);
let state = load_state(&root).await;
let app = init_http_app!(state);
let registration = test::call_service(
&app,
req_json(
"POST",
"/api/auth/register",
json!({"email":"alice@example.com","password":"pw"}),
),
)
.await;
let token = read_json(registration).await["token"]
.as_str()
.unwrap()
.to_string();
let anonymous = test::call_service(
&app,
test::TestRequest::post()
.uri("/api/uploads?filename=logo.png")
.header(CONTENT_TYPE, "image/png")
.set_payload("PNG")
.to_request(),
)
.await;
assert_eq!(anonymous.status().as_u16(), 401);
let wrong_type = test::call_service(
&app,
bearer(
test::TestRequest::post()
.uri("/api/uploads?filename=payload.html")
.header(CONTENT_TYPE, "text/html")
.set_payload("<script>"),
&token,
)
.to_request(),
)
.await;
assert_eq!(wrong_type.status().as_u16(), 415);
let upload = test::call_service(
&app,
bearer(
test::TestRequest::post()
.uri("/api/uploads?filename=Logo%20Final%20(2).PNG")
.header(CONTENT_TYPE, "image/png")
.set_payload("PNGDATA"),
&token,
)
.to_request(),
)
.await;
assert_eq!(upload.status().as_u16(), 200);
let stored = read_json(upload).await;
let url = stored["url"].as_str().unwrap().to_string();
assert!(url.starts_with("/files/"), "{url} should be relative");
assert!(url.ends_with("-logo-final-2.png"), "{url} keeps the name");
assert_eq!(stored["content_type"], "image/png");
let key = stored["key"].as_str().unwrap();
assert_eq!(
fs::read(root.join("uploads").join(key)).unwrap(),
b"PNGDATA"
);
let served = test::call_service(&app, test::TestRequest::get().uri(&url).to_request()).await;
assert_eq!(served.status().as_u16(), 200);
assert_eq!(served.headers().get("content-type").unwrap(), "image/png");
assert_eq!(
served.headers().get("x-content-type-options").unwrap(),
"nosniff"
);
assert_eq!(test::read_body(served).await, "PNGDATA");
let escape = test::call_service(
&app,
test::TestRequest::get()
.uri("/files/../../main.toml")
.to_request(),
)
.await;
assert_ne!(escape.status().as_u16(), 200);
let missing = test::call_service(
&app,
test::TestRequest::get()
.uri("/files/2026/01/nothing.png")
.to_request(),
)
.await;
assert_eq!(missing.status().as_u16(), 404);
let created = test::call_service(
&app,
bearer(
test::TestRequest::post()
.uri("/api/brand")
.header(CONTENT_TYPE, "application/json")
.set_payload(json!({"name": "Acme", "logo": url}).to_string()),
&token,
)
.to_request(),
)
.await;
assert_eq!(created.status().as_u16(), 201);
assert_eq!(read_json(created).await["logo"], url.as_str());
}
#[ntex::test]
async fn a_file_field_is_a_string_to_every_client() {
let db = TempDatabase::create("filefield").await;
let root = temp_dir("filefield");
write_files(
&root,
&[
(
"main.toml",
&format!(
"[server]\nbase_path = \"/api\"\n\n[database]\nurl = \"{}\"\n",
db.url
),
),
(
"models/doc.toml",
r#"
[resource]
name = "doc"
scope = "global"
[permissions]
list = "public"
read = "public"
create = "public"
[fields.attachment]
type = "file"
max_length = 512
"#,
),
],
);
let state = load_state(&root).await;
let app = init_http_app!(state);
let spec = read_json(
test::call_service(
&app,
test::TestRequest::get()
.uri("/api/openapi.json")
.to_request(),
)
.await,
)
.await;
let schema = &spec["components"]["schemas"]["Doc"]["properties"]["attachment"];
assert_eq!(schema["type"], "string");
assert_eq!(schema["format"], "uri-reference");
let created = test::call_service(
&app,
req_json(
"POST",
"/api/doc",
json!({"attachment": "https://cdn.example.invalid/a.pdf"}),
),
)
.await;
assert_eq!(created.status().as_u16(), 201);
assert_eq!(
read_json(created).await["attachment"],
"https://cdn.example.invalid/a.pdf"
);
let manifest: Value = serde_json::from_str(&state.admin_manifest).unwrap();
let field = manifest["resources"]
.as_array()
.unwrap()
.iter()
.find(|resource| resource["name"] == "doc")
.unwrap()["fields"]
.as_array()
.unwrap()
.iter()
.find(|field| field["name"] == "attachment")
.unwrap()
.clone();
assert_eq!(field["type"], "file");
assert_eq!(field["widget"], "file");
}
#[ntex::test]
async fn an_app_that_stores_nothing_has_no_upload_routes() {
let db = TempDatabase::create("nostorage").await;
let root = temp_dir("nostorage");
write_files(
&root,
&[(
"main.toml",
&format!(
"[server]\nbase_path = \"/api\"\n\n[database]\nurl = \"{}\"\n\n[storage]\nbackend = \"none\"\n",
db.url
),
)],
);
let state = load_state(&root).await;
assert!(state.storage.is_none());
let app = init_http_app!(state);
let upload = test::call_service(
&app,
test::TestRequest::post()
.uri("/api/uploads?filename=a.png")
.header(CONTENT_TYPE, "image/png")
.set_payload("x")
.to_request(),
)
.await;
assert!(!upload.status().is_success(), "{}", upload.status());
let serve = test::call_service(
&app,
test::TestRequest::get().uri("/files/a.png").to_request(),
)
.await;
assert_eq!(serve.status().as_u16(), 404);
}