feat: add cluster discovery, failover, VM management, and console support
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
//! Integration tests for the Proxmox API client core.
|
||||
//!
|
||||
//! These tests exercise the generic `api_request` helper against a local HTTP
|
||||
//! mock server, covering auth header injection, response envelope unwrapping,
|
||||
//! error mapping, query parameters, and URL construction.
|
||||
|
||||
use httpmock::prelude::*;
|
||||
use proxmox_desktop::{api_request, AuthContext, AuthMode, Error};
|
||||
use reqwest::Client;
|
||||
use reqwest::Method as RMethod;
|
||||
|
||||
const TICKET: &str = "PVE:root@pam:abc123";
|
||||
const CSRF_TOKEN: &str = "csrf-token-123";
|
||||
|
||||
fn token_auth() -> AuthContext {
|
||||
AuthContext {
|
||||
mode: AuthMode::Token,
|
||||
token: Some("root@pam!test-token".to_string()),
|
||||
ticket: None,
|
||||
csrf_token: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn password_auth() -> AuthContext {
|
||||
AuthContext {
|
||||
mode: AuthMode::Password,
|
||||
token: None,
|
||||
ticket: Some(TICKET.to_string()),
|
||||
csrf_token: Some(CSRF_TOKEN.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn token_auth_sends_authorization_header_and_unwraps_envelope() {
|
||||
let server = MockServer::start();
|
||||
let expected = serde_json::json!({
|
||||
"version": "8.1.0",
|
||||
"release": "8.1",
|
||||
"repoid": "abc123",
|
||||
});
|
||||
let mock = server.mock(|when, then| {
|
||||
when.method(GET)
|
||||
.path("/api2/json/version")
|
||||
.header("Authorization", "PVEAPIToken=root@pam!test-token");
|
||||
then.status(200)
|
||||
.header("content-type", "application/json")
|
||||
.body(serde_json::json!({ "data": expected }).to_string());
|
||||
});
|
||||
|
||||
let result = api_request(
|
||||
&Client::new(),
|
||||
&server.base_url(),
|
||||
RMethod::GET,
|
||||
"/version",
|
||||
&token_auth(),
|
||||
&[],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("request should succeed");
|
||||
|
||||
assert_eq!(result, expected);
|
||||
mock.assert();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn password_auth_sends_cookie_header_on_get() {
|
||||
let server = MockServer::start();
|
||||
let mock = server.mock(|when, then| {
|
||||
when.method(GET)
|
||||
.path("/api2/json/version")
|
||||
.header("Cookie", format!("PVEAuthCookie={}", TICKET));
|
||||
then.status(200)
|
||||
.header("content-type", "application/json")
|
||||
.body(r#"{"data":{"version":"8.1.0"}}"#);
|
||||
});
|
||||
|
||||
let result = api_request(
|
||||
&Client::new(),
|
||||
&server.base_url(),
|
||||
RMethod::GET,
|
||||
"/version",
|
||||
&password_auth(),
|
||||
&[],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("request should succeed");
|
||||
|
||||
assert_eq!(result["version"], "8.1.0");
|
||||
mock.assert();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn password_auth_sends_cookie_and_csrf_headers_on_post() {
|
||||
let server = MockServer::start();
|
||||
let mock = server.mock(|when, then| {
|
||||
when.method(POST)
|
||||
.path("/api2/json/nodes/pve/qemu/100/status/start")
|
||||
.header("Cookie", format!("PVEAuthCookie={}", TICKET))
|
||||
.header("CSRFPreventionToken", CSRF_TOKEN);
|
||||
then.status(200)
|
||||
.header("content-type", "application/json")
|
||||
.body(r#"{"data":null}"#);
|
||||
});
|
||||
|
||||
let result = api_request(
|
||||
&Client::new(),
|
||||
&server.base_url(),
|
||||
RMethod::POST,
|
||||
"/nodes/pve/qemu/100/status/start",
|
||||
&password_auth(),
|
||||
&[],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("request should succeed");
|
||||
|
||||
assert_eq!(result, serde_json::Value::Null);
|
||||
mock.assert();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn server_error_message_is_mapped_to_api_error() {
|
||||
let server = MockServer::start();
|
||||
let mock = server.mock(|when, then| {
|
||||
when.method(GET).path("/api2/json/version");
|
||||
then.status(500)
|
||||
.header("content-type", "application/json")
|
||||
.body(r#"{"message":"boom"}"#);
|
||||
});
|
||||
|
||||
let error = api_request(
|
||||
&Client::new(),
|
||||
&server.base_url(),
|
||||
RMethod::GET,
|
||||
"/version",
|
||||
&token_auth(),
|
||||
&[],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect_err("request should fail");
|
||||
|
||||
assert!(
|
||||
matches!(error, Error::ApiError(ref message) if message == "boom"),
|
||||
"expected ApiError with message 'boom', got: {}",
|
||||
error
|
||||
);
|
||||
mock.assert();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn query_params_are_included_in_request() {
|
||||
let server = MockServer::start();
|
||||
let mock = server.mock(|when, then| {
|
||||
when.method(GET)
|
||||
.path("/api2/json/nodes/pve/qemu")
|
||||
.query_param("node", "pve")
|
||||
.query_param("vmid", "100")
|
||||
.query_param("include-config", "true");
|
||||
then.status(200)
|
||||
.header("content-type", "application/json")
|
||||
.body(r#"{"data":[]}"#);
|
||||
});
|
||||
|
||||
let query = [
|
||||
("node", "pve".to_string()),
|
||||
("vmid", "100".to_string()),
|
||||
("include-config", "true".to_string()),
|
||||
];
|
||||
let result = api_request(
|
||||
&Client::new(),
|
||||
&server.base_url(),
|
||||
RMethod::GET,
|
||||
"/nodes/pve/qemu",
|
||||
&token_auth(),
|
||||
&query,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("request should succeed");
|
||||
|
||||
assert_eq!(result, serde_json::json!([]));
|
||||
mock.assert();
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn base_url_trailing_slash_is_stripped() {
|
||||
let server = MockServer::start();
|
||||
let mock = server.mock(|when, then| {
|
||||
when.method(GET).path("/api2/json/version");
|
||||
then.status(200)
|
||||
.header("content-type", "application/json")
|
||||
.body(r#"{"data":{"version":"8.1.0"}}"#);
|
||||
});
|
||||
|
||||
let base_url = format!("{}/", server.base_url());
|
||||
let result = api_request(
|
||||
&Client::new(),
|
||||
&base_url,
|
||||
RMethod::GET,
|
||||
"/version",
|
||||
&token_auth(),
|
||||
&[],
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("request should succeed");
|
||||
|
||||
assert_eq!(result["version"], "8.1.0");
|
||||
mock.assert();
|
||||
}
|
||||
Reference in New Issue
Block a user