From d3947d9e151b9b29420d351ec8e70ea64b21b30d Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Wed, 7 Jan 2026 14:58:32 -0700 Subject: [PATCH] fix: Improved fault tolerance for search result tables and test all indexer results tables --- src/network/radarr_network/indexers/mod.rs | 10 ++++-- .../indexers/radarr_indexers_network_tests.rs | 25 +++++++++++++++ src/network/radarr_network/library/mod.rs | 10 ++++-- .../library/radarr_library_network_tests.rs | 32 +++++++++++++++++-- src/network/sonarr_network/indexers/mod.rs | 10 ++++-- .../indexers/sonarr_indexers_network_tests.rs | 25 +++++++++++++++ .../sonarr_network/library/series/mod.rs | 20 ++++++++---- .../series/sonarr_series_network_tests.rs | 29 +++++++++++++++++ 8 files changed, 145 insertions(+), 16 deletions(-) diff --git a/src/network/radarr_network/indexers/mod.rs b/src/network/radarr_network/indexers/mod.rs index e9c67ee..a2334f5 100644 --- a/src/network/radarr_network/indexers/mod.rs +++ b/src/network/radarr_network/indexers/mod.rs @@ -368,7 +368,7 @@ impl Network<'_, '_> { .await; request_props.ignore_status_code = true; - self + let result = self .handle_request::<(), Vec>(request_props, |test_results, mut app| { let mut test_all_indexer_results = StatefulTable::default(); let indexers = app.data.radarr_data.indexers.items.clone(); @@ -403,6 +403,12 @@ impl Network<'_, '_> { test_all_indexer_results.set_items(modal_test_results); app.data.radarr_data.indexer_test_all_results = Some(test_all_indexer_results); }) - .await + .await; + + if result.is_err() { + self.app.lock().await.data.radarr_data.indexer_test_all_results = Some(StatefulTable::default()); + } + + result } } diff --git a/src/network/radarr_network/indexers/radarr_indexers_network_tests.rs b/src/network/radarr_network/indexers/radarr_indexers_network_tests.rs index 4c0c228..bc545d5 100644 --- a/src/network/radarr_network/indexers/radarr_indexers_network_tests.rs +++ b/src/network/radarr_network/indexers/radarr_indexers_network_tests.rs @@ -925,4 +925,29 @@ mod tests { ); assert_eq!(results, response); } + + #[tokio::test] + async fn test_handle_test_all_radarr_indexers_event_sets_empty_table_on_api_error() { + let (async_server, app, _server) = MockServarrApi::post() + .status(500) + .build_for(RadarrEvent::TestAllIndexers) + .await; + let mut network = test_network(&app); + + let result = network + .handle_radarr_event(RadarrEvent::TestAllIndexers) + .await; + + async_server.assert_async().await; + assert_err!(result); + assert_some!( + &app + .lock() + .await + .data + .radarr_data + .indexer_test_all_results + ); + assert_is_empty!(app.lock().await.data.radarr_data.indexer_test_all_results.as_ref().unwrap()); + } } diff --git a/src/network/radarr_network/library/mod.rs b/src/network/radarr_network/library/mod.rs index 6d08957..c68a63c 100644 --- a/src/network/radarr_network/library/mod.rs +++ b/src/network/radarr_network/library/mod.rs @@ -498,7 +498,7 @@ impl Network<'_, '_> { ) .await; - self + let result = self .handle_request::<(), Vec>(request_props, |movie_vec, mut app| { if movie_vec.is_empty() { app.pop_and_push_navigation_stack(ActiveRadarrBlock::AddMovieEmptySearchResults.into()); @@ -511,7 +511,13 @@ impl Network<'_, '_> { app.data.radarr_data.add_searched_movies = Some(add_searched_movies); } }) - .await + .await; + + if result.is_err() { + self.app.lock().await.data.radarr_data.add_searched_movies = Some(StatefulTable::default()); + } + + result } pub(in crate::network) async fn toggle_movie_monitoring(&mut self, movie_id: i64) -> Result<()> { diff --git a/src/network/radarr_network/library/radarr_library_network_tests.rs b/src/network/radarr_network/library/radarr_library_network_tests.rs index 24288c2..f91f2c9 100644 --- a/src/network/radarr_network/library/radarr_library_network_tests.rs +++ b/src/network/radarr_network/library/radarr_library_network_tests.rs @@ -981,14 +981,13 @@ mod tests { ); async_server.assert_async().await; - assert!( - app_arc + assert_none!( + &app_arc .lock() .await .data .radarr_data .add_searched_movies - .is_none() ); assert_eq!( app_arc.lock().await.get_current_route(), @@ -996,6 +995,33 @@ mod tests { ); } + #[tokio::test] + async fn test_handle_search_new_movie_event_sets_empty_table_on_api_error() { + let (async_server, app_arc, _server) = MockServarrApi::get() + .returns(json!([])) + .status(500) + .query("term=test%20term") + .build_for(RadarrEvent::SearchNewMovie("test term".into())) + .await; + let mut network = test_network(&app_arc); + + let result = network + .handle_radarr_event(RadarrEvent::SearchNewMovie("test term".into())) + .await; + + async_server.assert_async().await; + assert_err!(result); + assert_some!( + &app_arc + .lock() + .await + .data + .radarr_data + .add_searched_movies + ); + assert_is_empty!(app_arc.lock().await.data.radarr_data.add_searched_movies.as_ref().unwrap()); + } + #[tokio::test] async fn test_handle_toggle_movie_monitoring_event() { let mut expected_body: Value = serde_json::from_str(MOVIE_JSON).unwrap(); diff --git a/src/network/sonarr_network/indexers/mod.rs b/src/network/sonarr_network/indexers/mod.rs index 7200d47..576a8c7 100644 --- a/src/network/sonarr_network/indexers/mod.rs +++ b/src/network/sonarr_network/indexers/mod.rs @@ -366,7 +366,7 @@ impl Network<'_, '_> { .await; request_props.ignore_status_code = true; - self + let result = self .handle_request::<(), Vec>(request_props, |test_results, mut app| { let mut test_all_indexer_results = StatefulTable::default(); let indexers = app.data.sonarr_data.indexers.items.clone(); @@ -401,6 +401,12 @@ impl Network<'_, '_> { test_all_indexer_results.set_items(modal_test_results); app.data.sonarr_data.indexer_test_all_results = Some(test_all_indexer_results); }) - .await + .await; + + if result.is_err() { + self.app.lock().await.data.sonarr_data.indexer_test_all_results = Some(StatefulTable::default()); + } + + result } } diff --git a/src/network/sonarr_network/indexers/sonarr_indexers_network_tests.rs b/src/network/sonarr_network/indexers/sonarr_indexers_network_tests.rs index 3bd86bd..f5512cf 100644 --- a/src/network/sonarr_network/indexers/sonarr_indexers_network_tests.rs +++ b/src/network/sonarr_network/indexers/sonarr_indexers_network_tests.rs @@ -884,4 +884,29 @@ mod tests { ); assert_eq!(results, response); } + + #[tokio::test] + async fn test_handle_test_all_sonarr_indexers_event_sets_empty_table_on_api_error() { + let (async_server, app, _server) = MockServarrApi::post() + .status(500) + .build_for(SonarrEvent::TestAllIndexers) + .await; + let mut network = test_network(&app); + app.lock().await.server_tabs.next(); + + let result = network + .handle_sonarr_event(SonarrEvent::TestAllIndexers) + .await; + + async_server.assert_async().await; + assert_err!(result); + let app = app.lock().await; + assert_some!( + &app + .data + .sonarr_data + .indexer_test_all_results + ); + assert_is_empty!(app.data.sonarr_data.indexer_test_all_results.as_ref().unwrap()); + } } diff --git a/src/network/sonarr_network/library/series/mod.rs b/src/network/sonarr_network/library/series/mod.rs index 3c532c8..151cbe6 100644 --- a/src/network/sonarr_network/library/series/mod.rs +++ b/src/network/sonarr_network/library/series/mod.rs @@ -362,20 +362,26 @@ impl Network<'_, '_> { ) .await; - self + let result = self .handle_request::<(), Vec>(request_props, |series_vec, mut app| { if series_vec.is_empty() { app.pop_and_push_navigation_stack(ActiveSonarrBlock::AddSeriesEmptySearchResults.into()); - } else if let Some(add_searched_seriess) = app.data.sonarr_data.add_searched_series.as_mut() + } else if let Some(add_searched_series) = app.data.sonarr_data.add_searched_series.as_mut() { - add_searched_seriess.set_items(series_vec); + add_searched_series.set_items(series_vec); } else { - let mut add_searched_seriess = StatefulTable::default(); - add_searched_seriess.set_items(series_vec); - app.data.sonarr_data.add_searched_series = Some(add_searched_seriess); + let mut add_searched_series = StatefulTable::default(); + add_searched_series.set_items(series_vec); + app.data.sonarr_data.add_searched_series = Some(add_searched_series); } }) - .await + .await; + + if result.is_err() { + self.app.lock().await.data.sonarr_data.add_searched_series = Some(StatefulTable::default()); + } + + result } pub(in crate::network::sonarr_network) async fn trigger_automatic_series_search( diff --git a/src/network/sonarr_network/library/series/sonarr_series_network_tests.rs b/src/network/sonarr_network/library/series/sonarr_series_network_tests.rs index fabd110..d4b83f3 100644 --- a/src/network/sonarr_network/library/series/sonarr_series_network_tests.rs +++ b/src/network/sonarr_network/library/series/sonarr_series_network_tests.rs @@ -943,6 +943,35 @@ mod tests { ); } + #[tokio::test] + async fn test_handle_search_new_series_event_sets_empty_table_on_api_error() { + let (async_server, app, _server) = MockServarrApi::get() + .status(500) + .query("term=test%20term") + .build_for(SonarrEvent::SearchNewSeries("test term".into())) + .await; + app.lock().await.server_tabs.next(); + let mut network = test_network(&app); + + let result = + network + .handle_sonarr_event(SonarrEvent::SearchNewSeries("test term".into())) + .await; + + async_server.assert_async().await; + assert_err!(result); + let app = app.lock().await; + assert_some!( + &app + .data + .sonarr_data + .add_searched_series + ); + assert_is_empty!( + app.data.sonarr_data.add_searched_series.as_ref().unwrap() + ); + } + #[tokio::test] async fn test_handle_trigger_automatic_series_search_event() { let (async_server, app, _server) = MockServarrApi::post()