chore: initial sanitized public snapshot
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn magnet_with_tracker_tiers_and_dht_hint_preserves_bt_status_shape() {
|
||||
let magnet = "magnet:?xt=urn:btih:00112233445566778899aabbccddeeff00112233&dn=bt-dht-tiered.iso&tr=http%3A%2F%2Ftracker-a.example.org%2Fannounce&tr=udp%3A%2F%2Ftracker-b.example.org%3A6969&x.pe=198.51.100.9%3A51413";
|
||||
let mut dispatcher = InProcessRpcDispatcher::new();
|
||||
let add = dispatcher.dispatch_json(JsonRpcRequest {
|
||||
jsonrpc: Some("2.0".to_owned()),
|
||||
id: None,
|
||||
method: RpcMethod::Aria2AddUri.as_str().to_owned(),
|
||||
params: vec![RpcValue::String(magnet.to_owned())],
|
||||
meta: Default::default(),
|
||||
});
|
||||
let gid = match add.result {
|
||||
Some(RpcValue::String(gid)) => gid,
|
||||
other => panic!("unexpected addUri magnet result: {other:?}"),
|
||||
};
|
||||
|
||||
let status = dispatcher.dispatch_json(JsonRpcRequest {
|
||||
jsonrpc: Some("2.0".to_owned()),
|
||||
id: None,
|
||||
method: RpcMethod::Aria2TellStatus.as_str().to_owned(),
|
||||
params: vec![RpcValue::String(gid.clone())],
|
||||
meta: Default::default(),
|
||||
});
|
||||
match status.result {
|
||||
Some(RpcValue::Object(payload)) => {
|
||||
assert_eq!(payload.get("isBt"), Some(&RpcValue::Bool(true)));
|
||||
assert!(matches!(
|
||||
payload.get("announceList"),
|
||||
Some(RpcValue::Array(tiers)) if !tiers.is_empty()
|
||||
));
|
||||
assert!(matches!(
|
||||
payload.get("magnetUri"),
|
||||
Some(RpcValue::String(uri)) if uri.starts_with("magnet:?xt=urn:btih:")
|
||||
));
|
||||
assert!(
|
||||
payload.contains_key("numSeeders"),
|
||||
"compat bt status should expose numSeeders key"
|
||||
);
|
||||
}
|
||||
other => panic!("unexpected tellStatus payload for tiered magnet: {other:?}"),
|
||||
}
|
||||
|
||||
let peers = dispatcher.dispatch_json(JsonRpcRequest {
|
||||
jsonrpc: Some("2.0".to_owned()),
|
||||
id: None,
|
||||
method: RpcMethod::Aria2GetPeers.as_str().to_owned(),
|
||||
params: vec![RpcValue::String(gid)],
|
||||
meta: Default::default(),
|
||||
});
|
||||
assert!(
|
||||
matches!(peers.result, Some(RpcValue::Array(_))),
|
||||
"getPeers should remain type-stable for dht/tiered magnet surface"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tracker_announce_reingest_replaces_peer_view_with_latest_snapshot() {
|
||||
fn bencode_int(value: i64) -> Vec<u8> {
|
||||
format!("i{value}e").into_bytes()
|
||||
}
|
||||
fn bencode_bytes(value: &[u8]) -> Vec<u8> {
|
||||
let mut out = format!("{}:", value.len()).into_bytes();
|
||||
out.extend_from_slice(value);
|
||||
out
|
||||
}
|
||||
fn bencode_list(values: Vec<Vec<u8>>) -> Vec<u8> {
|
||||
let mut out = vec![b'l'];
|
||||
for value in values {
|
||||
out.extend_from_slice(&value);
|
||||
}
|
||||
out.push(b'e');
|
||||
out
|
||||
}
|
||||
fn bencode_dict(entries: Vec<(&str, Vec<u8>)>) -> Vec<u8> {
|
||||
let mut out = vec![b'd'];
|
||||
for (key, value) in entries {
|
||||
out.extend_from_slice(format!("{}:{key}", key.len()).as_bytes());
|
||||
out.extend_from_slice(&value);
|
||||
}
|
||||
out.push(b'e');
|
||||
out
|
||||
}
|
||||
|
||||
let magnet = "magnet:?xt=urn:btih:8899aabbccddeeff00112233445566778899aabb&dn=bt-reannounce.iso&tr=http%3A%2F%2Ftracker.example.org%2Fannounce";
|
||||
let mut dispatcher = InProcessRpcDispatcher::new();
|
||||
let add = dispatcher.dispatch_json(JsonRpcRequest {
|
||||
jsonrpc: Some("2.0".to_owned()),
|
||||
id: None,
|
||||
method: RpcMethod::Aria2AddUri.as_str().to_owned(),
|
||||
params: vec![RpcValue::String(magnet.to_owned())],
|
||||
meta: Default::default(),
|
||||
});
|
||||
let gid = match add.result {
|
||||
Some(RpcValue::String(gid)) => gid,
|
||||
other => panic!("unexpected addUri result: {other:?}"),
|
||||
};
|
||||
|
||||
let announce_a = TrackerResponseModel::from_announce_bytes(&bencode_dict(vec![
|
||||
("interval", bencode_int(1200)),
|
||||
(
|
||||
"peers",
|
||||
bencode_list(vec![bencode_dict(vec![
|
||||
("ip", bencode_bytes(b"198.51.100.41")),
|
||||
("port", bencode_int(6001)),
|
||||
])]),
|
||||
),
|
||||
]))
|
||||
.expect("announce-a should parse");
|
||||
dispatcher
|
||||
.apply_tracker_announce_result(&gid, &announce_a)
|
||||
.expect("announce-a should ingest");
|
||||
|
||||
let announce_b = TrackerResponseModel::from_announce_bytes(&bencode_dict(vec![
|
||||
("interval", bencode_int(900)),
|
||||
(
|
||||
"peers",
|
||||
bencode_list(vec![
|
||||
bencode_dict(vec![
|
||||
("ip", bencode_bytes(b"198.51.100.42")),
|
||||
("port", bencode_int(6002)),
|
||||
]),
|
||||
bencode_dict(vec![
|
||||
("ip", bencode_bytes(b"198.51.100.43")),
|
||||
("port", bencode_int(6003)),
|
||||
]),
|
||||
]),
|
||||
),
|
||||
]))
|
||||
.expect("announce-b should parse");
|
||||
dispatcher
|
||||
.apply_tracker_announce_result(&gid, &announce_b)
|
||||
.expect("announce-b should ingest");
|
||||
|
||||
let peers = dispatcher.dispatch_json(JsonRpcRequest {
|
||||
jsonrpc: Some("2.0".to_owned()),
|
||||
id: None,
|
||||
method: RpcMethod::Aria2GetPeers.as_str().to_owned(),
|
||||
params: vec![RpcValue::String(gid)],
|
||||
meta: Default::default(),
|
||||
});
|
||||
match peers.result {
|
||||
Some(RpcValue::Array(items)) => {
|
||||
assert_eq!(
|
||||
items.len(),
|
||||
2,
|
||||
"second announce snapshot should be reflected"
|
||||
);
|
||||
let ports = items
|
||||
.into_iter()
|
||||
.filter_map(|item| match item {
|
||||
RpcValue::Object(peer) => peer.get("port").cloned(),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
assert!(ports.contains(&RpcValue::String("6002".to_owned())));
|
||||
assert!(ports.contains(&RpcValue::String("6003".to_owned())));
|
||||
}
|
||||
other => panic!("unexpected getPeers payload after reannounce: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bt_mixed_rpc_surface_smoke_preserves_peer_and_server_type_contracts() {
|
||||
let mut dispatcher = InProcessRpcDispatcher::new();
|
||||
let torrent_payload = "ZDg6YW5ub3VuY2UzNTpodHRwOi8vdHJhY2tlci5leGFtcGxlLm9yZy9hbm5vdW5jZTQ6aW5mb2Q0Om5hbWUxMDp1YnVudHUuaXNvMTI6cGllY2UgbGVuZ3RoaTE2Mzg0ZTY6bGVuZ3RoaTMyNzY4ZTY6cGllY2VzNDA6YWFhYWFhYWFhYWFhYWFhYWFhYWFiYmJiYmJiYmJiYmJiYmJiYmJiYmVl";
|
||||
let add_torrent = dispatcher.dispatch_json(JsonRpcRequest {
|
||||
jsonrpc: Some("2.0".to_owned()),
|
||||
id: None,
|
||||
method: RpcMethod::Aria2AddTorrent.as_str().to_owned(),
|
||||
params: vec![RpcValue::String(torrent_payload.to_owned())],
|
||||
meta: Default::default(),
|
||||
});
|
||||
let torrent_gid = match add_torrent.result {
|
||||
Some(RpcValue::String(gid)) => gid,
|
||||
other => panic!("unexpected addTorrent result: {other:?}"),
|
||||
};
|
||||
|
||||
let mut magnet_gids = Vec::new();
|
||||
for i in 0..20 {
|
||||
let magnet = format!(
|
||||
"magnet:?xt=urn:btih:{:040x}&dn=bt-mixed-{i}&tr=http%3A%2F%2Ftracker.example.org%2Fannounce",
|
||||
i + 4000
|
||||
);
|
||||
let add = dispatcher.dispatch_json(JsonRpcRequest {
|
||||
jsonrpc: Some("2.0".to_owned()),
|
||||
id: None,
|
||||
method: RpcMethod::Aria2AddUri.as_str().to_owned(),
|
||||
params: vec![RpcValue::String(magnet)],
|
||||
meta: Default::default(),
|
||||
});
|
||||
match add.result {
|
||||
Some(RpcValue::String(gid)) => magnet_gids.push(gid),
|
||||
other => panic!("unexpected addUri result in mixed smoke: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
let mut bt_status_objects = 0usize;
|
||||
for gid in magnet_gids.iter().chain(std::iter::once(&torrent_gid)) {
|
||||
let status = dispatcher.dispatch_json(JsonRpcRequest {
|
||||
jsonrpc: Some("2.0".to_owned()),
|
||||
id: None,
|
||||
method: RpcMethod::Aria2TellStatus.as_str().to_owned(),
|
||||
params: vec![RpcValue::String(gid.clone())],
|
||||
meta: Default::default(),
|
||||
});
|
||||
match status.result {
|
||||
Some(RpcValue::Object(payload)) => {
|
||||
assert_eq!(payload.get("isBt"), Some(&RpcValue::Bool(true)));
|
||||
assert!(payload.contains_key("status"));
|
||||
assert!(payload.contains_key("completedLength"));
|
||||
bt_status_objects += 1;
|
||||
}
|
||||
other => panic!("unexpected tellStatus payload in mixed smoke: {other:?}"),
|
||||
}
|
||||
|
||||
let servers = dispatcher.dispatch_json(JsonRpcRequest {
|
||||
jsonrpc: Some("2.0".to_owned()),
|
||||
id: None,
|
||||
method: RpcMethod::Aria2GetServers.as_str().to_owned(),
|
||||
params: vec![RpcValue::String(gid.clone())],
|
||||
meta: Default::default(),
|
||||
});
|
||||
let error = servers
|
||||
.error
|
||||
.expect("getServers should reject non-active BT downloads");
|
||||
assert!(
|
||||
error
|
||||
.message
|
||||
.contains(&format!("No active download for GID#{gid}"))
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(bt_status_objects, magnet_gids.len() + 1);
|
||||
}
|
||||
Reference in New Issue
Block a user