fix(config): The CLI panics if the servarr you specify has no config defined

This commit is contained in:
2024-11-19 16:29:25 -07:00
parent cc02832512
commit 16bf06426f
6 changed files with 124 additions and 32 deletions
+16 -8
View File
@@ -5,7 +5,7 @@ mod tests {
use tokio::sync::mpsc; use tokio::sync::mpsc;
use crate::app::context_clues::{build_context_clue_string, SERVARR_CONTEXT_CLUES}; use crate::app::context_clues::{build_context_clue_string, SERVARR_CONTEXT_CLUES};
use crate::app::{App, Data, ServarrConfig, DEFAULT_ROUTE}; use crate::app::{App, AppConfig, Data, ServarrConfig, DEFAULT_ROUTE};
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, RadarrData}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, RadarrData};
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData};
use crate::models::{HorizontallyScrollableText, TabRoute}; use crate::models::{HorizontallyScrollableText, TabRoute};
@@ -255,13 +255,21 @@ mod tests {
} }
#[test] #[test]
fn test_servarr_config_default() { fn test_app_config_default() {
let radarr_config = ServarrConfig::default(); let app_config = AppConfig::default();
assert_eq!(radarr_config.host, Some("localhost".to_string())); assert!(app_config.radarr.is_none());
assert_eq!(radarr_config.port, None); assert!(app_config.sonarr.is_none());
assert_eq!(radarr_config.uri, None); }
assert!(radarr_config.api_token.is_empty());
assert_eq!(radarr_config.ssl_cert_path, None); #[test]
fn test_servarr_config_default() {
let servarr_config = ServarrConfig::default();
assert_eq!(servarr_config.host, Some("localhost".to_string()));
assert_eq!(servarr_config.port, None);
assert_eq!(servarr_config.uri, None);
assert!(servarr_config.api_token.is_empty());
assert_eq!(servarr_config.ssl_cert_path, None);
} }
} }
+32 -6
View File
@@ -8,6 +8,7 @@ use tokio::sync::mpsc::Sender;
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use crate::app::context_clues::{build_context_clue_string, SERVARR_CONTEXT_CLUES}; use crate::app::context_clues::{build_context_clue_string, SERVARR_CONTEXT_CLUES};
use crate::cli::Command;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, RadarrData}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, RadarrData};
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData};
use crate::models::{HorizontallyScrollableText, Route, TabRoute, TabState}; use crate::models::{HorizontallyScrollableText, Route, TabRoute, TabState};
@@ -178,20 +179,45 @@ pub struct Data<'a> {
pub sonarr_data: SonarrData, pub sonarr_data: SonarrData,
} }
#[derive(Debug, Deserialize, Serialize, Default)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
pub struct AppConfig { pub struct AppConfig {
pub radarr: ServarrConfig, pub radarr: Option<ServarrConfig>,
pub sonarr: ServarrConfig, pub sonarr: Option<ServarrConfig>,
} }
impl AppConfig { impl AppConfig {
pub fn validate(&self) { pub fn validate(&self) {
self.radarr.validate(); if let Some(radarr_config) = &self.radarr {
radarr_config.validate();
}
if let Some(sonarr_config) = &self.sonarr {
sonarr_config.validate();
}
}
pub fn verify_config_present_for_cli(&self, command: &Command) {
let msg = |servarr: &str| {
log_and_print_error(format!(
"{} configuration missing; Unable to run any {} commands.",
servarr, servarr
))
};
match command {
Command::Radarr(_) if self.radarr.is_none() => {
msg("Radarr");
process::exit(1);
}
Command::Sonarr(_) if self.sonarr.is_none() => {
msg("Sonarr");
process::exit(1);
}
_ => (),
}
} }
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize, Clone)]
#[cfg_attr(test, derive(Clone))]
pub struct ServarrConfig { pub struct ServarrConfig {
pub host: Option<String>, pub host: Option<String>,
pub port: Option<u16>, pub port: Option<u16>,
+12 -2
View File
@@ -106,13 +106,14 @@ async fn main() -> Result<()> {
let app = Arc::new(Mutex::new(App::new( let app = Arc::new(Mutex::new(App::new(
sync_network_tx, sync_network_tx,
config, config.clone(),
cancellation_token.clone(), cancellation_token.clone(),
))); )));
match args.command { match args.command {
Some(command) => match command { Some(command) => match command {
Command::Radarr(_) | Command::Sonarr(_) => { Command::Radarr(_) | Command::Sonarr(_) => {
config.verify_config_present_for_cli(&command);
app.lock().await.cli_mode = true; app.lock().await.cli_mode = true;
let app_nw = Arc::clone(&app); let app_nw = Arc::clone(&app);
let mut network = Network::new(&app_nw, cancellation_token, reqwest_client); let mut network = Network::new(&app_nw, cancellation_token, reqwest_client);
@@ -249,10 +250,19 @@ fn build_network_client(config: &AppConfig) -> Client {
.http2_keep_alive_interval(Duration::from_secs(5)) .http2_keep_alive_interval(Duration::from_secs(5))
.tcp_keepalive(Duration::from_secs(5)); .tcp_keepalive(Duration::from_secs(5));
if let Some(ref cert_path) = config.radarr.ssl_cert_path { if let Some(radarr_config) = &config.radarr {
if let Some(ref cert_path) = &radarr_config.ssl_cert_path {
let cert = create_cert(cert_path, "Radarr"); let cert = create_cert(cert_path, "Radarr");
client_builder = client_builder.add_root_certificate(cert); client_builder = client_builder.add_root_certificate(cert);
} }
}
if let Some(sonarr_config) = &config.sonarr {
if let Some(ref cert_path) = &sonarr_config.ssl_cert_path {
let cert = create_cert(cert_path, "Sonarr");
client_builder = client_builder.add_root_certificate(cert);
}
}
match client_builder.build() { match client_builder.build() {
Ok(client) => client, Ok(client) => client,
+8 -2
View File
@@ -216,8 +216,14 @@ impl<'a, 'b> Network<'a, 'b> {
}, },
default_port, default_port,
) = match network_event.into() { ) = match network_event.into() {
NetworkEvent::Radarr(_) => (&app.config.radarr, 7878), NetworkEvent::Radarr(_) => (
NetworkEvent::Sonarr(_) => (&app.config.sonarr, 8989), &app.config.radarr.as_ref().expect("Radarr config undefined"),
7878,
),
NetworkEvent::Sonarr(_) => (
&app.config.sonarr.as_ref().expect("Sonarr config undefined"),
8989,
),
}; };
let mut uri = if let Some(servarr_uri) = uri { let mut uri = if let Some(servarr_uri) = uri {
format!("{servarr_uri}/api/v3{resource}") format!("{servarr_uri}/api/v3{resource}")
+53 -11
View File
@@ -43,7 +43,7 @@ mod tests {
ssl_cert_path: None, ssl_cert_path: None,
..ServarrConfig::default() ..ServarrConfig::default()
}; };
app.config.radarr = radarr_config; app.config.radarr = Some(radarr_config);
let app_arc = Arc::new(Mutex::new(app)); let app_arc = Arc::new(Mutex::new(app));
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
@@ -397,6 +397,40 @@ mod tests {
async_server.assert_async().await; async_server.assert_async().await;
} }
#[tokio::test]
#[should_panic(expected = "Radarr config undefined")]
async fn test_request_props_from_requires_radarr_config_to_be_present_for_radarr_events() {
let app_arc = Arc::new(Mutex::new(App::default()));
let network = Network::new(&app_arc, CancellationToken::new(), Client::new());
network
.request_props_from(
RadarrEvent::GetMovies,
RequestMethod::Get,
None::<()>,
None,
None,
)
.await;
}
#[tokio::test]
#[should_panic(expected = "Sonarr config undefined")]
async fn test_request_props_from_requires_sonarr_config_to_be_present_for_sonarr_events() {
let app_arc = Arc::new(Mutex::new(App::default()));
let network = Network::new(&app_arc, CancellationToken::new(), Client::new());
network
.request_props_from(
SonarrEvent::ListSeries,
RequestMethod::Get,
None::<()>,
None,
None,
)
.await;
}
#[rstest] #[rstest]
#[case(RadarrEvent::GetMovies, 7878)] #[case(RadarrEvent::GetMovies, 7878)]
#[case(SonarrEvent::ListSeries, 8989)] #[case(SonarrEvent::ListSeries, 8989)]
@@ -408,6 +442,10 @@ mod tests {
let app_arc = Arc::new(Mutex::new(App::default())); let app_arc = Arc::new(Mutex::new(App::default()));
let network = Network::new(&app_arc, CancellationToken::new(), Client::new()); let network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let resource = network_event.resource(); let resource = network_event.resource();
app_arc.lock().await.config = AppConfig {
radarr: Some(ServarrConfig::default()),
sonarr: Some(ServarrConfig::default()),
};
let request_props = network let request_props = network
.request_props_from(network_event, RequestMethod::Get, None::<()>, None, None) .request_props_from(network_event, RequestMethod::Get, None::<()>, None, None)
@@ -440,8 +478,8 @@ mod tests {
}; };
{ {
let mut app = app_arc.lock().await; let mut app = app_arc.lock().await;
app.config.radarr = servarr_config.clone(); app.config.radarr = Some(servarr_config.clone());
app.config.sonarr = servarr_config; app.config.sonarr = Some(servarr_config);
} }
let network = Network::new(&app_arc, CancellationToken::new(), Client::new()); let network = Network::new(&app_arc, CancellationToken::new(), Client::new());
@@ -474,8 +512,8 @@ mod tests {
}; };
{ {
let mut app = app_arc.lock().await; let mut app = app_arc.lock().await;
app.config.radarr = servarr_config.clone(); app.config.radarr = Some(servarr_config.clone());
app.config.sonarr = servarr_config; app.config.sonarr = Some(servarr_config);
} }
let network = Network::new(&app_arc, CancellationToken::new(), Client::new()); let network = Network::new(&app_arc, CancellationToken::new(), Client::new());
@@ -503,6 +541,10 @@ mod tests {
let app_arc = Arc::new(Mutex::new(App::default())); let app_arc = Arc::new(Mutex::new(App::default()));
let network = Network::new(&app_arc, CancellationToken::new(), Client::new()); let network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let resource = network_event.resource(); let resource = network_event.resource();
app_arc.lock().await.config = AppConfig {
radarr: Some(ServarrConfig::default()),
sonarr: Some(ServarrConfig::default()),
};
let request_props = network let request_props = network
.request_props_from( .request_props_from(
@@ -541,8 +583,8 @@ mod tests {
}; };
{ {
let mut app = app_arc.lock().await; let mut app = app_arc.lock().await;
app.config.radarr = servarr_config.clone(); app.config.radarr = Some(servarr_config.clone());
app.config.sonarr = servarr_config; app.config.sonarr = Some(servarr_config);
} }
let network = Network::new(&app_arc, CancellationToken::new(), Client::new()); let network = Network::new(&app_arc, CancellationToken::new(), Client::new());
@@ -581,8 +623,8 @@ mod tests {
}; };
{ {
let mut app = app_arc.lock().await; let mut app = app_arc.lock().await;
app.config.radarr = servarr_config.clone(); app.config.radarr = Some(servarr_config.clone());
app.config.sonarr = servarr_config; app.config.sonarr = Some(servarr_config);
} }
let network = Network::new(&app_arc, CancellationToken::new(), Client::new()); let network = Network::new(&app_arc, CancellationToken::new(), Client::new());
@@ -701,8 +743,8 @@ pub(in crate::network) mod test_utils {
}; };
match network_event.into() { match network_event.into() {
NetworkEvent::Radarr(_) => app.config.radarr = servarr_config, NetworkEvent::Radarr(_) => app.config.radarr = Some(servarr_config),
NetworkEvent::Sonarr(_) => app.config.sonarr = servarr_config, NetworkEvent::Sonarr(_) => app.config.sonarr = Some(servarr_config),
} }
let app_arc = Arc::new(Mutex::new(app)); let app_arc = Arc::new(Mutex::new(app));
+1 -1
View File
@@ -827,7 +827,7 @@ mod test {
api_token: "test1234".to_owned(), api_token: "test1234".to_owned(),
..ServarrConfig::default() ..ServarrConfig::default()
}; };
app.config.radarr = radarr_config; app.config.radarr = Some(radarr_config);
let app_arc = Arc::new(Mutex::new(app)); let app_arc = Arc::new(Mutex::new(app));
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());