From 54d7d8f8a36086715518ed9f447db7669a650b42 Mon Sep 17 00:00:00 2001 From: michel Date: Sun, 19 Jul 2026 18:48:33 +0200 Subject: [PATCH] test(shares): two real clients search and download a shared file e2e End-to-end proof of the whole sharing stack with no mock peer: a sharer indexes a temp file, the leecher's search is distributed by soulfind, the sharer replies with a FileSearchResponse, and the leecher downloads the real bytes that the sharer serves over a peer-to-peer transfer. Asserts the search result and that the downloaded bytes match the source. Server-gated (SOULSEEK_E2E_REQUIRED). --- soulseek-rs-lib/tests/e2e.rs | 102 +++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/soulseek-rs-lib/tests/e2e.rs b/soulseek-rs-lib/tests/e2e.rs index f1548a2..1adf385 100644 --- a/soulseek-rs-lib/tests/e2e.rs +++ b/soulseek-rs-lib/tests/e2e.rs @@ -1043,3 +1043,105 @@ fn a_file_downloads_from_a_firewalled_peer_via_server_broker() { let _ = std::fs::remove_dir_all(&download_dir); } + +// --------------------------------------------------------------------------- +// Two real clients: one shares a file, the other searches for it and downloads +// it — the entire search + connect + upload/download stack, no mock peer. +// --------------------------------------------------------------------------- + +#[test] +fn two_real_clients_search_and_download() { + let server = server_or_skip!(); + + // Sharer with one distinctively named file. + let share_dir = unique_download_dir(); + let content: Vec = (0..4096u32).map(|i| (i % 251) as u8).collect(); + let filename = "e2e_probe_xyzzy.bin"; + std::fs::write(share_dir.join(filename), &content).unwrap(); + + let sharer_port = free_port().expect("sharer port"); + let mut sharer = Client::with_settings(ClientSettings { + shared_directory: Some(share_dir.display().to_string()), + ..server.listening_settings("e2e_sharer", "pw", sharer_port) + }); + sharer.connect().expect("sharer connect"); + assert!(sharer.login().expect("sharer login")); + + let leecher_port = free_port().expect("leecher port"); + let mut leecher = Client::with_settings(server.listening_settings( + "e2e_leecher", + "pw", + leecher_port, + )); + leecher.connect().expect("leecher connect"); + assert!(leecher.login().expect("leecher login")); + + // Let soulfind register both SetWaitPorts before the search resolves peers. + std::thread::sleep(Duration::from_secs(1)); + + let query = "xyzzy"; + let _ = leecher.search(query, Duration::from_secs(3)); + + // Poll until the sharer's response for our file arrives. + let mut hit: Option<(String, u64)> = None; + let deadline = Instant::now() + Duration::from_secs(20); + while Instant::now() < deadline && hit.is_none() { + for result in leecher.get_search_results(query) { + if result.username == "e2e_sharer" { + for file in &result.files { + if file.name.contains("e2e_probe_xyzzy") { + hit = Some((file.name.clone(), file.size)); + } + } + } + } + if hit.is_none() { + std::thread::sleep(Duration::from_millis(200)); + } + } + let (result_path, size) = + hit.expect("leecher should find the sharer's file"); + assert_eq!(size, content.len() as u64); + + // Download it from the sharer. + let download_dir = unique_download_dir(); + let (_download, status_rx) = leecher + .download( + result_path.clone(), + "e2e_sharer".to_string(), + size, + download_dir.display().to_string(), + ) + .expect("start download"); + + let mut completed = false; + let deadline = Instant::now() + Duration::from_secs(25); + while Instant::now() < deadline { + match status_rx.recv_timeout(Duration::from_millis(500)) { + Ok(DownloadStatus::Completed) => { + completed = true; + break; + } + Ok(DownloadStatus::Failed | DownloadStatus::TimedOut) => break, + _ => {} + } + if leecher + .get_all_downloads() + .iter() + .any(|d| matches!(d.status, DownloadStatus::Completed)) + { + completed = true; + break; + } + } + assert!(completed, "the download should complete"); + + // The virtual path is backslash-separated; the saved file uses the basename. + let basename = result_path.rsplit(['\\', '/']).next().unwrap(); + let written = std::fs::read(download_dir.join(basename)) + .expect("downloaded file should exist"); + assert_eq!(written, content, "downloaded bytes should match the source"); + + let _ = std::fs::remove_dir_all(share_dir); + let _ = std::fs::remove_dir_all(download_dir); +}