git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
301 lines
8.5 KiB
Rust
301 lines
8.5 KiB
Rust
// Cache integration tests
|
|
//
|
|
// Tests caching behavior, hit/miss ratios, similarity search, and persistence
|
|
//
|
|
// Note: These tests use mock test infrastructure.
|
|
// Real OCR processing requires ONNX models to be configured.
|
|
|
|
use super::*;
|
|
use crate::common::{CacheStats, OutputFormat};
|
|
|
|
#[tokio::test]
|
|
async fn test_cache_hit_miss_behavior() {
|
|
let test_server = TestServer::with_cache()
|
|
.await
|
|
.expect("Failed to start test server with cache");
|
|
|
|
let image = images::generate_simple_equation("x^2");
|
|
image.save("/tmp/cache_test_1.png").unwrap();
|
|
|
|
// First request - should miss cache
|
|
let result1 = test_server
|
|
.process_image("/tmp/cache_test_1.png", OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
|
|
// Get cache stats
|
|
let _stats = test_server
|
|
.cache_stats()
|
|
.await
|
|
.expect("Failed to get cache stats");
|
|
|
|
// Second request - should hit cache
|
|
let result2 = test_server
|
|
.process_image("/tmp/cache_test_1.png", OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
|
|
// Verify results match
|
|
assert_eq!(result1.latex, result2.latex, "Cached result should match");
|
|
|
|
test_server.shutdown().await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_cache_similarity_lookup() {
|
|
let test_server = TestServer::with_cache()
|
|
.await
|
|
.expect("Failed to start test server");
|
|
|
|
// Create original image
|
|
let image1 = images::generate_simple_equation("a + b");
|
|
image1.save("/tmp/similarity_1.png").unwrap();
|
|
|
|
// Create similar image (slightly different rendering)
|
|
let mut image2 = images::generate_simple_equation("a + b");
|
|
images::add_slight_variation(&mut image2, 0.05);
|
|
image2.save("/tmp/similarity_2.png").unwrap();
|
|
|
|
// Process first image
|
|
let result1 = test_server
|
|
.process_image("/tmp/similarity_1.png", OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
|
|
// Process similar image
|
|
let result2 = test_server
|
|
.process_image("/tmp/similarity_2.png", OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
|
|
// Results should be similar
|
|
let similarity = latex::calculate_similarity(&result1.latex, &result2.latex);
|
|
assert!(
|
|
similarity > 0.9,
|
|
"Similar images should produce similar results"
|
|
);
|
|
|
|
test_server.shutdown().await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_cache_eviction() {
|
|
// Start server with small cache size
|
|
let test_server = TestServer::with_cache_size(3)
|
|
.await
|
|
.expect("Failed to start test server");
|
|
|
|
// Create and process 5 different images
|
|
for i in 0..5 {
|
|
let eq = format!("x + {}", i);
|
|
let image = images::generate_simple_equation(&eq);
|
|
let path = format!("/tmp/eviction_{}.png", i);
|
|
image.save(&path).unwrap();
|
|
|
|
test_server
|
|
.process_image(&path, OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
}
|
|
|
|
// Get cache stats
|
|
let stats = test_server
|
|
.cache_stats()
|
|
.await
|
|
.expect("Failed to get cache stats");
|
|
assert!(stats.current_size <= 3, "Cache should not exceed max size");
|
|
|
|
test_server.shutdown().await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_cache_persistence() {
|
|
let cache_dir = "/tmp/scipix_cache_persist";
|
|
std::fs::create_dir_all(cache_dir).unwrap();
|
|
|
|
// Start server with persistent cache
|
|
let test_server = TestServer::with_persistent_cache(cache_dir)
|
|
.await
|
|
.expect("Failed to start test server");
|
|
|
|
// Process image
|
|
let image = images::generate_simple_equation("persistent");
|
|
image.save("/tmp/persist_test.png").unwrap();
|
|
|
|
let result1 = test_server
|
|
.process_image("/tmp/persist_test.png", OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
|
|
// Shutdown server
|
|
test_server.shutdown().await;
|
|
|
|
// Start new server with same cache directory
|
|
let test_server2 = TestServer::with_persistent_cache(cache_dir)
|
|
.await
|
|
.expect("Failed to start second test server");
|
|
|
|
// Process same image - should hit persistent cache
|
|
let result2 = test_server2
|
|
.process_image("/tmp/persist_test.png", OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
|
|
// Results should match
|
|
assert_eq!(
|
|
result1.latex, result2.latex,
|
|
"Persistent cache should restore results"
|
|
);
|
|
|
|
test_server2.shutdown().await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_cache_invalidation() {
|
|
let test_server = TestServer::with_cache()
|
|
.await
|
|
.expect("Failed to start test server");
|
|
|
|
// Process image
|
|
let image = images::generate_simple_equation("invalidate");
|
|
image.save("/tmp/invalidate_test.png").unwrap();
|
|
|
|
let result1 = test_server
|
|
.process_image("/tmp/invalidate_test.png", OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
|
|
// Invalidate cache
|
|
test_server
|
|
.invalidate_cache()
|
|
.await
|
|
.expect("Cache invalidation failed");
|
|
|
|
// Process again - should miss cache
|
|
let result2 = test_server
|
|
.process_image("/tmp/invalidate_test.png", OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
|
|
// Results should match but processing should take time
|
|
assert_eq!(result1.latex, result2.latex, "Results should still match");
|
|
|
|
test_server.shutdown().await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_cache_hit_ratio() {
|
|
let test_server = TestServer::with_cache()
|
|
.await
|
|
.expect("Failed to start test server");
|
|
|
|
// Create test images
|
|
let equations = vec!["a", "b", "c"];
|
|
for eq in &equations {
|
|
let image = images::generate_simple_equation(eq);
|
|
image.save(&format!("/tmp/ratio_{}.png", eq)).unwrap();
|
|
}
|
|
|
|
// Process each image twice
|
|
for eq in &equations {
|
|
let path = format!("/tmp/ratio_{}.png", eq);
|
|
|
|
// First time (miss)
|
|
test_server
|
|
.process_image(&path, OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
|
|
// Second time (hit)
|
|
test_server
|
|
.process_image(&path, OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
}
|
|
|
|
// Get stats
|
|
let _stats = test_server
|
|
.cache_stats()
|
|
.await
|
|
.expect("Failed to get cache stats");
|
|
|
|
test_server.shutdown().await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_cache_ttl_expiration() {
|
|
// Start server with 1-second TTL
|
|
let test_server = TestServer::with_cache_ttl(1)
|
|
.await
|
|
.expect("Failed to start test server");
|
|
|
|
// Process image
|
|
let image = images::generate_simple_equation("ttl");
|
|
image.save("/tmp/ttl_test.png").unwrap();
|
|
|
|
let result1 = test_server
|
|
.process_image("/tmp/ttl_test.png", OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
|
|
// Immediately reprocess - should hit cache
|
|
let result2 = test_server
|
|
.process_image("/tmp/ttl_test.png", OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
|
|
assert_eq!(result1.latex, result2.latex);
|
|
|
|
test_server.shutdown().await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_cache_concurrent_access() {
|
|
let test_server = TestServer::with_cache()
|
|
.await
|
|
.expect("Failed to start test server");
|
|
|
|
let image = images::generate_simple_equation("concurrent");
|
|
image.save("/tmp/concurrent_cache.png").unwrap();
|
|
|
|
// First request to populate cache
|
|
test_server
|
|
.process_image("/tmp/concurrent_cache.png", OutputFormat::LaTeX)
|
|
.await
|
|
.expect("Processing failed");
|
|
|
|
// Spawn multiple concurrent requests
|
|
let mut handles = vec![];
|
|
for _ in 0..10 {
|
|
let server = test_server.clone();
|
|
let handle = tokio::spawn(async move {
|
|
server
|
|
.process_image("/tmp/concurrent_cache.png", OutputFormat::LaTeX)
|
|
.await
|
|
});
|
|
handles.push(handle);
|
|
}
|
|
|
|
// Wait for all to complete
|
|
let results = futures::future::join_all(handles).await;
|
|
|
|
// All should succeed and return same result
|
|
assert!(
|
|
results.iter().all(|r| r.is_ok()),
|
|
"All requests should succeed"
|
|
);
|
|
|
|
let first_latex = &results[0].as_ref().unwrap().as_ref().unwrap().latex;
|
|
assert!(
|
|
results
|
|
.iter()
|
|
.all(|r| { &r.as_ref().unwrap().as_ref().unwrap().latex == first_latex }),
|
|
"All results should match"
|
|
);
|
|
|
|
test_server.shutdown().await;
|
|
}
|
|
|
|
// Re-export CacheStats for backward compatibility
|
|
pub use crate::common::CacheStats as CacheStatsCompat;
|