Skip to content

Commit 63393c8

Browse files
committed
fixing rust build a bit, adding testing to crdt
1 parent ecdab32 commit 63393c8

2 files changed

Lines changed: 153 additions & 0 deletions

File tree

.github/workflows/rust.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,20 @@ jobs:
1616

1717
steps:
1818
- uses: actions/checkout@v4
19+
- name: Install Rust toolchain
20+
uses: actions-rs/toolchain@v1
21+
with:
22+
profile: minimal
23+
toolchain: stable
24+
override: true
25+
components: rustfmt, clippy
26+
- name: Check formatting
27+
run: cargo fmt --all -- --check
28+
- name: Clippy
29+
run: cargo clippy --all -- -D warnings
1930
- name: Build
2031
run: cargo build --verbose
2132
- name: Run tests
2233
run: cargo test --verbose
34+
- name: Run benchmarks
35+
run: cargo bench --no-run

src/core/centroid_crdt.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,144 @@ impl CentroidCRDT {
160160
distances.truncate(limit);
161161
distances
162162
}
163+
}
164+
165+
#[cfg(test)]
166+
mod tests {
167+
use super::*;
168+
use uuid::Uuid;
169+
170+
#[test]
171+
fn test_create_centroid() {
172+
let node_id = Uuid::new_v4();
173+
let mut crdt = CentroidCRDT::new(node_id);
174+
175+
let vector = Vector::new(vec![1.0, 2.0, 3.0]);
176+
let centroid_id = crdt.create_centroid(vector.clone());
177+
178+
assert_eq!(crdt.centroids.len(), 1);
179+
assert_eq!(crdt.operations.len(), 1);
180+
181+
let centroid = crdt.get_centroid(&centroid_id).unwrap();
182+
assert_eq!(centroid.vector.values, vector.values);
183+
}
184+
185+
#[test]
186+
fn test_update_centroid() {
187+
let node_id = Uuid::new_v4();
188+
let mut crdt = CentroidCRDT::new(node_id);
189+
190+
let vector1 = Vector::new(vec![1.0, 2.0, 3.0]);
191+
let centroid_id = crdt.create_centroid(vector1);
192+
193+
let vector2 = Vector::new(vec![4.0, 5.0, 6.0]);
194+
crdt.update_centroid(centroid_id, vector2).unwrap();
195+
196+
assert_eq!(crdt.operations.len(), 2);
197+
198+
let centroid = crdt.get_centroid(&centroid_id).unwrap();
199+
// After updating, the vector should be a weighted average of the original and new vector
200+
// With 1 existing element and 1 new element, the weights are 1/2 each
201+
// So the expected value is (1.0*1 + 4.0*1)/2, (2.0*1 + 5.0*1)/2, (3.0*1 + 6.0*1)/2
202+
// Which equals 2.5, 3.5, 4.5
203+
assert!(centroid.vector.values[0] > 1.0 && centroid.vector.values[0] < 4.0);
204+
assert!(centroid.vector.values[1] > 2.0 && centroid.vector.values[1] < 5.0);
205+
assert!(centroid.vector.values[2] > 3.0 && centroid.vector.values[2] < 6.0);
206+
assert_eq!(centroid.count, 2);
207+
}
208+
209+
#[test]
210+
fn test_delete_centroid() {
211+
let node_id = Uuid::new_v4();
212+
let mut crdt = CentroidCRDT::new(node_id);
213+
214+
let vector = Vector::new(vec![1.0, 2.0, 3.0]);
215+
let centroid_id = crdt.create_centroid(vector.clone());
216+
217+
crdt.delete_centroid(centroid_id).unwrap();
218+
219+
assert_eq!(crdt.centroids.len(), 0);
220+
assert_eq!(crdt.operations.len(), 2);
221+
}
222+
223+
#[test]
224+
fn test_merge() {
225+
// Create two CRDTs
226+
let node_id1 = Uuid::new_v4();
227+
let node_id2 = Uuid::new_v4();
228+
let mut crdt1 = CentroidCRDT::new(node_id1);
229+
let mut crdt2 = CentroidCRDT::new(node_id2);
230+
231+
// Add a centroid to the first CRDT
232+
let vector1 = Vector::new(vec![1.0, 2.0, 3.0]);
233+
let centroid_id1 = crdt1.create_centroid(vector1.clone());
234+
235+
// Add a different centroid to the second CRDT
236+
let vector2 = Vector::new(vec![4.0, 5.0, 6.0]);
237+
let centroid_id2 = crdt2.create_centroid(vector2.clone());
238+
239+
// Merge the second CRDT into the first
240+
crdt1.merge(&crdt2);
241+
242+
// First CRDT should now have both centroids
243+
assert_eq!(crdt1.centroids.len(), 2);
244+
assert!(crdt1.centroids.contains_key(&centroid_id1));
245+
assert!(crdt1.centroids.contains_key(&centroid_id2));
246+
247+
// Verify the centroids have the correct vectors
248+
let merged_centroid1 = crdt1.get_centroid(&centroid_id1).unwrap();
249+
let merged_centroid2 = crdt1.get_centroid(&centroid_id2).unwrap();
250+
251+
assert_eq!(merged_centroid1.vector.values, vector1.values);
252+
assert_eq!(merged_centroid2.vector.values, vector2.values);
253+
254+
// Operations should be merged too
255+
assert_eq!(crdt1.operations.len(), 2);
256+
assert_eq!(crdt1.observed.len(), 2);
257+
}
258+
259+
#[test]
260+
fn test_concurrent_operations() {
261+
// Test handling of concurrent operations with different timestamps
262+
let node_id1 = Uuid::new_v4();
263+
let node_id2 = Uuid::new_v4();
264+
let mut crdt1 = CentroidCRDT::new(node_id1);
265+
let mut crdt2 = CentroidCRDT::new(node_id2);
266+
267+
// Both CRDTs create a centroid with the same ID but different vectors
268+
let centroid_id = Uuid::new_v4();
269+
let vector1 = Vector::new(vec![1.0, 2.0, 3.0]);
270+
let vector2 = Vector::new(vec![4.0, 5.0, 6.0]);
271+
272+
// Create the same centroid in both CRDTs with different timestamps
273+
let now = chrono::Utc::now();
274+
let later = now + chrono::Duration::seconds(10);
275+
276+
// Earlier operation in CRDT1
277+
let op1 = CentroidOperation {
278+
id: Uuid::new_v4(),
279+
centroid_id,
280+
timestamp: now,
281+
operation_type: OperationType::Create(vector1),
282+
};
283+
284+
// Later operation in CRDT2
285+
let op2 = CentroidOperation {
286+
id: Uuid::new_v4(),
287+
centroid_id,
288+
timestamp: later,
289+
operation_type: OperationType::Create(vector2.clone()),
290+
};
291+
292+
crdt1.apply_operation(op1);
293+
crdt2.apply_operation(op2);
294+
295+
// Merge CRDT2 into CRDT1
296+
crdt1.merge(&crdt2);
297+
298+
// The centroid in CRDT1 should now have the vector from CRDT2
299+
// because it has a later timestamp
300+
let centroid = crdt1.get_centroid(&centroid_id).unwrap();
301+
assert_eq!(centroid.vector.values, vector2.values);
302+
}
163303
}

0 commit comments

Comments
 (0)