mirror of
https://git.proxmox.com/git/proxmox
synced 2025-05-02 04:01:08 +00:00

An `fn` type can be more annoying to produce in some generic cases, and we haven't really needed it yet. Signed-off-by: Wolfgang Bumiller <wry.git@bumiller.com>
181 lines
5.4 KiB
Rust
181 lines
5.4 KiB
Rust
#![feature(async_await)]
|
|
|
|
use bytes::Bytes;
|
|
|
|
use proxmox_api::Router;
|
|
|
|
#[test]
|
|
fn basic() {
|
|
let info: &proxmox_api::ApiMethod<Bytes> = &methods::GET_PEOPLE;
|
|
let get_subpath: &proxmox_api::ApiMethod<Bytes> = &methods::GET_SUBPATH;
|
|
let router: Router<Bytes> = Router::new()
|
|
.subdir(
|
|
"people",
|
|
Router::new().parameter_subdir("person", Router::new().get(info)),
|
|
)
|
|
.subdir(
|
|
"wildcard",
|
|
Router::new().wildcard("subpath").get(get_subpath),
|
|
);
|
|
|
|
check_with_matched_params(&router, "people/foo", "person", "foo", "foo");
|
|
check_with_matched_params(&router, "people//foo", "person", "foo", "foo");
|
|
check_with_matched_params(&router, "wildcard", "subpath", "", "");
|
|
check_with_matched_params(&router, "wildcard/", "subpath", "", "");
|
|
check_with_matched_params(&router, "wildcard//", "subpath", "", "");
|
|
check_with_matched_params(&router, "wildcard/dir1", "subpath", "dir1", "dir1");
|
|
check_with_matched_params(
|
|
&router,
|
|
"wildcard/dir1/dir2",
|
|
"subpath",
|
|
"dir1/dir2",
|
|
"dir1/dir2",
|
|
);
|
|
check_with_matched_params(&router, "wildcard/dir1//2", "subpath", "dir1//2", "dir1//2");
|
|
}
|
|
|
|
fn check_with_matched_params(
|
|
router: &Router<Bytes>,
|
|
path: &str,
|
|
param_name: &str,
|
|
param_value: &str,
|
|
expected_body: &str,
|
|
) {
|
|
let (target, params) = router
|
|
.lookup(path)
|
|
.expect(&format!("must be able to lookup '{}'", path));
|
|
|
|
let params = params.expect(&format!(
|
|
"expected parameters to be matched into '{}'",
|
|
param_name,
|
|
));
|
|
|
|
let arg = params[param_name].as_str().expect(&format!(
|
|
"expected lookup() to fill the '{}' parameter",
|
|
param_name
|
|
));
|
|
|
|
assert_eq!(
|
|
arg, param_value,
|
|
"lookup of '{}' should set '{}' to '{}'",
|
|
path, param_name, param_value,
|
|
);
|
|
|
|
let apifut = target
|
|
.get
|
|
.as_ref()
|
|
.expect(&format!("expected GET method on {}", path))
|
|
.call(params);
|
|
|
|
let response = futures::executor::block_on(apifut)
|
|
.expect("expected the simple test api function to be ready immediately");
|
|
|
|
assert_eq!(response.status(), 200, "response status must be 200");
|
|
|
|
let body =
|
|
std::str::from_utf8(response.body().as_ref()).expect("expected a valid utf8 repsonse body");
|
|
|
|
assert_eq!(
|
|
body, expected_body,
|
|
"response of {} should be '{}', got '{}'",
|
|
path, expected_body, body,
|
|
);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod methods {
|
|
use bytes::Bytes;
|
|
use failure::{bail, Error};
|
|
use http::Response;
|
|
use lazy_static::lazy_static;
|
|
use serde_derive::{Deserialize, Serialize};
|
|
use serde_json::Value;
|
|
|
|
use proxmox_api::{
|
|
get_type_info, ApiFuture, ApiMethod, ApiOutput, ApiType, Parameter, TypeInfo,
|
|
};
|
|
|
|
pub async fn get_people(value: Value) -> ApiOutput<Bytes> {
|
|
Ok(Response::builder()
|
|
.status(200)
|
|
.header("content-type", "application/json")
|
|
.body(value["person"].as_str().unwrap().into())?)
|
|
}
|
|
|
|
pub async fn get_subpath(value: Value) -> ApiOutput<Bytes> {
|
|
Ok(Response::builder()
|
|
.status(200)
|
|
.header("content-type", "application/json")
|
|
.body(value["subpath"].as_str().unwrap().into())?)
|
|
}
|
|
|
|
lazy_static! {
|
|
static ref GET_PEOPLE_PARAMS: Vec<Parameter> = {
|
|
vec![Parameter {
|
|
name: "person",
|
|
description: "the person to get",
|
|
type_info: String::type_info,
|
|
}]
|
|
};
|
|
pub static ref GET_PEOPLE: ApiMethod<Bytes> = {
|
|
ApiMethod {
|
|
description: "get some people",
|
|
parameters: &GET_PEOPLE_PARAMS,
|
|
return_type: get_type_info::<String>(),
|
|
protected: false,
|
|
reload_timezone: false,
|
|
handler: |value: Value| -> ApiFuture<Bytes> { Box::pin(get_people(value)) },
|
|
}
|
|
};
|
|
static ref GET_SUBPATH_PARAMS: Vec<Parameter> = {
|
|
vec![Parameter {
|
|
name: "subpath",
|
|
description: "the matched relative subdir path",
|
|
type_info: String::type_info,
|
|
}]
|
|
};
|
|
pub static ref GET_SUBPATH: ApiMethod<Bytes> = {
|
|
ApiMethod {
|
|
description: "get the 'subpath' parameter returned back",
|
|
parameters: &GET_SUBPATH_PARAMS,
|
|
return_type: get_type_info::<String>(),
|
|
protected: false,
|
|
reload_timezone: false,
|
|
handler: |value: Value| -> ApiFuture<Bytes> { Box::pin(get_subpath(value)) },
|
|
}
|
|
};
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize)]
|
|
pub struct CubicMeters(f64);
|
|
|
|
// We don't bother with the CLI interface in this test:
|
|
proxmox_api::no_cli_type! {CubicMeters}
|
|
proxmox_api::unconstrained_api_type! {CubicMeters}
|
|
|
|
#[derive(Deserialize, Serialize)]
|
|
pub struct Thing {
|
|
shape: String,
|
|
size: CubicMeters,
|
|
}
|
|
|
|
impl ApiType for Thing {
|
|
fn type_info() -> &'static TypeInfo {
|
|
const INFO: TypeInfo = TypeInfo {
|
|
name: "Thing",
|
|
description: "A thing",
|
|
complete_fn: None,
|
|
parse_cli: None,
|
|
};
|
|
&INFO
|
|
}
|
|
|
|
fn verify(&self) -> Result<(), Error> {
|
|
if self.shape == "flat" {
|
|
bail!("flat shapes not allowed...");
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|