fix: keep history readable when an event type is unrecognised
A single history record whose event type the Servarr build has no name for made the entire history response fail to decode, so the view died with "Failed to parse response!" and showed nothing at all. The event type is stored as an integer and is only serialized as a camelCase string when the build can name it. For values it cannot name, it is emitted as a bare JSON number instead, which is a type mismatch rather than merely an unknown name. Serde's other attribute does not help: it is rejected outright unless it sits on the last variant, and even there it only catches unrecognised strings, leaving a number to fail exactly as before. from_json_or_default buffers the field and falls back to the type's default for any input the enum does not recognise, whether that is an unknown string, a number, or any other JSON value. It is applied to the event type of all four history item types. Known values still map exactly as they did, and serialization is untouched. Verified against a live Readarr carrying such a record: the history listing failed to decode before the change, and afterwards lists every record, rendering the unnamed one as Unknown. Verified by mutation. Seven mutations all fail the new suite: dropping the fallback, discarding the decoded value, removing the attribute from each of the four history items, and renaming a variant on serialize only. The five per-tree and serialize-only mutations were each invisible to every pre-existing test.
This commit is contained in:
10 files changed
+578
-6
No files matched your search
@@ -404,6 +404,7 @@ pub struct LidarrHistoryItem {
|
||||
#[serde(default)]
|
||||
pub quality: QualityWrapper,
|
||||
pub date: DateTime<Utc>,
|
||||
#[serde(deserialize_with = "super::from_json_or_default")]
|
||||
pub event_type: LidarrHistoryEventType,
|
||||
#[serde(default)]
|
||||
pub data: LidarrHistoryData,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
mod tests {
|
||||
use chrono::Utc;
|
||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||
use serde_json::json;
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::models::lidarr_models::{
|
||||
AddArtistSearchResult, Album, AudioTags, BlocklistItem, BlocklistResponse, DownloadRecord,
|
||||
@@ -773,6 +773,126 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lidarr_history_event_type_deserialization() {
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("unknown")),
|
||||
LidarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("grabbed")),
|
||||
LidarrHistoryEventType::Grabbed
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("artistFolderImported")),
|
||||
LidarrHistoryEventType::ArtistFolderImported
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("albumImportIncomplete")),
|
||||
LidarrHistoryEventType::AlbumImportIncomplete
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("downloadIgnored")),
|
||||
LidarrHistoryEventType::DownloadIgnored
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("downloadImported")),
|
||||
LidarrHistoryEventType::DownloadImported
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("downloadFailed")),
|
||||
LidarrHistoryEventType::DownloadFailed
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("trackFileDeleted")),
|
||||
LidarrHistoryEventType::TrackFileDeleted
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("trackFileImported")),
|
||||
LidarrHistoryEventType::TrackFileImported
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("trackFileRenamed")),
|
||||
LidarrHistoryEventType::TrackFileRenamed
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("trackFileRetagged")),
|
||||
LidarrHistoryEventType::TrackFileRetagged
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lidarr_history_event_type_deserialization_falls_back_to_unknown() {
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("albumImportPartiallyComplete")),
|
||||
LidarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!(2)),
|
||||
LidarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!(11)),
|
||||
LidarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!(null)),
|
||||
LidarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!({ "id": 2 })),
|
||||
LidarrHistoryEventType::Unknown
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lidarr_history_event_type_serialization() {
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(LidarrHistoryEventType::Unknown),
|
||||
"unknown"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(LidarrHistoryEventType::Grabbed),
|
||||
"grabbed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(LidarrHistoryEventType::ArtistFolderImported),
|
||||
"artistFolderImported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(LidarrHistoryEventType::AlbumImportIncomplete),
|
||||
"albumImportIncomplete"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(LidarrHistoryEventType::DownloadIgnored),
|
||||
"downloadIgnored"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(LidarrHistoryEventType::DownloadImported),
|
||||
"downloadImported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(LidarrHistoryEventType::DownloadFailed),
|
||||
"downloadFailed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(LidarrHistoryEventType::TrackFileDeleted),
|
||||
"trackFileDeleted"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(LidarrHistoryEventType::TrackFileImported),
|
||||
"trackFileImported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(LidarrHistoryEventType::TrackFileRenamed),
|
||||
"trackFileRenamed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(LidarrHistoryEventType::TrackFileRetagged),
|
||||
"trackFileRetagged"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_artist_search_result_deserialization() {
|
||||
let search_result_json = json!({
|
||||
@@ -825,4 +945,32 @@ mod tests {
|
||||
assert!(search_result.genres.is_empty());
|
||||
assert_none!(&search_result.ratings);
|
||||
}
|
||||
|
||||
fn deserialize_history_event_type(event_type: Value) -> LidarrHistoryEventType {
|
||||
let history_item_json = json!({
|
||||
"id": 1,
|
||||
"sourceTitle": "Test Source Title",
|
||||
"albumId": 1,
|
||||
"artistId": 1,
|
||||
"trackId": 1,
|
||||
"date": "2024-01-01T00:00:00Z",
|
||||
"eventType": event_type
|
||||
});
|
||||
|
||||
serde_json::from_value::<LidarrHistoryItem>(history_item_json)
|
||||
.unwrap()
|
||||
.event_type
|
||||
}
|
||||
|
||||
fn serialize_history_event_type(event_type: LidarrHistoryEventType) -> String {
|
||||
let history_item = LidarrHistoryItem {
|
||||
event_type,
|
||||
..LidarrHistoryItem::default()
|
||||
};
|
||||
|
||||
serde_json::to_value(history_item).unwrap()["eventType"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
+10
-1
@@ -11,7 +11,7 @@ use radarr_models::RadarrSerdeable;
|
||||
use readarr_models::ReadarrSerdeable;
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
|
||||
use serde_json::Number;
|
||||
use serde_json::{Number, Value};
|
||||
use servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
|
||||
use sonarr_models::SonarrSerdeable;
|
||||
|
||||
@@ -442,6 +442,15 @@ where
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn from_json_or_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: Deserialize<'de> + Default,
|
||||
{
|
||||
let value: Value = Deserialize::deserialize(deserializer)?;
|
||||
Ok(T::deserialize(value).unwrap_or_default())
|
||||
}
|
||||
|
||||
pub fn strip_non_search_characters(input: &str) -> String {
|
||||
Regex::new(r"[^a-zA-Z0-9.,/'\-:\s]")
|
||||
.unwrap()
|
||||
|
||||
@@ -11,12 +11,13 @@ mod tests {
|
||||
use crate::models::{
|
||||
BlockSelectionState, HorizontallyScrollableText, Scrollable, ScrollableText, TabRoute, TabState,
|
||||
};
|
||||
use crate::models::{from_i64, strip_non_search_characters};
|
||||
use crate::models::{from_i64, from_json_or_default, strip_non_search_characters};
|
||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||
use serde::de::IntoDeserializer;
|
||||
use serde::de::value::Error as ValueError;
|
||||
use serde::de::value::F64Deserializer;
|
||||
use serde::de::value::I64Deserializer;
|
||||
use serde::de::value::StrDeserializer;
|
||||
use serde_json::to_string;
|
||||
|
||||
const BLOCKS: &[&[i32]] = &[&[11, 12], &[21, 22], &[31, 32]];
|
||||
@@ -803,6 +804,20 @@ mod tests {
|
||||
assert_ok_eq_x!(from_f64(deserializer), 1.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_json_or_default() {
|
||||
let deserializer: I64Deserializer<ValueError> = 1i64.into_deserializer();
|
||||
|
||||
assert_ok_eq_x!(from_json_or_default::<_, i64>(deserializer), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_json_or_default_falls_back_to_default() {
|
||||
let deserializer: StrDeserializer<'_, ValueError> = "unexpected".into_deserializer();
|
||||
|
||||
assert_ok_eq_x!(from_json_or_default::<_, i64>(deserializer), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_horizontally_scrollable_serialize() {
|
||||
let text = HorizontallyScrollableText::from("Test");
|
||||
|
||||
@@ -459,6 +459,7 @@ pub struct RadarrHistoryItem {
|
||||
pub quality: QualityWrapper,
|
||||
pub languages: Vec<Language>,
|
||||
pub date: DateTime<Utc>,
|
||||
#[serde(deserialize_with = "super::from_json_or_default")]
|
||||
pub event_type: RadarrHistoryEventType,
|
||||
#[serde(default)]
|
||||
pub data: RadarrHistoryData,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||
use serde_json::json;
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::models::radarr_models::{
|
||||
RadarrHistoryEventType, RadarrHistoryItem, RadarrHistoryWrapper,
|
||||
@@ -126,6 +126,102 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_radarr_history_event_type_deserialization() {
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("unknown")),
|
||||
RadarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("grabbed")),
|
||||
RadarrHistoryEventType::Grabbed
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("downloadFolderImported")),
|
||||
RadarrHistoryEventType::DownloadFolderImported
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("downloadFailed")),
|
||||
RadarrHistoryEventType::DownloadFailed
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("movieFileDeleted")),
|
||||
RadarrHistoryEventType::MovieFileDeleted
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("movieFolderImported")),
|
||||
RadarrHistoryEventType::MovieFolderImported
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("movieFileRenamed")),
|
||||
RadarrHistoryEventType::MovieFileRenamed
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("downloadIgnored")),
|
||||
RadarrHistoryEventType::DownloadIgnored
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_radarr_history_event_type_deserialization_falls_back_to_unknown() {
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("movieFileImportFailed")),
|
||||
RadarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!(2)),
|
||||
RadarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!(11)),
|
||||
RadarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!(null)),
|
||||
RadarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!({ "id": 2 })),
|
||||
RadarrHistoryEventType::Unknown
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_radarr_history_event_type_serialization() {
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(RadarrHistoryEventType::Unknown),
|
||||
"unknown"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(RadarrHistoryEventType::Grabbed),
|
||||
"grabbed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(RadarrHistoryEventType::DownloadFolderImported),
|
||||
"downloadFolderImported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(RadarrHistoryEventType::DownloadFailed),
|
||||
"downloadFailed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(RadarrHistoryEventType::MovieFileDeleted),
|
||||
"movieFileDeleted"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(RadarrHistoryEventType::MovieFolderImported),
|
||||
"movieFolderImported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(RadarrHistoryEventType::MovieFileRenamed),
|
||||
"movieFileRenamed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(RadarrHistoryEventType::DownloadIgnored),
|
||||
"downloadIgnored"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_download_record_default_indexer_value() {
|
||||
let json = r#"{
|
||||
@@ -517,4 +613,32 @@ mod tests {
|
||||
RadarrSerdeable::IndexerTestResults(indexer_test_results)
|
||||
);
|
||||
}
|
||||
|
||||
fn deserialize_history_event_type(event_type: Value) -> RadarrHistoryEventType {
|
||||
let history_item_json = json!({
|
||||
"id": 1,
|
||||
"sourceTitle": "Test Source Title",
|
||||
"movieId": 1,
|
||||
"quality": { "quality": { "name": "HD - 1080p" } },
|
||||
"languages": [],
|
||||
"date": "2024-01-01T00:00:00Z",
|
||||
"eventType": event_type
|
||||
});
|
||||
|
||||
serde_json::from_value::<RadarrHistoryItem>(history_item_json)
|
||||
.unwrap()
|
||||
.event_type
|
||||
}
|
||||
|
||||
fn serialize_history_event_type(event_type: RadarrHistoryEventType) -> String {
|
||||
let history_item = RadarrHistoryItem {
|
||||
event_type,
|
||||
..RadarrHistoryItem::default()
|
||||
};
|
||||
|
||||
serde_json::to_value(history_item).unwrap()["eventType"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
@@ -413,6 +413,7 @@ pub struct ReadarrHistoryItem {
|
||||
#[serde(default)]
|
||||
pub quality: QualityWrapper,
|
||||
pub date: DateTime<Utc>,
|
||||
#[serde(deserialize_with = "super::from_json_or_default")]
|
||||
pub event_type: ReadarrHistoryEventType,
|
||||
#[serde(default)]
|
||||
pub data: ReadarrHistoryData,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
mod tests {
|
||||
use chrono::Utc;
|
||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||
use serde_json::json;
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::models::readarr_models::{
|
||||
AddAuthorSearchResult, BlocklistItem, BlocklistResponse, Book, BookFile, DownloadRecord,
|
||||
@@ -758,6 +758,126 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_readarr_history_event_type_deserialization() {
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("unknown")),
|
||||
ReadarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("grabbed")),
|
||||
ReadarrHistoryEventType::Grabbed
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("authorFolderImported")),
|
||||
ReadarrHistoryEventType::AuthorFolderImported
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("bookImportIncomplete")),
|
||||
ReadarrHistoryEventType::BookImportIncomplete
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("downloadIgnored")),
|
||||
ReadarrHistoryEventType::DownloadIgnored
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("downloadImported")),
|
||||
ReadarrHistoryEventType::DownloadImported
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("downloadFailed")),
|
||||
ReadarrHistoryEventType::DownloadFailed
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("bookFileDeleted")),
|
||||
ReadarrHistoryEventType::BookFileDeleted
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("bookFileImported")),
|
||||
ReadarrHistoryEventType::BookFileImported
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("bookFileRenamed")),
|
||||
ReadarrHistoryEventType::BookFileRenamed
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("bookFileRetagged")),
|
||||
ReadarrHistoryEventType::BookFileRetagged
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_readarr_history_event_type_deserialization_falls_back_to_unknown() {
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("bookImportPartiallyComplete")),
|
||||
ReadarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!(2)),
|
||||
ReadarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!(11)),
|
||||
ReadarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!(null)),
|
||||
ReadarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!({ "id": 2 })),
|
||||
ReadarrHistoryEventType::Unknown
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_readarr_history_event_type_serialization() {
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(ReadarrHistoryEventType::Unknown),
|
||||
"unknown"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(ReadarrHistoryEventType::Grabbed),
|
||||
"grabbed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(ReadarrHistoryEventType::AuthorFolderImported),
|
||||
"authorFolderImported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(ReadarrHistoryEventType::BookImportIncomplete),
|
||||
"bookImportIncomplete"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(ReadarrHistoryEventType::DownloadIgnored),
|
||||
"downloadIgnored"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(ReadarrHistoryEventType::DownloadImported),
|
||||
"downloadImported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(ReadarrHistoryEventType::DownloadFailed),
|
||||
"downloadFailed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(ReadarrHistoryEventType::BookFileDeleted),
|
||||
"bookFileDeleted"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(ReadarrHistoryEventType::BookFileImported),
|
||||
"bookFileImported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(ReadarrHistoryEventType::BookFileRenamed),
|
||||
"bookFileRenamed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(ReadarrHistoryEventType::BookFileRetagged),
|
||||
"bookFileRetagged"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_readarr_task_name_display() {
|
||||
assert_str_eq!(
|
||||
@@ -1019,4 +1139,31 @@ mod tests {
|
||||
assert!(search_result.genres.is_empty());
|
||||
assert_none!(&search_result.ratings);
|
||||
}
|
||||
|
||||
fn deserialize_history_event_type(event_type: Value) -> ReadarrHistoryEventType {
|
||||
let history_item_json = json!({
|
||||
"id": 1,
|
||||
"authorId": 1,
|
||||
"bookId": 1,
|
||||
"sourceTitle": "Test Source Title",
|
||||
"date": "2024-01-01T00:00:00Z",
|
||||
"eventType": event_type
|
||||
});
|
||||
|
||||
serde_json::from_value::<ReadarrHistoryItem>(history_item_json)
|
||||
.unwrap()
|
||||
.event_type
|
||||
}
|
||||
|
||||
fn serialize_history_event_type(event_type: ReadarrHistoryEventType) -> String {
|
||||
let history_item = ReadarrHistoryItem {
|
||||
event_type,
|
||||
..ReadarrHistoryItem::default()
|
||||
};
|
||||
|
||||
serde_json::to_value(history_item).unwrap()["eventType"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
@@ -499,6 +499,7 @@ pub struct SonarrHistoryItem {
|
||||
pub quality: QualityWrapper,
|
||||
pub languages: Vec<Option<Language>>,
|
||||
pub date: DateTime<Utc>,
|
||||
#[serde(deserialize_with = "super::from_json_or_default")]
|
||||
pub event_type: SonarrHistoryEventType,
|
||||
pub data: SonarrHistoryData,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||
use serde_json::json;
|
||||
use serde_json::{Value, json};
|
||||
|
||||
use crate::models::{
|
||||
Serdeable,
|
||||
@@ -213,6 +213,102 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sonarr_history_event_type_deserialization() {
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("unknown")),
|
||||
SonarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("grabbed")),
|
||||
SonarrHistoryEventType::Grabbed
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("seriesFolderImported")),
|
||||
SonarrHistoryEventType::SeriesFolderImported
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("downloadFolderImported")),
|
||||
SonarrHistoryEventType::DownloadFolderImported
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("downloadFailed")),
|
||||
SonarrHistoryEventType::DownloadFailed
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("episodeFileDeleted")),
|
||||
SonarrHistoryEventType::EpisodeFileDeleted
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("episodeFileRenamed")),
|
||||
SonarrHistoryEventType::EpisodeFileRenamed
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("downloadIgnored")),
|
||||
SonarrHistoryEventType::DownloadIgnored
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sonarr_history_event_type_deserialization_falls_back_to_unknown() {
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!("episodeFileImportFailed")),
|
||||
SonarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!(2)),
|
||||
SonarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!(11)),
|
||||
SonarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!(null)),
|
||||
SonarrHistoryEventType::Unknown
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_history_event_type(json!({ "id": 2 })),
|
||||
SonarrHistoryEventType::Unknown
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sonarr_history_event_type_serialization() {
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(SonarrHistoryEventType::Unknown),
|
||||
"unknown"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(SonarrHistoryEventType::Grabbed),
|
||||
"grabbed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(SonarrHistoryEventType::SeriesFolderImported),
|
||||
"seriesFolderImported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(SonarrHistoryEventType::DownloadFolderImported),
|
||||
"downloadFolderImported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(SonarrHistoryEventType::DownloadFailed),
|
||||
"downloadFailed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(SonarrHistoryEventType::EpisodeFileDeleted),
|
||||
"episodeFileDeleted"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(SonarrHistoryEventType::EpisodeFileRenamed),
|
||||
"episodeFileRenamed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
serialize_history_event_type(SonarrHistoryEventType::DownloadIgnored),
|
||||
"downloadIgnored"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_task_name_display() {
|
||||
assert_str_eq!(
|
||||
@@ -601,4 +697,33 @@ mod tests {
|
||||
SonarrSerdeable::IndexerTestResults(indexer_test_results)
|
||||
);
|
||||
}
|
||||
|
||||
fn deserialize_history_event_type(event_type: Value) -> SonarrHistoryEventType {
|
||||
let history_item_json = json!({
|
||||
"id": 1,
|
||||
"sourceTitle": "Test Source Title",
|
||||
"episodeId": 1,
|
||||
"quality": { "quality": { "name": "HDTV - 1080p" } },
|
||||
"languages": [],
|
||||
"date": "2024-01-01T00:00:00Z",
|
||||
"eventType": event_type,
|
||||
"data": {}
|
||||
});
|
||||
|
||||
serde_json::from_value::<SonarrHistoryItem>(history_item_json)
|
||||
.unwrap()
|
||||
.event_type
|
||||
}
|
||||
|
||||
fn serialize_history_event_type(event_type: SonarrHistoryEventType) -> String {
|
||||
let history_item = SonarrHistoryItem {
|
||||
event_type,
|
||||
..SonarrHistoryItem::default()
|
||||
};
|
||||
|
||||
serde_json::to_value(history_item).unwrap()["eventType"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user