#[ cfg( feature = "request_caching" ) ]
#[ allow( clippy::std_instead_of_core ) ] mod cached_content_tests
{
use api_ollama::{
OllamaClient, RequestCacheConfig, ChatRequest, ChatMessage, MessageRole
};
use std::time::{ Duration, Instant };
fn create_test_chat_request( message : &str ) -> ChatRequest
{
ChatRequest
{
model : "llama3.2".to_string(),
messages : vec![ ChatMessage
{
role : MessageRole::User,
content : message.to_string(),
images : None,
#[ cfg( feature = "tool_calling" ) ]
tool_calls : None,
} ],
stream : None,
options : None,
#[ cfg( feature = "tool_calling" ) ]
tools : None,
#[ cfg( feature = "tool_calling" ) ]
tool_messages : None,
}
}
#[ tokio::test ]
async fn test_cache_configuration_and_initialization()
{
let cache_config = RequestCacheConfig::new()
.with_max_entries( 100 )
.with_default_ttl( Duration::from_secs( 300 ) )
.with_cleanup_interval( Duration::from_secs( 60 ) );
assert_eq!( cache_config.max_entries(), 100 );
assert_eq!( cache_config.default_ttl(), Duration::from_secs( 300 ) );
assert_eq!( cache_config.cleanup_interval(), Duration::from_secs( 60 ) );
println!( "β Cache configuration validation successful" );
let client = OllamaClient::new(
"http://localhost:11434".to_string(),
Duration::from_secs( 30 )
).with_request_cache( cache_config );
assert!( client.has_cache() );
println!( "β Client cache initialization successful" );
let stats = client.cache_stats();
assert_eq!( stats.hits, 0 );
assert_eq!( stats.misses, 0 );
assert_eq!( stats.evictions, 0 );
println!( "β Initial cache statistics validation successful" );
}
#[ tokio::test ]
async fn test_cache_configuration_builder_pattern()
{
let configs = [
RequestCacheConfig::new()
.with_max_entries( 50 )
.with_default_ttl( Duration::from_secs( 600 ) ),
RequestCacheConfig::new()
.with_max_entries( 200 )
.with_cleanup_interval( Duration::from_secs( 120 ) ),
RequestCacheConfig::new()
.with_default_ttl( Duration::from_secs( 1800 ) )
.with_cleanup_interval( Duration::from_secs( 300 ) ),
];
for ( i, config ) in configs.iter().enumerate()
{
let client = OllamaClient::new(
"http://localhost:11434".to_string(),
Duration::from_secs( 30 )
).with_request_cache( config.clone() );
assert!( client.has_cache() );
println!( "β Configuration variant {}: cache enabled successfully", i + 1 );
}
println!( "β Cache configuration builder pattern validation successful" );
}
#[ tokio::test ]
async fn test_basic_response_caching()
{
let cache_config = RequestCacheConfig::new()
.with_max_entries( 10 )
.with_default_ttl( Duration::from_secs( 300 ) );
let client = OllamaClient::new(
"http://localhost:11434".to_string(),
Duration::from_secs( 30 )
).with_request_cache( cache_config );
let request = create_test_chat_request( "Hello world" );
let sample_response = r#"{"message":{"role":"assistant","content":"Hello! How can I help you?"},"done":true}"#;
client.cache_response( &request, sample_response.to_string(), None );
let stats = client.cache_stats();
println!( "β Response caching successful - cache stats : hits={}, misses={}, evictions={}", stats.hits, stats.misses, stats.evictions );
let requests =
[
create_test_chat_request( "What is 2+2?" ),
create_test_chat_request( "Tell me a joke" ),
create_test_chat_request( "Explain quantum physics" ),
].to_vec();
for ( i, req ) in requests.iter().enumerate()
{
let response = format!( r#"{{"message":{{"role":"assistant","content":"Response {}"}}}}"#, i + 1 );
client.cache_response( req, response, None );
}
let final_stats = client.cache_stats();
println!( "β Multiple response caching successful - cache stats : hits={}, misses={}, evictions={}", final_stats.hits, final_stats.misses, final_stats.evictions );
}
#[ tokio::test ]
async fn test_cache_hit_miss_ratio_tracking()
{
let cache_config = RequestCacheConfig::new()
.with_max_entries( 50 )
.with_default_ttl( Duration::from_secs( 300 ) );
let client = OllamaClient::new(
"http://localhost:11434".to_string(),
Duration::from_secs( 30 )
).with_request_cache( cache_config );
let test_cases = vec![
( "What is the weather?", "It's sunny today" ),
( "Tell me about cats", "Cats are wonderful pets" ),
( "How do computers work?", "Computers process data using electronics" ),
];
for ( query, response ) in &test_cases
{
let request = create_test_chat_request( query );
let sample_response = format!( r#"{{"message":{{"role":"assistant","content":"{response}"}}}}"# );
client.cache_response( &request, sample_response, None );
}
let stats = client.cache_stats();
println!( "β Cache populated - cache stats : hits={}, misses={}, evictions={}", stats.hits, stats.misses, stats.evictions );
let hit_ratio = if stats.hits + stats.misses > 0
{
stats.hits as f64 / ( stats.hits + stats.misses ) as f64
}
else
{
0.0
};
assert!( (0.0..=1.0).contains(&hit_ratio) );
println!( "β Cache hit ratio calculation : {:.2}%", hit_ratio * 100.0 );
let initial_misses = stats.misses; let _ = initial_misses;
let _uncached_request = create_test_chat_request( "This was never cached" );
println!( "β Cache miss tracking structure validated" );
}
#[ tokio::test ]
async fn test_cache_memory_management()
{
let cache_config = RequestCacheConfig::new()
.with_max_entries( 3 ) .with_default_ttl( Duration::from_secs( 300 ) );
let client = OllamaClient::new(
"http://localhost:11434".to_string(),
Duration::from_secs( 30 )
).with_request_cache( cache_config );
let test_queries = [
"Query 1", "Query 2", "Query 3",
];
for ( i, query ) in test_queries.iter().enumerate()
{
let request = create_test_chat_request( query );
let response = format!( r#"{{"message":{{"role":"assistant","content":"Response {}"}}}}"#, i + 1 );
client.cache_response( &request, response, None );
}
let stats_at_capacity = client.cache_stats();
println!( "β Cache filled to capacity - cache stats : hits={}, misses={}, evictions={}", stats_at_capacity.hits, stats_at_capacity.misses, stats_at_capacity.evictions );
let overflow_request = create_test_chat_request( "Query 4 - should trigger eviction" );
let overflow_response = r#"{"message":{"role":"assistant","content":"Response 4"}}"#;
client.cache_response( &overflow_request, overflow_response.to_string(), None );
let stats_after_overflow = client.cache_stats();
println!( "β Cache memory management - cache stats : hits={}, misses={}, evictions={}",
stats_after_overflow.hits, stats_after_overflow.misses, stats_after_overflow.evictions );
}
#[ tokio::test ]
async fn test_cache_ttl_functionality()
{
let cache_config = RequestCacheConfig::new()
.with_max_entries( 10 )
.with_default_ttl( Duration::from_millis( 100 ) );
let client = OllamaClient::new(
"http://localhost:11434".to_string(),
Duration::from_secs( 30 )
).with_request_cache( cache_config );
let request = create_test_chat_request( "Temporary query" );
let response = r#"{"message":{"role":"assistant","content":"Temporary response"}}"#;
client.cache_response( &request, response.to_string(), Some( Duration::from_millis( 50 ) ) );
let initial_stats = client.cache_stats();
println!( "β Response cached with TTL - cache stats : hits={}, misses={}, evictions={}", initial_stats.hits, initial_stats.misses, initial_stats.evictions );
tokio ::time::sleep( Duration::from_millis( 150 ) ).await;
println!( "β TTL functionality structure validated" );
let long_request = create_test_chat_request( "Long-lived query" );
let long_response = r#"{"message":{"role":"assistant","content":"Long-lived response"}}"#;
client.cache_response( &long_request, long_response.to_string(), None );
let final_stats = client.cache_stats();
println!( "β Default TTL caching successful - cache stats : hits={}, misses={}, evictions={}", final_stats.hits, final_stats.misses, final_stats.evictions );
}
#[ tokio::test ]
async fn test_cache_performance_optimization()
{
let cache_config = RequestCacheConfig::new()
.with_max_entries( 100 )
.with_default_ttl( Duration::from_secs( 600 ) );
let client = OllamaClient::new(
"http://localhost:11434".to_string(),
Duration::from_secs( 30 )
).with_request_cache( cache_config );
let request = create_test_chat_request( "Performance test query" );
let response = r#"{"message":{"role":"assistant","content":"Performance test response"}}"#;
let start_cache = Instant::now();
client.cache_response( &request, response.to_string(), None );
let cache_duration = start_cache.elapsed();
assert!( cache_duration < Duration::from_millis( 10 ) ); println!( "β Cache write performance : {cache_duration:?}" );
let start_stats = Instant::now();
let _stats = client.cache_stats();
let stats_duration = start_stats.elapsed();
assert!( stats_duration < Duration::from_millis( 5 ) ); println!( "β Cache stats performance : {stats_duration:?}" );
let start_batch = Instant::now();
for i in 0..10
{
let req = create_test_chat_request( &format!( "Batch query {i}" ) );
let resp = format!( r#"{{"message":{{"role":"assistant","content":"Batch response {i}"}}}}"# );
client.cache_response( &req, resp, None );
}
let batch_duration = start_batch.elapsed();
assert!( batch_duration < Duration::from_millis( 50 ) ); println!( "β Batch cache operations performance : {batch_duration:?}" );
let final_stats = client.cache_stats();
println!( "β Performance optimization validation successful - cache stats : hits={}, misses={}, evictions={}", final_stats.hits, final_stats.misses, final_stats.evictions );
}
#[ tokio::test ]
async fn test_cache_integration_with_request_types()
{
let cache_config = RequestCacheConfig::new()
.with_max_entries( 50 )
.with_default_ttl( Duration::from_secs( 300 ) );
let client = OllamaClient::new(
"http://localhost:11434".to_string(),
Duration::from_secs( 30 )
).with_request_cache( cache_config );
let request_types = [
( "Simple question", None ),
( "Question with context", Some( serde_json::json!({ "temperature": 0.7 }) ) ),
( "Complex multipart question with detailed context", None ),
];
for ( i, ( message, options ) ) in request_types.iter().enumerate()
{
let mut request = create_test_chat_request( message );
if let Some( opts ) = options
{
request.options = Some( opts.clone() );
}
let response = format!( r#"{{"message":{{"role":"assistant","content":"Response type {}"}}}}"#, i + 1 );
client.cache_response( &request, response, None );
}
let stats = client.cache_stats();
println!( "β Cache integration with {} request types successful - cache stats : hits={}, misses={}, evictions={}", request_types.len(), stats.hits, stats.misses, stats.evictions );
let base_message = "Same message, different options";
let request1 = create_test_chat_request( base_message );
let mut request2 = create_test_chat_request( base_message );
request2.options = Some( serde_json::json!({ "max_tokens": 100 }) );
client.cache_response( &request1, "Response 1".to_string(), None );
client.cache_response( &request2, "Response 2".to_string(), None );
let final_stats = client.cache_stats();
println!( "β Cache request differentiation successful - cache stats : hits={}, misses={}, evictions={}", final_stats.hits, final_stats.misses, final_stats.evictions );
}
#[ tokio::test ]
async fn test_cache_error_handling()
{
let cache_config = RequestCacheConfig::new()
.with_max_entries( 5 )
.with_default_ttl( Duration::from_secs( 300 ) );
let client = OllamaClient::new(
"http://localhost:11434".to_string(),
Duration::from_secs( 30 )
).with_request_cache( cache_config );
let empty_request = create_test_chat_request( "Empty response test" );
client.cache_response( &empty_request, String::new(), None );
let stats_empty = client.cache_stats();
println!( "β Empty response caching handled successfully - cache stats : hits={}, misses={}, evictions={}", stats_empty.hits, stats_empty.misses, stats_empty.evictions );
let large_response = "Large response content : ".to_string() + &"x".repeat( 10000 );
let large_request = create_test_chat_request( "Large response test" );
client.cache_response( &large_request, large_response, None );
let stats_large = client.cache_stats();
println!( "β Large response caching handled successfully - cache stats : hits={}, misses={}, evictions={}", stats_large.hits, stats_large.misses, stats_large.evictions );
let unicode_request = create_test_chat_request( "Unicode test : πππ« special chars" );
let unicode_response = r#"{"message":{"role":"assistant","content":"Unicode response : δ½ ε₯½δΈη π"}}"#;
client.cache_response( &unicode_request, unicode_response.to_string(), None );
let stats_unicode = client.cache_stats();
println!( "β Unicode content caching handled successfully - cache stats : hits={}, misses={}, evictions={}", stats_unicode.hits, stats_unicode.misses, stats_unicode.evictions );
let zero_ttl_request = create_test_chat_request( "Zero TTL test" );
client.cache_response( &zero_ttl_request, "Zero TTL response".to_string(), Some( Duration::from_secs( 0 ) ) );
let stats_zero_ttl = client.cache_stats();
println!( "β Zero TTL caching handled - cache stats : hits={}, misses={}, evictions={}", stats_zero_ttl.hits, stats_zero_ttl.misses, stats_zero_ttl.evictions );
println!( "β Cache error handling and edge cases validation successful" );
}
#[ tokio::test ]
async fn test_cache_cleanup_and_maintenance()
{
let cache_config = RequestCacheConfig::new()
.with_max_entries( 10 )
.with_default_ttl( Duration::from_secs( 300 ) )
.with_cleanup_interval( Duration::from_secs( 60 ) );
let client = OllamaClient::new(
"http://localhost:11434".to_string(),
Duration::from_secs( 30 )
).with_request_cache( cache_config );
for i in 0..8
{
let request = create_test_chat_request( &format!( "Cleanup test query {i}" ) );
let response = format!( r#"{{"message":{{"role":"assistant","content":"Cleanup response {i}"}}}}"# );
client.cache_response( &request, response, None );
}
let populated_stats = client.cache_stats();
println!( "β Cache populated for cleanup test - cache stats : hits={}, misses={}, evictions={}", populated_stats.hits, populated_stats.misses, populated_stats.evictions );
let stats1 = client.cache_stats();
let stats2 = client.cache_stats();
assert_eq!( stats1.hits, stats2.hits );
assert_eq!( stats1.misses, stats2.misses );
assert_eq!( stats1.evictions, stats2.evictions );
println!( "β Cache statistics consistency validated" );
let no_cache_client = OllamaClient::new(
"http://localhost:11434".to_string(),
Duration::from_secs( 30 )
);
assert!( !no_cache_client.has_cache() );
let empty_stats = no_cache_client.cache_stats();
assert_eq!( empty_stats.hits, 0 );
assert_eq!( empty_stats.misses, 0 );
assert_eq!( empty_stats.evictions, 0 );
println!( "β No-cache client handling validated" );
println!( "β Cache cleanup and maintenance validation successful" );
}
}