|
| 1 | +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; |
| 2 | +use std::str::FromStr; |
| 3 | +use std::sync::Arc; |
| 4 | + |
| 5 | +use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes, PeerId}; |
| 6 | +use bittorrent_primitives::info_hash::InfoHash; |
| 7 | +use bittorrent_tracker_core::announce_handler::{AnnounceHandler, PeersWanted}; |
| 8 | +use bittorrent_tracker_core::databases::setup::initialize_database; |
| 9 | +use bittorrent_tracker_core::scrape_handler::ScrapeHandler; |
| 10 | +use bittorrent_tracker_core::torrent::repository::in_memory::InMemoryTorrentRepository; |
| 11 | +use bittorrent_tracker_core::torrent::repository::persisted::DatabasePersistentTorrentRepository; |
| 12 | +use bittorrent_tracker_core::whitelist; |
| 13 | +use bittorrent_tracker_core::whitelist::repository::in_memory::InMemoryWhitelist; |
| 14 | +use torrust_tracker_configuration::Core; |
| 15 | +use torrust_tracker_primitives::peer::Peer; |
| 16 | +use torrust_tracker_primitives::DurationSinceUnixEpoch; |
| 17 | +use torrust_tracker_test_helpers::configuration::ephemeral_sqlite_database; |
| 18 | + |
| 19 | +/// # Panics |
| 20 | +/// |
| 21 | +/// Will panic if the temporary file path is not a valid UTF-8 string. |
| 22 | +#[must_use] |
| 23 | +pub fn ephemeral_configuration() -> Core { |
| 24 | + let mut config = Core::default(); |
| 25 | + |
| 26 | + let temp_file = ephemeral_sqlite_database(); |
| 27 | + temp_file.to_str().unwrap().clone_into(&mut config.database.path); |
| 28 | + |
| 29 | + config |
| 30 | +} |
| 31 | + |
| 32 | +/// # Panics |
| 33 | +/// |
| 34 | +/// Will panic if the string representation of the info hash is not a valid infohash. |
| 35 | +#[must_use] |
| 36 | +pub fn sample_info_hash() -> InfoHash { |
| 37 | + "3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0" // DevSkim: ignore DS173237 |
| 38 | + .parse::<InfoHash>() |
| 39 | + .expect("String should be a valid info hash") |
| 40 | +} |
| 41 | + |
| 42 | +/// Sample peer whose state is not relevant for the tests. |
| 43 | +#[must_use] |
| 44 | +pub fn sample_peer() -> Peer { |
| 45 | + Peer { |
| 46 | + peer_id: PeerId(*b"-qB00000000000000000"), |
| 47 | + peer_addr: SocketAddr::new(remote_client_ip(), 8080), |
| 48 | + updated: DurationSinceUnixEpoch::new(1_669_397_478_934, 0), |
| 49 | + uploaded: NumberOfBytes::new(0), |
| 50 | + downloaded: NumberOfBytes::new(0), |
| 51 | + left: NumberOfBytes::new(0), // No bytes left to download |
| 52 | + event: AnnounceEvent::Completed, |
| 53 | + } |
| 54 | +} |
| 55 | + |
| 56 | +// The client peer IP. |
| 57 | +#[must_use] |
| 58 | +fn remote_client_ip() -> IpAddr { |
| 59 | + IpAddr::V4(Ipv4Addr::from_str("126.0.0.1").unwrap()) |
| 60 | +} |
| 61 | + |
| 62 | +struct Container { |
| 63 | + pub announce_handler: Arc<AnnounceHandler>, |
| 64 | + pub scrape_handler: Arc<ScrapeHandler>, |
| 65 | +} |
| 66 | + |
| 67 | +impl Container { |
| 68 | + pub fn initialize(config: &Core) -> Self { |
| 69 | + let database = initialize_database(config); |
| 70 | + let in_memory_torrent_repository = Arc::new(InMemoryTorrentRepository::default()); |
| 71 | + let db_torrent_repository = Arc::new(DatabasePersistentTorrentRepository::new(&database)); |
| 72 | + let in_memory_whitelist = Arc::new(InMemoryWhitelist::default()); |
| 73 | + let whitelist_authorization = Arc::new(whitelist::authorization::WhitelistAuthorization::new( |
| 74 | + config, |
| 75 | + &in_memory_whitelist.clone(), |
| 76 | + )); |
| 77 | + let announce_handler = Arc::new(AnnounceHandler::new( |
| 78 | + config, |
| 79 | + &in_memory_torrent_repository, |
| 80 | + &db_torrent_repository, |
| 81 | + )); |
| 82 | + let scrape_handler = Arc::new(ScrapeHandler::new(&whitelist_authorization, &in_memory_torrent_repository)); |
| 83 | + |
| 84 | + Self { |
| 85 | + announce_handler, |
| 86 | + scrape_handler, |
| 87 | + } |
| 88 | + } |
| 89 | +} |
| 90 | + |
| 91 | +#[tokio::test] |
| 92 | +async fn test_announce_and_scrape_requests() { |
| 93 | + let config = ephemeral_configuration(); |
| 94 | + |
| 95 | + let container = Container::initialize(&config); |
| 96 | + |
| 97 | + let info_hash = sample_info_hash(); |
| 98 | + |
| 99 | + let mut peer = sample_peer(); |
| 100 | + |
| 101 | + // Announce |
| 102 | + |
| 103 | + // First announce: download started |
| 104 | + peer.event = AnnounceEvent::Started; |
| 105 | + let announce_data = |
| 106 | + container |
| 107 | + .announce_handler |
| 108 | + .announce(&info_hash, &mut peer, &remote_client_ip(), &PeersWanted::AsManyAsPossible); |
| 109 | + |
| 110 | + // NOTICE: you don't get back the peer making the request. |
| 111 | + assert_eq!(announce_data.peers.len(), 0); |
| 112 | + assert_eq!(announce_data.stats.downloaded, 0); |
| 113 | + |
| 114 | + // Second announce: download completed |
| 115 | + peer.event = AnnounceEvent::Completed; |
| 116 | + let announce_data = |
| 117 | + container |
| 118 | + .announce_handler |
| 119 | + .announce(&info_hash, &mut peer, &remote_client_ip(), &PeersWanted::AsManyAsPossible); |
| 120 | + |
| 121 | + assert_eq!(announce_data.peers.len(), 0); |
| 122 | + assert_eq!(announce_data.stats.downloaded, 1); |
| 123 | + |
| 124 | + // Scrape |
| 125 | + |
| 126 | + let scrape_data = container.scrape_handler.scrape(&vec![info_hash]).await; |
| 127 | + |
| 128 | + assert!(scrape_data.files.contains_key(&info_hash)); |
| 129 | +} |
| 130 | + |
| 131 | +#[test] |
| 132 | +fn test_scrape_request() {} |
0 commit comments