1019 lines
39 KiB
Rust
1019 lines
39 KiB
Rust
|
|
#![cfg(feature = "integration")]
|
||
|
|
use sunbeam_sdk::client::{AuthMethod, ServiceClient};
|
||
|
|
use sunbeam_sdk::lasuite::*;
|
||
|
|
use wiremock::{MockServer, Mock, ResponseTemplate};
|
||
|
|
use wiremock::matchers::{method, path, query_param};
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Helpers
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
/// Build a standard DRF paginated response with a single result.
|
||
|
|
fn drf_page(result: serde_json::Value) -> serde_json::Value {
|
||
|
|
serde_json::json!({
|
||
|
|
"count": 1,
|
||
|
|
"next": null,
|
||
|
|
"previous": null,
|
||
|
|
"results": [result]
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
fn empty_page() -> serde_json::Value {
|
||
|
|
serde_json::json!({
|
||
|
|
"count": 0,
|
||
|
|
"next": null,
|
||
|
|
"previous": null,
|
||
|
|
"results": []
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// =========================================================================
|
||
|
|
// PeopleClient
|
||
|
|
// =========================================================================
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_list_contacts() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "c1", "first_name": "Alice", "email": "alice@example.com"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/contacts/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = PeopleClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_contacts(None).await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results.len(), 1);
|
||
|
|
assert_eq!(page.results[0].id, "c1");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_list_contacts_paginated() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "c2"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/contacts/"))
|
||
|
|
.and(query_param("page", "2"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = PeopleClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_contacts(Some(2)).await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].id, "c2");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_get_contact() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let contact = serde_json::json!({"id": "c1", "first_name": "Alice", "last_name": "Smith"});
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/contacts/c1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&contact))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = PeopleClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let result = c.get_contact("c1").await.unwrap();
|
||
|
|
assert_eq!(result.id, "c1");
|
||
|
|
assert_eq!(result.first_name.as_deref(), Some("Alice"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_create_contact() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "c-new", "first_name": "Bob"});
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/contacts/"))
|
||
|
|
.respond_with(ResponseTemplate::new(201).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = PeopleClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"first_name": "Bob"});
|
||
|
|
let result = c.create_contact(&body).await.unwrap();
|
||
|
|
assert_eq!(result.id, "c-new");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_update_contact() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "c1", "first_name": "Alice", "last_name": "Jones"});
|
||
|
|
Mock::given(method("PATCH"))
|
||
|
|
.and(path("/contacts/c1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = PeopleClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"last_name": "Jones"});
|
||
|
|
let result = c.update_contact("c1", &body).await.unwrap();
|
||
|
|
assert_eq!(result.last_name.as_deref(), Some("Jones"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_delete_contact() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
Mock::given(method("DELETE"))
|
||
|
|
.and(path("/contacts/c1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(204))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = PeopleClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
c.delete_contact("c1").await.unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_list_teams() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "t1", "name": "Engineering"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/teams/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = PeopleClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_teams(None).await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].name.as_deref(), Some("Engineering"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_list_teams_paginated() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "t2", "name": "Design"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/teams/"))
|
||
|
|
.and(query_param("page", "3"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = PeopleClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_teams(Some(3)).await.unwrap();
|
||
|
|
assert_eq!(page.results[0].id, "t2");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_get_team() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let team = serde_json::json!({"id": "t1", "name": "Engineering", "members": ["u1", "u2"]});
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/teams/t1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&team))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = PeopleClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let result = c.get_team("t1").await.unwrap();
|
||
|
|
assert_eq!(result.id, "t1");
|
||
|
|
assert_eq!(result.members.as_ref().unwrap().len(), 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_create_team() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "t-new", "name": "Ops"});
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/teams/"))
|
||
|
|
.respond_with(ResponseTemplate::new(201).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = PeopleClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"name": "Ops"});
|
||
|
|
let result = c.create_team(&body).await.unwrap();
|
||
|
|
assert_eq!(result.id, "t-new");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_list_service_providers() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "sp1", "name": "OIDC Provider", "base_url": "https://auth.example.com"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/service-providers/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = PeopleClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_service_providers().await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].name.as_deref(), Some("OIDC Provider"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_list_mail_domains() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "md1", "name": "example.com", "status": "active"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/mail-domains/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = PeopleClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_mail_domains().await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].status.as_deref(), Some("active"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn people_connect_and_with_token() {
|
||
|
|
let c = PeopleClient::connect("example.com").with_token("my-tok");
|
||
|
|
assert_eq!(c.base_url(), "https://people.example.com/api/v1.0");
|
||
|
|
assert_eq!(c.service_name(), "people");
|
||
|
|
}
|
||
|
|
|
||
|
|
// =========================================================================
|
||
|
|
// DocsClient
|
||
|
|
// =========================================================================
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn docs_list_documents() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "d1", "title": "My Doc"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/documents/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DocsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_documents(None).await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].title.as_deref(), Some("My Doc"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn docs_list_documents_paginated() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "d2"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/documents/"))
|
||
|
|
.and(query_param("page", "2"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DocsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_documents(Some(2)).await.unwrap();
|
||
|
|
assert_eq!(page.results[0].id, "d2");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn docs_get_document() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let doc = serde_json::json!({"id": "d1", "title": "My Doc", "content": "Hello world"});
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/documents/d1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&doc))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DocsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let result = c.get_document("d1").await.unwrap();
|
||
|
|
assert_eq!(result.id, "d1");
|
||
|
|
assert_eq!(result.content.as_deref(), Some("Hello world"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn docs_create_document() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "d-new", "title": "New Doc", "is_public": false});
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/documents/"))
|
||
|
|
.respond_with(ResponseTemplate::new(201).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DocsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"title": "New Doc"});
|
||
|
|
let result = c.create_document(&body).await.unwrap();
|
||
|
|
assert_eq!(result.id, "d-new");
|
||
|
|
assert_eq!(result.is_public, Some(false));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn docs_update_document() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "d1", "title": "Updated Doc"});
|
||
|
|
Mock::given(method("PATCH"))
|
||
|
|
.and(path("/documents/d1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DocsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"title": "Updated Doc"});
|
||
|
|
let result = c.update_document("d1", &body).await.unwrap();
|
||
|
|
assert_eq!(result.title.as_deref(), Some("Updated Doc"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn docs_delete_document() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
Mock::given(method("DELETE"))
|
||
|
|
.and(path("/documents/d1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(204))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DocsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
c.delete_document("d1").await.unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn docs_list_templates() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "tpl1", "title": "Meeting Notes"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/templates/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DocsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_templates(None).await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].title.as_deref(), Some("Meeting Notes"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn docs_list_templates_paginated() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "tpl2"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/templates/"))
|
||
|
|
.and(query_param("page", "4"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DocsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_templates(Some(4)).await.unwrap();
|
||
|
|
assert_eq!(page.results[0].id, "tpl2");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn docs_create_template() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "tpl-new", "title": "Blank", "is_public": true});
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/templates/"))
|
||
|
|
.respond_with(ResponseTemplate::new(201).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DocsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"title": "Blank"});
|
||
|
|
let result = c.create_template(&body).await.unwrap();
|
||
|
|
assert_eq!(result.id, "tpl-new");
|
||
|
|
assert_eq!(result.is_public, Some(true));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn docs_list_versions() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "v1", "document_id": "d1", "version_number": 3}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/documents/d1/versions/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DocsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_versions("d1").await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].version_number, Some(3));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn docs_invite_user() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "inv1", "email": "bob@example.com", "role": "editor", "document_id": "d1"});
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/documents/d1/invitations/"))
|
||
|
|
.respond_with(ResponseTemplate::new(201).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DocsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"email": "bob@example.com", "role": "editor"});
|
||
|
|
let result = c.invite_user("d1", &body).await.unwrap();
|
||
|
|
assert_eq!(result.id, "inv1");
|
||
|
|
assert_eq!(result.role.as_deref(), Some("editor"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn docs_connect_and_with_token() {
|
||
|
|
let c = DocsClient::connect("example.com").with_token("my-tok");
|
||
|
|
assert_eq!(c.base_url(), "https://docs.example.com/api/v1.0");
|
||
|
|
assert_eq!(c.service_name(), "docs");
|
||
|
|
}
|
||
|
|
|
||
|
|
// =========================================================================
|
||
|
|
// MeetClient
|
||
|
|
// =========================================================================
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn meet_list_rooms() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "r1", "name": "Standup", "slug": "standup"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/rooms/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MeetClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_rooms(None).await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].slug.as_deref(), Some("standup"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn meet_list_rooms_paginated() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "r2", "name": "Retro"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/rooms/"))
|
||
|
|
.and(query_param("page", "2"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MeetClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_rooms(Some(2)).await.unwrap();
|
||
|
|
assert_eq!(page.results[0].id, "r2");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn meet_create_room() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "r-new", "name": "Planning", "is_public": true});
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/rooms/"))
|
||
|
|
.respond_with(ResponseTemplate::new(201).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MeetClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"name": "Planning"});
|
||
|
|
let result = c.create_room(&body).await.unwrap();
|
||
|
|
assert_eq!(result.id, "r-new");
|
||
|
|
assert_eq!(result.is_public, Some(true));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn meet_get_room() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let room = serde_json::json!({"id": "r1", "name": "Standup", "configuration": {"audio": true}});
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/rooms/r1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&room))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MeetClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let result = c.get_room("r1").await.unwrap();
|
||
|
|
assert_eq!(result.id, "r1");
|
||
|
|
assert!(result.configuration.is_some());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn meet_update_room() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "r1", "name": "Daily Standup"});
|
||
|
|
Mock::given(method("PATCH"))
|
||
|
|
.and(path("/rooms/r1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MeetClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"name": "Daily Standup"});
|
||
|
|
let result = c.update_room("r1", &body).await.unwrap();
|
||
|
|
assert_eq!(result.name.as_deref(), Some("Daily Standup"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn meet_delete_room() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
Mock::given(method("DELETE"))
|
||
|
|
.and(path("/rooms/r1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(204))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MeetClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
c.delete_room("r1").await.unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn meet_list_recordings() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "rec1", "room_id": "r1", "filename": "recording.mp4", "duration": 3600.5}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/rooms/r1/recordings/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MeetClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_recordings("r1").await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].duration, Some(3600.5));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn meet_connect_and_with_token() {
|
||
|
|
let c = MeetClient::connect("example.com").with_token("my-tok");
|
||
|
|
assert_eq!(c.base_url(), "https://meet.example.com/api/v1.0");
|
||
|
|
assert_eq!(c.service_name(), "meet");
|
||
|
|
}
|
||
|
|
|
||
|
|
// =========================================================================
|
||
|
|
// DriveClient
|
||
|
|
// =========================================================================
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn drive_list_files() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "f1", "name": "report.pdf", "size": 1024, "mime_type": "application/pdf"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/files/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DriveClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_files(None).await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].name.as_deref(), Some("report.pdf"));
|
||
|
|
assert_eq!(page.results[0].size, Some(1024));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn drive_list_files_paginated() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "f2"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/files/"))
|
||
|
|
.and(query_param("page", "5"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DriveClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_files(Some(5)).await.unwrap();
|
||
|
|
assert_eq!(page.results[0].id, "f2");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn drive_get_file() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let file = serde_json::json!({"id": "f1", "name": "report.pdf", "url": "https://cdn.example.com/f1"});
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/files/f1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&file))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DriveClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let result = c.get_file("f1").await.unwrap();
|
||
|
|
assert_eq!(result.id, "f1");
|
||
|
|
assert_eq!(result.url.as_deref(), Some("https://cdn.example.com/f1"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn drive_upload_file() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "f-new", "name": "upload.txt", "size": 256});
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/files/"))
|
||
|
|
.respond_with(ResponseTemplate::new(201).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DriveClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"name": "upload.txt"});
|
||
|
|
let result = c.upload_file(&body).await.unwrap();
|
||
|
|
assert_eq!(result.id, "f-new");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn drive_delete_file() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
Mock::given(method("DELETE"))
|
||
|
|
.and(path("/files/f1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(204))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DriveClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
c.delete_file("f1").await.unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn drive_list_folders() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "fld1", "name": "Documents", "parent_id": null}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/folders/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DriveClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_folders(None).await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].name.as_deref(), Some("Documents"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn drive_list_folders_paginated() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "fld2"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/folders/"))
|
||
|
|
.and(query_param("page", "2"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DriveClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_folders(Some(2)).await.unwrap();
|
||
|
|
assert_eq!(page.results[0].id, "fld2");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn drive_create_folder() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "fld-new", "name": "Archive"});
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/folders/"))
|
||
|
|
.respond_with(ResponseTemplate::new(201).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DriveClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"name": "Archive"});
|
||
|
|
let result = c.create_folder(&body).await.unwrap();
|
||
|
|
assert_eq!(result.id, "fld-new");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn drive_share_file() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "sh1", "file_id": "f1", "user_id": "u1", "role": "viewer"});
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/files/f1/shares/"))
|
||
|
|
.respond_with(ResponseTemplate::new(201).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DriveClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"user_id": "u1", "role": "viewer"});
|
||
|
|
let result = c.share_file("f1", &body).await.unwrap();
|
||
|
|
assert_eq!(result.id, "sh1");
|
||
|
|
assert_eq!(result.role.as_deref(), Some("viewer"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn drive_get_permissions() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "perm1", "file_id": "f1", "can_read": true, "can_write": false}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/files/f1/permissions/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = DriveClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.get_permissions("f1").await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].can_read, Some(true));
|
||
|
|
assert_eq!(page.results[0].can_write, Some(false));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn drive_connect_and_with_token() {
|
||
|
|
let c = DriveClient::connect("example.com").with_token("my-tok");
|
||
|
|
assert_eq!(c.base_url(), "https://drive.example.com/api/v1.0");
|
||
|
|
assert_eq!(c.service_name(), "drive");
|
||
|
|
}
|
||
|
|
|
||
|
|
// =========================================================================
|
||
|
|
// MessagesClient
|
||
|
|
// =========================================================================
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn messages_list_mailboxes() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "mb1", "email": "alice@example.com", "display_name": "Alice"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/mailboxes/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MessagesClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_mailboxes().await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].email.as_deref(), Some("alice@example.com"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn messages_get_mailbox() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let mb = serde_json::json!({"id": "mb1", "email": "alice@example.com", "display_name": "Alice"});
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/mailboxes/mb1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&mb))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MessagesClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let result = c.get_mailbox("mb1").await.unwrap();
|
||
|
|
assert_eq!(result.id, "mb1");
|
||
|
|
assert_eq!(result.display_name.as_deref(), Some("Alice"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn messages_list_messages() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({
|
||
|
|
"id": "msg1", "subject": "Hello", "from_address": "bob@example.com",
|
||
|
|
"to_addresses": ["alice@example.com"], "is_read": false
|
||
|
|
}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/mailboxes/mb1/messages/"))
|
||
|
|
.and(query_param("folder", "inbox"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MessagesClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_messages("mb1", "inbox").await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].subject.as_deref(), Some("Hello"));
|
||
|
|
assert_eq!(page.results[0].is_read, Some(false));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn messages_get_message() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let msg = serde_json::json!({
|
||
|
|
"id": "msg1", "subject": "Hello", "body": "Hi Alice",
|
||
|
|
"from_address": "bob@example.com", "folder": "inbox"
|
||
|
|
});
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/mailboxes/mb1/messages/msg1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&msg))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MessagesClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let result = c.get_message("mb1", "msg1").await.unwrap();
|
||
|
|
assert_eq!(result.id, "msg1");
|
||
|
|
assert_eq!(result.body.as_deref(), Some("Hi Alice"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn messages_send_message() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({
|
||
|
|
"id": "msg-new", "subject": "Re: Hello",
|
||
|
|
"to_addresses": ["bob@example.com"], "folder": "sent"
|
||
|
|
});
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/mailboxes/mb1/messages/"))
|
||
|
|
.respond_with(ResponseTemplate::new(201).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MessagesClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"subject": "Re: Hello", "to_addresses": ["bob@example.com"], "body": "Thanks!"});
|
||
|
|
let result = c.send_message("mb1", &body).await.unwrap();
|
||
|
|
assert_eq!(result.id, "msg-new");
|
||
|
|
assert_eq!(result.folder.as_deref(), Some("sent"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn messages_list_folders() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "fld1", "name": "inbox", "message_count": 42, "unread_count": 5}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/mailboxes/mb1/folders/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MessagesClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_folders("mb1").await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].message_count, Some(42));
|
||
|
|
assert_eq!(page.results[0].unread_count, Some(5));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn messages_list_contacts() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "mc1", "email": "charlie@example.com", "display_name": "Charlie"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/mailboxes/mb1/contacts/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = MessagesClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_contacts("mb1").await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].display_name.as_deref(), Some("Charlie"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn messages_connect_and_with_token() {
|
||
|
|
let c = MessagesClient::connect("example.com").with_token("my-tok");
|
||
|
|
assert_eq!(c.base_url(), "https://mail.example.com/api/v1.0");
|
||
|
|
assert_eq!(c.service_name(), "messages");
|
||
|
|
}
|
||
|
|
|
||
|
|
// =========================================================================
|
||
|
|
// CalendarsClient
|
||
|
|
// =========================================================================
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn calendars_list_calendars() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "cal1", "name": "Work", "color": "#0000ff", "is_default": true}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/calendars/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = CalendarsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_calendars().await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].name.as_deref(), Some("Work"));
|
||
|
|
assert_eq!(page.results[0].is_default, Some(true));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn calendars_get_calendar() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let cal = serde_json::json!({"id": "cal1", "name": "Work", "description": "Work calendar"});
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/calendars/cal1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&cal))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = CalendarsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let result = c.get_calendar("cal1").await.unwrap();
|
||
|
|
assert_eq!(result.id, "cal1");
|
||
|
|
assert_eq!(result.description.as_deref(), Some("Work calendar"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn calendars_create_calendar() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "cal-new", "name": "Personal", "color": "#ff0000"});
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/calendars/"))
|
||
|
|
.respond_with(ResponseTemplate::new(201).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = CalendarsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"name": "Personal", "color": "#ff0000"});
|
||
|
|
let result = c.create_calendar(&body).await.unwrap();
|
||
|
|
assert_eq!(result.id, "cal-new");
|
||
|
|
assert_eq!(result.color.as_deref(), Some("#ff0000"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn calendars_list_events() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({
|
||
|
|
"id": "ev1", "title": "Standup", "start": "2026-03-21T09:00:00Z",
|
||
|
|
"end": "2026-03-21T09:30:00Z", "all_day": false
|
||
|
|
}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/calendars/cal1/events/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = CalendarsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.list_events("cal1").await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].title.as_deref(), Some("Standup"));
|
||
|
|
assert_eq!(page.results[0].all_day, Some(false));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn calendars_get_event() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let ev = serde_json::json!({
|
||
|
|
"id": "ev1", "title": "Standup", "location": "Room A",
|
||
|
|
"attendees": ["alice@example.com", "bob@example.com"]
|
||
|
|
});
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/calendars/cal1/events/ev1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&ev))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = CalendarsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let result = c.get_event("cal1", "ev1").await.unwrap();
|
||
|
|
assert_eq!(result.id, "ev1");
|
||
|
|
assert_eq!(result.location.as_deref(), Some("Room A"));
|
||
|
|
assert_eq!(result.attendees.as_ref().unwrap().len(), 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn calendars_create_event() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({
|
||
|
|
"id": "ev-new", "title": "Lunch", "start": "2026-03-21T12:00:00Z",
|
||
|
|
"end": "2026-03-21T13:00:00Z", "calendar_id": "cal1"
|
||
|
|
});
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/calendars/cal1/events/"))
|
||
|
|
.respond_with(ResponseTemplate::new(201).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = CalendarsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"title": "Lunch", "start": "2026-03-21T12:00:00Z", "end": "2026-03-21T13:00:00Z"});
|
||
|
|
let result = c.create_event("cal1", &body).await.unwrap();
|
||
|
|
assert_eq!(result.id, "ev-new");
|
||
|
|
assert_eq!(result.calendar_id.as_deref(), Some("cal1"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn calendars_update_event() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let resp = serde_json::json!({"id": "ev1", "title": "Updated Standup", "location": "Room B"});
|
||
|
|
Mock::given(method("PATCH"))
|
||
|
|
.and(path("/calendars/cal1/events/ev1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&resp))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = CalendarsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"title": "Updated Standup", "location": "Room B"});
|
||
|
|
let result = c.update_event("cal1", "ev1", &body).await.unwrap();
|
||
|
|
assert_eq!(result.title.as_deref(), Some("Updated Standup"));
|
||
|
|
assert_eq!(result.location.as_deref(), Some("Room B"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn calendars_delete_event() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
Mock::given(method("DELETE"))
|
||
|
|
.and(path("/calendars/cal1/events/ev1/"))
|
||
|
|
.respond_with(ResponseTemplate::new(204))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = CalendarsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
c.delete_event("cal1", "ev1").await.unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn calendars_rsvp() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
Mock::given(method("POST"))
|
||
|
|
.and(path("/calendars/cal1/events/ev1/rsvp/"))
|
||
|
|
.respond_with(ResponseTemplate::new(200))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = CalendarsClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let body = serde_json::json!({"status": "accepted"});
|
||
|
|
c.rsvp("cal1", "ev1", &body).await.unwrap();
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn calendars_connect_and_with_token() {
|
||
|
|
let c = CalendarsClient::connect("example.com").with_token("my-tok");
|
||
|
|
assert_eq!(c.base_url(), "https://calendar.example.com/api/v1.0");
|
||
|
|
assert_eq!(c.service_name(), "calendars");
|
||
|
|
}
|
||
|
|
|
||
|
|
// =========================================================================
|
||
|
|
// FindClient
|
||
|
|
// =========================================================================
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn find_search() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({
|
||
|
|
"id": "sr1", "title": "Meeting Notes", "description": "Notes from standup",
|
||
|
|
"url": "https://docs.example.com/d/1", "source": "docs", "score": 0.95
|
||
|
|
}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/search/"))
|
||
|
|
.and(query_param("q", "meeting"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = FindClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.search("meeting", None).await.unwrap();
|
||
|
|
assert_eq!(page.count, 1);
|
||
|
|
assert_eq!(page.results[0].title.as_deref(), Some("Meeting Notes"));
|
||
|
|
assert_eq!(page.results[0].score, Some(0.95));
|
||
|
|
assert_eq!(page.results[0].source.as_deref(), Some("docs"));
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn find_search_paginated() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = drf_page(serde_json::json!({"id": "sr2", "title": "Budget Report"}));
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/search/"))
|
||
|
|
.and(query_param("q", "budget"))
|
||
|
|
.and(query_param("page", "3"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = FindClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.search("budget", Some(3)).await.unwrap();
|
||
|
|
assert_eq!(page.results[0].id, "sr2");
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn find_search_empty() {
|
||
|
|
let server = MockServer::start().await;
|
||
|
|
let body = empty_page();
|
||
|
|
Mock::given(method("GET"))
|
||
|
|
.and(path("/search/"))
|
||
|
|
.and(query_param("q", "nonexistent"))
|
||
|
|
.respond_with(ResponseTemplate::new(200).set_body_json(&body))
|
||
|
|
.mount(&server).await;
|
||
|
|
|
||
|
|
let c = FindClient::from_parts(server.uri(), AuthMethod::Bearer("tok".into()));
|
||
|
|
let page = c.search("nonexistent", None).await.unwrap();
|
||
|
|
assert_eq!(page.count, 0);
|
||
|
|
assert!(page.results.is_empty());
|
||
|
|
}
|
||
|
|
|
||
|
|
#[tokio::test]
|
||
|
|
async fn find_connect_and_with_token() {
|
||
|
|
let c = FindClient::connect("example.com").with_token("my-tok");
|
||
|
|
assert_eq!(c.base_url(), "https://find.example.com/api/v1.0");
|
||
|
|
assert_eq!(c.service_name(), "find");
|
||
|
|
}
|