From e9762ff9f719fd66b32725aab5fb9f12a10c3c81 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Mon, 8 May 2023 12:54:08 +0100 Subject: [PATCH] test: [#115] add more E2E tests for endpoints using torrent ID Since we are going to change those endpoint, it's convenient to add more test. Endpoints starting with `torrent/{id}` will be change to use the infohash instead of the internal torrent id, generated by the database. --- src/routes/torrent.rs | 2 + tests/e2e/contexts/torrent/asserts.rs | 11 +-- tests/e2e/contexts/torrent/contract.rs | 92 ++++++++++++++++++++++---- 3 files changed, 87 insertions(+), 18 deletions(-) diff --git a/src/routes/torrent.rs b/src/routes/torrent.rs index 10f5fdba..411ad6eb 100644 --- a/src/routes/torrent.rs +++ b/src/routes/torrent.rs @@ -220,6 +220,8 @@ pub async fn get_torrent(req: HttpRequest, app_data: WebAppData) -> ServiceResul } } + // todo: extract a struct or function to build the magnet links + // add magnet link let mut magnet = format!( "magnet:?xt=urn:btih:{}&dn={}", diff --git a/tests/e2e/contexts/torrent/asserts.rs b/tests/e2e/contexts/torrent/asserts.rs index b6e8ae76..c5c9759f 100644 --- a/tests/e2e/contexts/torrent/asserts.rs +++ b/tests/e2e/contexts/torrent/asserts.rs @@ -34,7 +34,7 @@ pub async fn expected_torrent(mut uploaded_torrent: Torrent, env: &TestEnv, down uploaded_torrent } -async fn get_user_tracker_key(logged_in_user: &LoggedInUserData, env: &TestEnv) -> Option { +pub async fn get_user_tracker_key(logged_in_user: &LoggedInUserData, env: &TestEnv) -> Option { // code-review: could we add a new endpoint to get the user's tracker key? // `/user/keys/recent` or `/user/keys/latest // We could use that endpoint to get the user's tracker key instead of @@ -43,7 +43,7 @@ async fn get_user_tracker_key(logged_in_user: &LoggedInUserData, env: &TestEnv) let database = Arc::new( connect_database(&env.database_connect_url().unwrap()) .await - .expect("Database error."), + .expect("database connection to be established."), ); // Get the logged-in user id @@ -53,12 +53,15 @@ async fn get_user_tracker_key(logged_in_user: &LoggedInUserData, env: &TestEnv) .unwrap(); // Get the user's tracker key - let tracker_key = database.get_user_tracker_key(user_profile.user_id).await.unwrap(); + let tracker_key = database + .get_user_tracker_key(user_profile.user_id) + .await + .expect("user to have a tracker key"); Some(tracker_key) } -fn build_announce_url(tracker_url: &str, tracker_key: &Option) -> String { +pub fn build_announce_url(tracker_url: &str, tracker_key: &Option) -> String { if let Some(key) = &tracker_key { format!("{tracker_url}/{}", key.key) } else { diff --git a/tests/e2e/contexts/torrent/contract.rs b/tests/e2e/contexts/torrent/contract.rs index 2620dd37..cca181ac 100644 --- a/tests/e2e/contexts/torrent/contract.rs +++ b/tests/e2e/contexts/torrent/contract.rs @@ -10,9 +10,6 @@ Delete torrent: Get torrent info: - The torrent info: - - should contain the tracker URL - - If no user owned tracker key can be found, it should use the default tracker url - - If user owned tracker key can be found, it should use the personal tracker url - should contain the magnet link with the trackers from the torrent file - should contain realtime seeders and leechers from the tracker */ @@ -74,6 +71,9 @@ mod for_guests { let torrent_details_response: TorrentDetailsResponse = serde_json::from_str(&response.body).unwrap(); + let tracker_url = format!("{}", env.server_settings().unwrap().tracker.url); + let encoded_tracker_url = urlencoding::encode(&tracker_url); + let expected_torrent = TorrentDetails { torrent_id: uploaded_torrent.torrent_id, uploader: uploader.username, @@ -95,13 +95,19 @@ mod for_guests { length: test_torrent.file_info.content_size, md5sum: None, }], - // code-review: why is this duplicated? - trackers: vec!["udp://tracker:6969".to_string(), "udp://tracker:6969".to_string()], + // code-review: why is this duplicated? It seems that is adding the + // same tracker twice because first ti adds all trackers and then + // it adds the tracker with the personal announce url, if the user + // is logged in. If the user is not logged in, it adds the default + // tracker again, and it ends up with two trackers. + trackers: vec![tracker_url.clone(), tracker_url.clone()], magnet_link: format!( // cspell:disable-next-line - "magnet:?xt=urn:btih:{}&dn={}&tr=udp%3A%2F%2Ftracker%3A6969&tr=udp%3A%2F%2Ftracker%3A6969", + "magnet:?xt=urn:btih:{}&dn={}&tr={}&tr={}", test_torrent.file_info.info_hash.to_uppercase(), - test_torrent.index_info.title + urlencoding::encode(&test_torrent.index_info.title), + encoded_tracker_url, + encoded_tracker_url ), }; @@ -134,6 +140,26 @@ mod for_guests { assert!(response.is_bittorrent_and_ok()); } + #[tokio::test] + async fn it_should_return_a_not_found_trying_to_download_a_non_existing_torrent() { + let mut env = TestEnv::new(); + env.start().await; + + if !env.provides_a_tracker() { + println!("test skipped. It requires a tracker to be running."); + return; + } + + let client = Client::unauthenticated(&env.server_socket_addr().unwrap()); + + let non_existing_info_hash = "443c7602b4fde83d1154d6d9da48808418b181b6".to_string(); + + let response = client.download_torrent(non_existing_info_hash).await; + + // code-review: should this be 404? + assert_eq!(response.status, 400); + } + #[tokio::test] async fn it_should_not_allow_guests_to_delete_torrents() { let mut env = TestEnv::new(); @@ -163,7 +189,7 @@ mod for_authenticated_users { use crate::common::contexts::torrent::fixtures::random_torrent; use crate::common::contexts::torrent::forms::UploadTorrentMultipartForm; use crate::common::contexts::torrent::responses::UploadedTorrentResponse; - use crate::e2e::contexts::torrent::asserts::expected_torrent; + use crate::e2e::contexts::torrent::asserts::{build_announce_url, get_user_tracker_key}; use crate::e2e::contexts::torrent::steps::upload_random_torrent_to_index; use crate::e2e::contexts::user::steps::new_logged_in_user; use crate::e2e::environment::TestEnv; @@ -289,8 +315,6 @@ mod for_authenticated_users { // Given a previously uploaded torrent let uploader = new_logged_in_user(&env).await; let (test_torrent, _torrent_listed_in_index) = upload_random_torrent_to_index(&uploader, &env).await; - let uploaded_torrent = - decode_torrent(&test_torrent.index_info.torrent_file.contents).expect("could not decode uploaded torrent"); // And a logged in user who is going to download the torrent let downloader = new_logged_in_user(&env).await; @@ -302,14 +326,20 @@ mod for_authenticated_users { let torrent = decode_torrent(&response.bytes).expect("could not decode downloaded torrent"); // Then the torrent should have the personal announce URL - let expected_torrent = expected_torrent(uploaded_torrent, &env, &Some(downloader)).await; - - assert_eq!(torrent, expected_torrent); - assert!(response.is_bittorrent_and_ok()); + let tracker_key = get_user_tracker_key(&downloader, &env) + .await + .expect("uploader should have a valid tracker key"); + let tracker_url = format!("{}", env.server_settings().unwrap().tracker.url); + + assert_eq!( + torrent.announce.unwrap(), + build_announce_url(&tracker_url, &Some(tracker_key)) + ); } mod and_non_admins { use crate::common::client::Client; + use crate::common::contexts::torrent::forms::UpdateTorrentFrom; use crate::e2e::contexts::torrent::steps::upload_random_torrent_to_index; use crate::e2e::contexts::user::steps::new_logged_in_user; use crate::e2e::environment::TestEnv; @@ -333,6 +363,40 @@ mod for_authenticated_users { assert_eq!(response.status, 403); } + + #[tokio::test] + async fn it_should_allow_non_admin_users_to_update_someone_elses_torrents() { + let mut env = TestEnv::new(); + env.start().await; + + if !env.provides_a_tracker() { + println!("test skipped. It requires a tracker to be running."); + return; + } + + // Given a users uploads a torrent + let uploader = new_logged_in_user(&env).await; + let (test_torrent, uploaded_torrent) = upload_random_torrent_to_index(&uploader, &env).await; + + // Then another non admin user should not be able to update the torrent + let not_the_uploader = new_logged_in_user(&env).await; + let client = Client::authenticated(&env.server_socket_addr().unwrap(), ¬_the_uploader.token); + + let new_title = format!("{}-new-title", test_torrent.index_info.title); + let new_description = format!("{}-new-description", test_torrent.index_info.description); + + let response = client + .update_torrent( + uploaded_torrent.torrent_id, + UpdateTorrentFrom { + title: Some(new_title.clone()), + description: Some(new_description.clone()), + }, + ) + .await; + + assert_eq!(response.status, 403); + } } mod and_torrent_owners {