feat: Added Lidarr CLI support for fetching the host config and the security config

This commit is contained in:
2026-01-06 11:00:19 -07:00
parent 4e13d5d34d
commit 96308afeee
10 changed files with 271 additions and 34 deletions
@@ -20,6 +20,13 @@ mod tests {
assert_str_eq!(event.resource(), "/artist");
}
#[rstest]
fn test_resource_config(
#[values(LidarrEvent::GetHostConfig, LidarrEvent::GetSecurityConfig)] event: LidarrEvent,
) {
assert_str_eq!(event.resource(), "/config/host");
}
#[rstest]
#[case(LidarrEvent::GetDiskSpace, "/diskspace")]
#[case(LidarrEvent::GetDownloads(500), "/queue")]
@@ -41,6 +48,19 @@ mod tests {
);
}
#[tokio::test]
async fn test_handle_get_lidarr_healthcheck_event() {
let (mock, app, _server) = MockServarrApi::get()
.build_for(LidarrEvent::HealthCheck)
.await;
app.lock().await.server_tabs.set_index(2);
let mut network = test_network(&app);
let _ = network.handle_lidarr_event(LidarrEvent::HealthCheck).await;
mock.assert_async().await;
}
#[tokio::test]
async fn test_handle_get_metadata_profiles_event() {
let metadata_profiles_json = json!([{
+24
View File
@@ -21,9 +21,11 @@ pub enum LidarrEvent {
GetArtistDetails(i64),
GetDiskSpace,
GetDownloads(u64),
GetHostConfig,
GetMetadataProfiles,
GetQualityProfiles,
GetRootFolders,
GetSecurityConfig,
GetStatus,
GetTags,
HealthCheck,
@@ -40,6 +42,7 @@ impl NetworkResource for LidarrEvent {
| LidarrEvent::ToggleArtistMonitoring(_) => "/artist",
LidarrEvent::GetDiskSpace => "/diskspace",
LidarrEvent::GetDownloads(_) => "/queue",
LidarrEvent::GetHostConfig | LidarrEvent::GetSecurityConfig => "/config/host",
LidarrEvent::GetMetadataProfiles => "/metadataprofile",
LidarrEvent::GetQualityProfiles => "/qualityprofile",
LidarrEvent::GetRootFolders => "/rootfolder",
@@ -74,6 +77,10 @@ impl Network<'_, '_> {
.get_lidarr_downloads(count)
.await
.map(LidarrSerdeable::from),
LidarrEvent::GetHostConfig => self
.get_lidarr_host_config()
.await
.map(LidarrSerdeable::from),
LidarrEvent::GetMetadataProfiles => self
.get_lidarr_metadata_profiles()
.await
@@ -86,6 +93,10 @@ impl Network<'_, '_> {
.get_lidarr_root_folders()
.await
.map(LidarrSerdeable::from),
LidarrEvent::GetSecurityConfig => self
.get_lidarr_security_config()
.await
.map(LidarrSerdeable::from),
LidarrEvent::GetStatus => self.get_lidarr_status().await.map(LidarrSerdeable::from),
LidarrEvent::GetTags => self.get_lidarr_tags().await.map(LidarrSerdeable::from),
LidarrEvent::HealthCheck => self
@@ -100,6 +111,19 @@ impl Network<'_, '_> {
}
}
pub(in crate::network::lidarr_network) async fn get_lidarr_healthcheck(&mut self) -> Result<()> {
info!("Performing Lidarr health check");
let event = LidarrEvent::HealthCheck;
let request_props = self
.request_props_from(event, RequestMethod::Get, None::<()>, None, None)
.await;
self
.handle_request::<(), ()>(request_props, |_, _| ())
.await
}
async fn get_lidarr_metadata_profiles(&mut self) -> Result<Vec<MetadataProfile>> {
info!("Fetching Lidarr metadata profiles");
let event = LidarrEvent::GetMetadataProfiles;
@@ -1,31 +1,24 @@
#[cfg(test)]
mod tests {
use crate::models::lidarr_models::{LidarrSerdeable, SystemStatus};
use crate::models::servarr_models::DiskSpace;
use crate::models::servarr_models::{DiskSpace, HostConfig, SecurityConfig};
use crate::network::lidarr_network::LidarrEvent;
use crate::network::network_tests::test_utils::{MockServarrApi, test_network};
use pretty_assertions::assert_eq;
use serde_json::json;
#[tokio::test]
async fn test_handle_get_lidarr_healthcheck_event() {
let (mock, app, _server) = MockServarrApi::get()
.build_for(LidarrEvent::HealthCheck)
.await;
app.lock().await.server_tabs.set_index(2);
let mut network = test_network(&app);
let _ = network.handle_lidarr_event(LidarrEvent::HealthCheck).await;
mock.assert_async().await;
}
#[tokio::test]
async fn test_handle_get_diskspace_event() {
let diskspace_json = json!([{
"freeSpace": 50000000000i64,
"totalSpace": 100000000000i64
}]);
let diskspace_json = json!([
{
"freeSpace": 1111,
"totalSpace": 2222,
},
{
"freeSpace": 3333,
"totalSpace": 4444
}
]);
let response: Vec<DiskSpace> = serde_json::from_value(diskspace_json.clone()).unwrap();
let (mock, app, _server) = MockServarrApi::get()
.returns(diskspace_json)
@@ -46,6 +39,71 @@ mod tests {
assert!(!app.lock().await.data.lidarr_data.disk_space_vec.is_empty());
}
#[tokio::test]
async fn test_handle_get_host_config_event() {
let host_config_json = json!({
"bindAddress": "*",
"port": 8686,
"urlBase": "some.test.site/lidarr",
"instanceName": "Lidarr",
"applicationUrl": "https://some.test.site:8686/lidarr",
"enableSsl": true,
"sslPort": 6868,
"sslCertPath": "/app/lidarr.pfx",
"sslCertPassword": "test"
});
let response: HostConfig = serde_json::from_value(host_config_json.clone()).unwrap();
let (mock, app, _server) = MockServarrApi::get()
.returns(host_config_json)
.build_for(LidarrEvent::GetHostConfig)
.await;
app.lock().await.server_tabs.set_index(2);
let mut network = test_network(&app);
let result = network
.handle_lidarr_event(LidarrEvent::GetHostConfig)
.await;
mock.assert_async().await;
let LidarrSerdeable::HostConfig(host_config) = result.unwrap() else {
panic!("Expected HostConfig");
};
assert_eq!(host_config, response);
}
#[tokio::test]
async fn test_handle_get_security_config_event() {
let security_config_json = json!({
"authenticationMethod": "forms",
"authenticationRequired": "disabledForLocalAddresses",
"username": "test",
"password": "some password",
"apiKey": "someApiKey12345",
"certificateValidation": "disabledForLocalAddresses"
});
let response: SecurityConfig = serde_json::from_value(security_config_json.clone()).unwrap();
let (mock, app, _server) = MockServarrApi::get()
.returns(security_config_json)
.build_for(LidarrEvent::GetSecurityConfig)
.await;
app.lock().await.server_tabs.set_index(2);
let mut network = test_network(&app);
let result = network
.handle_lidarr_event(LidarrEvent::GetSecurityConfig)
.await;
mock.assert_async().await;
let LidarrSerdeable::SecurityConfig(security_config) = result.unwrap() else {
panic!("Expected SecurityConfig");
};
assert_eq!(security_config, response);
}
#[tokio::test]
async fn test_handle_get_status_event() {
let status_json = json!({
+22 -5
View File
@@ -2,7 +2,7 @@ use anyhow::Result;
use log::info;
use crate::models::lidarr_models::SystemStatus;
use crate::models::servarr_models::DiskSpace;
use crate::models::servarr_models::{DiskSpace, HostConfig, SecurityConfig};
use crate::network::lidarr_network::LidarrEvent;
use crate::network::{Network, RequestMethod};
@@ -11,16 +11,33 @@ use crate::network::{Network, RequestMethod};
mod lidarr_system_network_tests;
impl Network<'_, '_> {
pub(in crate::network::lidarr_network) async fn get_lidarr_healthcheck(&mut self) -> Result<()> {
info!("Performing Lidarr health check");
let event = LidarrEvent::HealthCheck;
pub(in crate::network::lidarr_network) async fn get_lidarr_host_config(
&mut self,
) -> Result<HostConfig> {
info!("Fetching Lidarr host config");
let event = LidarrEvent::GetHostConfig;
let request_props = self
.request_props_from(event, RequestMethod::Get, None::<()>, None, None)
.await;
self
.handle_request::<(), ()>(request_props, |_, _| ())
.handle_request::<(), HostConfig>(request_props, |_, _| ())
.await
}
pub(in crate::network::lidarr_network) async fn get_lidarr_security_config(
&mut self,
) -> Result<SecurityConfig> {
info!("Fetching Lidarr security config");
let event = LidarrEvent::GetSecurityConfig;
let request_props = self
.request_props_from(event, RequestMethod::Get, None::<()>, None, None)
.await;
self
.handle_request::<(), SecurityConfig>(request_props, |_, _| ())
.await
}
+13 -6
View File
@@ -18,6 +18,7 @@ mod tests {
use crate::app::{App, AppConfig, ServarrConfig};
use crate::models::HorizontallyScrollableText;
use crate::network::NetworkResource;
use crate::network::lidarr_network::LidarrEvent;
use crate::network::network_tests::test_utils::test_network;
use crate::network::radarr_network::RadarrEvent;
use crate::network::sonarr_network::SonarrEvent;
@@ -421,11 +422,13 @@ mod tests {
}
#[rstest]
#[case(RadarrEvent::GetMovies, 7878)]
#[case(SonarrEvent::ListSeries, 8989)]
#[case(RadarrEvent::GetMovies, "v3", 7878)]
#[case(SonarrEvent::ListSeries, "v3", 8989)]
#[case(LidarrEvent::ListArtists, "v1", 8686)]
#[tokio::test]
async fn test_request_props_from_default_config(
#[case] network_event: impl Into<NetworkEvent> + NetworkResource,
#[case] api_version: &str,
#[case] default_port: u16,
) {
let app_arc = Arc::new(Mutex::new(App::test_default()));
@@ -435,6 +438,7 @@ mod tests {
let mut app = app_arc.lock().await;
app.server_tabs.tabs[0].config = Some(ServarrConfig::default());
app.server_tabs.tabs[1].config = Some(ServarrConfig::default());
app.server_tabs.tabs[2].config = Some(ServarrConfig::default());
}
let request_props = network
@@ -443,7 +447,7 @@ mod tests {
assert_str_eq!(
request_props.uri,
format!("http://localhost:{default_port}/api/v3{resource}")
format!("http://localhost:{default_port}/api/{api_version}{resource}")
);
assert_eq!(request_props.method, RequestMethod::Get);
assert_eq!(request_props.body, None);
@@ -564,11 +568,13 @@ mod tests {
}
#[rstest]
#[case(RadarrEvent::GetMovies, 7878)]
#[case(SonarrEvent::ListSeries, 8989)]
#[case(RadarrEvent::GetMovies, "v3", 7878)]
#[case(SonarrEvent::ListSeries, "v3", 8989)]
#[case(LidarrEvent::ListArtists, "v1", 8686)]
#[tokio::test]
async fn test_request_props_from_default_config_with_path_and_query_params(
#[case] network_event: impl Into<NetworkEvent> + NetworkResource,
#[case] api_version: &str,
#[case] default_port: u16,
) {
let app_arc = Arc::new(Mutex::new(App::test_default()));
@@ -578,6 +584,7 @@ mod tests {
let mut app = app_arc.lock().await;
app.server_tabs.tabs[0].config = Some(ServarrConfig::default());
app.server_tabs.tabs[1].config = Some(ServarrConfig::default());
app.server_tabs.tabs[2].config = Some(ServarrConfig::default());
}
let request_props = network
@@ -592,7 +599,7 @@ mod tests {
assert_str_eq!(
request_props.uri,
format!("http://localhost:{default_port}/api/v3{resource}/test?id=1")
format!("http://localhost:{default_port}/api/{api_version}{resource}/test?id=1")
);
assert_eq!(request_props.method, RequestMethod::Get);
assert_eq!(request_props.body, None);