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
@@ -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