diff --git a/src/app/readarr/mod.rs b/src/app/readarr/mod.rs index 70f89f2c..ce719e24 100644 --- a/src/app/readarr/mod.rs +++ b/src/app/readarr/mod.rs @@ -1,5 +1,8 @@ use super::App; -use crate::models::servarr_data::readarr::readarr_data::ActiveReadarrBlock; +use crate::{ + models::servarr_data::readarr::readarr_data::ActiveReadarrBlock, + network::readarr_network::ReadarrEvent, +}; pub mod readarr_context_clues; @@ -10,12 +13,179 @@ mod readarr_tests; impl App<'_> { pub(super) async fn dispatch_by_readarr_block( &mut self, - _active_readarr_block: &ActiveReadarrBlock, + active_readarr_block: &ActiveReadarrBlock, ) { + match active_readarr_block { + ActiveReadarrBlock::Authors => { + self + .dispatch_network_event(ReadarrEvent::GetQualityProfiles.into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetMetadataProfiles.into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetTags.into()) + .await; + self + .dispatch_network_event(ReadarrEvent::ListAuthors.into()) + .await; + } + ActiveReadarrBlock::Blocklist => { + self + .dispatch_network_event(ReadarrEvent::GetBlocklist.into()) + .await; + } + ActiveReadarrBlock::Downloads => { + self + .dispatch_network_event(ReadarrEvent::GetDownloads(500).into()) + .await; + } + ActiveReadarrBlock::AuthorDetails => { + self + .dispatch_network_event(ReadarrEvent::GetBooks(self.extract_author_id().await).into()) + .await; + } + ActiveReadarrBlock::AuthorHistory => { + self + .dispatch_network_event( + ReadarrEvent::GetAuthorHistory(self.extract_author_id().await).into(), + ) + .await; + } + ActiveReadarrBlock::ManualAuthorSearch => { + if self.data.readarr_data.author_releases.is_empty() { + self + .dispatch_network_event( + ReadarrEvent::GetAuthorReleases(self.extract_author_id().await).into(), + ) + .await; + } + } + ActiveReadarrBlock::BookDetails => { + let book_id = self.extract_book_id().await; + self + .dispatch_network_event(ReadarrEvent::GetBookEditions(book_id).into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetBookFiles(book_id).into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetDownloads(500).into()) + .await; + } + ActiveReadarrBlock::BookHistory => { + if !self.data.readarr_data.books.is_empty() { + self + .dispatch_network_event( + ReadarrEvent::GetBookHistory( + self.extract_author_id().await, + self.extract_book_id().await, + ) + .into(), + ) + .await; + } + } + ActiveReadarrBlock::ManualBookSearch => { + match self.data.readarr_data.book_details_modal.as_ref() { + Some(book_details_modal) if book_details_modal.book_releases.is_empty() => { + self + .dispatch_network_event( + ReadarrEvent::GetBookReleases(self.extract_book_id().await).into(), + ) + .await; + } + _ => (), + } + } + ActiveReadarrBlock::AddAuthorSearchResults => { + self + .dispatch_network_event( + ReadarrEvent::SearchNewAuthor(self.extract_add_new_author_search_query().await).into(), + ) + .await; + } + ActiveReadarrBlock::History => { + self + .dispatch_network_event(ReadarrEvent::GetHistory(500).into()) + .await + } + ActiveReadarrBlock::RootFolders => { + self + .dispatch_network_event(ReadarrEvent::GetRootFolders.into()) + .await; + } + ActiveReadarrBlock::Indexers => { + self + .dispatch_network_event(ReadarrEvent::GetTags.into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetIndexers.into()) + .await; + } + ActiveReadarrBlock::AllIndexerSettingsPrompt => { + self + .dispatch_network_event(ReadarrEvent::GetAllIndexerSettings.into()) + .await; + } + ActiveReadarrBlock::TestIndexer => { + self + .dispatch_network_event( + ReadarrEvent::TestIndexer(self.extract_readarr_indexer_id().await).into(), + ) + .await; + } + ActiveReadarrBlock::TestAllIndexers => { + self + .dispatch_network_event(ReadarrEvent::TestAllIndexers.into()) + .await; + } + ActiveReadarrBlock::System => { + self + .dispatch_network_event(ReadarrEvent::GetTasks.into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetQueuedEvents.into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetLogs(500).into()) + .await; + } + ActiveReadarrBlock::SystemUpdates => { + self + .dispatch_network_event(ReadarrEvent::GetUpdates.into()) + .await; + } + _ => (), + } + self.check_for_readarr_prompt_action().await; self.reset_tick_count(); } + async fn extract_add_new_author_search_query(&self) -> String { + self + .data + .readarr_data + .add_author_search + .as_ref() + .expect("Add author search is empty") + .text + .clone() + } + + async fn extract_author_id(&self) -> i64 { + self.data.readarr_data.authors.current_selection().id + } + + async fn extract_book_id(&self) -> i64 { + self.data.readarr_data.books.current_selection().id + } + + async fn extract_readarr_indexer_id(&self) -> i64 { + self.data.readarr_data.indexers.current_selection().id + } + async fn check_for_readarr_prompt_action(&mut self) { if self.data.readarr_data.prompt_confirm { self.data.readarr_data.prompt_confirm = false; @@ -28,6 +198,7 @@ impl App<'_> { pub(super) async fn readarr_on_tick(&mut self, active_readarr_block: ActiveReadarrBlock) { if self.is_first_render { + self.refresh_readarr_metadata().await; self.dispatch_by_readarr_block(&active_readarr_block).await; self.is_first_render = false; return; @@ -35,6 +206,7 @@ impl App<'_> { if self.should_refresh { self.dispatch_by_readarr_block(&active_readarr_block).await; + self.refresh_readarr_metadata().await; } if self.is_routing { @@ -44,5 +216,33 @@ impl App<'_> { self.dispatch_by_readarr_block(&active_readarr_block).await; } } + + if self.tick_count.is_multiple_of(self.tick_until_poll) { + self.refresh_readarr_metadata().await; + } + } + + async fn refresh_readarr_metadata(&mut self) { + self + .dispatch_network_event(ReadarrEvent::GetQualityProfiles.into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetMetadataProfiles.into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetTags.into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetRootFolders.into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetDownloads(500).into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetDiskSpace.into()) + .await; + self + .dispatch_network_event(ReadarrEvent::GetStatus.into()) + .await; } } diff --git a/src/app/readarr/readarr_tests.rs b/src/app/readarr/readarr_tests.rs index 1aa8a0cc..2b771b4e 100644 --- a/src/app/readarr/readarr_tests.rs +++ b/src/app/readarr/readarr_tests.rs @@ -1,8 +1,506 @@ #[cfg(test)] mod tests { use crate::app::App; + use crate::models::readarr_models::{Author, Book, ReadarrRelease}; + use crate::models::servarr_data::readarr::modals::BookDetailsModal; use crate::models::servarr_data::readarr::readarr_data::ActiveReadarrBlock; - use pretty_assertions::assert_eq; + use crate::models::servarr_models::Indexer; + use crate::network::NetworkEvent; + use crate::network::readarr_network::ReadarrEvent; + use pretty_assertions::{assert_eq, assert_str_eq}; + use tokio::sync::mpsc; + + #[tokio::test] + async fn test_dispatch_by_readarr_block_authors() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::Authors) + .await; + + assert!(app.is_loading); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetQualityProfiles.into() + ); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetMetadataProfiles.into() + ); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetTags.into()); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::ListAuthors.into()); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_readarr_block_author_details() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.data.readarr_data.authors.set_items(vec![Author { + id: 1, + ..Author::default() + }]); + app.network_tx = Some(tx); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::AuthorDetails) + .await; + + assert!(app.is_loading); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetBooks(1).into()); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_blocklist_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::Blocklist) + .await; + + assert!(app.is_loading); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetBlocklist.into()); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_author_history_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + app.data.readarr_data.authors.set_items(vec![Author { + id: 1, + ..Author::default() + }]); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::AuthorHistory) + .await; + + assert!(app.is_loading); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetAuthorHistory(1).into() + ); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_manual_author_search_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + app.data.readarr_data.authors.set_items(vec![Author { + id: 1, + ..Author::default() + }]); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::ManualAuthorSearch) + .await; + + assert!(app.is_loading); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetAuthorReleases(1).into() + ); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_manual_author_search_block_author_releases_non_empty() { + let mut app = App::test_default(); + app + .data + .readarr_data + .author_releases + .set_items(vec![ReadarrRelease::default()]); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::ManualAuthorSearch) + .await; + + assert!(!app.is_loading); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_book_details_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + app.data.readarr_data.authors.set_items(vec![Author { + id: 1, + ..Author::default() + }]); + app.data.readarr_data.books.set_items(vec![Book { + id: 2, + ..Book::default() + }]); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::BookDetails) + .await; + + assert!(app.is_loading); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetBookEditions(2).into() + ); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetBookFiles(2).into() + ); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetDownloads(500).into() + ); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_book_history_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + app.data.readarr_data.authors.set_items(vec![Author { + id: 1, + ..Author::default() + }]); + app.data.readarr_data.books.set_items(vec![Book { + id: 2, + ..Book::default() + }]); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::BookHistory) + .await; + + assert!(app.is_loading); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetBookHistory(1, 2).into() + ); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_book_history_block_no_op_when_books_table_is_empty() { + let (tx, _) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + app.data.readarr_data.authors.set_items(vec![Author { + id: 1, + ..Author::default() + }]); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::BookHistory) + .await; + + assert!(!app.is_loading); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_manual_book_search_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + app.data.readarr_data.authors.set_items(vec![Author { + id: 1, + ..Author::default() + }]); + app.data.readarr_data.books.set_items(vec![Book { + id: 2, + ..Book::default() + }]); + app.data.readarr_data.book_details_modal = Some(BookDetailsModal::default()); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::ManualBookSearch) + .await; + + assert!(app.is_loading); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetBookReleases(2).into() + ); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_manual_book_search_block_is_loading() { + let mut app = App { + is_loading: true, + ..App::test_default() + }; + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::ManualBookSearch) + .await; + + assert!(app.is_loading); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_manual_book_search_block_book_releases_non_empty() { + let mut app = App::test_default(); + let mut book_details_modal = BookDetailsModal::default(); + book_details_modal + .book_releases + .set_items(vec![ReadarrRelease::default()]); + app.data.readarr_data.book_details_modal = Some(book_details_modal); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::ManualBookSearch) + .await; + + assert!(!app.is_loading); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_book_edition_details_block_does_not_dispatch() { + let mut app = App::test_default_fully_populated(); + app.data.readarr_data.prompt_confirm = false; + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::BookEditionDetails) + .await; + + assert!(!app.is_loading); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_downloads_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::Downloads) + .await; + + assert!(app.is_loading); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetDownloads(500).into() + ); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_readarr_block_add_author_search_results() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + app.data.readarr_data.add_author_search = Some("test author".into()); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::AddAuthorSearchResults) + .await; + + assert!(app.is_loading); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::SearchNewAuthor("test author".to_owned()).into() + ); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_history_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::History) + .await; + + assert!(app.is_loading); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetHistory(500).into() + ); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_root_folders_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::RootFolders) + .await; + + assert!(app.is_loading); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetRootFolders.into() + ); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_indexers_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::Indexers) + .await; + + assert!(app.is_loading); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetTags.into()); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetIndexers.into()); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_all_indexer_settings_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::AllIndexerSettingsPrompt) + .await; + + assert!(app.is_loading); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetAllIndexerSettings.into() + ); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_test_indexer_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + app.data.readarr_data.indexers.set_items(vec![Indexer { + id: 3, + ..Indexer::default() + }]); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::TestIndexer) + .await; + + assert!(app.is_loading); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::TestIndexer(3).into() + ); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_test_all_indexers_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::TestAllIndexers) + .await; + + assert!(app.is_loading); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::TestAllIndexers.into() + ); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_system_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::System) + .await; + + assert!(app.is_loading); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetTasks.into()); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetQueuedEvents.into() + ); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetLogs(500).into()); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_dispatch_by_system_updates_block() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + + app + .dispatch_by_readarr_block(&ActiveReadarrBlock::SystemUpdates) + .await; + + assert!(app.is_loading); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetUpdates.into()); + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(app.tick_count, 0); + } #[tokio::test] async fn test_dispatch_by_readarr_block_resets_the_tick_count() { @@ -55,21 +553,93 @@ mod tests { } #[tokio::test] - async fn test_readarr_on_tick_first_render() { + async fn test_check_for_readarr_prompt_action() { + let (tx, mut rx) = mpsc::channel::(500); let mut app = App::test_default(); app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + app.data.readarr_data.prompt_confirm_action = Some(ReadarrEvent::GetStatus); + + app.check_for_readarr_prompt_action().await; + + assert!(!app.data.readarr_data.prompt_confirm); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetStatus.into()); + assert!(app.should_refresh); + assert_eq!(app.data.readarr_data.prompt_confirm_action, None); + } + + #[tokio::test] + async fn test_readarr_refresh_metadata() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + app.is_routing = true; + + app.refresh_readarr_metadata().await; + + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetQualityProfiles.into() + ); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetMetadataProfiles.into() + ); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetTags.into()); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetRootFolders.into() + ); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetDownloads(500).into() + ); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetDiskSpace.into()); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetStatus.into()); + assert!(app.is_loading); + } + + #[tokio::test] + async fn test_readarr_on_tick_first_render() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); app.is_first_render = true; app.readarr_on_tick(ActiveReadarrBlock::Downloads).await; + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetQualityProfiles.into() + ); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetMetadataProfiles.into() + ); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetTags.into()); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetRootFolders.into() + ); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetDownloads(500).into() + ); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetDiskSpace.into()); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetStatus.into()); + assert!(app.is_loading); assert!(!app.data.readarr_data.prompt_confirm); assert!(!app.is_first_render); } #[tokio::test] async fn test_readarr_on_tick_routing() { + let (tx, mut rx) = mpsc::channel::(500); let mut app = App::test_default(); app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); app.is_routing = true; app.should_refresh = true; app.is_first_render = false; @@ -77,14 +647,19 @@ mod tests { app.readarr_on_tick(ActiveReadarrBlock::Downloads).await; + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetDownloads(500).into() + ); assert!(!app.data.readarr_data.prompt_confirm); - assert!(!app.cancellation_token.is_cancelled()); } #[tokio::test] async fn test_readarr_on_tick_routing_while_long_request_is_running_should_cancel_request() { + let (tx, _) = mpsc::channel::(500); let mut app = App::test_default(); app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); app.is_routing = true; app.should_refresh = false; app.is_first_render = false; @@ -97,16 +672,127 @@ mod tests { #[tokio::test] async fn test_readarr_on_tick_should_refresh() { + let (tx, mut rx) = mpsc::channel::(500); let mut app = App::test_default(); app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); app.should_refresh = true; app.is_first_render = false; app.tick_count = 1; app.readarr_on_tick(ActiveReadarrBlock::Downloads).await; + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetDownloads(500).into() + ); assert!(app.should_refresh); assert!(!app.data.readarr_data.prompt_confirm); - assert_eq!(app.tick_count, 0); + } + + #[tokio::test] + async fn test_readarr_on_tick_should_refresh_does_not_cancel_prompt_requests() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + app.is_loading = true; + app.is_routing = true; + app.should_refresh = true; + app.is_first_render = false; + app.tick_count = 1; + + app.readarr_on_tick(ActiveReadarrBlock::Downloads).await; + + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetDownloads(500).into() + ); + assert!(app.is_loading); + assert!(app.should_refresh); + assert!(!app.data.readarr_data.prompt_confirm); + assert!(!app.cancellation_token.is_cancelled()); + } + + #[tokio::test] + async fn test_readarr_on_tick_network_tick_frequency() { + let (tx, mut rx) = mpsc::channel::(500); + let mut app = App::test_default(); + app.data.readarr_data.prompt_confirm = true; + app.network_tx = Some(tx); + app.is_first_render = false; + app.tick_count = 2; + app.tick_until_poll = 2; + + app.readarr_on_tick(ActiveReadarrBlock::Downloads).await; + + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetQualityProfiles.into() + ); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetMetadataProfiles.into() + ); + assert_eq!(rx.recv().await.unwrap(), ReadarrEvent::GetTags.into()); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetRootFolders.into() + ); + assert_eq!( + rx.recv().await.unwrap(), + ReadarrEvent::GetDownloads(500).into() + ); + assert!(app.is_loading); + } + + #[tokio::test] + async fn test_extract_add_new_author_search_query() { + let app = App::test_default_fully_populated(); + + let query = app.extract_add_new_author_search_query().await; + + assert_str_eq!(query, "Test Author"); + } + + #[tokio::test] + #[should_panic(expected = "Add author search is empty")] + async fn test_extract_add_new_author_search_query_panics_when_the_query_is_not_set() { + let app = App::test_default(); + + app.extract_add_new_author_search_query().await; + } + + #[tokio::test] + async fn test_extract_author_id() { + let mut app = App::test_default(); + app.data.readarr_data.authors.set_items(vec![Author { + id: 1, + ..Author::default() + }]); + + assert_eq!(app.extract_author_id().await, 1); + } + + #[tokio::test] + async fn test_extract_book_id() { + let mut app = App::test_default(); + app.data.readarr_data.books.set_items(vec![Book { + id: 2, + ..Book::default() + }]); + + assert_eq!(app.extract_book_id().await, 2); + } + + #[tokio::test] + async fn test_extract_readarr_indexer_id() { + let mut app = App::test_default(); + app.data.readarr_data.indexers.set_items(vec![Indexer { + id: 3, + ..Indexer::default() + }]); + + assert_eq!(app.extract_readarr_indexer_id().await, 3); } }