diff --git a/src/cli/readarr/list_command_handler.rs b/src/cli/readarr/list_command_handler.rs index 85909d48..1eac67c9 100644 --- a/src/cli/readarr/list_command_handler.rs +++ b/src/cli/readarr/list_command_handler.rs @@ -29,6 +29,8 @@ pub enum ReadarrListCommand { )] output_in_log_format: bool, }, + #[command(about = "List all Readarr tasks")] + Tasks, #[command(about = "List all Readarr updates")] Updates, } @@ -84,6 +86,13 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, ReadarrListCommand> for ReadarrListComman serde_json::to_string_pretty(&logs)? } } + ReadarrListCommand::Tasks => { + let resp = self + .network + .handle_network_event(ReadarrEvent::GetTasks.into()) + .await?; + serde_json::to_string_pretty(&resp)? + } ReadarrListCommand::Updates => { let resp = self .network diff --git a/src/cli/readarr/list_command_handler_tests.rs b/src/cli/readarr/list_command_handler_tests.rs index 3a9db21e..b0e7494b 100644 --- a/src/cli/readarr/list_command_handler_tests.rs +++ b/src/cli/readarr/list_command_handler_tests.rs @@ -25,7 +25,7 @@ mod tests { #[rstest] fn test_list_commands_have_no_arg_requirements( - #[values("disk-space", "updates")] subcommand: &str, + #[values("disk-space", "tasks", "updates")] subcommand: &str, ) { let result = Cli::command().try_get_matches_from(["managarr", "readarr", "list", subcommand]); @@ -161,6 +161,28 @@ mod tests { assert_str_eq!(result.unwrap(), "[\n \"readarr log line\"\n]"); } + #[tokio::test] + async fn test_handle_list_tasks_command() { + let mut mock_network = MockNetworkTrait::new(); + mock_network + .expect_handle_network_event() + .with(eq::(ReadarrEvent::GetTasks.into())) + .times(1) + .returning(|_| { + Ok(Serdeable::Readarr(ReadarrSerdeable::Value( + json!({"testResponse": "response"}), + ))) + }); + let app_arc = Arc::new(Mutex::new(App::test_default())); + let list_tasks_command = ReadarrListCommand::Tasks; + + let result = ReadarrListCommandHandler::with(&app_arc, list_tasks_command, &mut mock_network) + .handle() + .await; + + assert_ok!(&result); + } + #[tokio::test] async fn test_handle_list_updates_command() { let mut mock_network = MockNetworkTrait::new(); diff --git a/src/network/readarr_network/mod.rs b/src/network/readarr_network/mod.rs index 91d407fc..6e30e081 100644 --- a/src/network/readarr_network/mod.rs +++ b/src/network/readarr_network/mod.rs @@ -18,6 +18,7 @@ pub enum ReadarrEvent { GetLogs(u64), GetSecurityConfig, GetStatus, + GetTasks, GetUpdates, HealthCheck, } @@ -30,6 +31,7 @@ impl NetworkResource for ReadarrEvent { ReadarrEvent::HealthCheck => "/health", ReadarrEvent::GetLogs(_) => "/log", ReadarrEvent::GetStatus => "/system/status", + ReadarrEvent::GetTasks => "/system/task", ReadarrEvent::GetUpdates => "/update", } } @@ -64,6 +66,7 @@ impl Network<'_, '_> { .await .map(ReadarrSerdeable::from), ReadarrEvent::GetStatus => self.get_readarr_status().await.map(ReadarrSerdeable::from), + ReadarrEvent::GetTasks => self.get_readarr_tasks().await.map(ReadarrSerdeable::from), ReadarrEvent::GetUpdates => self.get_readarr_updates().await.map(ReadarrSerdeable::from), ReadarrEvent::HealthCheck => self .get_readarr_healthcheck() diff --git a/src/network/readarr_network/readarr_network_tests.rs b/src/network/readarr_network/readarr_network_tests.rs index 4b1cf495..96ecf18d 100644 --- a/src/network/readarr_network/readarr_network_tests.rs +++ b/src/network/readarr_network/readarr_network_tests.rs @@ -12,6 +12,7 @@ mod tests { #[case(ReadarrEvent::HealthCheck, "/health")] #[case(ReadarrEvent::GetLogs(500), "/log")] #[case(ReadarrEvent::GetStatus, "/system/status")] + #[case(ReadarrEvent::GetTasks, "/system/task")] #[case(ReadarrEvent::GetUpdates, "/update")] fn test_resource(#[case] event: ReadarrEvent, #[case] expected_uri: &str) { assert_str_eq!(event.resource(), expected_uri); diff --git a/src/network/readarr_network/system/mod.rs b/src/network/readarr_network/system/mod.rs index 4b960ec6..4f28dcb2 100644 --- a/src/network/readarr_network/system/mod.rs +++ b/src/network/readarr_network/system/mod.rs @@ -1,3 +1,4 @@ +use crate::models::readarr_models::ReadarrTask; use crate::models::servarr_models::{ DiskSpace, HostConfig, LogResponse, SecurityConfig, SystemStatus, Update, }; @@ -134,6 +135,23 @@ impl Network<'_, '_> { .await } + pub(in crate::network::readarr_network) async fn get_readarr_tasks( + &mut self, + ) -> Result> { + info!("Fetching Readarr tasks"); + let event = ReadarrEvent::GetTasks; + + let request_props = self + .request_props_from(event, RequestMethod::Get, None::<()>, None, None) + .await; + + self + .handle_request::<(), Vec>(request_props, |tasks_vec, mut app| { + app.data.readarr_data.tasks.set_items(tasks_vec); + }) + .await + } + pub(in crate::network::readarr_network) async fn get_readarr_updates( &mut self, ) -> Result> { diff --git a/src/network/readarr_network/system/readarr_system_network_tests.rs b/src/network/readarr_network/system/readarr_system_network_tests.rs index a8b4ed60..5a50a7c2 100644 --- a/src/network/readarr_network/system/readarr_system_network_tests.rs +++ b/src/network/readarr_network/system/readarr_system_network_tests.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod tests { use crate::models::HorizontallyScrollableText; - use crate::models::readarr_models::ReadarrSerdeable; + use crate::models::readarr_models::{ReadarrSerdeable, ReadarrTask, ReadarrTaskName}; use crate::models::servarr_models::{ AuthenticationMethod, AuthenticationRequired, CertificateValidation, DiskSpace, HostConfig, LogResponse, SecurityConfig, SystemStatus, Update, @@ -337,6 +337,83 @@ mod tests { assert_is_empty!(app.lock().await.data.readarr_data.version); } + #[tokio::test] + async fn test_handle_get_readarr_tasks_event() { + let tasks_json = json!([{ + "name": "Application Update Check", + "taskName": "ApplicationUpdateCheck", + "interval": 360, + "lastExecution": "2023-05-20T21:29:16Z", + "lastDuration": "00:00:00.2293467", + "nextExecution": "2023-05-20T21:29:16Z", + }, + { + "name": "Refresh Author", + "taskName": "RefreshAuthor", + "interval": 10080, + "lastExecution": "2023-05-20T21:29:16Z", + "lastDuration": "00:00:03.7211204", + "nextExecution": "2023-05-20T21:29:16Z", + }]); + let response: Vec = serde_json::from_value(tasks_json.clone()).unwrap(); + let timestamp = DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T21:29:16Z").unwrap()); + let expected_tasks = vec![ + ReadarrTask { + name: "Application Update Check".to_owned(), + task_name: ReadarrTaskName::ApplicationUpdateCheck, + interval: 360, + last_execution: timestamp, + last_duration: "00:00:00.2293467".to_owned(), + next_execution: timestamp, + }, + ReadarrTask { + name: "Refresh Author".to_owned(), + task_name: ReadarrTaskName::RefreshAuthor, + interval: 10080, + last_execution: timestamp, + last_duration: "00:00:03.7211204".to_owned(), + next_execution: timestamp, + }, + ]; + let (mock, app, _server) = MockServarrApi::get() + .returns(tasks_json) + .build_for(ReadarrEvent::GetTasks) + .await; + app.lock().await.server_tabs.set_index(3); + let mut network = test_network(&app); + + let result = network.handle_readarr_event(ReadarrEvent::GetTasks).await; + + mock.assert_async().await; + + let ReadarrSerdeable::Tasks(tasks) = result.unwrap() else { + panic!("Expected Tasks") + }; + + assert_eq!(tasks, response); + assert_eq!( + app.lock().await.data.readarr_data.tasks.items, + expected_tasks + ); + } + + #[tokio::test] + async fn test_handle_get_readarr_tasks_event_failure() { + let (mock, app, _server) = MockServarrApi::get() + .returns(json!({})) + .status(500) + .build_for(ReadarrEvent::GetTasks) + .await; + app.lock().await.server_tabs.set_index(3); + let mut network = test_network(&app); + + let result = network.handle_readarr_event(ReadarrEvent::GetTasks).await; + + mock.assert_async().await; + assert_err!(result); + assert_is_empty!(app.lock().await.data.readarr_data.tasks); + } + #[tokio::test] async fn test_handle_get_readarr_updates_event() { let updates_json = json!([{