use std::sync::Arc;
use axum::body::Body;
use axum::http::{Method, Request, StatusCode};
use base64::engine::general_purpose::STANDARD as BASE64;
use base64::Engine;
use http_body_util::BodyExt;
use serde_json::{json, Value};
use tensor_wasm_api::{build_router_with_config, AppState, AuthConfig, TenantConfig};
use tower::ServiceExt;
use uuid::Uuid;
const WASM_MIN_MODULE: [u8; 8] = [0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00];
async fn body_json(body: Body) -> Value {
let bytes = body
.collect()
.await
.expect("collect body")
.to_bytes()
.to_vec();
serde_json::from_slice(&bytes).expect("body is JSON")
}
fn router() -> axum::Router {
build_router_with_config(
Arc::new(AppState::default()),
AuthConfig::default(),
TenantConfig::default(),
)
}
fn json_post(uri: &str, body: Value) -> Request<Body> {
Request::builder()
.method(Method::POST)
.uri(uri)
.header("content-type", "application/json")
.body(Body::from(serde_json::to_vec(&body).unwrap()))
.unwrap()
}
async fn assert_invalid_name(name: Value) {
let wasm_b64 = BASE64.encode(WASM_MIN_MODULE);
let req = json_post("/functions", json!({ "name": name, "wasm_b64": wasm_b64 }));
let resp = router().oneshot(req).await.unwrap();
assert_eq!(
resp.status(),
StatusCode::BAD_REQUEST,
"expected 400 for name {name:?}"
);
let body = body_json(resp.into_body()).await;
assert_eq!(
body.pointer("/error/kind").and_then(Value::as_str),
Some("invalid_name"),
"got {body}"
);
}
#[tokio::test]
async fn empty_name_is_rejected() {
assert_invalid_name(json!("")).await;
}
#[tokio::test]
async fn whitespace_only_name_is_rejected() {
assert_invalid_name(json!(" ")).await;
}
#[tokio::test]
async fn oversized_name_is_rejected() {
let name = "a".repeat(257);
assert_invalid_name(json!(name)).await;
}
#[tokio::test]
async fn embedded_nul_name_is_rejected() {
assert_invalid_name(json!("hello\u{0}world")).await;
}
#[tokio::test]
async fn well_formed_name_is_accepted() {
let wasm_b64 = BASE64.encode(WASM_MIN_MODULE);
let req = json_post(
"/functions",
json!({ "name": "ok_name", "wasm_b64": wasm_b64 }),
);
let resp = router().oneshot(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK, "expected 200 OK");
let body = body_json(resp.into_body()).await;
let id = body
.get("id")
.and_then(Value::as_str)
.expect("id field present and string");
Uuid::parse_str(id).expect("id is a valid UUID");
}