diff --git a/fuzz/fuzz_targets/mpu_crdt.rs b/fuzz/fuzz_targets/mpu_crdt.rs index 3051f2f4..86eb9900 100644 --- a/fuzz/fuzz_targets/mpu_crdt.rs +++ b/fuzz/fuzz_targets/mpu_crdt.rs @@ -1,7 +1,7 @@ #![no_main] +use garage_fuzz::check_crdt_laws; use garage_model::s3::mpu_table::{MpuPart, MpuPartKey, MultipartUpload}; -use garage_table::crdt::Crdt; use libfuzzer_sys::fuzz_target; /// Build a MultipartUpload from an arbitrary deleted flag and parts list, using a fixed @@ -33,45 +33,5 @@ fuzz_target!(|inputs: ( (bool, Vec<(MpuPartKey, MpuPart)>) )| { let ((d1, p1), (d2, p2), (d3, p3)) = inputs; - let a = make_mpu(d1, p1); - let b = make_mpu(d2, p2); - let c = make_mpu(d3, p3); - - // Idempotency: merge(a, a) == a - { - let mut a2 = a.clone(); - a2.merge(&a.clone()); - assert_eq!(a2, a, "merge is not idempotent: {a2:#?} != {a:#?}"); - } - - // Commutativity: merge(a, b) == merge(b, a) - let ab = { - let mut t = a.clone(); - t.merge(&b); - t - }; - let ba = { - let mut t = b.clone(); - t.merge(&a); - t - }; - assert_eq!(ab, ba, "merge is not commutative: {ab:#?} != {ba:#?}"); - - // Associativity: merge(merge(a, b), c) == merge(a, merge(b, c)) - let ab_c = { - let mut t = ab.clone(); - t.merge(&c); - t - }; - let bc = { - let mut t = b.clone(); - t.merge(&c); - t - }; - let a_bc = { - let mut t = a.clone(); - t.merge(&bc); - t - }; - assert_eq!(ab_c, a_bc, "merge is not associative: {ab_c:#?} != {a_bc:#?}"); + check_crdt_laws(make_mpu(d1, p1), make_mpu(d2, p2), make_mpu(d3, p3)); }); diff --git a/fuzz/fuzz_targets/version_crdt.rs b/fuzz/fuzz_targets/version_crdt.rs index 87fc7368..b14c6120 100644 --- a/fuzz/fuzz_targets/version_crdt.rs +++ b/fuzz/fuzz_targets/version_crdt.rs @@ -1,7 +1,7 @@ #![no_main] +use garage_fuzz::check_crdt_laws; use garage_model::s3::version_table::{Version, VersionBacklink, VersionBlock, VersionBlockKey}; -use garage_table::crdt::Crdt; use libfuzzer_sys::fuzz_target; /// Build a Version from an arbitrary deleted flag and block list, using a fixed uuid/backlink @@ -34,45 +34,5 @@ fuzz_target!(|inputs: ( (bool, Vec<(VersionBlockKey, VersionBlock)>) )| { let ((d1, b1), (d2, b2), (d3, b3)) = inputs; - let a = make_version(d1, b1); - let b = make_version(d2, b2); - let c = make_version(d3, b3); - - // Idempotency: merge(a, a) == a - { - let mut a2 = a.clone(); - a2.merge(&a.clone()); - assert_eq!(a2, a, "merge is not idempotent: {a2:#?} != {a:#?}"); - } - - // Commutativity: merge(a, b) == merge(b, a) - let ab = { - let mut t = a.clone(); - t.merge(&b); - t - }; - let ba = { - let mut t = b.clone(); - t.merge(&a); - t - }; - assert_eq!(ab, ba, "merge is not commutative: {ab:#?} != {ba:#?}"); - - // Associativity: merge(merge(a, b), c) == merge(a, merge(b, c)) - let ab_c = { - let mut t = ab.clone(); - t.merge(&c); - t - }; - let bc = { - let mut t = b.clone(); - t.merge(&c); - t - }; - let a_bc = { - let mut t = a.clone(); - t.merge(&bc); - t - }; - assert_eq!(ab_c, a_bc, "merge is not associative: {ab_c:#?} != {a_bc:#?}"); + check_crdt_laws(make_version(d1, b1), make_version(d2, b2), make_version(d3, b3)); }); diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs new file mode 100644 index 00000000..1715d1e9 --- /dev/null +++ b/fuzz/src/lib.rs @@ -0,0 +1,45 @@ +use garage_table::crdt::Crdt; +use std::fmt::Debug; + +pub fn check_crdt_laws(a: T, b: T, c: T) +where + T: Crdt + PartialEq + Clone + Debug, +{ + // Idempotency: merge(a, a) == a + { + let mut a2 = a.clone(); + a2.merge(&a.clone()); + assert_eq!(a2, a, "merge is not idempotent: {a2:#?} != {a:#?}"); + } + + // Commutativity: merge(a, b) == merge(b, a) + let ab = { + let mut t = a.clone(); + t.merge(&b); + t + }; + let ba = { + let mut t = b.clone(); + t.merge(&a); + t + }; + assert_eq!(ab, ba, "merge is not commutative: {ab:#?} != {ba:#?}"); + + // Associativity: merge(merge(a, b), c) == merge(a, merge(b, c)) + let ab_c = { + let mut t = ab.clone(); + t.merge(&c); + t + }; + let bc = { + let mut t = b.clone(); + t.merge(&c); + t + }; + let a_bc = { + let mut t = a.clone(); + t.merge(&bc); + t + }; + assert_eq!(ab_c, a_bc, "merge is not associative: {ab_c:#?} != {a_bc:#?}"); +}