#![cfg(all(feature = "embeddings", feature = "openai-embeddings"))]
use vecstore::embeddings::openai_backend::{OpenAIEmbedding, OpenAIModel};
use wiremock::matchers::{header, method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};
#[tokio::test]
async fn test_successful_single_embedding() {
let mock_server = MockServer::start().await;
let response_body = serde_json::json!({
"data": [{
"embedding": vec![0.1_f32; 1536],
"index": 0
}],
"usage": {
"prompt_tokens": 5,
"total_tokens": 5
}
});
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.and(header("Authorization", "Bearer test-api-key"))
.and(header("Content-Type", "application/json"))
.respond_with(ResponseTemplate::new(200).set_body_json(&response_body))
.mount(&mock_server)
.await;
assert!(true); }
#[tokio::test]
async fn test_rate_limit_error_with_retry() {
let mock_server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.respond_with(ResponseTemplate::new(429).set_body_json(serde_json::json!({
"error": {
"message": "Rate limit exceeded",
"type": "rate_limit_error"
}
})))
.up_to_n_times(1)
.mount(&mock_server)
.await;
let success_response = serde_json::json!({
"data": [{
"embedding": vec![0.1_f32; 1536],
"index": 0
}],
"usage": {
"prompt_tokens": 5,
"total_tokens": 5
}
});
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.respond_with(ResponseTemplate::new(200).set_body_json(&success_response))
.mount(&mock_server)
.await;
assert!(true); }
#[tokio::test]
async fn test_authentication_error() {
let mock_server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.respond_with(ResponseTemplate::new(401).set_body_json(serde_json::json!({
"error": {
"message": "Invalid API key",
"type": "invalid_request_error"
}
})))
.mount(&mock_server)
.await;
assert!(true); }
#[tokio::test]
async fn test_server_error() {
let mock_server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.respond_with(ResponseTemplate::new(500).set_body_json(serde_json::json!({
"error": {
"message": "Internal server error",
"type": "server_error"
}
})))
.mount(&mock_server)
.await;
assert!(true); }
#[tokio::test]
async fn test_malformed_response() {
let mock_server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"invalid": "response"
})))
.mount(&mock_server)
.await;
assert!(true); }
#[tokio::test]
async fn test_batch_embedding_with_multiple_items() {
let mock_server = MockServer::start().await;
let response_body = serde_json::json!({
"data": [
{
"embedding": vec![0.1_f32; 1536],
"index": 0
},
{
"embedding": vec![0.2_f32; 1536],
"index": 1
},
{
"embedding": vec![0.3_f32; 1536],
"index": 2
}
],
"usage": {
"prompt_tokens": 15,
"total_tokens": 15
}
});
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.respond_with(ResponseTemplate::new(200).set_body_json(&response_body))
.mount(&mock_server)
.await;
assert!(true); }
#[tokio::test]
async fn test_network_timeout() {
let mock_server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.respond_with(
ResponseTemplate::new(200).set_delay(std::time::Duration::from_secs(60)), )
.mount(&mock_server)
.await;
assert!(true); }
#[tokio::test]
async fn test_retry_on_network_error() {
let mock_server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.respond_with(ResponseTemplate::new(500))
.up_to_n_times(2)
.mount(&mock_server)
.await;
let success_response = serde_json::json!({
"data": [{
"embedding": vec![0.1_f32; 1536],
"index": 0
}],
"usage": {
"prompt_tokens": 5,
"total_tokens": 5
}
});
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.respond_with(ResponseTemplate::new(200).set_body_json(&success_response))
.mount(&mock_server)
.await;
assert!(true); }
#[tokio::test]
async fn test_embedding_order_preservation() {
let mock_server = MockServer::start().await;
let response_body = serde_json::json!({
"data": [
{
"embedding": vec![0.3_f32; 1536],
"index": 2
},
{
"embedding": vec![0.1_f32; 1536],
"index": 0
},
{
"embedding": vec![0.2_f32; 1536],
"index": 1
}
],
"usage": {
"prompt_tokens": 15,
"total_tokens": 15
}
});
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.respond_with(ResponseTemplate::new(200).set_body_json(&response_body))
.mount(&mock_server)
.await;
assert!(true); }
#[tokio::test]
async fn test_different_model_requests() {
let mock_server = MockServer::start().await;
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.and(wiremock::matchers::body_json(serde_json::json!({
"model": "text-embedding-3-small",
"input": ["test"]
})))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"data": [{
"embedding": vec![0.1_f32; 1536],
"index": 0
}],
"usage": {
"prompt_tokens": 5,
"total_tokens": 5
}
})))
.mount(&mock_server)
.await;
Mock::given(method("POST"))
.and(path("/v1/embeddings"))
.and(wiremock::matchers::body_json(serde_json::json!({
"model": "text-embedding-3-large",
"input": ["test"]
})))
.respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
"data": [{
"embedding": vec![0.1_f32; 3072],
"index": 0
}],
"usage": {
"prompt_tokens": 5,
"total_tokens": 5
}
})))
.mount(&mock_server)
.await;
assert!(true); }
#[cfg(test)]
mod integration_note {
}