use api_gemini::{ client::Client, * };
use core::time::Duration;
#[ test ]
fn test_sync_client_construction()
{
let api_key = std::env::var( "GEMINI_API_KEY" )
.or_else( | _ | std::fs::read_to_string( "secret/gemini_api_key" ).map( | s | s.trim().to_string() ) )
.unwrap_or_else( | _ | "test-key".to_string() );
let _sync_client = Client::sync_builder()
.api_key( api_key )
.timeout( Duration::from_secs( 30 ) )
.build()
.expect( "Failed to build sync client" );
}
#[ test ]
fn test_sync_models_api()
{
use workspace_tools as workspace;
let ws = workspace::workspace().expect( "Failed to resolve workspace" );
let api_key = ws.load_secret_key( "GEMINI_API_KEY", "-secrets.sh" )
.or_else( |_| std::env::var( "GEMINI_API_KEY" ) )
.expect( "❌ GEMINI_API_KEY not found in workspace secrets or environment" );
let sync_client = Client::sync_builder()
.api_key( api_key )
.build()
.expect( "Failed to build sync client" );
let models = sync_client.models().list()
.expect( "Models list should succeed with valid API key" );
assert!( !models.models.is_empty(), "Should have at least one model" );
println!( "✅ Sync models list successful" );
match sync_client.models().by_name("gemini-1.5-pro-latest")
{
Ok(_model) => {
println!("✅ Sync model by_name successful");
}
Err(e) => {
println!("⚠️ Model by_name failed : {e:?}");
}
}
}
#[ test ]
fn test_sync_content_generation()
{
let api_key = std::env::var( "GEMINI_API_KEY" )
.or_else( | _ | std::fs::read_to_string( "secret/gemini_api_key" ).map( | s | s.trim().to_string() ) )
.unwrap_or_else( | _ | "test-key".to_string() );
let sync_client = Client::sync_builder()
.api_key(api_key)
.build()
.expect("Failed to build sync client");
let request = GenerateContentRequest {
contents : vec![Content {
parts : vec![Part {
text: Some("Hello, world!".to_string()),
..Default::default()
}],
role: "user".to_string(),
}],
..Default::default()
};
let models_api = sync_client.models();
let model_result = models_api.by_name("gemini-1.5-pro-latest");
if let Ok(model) = model_result
{
match model.generate_content(&request)
{
Ok(response) => {
assert!(!response.candidates.is_empty(), "Should have at least one candidate");
println!("✅ Sync content generation successful");
}
Err( api_gemini::error::Error::AuthenticationError( _ ) ) =>
{
println!( "⚠️ Authentication error (expected without valid API key)" );
}
Err(e) => {
panic!("Unexpected error type : {e:?}");
}
}
} else {
panic!("Failed to get model");
}
}
#[ test ]
fn test_sync_embeddings()
{
let api_key = std::env::var( "GEMINI_API_KEY" )
.or_else( | _ | std::fs::read_to_string( "secret/gemini_api_key" ).map( | s | s.trim().to_string() ) )
.unwrap_or_else( | _ | "test-key".to_string() );
let sync_client = Client::sync_builder()
.api_key(api_key)
.build()
.expect("Failed to build sync client");
let request = EmbedContentRequest {
content : Content {
parts : vec![Part {
text: Some("Test embedding content".to_string()),
..Default::default()
}],
role: "user".to_string(),
},
..Default::default()
};
let models_api = sync_client.models();
let model_result = models_api.by_name("text-embedding-004");
if let Ok(model) = model_result
{
match model.embed_content(&request)
{
Ok(response) => {
assert!(!response.embedding.values.is_empty(), "Should have embedding values");
println!("✅ Sync embeddings successful");
}
Err( api_gemini::error::Error::AuthenticationError( _ ) ) =>
{
println!( "⚠️ Authentication error (expected without valid API key)" );
}
Err(e) => {
panic!("Unexpected error type : {e:?}");
}
}
} else {
panic!("Failed to get model");
}
}
#[ test ]
fn test_sync_runtime_management()
{
use std::sync::Arc;
use std::thread;
let api_key = std::env::var( "GEMINI_API_KEY" )
.or_else( | _ | std::fs::read_to_string( "secret/gemini_api_key" ).map( | s | s.trim().to_string() ) )
.unwrap_or_else( | _ | "test-key".to_string() );
let sync_client = Arc::new(
Client::sync_builder()
.api_key(api_key)
.build()
.expect("Failed to build sync client")
);
let mut handles = vec![];
for i in 0..3
{
let client = Arc::clone(&sync_client);
let handle = thread::spawn(move || {
match client.models().list()
{
Ok( models ) =>
{
assert!(!models.models.is_empty(), "Thread {i} should have models");
println!("✅ Thread {i} sync models list successful");
}
Err( api_gemini::error::Error::AuthenticationError( _ ) ) =>
{
println!("⚠️ Thread {i} authentication error (expected without valid API key)");
}
Err(e) => {
panic!("Thread {i} unexpected error type : {e:?}");
}
}
});
handles.push(handle);
}
for handle in handles
{
handle.join().expect("Thread panicked");
}
}
#[ cfg( feature = "streaming" ) ]
#[ test ]
fn test_sync_streaming_blocking()
{
let api_key = std::env::var( "GEMINI_API_KEY" )
.or_else( | _ | std::fs::read_to_string( "secret/gemini_api_key" ).map( | s | s.trim().to_string() ) )
.unwrap_or_else( | _ | "test-key".to_string() );
let sync_client = Client::sync_builder()
.api_key(api_key)
.build()
.expect("Failed to build sync client");
let request = GenerateContentRequest {
contents : vec![Content {
parts : vec![Part {
text: Some("Tell me a short story".to_string()),
..Default::default()
}],
role: "user".to_string(),
}],
..Default::default()
};
let models_api = sync_client.models();
let model_result = models_api.by_name("gemini-1.5-pro-latest");
if let Ok(model) = model_result
{
match model.generate_content_stream(&request)
{
Ok(responses) => {
assert!(!responses.is_empty(), "Should have streamed responses");
println!("✅ Sync streaming successful");
}
Err( api_gemini::error::Error::AuthenticationError( _ ) ) =>
{
println!( "⚠️ Authentication error (expected without valid API key)" );
}
Err(api_gemini::error::Error::ApiError(msg)) if msg.contains("API key") =>
{
println!("⚠️ API key error (expected without valid API key): {msg}");
}
Err(e) => {
panic!("Unexpected error type : {e:?}");
}
}
} else {
panic!("Failed to get model");
}
}
#[ test ]
fn test_sync_wrapper_performance()
{
let api_key = std::env::var( "GEMINI_API_KEY" )
.or_else( | _ | std::fs::read_to_string( "secret/gemini_api_key" ).map( | s | s.trim().to_string() ) )
.unwrap_or_else( | _ | "test-key".to_string() );
let rt = tokio::runtime::Runtime::new().expect("Failed to create runtime");
let async_client = rt.block_on(async {
Client::builder()
.api_key(api_key.clone())
.build()
}).expect("Failed to build async client");
let sync_client = Client::sync_builder()
.api_key(api_key)
.build()
.expect("Failed to build sync client");
let request = GenerateContentRequest {
contents : vec![Content {
parts : vec![Part {
text: Some("Simple test".to_string()),
..Default::default()
}],
role: "user".to_string(),
}],
..Default::default()
};
let async_start = std::time::Instant::now();
let async_result = rt.block_on(async {
async_client.models().by_name("gemini-1.5-pro-latest")
.generate_content(&request).await
});
let async_duration = async_start.elapsed();
match async_result
{
Ok(_async_response) => {
let sync_start = std::time::Instant::now();
let models_api = sync_client.models();
let model_result = models_api.by_name("gemini-1.5-pro-latest");
if let Ok(model) = model_result
{
match model.generate_content(&request)
{
Ok(_sync_response) => {
let sync_duration = sync_start.elapsed();
let overhead_ratio = sync_duration.as_secs_f64() / async_duration.as_secs_f64();
assert!(overhead_ratio < 1.5, "Sync wrapper overhead too high : {overhead_ratio:.2}x");
println!("✅ Performance test successful - overhead : {overhead_ratio:.2}x");
}
Err(e) => panic!("Sync call failed : {e:?}"),
}
} else {
panic!("Failed to get model for sync test");
}
}
Err( api_gemini::error::Error::AuthenticationError( _ ) ) =>
{
println!("⚠️ Performance test skipped due to authentication error (expected without valid API key)");
}
Err(e) => {
panic!("Async call failed with unexpected error : {e:?}");
}
}
}
#[ test ]
fn test_sync_error_handling()
{
let sync_client = Client::sync_builder()
.api_key("invalid-key".to_string())
.build()
.expect("Failed to build sync client");
let request = GenerateContentRequest {
contents : vec![Content {
parts : vec![Part {
text: Some("Test".to_string()),
..Default::default()
}],
role: "user".to_string(),
}],
..Default::default()
};
let result = sync_client.models().by_name("gemini-1.5-pro-latest")
.and_then(|model| model.generate_content(&request));
assert!(result.is_err(), "Should fail with invalid API key");
if let Err(error) = result
{
let error_str = format!("{error}");
let is_auth_error = error_str.contains("API_KEY_INVALID")
|| error_str.contains("authentication")
|| error_str.contains("unauthorized")
|| error_str.contains("API key not valid")
|| error_str.contains("AuthenticationError");
if is_auth_error
{
println!("✅ Correct authentication error detected : {error_str}");
} else {
println!("⚠️ Unexpected error format : {error_str}");
}
}
}