352 lines
10 KiB
Rust
352 lines
10 KiB
Rust
mod common;
|
||
|
||
use std::net::Ipv6Addr;
|
||
|
||
use common::test_helper::{
|
||
indent_block, payloads_to_string, test_report, v4_origin, v6_origin,
|
||
};
|
||
|
||
use rpki::rtr::cache::{Delta, Snapshot};
|
||
use rpki::rtr::payload::Payload;
|
||
use rpki::rtr::store_db::RtrStore;
|
||
|
||
fn snapshot_to_string(snapshot: &Snapshot) -> String {
|
||
let payloads = snapshot.payloads_for_rtr();
|
||
payloads_to_string(&payloads)
|
||
}
|
||
|
||
fn delta_to_string(delta: &Delta) -> String {
|
||
format!(
|
||
"serial: {}\nannounced:\n{}withdrawn:\n{}",
|
||
delta.serial(),
|
||
indent_block(&payloads_to_string(delta.announced()), 2),
|
||
indent_block(&payloads_to_string(delta.withdrawn()), 2),
|
||
)
|
||
}
|
||
|
||
#[test]
|
||
fn store_db_save_and_get_snapshot() {
|
||
let dir = tempfile::tempdir().unwrap();
|
||
let store = RtrStore::open(dir.path()).unwrap();
|
||
|
||
let input_payloads = vec![
|
||
Payload::RouteOrigin(v4_origin(192, 0, 2, 0, 24, 24, 64496)),
|
||
Payload::RouteOrigin(v6_origin(
|
||
Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0),
|
||
32,
|
||
48,
|
||
64497,
|
||
)),
|
||
];
|
||
let snapshot = Snapshot::from_payloads(input_payloads.clone());
|
||
|
||
store.save_snapshot(&snapshot).unwrap();
|
||
let loaded = store.get_snapshot().unwrap().expect("snapshot should exist");
|
||
|
||
let input = format!(
|
||
"db_path: {}\nsnapshot:\n{}",
|
||
dir.path().display(),
|
||
indent_block(&payloads_to_string(&input_payloads), 2),
|
||
);
|
||
|
||
let output = format!(
|
||
"loaded snapshot:\n{}same_content: {}\n",
|
||
indent_block(&snapshot_to_string(&loaded), 2),
|
||
snapshot.same_content(&loaded),
|
||
);
|
||
|
||
test_report(
|
||
"store_db_save_and_get_snapshot",
|
||
"验证 save_snapshot() 后可以通过 get_snapshot() 正确读回 Snapshot。",
|
||
&input,
|
||
&output,
|
||
);
|
||
|
||
assert!(snapshot.same_content(&loaded));
|
||
}
|
||
|
||
#[test]
|
||
fn store_db_set_and_get_meta_fields() {
|
||
let dir = tempfile::tempdir().unwrap();
|
||
let store = RtrStore::open(dir.path()).unwrap();
|
||
|
||
store.set_session_id(42).unwrap();
|
||
store.set_serial(100).unwrap();
|
||
store.set_delta_window(101, 110).unwrap();
|
||
|
||
let session_id = store.get_session_id().unwrap();
|
||
let serial = store.get_serial().unwrap();
|
||
let window = store.get_delta_window().unwrap();
|
||
|
||
let input = format!(
|
||
"db_path: {}\nset_session_id=42\nset_serial=100\nset_delta_window=(101, 110)\n",
|
||
dir.path().display(),
|
||
);
|
||
|
||
let output = format!(
|
||
"get_session_id: {:?}\nget_serial: {:?}\nget_delta_window: {:?}\n",
|
||
session_id, serial, window,
|
||
);
|
||
|
||
test_report(
|
||
"store_db_set_and_get_meta_fields",
|
||
"验证 session_id / serial / delta_window 能正确写入并读回。",
|
||
&input,
|
||
&output,
|
||
);
|
||
|
||
assert_eq!(session_id, Some(42));
|
||
assert_eq!(serial, Some(100));
|
||
assert_eq!(window, Some((101, 110)));
|
||
}
|
||
|
||
#[test]
|
||
fn store_db_save_and_get_delta() {
|
||
let dir = tempfile::tempdir().unwrap();
|
||
let store = RtrStore::open(dir.path()).unwrap();
|
||
|
||
let delta = Delta::new(
|
||
101,
|
||
vec![Payload::RouteOrigin(v4_origin(198, 51, 100, 0, 24, 24, 64497))],
|
||
vec![Payload::RouteOrigin(v4_origin(192, 0, 2, 0, 24, 24, 64496))],
|
||
);
|
||
|
||
store.save_delta(&delta).unwrap();
|
||
let loaded = store.get_delta(101).unwrap().expect("delta should exist");
|
||
|
||
let input = format!(
|
||
"db_path: {}\ndelta:\n{}",
|
||
dir.path().display(),
|
||
indent_block(&delta_to_string(&delta), 2),
|
||
);
|
||
|
||
let output = format!(
|
||
"loaded delta:\n{}",
|
||
indent_block(&delta_to_string(&loaded), 2),
|
||
);
|
||
|
||
test_report(
|
||
"store_db_save_and_get_delta",
|
||
"验证 save_delta() 后可以通过 get_delta(serial) 正确读回 Delta。",
|
||
&input,
|
||
&output,
|
||
);
|
||
|
||
assert_eq!(loaded.serial(), 101);
|
||
assert_eq!(loaded.announced().len(), 1);
|
||
assert_eq!(loaded.withdrawn().len(), 1);
|
||
}
|
||
|
||
#[test]
|
||
fn store_db_load_deltas_since_returns_only_newer_deltas_in_order() {
|
||
let dir = tempfile::tempdir().unwrap();
|
||
let store = RtrStore::open(dir.path()).unwrap();
|
||
|
||
let d101 = Delta::new(
|
||
101,
|
||
vec![Payload::RouteOrigin(v4_origin(192, 0, 2, 0, 24, 24, 64496))],
|
||
vec![],
|
||
);
|
||
let d102 = Delta::new(
|
||
102,
|
||
vec![Payload::RouteOrigin(v4_origin(198, 51, 100, 0, 24, 24, 64497))],
|
||
vec![],
|
||
);
|
||
let d103 = Delta::new(
|
||
103,
|
||
vec![Payload::RouteOrigin(v4_origin(203, 0, 113, 0, 24, 24, 64498))],
|
||
vec![],
|
||
);
|
||
|
||
store.save_delta(&d101).unwrap();
|
||
store.save_delta(&d102).unwrap();
|
||
store.save_delta(&d103).unwrap();
|
||
|
||
let loaded = store.load_deltas_since(101).unwrap();
|
||
|
||
let input = format!(
|
||
"db_path: {}\nsaved delta serials: [101, 102, 103]\nload_deltas_since(101)\n",
|
||
dir.path().display(),
|
||
);
|
||
|
||
let output = {
|
||
let mut s = String::new();
|
||
for (idx, d) in loaded.iter().enumerate() {
|
||
s.push_str(&format!("loaded[{}]:\n", idx));
|
||
s.push_str(&indent_block(&delta_to_string(d), 2));
|
||
}
|
||
s
|
||
};
|
||
|
||
test_report(
|
||
"store_db_load_deltas_since_returns_only_newer_deltas_in_order",
|
||
"验证 load_deltas_since(x) 只返回 serial > x 的 Delta,且顺序正确。",
|
||
&input,
|
||
&output,
|
||
);
|
||
|
||
assert_eq!(loaded.len(), 2);
|
||
assert_eq!(loaded[0].serial(), 102);
|
||
assert_eq!(loaded[1].serial(), 103);
|
||
}
|
||
|
||
#[test]
|
||
fn store_db_save_snapshot_and_meta_writes_all_fields() {
|
||
let dir = tempfile::tempdir().unwrap();
|
||
let store = RtrStore::open(dir.path()).unwrap();
|
||
|
||
let snapshot = Snapshot::from_payloads(vec![
|
||
Payload::RouteOrigin(v4_origin(192, 0, 2, 0, 24, 24, 64496)),
|
||
Payload::RouteOrigin(v4_origin(198, 51, 100, 0, 24, 24, 64497)),
|
||
]);
|
||
|
||
store.save_snapshot_and_meta(&snapshot, 42, 100).unwrap();
|
||
|
||
let loaded_snapshot = store.get_snapshot().unwrap().expect("snapshot should exist");
|
||
let loaded_session = store.get_session_id().unwrap();
|
||
let loaded_serial = store.get_serial().unwrap();
|
||
|
||
let input = format!(
|
||
"db_path: {}\nsnapshot:\n{}session_id=42\nserial=100\n",
|
||
dir.path().display(),
|
||
indent_block(&snapshot_to_string(&snapshot), 2),
|
||
);
|
||
|
||
let output = format!(
|
||
"loaded_snapshot:\n{}loaded_session_id: {:?}\nloaded_serial: {:?}\n",
|
||
indent_block(&snapshot_to_string(&loaded_snapshot), 2),
|
||
loaded_session,
|
||
loaded_serial,
|
||
);
|
||
|
||
test_report(
|
||
"store_db_save_snapshot_and_meta_writes_all_fields",
|
||
"验证 save_snapshot_and_meta() 会同时写入 snapshot、session_id 和 serial。",
|
||
&input,
|
||
&output,
|
||
);
|
||
|
||
assert!(snapshot.same_content(&loaded_snapshot));
|
||
assert_eq!(loaded_session, Some(42));
|
||
assert_eq!(loaded_serial, Some(100));
|
||
}
|
||
|
||
#[test]
|
||
fn store_db_load_snapshot_and_serial_returns_consistent_pair() {
|
||
let dir = tempfile::tempdir().unwrap();
|
||
let store = RtrStore::open(dir.path()).unwrap();
|
||
|
||
let snapshot = Snapshot::from_payloads(vec![
|
||
Payload::RouteOrigin(v4_origin(203, 0, 113, 0, 24, 24, 64498)),
|
||
]);
|
||
|
||
store.save_snapshot_and_serial(&snapshot, 200).unwrap();
|
||
|
||
let loaded = store
|
||
.load_snapshot_and_serial()
|
||
.unwrap()
|
||
.expect("snapshot+serial should exist");
|
||
|
||
let input = format!(
|
||
"db_path: {}\nsnapshot:\n{}serial=200\n",
|
||
dir.path().display(),
|
||
indent_block(&snapshot_to_string(&snapshot), 2),
|
||
);
|
||
|
||
let output = format!(
|
||
"loaded_snapshot:\n{}loaded_serial: {}\n",
|
||
indent_block(&snapshot_to_string(&loaded.0), 2),
|
||
loaded.1,
|
||
);
|
||
|
||
test_report(
|
||
"store_db_load_snapshot_and_serial_returns_consistent_pair",
|
||
"验证 load_snapshot_and_serial() 能正确返回一致的 snapshot 与 serial。",
|
||
&input,
|
||
&output,
|
||
);
|
||
|
||
assert!(snapshot.same_content(&loaded.0));
|
||
assert_eq!(loaded.1, 200);
|
||
}
|
||
|
||
#[test]
|
||
fn store_db_delete_snapshot_delta_and_serial_removes_data() {
|
||
let dir = tempfile::tempdir().unwrap();
|
||
let store = RtrStore::open(dir.path()).unwrap();
|
||
|
||
let snapshot = Snapshot::from_payloads(vec![
|
||
Payload::RouteOrigin(v4_origin(192, 0, 2, 0, 24, 24, 64496)),
|
||
]);
|
||
let delta = Delta::new(
|
||
101,
|
||
vec![Payload::RouteOrigin(v4_origin(198, 51, 100, 0, 24, 24, 64497))],
|
||
vec![],
|
||
);
|
||
|
||
store.save_snapshot(&snapshot).unwrap();
|
||
store.save_delta(&delta).unwrap();
|
||
store.set_serial(100).unwrap();
|
||
|
||
store.delete_snapshot().unwrap();
|
||
store.delete_delta(101).unwrap();
|
||
store.delete_serial().unwrap();
|
||
|
||
let loaded_snapshot = store.get_snapshot().unwrap();
|
||
let loaded_delta = store.get_delta(101).unwrap();
|
||
let loaded_serial = store.get_serial().unwrap();
|
||
|
||
let input = format!(
|
||
"db_path: {}\nsave snapshot + delta(101) + serial(100), then delete all three.\n",
|
||
dir.path().display(),
|
||
);
|
||
|
||
let output = format!(
|
||
"get_snapshot: {:?}\nget_delta(101): {:?}\nget_serial: {:?}\n",
|
||
loaded_snapshot.as_ref().map(|_| "Some(snapshot)"),
|
||
loaded_delta.as_ref().map(|_| "Some(delta)"),
|
||
loaded_serial,
|
||
);
|
||
|
||
test_report(
|
||
"store_db_delete_snapshot_delta_and_serial_removes_data",
|
||
"验证 delete_snapshot()/delete_delta()/delete_serial() 后,对应数据不再可读。",
|
||
&input,
|
||
&output,
|
||
);
|
||
|
||
assert!(loaded_snapshot.is_none());
|
||
assert!(loaded_delta.is_none());
|
||
assert!(loaded_serial.is_none());
|
||
}
|
||
|
||
#[test]
|
||
fn store_db_load_snapshot_and_serial_errors_on_inconsistent_state() {
|
||
let dir = tempfile::tempdir().unwrap();
|
||
let store = RtrStore::open(dir.path()).unwrap();
|
||
|
||
let snapshot = Snapshot::from_payloads(vec![
|
||
Payload::RouteOrigin(v4_origin(192, 0, 2, 0, 24, 24, 64496)),
|
||
]);
|
||
|
||
store.save_snapshot(&snapshot).unwrap();
|
||
// 故意不写 serial,制造不一致状态
|
||
|
||
let result = store.load_snapshot_and_serial();
|
||
|
||
let input = format!(
|
||
"db_path: {}\n仅保存 snapshot,不保存 serial。\n",
|
||
dir.path().display(),
|
||
);
|
||
|
||
let output = format!("load_snapshot_and_serial result: {:?}\n", result);
|
||
|
||
test_report(
|
||
"store_db_load_snapshot_and_serial_errors_on_inconsistent_state",
|
||
"验证当 snapshot 和 serial 状态不一致时,load_snapshot_and_serial() 返回错误。",
|
||
&input,
|
||
&output,
|
||
);
|
||
|
||
assert!(result.is_err());
|
||
} |