#[cfg(test)]
use crate::access::accesses::*;
use serde_json::json;
use wiremock::{
Mock, MockServer, ResponseTemplate,
matchers::{header, method, path},
};
#[test]
fn access_resource_access_level_new() {
let access_level = AccessResourceAccessLevel::new(1000).unwrap();
assert_eq!(access_level, AccessResourceAccessLevel::Owner);
}
#[test]
fn access_resource_access_level_to_int() {
let access_level = AccessResourceAccessLevel::Owner;
assert_eq!(access_level.to_int(), 1000);
}
#[test]
fn access_resource_access_level_from_int() {
let access_level = AccessResourceAccessLevel::from_int(1000).unwrap();
assert_eq!(access_level, AccessResourceAccessLevel::Owner);
}
#[test]
fn access_resource_access_level_to_string() {
let access_level = AccessResourceAccessLevel::Owner;
assert_eq!(access_level.to_string(), "owner");
}
#[test]
fn access_resource_access_level_from_string() {
let access_level = AccessResourceAccessLevel::from_string("1000".to_string());
assert!(access_level.is_ok());
assert_eq!(access_level.unwrap(), AccessResourceAccessLevel::Owner);
}
#[test]
fn access_resource_access_level_from_string_invalid() {
let access_level = AccessResourceAccessLevel::from_string("invalid".to_string());
assert!(access_level.is_err());
}
#[test]
fn access_resource_access_level_from_string_with_invalid_access_level() {
let access_level = AccessResourceAccessLevel::from_string("1001".to_string());
assert!(access_level.is_err());
}
#[test]
fn access_resource_access_level_from_str() {
let access_level = AccessResourceAccessLevel::from_str("1000");
assert!(access_level.is_ok());
assert_eq!(access_level.unwrap(), AccessResourceAccessLevel::Owner);
}
#[test]
fn access_resource_access_level_from_str_with_invalid() {
let access_level = AccessResourceAccessLevel::from_str("invalid");
assert!(access_level.is_err());
}
#[test]
fn access_resource_access_level_from_str_with_invalid_access_level() {
let access_level = AccessResourceAccessLevel::from_str("1001");
assert!(access_level.is_err());
}
#[test]
fn access_resource_access_level_serialize() {
let access_level = AccessResourceAccessLevel::Owner;
let serialized = serde_json::to_string(&access_level).unwrap();
assert_eq!(serialized, "1000");
}
#[test]
fn access_resource_access_level_deserialize() {
let access_level = 1000;
let deserialized: AccessResourceAccessLevel =
serde_json::from_value(json!(access_level)).unwrap();
assert_eq!(deserialized, AccessResourceAccessLevel::Owner);
}
#[cfg(test)]
fn new_list_response() -> String {
json!(vec![AccessRecord {
id: 1,
specifier_type: AccessSpecifierType::User,
specifier: AccessSpecifier {
id: 1,
email: "test@example.com".to_string(),
name: "test".to_string(),
two_factor_authentication_enabled: false,
},
resources: vec![AccessResource {
resource_id: 1,
resource_type: AccessResourceType::Account,
access_level: AccessResourceAccessLevel::Owner,
}],
permissions: AccessPermission {
can_read: true,
can_update: true,
can_destroy: true,
can_leave: true,
},
},])
.to_string()
}
#[cfg(test)]
fn new_remove_response() -> String {
json!(AccessRemoveResponse { id: 1 }).to_string()
}
#[tokio::test]
async fn access_list_fails_with_no_api_key_or_bearer_token() {
let access = Access::new();
let result = access
.list(None, None, None, "1234567890", None, None, None)
.await;
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"API key or bearer token is required"
);
}
#[tokio::test]
async fn access_list_fails_with_empty_account_id() {
let access = Access::new();
let result = access
.list(None, Some("1234"), None, "", None, None, None)
.await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Account ID is empty");
}
#[tokio::test]
async fn access_list_fails_with_empty_domain_ids() {
let access = Access::new();
let result = access
.list(
None,
Some("1234"),
None,
"1234567890",
Some(vec![]),
None,
None,
)
.await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Domain IDs are empty");
let result = access
.list(
None,
Some("1234"),
None,
"1234567890",
Some(vec![""]),
None,
None,
)
.await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Domain IDs are empty");
}
#[tokio::test]
async fn access_list_fails_with_empty_inbox_ids() {
let access = Access::new();
let result = access
.list(
None,
Some("1234"),
None,
"1234567890",
None,
Some(vec![]),
None,
)
.await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Inbox IDs are empty");
let result = access
.list(
None,
Some("1234"),
None,
"1234567890",
None,
Some(vec![""]),
None,
)
.await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Inbox IDs are empty");
}
#[tokio::test]
async fn access_list_fails_with_empty_project_ids() {
let access = Access::new();
let result = access
.list(
None,
Some("1234"),
None,
"1234567890",
None,
None,
Some(vec![]),
)
.await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Project IDs are empty");
let result = access
.list(
None,
Some("1234"),
None,
"1234567890",
None,
None,
Some(vec![""]),
)
.await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Project IDs are empty");
}
#[tokio::test]
async fn access_list_fails_with_empty_api_url() {
let access = Access::new();
let result = access
.list(Some(""), Some("1234"), None, "1234567890", None, None, None)
.await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "URL is empty");
}
#[tokio::test]
async fn access_list_fails_with_empty_bad_api_url() {
let access = Access::new();
let result = access
.list(
Some("invalid"),
Some("1234"),
None,
"1234567890",
None,
None,
None,
)
.await;
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"Failed to parse URL: relative URL without a base"
);
}
#[tokio::test]
async fn access_list_succeeds_with_200() {
let mock_server = MockServer::start().await;
let url = mock_server.uri();
let access = Access::new();
let response_body = new_list_response();
let response_template =
ResponseTemplate::new(200).set_body_bytes(response_body.as_bytes().to_vec());
let account_id = "1234567890";
let expected: Vec<AccessRecord> = serde_json::from_slice(&response_body.as_bytes()).unwrap();
Mock::given(method("GET"))
.and(path(
format!("/api/accounts/{}/account_access", account_id).as_str(),
))
.and(header("Api-Token", "1234"))
.respond_with(response_template)
.expect(1)
.mount(&mock_server)
.await;
let result = access
.list(
Some(url.as_str()),
Some("1234"),
None,
account_id,
None,
None,
None,
)
.await;
assert!(result.is_ok());
let records = result.unwrap();
assert!(!records.is_empty());
assert_eq!(records, expected);
}
#[tokio::test]
async fn access_list_fails_with_401() {
let mock_server = MockServer::start().await;
let url = mock_server.uri();
let access = Access::new();
let account_id = "1234567890";
let response_body = AccessErrorResponse {
error: "Unauthorized".to_string(),
};
let response_template = ResponseTemplate::new(401).set_body_json(response_body);
Mock::given(method("GET"))
.and(path(
format!("/api/accounts/{}/account_access", account_id).as_str(),
))
.and(header("Api-Token", "1234"))
.respond_with(response_template)
.expect(1)
.mount(&mock_server)
.await;
let result = access
.list(
Some(url.as_str()),
Some("1234"),
None,
account_id,
None,
None,
None,
)
.await;
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"Failed to get access list: Unauthorized"
);
}
#[tokio::test]
async fn access_list_fails_with_403() {
let mock_server = MockServer::start().await;
let url = mock_server.uri();
let access = Access::new();
let account_id = "1234567890";
let response_body = AccessErrorsResponse {
errors: vec!["Forbidden".to_string()],
};
let response_template = ResponseTemplate::new(403).set_body_json(response_body);
Mock::given(method("GET"))
.and(path(
format!("/api/accounts/{}/account_access", account_id).as_str(),
))
.and(header("Api-Token", "1234"))
.respond_with(response_template)
.expect(1)
.mount(&mock_server)
.await;
let result = access
.list(
Some(url.as_str()),
Some("1234"),
None,
account_id,
None,
None,
None,
)
.await;
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"Failed to get access list: Forbidden"
);
}
#[tokio::test]
async fn access_remove_fails_with_no_api_key_or_bearer_token() {
let access = Access::new();
let result = access
.remove(None, None, None, "1234567890", "1234567890")
.await;
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"API key or bearer token is required"
);
}
#[tokio::test]
async fn access_remove_fails_with_empty_api_key() {
let access = Access::new();
let result = access
.remove(None, Some(""), None, "1234567890", "1234567890")
.await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "API key is empty");
}
#[tokio::test]
async fn access_remove_fails_with_empty_bearer_token() {
let access = Access::new();
let result = access
.remove(None, None, Some(""), "1234567890", "1234567890")
.await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Bearer token is empty");
}
#[tokio::test]
async fn access_remove_fails_with_empty_account_id() {
let access = Access::new();
let result = access
.remove(None, Some("1234"), None, "", "1234567890")
.await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "Account ID is empty");
}
#[tokio::test]
async fn access_remove_fails_with_empty_account_access_id() {
let access = Access::new();
let result = access
.remove(None, Some("1234"), None, "1234567890", "")
.await;
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"Account access ID is empty"
);
}
#[tokio::test]
async fn access_remove_fails_with_empty_url() {
let access = Access::new();
let result = access
.remove(Some(""), Some("1234"), None, "1234567890", "1234567890")
.await;
assert!(result.is_err());
assert_eq!(result.unwrap_err().to_string(), "URL is empty");
}
#[tokio::test]
async fn access_remove_fails_with_401() {
let mock_server = MockServer::start().await;
let url = mock_server.uri();
let access = Access::new();
let account_id = "1234567890";
let account_access_id = "1234567890";
let response_body = AccessErrorResponse {
error: "Unauthorized".to_string(),
};
let response_template = ResponseTemplate::new(401).set_body_json(response_body);
Mock::given(method("DELETE"))
.and(path(
format!(
"/api/accounts/{}/account_accesses/{}",
account_id, account_access_id
)
.as_str(),
))
.and(header("Api-Token", "1234"))
.respond_with(response_template)
.expect(1)
.mount(&mock_server)
.await;
let result = access
.remove(
Some(url.as_str()),
Some("1234"),
None,
account_id,
account_access_id,
)
.await;
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"Failed to remove access: Unauthorized"
);
}
#[tokio::test]
async fn access_remove_fails_with_403() {
let mock_server = MockServer::start().await;
let url = mock_server.uri();
let access = Access::new();
let account_id = "1234567890";
let account_access_id = "1234567890";
let response_body = AccessErrorsResponse {
errors: vec!["Forbidden".to_string()],
};
let response_template = ResponseTemplate::new(403).set_body_json(response_body);
Mock::given(method("DELETE"))
.and(path(
format!(
"/api/accounts/{}/account_accesses/{}",
account_id, account_access_id
)
.as_str(),
))
.and(header("Api-Token", "1234"))
.respond_with(response_template)
.expect(1)
.mount(&mock_server)
.await;
let result = access
.remove(
Some(url.as_str()),
Some("1234"),
None,
account_id,
account_access_id,
)
.await;
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"Failed to remove access: Forbidden"
);
}
#[tokio::test]
async fn access_remove_fails_with_404() {
let mock_server = MockServer::start().await;
let url = mock_server.uri();
let access = Access::new();
let account_id = "1234567890";
let account_access_id = "1234567890";
let response_body = AccessErrorResponse {
error: "Not Found".to_string(),
};
let response_template = ResponseTemplate::new(404).set_body_json(response_body);
Mock::given(method("DELETE"))
.and(path(
format!(
"/api/accounts/{}/account_accesses/{}",
account_id, account_access_id
)
.as_str(),
))
.and(header("Api-Token", "1234"))
.respond_with(response_template)
.expect(1)
.mount(&mock_server)
.await;
let result = access
.remove(
Some(url.as_str()),
Some("1234"),
None,
account_id,
account_access_id,
)
.await;
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"Failed to remove access: Not Found"
);
}
#[tokio::test]
async fn access_remove_succeeds_with_200() {
let mock_server = MockServer::start().await;
let url = mock_server.uri();
let access = Access::new();
let account_id = "1234567890";
let account_access_id = "1234567890";
let response_body = new_remove_response();
let response_template =
ResponseTemplate::new(200).set_body_bytes(response_body.as_bytes().to_vec());
Mock::given(method("DELETE"))
.and(path(
format!(
"/api/accounts/{}/account_accesses/{}",
account_id, account_access_id
)
.as_str(),
))
.and(header("Api-Token", "1234"))
.respond_with(response_template)
.expect(1)
.mount(&mock_server)
.await;
let result = access
.remove(
Some(url.as_str()),
Some("1234"),
None,
account_id,
account_access_id,
)
.await;
assert!(result.is_ok());
let response = result.unwrap();
let expected: AccessRemoveResponse = serde_json::from_slice(&response_body.as_bytes()).unwrap();
assert_eq!(response, expected);
}