keeper-secrets-manager-core 17.3.0

Rust SDK for Keeper Secrets Manager
Documentation
// Manual Integration Test 6: Disaster Recovery Caching
//
// This test validates:
// - make_caching_post_function (recommended safe API — reuses one pre-built reqwest Client)
// - Cache save on success
// - Cache fallback on failure
// - Cache file operations
//
// Run with: cargo run --example 06_caching_function
//
// Prerequisites:
// - Run 01_initialize_and_get_secrets first

use keeper_secrets_manager_core::{
    caching,
    core::{ClientOptions, SecretsManager},
    custom_error::KSMRError,
    storage::FileKeyValueStorage,
};

fn main() -> Result<(), KSMRError> {
    println!("=== Manual Integration Test 6: Disaster Recovery Caching ===\n");

    // Clear any existing cache
    println!("Clearing existing cache...");
    caching::clear_cache().ok();
    println!("Cache cleared: {}", !caching::cache_exists());

    // Initialize with caching function
    let config = FileKeyValueStorage::new_config_storage("test_config.json".to_string())?;
    let mut client_options = ClientOptions::new_client_options(config);

    // Build the reqwest client once outside any async context so it is safe under
    // tokio::task::spawn_blocking. See caching::make_caching_post_function for details.
    let client = reqwest::blocking::Client::builder()
        .build()
        .expect("build reqwest client");

    println!("\nEnabling disaster recovery caching...");
    client_options.set_custom_post_function(caching::make_caching_post_function(client));

    let mut secrets_manager = SecretsManager::new(client_options)?;

    // First call - should save to cache
    println!("First API call (should save to cache)...");
    let secrets = secrets_manager.get_secrets(Vec::new())?;
    println!("✅ Retrieved {} secrets", secrets.len());

    // Check if cache was created
    let cache_path = caching::get_cache_file_path();
    println!("\nChecking cache...");
    println!("Cache path: {:?}", cache_path);
    println!("Cache exists: {}", caching::cache_exists());

    if caching::cache_exists() {
        println!("✅ Cache file created successfully");

        // Get cache size
        if let Ok(metadata) = std::fs::metadata(&cache_path) {
            println!("Cache size: {} bytes", metadata.len());
        }
    } else {
        println!("⚠️ Cache file not created");
    }

    // Test cache loading
    println!("\nTesting cache data retrieval...");
    if let Some(cached_data) = caching::get_cached_data() {
        println!("✅ Cache loaded: {} bytes", cached_data.len());
        println!("   First 32 bytes: transmission key");
        println!("   Remaining bytes: encrypted response");
    } else {
        println!("⚠️ Failed to load cache");
    }

    // NOTE: To test fallback on network failure, you would need to:
    // 1. Disconnect from network
    // 2. Make another get_secrets() call
    // 3. It should return cached data instead of network error
    //
    // This is difficult to test automatically, so we just verify the cache
    // save mechanism works correctly.

    println!("\n=== Cache Function Validation ===");
    println!("✅ make_caching_post_function() can be set");
    println!("✅ Cache saves on successful API call");
    println!("✅ Cache file accessible via get_cached_data()");
    println!("✅ Cache can be cleared via clear_cache()");

    // Clean up
    println!("\nCleaning up cache file...");
    caching::clear_cache().ok();
    println!("✅ Cache cleared");

    Ok(())
}