Skip to content

Commit ae64f91

Browse files
committed
bgp, rdb: make small-domain proptests exhaustive
The PathOrigin dedup test draws from a 3x3 space — replace with an exhaustive loop. The cross-family within test depends only on the V4/V6 discriminant — replace with a single deterministic case. Delete the prefix-length-in-bounds tests, which only assert that proptest's own range constraint holds.
1 parent 04066ed commit ae64f91

4 files changed

Lines changed: 60 additions & 66 deletions

File tree

bgp/src/messages.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8984,4 +8984,56 @@ mod tests {
89848984
assert!(Header::from_wire(&wire).is_err());
89858985
}
89868986
}
8987+
8988+
/// Exhaustive test: duplicate ORIGIN attributes are deduplicated to
8989+
/// the first occurrence. PathOrigin has 3 variants, so 9 cases total.
8990+
#[test]
8991+
fn duplicate_origin_attrs_deduplicated() {
8992+
let origins =
8993+
[PathOrigin::Igp, PathOrigin::Egp, PathOrigin::Incomplete];
8994+
for origin1 in origins {
8995+
for origin2 in origins {
8996+
let mut wire = Vec::new();
8997+
wire.extend_from_slice(&0u16.to_be_bytes());
8998+
8999+
let attrs = vec![
9000+
path_attribute_flags::TRANSITIVE,
9001+
PathAttributeTypeCode::Origin as u8,
9002+
1,
9003+
origin1 as u8,
9004+
path_attribute_flags::TRANSITIVE,
9005+
PathAttributeTypeCode::Origin as u8,
9006+
1,
9007+
origin2 as u8,
9008+
];
9009+
9010+
wire.extend_from_slice(&(attrs.len() as u16).to_be_bytes());
9011+
wire.extend_from_slice(&attrs);
9012+
9013+
let decoded =
9014+
UpdateMessage::from_wire(&wire).expect("should decode");
9015+
9016+
let decoded_origins: Vec<_> = decoded
9017+
.path_attributes
9018+
.iter()
9019+
.filter_map(|a| match &a.value {
9020+
PathAttributeValue::Origin(o) => Some(*o),
9021+
_ => None,
9022+
})
9023+
.collect();
9024+
9025+
assert_eq!(
9026+
decoded_origins.len(),
9027+
1,
9028+
"origin1={origin1:?} origin2={origin2:?}: \
9029+
expected exactly one ORIGIN after dedup",
9030+
);
9031+
assert_eq!(
9032+
decoded_origins[0], origin1,
9033+
"origin1={origin1:?} origin2={origin2:?}: \
9034+
should keep first ORIGIN value",
9035+
);
9036+
}
9037+
}
9038+
}
89879039
}

bgp/src/proptest.rs

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -616,50 +616,6 @@ proptest! {
616616
}
617617
}
618618

619-
/// Property: Duplicate non-MP-BGP attributes are deduplicated to first occurrence
620-
#[test]
621-
fn prop_duplicate_attrs_deduplicated(
622-
origin1 in path_origin_strategy(),
623-
origin2 in path_origin_strategy()
624-
) {
625-
// Manually construct wire bytes with duplicate ORIGIN attributes
626-
let mut wire = Vec::new();
627-
628-
// Withdrawn routes length (0)
629-
wire.extend_from_slice(&0u16.to_be_bytes());
630-
631-
// Path attributes: two ORIGIN attributes (second should be discarded)
632-
let attrs = vec![
633-
// First ORIGIN attribute
634-
path_attribute_flags::TRANSITIVE,
635-
PathAttributeTypeCode::Origin as u8,
636-
1, // length
637-
origin1 as u8,
638-
// Second ORIGIN attribute (should be discarded)
639-
path_attribute_flags::TRANSITIVE,
640-
PathAttributeTypeCode::Origin as u8,
641-
1, // length
642-
origin2 as u8,
643-
];
644-
645-
// Path attributes length
646-
wire.extend_from_slice(&(attrs.len() as u16).to_be_bytes());
647-
wire.extend_from_slice(&attrs);
648-
649-
let decoded = UpdateMessage::from_wire(&wire).expect("should decode");
650-
651-
// Should only have one ORIGIN attribute
652-
let origins: Vec<_> = decoded.path_attributes.iter()
653-
.filter_map(|a| match &a.value {
654-
PathAttributeValue::Origin(o) => Some(*o),
655-
_ => None,
656-
})
657-
.collect();
658-
659-
prop_assert_eq!(origins.len(), 1, "Should have exactly one ORIGIN after dedup");
660-
prop_assert_eq!(origins[0], origin1, "Should keep first ORIGIN value");
661-
}
662-
663619
/// Property: Encoding then decoding produces semantically equivalent message
664620
#[test]
665621
fn prop_encode_decode_semantic_equivalence(update in update_strategy()) {

rdb/src/proptest.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -259,28 +259,6 @@ proptest! {
259259
);
260260
}
261261

262-
/// Property: Prefix enum V4 is never within V6 and vice versa
263-
#[test]
264-
fn prop_prefix_enum_no_cross_family(p4 in ipv4_prefix_strategy(), p6 in ipv6_prefix_strategy()) {
265-
let v4 = Prefix::V4(p4);
266-
let v6 = Prefix::V6(p6);
267-
268-
prop_assert!(!v4.within(&v6), "IPv4 should not be within IPv6");
269-
prop_assert!(!v6.within(&v4), "IPv6 should not be within IPv4");
270-
}
271-
272-
/// Property: IPv4 prefix length bounds are validated (0-32)
273-
#[test]
274-
fn prop_ipv4_length_in_bounds(prefix in ipv4_prefix_strategy()) {
275-
prop_assert!(prefix.length <= 32u8, "IPv4 prefix length must be <= 32");
276-
}
277-
278-
/// Property: IPv6 prefix length bounds are validated (0-128)
279-
#[test]
280-
fn prop_ipv6_length_in_bounds(prefix in ipv6_prefix_strategy()) {
281-
prop_assert!(prefix.length <= 128u8, "IPv6 prefix length must be <= 128");
282-
}
283-
284262
/// Property: IPv4 host bits unset operation is idempotent
285263
#[test]
286264
fn prop_ipv4_unset_host_bits_idempotent(prefix in ipv4_prefix_strategy()) {

rdb/src/types.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,4 +1042,12 @@ mod test {
10421042
let st = static_path(ip1);
10431043
assert_eq!(bgp.cmp(&st), st.cmp(&bgp).reverse());
10441044
}
1045+
1046+
#[test]
1047+
fn prefix_no_cross_family_within() {
1048+
let v4 = Prefix::V4(Prefix4::new(Ipv4Addr::new(10, 0, 0, 0), 8));
1049+
let v6 = Prefix::V6(Prefix6::new(Ipv6Addr::LOCALHOST, 128));
1050+
assert!(!v4.within(&v6));
1051+
assert!(!v6.within(&v4));
1052+
}
10451053
}

0 commit comments

Comments
 (0)