redis-cloud 0.9.5

Redis Cloud REST API client library
Documentation
//! OpenAPI Specification Validation Tests
//!
//! This test suite validates that our implementation matches the official
//! Redis Cloud OpenAPI specification.

use serde_json::Value;
use std::collections::HashSet;

const OPENAPI_SPEC: &str = include_str!("fixtures/cloud_openapi.json");

#[test]
fn test_openapi_spec_loads() {
    let spec: Value = serde_json::from_str(OPENAPI_SPEC).expect("Failed to parse OpenAPI spec");

    assert!(spec.get("openapi").is_some(), "OpenAPI version missing");
    assert!(spec.get("paths").is_some(), "Paths missing from spec");
    assert!(
        spec.get("components").is_some(),
        "Components missing from spec"
    );
}

#[test]
fn test_all_endpoints_documented() {
    let spec: Value = serde_json::from_str(OPENAPI_SPEC).unwrap();
    let paths = spec["paths"].as_object().unwrap();

    // Count total endpoints
    let mut endpoint_count = 0;
    for (_path, methods) in paths {
        let methods_obj = methods.as_object().unwrap();
        for method in methods_obj.keys() {
            if matches!(method.as_str(), "get" | "post" | "put" | "delete" | "patch") {
                endpoint_count += 1;
            }
        }
    }

    // The OpenAPI spec in our repo has 130 endpoints
    // (Note: The spec we analyzed from redis.io had 140, but this is the version we have)
    assert!(
        endpoint_count >= 130,
        "Expected at least 130 endpoints in OpenAPI spec, found {}",
        endpoint_count
    );
}

#[test]
fn test_schema_definitions_complete() {
    let spec: Value = serde_json::from_str(OPENAPI_SPEC).unwrap();
    let schemas = spec["components"]["schemas"].as_object().unwrap();

    // Key response types we use
    let required_schemas = vec![
        "CloudAccount",
        "Database",
        "Subscription",
        "ACLUser",
        "AccountUser",
        "TaskStateUpdate",
        "ProcessorResponse",
    ];

    for schema_name in required_schemas {
        assert!(
            schemas.contains_key(schema_name),
            "Schema '{}' missing from OpenAPI spec",
            schema_name
        );
    }
}

#[test]
fn test_endpoint_categories() {
    let spec: Value = serde_json::from_str(OPENAPI_SPEC).unwrap();
    let paths = spec["paths"].as_object().unwrap();

    // Collect all tags (categories)
    let mut tags = HashSet::new();
    for (_path, methods) in paths {
        let methods_obj = methods.as_object().unwrap();
        for (_method, operation) in methods_obj {
            if let Some(op_tags) = operation.get("tags").and_then(|t| t.as_array()) {
                for tag in op_tags {
                    if let Some(tag_str) = tag.as_str() {
                        tags.insert(tag_str.to_string());
                    }
                }
            }
        }
    }

    // Expected categories from our coverage audit
    let expected_categories = vec![
        "Account",
        "Cloud Accounts",
        "Databases - Pro",
        "Databases - Essentials",
        "Subscriptions - Pro",
        "Subscriptions - Essentials",
        "Role-based Access Control (RBAC)",
        "Tasks",
        "Users",
    ];

    for category in expected_categories {
        assert!(
            tags.contains(category),
            "Expected category '{}' not found in spec",
            category
        );
    }
}

#[test]
fn test_response_type_field_coverage() {
    let spec: Value = serde_json::from_str(OPENAPI_SPEC).unwrap();
    let schemas = spec["components"]["schemas"].as_object().unwrap();

    // Test CloudAccount has required fields
    let cloud_account = &schemas["CloudAccount"];
    let properties = cloud_account["properties"].as_object().unwrap();

    // Core fields that are always present
    assert!(
        properties.contains_key("id"),
        "CloudAccount missing id field"
    );
    assert!(
        properties.contains_key("name"),
        "CloudAccount missing name field"
    );
    assert!(
        properties.contains_key("provider"),
        "CloudAccount missing provider field"
    );

    // Note: AWS-specific fields (awsConsoleRoleArn, awsUserArn) may not be in all
    // versions of the spec, but we support them in our implementation

    // Test other key types
    let processor_response = &schemas["ProcessorResponse"];
    let pr_props = processor_response["properties"].as_object().unwrap();
    assert_eq!(
        pr_props.len(),
        5,
        "ProcessorResponse should have 5 properties"
    );

    let task_state = &schemas["TaskStateUpdate"];
    let ts_props = task_state["properties"].as_object().unwrap();
    assert_eq!(
        ts_props.len(),
        7,
        "TaskStateUpdate should have 7 properties"
    );
}