diff --git a/src/databases/database.rs b/src/databases/database.rs index 96d7b16f..0ba2a5a1 100644 --- a/src/databases/database.rs +++ b/src/databases/database.rs @@ -13,6 +13,27 @@ use crate::models::torrent_tag::{TagId, TorrentTag}; use crate::models::tracker_key::TrackerKey; use crate::models::user::{User, UserAuthentication, UserCompact, UserId, UserProfile}; +/// Database tables to be truncated when upgrading from v1.0.0 to v2.0.0. +/// They must be in the correct order to avoid foreign key errors. +pub const TABLES_TO_TRUNCATE: &[&str] = &[ + "torrust_torrent_announce_urls", + "torrust_torrent_files", + "torrust_torrent_info", + "torrust_torrent_tag_links", + "torrust_torrent_tracker_stats", + "torrust_torrents", + "torrust_tracker_keys", + "torrust_user_authentication", + "torrust_user_bans", + "torrust_user_invitation_uses", + "torrust_user_invitations", + "torrust_user_profiles", + "torrust_user_public_keys", + "torrust_users", + "torrust_categories", + "torrust_torrent_tags", +]; + /// Database drivers. #[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)] pub enum Driver { diff --git a/src/databases/mysql.rs b/src/databases/mysql.rs index 60991edd..9b28e51f 100644 --- a/src/databases/mysql.rs +++ b/src/databases/mysql.rs @@ -6,6 +6,7 @@ use chrono::NaiveDateTime; use sqlx::mysql::{MySqlConnectOptions, MySqlPoolOptions}; use sqlx::{query, query_as, Acquire, ConnectOptions, MySqlPool}; +use super::database::TABLES_TO_TRUNCATE; use crate::databases::database; use crate::databases::database::{Category, Database, Driver, Sorting, TorrentCompact}; use crate::models::category::CategoryId; @@ -852,55 +853,12 @@ impl Database for Mysql { } async fn delete_all_database_rows(&self) -> Result<(), database::Error> { - query("DELETE FROM torrust_categories;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_torrents;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_tracker_keys;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_users;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_user_authentication;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_user_bans;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_user_invitations;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_user_profiles;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_torrents;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_user_public_keys;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; + for table in TABLES_TO_TRUNCATE { + query(&format!("DELETE FROM {table};")) + .execute(&self.pool) + .await + .map_err(|_| database::Error::Error)?; + } Ok(()) } diff --git a/src/databases/sqlite.rs b/src/databases/sqlite.rs index 66c509b0..8d2123a3 100644 --- a/src/databases/sqlite.rs +++ b/src/databases/sqlite.rs @@ -6,6 +6,7 @@ use chrono::NaiveDateTime; use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions}; use sqlx::{query, query_as, Acquire, ConnectOptions, SqlitePool}; +use super::database::TABLES_TO_TRUNCATE; use crate::databases::database; use crate::databases::database::{Category, Database, Driver, Sorting, TorrentCompact}; use crate::models::category::CategoryId; @@ -842,55 +843,12 @@ impl Database for Sqlite { } async fn delete_all_database_rows(&self) -> Result<(), database::Error> { - query("DELETE FROM torrust_categories;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_torrents;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_tracker_keys;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_users;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_user_authentication;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_user_bans;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_user_invitations;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_user_profiles;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_torrents;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; - - query("DELETE FROM torrust_user_public_keys;") - .execute(&self.pool) - .await - .map_err(|_| database::Error::Error)?; + for table in TABLES_TO_TRUNCATE { + query(&format!("DELETE FROM {table};")) + .execute(&self.pool) + .await + .map_err(|_| database::Error::Error)?; + } Ok(()) } diff --git a/src/upgrades/from_v1_0_0_to_v2_0_0/databases/mod.rs b/src/upgrades/from_v1_0_0_to_v2_0_0/databases/mod.rs index df2054e6..a5f8b0e9 100644 --- a/src/upgrades/from_v1_0_0_to_v2_0_0/databases/mod.rs +++ b/src/upgrades/from_v1_0_0_to_v2_0_0/databases/mod.rs @@ -21,7 +21,7 @@ pub async fn migrate_target_database(target_database: Arc) target_database.migrate().await; } -pub async fn reset_target_database(target_database: Arc) { +pub async fn truncate_target_database(target_database: Arc) { println!("Truncating all tables in target database ..."); target_database .delete_all_database_rows() diff --git a/src/upgrades/from_v1_0_0_to_v2_0_0/databases/sqlite_v2_0_0.rs b/src/upgrades/from_v1_0_0_to_v2_0_0/databases/sqlite_v2_0_0.rs index d054ca1c..065d6306 100644 --- a/src/upgrades/from_v1_0_0_to_v2_0_0/databases/sqlite_v2_0_0.rs +++ b/src/upgrades/from_v1_0_0_to_v2_0_0/databases/sqlite_v2_0_0.rs @@ -6,7 +6,7 @@ use sqlx::sqlite::{SqlitePoolOptions, SqliteQueryResult}; use sqlx::{query, query_as, SqlitePool}; use super::sqlite_v1_0_0::{TorrentRecordV1, UserRecordV1}; -use crate::databases::database; +use crate::databases::database::{self, TABLES_TO_TRUNCATE}; use crate::models::torrent_file::{TorrentFile, TorrentInfo}; #[derive(Debug, Serialize, Deserialize, sqlx::FromRow)] @@ -261,34 +261,12 @@ impl SqliteDatabaseV2_0_0 { #[allow(clippy::missing_panics_doc)] pub async fn delete_all_database_rows(&self) -> Result<(), database::Error> { - query("DELETE FROM torrust_categories").execute(&self.pool).await.unwrap(); - - query("DELETE FROM torrust_torrents").execute(&self.pool).await.unwrap(); - - query("DELETE FROM torrust_tracker_keys").execute(&self.pool).await.unwrap(); - - query("DELETE FROM torrust_users").execute(&self.pool).await.unwrap(); - - query("DELETE FROM torrust_user_authentication") - .execute(&self.pool) - .await - .unwrap(); - - query("DELETE FROM torrust_user_bans").execute(&self.pool).await.unwrap(); - - query("DELETE FROM torrust_user_invitations") - .execute(&self.pool) - .await - .unwrap(); - - query("DELETE FROM torrust_user_profiles").execute(&self.pool).await.unwrap(); - - query("DELETE FROM torrust_torrents").execute(&self.pool).await.unwrap(); - - query("DELETE FROM torrust_user_public_keys") - .execute(&self.pool) - .await - .unwrap(); + for table in TABLES_TO_TRUNCATE { + query(&format!("DELETE FROM {table};")) + .execute(&self.pool) + .await + .expect("table {table} should be deleted"); + } Ok(()) } diff --git a/src/upgrades/from_v1_0_0_to_v2_0_0/upgrader.rs b/src/upgrades/from_v1_0_0_to_v2_0_0/upgrader.rs index 0c0f7a9d..c010d8e2 100644 --- a/src/upgrades/from_v1_0_0_to_v2_0_0/upgrader.rs +++ b/src/upgrades/from_v1_0_0_to_v2_0_0/upgrader.rs @@ -52,7 +52,7 @@ use std::time::SystemTime; use chrono::prelude::{DateTime, Utc}; use text_colorizer::Colorize; -use crate::upgrades::from_v1_0_0_to_v2_0_0::databases::{current_db, migrate_target_database, new_db, reset_target_database}; +use crate::upgrades::from_v1_0_0_to_v2_0_0::databases::{current_db, migrate_target_database, new_db, truncate_target_database}; use crate::upgrades::from_v1_0_0_to_v2_0_0::transferrers::category_transferrer::transfer_categories; use crate::upgrades::from_v1_0_0_to_v2_0_0::transferrers::torrent_transferrer::transfer_torrents; use crate::upgrades::from_v1_0_0_to_v2_0_0::transferrers::tracker_key_transferrer::transfer_tracker_keys; @@ -120,7 +120,7 @@ pub async fn upgrade(args: &Arguments, date_imported: &str) { println!("Upgrading data from version v1.0.0 to v2.0.0 ..."); migrate_target_database(target_database.clone()).await; - reset_target_database(target_database.clone()).await; + truncate_target_database(target_database.clone()).await; transfer_categories(source_database.clone(), target_database.clone()).await; transfer_users(source_database.clone(), target_database.clone(), date_imported).await; diff --git a/tests/databases/README.md b/tests/databases/README.md deleted file mode 100644 index 54a1b842..00000000 --- a/tests/databases/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# Persistence Tests - -Torrust requires Docker to run different database systems for testing. - -Start the databases with `docker-compose` before running tests: - -```s -docker-compose -f tests/databases/docker-compose.yml up -``` - -Run all tests using: - -```s -cargo test -``` - -Connect to the DB using MySQL client: - -```s -mysql -h127.0.0.1 -uroot -ppassword torrust-index_test -``` - -Right now only tests for MySQLite are executed. To run tests for MySQL too, -you have to replace this line in `tests/databases/mysql.rs`: - -```rust - -```rust -#[tokio::test] -#[should_panic] -async fn run_mysql_tests() { - panic!("Todo Test Times Out!"); - #[allow(unreachable_code)] - { - run_tests(DATABASE_URL).await; - } -} -``` - -with this: - -```rust -#[tokio::test] -async fn run_mysql_tests() { - run_tests(DATABASE_URL).await; -} -``` diff --git a/tests/databases/docker-compose.yml b/tests/databases/docker-compose.yml deleted file mode 100644 index 4a5501bd..00000000 --- a/tests/databases/docker-compose.yml +++ /dev/null @@ -1,12 +0,0 @@ -version: "3.9" - -services: - - mysql_8: - image: mysql:8.0.30 - ports: - - "3306:3306" - environment: - MYSQL_ROOT_HOST: '%' - MYSQL_ROOT_PASSWORD: password - MYSQL_DATABASE: torrust-index_test diff --git a/tests/databases/mod.rs b/tests/databases/mod.rs deleted file mode 100644 index 22d83c5e..00000000 --- a/tests/databases/mod.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::future::Future; - -use torrust_index_backend::databases::database; -use torrust_index_backend::databases::database::Database; - -mod mysql; -mod sqlite; -mod tests; - -// used to run tests with a clean database -async fn run_test<'a, T, F, DB: Database + ?Sized>(db_fn: T, db: &'a DB) -where - T: FnOnce(&'a DB) -> F + 'a, - F: Future, -{ - // cleanup database before testing - assert!(db.delete_all_database_rows().await.is_ok()); - - // run test using clean database - db_fn(db).await; -} - -// runs all tests -pub async fn run_tests(db_path: &str) { - let db_res = database::connect(db_path).await; - - assert!(db_res.is_ok()); - - let db_boxed = db_res.unwrap(); - - let db: &dyn Database = db_boxed.as_ref(); - - run_test(tests::it_can_add_a_user, db).await; - run_test(tests::it_can_add_a_torrent_category, db).await; - run_test(tests::it_can_add_a_torrent_and_tracker_stats_to_that_torrent, db).await; -} diff --git a/tests/databases/mysql.rs b/tests/databases/mysql.rs deleted file mode 100644 index e2b58102..00000000 --- a/tests/databases/mysql.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[allow(unused_imports)] -use crate::databases::run_tests; - -#[allow(dead_code)] -const DATABASE_URL: &str = "mysql://root:password@localhost:3306/torrust-index_test"; - -#[tokio::test] -#[should_panic] -async fn run_mysql_tests() { - panic!("Todo Test Times Out!"); - #[allow(unreachable_code)] - { - run_tests(DATABASE_URL).await; - } -} diff --git a/tests/databases/sqlite.rs b/tests/databases/sqlite.rs deleted file mode 100644 index 37d89a97..00000000 --- a/tests/databases/sqlite.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::databases::run_tests; - -const DATABASE_URL: &str = "sqlite::memory:"; - -#[tokio::test] -async fn run_sqlite_tests() { - run_tests(DATABASE_URL).await; -} diff --git a/tests/databases/tests.rs b/tests/databases/tests.rs deleted file mode 100644 index 98c24d60..00000000 --- a/tests/databases/tests.rs +++ /dev/null @@ -1,159 +0,0 @@ -use serde_bytes::ByteBuf; -use torrust_index_backend::databases::database; -use torrust_index_backend::databases::database::Database; -use torrust_index_backend::models::torrent::TorrentListing; -use torrust_index_backend::models::torrent_file::{Torrent, TorrentInfo}; -use torrust_index_backend::models::user::UserProfile; - -// test user options -const TEST_USER_USERNAME: &str = "luckythelab"; -const TEST_USER_EMAIL: &str = "lucky@labradormail.com"; -const TEST_USER_PASSWORD: &str = "imagoodboy"; - -// test category options -const TEST_CATEGORY_NAME: &str = "Labrador Retrievers"; - -// test torrent options -const TEST_TORRENT_TITLE: &str = "Picture of dog treat"; -const TEST_TORRENT_DESCRIPTION: &str = "This is a picture of a dog treat."; -const TEST_TORRENT_FILE_SIZE: i64 = 128_000; -const TEST_TORRENT_SEEDERS: i64 = 437; -const TEST_TORRENT_LEECHERS: i64 = 1289; - -async fn add_test_user(db: &T) -> Result { - db.insert_user_and_get_id(TEST_USER_USERNAME, TEST_USER_EMAIL, TEST_USER_PASSWORD) - .await -} - -async fn add_test_torrent_category(db: &T) -> Result { - db.insert_category_and_get_id(TEST_CATEGORY_NAME).await -} - -pub async fn it_can_add_a_user(db: &T) { - let add_test_user_result = add_test_user(db).await; - - assert!(add_test_user_result.is_ok()); - - let inserted_user_id = add_test_user_result.unwrap(); - - let get_user_profile_from_username_result = db.get_user_profile_from_username(TEST_USER_USERNAME).await; - - // verify that we can grab the newly inserted user's profile data - assert!(get_user_profile_from_username_result.is_ok()); - - let returned_user_profile = get_user_profile_from_username_result.unwrap(); - - // verify that the profile data is as we expect it to be - assert_eq!( - returned_user_profile, - UserProfile { - user_id: inserted_user_id, - username: TEST_USER_USERNAME.to_string(), - email: TEST_USER_EMAIL.to_string(), - email_verified: returned_user_profile.email_verified, - bio: returned_user_profile.bio.clone(), - avatar: returned_user_profile.avatar.clone() - } - ); -} - -pub async fn it_can_add_a_torrent_category(db: &T) { - let add_test_torrent_category_result = add_test_torrent_category(db).await; - - assert!(add_test_torrent_category_result.is_ok()); - - let get_category_from_name_result = db.get_category_from_name(TEST_CATEGORY_NAME).await; - - assert!(get_category_from_name_result.is_ok()); - - let category = get_category_from_name_result.unwrap(); - - assert_eq!(category.name, TEST_CATEGORY_NAME.to_string()); -} - -pub async fn it_can_add_a_torrent_and_tracker_stats_to_that_torrent(db: &T) { - // set pre-conditions - let user_id = add_test_user(db).await.expect("add_test_user failed."); - let torrent_category_id = add_test_torrent_category(db) - .await - .expect("add_test_torrent_category failed."); - - let torrent = Torrent { - info: TorrentInfo { - name: TEST_TORRENT_TITLE.to_string(), - pieces: Some(ByteBuf::from("1234567890123456789012345678901234567890".as_bytes())), - piece_length: 256_000, - md5sum: None, - length: Some(TEST_TORRENT_FILE_SIZE), - files: None, - private: Some(1), - path: None, - root_hash: None, - }, - announce: Some("https://tracker.dutchbits.nl/announce".to_string()), - nodes: None, - encoding: None, - httpseeds: None, - announce_list: None, - creation_date: None, - comment: None, - created_by: None, - }; - - let insert_torrent_and_get_id_result = db - .insert_torrent_and_get_id( - &torrent, - user_id, - torrent_category_id, - TEST_TORRENT_TITLE, - TEST_TORRENT_DESCRIPTION, - ) - .await; - - assert!(insert_torrent_and_get_id_result.is_ok()); - - let torrent_id = insert_torrent_and_get_id_result.unwrap(); - - // add tracker stats to the torrent - let insert_torrent_tracker_stats_result = db - .update_tracker_info( - torrent_id, - "https://tracker.torrust.com", - TEST_TORRENT_SEEDERS, - TEST_TORRENT_LEECHERS, - ) - .await; - - assert!(insert_torrent_tracker_stats_result.is_ok()); - - let get_torrent_listing_from_id_result = db.get_torrent_listing_from_id(torrent_id).await; - - assert!(get_torrent_listing_from_id_result.is_ok()); - - let returned_torrent_listing = get_torrent_listing_from_id_result.unwrap(); - - assert_eq!( - returned_torrent_listing, - TorrentListing { - torrent_id, - uploader: TEST_USER_USERNAME.to_string(), - info_hash: returned_torrent_listing.info_hash.to_string(), - title: TEST_TORRENT_TITLE.to_string(), - description: Some(TEST_TORRENT_DESCRIPTION.to_string()), - category_id: torrent_category_id, - date_uploaded: returned_torrent_listing.date_uploaded.to_string(), - file_size: TEST_TORRENT_FILE_SIZE, - seeders: TEST_TORRENT_SEEDERS, - leechers: TEST_TORRENT_LEECHERS - } - ); - - // check if we get the same info hash on the retrieved torrent from database - let get_torrent_from_id_result = db.get_torrent_from_id(torrent_id).await; - - assert!(get_torrent_from_id_result.is_ok()); - - let returned_torrent = get_torrent_from_id_result.unwrap(); - - assert_eq!(returned_torrent.info_hash(), torrent.info_hash()); -} diff --git a/tests/mod.rs b/tests/mod.rs index 6180292f..4d330909 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -1,5 +1,4 @@ mod common; -mod databases; mod e2e; pub mod environments; mod upgrades;