#![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, ) { 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); }