feat(network): Added the ability to test an individual indexer in Sonarr
This commit is contained in:
@@ -26,6 +26,7 @@ pub struct SonarrData {
|
|||||||
pub history: StatefulTable<SonarrHistoryItem>,
|
pub history: StatefulTable<SonarrHistoryItem>,
|
||||||
pub indexers: StatefulTable<Indexer>,
|
pub indexers: StatefulTable<Indexer>,
|
||||||
pub indexer_settings: Option<IndexerSettings>,
|
pub indexer_settings: Option<IndexerSettings>,
|
||||||
|
pub indexer_test_error: Option<String>,
|
||||||
pub logs: StatefulList<HorizontallyScrollableText>,
|
pub logs: StatefulList<HorizontallyScrollableText>,
|
||||||
pub quality_profile_map: BiMap<i64, String>,
|
pub quality_profile_map: BiMap<i64, String>,
|
||||||
pub queued_events: StatefulTable<QueueEvent>,
|
pub queued_events: StatefulTable<QueueEvent>,
|
||||||
@@ -51,6 +52,7 @@ impl Default for SonarrData {
|
|||||||
history: StatefulTable::default(),
|
history: StatefulTable::default(),
|
||||||
indexers: StatefulTable::default(),
|
indexers: StatefulTable::default(),
|
||||||
indexer_settings: None,
|
indexer_settings: None,
|
||||||
|
indexer_test_error: None,
|
||||||
logs: StatefulList::default(),
|
logs: StatefulList::default(),
|
||||||
quality_profile_map: BiMap::new(),
|
quality_profile_map: BiMap::new(),
|
||||||
queued_events: StatefulTable::default(),
|
queued_events: StatefulTable::default(),
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ mod tests {
|
|||||||
assert!(sonarr_data.history.is_empty());
|
assert!(sonarr_data.history.is_empty());
|
||||||
assert!(sonarr_data.indexers.is_empty());
|
assert!(sonarr_data.indexers.is_empty());
|
||||||
assert!(sonarr_data.indexer_settings.is_none());
|
assert!(sonarr_data.indexer_settings.is_none());
|
||||||
|
assert!(sonarr_data.indexer_test_error.is_none());
|
||||||
assert!(sonarr_data.logs.is_empty());
|
assert!(sonarr_data.logs.is_empty());
|
||||||
assert!(sonarr_data.quality_profile_map.is_empty());
|
assert!(sonarr_data.quality_profile_map.is_empty());
|
||||||
assert!(sonarr_data.queued_events.is_empty());
|
assert!(sonarr_data.queued_events.is_empty());
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.await
|
.await
|
||||||
.map(RadarrSerdeable::from),
|
.map(RadarrSerdeable::from),
|
||||||
RadarrEvent::TestIndexer(indexer_id) => self
|
RadarrEvent::TestIndexer(indexer_id) => self
|
||||||
.test_indexer(indexer_id)
|
.test_radarr_indexer(indexer_id)
|
||||||
.await
|
.await
|
||||||
.map(RadarrSerdeable::from),
|
.map(RadarrSerdeable::from),
|
||||||
RadarrEvent::TestAllIndexers => self.test_all_indexers().await.map(RadarrSerdeable::from),
|
RadarrEvent::TestAllIndexers => self.test_all_indexers().await.map(RadarrSerdeable::from),
|
||||||
@@ -2036,7 +2036,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn test_indexer(&mut self, indexer_id: Option<i64>) -> Result<Value> {
|
async fn test_radarr_indexer(&mut self, indexer_id: Option<i64>) -> Result<Value> {
|
||||||
let detail_event = RadarrEvent::GetIndexers;
|
let detail_event = RadarrEvent::GetIndexers;
|
||||||
let event = RadarrEvent::TestIndexer(None);
|
let event = RadarrEvent::TestIndexer(None);
|
||||||
let id = if let Some(i_id) = indexer_id {
|
let id = if let Some(i_id) = indexer_id {
|
||||||
|
|||||||
@@ -862,7 +862,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_test_indexer_event_error() {
|
async fn test_handle_test_radarr_indexer_event_error() {
|
||||||
let indexer_details_json = json!({
|
let indexer_details_json = json!({
|
||||||
"enableRss": true,
|
"enableRss": true,
|
||||||
"enableAutomaticSearch": true,
|
"enableAutomaticSearch": true,
|
||||||
@@ -938,7 +938,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_test_indexer_event_success() {
|
async fn test_handle_test_radarr_indexer_event_success() {
|
||||||
let indexer_details_json = json!({
|
let indexer_details_json = json!({
|
||||||
"enableRss": true,
|
"enableRss": true,
|
||||||
"enableAutomaticSearch": true,
|
"enableAutomaticSearch": true,
|
||||||
@@ -1007,7 +1007,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_test_indexer_event_success_uses_provided_id() {
|
async fn test_handle_test_radarr_indexer_event_success_uses_provided_id() {
|
||||||
let indexer_details_json = json!({
|
let indexer_details_json = json!({
|
||||||
"enableRss": true,
|
"enableRss": true,
|
||||||
"enableAutomaticSearch": true,
|
"enableAutomaticSearch": true,
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ pub enum SonarrEvent {
|
|||||||
ListSeries,
|
ListSeries,
|
||||||
MarkHistoryItemAsFailed(i64),
|
MarkHistoryItemAsFailed(i64),
|
||||||
StartTask(Option<SonarrTaskName>),
|
StartTask(Option<SonarrTaskName>),
|
||||||
|
TestIndexer(Option<i64>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkResource for SonarrEvent {
|
impl NetworkResource for SonarrEvent {
|
||||||
@@ -98,6 +99,7 @@ impl NetworkResource for SonarrEvent {
|
|||||||
SonarrEvent::ListSeries | SonarrEvent::GetSeriesDetails(_) => "/series",
|
SonarrEvent::ListSeries | SonarrEvent::GetSeriesDetails(_) => "/series",
|
||||||
SonarrEvent::MarkHistoryItemAsFailed(_) => "/history/failed",
|
SonarrEvent::MarkHistoryItemAsFailed(_) => "/history/failed",
|
||||||
SonarrEvent::StartTask(_) => "/command",
|
SonarrEvent::StartTask(_) => "/command",
|
||||||
|
SonarrEvent::TestIndexer(_) => "/indexer/test",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,6 +226,10 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.start_sonarr_task(task_name)
|
.start_sonarr_task(task_name)
|
||||||
.await
|
.await
|
||||||
.map(SonarrSerdeable::from),
|
.map(SonarrSerdeable::from),
|
||||||
|
SonarrEvent::TestIndexer(indexer_id) => self
|
||||||
|
.test_sonarr_indexer(indexer_id)
|
||||||
|
.await
|
||||||
|
.map(SonarrSerdeable::from),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1311,6 +1317,65 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn test_sonarr_indexer(&mut self, indexer_id: Option<i64>) -> Result<Value> {
|
||||||
|
let detail_event = SonarrEvent::GetIndexers;
|
||||||
|
let event = SonarrEvent::TestIndexer(None);
|
||||||
|
let id = if let Some(i_id) = indexer_id {
|
||||||
|
i_id
|
||||||
|
} else {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.current_selection()
|
||||||
|
.id
|
||||||
|
};
|
||||||
|
info!("Testing Sonarr indexer with ID: {id}");
|
||||||
|
|
||||||
|
info!("Fetching indexer details for indexer with ID: {id}");
|
||||||
|
|
||||||
|
let request_props = self
|
||||||
|
.request_props_from(
|
||||||
|
detail_event,
|
||||||
|
RequestMethod::Get,
|
||||||
|
None::<()>,
|
||||||
|
Some(format!("/{id}")),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let mut test_body: Value = Value::default();
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<(), Value>(request_props, |detailed_indexer_body, _| {
|
||||||
|
test_body = detailed_indexer_body;
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
info!("Testing indexer");
|
||||||
|
|
||||||
|
let mut request_props = self
|
||||||
|
.request_props_from(event, RequestMethod::Post, Some(test_body), None, None)
|
||||||
|
.await;
|
||||||
|
request_props.ignore_status_code = true;
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<Value, Value>(request_props, |test_results, mut app| {
|
||||||
|
if test_results.as_object().is_none() {
|
||||||
|
app.data.sonarr_data.indexer_test_error = Some(
|
||||||
|
test_results.as_array().unwrap()[0]
|
||||||
|
.get("errorMessage")
|
||||||
|
.unwrap()
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
async fn extract_series_id(&mut self, series_id: Option<i64>) -> (i64, String) {
|
async fn extract_series_id(&mut self, series_id: Option<i64>) -> (i64, String) {
|
||||||
let series_id = if let Some(id) = series_id {
|
let series_id = if let Some(id) = series_id {
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ mod test {
|
|||||||
use bimap::BiMap;
|
use bimap::BiMap;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use indoc::formatdoc;
|
use indoc::formatdoc;
|
||||||
|
use mockito::Matcher;
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
@@ -223,6 +224,7 @@ mod test {
|
|||||||
#[case(SonarrEvent::GetTasks, "/system/task")]
|
#[case(SonarrEvent::GetTasks, "/system/task")]
|
||||||
#[case(SonarrEvent::GetUpdates, "/update")]
|
#[case(SonarrEvent::GetUpdates, "/update")]
|
||||||
#[case(SonarrEvent::MarkHistoryItemAsFailed(0), "/history/failed")]
|
#[case(SonarrEvent::MarkHistoryItemAsFailed(0), "/history/failed")]
|
||||||
|
#[case(SonarrEvent::TestIndexer(None), "/indexer/test")]
|
||||||
fn test_resource(#[case] event: SonarrEvent, #[case] expected_uri: String) {
|
fn test_resource(#[case] event: SonarrEvent, #[case] expected_uri: String) {
|
||||||
assert_str_eq!(event.resource(), expected_uri);
|
assert_str_eq!(event.resource(), expected_uri);
|
||||||
}
|
}
|
||||||
@@ -3923,6 +3925,209 @@ mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_test_sonarr_indexer_event_error() {
|
||||||
|
let indexer_details_json = json!({
|
||||||
|
"enableRss": true,
|
||||||
|
"enableAutomaticSearch": true,
|
||||||
|
"enableInteractiveSearch": true,
|
||||||
|
"name": "Test Indexer",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://test.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seedCriteria.seedRatio",
|
||||||
|
"value": "1.2",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let response_json = json!([
|
||||||
|
{
|
||||||
|
"isWarning": false,
|
||||||
|
"propertyName": "",
|
||||||
|
"errorMessage": "test failure",
|
||||||
|
"severity": "error"
|
||||||
|
}]);
|
||||||
|
let (async_details_server, app_arc, mut server) = mock_servarr_api(
|
||||||
|
RequestMethod::Get,
|
||||||
|
None,
|
||||||
|
Some(indexer_details_json.clone()),
|
||||||
|
None,
|
||||||
|
SonarrEvent::GetIndexers,
|
||||||
|
Some("/1"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let async_test_server = server
|
||||||
|
.mock(
|
||||||
|
"POST",
|
||||||
|
format!("/api/v3{}", SonarrEvent::TestIndexer(None).resource()).as_str(),
|
||||||
|
)
|
||||||
|
.with_status(400)
|
||||||
|
.match_header("X-Api-Key", "test1234")
|
||||||
|
.match_body(Matcher::Json(indexer_details_json.clone()))
|
||||||
|
.with_body(response_json.to_string())
|
||||||
|
.create_async()
|
||||||
|
.await;
|
||||||
|
app_arc
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![indexer()]);
|
||||||
|
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
|
||||||
|
|
||||||
|
if let SonarrSerdeable::Value(value) = network
|
||||||
|
.handle_sonarr_event(SonarrEvent::TestIndexer(None))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
async_details_server.assert_async().await;
|
||||||
|
async_test_server.assert_async().await;
|
||||||
|
assert_eq!(
|
||||||
|
app_arc.lock().await.data.sonarr_data.indexer_test_error,
|
||||||
|
Some("\"test failure\"".to_owned())
|
||||||
|
);
|
||||||
|
assert_eq!(value, response_json)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_test_sonarr_indexer_event_success() {
|
||||||
|
let indexer_details_json = json!({
|
||||||
|
"enableRss": true,
|
||||||
|
"enableAutomaticSearch": true,
|
||||||
|
"enableInteractiveSearch": true,
|
||||||
|
"name": "Test Indexer",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://test.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seedCriteria.seedRatio",
|
||||||
|
"value": "1.2",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let (async_details_server, app_arc, mut server) = mock_servarr_api(
|
||||||
|
RequestMethod::Get,
|
||||||
|
None,
|
||||||
|
Some(indexer_details_json.clone()),
|
||||||
|
None,
|
||||||
|
SonarrEvent::GetIndexers,
|
||||||
|
Some("/1"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let async_test_server = server
|
||||||
|
.mock(
|
||||||
|
"POST",
|
||||||
|
format!("/api/v3{}", SonarrEvent::TestIndexer(None).resource()).as_str(),
|
||||||
|
)
|
||||||
|
.with_status(200)
|
||||||
|
.match_header("X-Api-Key", "test1234")
|
||||||
|
.match_body(Matcher::Json(indexer_details_json.clone()))
|
||||||
|
.with_body("{}")
|
||||||
|
.create_async()
|
||||||
|
.await;
|
||||||
|
app_arc
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![indexer()]);
|
||||||
|
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
|
||||||
|
|
||||||
|
if let SonarrSerdeable::Value(value) = network
|
||||||
|
.handle_sonarr_event(SonarrEvent::TestIndexer(None))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
async_details_server.assert_async().await;
|
||||||
|
async_test_server.assert_async().await;
|
||||||
|
assert_eq!(
|
||||||
|
app_arc.lock().await.data.sonarr_data.indexer_test_error,
|
||||||
|
None
|
||||||
|
);
|
||||||
|
assert_eq!(value, json!({}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_test_sonarr_indexer_event_success_uses_provided_id() {
|
||||||
|
let indexer_details_json = json!({
|
||||||
|
"enableRss": true,
|
||||||
|
"enableAutomaticSearch": true,
|
||||||
|
"enableInteractiveSearch": true,
|
||||||
|
"name": "Test Indexer",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "baseUrl",
|
||||||
|
"value": "https://test.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apiKey",
|
||||||
|
"value": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seedCriteria.seedRatio",
|
||||||
|
"value": "1.2",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"tags": [1],
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let (async_details_server, app_arc, mut server) = mock_servarr_api(
|
||||||
|
RequestMethod::Get,
|
||||||
|
None,
|
||||||
|
Some(indexer_details_json.clone()),
|
||||||
|
None,
|
||||||
|
SonarrEvent::GetIndexers,
|
||||||
|
Some("/1"),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let async_test_server = server
|
||||||
|
.mock(
|
||||||
|
"POST",
|
||||||
|
format!("/api/v3{}", SonarrEvent::TestIndexer(None).resource()).as_str(),
|
||||||
|
)
|
||||||
|
.with_status(200)
|
||||||
|
.match_header("X-Api-Key", "test1234")
|
||||||
|
.match_body(Matcher::Json(indexer_details_json.clone()))
|
||||||
|
.with_body("{}")
|
||||||
|
.create_async()
|
||||||
|
.await;
|
||||||
|
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
|
||||||
|
|
||||||
|
if let SonarrSerdeable::Value(value) = network
|
||||||
|
.handle_sonarr_event(SonarrEvent::TestIndexer(Some(1)))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
async_details_server.assert_async().await;
|
||||||
|
async_test_server.assert_async().await;
|
||||||
|
assert_eq!(value, json!({}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_extract_series_id() {
|
async fn test_extract_series_id() {
|
||||||
let app_arc = Arc::new(Mutex::new(App::default()));
|
let app_arc = Arc::new(Mutex::new(App::default()));
|
||||||
|
|||||||
Reference in New Issue
Block a user