use api_gemini::client::Client;
fn create_integration_client() -> Client
{
Client::new().unwrap_or_else( |err| {
panic!(
"\n❌ INTEGRATION TEST FAILURE: No valid API key found!\n\
\n🔑 Required: Set GEMINI_API_KEY environment variable or create secret/gemini_api_key file\n\
\n📋 This integration test validates authentication with real API calls\n\
\n🚫 No API key available from any source\n\
\n💡 For unit tests only (no API), run: cargo test --no-default-features\n\
\nOriginal error : {err:?}"
);
})
}
#[ test ]
fn test_integration_failure_without_api_key()
{
let has_api_key = Client::new().is_ok();
if has_api_key
{
println!( "API key available - integration tests will run normally" );
let _client = Client::new().expect( "Client creation should succeed with valid API key" );
return;
}
let result = Client::new();
assert!( result.is_err(), "Client::new() should fail when no API key is available" );
let error = result.unwrap_err();
let error_msg = format!( "{error:?}" );
assert!( error_msg.to_lowercase().contains( "authentication" ) || error_msg.to_lowercase().contains( "api_key" ),
"Error should mention authentication or API key : {error_msg}" );
println!( "✅ Integration test properly fails with clear error message when no API key is available" );
}
#[ tokio::test ]
async fn integration_test_valid_authentication_real_api()
{
let client = create_integration_client();
let models_response = client.models()
.list()
.await
.expect( "Valid API key should allow model listing" );
assert!( !models_response.models.is_empty(), "Authenticated API should return available models" );
let first_model = &models_response.models[ 0 ];
assert!( !first_model.name.is_empty(), "Authenticated access should provide model names" );
assert!( first_model.display_name.is_some(), "Authenticated access should provide model metadata" );
}
#[ tokio::test ]
async fn integration_test_authentication_with_content_generation()
{
let client = create_integration_client();
let request = api_gemini::models::GenerateContentRequest
{
contents: vec!
[
api_gemini ::models::Content
{
parts: vec!
[
api_gemini ::models::Part
{
text: Some( "Test authentication: say 'auth-ok'".to_string() ),
..Default::default()
}
],
role: "user".to_string(),
}
],
generation_config: Some( api_gemini::models::GenerationConfig
{
max_output_tokens: Some( 10 ),
..Default::default()
}),
..Default::default()
};
let response = client.models().by_name( "gemini-flash-latest" )
.generate_content( &request )
.await
.expect( "Valid authentication should allow content generation" );
assert!( !response.candidates.is_empty(), "Authenticated request should return candidates" );
assert!( response.candidates[ 0 ].content.parts[ 0 ].text.is_some(),
"Authenticated request should return text response" );
let response_text = response.candidates[ 0 ].content.parts[ 0 ].text.as_ref().unwrap();
assert!( !response_text.is_empty(), "Authenticated response should not be empty" );
}
#[ tokio::test ]
async fn integration_test_authentication_with_embeddings()
{
let client = create_integration_client();
let embed_request = api_gemini::models::EmbedContentRequest
{
content: api_gemini::models::Content
{
role: "user".to_string(),
parts: vec!
[
api_gemini ::models::Part
{
text: Some( "authentication test".to_string() ),
..Default::default()
}
],
},
task_type: Some( "RETRIEVAL_QUERY".to_string() ),
title: None,
output_dimensionality: None,
};
let response = client.models().by_name( "text-embedding-004" )
.embed_content( &embed_request )
.await
.expect( "Valid authentication should allow embeddings" );
assert!( !response.embedding.values.is_empty(),
"Authenticated embeddings request should return vector" );
assert!( response.embedding.values.len() > 50,
"Authenticated embeddings should return meaningful vector size" );
let non_zero_count = response.embedding.values.iter()
.filter( |&&value| value.abs() > 0.001 )
.count();
assert!( non_zero_count > response.embedding.values.len() / 10,
"Authenticated embeddings should have non-zero values" );
}
#[ tokio::test ]
async fn integration_test_authentication_quota_and_limits()
{
let client = create_integration_client();
let mut successful_requests = 0;
let max_attempts = 5;
for i in 0..max_attempts
{
let request = api_gemini::models::GenerateContentRequest
{
contents: vec!
[
api_gemini ::models::Content
{
parts: vec!
[
api_gemini ::models::Part
{
text : Some( format!( "Request {}: count to 3", i + 1 ) ),
..Default::default()
}
],
role: "user".to_string(),
}
],
generation_config: Some( api_gemini::models::GenerationConfig
{
max_output_tokens: Some( 20 ),
..Default::default()
}),
..Default::default()
};
match client.models().by_name( "gemini-flash-latest" )
.generate_content( &request )
.await
{
Ok( response ) =>
{
successful_requests += 1;
assert!( !response.candidates.is_empty(), "Each successful request should return candidates" );
tokio ::time::sleep( tokio::time::Duration::from_millis( 200 ) ).await;
},
Err( err ) =>
{
let error_str = format!( "{err:?}" );
if error_str.contains( "quota" ) || error_str.contains( "rate" ) || error_str.contains( "429" )
{
println!( "Hit quota/rate limit on request {} (expected for auth validation)", i + 1 );
break;
}
panic!( "Unexpected error during quota test : {err:?}" );
}
}
}
assert!( successful_requests > 0,
"Authenticated client should make at least one successful request" );
println!( "Successfully made {successful_requests}/{max_attempts} authenticated requests" );
}