feat(network): Support for editing a sonarr indexer

This commit is contained in:
2024-11-25 15:17:13 -07:00
parent 1dd4cd74c3
commit d43862a3a7
18 changed files with 1041 additions and 71 deletions
+15 -11
View File
@@ -9,18 +9,18 @@ use urlencoding::encode;
use crate::models::radarr_models::{
AddMovieBody, AddMovieOptions, AddMovieSearchResult, BlocklistResponse, Collection,
CollectionMovie, Credit, CreditType, DeleteMovieParams, DownloadRecord, DownloadsResponse,
EditCollectionParams, EditIndexerParams, EditMovieParams, IndexerSettings, IndexerTestResult,
Movie, MovieCommandBody, MovieHistoryItem, RadarrRelease, RadarrReleaseDownloadBody,
RadarrSerdeable, RadarrTask, RadarrTaskName, SystemStatus,
EditCollectionParams, EditMovieParams, IndexerSettings, IndexerTestResult, Movie,
MovieCommandBody, MovieHistoryItem, RadarrRelease, RadarrReleaseDownloadBody, RadarrSerdeable,
RadarrTask, RadarrTaskName, SystemStatus,
};
use crate::models::servarr_data::modals::IndexerTestResultModalItem;
use crate::models::servarr_data::modals::{EditIndexerModal, IndexerTestResultModalItem};
use crate::models::servarr_data::radarr::modals::{
AddMovieModal, EditCollectionModal, EditIndexerModal, EditMovieModal, MovieDetailsModal,
AddMovieModal, EditCollectionModal, EditMovieModal, MovieDetailsModal,
};
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
use crate::models::servarr_models::{
AddRootFolderBody, CommandBody, DiskSpace, HostConfig, Indexer, LogResponse, QualityProfile,
QueueEvent, RootFolder, SecurityConfig, Tag, Update,
AddRootFolderBody, CommandBody, DiskSpace, EditIndexerParams, HostConfig, Indexer, LogResponse,
QualityProfile, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
};
use crate::models::stateful_table::StatefulTable;
use crate::models::{HorizontallyScrollableText, Route, Scrollable, ScrollableText};
@@ -188,9 +188,10 @@ impl<'a, 'b> Network<'a, 'b> {
.edit_collection(params)
.await
.map(RadarrSerdeable::from),
RadarrEvent::EditIndexer(params) => {
self.edit_indexer(params).await.map(RadarrSerdeable::from)
}
RadarrEvent::EditIndexer(params) => self
.edit_radarr_indexer(params)
.await
.map(RadarrSerdeable::from),
RadarrEvent::EditMovie(params) => self.edit_movie(params).await.map(RadarrSerdeable::from),
RadarrEvent::GetAllIndexerSettings => self
.get_all_radarr_indexer_settings()
@@ -882,7 +883,10 @@ impl<'a, 'b> Network<'a, 'b> {
.await
}
async fn edit_indexer(&mut self, edit_indexer_params: Option<EditIndexerParams>) -> Result<()> {
async fn edit_radarr_indexer(
&mut self,
edit_indexer_params: Option<EditIndexerParams>,
) -> Result<()> {
let detail_event = RadarrEvent::GetIndexers;
let event = RadarrEvent::EditIndexer(None);
let id = if let Some(ref params) = edit_indexer_params {
+7 -6
View File
@@ -4053,7 +4053,7 @@ mod test {
}
#[tokio::test]
async fn test_handle_edit_indexer_event() {
async fn test_handle_edit_radarr_indexer_event() {
let indexer_details_json = json!({
"enableRss": true,
"enableAutomaticSearch": true,
@@ -4153,7 +4153,7 @@ mod test {
}
#[tokio::test]
async fn test_handle_edit_indexer_event_does_not_add_seed_ratio_when_seed_ratio_field_is_none_in_details(
async fn test_handle_edit_radarr_indexer_event_does_not_add_seed_ratio_when_seed_ratio_field_is_none_in_details(
) {
let indexer_details_json = json!({
"enableRss": true,
@@ -4255,7 +4255,7 @@ mod test {
}
#[tokio::test]
async fn test_handle_edit_indexer_event_populates_the_seed_ratio_value_when_seed_ratio_field_is_present_in_details(
async fn test_handle_edit_radarr_indexer_event_populates_the_seed_ratio_value_when_seed_ratio_field_is_present_in_details(
) {
let indexer_details_json = json!({
"enableRss": true,
@@ -4371,7 +4371,7 @@ mod test {
}
#[tokio::test]
async fn test_handle_edit_indexer_event_uses_provided_parameters() {
async fn test_handle_edit_radarr_indexer_event_uses_provided_parameters() {
let indexer_details_json = json!({
"enableRss": true,
"enableAutomaticSearch": true,
@@ -4464,7 +4464,8 @@ mod test {
}
#[tokio::test]
async fn test_handle_edit_indexer_event_uses_provided_parameters_defaults_to_previous_values() {
async fn test_handle_edit_radarr_indexer_event_uses_provided_parameters_defaults_to_previous_values(
) {
let indexer_details_json = json!({
"enableRss": true,
"enableAutomaticSearch": true,
@@ -4525,7 +4526,7 @@ mod test {
}
#[tokio::test]
async fn test_handle_edit_indexer_event_uses_provided_parameters_clears_tags_when_clear_tags_is_true(
async fn test_handle_edit_radarr_indexer_event_uses_provided_parameters_clears_tags_when_clear_tags_is_true(
) {
let indexer_details_json = json!({
"enableRss": true,
+266 -4
View File
@@ -8,15 +8,15 @@ use crate::{
models::{
radarr_models::IndexerTestResult,
servarr_data::{
modals::IndexerTestResultModalItem,
modals::{EditIndexerModal, IndexerTestResultModalItem},
sonarr::{
modals::{AddSeriesModal, EpisodeDetailsModal, SeasonDetailsModal},
sonarr_data::ActiveSonarrBlock,
},
},
servarr_models::{
AddRootFolderBody, CommandBody, DiskSpace, HostConfig, Indexer, Language, LogResponse,
QualityProfile, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
AddRootFolderBody, CommandBody, DiskSpace, EditIndexerParams, HostConfig, Indexer, Language,
LogResponse, QualityProfile, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
},
sonarr_models::{
AddSeriesBody, AddSeriesOptions, AddSeriesSearchResult, BlocklistResponse,
@@ -51,6 +51,7 @@ pub enum SonarrEvent {
DeleteTag(i64),
DownloadRelease(SonarrReleaseDownloadBody),
EditAllIndexerSettings(Option<IndexerSettings>),
EditIndexer(Option<EditIndexerParams>),
GetAllIndexerSettings,
GetBlocklist,
GetDownloads,
@@ -106,7 +107,9 @@ impl NetworkResource for SonarrEvent {
SonarrEvent::GetEpisodes(_) | SonarrEvent::GetEpisodeDetails(_) => "/episode",
SonarrEvent::GetHistory(_) | SonarrEvent::GetEpisodeHistory(_) => "/history",
SonarrEvent::GetHostConfig | SonarrEvent::GetSecurityConfig => "/config/host",
SonarrEvent::GetIndexers | SonarrEvent::DeleteIndexer(_) => "/indexer",
SonarrEvent::GetIndexers | SonarrEvent::DeleteIndexer(_) | SonarrEvent::EditIndexer(_) => {
"/indexer"
}
SonarrEvent::GetLanguageProfiles => "/languageprofile",
SonarrEvent::GetLogs(_) => "/log",
SonarrEvent::GetDiskSpace => "/diskspace",
@@ -204,6 +207,10 @@ impl<'a, 'b> Network<'a, 'b> {
.edit_all_sonarr_indexer_settings(params)
.await
.map(SonarrSerdeable::from),
SonarrEvent::EditIndexer(params) => self
.edit_sonarr_indexer(params)
.await
.map(SonarrSerdeable::from),
SonarrEvent::GetBlocklist => self.get_sonarr_blocklist().await.map(SonarrSerdeable::from),
SonarrEvent::GetDownloads => self.get_sonarr_downloads().await.map(SonarrSerdeable::from),
SonarrEvent::GetEpisodes(series_id) => self
@@ -800,6 +807,261 @@ impl<'a, 'b> Network<'a, 'b> {
resp
}
async fn edit_sonarr_indexer(
&mut self,
edit_indexer_params: Option<EditIndexerParams>,
) -> Result<()> {
let detail_event = SonarrEvent::GetIndexers;
let event = SonarrEvent::EditIndexer(None);
let id = if let Some(ref params) = edit_indexer_params {
params.indexer_id
} else {
self
.app
.lock()
.await
.data
.sonarr_data
.indexers
.current_selection()
.id
};
info!("Updating 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 response = String::new();
self
.handle_request::<(), Value>(request_props, |detailed_indexer_body, _| {
response = detailed_indexer_body.to_string()
})
.await?;
info!("Constructing edit indexer body");
let mut detailed_indexer_body: Value = serde_json::from_str(&response).unwrap();
let priority = detailed_indexer_body["priority"]
.as_i64()
.expect("Unable to deserialize 'priority'");
let (
name,
enable_rss,
enable_automatic_search,
enable_interactive_search,
url,
api_key,
seed_ratio,
tags,
priority,
) = if let Some(params) = edit_indexer_params {
let seed_ratio_field_option = detailed_indexer_body["fields"]
.as_array()
.unwrap()
.iter()
.find(|field| field["name"] == "seedCriteria.seedRatio");
let name = params.name.unwrap_or(
detailed_indexer_body["name"]
.as_str()
.expect("Unable to deserialize 'name'")
.to_owned(),
);
let enable_rss = params.enable_rss.unwrap_or(
detailed_indexer_body["enableRss"]
.as_bool()
.expect("Unable to deserialize 'enableRss'"),
);
let enable_automatic_search = params.enable_automatic_search.unwrap_or(
detailed_indexer_body["enableAutomaticSearch"]
.as_bool()
.expect("Unable to deserialize 'enableAutomaticSearch"),
);
let enable_interactive_search = params.enable_interactive_search.unwrap_or(
detailed_indexer_body["enableInteractiveSearch"]
.as_bool()
.expect("Unable to deserialize 'enableInteractiveSearch'"),
);
let url = params.url.unwrap_or(
detailed_indexer_body["fields"]
.as_array()
.expect("Unable to deserialize 'fields'")
.iter()
.find(|field| field["name"] == "baseUrl")
.expect("Field 'baseUrl' was not found in the 'fields' array")
.get("value")
.unwrap_or(&json!(""))
.as_str()
.expect("Unable to deserialize 'baseUrl value'")
.to_owned(),
);
let api_key = params.api_key.unwrap_or(
detailed_indexer_body["fields"]
.as_array()
.expect("Unable to deserialize 'fields'")
.iter()
.find(|field| field["name"] == "apiKey")
.expect("Field 'apiKey' was not found in the 'fields' array")
.get("value")
.unwrap_or(&json!(""))
.as_str()
.expect("Unable to deserialize 'apiKey value'")
.to_owned(),
);
let seed_ratio = params.seed_ratio.unwrap_or_else(|| {
if let Some(seed_ratio_field) = seed_ratio_field_option {
return seed_ratio_field
.get("value")
.unwrap_or(&json!(""))
.as_str()
.expect("Unable to deserialize 'seedCriteria.seedRatio value'")
.to_owned();
}
String::new()
});
let tags = if params.clear_tags {
vec![]
} else {
params.tags.unwrap_or(
detailed_indexer_body["tags"]
.as_array()
.expect("Unable to deserialize 'tags'")
.iter()
.map(|item| item.as_i64().expect("Unable to deserialize tag ID"))
.collect(),
)
};
let priority = params.priority.unwrap_or(priority);
(
name,
enable_rss,
enable_automatic_search,
enable_interactive_search,
url,
api_key,
seed_ratio,
tags,
priority,
)
} else {
let tags = self
.app
.lock()
.await
.data
.sonarr_data
.edit_indexer_modal
.as_ref()
.unwrap()
.tags
.text
.clone();
let tag_ids_vec = self.extract_and_add_sonarr_tag_ids_vec(tags).await;
let mut app = self.app.lock().await;
let params = {
let EditIndexerModal {
name,
enable_rss,
enable_automatic_search,
enable_interactive_search,
url,
api_key,
seed_ratio,
..
} = app.data.sonarr_data.edit_indexer_modal.as_ref().unwrap();
(
name.text.clone(),
enable_rss.unwrap_or_default(),
enable_automatic_search.unwrap_or_default(),
enable_interactive_search.unwrap_or_default(),
url.text.clone(),
api_key.text.clone(),
seed_ratio.text.clone(),
tag_ids_vec,
priority,
)
};
app.data.sonarr_data.edit_indexer_modal = None;
params
};
*detailed_indexer_body.get_mut("name").unwrap() = json!(name);
*detailed_indexer_body.get_mut("priority").unwrap() = json!(priority);
*detailed_indexer_body.get_mut("enableRss").unwrap() = json!(enable_rss);
*detailed_indexer_body
.get_mut("enableAutomaticSearch")
.unwrap() = json!(enable_automatic_search);
*detailed_indexer_body
.get_mut("enableInteractiveSearch")
.unwrap() = json!(enable_interactive_search);
*detailed_indexer_body
.get_mut("fields")
.unwrap()
.as_array_mut()
.unwrap()
.iter_mut()
.find(|field| field["name"] == "baseUrl")
.unwrap()
.get_mut("value")
.unwrap() = json!(url);
*detailed_indexer_body
.get_mut("fields")
.unwrap()
.as_array_mut()
.unwrap()
.iter_mut()
.find(|field| field["name"] == "apiKey")
.unwrap()
.get_mut("value")
.unwrap() = json!(api_key);
*detailed_indexer_body.get_mut("tags").unwrap() = json!(tags);
let seed_ratio_field_option = detailed_indexer_body
.get_mut("fields")
.unwrap()
.as_array_mut()
.unwrap()
.iter_mut()
.find(|field| field["name"] == "seedCriteria.seedRatio");
if let Some(seed_ratio_field) = seed_ratio_field_option {
seed_ratio_field
.as_object_mut()
.unwrap()
.insert("value".to_string(), json!(seed_ratio));
}
debug!("Edit indexer body: {detailed_indexer_body:?}");
let request_props = self
.request_props_from(
event,
RequestMethod::Put,
Some(detailed_indexer_body),
Some(format!("/{id}")),
None,
)
.await;
self
.handle_request::<Value, ()>(request_props, |_, _| ())
.await
}
async fn get_all_sonarr_indexer_settings(&mut self) -> Result<IndexerSettings> {
info!("Fetching Sonarr indexer settings");
let event = SonarrEvent::GetAllIndexerSettings;
+568 -4
View File
@@ -22,14 +22,14 @@ mod test {
use crate::app::{App, ServarrConfig};
use crate::models::radarr_models::IndexerTestResult;
use crate::models::servarr_data::modals::IndexerTestResultModalItem;
use crate::models::servarr_data::modals::{EditIndexerModal, IndexerTestResultModalItem};
use crate::models::servarr_data::sonarr::modals::{
AddSeriesModal, EpisodeDetailsModal, SeasonDetailsModal,
};
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
use crate::models::servarr_models::{
DiskSpace, HostConfig, Indexer, IndexerField, Language, LogResponse, Quality, QualityProfile,
QualityWrapper, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
DiskSpace, EditIndexerParams, HostConfig, Indexer, IndexerField, Language, LogResponse,
Quality, QualityProfile, QualityWrapper, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
};
use crate::models::sonarr_models::{
BlocklistItem, DeleteSeriesParams, DownloadRecord, DownloadsResponse, Episode, EpisodeFile,
@@ -205,7 +205,12 @@ mod test {
#[rstest]
fn test_resource_indexer(
#[values(SonarrEvent::GetIndexers, SonarrEvent::DeleteIndexer(None))] event: SonarrEvent,
#[values(
SonarrEvent::GetIndexers,
SonarrEvent::DeleteIndexer(None),
SonarrEvent::EditIndexer(None)
)]
event: SonarrEvent,
) {
assert_str_eq!(event.resource(), "/indexer");
}
@@ -1126,6 +1131,565 @@ mod test {
async_server.assert_async().await;
}
#[tokio::test]
async fn test_handle_edit_sonarr_indexer_event() {
let indexer_details_json = json!({
"enableRss": true,
"enableAutomaticSearch": true,
"enableInteractiveSearch": true,
"name": "Test Indexer",
"priority": 1,
"fields": [
{
"name": "baseUrl",
"value": "https://test.com",
},
{
"name": "apiKey",
"value": "",
},
{
"name": "seedCriteria.seedRatio",
"value": "1.2",
},
],
"tags": [1],
"id": 1
});
let expected_indexer_edit_body_json = json!({
"enableRss": false,
"enableAutomaticSearch": false,
"enableInteractiveSearch": false,
"name": "Test Update",
"priority": 1,
"fields": [
{
"name": "baseUrl",
"value": "https://localhost:9696/1/",
},
{
"name": "apiKey",
"value": "test1234",
},
{
"name": "seedCriteria.seedRatio",
"value": "1.3",
},
],
"tags": [1, 2],
"id": 1
});
let (async_details_server, app_arc, mut server) = mock_servarr_api(
RequestMethod::Get,
None,
Some(indexer_details_json),
None,
SonarrEvent::GetIndexers,
Some("/1"),
None,
)
.await;
let async_edit_server = server
.mock(
"PUT",
format!("/api/v3{}/1", SonarrEvent::EditIndexer(None).resource()).as_str(),
)
.with_status(202)
.match_header("X-Api-Key", "test1234")
.match_body(Matcher::Json(expected_indexer_edit_body_json))
.create_async()
.await;
{
let mut app = app_arc.lock().await;
app.data.sonarr_data.tags_map =
BiMap::from_iter([(1, "usenet".to_owned()), (2, "testing".to_owned())]);
let edit_indexer_modal = EditIndexerModal {
name: "Test Update".into(),
enable_rss: Some(false),
enable_automatic_search: Some(false),
enable_interactive_search: Some(false),
url: "https://localhost:9696/1/".into(),
api_key: "test1234".into(),
seed_ratio: "1.3".into(),
tags: "usenet, testing".into(),
};
app.data.sonarr_data.edit_indexer_modal = Some(edit_indexer_modal);
app.data.sonarr_data.indexers.set_items(vec![indexer()]);
}
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network
.handle_sonarr_event(SonarrEvent::EditIndexer(None))
.await
.is_ok());
async_details_server.assert_async().await;
async_edit_server.assert_async().await;
let app = app_arc.lock().await;
assert!(app.data.sonarr_data.edit_indexer_modal.is_none());
}
#[tokio::test]
async fn test_handle_edit_sonarr_indexer_event_does_not_add_seed_ratio_when_seed_ratio_field_is_none_in_details(
) {
let indexer_details_json = json!({
"enableRss": true,
"enableAutomaticSearch": true,
"enableInteractiveSearch": true,
"name": "Test Indexer",
"priority": 1,
"fields": [
{
"name": "baseUrl",
"value": "https://test.com",
},
{
"name": "apiKey",
"value": "",
},
],
"tags": [1],
"id": 1
});
let expected_indexer_edit_body_json = json!({
"enableRss": false,
"enableAutomaticSearch": false,
"enableInteractiveSearch": false,
"name": "Test Update",
"priority": 1,
"fields": [
{
"name": "baseUrl",
"value": "https://localhost:9696/1/",
},
{
"name": "apiKey",
"value": "test1234",
},
],
"tags": [1, 2],
"id": 1
});
let (async_details_server, app_arc, mut server) = mock_servarr_api(
RequestMethod::Get,
None,
Some(indexer_details_json),
None,
SonarrEvent::GetIndexers,
Some("/1"),
None,
)
.await;
let async_edit_server = server
.mock(
"PUT",
format!("/api/v3{}/1", SonarrEvent::EditIndexer(None).resource()).as_str(),
)
.with_status(202)
.match_header("X-Api-Key", "test1234")
.match_body(Matcher::Json(expected_indexer_edit_body_json))
.create_async()
.await;
{
let mut app = app_arc.lock().await;
app.data.sonarr_data.tags_map =
BiMap::from_iter([(1, "usenet".to_owned()), (2, "testing".to_owned())]);
let edit_indexer_modal = EditIndexerModal {
name: "Test Update".into(),
enable_rss: Some(false),
enable_automatic_search: Some(false),
enable_interactive_search: Some(false),
url: "https://localhost:9696/1/".into(),
api_key: "test1234".into(),
seed_ratio: "1.3".into(),
tags: "usenet, testing".into(),
};
app.data.sonarr_data.edit_indexer_modal = Some(edit_indexer_modal);
let mut indexer = indexer();
indexer.fields = Some(
indexer
.fields
.unwrap()
.into_iter()
.filter(|field| field.name != Some("seedCriteria.seedRatio".to_string()))
.collect(),
);
app.data.sonarr_data.indexers.set_items(vec![indexer]);
}
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network
.handle_sonarr_event(SonarrEvent::EditIndexer(None))
.await
.is_ok());
async_details_server.assert_async().await;
async_edit_server.assert_async().await;
let app = app_arc.lock().await;
assert!(app.data.sonarr_data.edit_indexer_modal.is_none());
}
#[tokio::test]
async fn test_handle_edit_sonarr_indexer_event_populates_the_seed_ratio_value_when_seed_ratio_field_is_present_in_details(
) {
let indexer_details_json = json!({
"enableRss": true,
"enableAutomaticSearch": true,
"enableInteractiveSearch": true,
"name": "Test Indexer",
"priority": 1,
"fields": [
{
"name": "baseUrl",
"value": "https://test.com",
},
{
"name": "apiKey",
"value": "",
},
{
"name": "seedCriteria.seedRatio",
},
],
"tags": [1],
"id": 1
});
let expected_indexer_edit_body_json = json!({
"enableRss": false,
"enableAutomaticSearch": false,
"enableInteractiveSearch": false,
"name": "Test Update",
"priority": 1,
"fields": [
{
"name": "baseUrl",
"value": "https://localhost:9696/1/",
},
{
"name": "apiKey",
"value": "test1234",
},
{
"name": "seedCriteria.seedRatio",
"value": "1.3",
},
],
"tags": [1, 2],
"id": 1
});
let (async_details_server, app_arc, mut server) = mock_servarr_api(
RequestMethod::Get,
None,
Some(indexer_details_json),
None,
SonarrEvent::GetIndexers,
Some("/1"),
None,
)
.await;
let async_edit_server = server
.mock(
"PUT",
format!("/api/v3{}/1", SonarrEvent::EditIndexer(None).resource()).as_str(),
)
.with_status(202)
.match_header("X-Api-Key", "test1234")
.match_body(Matcher::Json(expected_indexer_edit_body_json))
.create_async()
.await;
{
let mut app = app_arc.lock().await;
app.data.sonarr_data.tags_map =
BiMap::from_iter([(1, "usenet".to_owned()), (2, "testing".to_owned())]);
let edit_indexer_modal = EditIndexerModal {
name: "Test Update".into(),
enable_rss: Some(false),
enable_automatic_search: Some(false),
enable_interactive_search: Some(false),
url: "https://localhost:9696/1/".into(),
api_key: "test1234".into(),
seed_ratio: "1.3".into(),
tags: "usenet, testing".into(),
};
app.data.sonarr_data.edit_indexer_modal = Some(edit_indexer_modal);
let mut indexer = indexer();
indexer.fields = Some(
indexer
.fields
.unwrap()
.into_iter()
.map(|mut field| {
if field.name == Some("seedCriteria.seedRatio".to_string()) {
field.value = None;
field
} else {
field
}
})
.collect(),
);
app.data.sonarr_data.indexers.set_items(vec![indexer]);
}
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network
.handle_sonarr_event(SonarrEvent::EditIndexer(None))
.await
.is_ok());
async_details_server.assert_async().await;
async_edit_server.assert_async().await;
let app = app_arc.lock().await;
assert!(app.data.sonarr_data.edit_indexer_modal.is_none());
}
#[tokio::test]
async fn test_handle_edit_sonarr_indexer_event_uses_provided_parameters() {
let indexer_details_json = json!({
"enableRss": true,
"enableAutomaticSearch": true,
"enableInteractiveSearch": true,
"name": "Test Indexer",
"priority": 1,
"fields": [
{
"name": "baseUrl",
"value": "https://test.com",
},
{
"name": "apiKey",
"value": "",
},
{
"name": "seedCriteria.seedRatio",
"value": "1.2",
},
],
"tags": [1],
"id": 1
});
let expected_indexer_edit_body_json = json!({
"enableRss": false,
"enableAutomaticSearch": false,
"enableInteractiveSearch": false,
"name": "Test Update",
"priority": 25,
"fields": [
{
"name": "baseUrl",
"value": "https://localhost:9696/1/",
},
{
"name": "apiKey",
"value": "test1234",
},
{
"name": "seedCriteria.seedRatio",
"value": "1.3",
},
],
"tags": [1, 2],
"id": 1
});
let edit_indexer_params = EditIndexerParams {
indexer_id: 1,
name: Some("Test Update".to_owned()),
enable_rss: Some(false),
enable_automatic_search: Some(false),
enable_interactive_search: Some(false),
url: Some("https://localhost:9696/1/".to_owned()),
api_key: Some("test1234".to_owned()),
seed_ratio: Some("1.3".to_owned()),
tags: Some(vec![1, 2]),
priority: Some(25),
..EditIndexerParams::default()
};
let (async_details_server, app_arc, mut server) = mock_servarr_api(
RequestMethod::Get,
None,
Some(indexer_details_json),
None,
SonarrEvent::GetIndexers,
Some("/1"),
None,
)
.await;
let async_edit_server = server
.mock(
"PUT",
format!("/api/v3{}/1", SonarrEvent::EditIndexer(None).resource()).as_str(),
)
.with_status(202)
.match_header("X-Api-Key", "test1234")
.match_body(Matcher::Json(expected_indexer_edit_body_json))
.create_async()
.await;
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network
.handle_sonarr_event(SonarrEvent::EditIndexer(Some(edit_indexer_params)))
.await
.is_ok());
async_details_server.assert_async().await;
async_edit_server.assert_async().await;
}
#[tokio::test]
async fn test_handle_edit_sonarr_indexer_event_uses_provided_parameters_defaults_to_previous_values(
) {
let indexer_details_json = json!({
"enableRss": true,
"enableAutomaticSearch": true,
"enableInteractiveSearch": true,
"name": "Test Indexer",
"priority": 1,
"fields": [
{
"name": "baseUrl",
"value": "https://test.com",
},
{
"name": "apiKey",
"value": "",
},
{
"name": "seedCriteria.seedRatio",
"value": "1.2",
},
],
"tags": [1],
"id": 1
});
let edit_indexer_params = EditIndexerParams {
indexer_id: 1,
..EditIndexerParams::default()
};
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_edit_server = server
.mock(
"PUT",
format!("/api/v3{}/1", SonarrEvent::EditIndexer(None).resource()).as_str(),
)
.with_status(202)
.match_header("X-Api-Key", "test1234")
.match_body(Matcher::Json(indexer_details_json))
.create_async()
.await;
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network
.handle_sonarr_event(SonarrEvent::EditIndexer(Some(edit_indexer_params)))
.await
.is_ok());
async_details_server.assert_async().await;
async_edit_server.assert_async().await;
}
#[tokio::test]
async fn test_handle_edit_sonarr_indexer_event_uses_provided_parameters_clears_tags_when_clear_tags_is_true(
) {
let indexer_details_json = json!({
"enableRss": true,
"enableAutomaticSearch": true,
"enableInteractiveSearch": true,
"name": "Test Indexer",
"priority": 1,
"fields": [
{
"name": "baseUrl",
"value": "https://test.com",
},
{
"name": "apiKey",
"value": "",
},
{
"name": "seedCriteria.seedRatio",
"value": "1.2",
},
],
"tags": [1, 2],
"id": 1
});
let expected_edit_indexer_body = json!({
"enableRss": true,
"enableAutomaticSearch": true,
"enableInteractiveSearch": true,
"name": "Test Indexer",
"priority": 1,
"fields": [
{
"name": "baseUrl",
"value": "https://test.com",
},
{
"name": "apiKey",
"value": "",
},
{
"name": "seedCriteria.seedRatio",
"value": "1.2",
},
],
"tags": [],
"id": 1
});
let edit_indexer_params = EditIndexerParams {
indexer_id: 1,
clear_tags: true,
..EditIndexerParams::default()
};
let (async_details_server, app_arc, mut server) = mock_servarr_api(
RequestMethod::Get,
None,
Some(indexer_details_json),
None,
SonarrEvent::GetIndexers,
Some("/1"),
None,
)
.await;
let async_edit_server = server
.mock(
"PUT",
format!("/api/v3{}/1", SonarrEvent::EditIndexer(None).resource()).as_str(),
)
.with_status(202)
.match_header("X-Api-Key", "test1234")
.match_body(Matcher::Json(expected_edit_indexer_body))
.create_async()
.await;
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network
.handle_sonarr_event(SonarrEvent::EditIndexer(Some(edit_indexer_params)))
.await
.is_ok());
async_details_server.assert_async().await;
async_edit_server.assert_async().await;
}
#[rstest]
#[tokio::test]
async fn test_handle_get_sonarr_blocklist_event(#[values(true, false)] use_custom_sorting: bool) {