RTR server以及client的开发、test的补充
This commit is contained in:
1
tests/common/mod.rs
Normal file
1
tests/common/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod test_helper;
|
||||
332
tests/common/test_helper.rs
Normal file
332
tests/common/test_helper.rs
Normal file
@@ -0,0 +1,332 @@
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::fmt::Write;
|
||||
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use rpki::data_model::resources::ip_resources::{IPAddress, IPAddressPrefix};
|
||||
use rpki::rtr::payload::{Payload, RouteOrigin};
|
||||
use rpki::rtr::pdu::{CacheResponse, EndOfDataV1, IPv4Prefix, IPv6Prefix};
|
||||
use rpki::rtr::cache::SerialResult;
|
||||
|
||||
pub struct RtrDebugDumper {
|
||||
entries: Vec<Value>,
|
||||
}
|
||||
|
||||
impl RtrDebugDumper {
|
||||
pub fn new() -> Self {
|
||||
Self { entries: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn push<T: serde::Serialize>(&mut self, pdu: u8, body: &T) {
|
||||
self.entries.push(json!({
|
||||
"pdu": pdu,
|
||||
"pdu_name": pdu_type_name(pdu),
|
||||
"body": body
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn push_value(&mut self, pdu: u8, body: Value) {
|
||||
self.entries.push(json!({
|
||||
"pdu": pdu,
|
||||
"pdu_name": pdu_type_name(pdu),
|
||||
"body": body
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn print_pretty(&self, test_name: &str) {
|
||||
println!(
|
||||
"\n===== RTR Debug Dump: {} =====\n{}\n",
|
||||
test_name,
|
||||
serde_json::to_string_pretty(&self.entries).unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pdu_type_name(pdu: u8) -> &'static str {
|
||||
match pdu {
|
||||
0 => "Serial Notify",
|
||||
1 => "Serial Query",
|
||||
2 => "Reset Query",
|
||||
3 => "Cache Response",
|
||||
4 => "IPv4 Prefix",
|
||||
6 => "IPv6 Prefix",
|
||||
7 => "End of Data",
|
||||
8 => "Cache Reset",
|
||||
9 => "Router Key",
|
||||
10 => "Error Report",
|
||||
11 => "ASPA",
|
||||
255 => "Reserved",
|
||||
_ => "Unknown",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dump_cache_response(resp: &CacheResponse) -> Value {
|
||||
json!({
|
||||
"header": {
|
||||
"version": resp.version(),
|
||||
"pdu": resp.pdu(),
|
||||
"session_id": resp.session_id(),
|
||||
"length": 8
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn dump_ipv4_prefix(p: &IPv4Prefix) -> Value {
|
||||
json!({
|
||||
"header": {
|
||||
"version": p.version(),
|
||||
"pdu": p.pdu(),
|
||||
"session_id": 0,
|
||||
"length": 20
|
||||
},
|
||||
"flags": {
|
||||
"raw": if p.flag().is_announce() { 1 } else { 0 },
|
||||
"announce": p.flag().is_announce()
|
||||
},
|
||||
"prefix": p.prefix().to_string(),
|
||||
"prefix_len": p.prefix_len(),
|
||||
"max_len": p.max_len(),
|
||||
"asn": p.asn().into_u32()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn dump_ipv6_prefix(p: &IPv6Prefix) -> Value {
|
||||
json!({
|
||||
"header": {
|
||||
"version": p.version(),
|
||||
"pdu": p.pdu(),
|
||||
"session_id": 0,
|
||||
"length": 32
|
||||
},
|
||||
"flags": {
|
||||
"raw": if p.flag().is_announce() { 1 } else { 0 },
|
||||
"announce": p.flag().is_announce()
|
||||
},
|
||||
"prefix": p.prefix().to_string(),
|
||||
"prefix_len": p.prefix_len(),
|
||||
"max_len": p.max_len(),
|
||||
"asn": p.asn().into_u32()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn dump_eod_v1(eod: &EndOfDataV1) -> Value {
|
||||
let timing = eod.timing();
|
||||
json!({
|
||||
"header": {
|
||||
"version": eod.version(),
|
||||
"pdu": eod.pdu(),
|
||||
"session_id": eod.session_id(),
|
||||
"length": 24
|
||||
},
|
||||
"serial_number": eod.serial_number(),
|
||||
"refresh_interval": timing.refresh,
|
||||
"retry_interval": timing.retry,
|
||||
"expire_interval": timing.expire
|
||||
})
|
||||
}
|
||||
|
||||
pub fn dump_cache_reset(version: u8, pdu: u8) -> Value {
|
||||
json!({
|
||||
"header": {
|
||||
"version": version,
|
||||
"pdu": pdu,
|
||||
"session_id": 0,
|
||||
"length": 8
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn v4_prefix(a: u8, b: u8, c: u8, d: u8, prefix_len: u8) -> IPAddressPrefix {
|
||||
IPAddressPrefix {
|
||||
address: IPAddress::from_ipv4(Ipv4Addr::new(a, b, c, d)),
|
||||
prefix_length: prefix_len,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn v6_prefix(addr: Ipv6Addr, prefix_len: u8) -> IPAddressPrefix {
|
||||
IPAddressPrefix {
|
||||
address: IPAddress::from_ipv6(addr),
|
||||
prefix_length: prefix_len,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn v4_origin(
|
||||
a: u8,
|
||||
b: u8,
|
||||
c: u8,
|
||||
d: u8,
|
||||
prefix_len: u8,
|
||||
max_len: u8,
|
||||
asn: u32,
|
||||
) -> RouteOrigin {
|
||||
let prefix = v4_prefix(a, b, c, d, prefix_len);
|
||||
RouteOrigin::new(prefix, max_len, asn.into())
|
||||
}
|
||||
|
||||
pub fn v6_origin(
|
||||
addr: Ipv6Addr,
|
||||
prefix_len: u8,
|
||||
max_len: u8,
|
||||
asn: u32,
|
||||
) -> RouteOrigin {
|
||||
let prefix = v6_prefix(addr, prefix_len);
|
||||
RouteOrigin::new(prefix, max_len, asn.into())
|
||||
}
|
||||
|
||||
pub fn as_route_origin(payload: &Payload) -> &RouteOrigin {
|
||||
match payload {
|
||||
Payload::RouteOrigin(ro) => ro,
|
||||
_ => panic!("expected RouteOrigin payload"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_v4_route_origin(payload: &Payload) -> &RouteOrigin {
|
||||
let ro = as_route_origin(payload);
|
||||
assert!(ro.prefix().address.is_ipv4(), "expected IPv4 RouteOrigin");
|
||||
ro
|
||||
}
|
||||
|
||||
pub fn as_v6_route_origin(payload: &Payload) -> &RouteOrigin {
|
||||
let ro = as_route_origin(payload);
|
||||
assert!(ro.prefix().address.is_ipv6(), "expected IPv6 RouteOrigin");
|
||||
ro
|
||||
}
|
||||
|
||||
pub fn route_origin_to_string(ro: &RouteOrigin) -> String {
|
||||
let prefix = ro.prefix();
|
||||
let addr = match prefix.address {
|
||||
IPAddress::V4(v4) => v4.to_string(),
|
||||
IPAddress::V6(v6) => v6.to_string(),
|
||||
};
|
||||
|
||||
format!(
|
||||
"{}/{}-{} AS{}",
|
||||
addr,
|
||||
prefix.prefix_length,
|
||||
ro.max_length(),
|
||||
ro.asn().into_u32()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn payload_to_string(payload: &Payload) -> String {
|
||||
match payload {
|
||||
Payload::RouteOrigin(ro) => format!("RouteOrigin({})", route_origin_to_string(ro)),
|
||||
Payload::RouterKey(_) => "RouterKey(...)".to_string(),
|
||||
Payload::Aspa(_) => "Aspa(...)".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn payloads_to_pretty_lines(payloads: &[Payload]) -> String {
|
||||
let mut out = String::new();
|
||||
for (idx, payload) in payloads.iter().enumerate() {
|
||||
let _ = writeln!(&mut out, " [{}] {}", idx, payload_to_string(payload));
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
pub fn print_payloads(label: &str, payloads: &[Payload]) {
|
||||
println!(
|
||||
"\n===== {} =====\n{}",
|
||||
label,
|
||||
payloads_to_pretty_lines(payloads)
|
||||
);
|
||||
}
|
||||
|
||||
pub fn serial_result_to_string(result: &SerialResult) -> String {
|
||||
match result {
|
||||
SerialResult::UpToDate => "UpToDate".to_string(),
|
||||
SerialResult::ResetRequired => "ResetRequired".to_string(),
|
||||
SerialResult::Deltas(deltas) => {
|
||||
let serials: Vec<u32> = deltas.iter().map(|d| d.serial()).collect();
|
||||
format!("Deltas {:?}", serials)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_serial_result(label: &str, result: &SerialResult) {
|
||||
println!("\n===== {} =====\n{}\n", label, serial_result_to_string(result));
|
||||
}
|
||||
|
||||
pub fn bytes_to_hex(bytes: &[u8]) -> String {
|
||||
let mut out = String::with_capacity(bytes.len() * 2);
|
||||
for b in bytes {
|
||||
let _ = write!(&mut out, "{:02x}", b);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
pub fn print_snapshot_hashes(label: &str, snapshot: &rpki::rtr::cache::Snapshot) {
|
||||
println!(
|
||||
"\n===== {} =====\norigins_hash={}\nrouter_keys_hash={}\naspas_hash={}\nsnapshot_hash={}\n",
|
||||
label,
|
||||
bytes_to_hex(&snapshot.origins_hash()),
|
||||
bytes_to_hex(&snapshot.router_keys_hash()),
|
||||
bytes_to_hex(&snapshot.aspas_hash()),
|
||||
bytes_to_hex(&snapshot.snapshot_hash()),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn test_report(
|
||||
name: &str,
|
||||
purpose: &str,
|
||||
input: &str,
|
||||
output: &str,
|
||||
) {
|
||||
println!(
|
||||
"\n==================== TEST REPORT ====================\n测试名称: {}\n测试目的: {}\n\n【输入】\n{}\n【输出】\n{}\n====================================================\n",
|
||||
name, purpose, input, output
|
||||
);
|
||||
}
|
||||
|
||||
pub fn payloads_to_string(payloads: &[Payload]) -> String {
|
||||
let mut out = String::new();
|
||||
for (idx, payload) in payloads.iter().enumerate() {
|
||||
let _ = writeln!(&mut out, " [{}] {}", idx, payload_to_string(payload));
|
||||
}
|
||||
if out.is_empty() {
|
||||
out.push_str(" <empty>\n");
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
pub fn snapshot_hashes_to_string(snapshot: &rpki::rtr::cache::Snapshot) -> String {
|
||||
format!(
|
||||
" origins_hash: {}\n router_keys_hash: {}\n aspas_hash: {}\n snapshot_hash: {}\n",
|
||||
bytes_to_hex(&snapshot.origins_hash()),
|
||||
bytes_to_hex(&snapshot.router_keys_hash()),
|
||||
bytes_to_hex(&snapshot.aspas_hash()),
|
||||
bytes_to_hex(&snapshot.snapshot_hash()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn serial_result_detail_to_string(result: &rpki::rtr::cache::SerialResult) -> String {
|
||||
match result {
|
||||
rpki::rtr::cache::SerialResult::UpToDate => {
|
||||
" result: UpToDate\n".to_string()
|
||||
}
|
||||
rpki::rtr::cache::SerialResult::ResetRequired => {
|
||||
" result: ResetRequired\n".to_string()
|
||||
}
|
||||
rpki::rtr::cache::SerialResult::Deltas(deltas) => {
|
||||
let mut out = String::new();
|
||||
let _ = writeln!(&mut out, " result: Deltas");
|
||||
for (idx, delta) in deltas.iter().enumerate() {
|
||||
let _ = writeln!(&mut out, " delta[{}].serial: {}", idx, delta.serial());
|
||||
let _ = writeln!(&mut out, " delta[{}].announced:", idx);
|
||||
out.push_str(&indent_block(&payloads_to_string(delta.announced()), 4));
|
||||
let _ = writeln!(&mut out, " delta[{}].withdrawn:", idx);
|
||||
out.push_str(&indent_block(&payloads_to_string(delta.withdrawn()), 4));
|
||||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn indent_block(text: &str, spaces: usize) -> String {
|
||||
let pad = " ".repeat(spaces);
|
||||
let mut out = String::new();
|
||||
for line in text.lines() {
|
||||
let _ = writeln!(&mut out, "{}{}", pad, line);
|
||||
}
|
||||
out
|
||||
}
|
||||
Reference in New Issue
Block a user