mirror of
https://github.com/deuxfleurs-org/garage.git
synced 2026-07-26 07:58:14 +00:00
Merge pull request 'Improvements to the fuzzing code' (#1437) from krtab/garage:fuzz_crdts into main-v2
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/garage/pulls/1437 Reviewed-by: Alex <lx@deuxfleurs.fr>
This commit is contained in:
@@ -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
|
||||
@@ -27,67 +27,11 @@ fn make_mpu(deleted: bool, parts: Vec<(MpuPartKey, MpuPart)>) -> MultipartUpload
|
||||
mpu
|
||||
}
|
||||
|
||||
fn crdt_state(mpu: &MultipartUpload) -> (bool, &[(MpuPartKey, MpuPart)]) {
|
||||
(mpu.deleted.get(), mpu.parts.items())
|
||||
}
|
||||
|
||||
fuzz_target!(|inputs: (
|
||||
(bool, Vec<(MpuPartKey, MpuPart)>),
|
||||
(bool, Vec<(MpuPartKey, MpuPart)>),
|
||||
(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!(
|
||||
crdt_state(&a2),
|
||||
crdt_state(&a),
|
||||
"merge is not idempotent: {a2:#?} != {a:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
// Commutativity: crdt_state(merge(a, b)) == crdt_state(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!(
|
||||
crdt_state(&ab),
|
||||
crdt_state(&ba),
|
||||
"merge is not commutative: {ab:#?} != {ba:#?}"
|
||||
);
|
||||
|
||||
// Associativity: crdt_state(merge(merge(a, b), c)) == crdt_state(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!(
|
||||
crdt_state(&ab_c),
|
||||
crdt_state(&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));
|
||||
});
|
||||
|
||||
@@ -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
|
||||
@@ -28,67 +28,15 @@ fn make_version(deleted: bool, mut blocks: Vec<(VersionBlockKey, VersionBlock)>)
|
||||
v
|
||||
}
|
||||
|
||||
fn crdt_state(v: &Version) -> (bool, &[(VersionBlockKey, VersionBlock)]) {
|
||||
(v.deleted.get(), v.blocks.items())
|
||||
}
|
||||
|
||||
fuzz_target!(|inputs: (
|
||||
(bool, Vec<(VersionBlockKey, VersionBlock)>),
|
||||
(bool, Vec<(VersionBlockKey, VersionBlock)>),
|
||||
(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!(
|
||||
crdt_state(&a2),
|
||||
crdt_state(&a),
|
||||
"merge is not idempotent: {a2:#?} != {a:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
// Commutativity: crdt_state(merge(a, b)) == crdt_state(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!(
|
||||
crdt_state(&ab),
|
||||
crdt_state(&ba),
|
||||
"merge is not commutative: {ab:#?} != {ba:#?}"
|
||||
);
|
||||
|
||||
// Associativity: crdt_state(merge(merge(a, b), c)) == crdt_state(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!(
|
||||
crdt_state(&ab_c),
|
||||
crdt_state(&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),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
use garage_table::crdt::Crdt;
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub fn check_crdt_laws<T>(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);
|
||||
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:#?}");
|
||||
|
||||
// LX's corrolary: merge(merge(a,b),b) = merge(a,b)
|
||||
let ab_b = {
|
||||
let mut t = ab.clone();
|
||||
t.merge(&b);
|
||||
t
|
||||
};
|
||||
assert_eq!(ab, ab_b);
|
||||
|
||||
// Associativity: merge(merge(a, b), c) == merge(a, merge(b, c))
|
||||
let ab_c = {
|
||||
let mut t = ab;
|
||||
t.merge(&c);
|
||||
t
|
||||
};
|
||||
let bc = {
|
||||
let mut t = b;
|
||||
t.merge(&c);
|
||||
t
|
||||
};
|
||||
let a_bc = {
|
||||
let mut t = a;
|
||||
t.merge(&bc);
|
||||
t
|
||||
};
|
||||
assert_eq!(
|
||||
ab_c, a_bc,
|
||||
"merge is not associative: {ab_c:#?} != {a_bc:#?}"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user