fix(radarr): model the download status as a DownloadStatus enum
Radarr was the only tree still holding DownloadRecord.status as a bare String and comparing it against literals. It now carries its own DownloadStatus enum, shaped exactly like the Sonarr, Lidarr and Readarr copies, and is guarded with from_json_or_default so an unrecognised status degrades to Unknown instead of failing the whole queue fetch. The row-style decorator and get_movie_status compare against the enum variants. The status cell is never rendered in the Radarr tree, so no snapshot changes; the CLI JSON output is unchanged for every real value since the enum serializes to the same camelCase strings.
This commit is contained in:
8 files changed
+126
-29
No files matched your search
@@ -4,8 +4,8 @@ pub(in crate::handlers::radarr_handlers) mod utils {
|
||||
use crate::models::HorizontallyScrollableText;
|
||||
use crate::models::radarr_models::{
|
||||
AddMovieBody, AddMovieOptions, AddMovieSearchResult, Collection, CollectionMovie,
|
||||
DownloadRecord, IndexerSettings, MediaInfo, MinimumAvailability, Movie, MovieCollection,
|
||||
MovieFile, MovieMonitor, RadarrRelease, Rating, RatingsList,
|
||||
DownloadRecord, DownloadStatus, IndexerSettings, MediaInfo, MinimumAvailability, Movie,
|
||||
MovieCollection, MovieFile, MovieMonitor, RadarrRelease, Rating, RatingsList,
|
||||
};
|
||||
use crate::models::servarr_models::{
|
||||
Indexer, IndexerField, Language, Quality, QualityWrapper, RootFolder,
|
||||
@@ -407,7 +407,7 @@ pub(in crate::handlers::radarr_handlers) mod utils {
|
||||
pub fn download_record() -> DownloadRecord {
|
||||
DownloadRecord {
|
||||
title: "Test Download Title".to_owned(),
|
||||
status: "downloading".to_owned(),
|
||||
status: DownloadStatus::Downloading,
|
||||
id: 1,
|
||||
movie_id: 1,
|
||||
size: 3543348019,
|
||||
|
||||
@@ -154,7 +154,8 @@ pub struct DeleteMovieParams {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DownloadRecord {
|
||||
pub title: String,
|
||||
pub status: String,
|
||||
#[serde(deserialize_with = "super::from_json_or_default")]
|
||||
pub status: DownloadStatus,
|
||||
#[serde(deserialize_with = "super::from_i64")]
|
||||
pub id: i64,
|
||||
#[serde(deserialize_with = "super::from_i64")]
|
||||
@@ -169,6 +170,36 @@ pub struct DownloadRecord {
|
||||
pub download_client: String,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Default,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
EnumIter,
|
||||
Display,
|
||||
EnumDisplayStyle,
|
||||
)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[strum(serialize_all = "camelCase")]
|
||||
pub enum DownloadStatus {
|
||||
#[default]
|
||||
Unknown,
|
||||
Queued,
|
||||
Paused,
|
||||
Downloading,
|
||||
Completed,
|
||||
Failed,
|
||||
Warning,
|
||||
Delay,
|
||||
#[display_style(name = "Download Client Unavailable")]
|
||||
DownloadClientUnavailable,
|
||||
Fallback,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DownloadsResponse {
|
||||
|
||||
@@ -11,16 +11,16 @@ mod tests {
|
||||
Serdeable,
|
||||
radarr_models::{
|
||||
AddMovieSearchResult, BlocklistItem, BlocklistResponse, Collection, Credit, CreditType,
|
||||
DiskSpace, DownloadRecord, DownloadsResponse, Indexer, IndexerSettings, IndexerTestResult,
|
||||
MinimumAvailability, Movie, MovieHistoryItem, MovieMonitor, QualityProfile, RadarrRelease,
|
||||
RadarrSerdeable, RadarrTask, RadarrTaskName, Tag, Update,
|
||||
DiskSpace, DownloadRecord, DownloadStatus, DownloadsResponse, Indexer, IndexerSettings,
|
||||
IndexerTestResult, MinimumAvailability, Movie, MovieHistoryItem, MovieMonitor,
|
||||
QualityProfile, RadarrRelease, RadarrSerdeable, RadarrTask, RadarrTaskName, Tag, Update,
|
||||
},
|
||||
servarr_models::{
|
||||
HostConfig, Log, LogResponse, QueueEvent, RootFolder, SecurityConfig, SystemStatus,
|
||||
},
|
||||
};
|
||||
use crate::network::radarr_network::radarr_network_test_utils::test_utils::{
|
||||
MOVIE_JSON, collection, crew_credit, task,
|
||||
MOVIE_JSON, collection, crew_credit, download_record, task,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -70,6 +70,40 @@ mod tests {
|
||||
assert_str_eq!(MovieMonitor::None.to_display_str(), "None");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_download_status_display() {
|
||||
assert_str_eq!(DownloadStatus::Unknown.to_string(), "unknown");
|
||||
assert_str_eq!(DownloadStatus::Queued.to_string(), "queued");
|
||||
assert_str_eq!(DownloadStatus::Paused.to_string(), "paused");
|
||||
assert_str_eq!(DownloadStatus::Downloading.to_string(), "downloading");
|
||||
assert_str_eq!(DownloadStatus::Completed.to_string(), "completed");
|
||||
assert_str_eq!(DownloadStatus::Failed.to_string(), "failed");
|
||||
assert_str_eq!(DownloadStatus::Warning.to_string(), "warning");
|
||||
assert_str_eq!(DownloadStatus::Delay.to_string(), "delay");
|
||||
assert_str_eq!(
|
||||
DownloadStatus::DownloadClientUnavailable.to_string(),
|
||||
"downloadClientUnavailable"
|
||||
);
|
||||
assert_str_eq!(DownloadStatus::Fallback.to_string(), "fallback");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_download_status_to_display_str() {
|
||||
assert_str_eq!(DownloadStatus::Unknown.to_display_str(), "Unknown");
|
||||
assert_str_eq!(DownloadStatus::Queued.to_display_str(), "Queued");
|
||||
assert_str_eq!(DownloadStatus::Paused.to_display_str(), "Paused");
|
||||
assert_str_eq!(DownloadStatus::Downloading.to_display_str(), "Downloading");
|
||||
assert_str_eq!(DownloadStatus::Completed.to_display_str(), "Completed");
|
||||
assert_str_eq!(DownloadStatus::Failed.to_display_str(), "Failed");
|
||||
assert_str_eq!(DownloadStatus::Warning.to_display_str(), "Warning");
|
||||
assert_str_eq!(DownloadStatus::Delay.to_display_str(), "Delay");
|
||||
assert_str_eq!(
|
||||
DownloadStatus::DownloadClientUnavailable.to_display_str(),
|
||||
"Download Client Unavailable"
|
||||
);
|
||||
assert_str_eq!(DownloadStatus::Fallback.to_display_str(), "Fallback");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_radarr_history_event_type_display() {
|
||||
assert_str_eq!(RadarrHistoryEventType::Unknown.to_string(), "unknown");
|
||||
@@ -230,7 +264,7 @@ mod tests {
|
||||
fn test_download_record_default_indexer_value() {
|
||||
let json = r#"{
|
||||
"title": "test",
|
||||
"status": "test",
|
||||
"status": "downloading",
|
||||
"id": 0,
|
||||
"movieId": 0,
|
||||
"size": 0,
|
||||
@@ -239,7 +273,7 @@ mod tests {
|
||||
}"#;
|
||||
let expected_record = DownloadRecord {
|
||||
title: "test".to_owned(),
|
||||
status: "test".to_owned(),
|
||||
status: DownloadStatus::Downloading,
|
||||
id: 0,
|
||||
movie_id: 0,
|
||||
size: 0,
|
||||
@@ -693,6 +727,24 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_download_record_status_deserialization_falls_back_to_default() {
|
||||
let download_record_json = serde_json::to_string(&download_record()).unwrap();
|
||||
let expected = DownloadRecord {
|
||||
status: DownloadStatus::default(),
|
||||
..download_record()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
deserialize_with_field::<DownloadRecord>(&download_record_json, "status", json!(2)),
|
||||
expected
|
||||
);
|
||||
assert_eq!(
|
||||
deserialize_with_field::<DownloadRecord>(&download_record_json, "status", json!("notAThing")),
|
||||
expected
|
||||
);
|
||||
}
|
||||
|
||||
fn deserialize_with_field<T: DeserializeOwned>(json: &str, field: &str, value: Value) -> T {
|
||||
let mut fixture_json: Value = serde_json::from_str(json).unwrap();
|
||||
fixture_json[field] = value;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::models::radarr_models::{
|
||||
AddMovieBody, AddMovieSearchResult, Credit, CreditType, DeleteMovieParams, DownloadRecord,
|
||||
EditMovieParams, Movie, MovieCommandBody, MovieHistoryItem, RadarrRelease,
|
||||
DownloadStatus, EditMovieParams, Movie, MovieCommandBody, MovieHistoryItem, RadarrRelease,
|
||||
RadarrReleaseDownloadBody,
|
||||
};
|
||||
use crate::models::servarr_data::Notification;
|
||||
@@ -664,11 +664,11 @@ pub(in crate::network::radarr_network::library) fn get_movie_status(
|
||||
.iter()
|
||||
.find(|&download| download.movie_id == movie_id)
|
||||
{
|
||||
if download.status == "downloading" {
|
||||
if download.status == DownloadStatus::Downloading {
|
||||
return "Downloading".to_owned();
|
||||
}
|
||||
|
||||
if download.status == "completed" {
|
||||
if download.status == DownloadStatus::Completed {
|
||||
return "Awaiting Import".to_owned();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::models::radarr_models::{
|
||||
AddMovieBody, AddMovieOptions, Credit, DeleteMovieParams, DownloadRecord, EditMovieParams,
|
||||
MinimumAvailability, Movie, MovieHistoryItem, MovieMonitor, RadarrReleaseDownloadBody,
|
||||
AddMovieBody, AddMovieOptions, Credit, DeleteMovieParams, DownloadRecord, DownloadStatus,
|
||||
EditMovieParams, MinimumAvailability, Movie, MovieHistoryItem, MovieMonitor,
|
||||
RadarrReleaseDownloadBody,
|
||||
};
|
||||
use crate::models::servarr_data::Notification;
|
||||
use crate::models::servarr_data::radarr::modals::MovieDetailsModal;
|
||||
@@ -1199,7 +1200,7 @@ mod tests {
|
||||
false,
|
||||
&[DownloadRecord {
|
||||
movie_id: 1,
|
||||
status: "downloading".to_owned(),
|
||||
status: DownloadStatus::Downloading,
|
||||
..DownloadRecord::default()
|
||||
}],
|
||||
1
|
||||
@@ -1215,7 +1216,7 @@ mod tests {
|
||||
false,
|
||||
&[DownloadRecord {
|
||||
movie_id: 1,
|
||||
status: "completed".to_owned(),
|
||||
status: DownloadStatus::Completed,
|
||||
..DownloadRecord::default()
|
||||
}],
|
||||
1
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
pub mod test_utils {
|
||||
use crate::models::radarr_models::{
|
||||
AddMovieSearchResult, BlocklistItem, BlocklistItemMovie, Collection, CollectionMovie, Credit,
|
||||
CreditType, DownloadRecord, DownloadsResponse, IndexerSettings, MediaInfo, MinimumAvailability,
|
||||
Movie, MovieCollection, MovieFile, MovieHistoryItem, RadarrHistoryData, RadarrHistoryEventType,
|
||||
RadarrHistoryItem, RadarrRelease, RadarrTask, RadarrTaskName, Rating, RatingsList,
|
||||
CreditType, DownloadRecord, DownloadStatus, DownloadsResponse, IndexerSettings, MediaInfo,
|
||||
MinimumAvailability, Movie, MovieCollection, MovieFile, MovieHistoryItem, RadarrHistoryData,
|
||||
RadarrHistoryEventType, RadarrHistoryItem, RadarrRelease, RadarrTask, RadarrTaskName, Rating,
|
||||
RatingsList,
|
||||
};
|
||||
use crate::models::servarr_models::{
|
||||
Indexer, IndexerField, Language, Quality, QualityWrapper, RootFolder,
|
||||
@@ -339,7 +340,7 @@ pub mod test_utils {
|
||||
pub fn download_record() -> DownloadRecord {
|
||||
DownloadRecord {
|
||||
title: "Test Download Title".to_owned(),
|
||||
status: "downloading".to_owned(),
|
||||
status: DownloadStatus::Downloading,
|
||||
id: 1,
|
||||
movie_id: 1,
|
||||
size: 3543348019,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::app::App;
|
||||
use crate::logos::RADARR_LOGO;
|
||||
use crate::models::Route;
|
||||
use crate::models::radarr_models::{DownloadRecord, Movie};
|
||||
use crate::models::radarr_models::{DownloadRecord, DownloadStatus, Movie};
|
||||
use crate::models::servarr_data::radarr::radarr_data::RadarrData;
|
||||
use crate::models::servarr_models::{DiskSpace, RootFolder};
|
||||
use crate::ui::DrawUi;
|
||||
@@ -230,11 +230,11 @@ fn decorate_with_row_style<'a>(
|
||||
.iter()
|
||||
.find(|&download| download.movie_id == movie.id)
|
||||
{
|
||||
if download.status == "downloading" {
|
||||
if download.status == DownloadStatus::Downloading {
|
||||
return row.downloading();
|
||||
}
|
||||
|
||||
if download.status == "completed" {
|
||||
if download.status == DownloadStatus::Completed {
|
||||
return row.awaiting_import();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::models::radarr_models::{DownloadRecord, Movie};
|
||||
use crate::models::radarr_models::{DownloadRecord, DownloadStatus, Movie};
|
||||
use pretty_assertions::assert_eq;
|
||||
use ratatui::widgets::{Cell, Row};
|
||||
use rstest::rstest;
|
||||
@@ -50,8 +50,20 @@ mod tests {
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(false, Some("downloading"), false, "", RowStyle::Downloading)]
|
||||
#[case(false, Some("completed"), false, "", RowStyle::AwaitingImport)]
|
||||
#[case(
|
||||
false,
|
||||
Some(DownloadStatus::Downloading),
|
||||
false,
|
||||
"",
|
||||
RowStyle::Downloading
|
||||
)]
|
||||
#[case(
|
||||
false,
|
||||
Some(DownloadStatus::Completed),
|
||||
false,
|
||||
"",
|
||||
RowStyle::AwaitingImport
|
||||
)]
|
||||
#[case(false, None, false, "", RowStyle::UnmonitoredMissing)]
|
||||
#[case(false, None, true, "", RowStyle::Unreleased)]
|
||||
#[case(false, None, true, "released", RowStyle::Missing)]
|
||||
@@ -59,7 +71,7 @@ mod tests {
|
||||
#[case(true, None, true, "", RowStyle::Downloaded)]
|
||||
fn test_decorate_with_row_style(
|
||||
#[case] has_file: bool,
|
||||
#[case] download_status: Option<&str>,
|
||||
#[case] download_status: Option<DownloadStatus>,
|
||||
#[case] is_monitored: bool,
|
||||
#[case] movie_status: String,
|
||||
#[case] expected_style: RowStyle,
|
||||
@@ -67,7 +79,7 @@ mod tests {
|
||||
let downloads_vec = if let Some(download_status) = download_status {
|
||||
vec![DownloadRecord {
|
||||
movie_id: 1,
|
||||
status: download_status.to_owned(),
|
||||
status: download_status,
|
||||
..DownloadRecord::default()
|
||||
}]
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user