Fix cost tracking accuracy and OpenRouter model pricing (#3189)
Co-authored-by: jack <> Co-authored-by: angiejones <jones.angie@gmail.com>
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
use goose::providers::pricing::{get_model_pricing, initialize_pricing_cache, refresh_pricing};
|
||||
use std::time::Instant;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_pricing_cache_performance() {
|
||||
// Initialize the cache
|
||||
let start = Instant::now();
|
||||
initialize_pricing_cache()
|
||||
.await
|
||||
.expect("Failed to initialize pricing cache");
|
||||
let init_duration = start.elapsed();
|
||||
println!("Cache initialization took: {:?}", init_duration);
|
||||
|
||||
// Test fetching pricing for common models (using actual model names from OpenRouter)
|
||||
let models = vec![
|
||||
("anthropic", "claude-3.5-sonnet"),
|
||||
("openai", "gpt-4o"),
|
||||
("openai", "gpt-4o-mini"),
|
||||
("google", "gemini-flash-1.5"),
|
||||
("anthropic", "claude-sonnet-4"),
|
||||
];
|
||||
|
||||
// First fetch (should hit cache)
|
||||
let start = Instant::now();
|
||||
for (provider, model) in &models {
|
||||
let pricing = get_model_pricing(provider, model).await;
|
||||
assert!(
|
||||
pricing.is_some(),
|
||||
"Expected pricing for {}/{}",
|
||||
provider,
|
||||
model
|
||||
);
|
||||
}
|
||||
let first_fetch_duration = start.elapsed();
|
||||
println!(
|
||||
"First fetch of {} models took: {:?}",
|
||||
models.len(),
|
||||
first_fetch_duration
|
||||
);
|
||||
|
||||
// Second fetch (definitely from cache)
|
||||
let start = Instant::now();
|
||||
for (provider, model) in &models {
|
||||
let pricing = get_model_pricing(provider, model).await;
|
||||
assert!(
|
||||
pricing.is_some(),
|
||||
"Expected pricing for {}/{}",
|
||||
provider,
|
||||
model
|
||||
);
|
||||
}
|
||||
let second_fetch_duration = start.elapsed();
|
||||
println!(
|
||||
"Second fetch of {} models took: {:?}",
|
||||
models.len(),
|
||||
second_fetch_duration
|
||||
);
|
||||
|
||||
// Cache fetch should be significantly faster
|
||||
// Note: Both fetches are already very fast (microseconds), so we just ensure
|
||||
// the second fetch is not slower than the first (allowing for some variance)
|
||||
assert!(
|
||||
second_fetch_duration <= first_fetch_duration * 2,
|
||||
"Cache fetch should not be significantly slower than initial fetch. First: {:?}, Second: {:?}",
|
||||
first_fetch_duration,
|
||||
second_fetch_duration
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_pricing_refresh() {
|
||||
// Initialize first
|
||||
initialize_pricing_cache()
|
||||
.await
|
||||
.expect("Failed to initialize pricing cache");
|
||||
|
||||
// Get initial pricing (using a model that actually exists)
|
||||
let initial_pricing = get_model_pricing("anthropic", "claude-3.5-sonnet").await;
|
||||
assert!(initial_pricing.is_some(), "Expected initial pricing");
|
||||
|
||||
// Force refresh
|
||||
let start = Instant::now();
|
||||
refresh_pricing().await.expect("Failed to refresh pricing");
|
||||
let refresh_duration = start.elapsed();
|
||||
println!("Pricing refresh took: {:?}", refresh_duration);
|
||||
|
||||
// Get pricing after refresh
|
||||
let refreshed_pricing = get_model_pricing("anthropic", "claude-3.5-sonnet").await;
|
||||
assert!(
|
||||
refreshed_pricing.is_some(),
|
||||
"Expected pricing after refresh"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_model_not_in_openrouter() {
|
||||
initialize_pricing_cache()
|
||||
.await
|
||||
.expect("Failed to initialize pricing cache");
|
||||
|
||||
// Test a model that likely doesn't exist
|
||||
let pricing = get_model_pricing("fake-provider", "fake-model").await;
|
||||
assert!(
|
||||
pricing.is_none(),
|
||||
"Should return None for non-existent model"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_concurrent_access() {
|
||||
use tokio::task;
|
||||
|
||||
initialize_pricing_cache()
|
||||
.await
|
||||
.expect("Failed to initialize pricing cache");
|
||||
|
||||
// Spawn multiple tasks to access pricing concurrently
|
||||
let mut handles = vec![];
|
||||
|
||||
for i in 0..10 {
|
||||
let handle = task::spawn(async move {
|
||||
let start = Instant::now();
|
||||
let pricing = get_model_pricing("openai", "gpt-4o").await;
|
||||
let duration = start.elapsed();
|
||||
(i, pricing.is_some(), duration)
|
||||
});
|
||||
handles.push(handle);
|
||||
}
|
||||
|
||||
// Wait for all tasks
|
||||
for handle in handles {
|
||||
let (task_id, has_pricing, duration) = handle.await.unwrap();
|
||||
assert!(has_pricing, "Task {} should have gotten pricing", task_id);
|
||||
println!("Task {} took: {:?}", task_id, duration);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user