Skip to content

Commit 05b67c7

Browse files
committed
test: [#278] use non canonical info-hash to get torrent details
1 parent 83d31f2 commit 05b67c7

File tree

3 files changed

+90
-16
lines changed

3 files changed

+90
-16
lines changed

tests/common/contexts/torrent/fixtures.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ impl TestTorrent {
137137
}
138138
}
139139

140-
pub fn info_hash_as_hex_string(&self) -> InfoHash {
140+
pub fn file_info_hash(&self) -> InfoHash {
141141
self.file_info.info_hash.clone()
142142
}
143143
}

tests/e2e/web/api/v1/contexts/torrent/contract.rs

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,19 @@ Get torrent info:
1717
mod for_guests {
1818

1919
use torrust_index_backend::web::api;
20+
use uuid::Uuid;
2021

2122
use crate::common::client::Client;
2223
use crate::common::contexts::category::fixtures::software_predefined_category_id;
2324
use crate::common::contexts::torrent::asserts::assert_expected_torrent_details;
25+
use crate::common::contexts::torrent::fixtures::TestTorrent;
2426
use crate::common::contexts::torrent::requests::InfoHash;
2527
use crate::common::contexts::torrent::responses::{
2628
Category, File, TorrentDetails, TorrentDetailsResponse, TorrentListResponse,
2729
};
2830
use crate::common::http::{Query, QueryParam};
2931
use crate::e2e::environment::TestEnv;
30-
use crate::e2e::web::api::v1::contexts::torrent::steps::upload_random_torrent_to_index;
32+
use crate::e2e::web::api::v1::contexts::torrent::steps::{upload_random_torrent_to_index, upload_test_torrent};
3133
use crate::e2e::web::api::v1::contexts::user::steps::new_logged_in_user;
3234

3335
#[tokio::test]
@@ -164,7 +166,7 @@ mod for_guests {
164166
let uploader = new_logged_in_user(&env).await;
165167
let (test_torrent, uploaded_torrent) = upload_random_torrent_to_index(&uploader, &env).await;
166168

167-
let response = client.get_torrent(&test_torrent.info_hash_as_hex_string()).await;
169+
let response = client.get_torrent(&test_torrent.file_info_hash()).await;
168170

169171
let torrent_details_response: TorrentDetailsResponse = serde_json::from_str(&response.body).unwrap();
170172

@@ -213,7 +215,50 @@ mod for_guests {
213215
assert!(response.is_json_and_ok());
214216
}
215217

216-
mod it_should_allow_guests_download_a_torrent_file_searching_by_info_hash {
218+
#[tokio::test]
219+
async fn it_should_allow_guests_to_find_torrent_details_using_a_non_canonical_info_hash() {
220+
let mut env = TestEnv::new();
221+
env.start(api::Version::V1).await;
222+
223+
if !env.provides_a_tracker() {
224+
println!("test skipped. It requires a tracker to be running.");
225+
return;
226+
}
227+
228+
let uploader = new_logged_in_user(&env).await;
229+
let client = Client::authenticated(&env.server_socket_addr().unwrap(), &uploader.token);
230+
231+
// Sample data needed to build two torrents with the same canonical info-hash.
232+
// Those torrents belong to the same Canonical Infohash Group.
233+
let id = Uuid::new_v4();
234+
let title = format!("title-{id}");
235+
let file_contents = "data".to_string();
236+
237+
let mut first_torrent = TestTorrent::with_custom_info_dict_field(id, &file_contents, "custom 01");
238+
first_torrent.index_info.title = title.clone();
239+
240+
let first_torrent_canonical_info_hash = upload_test_torrent(&client, &first_torrent)
241+
.await
242+
.expect("first torrent should be uploaded");
243+
244+
let mut second_torrent = TestTorrent::with_custom_info_dict_field(id, &file_contents, "custom 02");
245+
second_torrent.index_info.title = format!("{title}-clone");
246+
247+
let _result = upload_test_torrent(&client, &second_torrent).await;
248+
249+
// Get torrent details using the non-canonical info-hash (second torrent info-hash)
250+
let response = client.get_torrent(&second_torrent.file_info_hash()).await;
251+
let torrent_details_response: TorrentDetailsResponse = serde_json::from_str(&response.body).unwrap();
252+
253+
// The returned torrent info should be the same as the first torrent
254+
assert_eq!(response.status, 200);
255+
assert_eq!(
256+
torrent_details_response.data.info_hash,
257+
first_torrent_canonical_info_hash.to_hex_string()
258+
);
259+
}
260+
261+
mod it_should_allow_guests_to_download_a_torrent_file_searching_by_info_hash {
217262

218263
use torrust_index_backend::utils::parse_torrent::{calculate_info_hash, decode_torrent};
219264
use torrust_index_backend::web::api;
@@ -241,7 +286,7 @@ mod for_guests {
241286
let (test_torrent, _torrent_listed_in_index) = upload_random_torrent_to_index(&uploader, &env).await;
242287

243288
// Download
244-
let response = client.download_torrent(&test_torrent.info_hash_as_hex_string()).await;
289+
let response = client.download_torrent(&test_torrent.file_info_hash()).await;
245290

246291
assert!(response.is_a_bit_torrent_file());
247292
}
@@ -264,13 +309,13 @@ mod for_guests {
264309
let (test_torrent, _torrent_listed_in_index) = upload_random_torrent_to_index(&uploader, &env).await;
265310

266311
// Download
267-
let response = client.download_torrent(&test_torrent.info_hash_as_hex_string()).await;
312+
let response = client.download_torrent(&test_torrent.file_info_hash()).await;
268313

269314
let downloaded_torrent_info_hash = calculate_info_hash(&response.bytes);
270315

271316
assert_eq!(
272317
downloaded_torrent_info_hash.to_hex_string(),
273-
test_torrent.info_hash_as_hex_string(),
318+
test_torrent.file_info_hash(),
274319
"downloaded torrent info-hash does not match uploaded torrent info-hash"
275320
);
276321
}
@@ -295,7 +340,7 @@ mod for_guests {
295340
decode_torrent(&test_torrent.index_info.torrent_file.contents).expect("could not decode uploaded torrent");
296341

297342
// Download
298-
let response = client.download_torrent(&test_torrent.info_hash_as_hex_string()).await;
343+
let response = client.download_torrent(&test_torrent.file_info_hash()).await;
299344

300345
let downloaded_torrent = decode_torrent(&response.bytes).expect("could not decode downloaded torrent");
301346

@@ -348,7 +393,7 @@ mod for_guests {
348393
let uploader = new_logged_in_user(&env).await;
349394
let (test_torrent, _uploaded_torrent) = upload_random_torrent_to_index(&uploader, &env).await;
350395

351-
let response = client.delete_torrent(&test_torrent.info_hash_as_hex_string()).await;
396+
let response = client.delete_torrent(&test_torrent.file_info_hash()).await;
352397

353398
assert_eq!(response.status, 401);
354399
}
@@ -384,7 +429,7 @@ mod for_authenticated_users {
384429
let client = Client::authenticated(&env.server_socket_addr().unwrap(), &uploader.token);
385430

386431
let test_torrent = random_torrent();
387-
let info_hash = test_torrent.info_hash_as_hex_string().clone();
432+
let info_hash = test_torrent.file_info_hash().clone();
388433

389434
let form: UploadTorrentMultipartForm = test_torrent.index_info.into();
390435

@@ -527,7 +572,7 @@ mod for_authenticated_users {
527572
let client = Client::authenticated(&env.server_socket_addr().unwrap(), &downloader.token);
528573

529574
// When the user downloads the torrent
530-
let response = client.download_torrent(&test_torrent.info_hash_as_hex_string()).await;
575+
let response = client.download_torrent(&test_torrent.file_info_hash()).await;
531576

532577
let torrent = decode_torrent(&response.bytes).expect("could not decode downloaded torrent");
533578

@@ -569,7 +614,7 @@ mod for_authenticated_users {
569614

570615
let client = Client::authenticated(&env.server_socket_addr().unwrap(), &uploader.token);
571616

572-
let response = client.delete_torrent(&test_torrent.info_hash_as_hex_string()).await;
617+
let response = client.delete_torrent(&test_torrent.file_info_hash()).await;
573618

574619
assert_eq!(response.status, 403);
575620
}
@@ -597,7 +642,7 @@ mod for_authenticated_users {
597642

598643
let response = client
599644
.update_torrent(
600-
&test_torrent.info_hash_as_hex_string(),
645+
&test_torrent.file_info_hash(),
601646
UpdateTorrentFrom {
602647
title: Some(new_title.clone()),
603648
description: Some(new_description.clone()),
@@ -642,7 +687,7 @@ mod for_authenticated_users {
642687

643688
let response = client
644689
.update_torrent(
645-
&test_torrent.info_hash_as_hex_string(),
690+
&test_torrent.file_info_hash(),
646691
UpdateTorrentFrom {
647692
title: Some(new_title.clone()),
648693
description: Some(new_description.clone()),
@@ -689,7 +734,7 @@ mod for_authenticated_users {
689734
let admin = new_logged_in_admin(&env).await;
690735
let client = Client::authenticated(&env.server_socket_addr().unwrap(), &admin.token);
691736

692-
let response = client.delete_torrent(&test_torrent.info_hash_as_hex_string()).await;
737+
let response = client.delete_torrent(&test_torrent.file_info_hash()).await;
693738

694739
let deleted_torrent_response: DeletedTorrentResponse = serde_json::from_str(&response.body).unwrap();
695740

@@ -718,7 +763,7 @@ mod for_authenticated_users {
718763

719764
let response = client
720765
.update_torrent(
721-
&test_torrent.info_hash_as_hex_string(),
766+
&test_torrent.file_info_hash(),
722767
UpdateTorrentFrom {
723768
title: Some(new_title.clone()),
724769
description: Some(new_description.clone()),

tests/e2e/web/api/v1/contexts/torrent/steps.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
use std::str::FromStr;
2+
3+
use torrust_index_backend::models::info_hash::InfoHash;
4+
use torrust_index_backend::web::api::v1::responses::ErrorResponseData;
5+
16
use crate::common::client::Client;
27
use crate::common::contexts::torrent::fixtures::{random_torrent, TestTorrent, TorrentIndexInfo, TorrentListedInIndex};
38
use crate::common::contexts::torrent::forms::UploadTorrentMultipartForm;
@@ -28,3 +33,27 @@ pub async fn upload_torrent(uploader: &LoggedInUserData, torrent: &TorrentIndexI
2833

2934
TorrentListedInIndex::from(torrent.clone(), res.unwrap().data.torrent_id)
3035
}
36+
37+
/// Upload a torrent to the index.
38+
///
39+
/// # Errors
40+
///
41+
/// Returns an `ErrorResponseData` if the response is not a 200.
42+
pub async fn upload_test_torrent(client: &Client, test_torrent: &TestTorrent) -> Result<InfoHash, ErrorResponseData> {
43+
let form: UploadTorrentMultipartForm = test_torrent.clone().index_info.into();
44+
let response = client.upload_torrent(form.into()).await;
45+
46+
if response.status != 200 {
47+
let error: ErrorResponseData = serde_json::from_str(&response.body)
48+
.unwrap_or_else(|_| panic!("response {:#?} should be a ErrorResponseData", response.body));
49+
return Err(error);
50+
}
51+
52+
let uploaded_torrent_response: UploadedTorrentResponse = serde_json::from_str(&response.body).unwrap();
53+
let canonical_info_hash_hex = uploaded_torrent_response.data.info_hash.to_lowercase();
54+
55+
let canonical_info_hash = InfoHash::from_str(&canonical_info_hash_hex)
56+
.unwrap_or_else(|_| panic!("Invalid info-hash in database: {canonical_info_hash_hex}"));
57+
58+
Ok(canonical_info_hash)
59+
}

0 commit comments

Comments
 (0)