Files

171 lines
6.1 KiB
Rust

#![expect(
missing_docs,
reason = "integration test scenarios are documented by case names rather than item-level rustdoc"
)]
use std::{
fs,
path::{Path, PathBuf},
time::{SystemTime, UNIX_EPOCH},
};
use aria2_rust_pro_cli::{
BtStatusReport, Invocation, TransferSelection, execute_runtime, execute_runtime_with_downloader,
};
use aria2_rust_pro_compat as _;
use aria2_rust_pro_core as _;
use aria2_rust_pro_protocol::FixtureHttpDownloader;
use aria2_rust_pro_storage as _;
use aria2_rust_pro_tests as _;
use criterion as _;
#[path = "../test_support/support.rs"]
mod support;
fn unique_temp_path(stem: &str) -> PathBuf {
let unique = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("system time should be after unix epoch")
.as_nanos();
std::env::temp_dir().join(format!("aria2-rust-pro-tests-{stem}-{unique}"))
}
fn write_config(path: &Path, download_dir: &Path) {
fs::write(path, format!("dir={}", download_dir.display())).expect("config should write");
}
fn assert_bt_snapshot(
bt: &BtStatusReport,
expected_metadata_only: bool,
expected_total_length: Option<u64>,
) {
assert_eq!(bt.is_bt, Some(true));
assert_eq!(bt.metadata_only, Some(expected_metadata_only));
assert_eq!(bt.share_time, Some(0));
assert_eq!(bt.share_ratio.as_deref(), Some("0.000"));
assert_eq!(bt.share_ratio_progress.as_deref(), Some("0.000"));
assert_eq!(bt.share_ratio_remaining.as_deref(), Some("0.000"));
assert!(
bt.announce_list_tier_count.unwrap_or_default() >= 1,
"bt snapshot should retain at least one announce tier"
);
if !expected_metadata_only {
assert!(
bt.magnet_uri
.as_deref()
.is_some_and(|uri| uri.starts_with("magnet:?xt=urn:btih:"))
);
assert_eq!(expected_total_length, Some(32_768));
}
}
#[test]
fn foreground_magnet_runtime_report_keeps_bt_snapshot_visible() {
let report = execute_runtime(Invocation::Run {
config_path: None,
uris: vec![String::from(
"magnet:?xt=urn:btih:00112233445566778899aabbccddeeff00112233&dn=dht-metadata.iso&tr=http%3A%2F%2Ftracker.example.org%2Fannounce&tr=udp%3A%2F%2Ftracker.example.org%3A6969",
)],
})
.expect("runtime should execute for a bt magnet");
assert_eq!(report.accepted_uri_count, 1);
assert_eq!(report.tracked_download_count, 1);
assert_eq!(report.completed_download_count, 0);
assert_eq!(report.transfer_kinds, vec![TransferSelection::Magnet]);
assert_eq!(report.recognized_schemes, vec![String::from("magnet")]);
assert_eq!(report.first_total_length, Some(0));
assert_eq!(report.first_completed_length, Some(0));
let bt = report
.first_bt_status
.as_ref()
.expect("magnet foreground execution should surface a bt snapshot");
assert_bt_snapshot(bt, true, report.first_total_length);
assert_eq!(bt.num_seeders, Some(0));
}
#[test]
fn foreground_local_torrent_file_runs_as_bt_session_not_plain_uri() {
let temp_root = unique_temp_path("local-torrent");
let download_dir = temp_root.join("downloads");
let torrent_path = temp_root.join("fixture.torrent");
let config_path = temp_root.join("aria2.conf");
fs::create_dir_all(&download_dir).expect("download directory should create");
support::write_torrent_fixture(&torrent_path);
write_config(&config_path, &download_dir);
let report = execute_runtime_with_downloader(
Invocation::Run {
config_path: Some(config_path),
uris: vec![torrent_path.to_string_lossy().into_owned()],
},
&FixtureHttpDownloader::new(),
)
.expect("runtime should accept a local torrent input");
assert_eq!(report.accepted_uri_count, 1);
assert_eq!(report.tracked_download_count, 1);
assert_eq!(report.completed_download_count, 0);
assert_eq!(report.transfer_kinds, vec![TransferSelection::Torrent]);
assert_eq!(report.first_total_length, Some(32_768));
assert_eq!(report.first_completed_length, Some(0));
let bt = report
.first_bt_status
.as_ref()
.expect("local torrent foreground execution should expose bt status");
assert_bt_snapshot(bt, false, report.first_total_length);
assert!(
!download_dir.join("fixture.torrent").exists(),
"torrent metainfo should bootstrap a bt session instead of being persisted as the final download artifact"
);
let _ = fs::remove_dir_all(&temp_root);
}
#[test]
fn foreground_remote_torrent_url_bootstraps_bt_session_instead_of_saving_metainfo_payload() {
let temp_root = unique_temp_path("remote-torrent");
let download_dir = temp_root.join("downloads");
let config_path = temp_root.join("aria2.conf");
fs::create_dir_all(&download_dir).expect("download directory should create");
write_config(&config_path, &download_dir);
let torrent_url = "https://tracker.example.org/files/ubuntu.torrent";
let mut downloader = FixtureHttpDownloader::new();
downloader.register(torrent_url, support::BT_TORRENT_FIXTURE_BYTES);
let report = execute_runtime_with_downloader(
Invocation::Run {
config_path: Some(config_path),
uris: vec![torrent_url.to_owned()],
},
&downloader,
)
.expect("runtime should accept a remote torrent url");
assert_eq!(report.accepted_uri_count, 1);
assert_eq!(report.tracked_download_count, 1);
assert_eq!(report.completed_download_count, 0);
assert_eq!(report.transfer_kinds, vec![TransferSelection::Torrent]);
assert_eq!(report.recognized_schemes, vec![String::from("https")]);
assert_eq!(report.first_total_length, Some(32_768));
assert_eq!(report.first_completed_length, Some(0));
let bt = report
.first_bt_status
.as_ref()
.expect("remote torrent bootstrap should expose bt status");
assert_bt_snapshot(bt, false, report.first_total_length);
assert!(
!download_dir.join("ubuntu.torrent").exists(),
"remote torrent bootstrap should not leave the .torrent payload behind as the downloaded artifact"
);
let _ = fs::remove_dir_all(&temp_root);
}