use super::*;
mod request_caching_functionality_tests
{
use super::*;
use std::time::{ Duration, Instant };
#[ test ]
fn test_cache_config_validation()
{
let valid_config = the_module::CacheConfig::new()
.with_ttl_seconds( 300 )
.with_max_entries( 1000 )
.with_memory_limit_mb( 100 );
assert!( valid_config.is_valid() );
assert_eq!( valid_config.ttl_seconds(), 300 );
assert_eq!( valid_config.max_entries(), 1000 );
assert_eq!( valid_config.memory_limit_mb(), 100 );
let invalid_config = the_module::CacheConfig::new()
.with_ttl_seconds( 0 );
assert!( !invalid_config.is_valid() );
let invalid_config2 = the_module::CacheConfig::new()
.with_max_entries( 0 );
assert!( !invalid_config2.is_valid() );
}
#[ test ]
fn test_cache_key_generation()
{
let cache = the_module::RequestCache::new( the_module::CacheConfig::default() );
let request1 = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello, world!" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let request2 = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello, world!" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let key1 = cache.generate_cache_key( &request1 );
let key2 = cache.generate_cache_key( &request2 );
assert_eq!( key1, key2, "Identical requests should generate identical cache keys" );
let request3 = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 200, messages : vec![ the_module::Message::user( "Hello, world!" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let key3 = cache.generate_cache_key( &request3 );
assert_ne!( key1, key3, "Different requests should generate different cache keys" );
}
#[ test ]
fn test_cache_storage_and_retrieval()
{
let cache = the_module::RequestCache::new( the_module::CacheConfig::default() );
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Test message" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let response = the_module::CreateMessageResponse
{
id : "msg_123".to_string(),
r#type : "message".to_string(),
role : "assistant".to_string(),
content : vec![ the_module::ResponseContent
{
r#type : "text".to_string(),
text : Some( "Cached response".to_string() ),
} ],
model : "claude-3-5-haiku-20241022".to_string(),
stop_reason : Some( "end_turn".to_string() ),
stop_sequence : None,
usage : the_module::Usage
{
input_tokens : 10,
output_tokens : 5,
},
};
cache.store( &request, response.clone() );
let cached_response = cache.get( &request );
assert!( cached_response.is_some(), "Response should be cached" );
let cached = cached_response.unwrap();
assert_eq!( cached.id, response.id );
assert_eq!( cached.content.len(), response.content.len() );
}
#[ test ]
fn test_cache_expiration()
{
let config = the_module::CacheConfig::new()
.with_ttl_seconds( 1 );
let cache = the_module::RequestCache::new( config );
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Expiring message" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let response = the_module::CreateMessageResponse
{
id : "msg_exp".to_string(),
r#type : "message".to_string(),
role : "assistant".to_string(),
content : vec![ the_module::ResponseContent
{
r#type : "text".to_string(),
text : Some( "This will expire".to_string() ),
} ],
model : "claude-3-5-haiku-20241022".to_string(),
stop_reason : Some( "end_turn".to_string() ),
stop_sequence : None,
usage : the_module::Usage
{
input_tokens : 8,
output_tokens : 4,
},
};
cache.store( &request, response.clone() );
assert!( cache.get( &request ).is_some(), "Response should be cached immediately" );
std::thread::sleep( Duration::from_millis( 1100 ) );
assert!( cache.get( &request ).is_none(), "Response should be expired after TTL" );
}
#[ test ]
fn test_cache_size_limits()
{
let config = the_module::CacheConfig::new()
.with_max_entries( 2 );
let cache = the_module::RequestCache::new( config );
let requests = vec![
the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Message 1" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
},
the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Message 2" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
},
the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Message 3" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
},
];
for ( i, request ) in requests.iter().enumerate()
{
let response = the_module::CreateMessageResponse
{
id : format!( "msg_{}", i + 1 ),
r#type : "message".to_string(),
role : "assistant".to_string(),
content : vec![ the_module::ResponseContent
{
r#type : "text".to_string(),
text : Some( format!( "Response {}", i + 1 ) ),
} ],
model : "claude-3-5-haiku-20241022".to_string(),
stop_reason : Some( "end_turn".to_string() ),
stop_sequence : None,
usage : the_module::Usage
{
input_tokens : 5,
output_tokens : 3,
},
};
cache.store( request, response.clone() );
}
assert!( cache.get( &requests[ 0 ] ).is_none(), "First entry should be evicted" );
assert!( cache.get( &requests[ 1 ] ).is_some(), "Second entry should still be cached" );
assert!( cache.get( &requests[ 2 ] ).is_some(), "Third entry should be cached" );
assert_eq!( cache.size(), 2, "Cache should contain exactly 2 entries" );
}
#[ test ]
fn test_cache_invalidation()
{
let cache = the_module::RequestCache::new( the_module::CacheConfig::default() );
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Invalidate me" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let response = the_module::CreateMessageResponse
{
id : "msg_inv".to_string(),
r#type : "message".to_string(),
role : "assistant".to_string(),
content : vec![ the_module::ResponseContent
{
r#type : "text".to_string(),
text : Some( "To be invalidated".to_string() ),
} ],
model : "claude-3-5-haiku-20241022".to_string(),
stop_reason : Some( "end_turn".to_string() ),
stop_sequence : None,
usage : the_module::Usage
{
input_tokens : 6,
output_tokens : 4,
},
};
cache.store( &request, response.clone() );
assert!( cache.get( &request ).is_some(), "Response should be cached" );
cache.invalidate( &request );
assert!( cache.get( &request ).is_none(), "Response should be invalidated" );
cache.store( &request, response.clone() );
assert!( cache.get( &request ).is_some(), "Response should be cached again" );
cache.clear();
assert!( cache.get( &request ).is_none(), "Cache should be empty after clear" );
assert_eq!( cache.size(), 0, "Cache size should be 0 after clear" );
}
#[ test ]
fn test_cache_metrics()
{
let cache = the_module::RequestCache::new( the_module::CacheConfig::default() );
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Metrics test" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let response = the_module::CreateMessageResponse
{
id : "msg_metrics".to_string(),
r#type : "message".to_string(),
role : "assistant".to_string(),
content : vec![ the_module::ResponseContent
{
r#type : "text".to_string(),
text : Some( "Metrics response".to_string() ),
} ],
model : "claude-3-5-haiku-20241022".to_string(),
stop_reason : Some( "end_turn".to_string() ),
stop_sequence : None,
usage : the_module::Usage
{
input_tokens : 5,
output_tokens : 3,
},
};
let metrics = cache.metrics();
assert_eq!( metrics.hits(), 0 );
assert_eq!( metrics.misses(), 0 );
assert_eq!( metrics.stores(), 0 );
cache.store( &request, response.clone() );
let metrics = cache.metrics();
assert_eq!( metrics.stores(), 1 );
cache.get( &the_module::CreateMessageRequest
{
model : "different-model".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Different request" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
} );
let metrics = cache.metrics();
assert_eq!( metrics.misses(), 1 );
cache.get( &request );
let metrics = cache.metrics();
assert_eq!( metrics.hits(), 1 );
assert!( ( metrics.hit_rate() - 0.5 ).abs() < 0.01 ); }
}
mod request_caching_integration_tests
{
use super::*;
use std::time::{ Duration, Instant };
#[ test ]
fn test_client_with_caching()
{
}
#[ tokio::test ]
async fn test_cached_message_requests()
{
}
#[ test ]
fn test_cache_performance()
{
let config = the_module::CacheConfig::new()
.with_max_entries( 1000 );
let cache = the_module::RequestCache::new( config );
let start = Instant::now();
for i in 0..100
{
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( &format!( "Message {}", i ) ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let response = the_module::CreateMessageResponse
{
id : format!( "msg_{}", i ),
r#type : "message".to_string(),
role : "assistant".to_string(),
content : vec![ the_module::ResponseContent
{
r#type : "text".to_string(),
text : Some( format!( "Response {}", i ) ),
} ],
model : "claude-3-5-haiku-20241022".to_string(),
stop_reason : Some( "end_turn".to_string() ),
stop_sequence : None,
usage : the_module::Usage
{
input_tokens : 5,
output_tokens : 3,
},
};
cache.store( &request, response.clone() );
}
let store_duration = start.elapsed();
let start = Instant::now();
for i in 0..100
{
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( &format!( "Message {}", i ) ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let _ = cache.get( &request );
}
let retrieval_duration = start.elapsed();
assert!( store_duration < Duration::from_millis( 100 ), "Cache storage should be fast" );
assert!( retrieval_duration < Duration::from_millis( 50 ), "Cache retrieval should be very fast" );
assert_eq!( cache.size(), 100 );
}
}