feat(readarr): add the Readarr health check network call

Inhabit ReadarrEvent with its first variant, HealthCheck, mapped to
GET /health, and add get_readarr_healthcheck alongside the equivalent
Lidarr, Radarr, and Sonarr fetchers. The call is internal only and has
no CLI surface, matching the other three servarrs; it exists so that an
unreachable instance surfaces an error banner on tick.

The healthcheck fetcher lives in readarr_network/mod.rs rather than a
submodule, so its tests live in readarr_network_tests.rs next to the
resource() and NetworkEvent conversion tests, mirroring Lidarr.

MockServarrApi::build_for matched NetworkEvent by value with no Radarr
fallback arm. It compiled only while ReadarrEvent was uninhabited and
no value could reach it; the first variant makes the match non
exhaustive, so it now assigns the config to the Readarr server tab.
This commit is contained in:
Dark-Alex-17 committed 2026-08-20 15:44:07 -06:00
1 parent 29f043f5c7
commit cd341c3d71
3 files changed
+87 -4

No files matched your search

+1
View File
@@ -992,6 +992,7 @@ pub(in crate::network) mod test_utils {
NetworkEvent::Radarr(_) => app.server_tabs.tabs[0].config = Some(servarr_config),
NetworkEvent::Sonarr(_) => app.server_tabs.tabs[1].config = Some(servarr_config),
NetworkEvent::Lidarr(_) => app.server_tabs.tabs[2].config = Some(servarr_config),
NetworkEvent::Readarr(_) => app.server_tabs.tabs[3].config = Some(servarr_config),
}
let app_arc = Arc::new(Mutex::new(app));
+33 -4
View File
@@ -1,15 +1,24 @@
use anyhow::Result;
use log::info;
use super::{NetworkEvent, NetworkResource};
use crate::models::readarr_models::ReadarrSerdeable;
use crate::network::Network;
use crate::network::{Network, RequestMethod};
#[cfg(test)]
#[path = "readarr_network_tests.rs"]
mod readarr_network_tests;
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum ReadarrEvent {}
pub enum ReadarrEvent {
HealthCheck,
}
impl NetworkResource for ReadarrEvent {
fn resource(&self) -> &'static str {
match *self {}
match &self {
ReadarrEvent::HealthCheck => "/health",
}
}
}
@@ -24,6 +33,26 @@ impl Network<'_, '_> {
&mut self,
readarr_event: ReadarrEvent,
) -> Result<ReadarrSerdeable> {
match readarr_event {}
match readarr_event {
ReadarrEvent::HealthCheck => self
.get_readarr_healthcheck()
.await
.map(ReadarrSerdeable::from),
}
}
pub(in crate::network::readarr_network) async fn get_readarr_healthcheck(
&mut self,
) -> Result<()> {
info!("Performing Readarr health check");
let event = ReadarrEvent::HealthCheck;
let request_props = self
.request_props_from(event, RequestMethod::Get, None::<()>, None, None)
.await;
self
.handle_request::<(), ()>(request_props, |_, _| ())
.await
}
}
@@ -0,0 +1,53 @@
#[cfg(test)]
mod tests {
use crate::network::network_tests::test_utils::{MockServarrApi, test_network};
use crate::network::{NetworkEvent, NetworkResource, readarr_network::ReadarrEvent};
use pretty_assertions::{assert_eq, assert_str_eq};
use rstest::rstest;
#[rstest]
#[case(ReadarrEvent::HealthCheck, "/health")]
fn test_resource(#[case] event: ReadarrEvent, #[case] expected_uri: &str) {
assert_str_eq!(event.resource(), expected_uri);
}
#[test]
fn test_from_readarr_event() {
assert_eq!(
NetworkEvent::Readarr(ReadarrEvent::HealthCheck),
NetworkEvent::from(ReadarrEvent::HealthCheck)
);
}
#[tokio::test]
async fn test_handle_get_readarr_healthcheck_event() {
let (mock, app, _server) = MockServarrApi::get()
.build_for(ReadarrEvent::HealthCheck)
.await;
app.lock().await.server_tabs.set_index(3);
let mut network = test_network(&app);
let _ = network
.handle_readarr_event(ReadarrEvent::HealthCheck)
.await;
mock.assert_async().await;
}
#[tokio::test]
async fn test_handle_get_readarr_healthcheck_event_failure() {
let (mock, app, _server) = MockServarrApi::get()
.status(500)
.build_for(ReadarrEvent::HealthCheck)
.await;
app.lock().await.server_tabs.set_index(3);
let mut network = test_network(&app);
let result = network
.handle_readarr_event(ReadarrEvent::HealthCheck)
.await;
mock.assert_async().await;
assert_err!(result);
}
}