#![expect(clippy::unwrap_used)]
use wiremock::matchers::{body_json, method, path, query_param};
use wiremock::{Mock, MockServer, ResponseTemplate};
use super::super::encode_path;
use crate::client::test_helpers::test_client;
use crate::types::{CreateUserParams, UpdateUserParams};
#[tokio::test]
async fn whoami_returns_user_info() {
let mock = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/rest/whoami"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"id": 42,
"name": "alice@example.com",
"real_name": "Alice",
"login": "alice@example.com"
})))
.mount(&mock)
.await;
let client = test_client(&mock.uri());
let who = client.whoami().await.unwrap();
assert_eq!(who.id, 42);
assert_eq!(who.name, "alice@example.com");
assert_eq!(who.real_name.as_deref(), Some("Alice"));
}
#[tokio::test]
async fn search_users_returns_matches() {
let mock = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/rest/user"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"users": [
{"id": 1, "name": "alice@example.com", "real_name": "Alice", "email": "alice@example.com"},
{"id": 2, "name": "bob@example.com", "real_name": "Bob", "email": "bob@example.com"}
]
})))
.mount(&mock)
.await;
let client = test_client(&mock.uri());
let users = client.search_users("example", false).await.unwrap();
assert_eq!(users.len(), 2);
assert_eq!(users[0].name, "alice@example.com");
assert_eq!(users[1].real_name.as_deref(), Some("Bob"));
}
#[tokio::test]
async fn search_users_empty() {
let mock = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/rest/user"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({"users": []})))
.mount(&mock)
.await;
let client = test_client(&mock.uri());
let users = client.search_users("nobody", false).await.unwrap();
assert!(users.is_empty());
}
#[tokio::test]
async fn search_users_details_sends_include_fields() {
let mock = MockServer::start().await;
Mock::given(method("GET"))
.and(path("/rest/user"))
.and(query_param("match", "alice"))
.and(query_param("include_fields", super::USER_FIELDS_DETAILED))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"users": [{
"id": 1,
"name": "alice@example.com",
"real_name": "Alice",
"email": "alice@example.com",
"can_login": true,
"groups": [{"id": 10, "name": "admin", "description": "Admins"}]
}]
})))
.mount(&mock)
.await;
let client = test_client(&mock.uri());
let users = client.search_users("alice", true).await.unwrap();
assert_eq!(users.len(), 1);
assert_eq!(users[0].can_login, Some(true));
assert_eq!(users[0].groups.len(), 1);
assert_eq!(users[0].groups[0].name, "admin");
}
#[tokio::test]
async fn create_user_returns_id() {
let mock = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/rest/user"))
.and(body_json(serde_json::json!({
"email": "new@example.com",
"full_name": "New User",
})))
.respond_with(ResponseTemplate::new(201).set_body_json(serde_json::json!({"id": 99})))
.expect(1)
.mount(&mock)
.await;
let client = test_client(&mock.uri());
let params = CreateUserParams {
email: "new@example.com".into(),
login: None,
full_name: Some("New User".into()),
password: None,
};
let id = client.create_user(¶ms).await.unwrap();
assert_eq!(id, 99);
}
#[tokio::test]
async fn create_user_forbidden() {
let mock = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/rest/user"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"error": true,
"code": 51,
"message": "You are not authorized."
})))
.mount(&mock)
.await;
let client = test_client(&mock.uri());
let params = CreateUserParams {
email: "x@x.com".into(),
login: None,
full_name: None,
password: None,
};
let err = client.create_user(¶ms).await.unwrap_err();
assert!(err.to_string().contains("not authorized"));
}
#[tokio::test]
async fn update_user_sends_put() {
let mock = MockServer::start().await;
Mock::given(method("PUT"))
.and(path(format!(
"/rest/user/{}",
encode_path("alice@example.com")
)))
.and(body_json(serde_json::json!({
"real_name": "Alice Smith",
"names": ["alice@example.com"],
})))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"users": [{"id": 1, "changes": {}}]
})))
.expect(1)
.mount(&mock)
.await;
let client = test_client(&mock.uri());
let params = UpdateUserParams {
names: Some(vec!["alice@example.com".into()]),
real_name: Some("Alice Smith".into()),
..Default::default()
};
client
.update_user("alice@example.com", ¶ms)
.await
.unwrap();
}
#[tokio::test]
async fn update_user_forbidden() {
let mock = MockServer::start().await;
Mock::given(method("PUT"))
.and(path(format!(
"/rest/user/{}",
encode_path("alice@example.com")
)))
.respond_with(ResponseTemplate::new(403).set_body_json(serde_json::json!({
"error": true,
"code": 51,
"message": "You are not authorized."
})))
.mount(&mock)
.await;
let client = test_client(&mock.uri());
let params = UpdateUserParams::default();
let err = client
.update_user("alice@example.com", ¶ms)
.await
.unwrap_err();
assert!(err.to_string().contains("not authorized"));
}