lmrc-cloudflare 0.3.16

Cloudflare API client library for the LMRC Stack - comprehensive DNS, zones, and cache management with automatic retry logic
Documentation
use lmrc_cloudflare::CloudflareClient;
use wiremock::matchers::{header, method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};

#[tokio::test]
async fn test_purge_everything() {
    let mock_server = MockServer::start().await;

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": {
            "id": "purge-all-id"
        }
    }"#;

    Mock::given(method("POST"))
        .and(path("/zones/zone123/purge_cache"))
        .and(header("authorization", "Bearer test-token"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    client.cache().purge_everything("zone123").await.unwrap();
}

#[tokio::test]
async fn test_purge_urls() {
    let mock_server = MockServer::start().await;

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": {
            "id": "purge-urls-id"
        }
    }"#;

    Mock::given(method("POST"))
        .and(path("/zones/zone123/purge_cache"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    client
        .cache()
        .purge_urls("zone123")
        .urls(vec![
            "https://example.com/page1",
            "https://example.com/page2",
        ])
        .send()
        .await
        .unwrap();
}

#[tokio::test]
async fn test_purge_urls_limit() {
    let client = CloudflareClient::builder()
        .api_token("test-token")
        .build()
        .unwrap();

    let urls: Vec<String> = (0..31)
        .map(|i| format!("https://example.com/page{}", i))
        .collect();

    let result = client.cache().purge_urls("zone123").urls(urls).send().await;

    assert!(result.is_err());
    match result.unwrap_err() {
        lmrc_cloudflare::Error::InvalidInput(msg) => {
            assert!(msg.contains("30 URLs"));
        }
        e => panic!("Expected InvalidInput error, got: {:?}", e),
    }
}

#[tokio::test]
async fn test_purge_tags() {
    let mock_server = MockServer::start().await;

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": {
            "id": "purge-tags-id"
        }
    }"#;

    Mock::given(method("POST"))
        .and(path("/zones/zone123/purge_cache"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    client
        .cache()
        .purge_tags("zone123")
        .tags(vec!["tag1", "tag2"])
        .send()
        .await
        .unwrap();
}

#[tokio::test]
async fn test_purge_tags_limit() {
    let client = CloudflareClient::builder()
        .api_token("test-token")
        .build()
        .unwrap();

    let tags: Vec<String> = (0..31).map(|i| format!("tag{}", i)).collect();

    let result = client.cache().purge_tags("zone123").tags(tags).send().await;

    assert!(result.is_err());
    match result.unwrap_err() {
        lmrc_cloudflare::Error::InvalidInput(msg) => {
            assert!(msg.contains("30 tags"));
        }
        e => panic!("Expected InvalidInput error, got: {:?}", e),
    }
}

#[tokio::test]
async fn test_purge_hosts() {
    let mock_server = MockServer::start().await;

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": {
            "id": "purge-hosts-id"
        }
    }"#;

    Mock::given(method("POST"))
        .and(path("/zones/zone123/purge_cache"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    client
        .cache()
        .purge_hosts("zone123")
        .hosts(vec!["example.com", "www.example.com"])
        .send()
        .await
        .unwrap();
}

#[tokio::test]
async fn test_purge_hosts_limit() {
    let client = CloudflareClient::builder()
        .api_token("test-token")
        .build()
        .unwrap();

    let hosts: Vec<String> = (0..31).map(|i| format!("host{}.example.com", i)).collect();

    let result = client
        .cache()
        .purge_hosts("zone123")
        .hosts(hosts)
        .send()
        .await;

    assert!(result.is_err());
    match result.unwrap_err() {
        lmrc_cloudflare::Error::InvalidInput(msg) => {
            assert!(msg.contains("30 hosts"));
        }
        e => panic!("Expected InvalidInput error, got: {:?}", e),
    }
}

#[tokio::test]
async fn test_purge_prefixes() {
    let mock_server = MockServer::start().await;

    let response_body = r#"{
        "success": true,
        "errors": [],
        "messages": [],
        "result": {
            "id": "purge-prefixes-id"
        }
    }"#;

    Mock::given(method("POST"))
        .and(path("/zones/zone123/purge_cache"))
        .respond_with(ResponseTemplate::new(200).set_body_string(response_body))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    client
        .cache()
        .purge_prefixes("zone123")
        .prefixes(vec!["example.com/images/", "example.com/css/"])
        .send()
        .await
        .unwrap();
}

#[tokio::test]
async fn test_purge_prefixes_limit() {
    let client = CloudflareClient::builder()
        .api_token("test-token")
        .build()
        .unwrap();

    let prefixes: Vec<String> = (0..31)
        .map(|i| format!("example.com/prefix{}/", i))
        .collect();

    let result = client
        .cache()
        .purge_prefixes("zone123")
        .prefixes(prefixes)
        .send()
        .await;

    assert!(result.is_err());
    match result.unwrap_err() {
        lmrc_cloudflare::Error::InvalidInput(msg) => {
            assert!(msg.contains("30 prefixes"));
        }
        e => panic!("Expected InvalidInput error, got: {:?}", e),
    }
}

#[tokio::test]
async fn test_cache_purge_error_handling() {
    let mock_server = MockServer::start().await;

    let error_response = r#"{
        "success": false,
        "errors": [
            {
                "code": 1003,
                "message": "Invalid zone identifier"
            }
        ],
        "messages": [],
        "result": null
    }"#;

    Mock::given(method("POST"))
        .and(path("/zones/invalid/purge_cache"))
        .respond_with(ResponseTemplate::new(400).set_body_string(error_response))
        .mount(&mock_server)
        .await;

    let client = CloudflareClient::builder()
        .api_token("test-token")
        .base_url(mock_server.uri())
        .build()
        .unwrap();

    let result = client.cache().purge_everything("invalid").await;

    assert!(result.is_err());
}