chore: initial sanitized public snapshot
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
#![expect(
|
||||
missing_docs,
|
||||
reason = "integration test scenarios are documented by case names rather than item-level rustdoc"
|
||||
)]
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use aria2_rust_pro_cli as _;
|
||||
use aria2_rust_pro_compat as _;
|
||||
use aria2_rust_pro_core as _;
|
||||
use aria2_rust_pro_protocol::{
|
||||
DhtMessageModel, DhtNodeModel,
|
||||
torrent::{PeerWireExtensionHandshakeModel, PeerWireMessageKind, PeerWireMetadataMessageModel},
|
||||
};
|
||||
use aria2_rust_pro_rpc::{InProcessRpcDispatcher, RpcMethod, RpcValue};
|
||||
use aria2_rust_pro_storage as _;
|
||||
use aria2_rust_pro_tests as _;
|
||||
use criterion as _;
|
||||
|
||||
#[path = "../test_support/support.rs"]
|
||||
mod support;
|
||||
|
||||
fn tell_status(dispatcher: &mut InProcessRpcDispatcher, gid: &str) -> BTreeMap<String, RpcValue> {
|
||||
support::rpc_result_object(dispatcher.dispatch_json(support::rpc_request(
|
||||
RpcMethod::Aria2TellStatus,
|
||||
vec![RpcValue::String(gid.to_owned())],
|
||||
)))
|
||||
}
|
||||
|
||||
fn get_files(dispatcher: &mut InProcessRpcDispatcher, gid: &str) -> Vec<RpcValue> {
|
||||
support::rpc_result_array(dispatcher.dispatch_json(support::rpc_request(
|
||||
RpcMethod::Aria2GetFiles,
|
||||
vec![RpcValue::String(gid.to_owned())],
|
||||
)))
|
||||
}
|
||||
|
||||
fn first_file<'a>(files: &'a [RpcValue], context: &str) -> &'a BTreeMap<String, RpcValue> {
|
||||
match files.first() {
|
||||
Some(RpcValue::Object(file)) => file,
|
||||
other => panic!("unexpected first file payload for {context}: {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn seed_peer_and_promote_metadata(
|
||||
dispatcher: &mut InProcessRpcDispatcher,
|
||||
gid: &str,
|
||||
info_hash_hex: &str,
|
||||
) {
|
||||
dispatcher
|
||||
.apply_dht_get_peers_result(
|
||||
gid,
|
||||
&DhtNodeModel {
|
||||
node_id: String::new(),
|
||||
address: "203.0.113.77".to_owned(),
|
||||
port: 51413,
|
||||
},
|
||||
&DhtMessageModel::get_peers_response(
|
||||
b"gp".to_vec(),
|
||||
vec![0x55; 20],
|
||||
Some(b"dht-token".to_vec()),
|
||||
None,
|
||||
vec![support::compact_peer([198, 51, 100, 42], 51415)],
|
||||
),
|
||||
)
|
||||
.expect("dht get_peers should seed a connectable peer");
|
||||
|
||||
let connector = support::FakePeerWireConnector::new(support::peer_wire_handshake_and_frames(
|
||||
support::decode_hex_20(info_hash_hex),
|
||||
*b"-AZ2060-META-PROMO01",
|
||||
&[
|
||||
PeerWireMessageKind::Unchoke,
|
||||
PeerWireMessageKind::Extension(
|
||||
PeerWireExtensionHandshakeModel {
|
||||
extensions: BTreeMap::from([("ut_metadata".to_owned(), 3_u8)]),
|
||||
client_name: Some("libtorrent/2.0.11".to_owned()),
|
||||
metadata_size: Some(
|
||||
u32::try_from(support::BT_TORRENT_FIXTURE_BYTES.len())
|
||||
.expect("fixture metadata length should fit u32"),
|
||||
),
|
||||
request_queue: Some(64),
|
||||
}
|
||||
.to_peer_wire_message(),
|
||||
),
|
||||
PeerWireMessageKind::Extension(
|
||||
PeerWireMetadataMessageModel::data(
|
||||
0,
|
||||
u32::try_from(support::BT_TORRENT_FIXTURE_BYTES.len())
|
||||
.expect("fixture metadata length should fit u32"),
|
||||
support::BT_TORRENT_FIXTURE_BYTES.to_vec(),
|
||||
)
|
||||
.to_peer_wire_message(3),
|
||||
),
|
||||
],
|
||||
));
|
||||
dispatcher
|
||||
.execute_peer_wire_exchange(gid, &connector)
|
||||
.expect("peer-wire metadata exchange should promote the magnet session");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn magnet_piece_observation_clears_metadata_only_and_pending_snapshot_flags() {
|
||||
let mut dispatcher = InProcessRpcDispatcher::new();
|
||||
let reference_gid = support::add_torrent(&mut dispatcher);
|
||||
let reference_status = tell_status(&mut dispatcher, &reference_gid);
|
||||
let magnet_uri = support::rpc_string_field(&reference_status, "magnetUri");
|
||||
let info_hash = support::rpc_string_field(&reference_status, "infoHash");
|
||||
|
||||
let gid = support::add_magnet(&mut dispatcher, &magnet_uri);
|
||||
let before = tell_status(&mut dispatcher, &gid);
|
||||
assert!(support::rpc_bool_field(&before, "metadataOnly"));
|
||||
assert_eq!(support::rpc_string_field(&before, "magnetUri"), magnet_uri);
|
||||
|
||||
let before_snapshot = dispatcher
|
||||
.bt_runtime_coordinator_snapshot(&gid)
|
||||
.expect("snapshot should inspect metadata-only magnet state");
|
||||
assert!(before_snapshot.metadata_only);
|
||||
assert!(before_snapshot.metadata_exchange_pending);
|
||||
|
||||
seed_peer_and_promote_metadata(&mut dispatcher, &gid, &info_hash);
|
||||
|
||||
let after = tell_status(&mut dispatcher, &gid);
|
||||
assert!(!support::rpc_bool_field(&after, "metadataOnly"));
|
||||
assert_eq!(support::rpc_string_field(&after, "magnetUri"), magnet_uri);
|
||||
|
||||
let after_snapshot = dispatcher
|
||||
.bt_runtime_coordinator_snapshot(&gid)
|
||||
.expect("snapshot should inspect promoted magnet state");
|
||||
assert!(!after_snapshot.metadata_only);
|
||||
assert!(!after_snapshot.metadata_exchange_pending);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn promoted_magnet_session_should_match_reference_torrent_file_surface() {
|
||||
let mut dispatcher = InProcessRpcDispatcher::new();
|
||||
let reference_gid = support::add_torrent(&mut dispatcher);
|
||||
let reference_status = tell_status(&mut dispatcher, &reference_gid);
|
||||
let reference_files = get_files(&mut dispatcher, &reference_gid);
|
||||
let reference_file = first_file(&reference_files, "reference torrent");
|
||||
let magnet_uri = support::rpc_string_field(&reference_status, "magnetUri");
|
||||
let info_hash = support::rpc_string_field(&reference_status, "infoHash");
|
||||
|
||||
let gid = support::add_magnet(&mut dispatcher, &magnet_uri);
|
||||
seed_peer_and_promote_metadata(&mut dispatcher, &gid, &info_hash);
|
||||
|
||||
let promoted_status = tell_status(&mut dispatcher, &gid);
|
||||
assert!(
|
||||
!support::rpc_bool_field(&promoted_status, "metadataOnly"),
|
||||
"metadata promotion should leave metadata-only mode before comparing the public torrent surface"
|
||||
);
|
||||
assert_eq!(
|
||||
support::rpc_u64_field(&promoted_status, "totalLength"),
|
||||
support::rpc_u64_field(&reference_status, "totalLength"),
|
||||
"promoted magnet sessions should hydrate the same totalLength visible on the equivalent .torrent bootstrap"
|
||||
);
|
||||
|
||||
let promoted_files = get_files(&mut dispatcher, &gid);
|
||||
let promoted_file = first_file(&promoted_files, "promoted magnet");
|
||||
assert_eq!(
|
||||
promoted_file.get("path"),
|
||||
reference_file.get("path"),
|
||||
"promoted magnet sessions should expose the real torrent file path instead of a synthetic placeholder row"
|
||||
);
|
||||
assert_eq!(
|
||||
promoted_file.get("length"),
|
||||
reference_file.get("length"),
|
||||
"promoted magnet sessions should expose the same per-file length as the equivalent .torrent bootstrap"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user