graph_storage_sdk/
contract.rs1#![allow(
20 clippy::expect_used,
21 reason = "this module is a test harness: a violated clause has to abort \
22 the caller's test with the clause named, and there is no other \
23 outcome for it to return"
24)]
25
26use std::time::Duration;
27
28use tokio_util::sync::CancellationToken;
29
30use crate::models::RemainingBudget;
31use crate::plugin_api::{EmbedRequest, EmbeddingProviderError, EmbeddingProviderV1};
32
33fn request(inputs: Vec<String>) -> EmbedRequest {
34 EmbedRequest {
35 inputs,
36 budget: RemainingBudget::starting_now(Duration::from_secs(30)),
37 cancel: CancellationToken::new(),
38 }
39}
40
41pub async fn assert_embedding_provider<P: EmbeddingProviderV1 + ?Sized>(provider: &P) {
51 assert_declaration(provider);
52 assert_alignment_and_width(provider).await;
53 assert_determinism(provider).await;
54 assert_empty_batch(provider).await;
55 assert_budget_and_cancellation(provider).await;
56
57 provider
58 .health()
59 .await
60 .expect("a provider that cannot answer `health` cannot be made ready");
61}
62
63fn assert_declaration<P: EmbeddingProviderV1 + ?Sized>(provider: &P) {
65 let space = provider.embedding_space();
66 assert_eq!(
67 space.dimension,
68 provider.dimension(),
69 "dimension() and embedding_space().dimension describe one space and must agree"
70 );
71 assert!(
72 provider.dimension() > 0,
73 "a zero-width space cannot rank anything"
74 );
75 assert!(
76 !space.identity_hash.is_empty(),
77 "the identity hash is what readiness compares against; an empty one \
78 makes every space look alike"
79 );
80}
81
82fn sample_inputs() -> Vec<String> {
86 vec![
87 "the first input".to_owned(),
88 "a second, quite different input".to_owned(),
89 String::new(),
90 ]
91}
92
93async fn assert_alignment_and_width<P: EmbeddingProviderV1 + ?Sized>(provider: &P) {
94 let dimension = provider.dimension() as usize;
95 let inputs = sample_inputs();
96 let response = provider
97 .embed(request(inputs.clone()))
98 .await
99 .expect("a provider must embed a well-formed batch");
100
101 assert_eq!(
102 response.vectors.len(),
103 inputs.len(),
104 "vectors are aligned with inputs by index, so a short answer is a \
105 silent mis-assignment of every vector after the gap"
106 );
107 for (index, vector) in response.vectors.iter().enumerate() {
108 assert_eq!(
109 vector.len(),
110 dimension,
111 "vector {index} is {} wide against a declared width of {dimension}",
112 vector.len()
113 );
114 assert!(
115 vector.iter().all(|lane| lane.is_finite()),
116 "vector {index} carries a NaN or an infinity, which no distance \
117 operator can order"
118 );
119 }
120 assert_eq!(
121 &response.space,
122 provider.embedding_space(),
123 "the echoed space must be the declared one, or a mismatch is only \
124 discoverable at configuration time"
125 );
126}
127
128const DETERMINISM_TOLERANCE: f32 = 1e-4;
135
136fn determinism_violation(first: &[Vec<f32>], second: &[Vec<f32>]) -> Option<String> {
138 if first.len() != second.len() {
139 return Some(format!(
140 "the same batch answered {} vectors and then {}",
141 first.len(),
142 second.len()
143 ));
144 }
145 for (index, (a, b)) in first.iter().zip(second).enumerate() {
146 if a.len() != b.len() {
147 return Some(format!("vector {index} changed width between calls"));
148 }
149 let similarity = cosine(a, b);
150 if similarity < 1.0 - DETERMINISM_TOLERANCE {
151 return Some(format!(
152 "vector {index} drifted to cosine {similarity} of itself between two calls \
153 with the same input; the same text must embed to the same direction"
154 ));
155 }
156 }
157 None
158}
159
160fn cosine(a: &[f32], b: &[f32]) -> f32 {
161 let dot: f32 = a.iter().zip(b).map(|(x, y)| x * y).sum();
162 let norm = |v: &[f32]| v.iter().map(|x| x * x).sum::<f32>().sqrt();
163 let denominator = norm(a) * norm(b);
164 if denominator == 0.0 {
165 return if a == b { 1.0 } else { 0.0 };
167 }
168 dot / denominator
169}
170
171async fn assert_determinism<P: EmbeddingProviderV1 + ?Sized>(provider: &P) {
172 let inputs = sample_inputs();
173 let first = provider
174 .embed(request(inputs.clone()))
175 .await
176 .expect("a provider must embed a well-formed batch");
177 let second = provider
178 .embed(request(inputs))
179 .await
180 .expect("a provider must embed a well-formed batch");
181
182 if let Some(problem) = determinism_violation(&first.vectors, &second.vectors) {
194 panic!("{problem}");
195 }
196 assert_ne!(
197 first.vectors.first(),
198 first.vectors.get(1),
199 "two unrelated inputs embedded identically; a provider that answers a \
200 constant passes every other clause here"
201 );
202}
203
204async fn assert_empty_batch<P: EmbeddingProviderV1 + ?Sized>(provider: &P) {
205 let empty = provider
206 .embed(request(Vec::new()))
207 .await
208 .expect("an empty batch is a no-op, not an error");
209 assert!(
210 empty.vectors.is_empty(),
211 "an empty batch produced {} vectors",
212 empty.vectors.len()
213 );
214}
215
216async fn assert_budget_and_cancellation<P: EmbeddingProviderV1 + ?Sized>(provider: &P) {
227 let exhausted = EmbedRequest {
228 inputs: vec!["anything".to_owned()],
229 budget: RemainingBudget::starting_now(Duration::ZERO),
230 cancel: CancellationToken::new(),
231 };
232 assert!(
233 matches!(
234 provider.embed(exhausted).await,
235 Err(EmbeddingProviderError::Deadline)
236 ),
237 "an exhausted budget must be refused as `Deadline`, not served late: \
238 the caller's deadline is absolute and already spent"
239 );
240
241 let cancel = CancellationToken::new();
242 cancel.cancel();
243 let cancelled = EmbedRequest {
244 inputs: vec!["anything".to_owned()],
245 budget: RemainingBudget::starting_now(Duration::from_secs(30)),
246 cancel,
247 };
248 assert!(
249 matches!(
250 provider.embed(cancelled).await,
251 Err(EmbeddingProviderError::Cancelled)
252 ),
253 "a cancelled call must be refused as `Cancelled`"
254 );
255}
256
257#[cfg(test)]
258mod tests {
259 use super::determinism_violation;
260
261 fn unit(v: &[f32]) -> Vec<f32> {
262 let norm = v.iter().map(|x| x * x).sum::<f32>().sqrt();
263 v.iter().map(|x| x / norm).collect()
264 }
265
266 #[test]
269 fn last_bits_drift_is_the_same_embedding() {
270 let first = vec![unit(&[0.3, 0.5, 0.8, 0.1])];
271 let second: Vec<Vec<f32>> = first
272 .iter()
273 .map(|v| v.iter().map(|x| x + 1e-6).collect())
274 .collect();
275 assert_ne!(first, second, "the fixture must actually differ");
276 assert_eq!(determinism_violation(&first, &second), None);
277 }
278
279 #[test]
282 fn a_different_direction_is_not_the_same_embedding() {
283 let first = vec![unit(&[1.0, 0.0, 0.0, 0.0])];
284 let second = vec![unit(&[0.9, 0.3, 0.0, 0.0])];
285 let problem =
286 determinism_violation(&first, &second).expect("a vector that moved is refused");
287 assert!(problem.contains("drifted"), "{problem}");
288 }
289
290 #[test]
294 fn a_zero_vector_is_the_same_only_as_another_zero_vector() {
295 let zero = vec![vec![0.0_f32, 0.0, 0.0]];
296 assert_eq!(
297 determinism_violation(&zero, &zero),
298 None,
299 "a provider that answers a zero vector twice is deterministic"
300 );
301 let other = vec![unit(&[1.0, 0.0, 0.0])];
302 assert!(
303 determinism_violation(&zero, &other).is_some(),
304 "a zero vector and then a real one is not the same embedding"
305 );
306 assert!(
307 determinism_violation(&other, &zero).is_some(),
308 "nor the other way round"
309 );
310 }
311
312 #[test]
313 fn a_changed_shape_is_refused() {
314 let one = vec![unit(&[1.0, 2.0])];
315 assert!(
316 determinism_violation(&one, &[]).is_some(),
317 "a vector went missing"
318 );
319 assert!(
320 determinism_violation(&one, &[unit(&[1.0, 2.0, 3.0])]).is_some(),
321 "a vector changed width"
322 );
323 }
324}