#![allow(clippy::indexing_slicing)]
use super::super::Queue;
use crate::testing_prelude::*;
use flat_db::Hash;
#[tokio::test]
async fn queue_set_adds_item() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_set_adds_item");
let queue = Queue::from_path(temp.to_path_buf());
let hash = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let item = QueueItem {
name: "Test Item".to_owned(),
path: PathBuf::from("/test/path.torrent"),
hash,
indexer: "red".to_owned(),
..QueueItem::default()
};
queue.set(item.clone()).await?;
let retrieved = queue.get(hash).await?;
assert!(retrieved.is_some());
let retrieved = retrieved.expect("should have item");
assert_eq!(retrieved.name, "Test Item");
assert_eq!(retrieved.indexer, "red");
Ok(())
}
#[tokio::test]
async fn queue_set_many_adds_items() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_set_many_adds_items");
let queue = Queue::from_path(temp.to_path_buf());
let hash1 = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let hash2 = Hash::<20>::from_string("0200000000000000000000000000000000000000")?;
let items = BTreeMap::from([
(
hash1,
QueueItem {
name: "Item One".to_owned(),
path: PathBuf::from("/test/one.torrent"),
hash: hash1,
indexer: "red".to_owned(),
..QueueItem::default()
},
),
(
hash2,
QueueItem {
name: "Item Two".to_owned(),
path: PathBuf::from("/test/two.torrent"),
hash: hash2,
indexer: "red".to_owned(),
..QueueItem::default()
},
),
]);
let added = queue.set_many(items, false).await?;
assert_eq!(added, 2);
assert!(queue.get(hash1).await?.is_some());
assert!(queue.get(hash2).await?.is_some());
Ok(())
}
#[tokio::test]
async fn queue_set_many_no_replace_skips_existing() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_set_many_no_replace");
let queue = Queue::from_path(temp.to_path_buf());
let hash = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let original = QueueItem {
name: "Original".to_owned(),
path: PathBuf::from("/test/original.torrent"),
hash,
indexer: "red".to_owned(),
..QueueItem::default()
};
queue.set(original).await?;
let updated = BTreeMap::from([(
hash,
QueueItem {
name: "Updated".to_owned(),
path: PathBuf::from("/test/updated.torrent"),
hash,
indexer: "red".to_owned(),
..QueueItem::default()
},
)]);
let added = queue.set_many(updated, false).await?;
assert_eq!(added, 0); let retrieved = queue.get(hash).await?.expect("should have item");
assert_eq!(retrieved.name, "Original"); Ok(())
}
#[tokio::test]
async fn queue_set_many_with_replace_overwrites() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_set_many_with_replace");
let queue = Queue::from_path(temp.to_path_buf());
let hash = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let original = QueueItem {
name: "Original".to_owned(),
path: PathBuf::from("/test/original.torrent"),
hash,
indexer: "red".to_owned(),
..QueueItem::default()
};
queue.set(original).await?;
let updated = BTreeMap::from([(
hash,
QueueItem {
name: "Updated".to_owned(),
path: PathBuf::from("/test/updated.torrent"),
hash,
indexer: "red".to_owned(),
..QueueItem::default()
},
)]);
let added = queue.set_many(updated, true).await?;
assert_eq!(added, 1); let retrieved = queue.get(hash).await?.expect("should have item");
assert_eq!(retrieved.name, "Updated"); Ok(())
}
#[tokio::test]
async fn queue_get_all_returns_all_items() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_get_all");
let queue = Queue::from_path(temp.to_path_buf());
let hash1 = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let hash2 = Hash::<20>::from_string("ff00000000000000000000000000000000000000")?;
queue
.set(QueueItem {
name: "Item 1".to_owned(),
hash: hash1,
path: PathBuf::new(),
indexer: "red".to_owned(),
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "Item 2".to_owned(),
hash: hash2,
path: PathBuf::new(),
indexer: "red".to_owned(),
..QueueItem::default()
})
.await?;
let all = queue.get_all().await?;
assert_eq!(all.len(), 2);
Ok(())
}
#[tokio::test]
async fn queue_remove_removes_existing_item() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_remove_existing");
let queue = Queue::from_path(temp.to_path_buf());
let hash = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let item = QueueItem {
name: "Test Item".to_owned(),
path: PathBuf::from("/test/path.torrent"),
hash,
indexer: "red".to_owned(),
..QueueItem::default()
};
queue.set(item).await?;
assert!(queue.get(hash).await?.is_some());
let removed = queue.remove(hash).await?;
assert!(removed.is_some());
let removed = removed.expect("should have removed item");
assert_eq!(removed.name, "Test Item");
assert!(queue.get(hash).await?.is_none());
Ok(())
}
#[tokio::test]
async fn queue_remove_nonexistent_returns_none() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_remove_nonexistent");
let queue = Queue::from_path(temp.to_path_buf());
let hash = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let removed = queue.remove(hash).await?;
assert!(removed.is_none());
Ok(())
}
#[tokio::test]
async fn queue_remove_only_affects_specified_item() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_remove_specific");
let queue = Queue::from_path(temp.to_path_buf());
let hash1 = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let hash2 = Hash::<20>::from_string("0200000000000000000000000000000000000000")?;
queue
.set(QueueItem {
name: "Item One".to_owned(),
path: PathBuf::from("/test/one.torrent"),
hash: hash1,
indexer: "red".to_owned(),
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "Item Two".to_owned(),
path: PathBuf::from("/test/two.torrent"),
hash: hash2,
indexer: "red".to_owned(),
..QueueItem::default()
})
.await?;
let removed = queue.remove(hash1).await?;
assert!(removed.is_some());
assert!(queue.get(hash1).await?.is_none()); assert!(queue.get(hash2).await?.is_some()); Ok(())
}
#[tokio::test]
#[allow(deprecated)]
async fn queue_get_unprocessed() -> Result<(), TestError> {
let new = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let verified = Hash::<20>::from_string("0200000000000000000000000000000000000000")?;
let not_verified = Hash::<20>::from_string("0300000000000000000000000000000000000000")?;
let transcoded = Hash::<20>::from_string("0400000000000000000000000000000000000000")?;
let not_transcoded = Hash::<20>::from_string("0500000000000000000000000000000000000000")?;
let uploaded = Hash::<20>::from_string("0600000000000000000000000000000000000000")?;
let not_uploaded = Hash::<20>::from_string("0700000000000000000000000000000000000000")?;
let temp = TempDirectory::create("queue_get_unprocessed");
let queue = Queue::from_path(temp.to_path_buf());
queue
.set(QueueItem {
name: "NEW".to_owned(),
path: PathBuf::new(),
hash: new,
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "VERIFIED".to_owned(),
path: PathBuf::new(),
hash: verified,
verify: Some(VerifyStatus::verified()),
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "VERIFY FAILURE".to_owned(),
path: PathBuf::new(),
hash: not_verified,
verify: Some(VerifyStatus::from_issue(SourceIssue::IdError {
details: "missing id".to_owned(),
})),
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "TRANSCODED".to_owned(),
path: PathBuf::new(),
hash: transcoded,
verify: Some(VerifyStatus::verified()),
transcode: Some(TranscodeStatus {
success: true,
completed: TimeStamp::now(),
formats: None,
error: None,
}),
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "TRANSCODE FAILURE".to_owned(),
path: PathBuf::new(),
hash: not_transcoded,
verify: Some(VerifyStatus::verified()),
transcode: Some(TranscodeStatus {
success: false,
completed: TimeStamp::now(),
formats: None,
error: None,
}),
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "UPLOADED".to_owned(),
path: PathBuf::new(),
hash: uploaded,
verify: Some(VerifyStatus::verified()),
transcode: Some(TranscodeStatus {
success: true,
completed: TimeStamp::now(),
formats: None,
error: None,
}),
upload: Some(UploadStatus {
success: true,
completed: TimeStamp::now(),
formats: None,
errors: None,
}),
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "UPLOAD FAILURE".to_owned(),
path: PathBuf::new(),
hash: not_uploaded,
verify: Some(VerifyStatus::verified()),
transcode: Some(TranscodeStatus {
success: true,
completed: TimeStamp::now(),
formats: None,
error: None,
}),
upload: Some(UploadStatus {
success: false,
completed: TimeStamp::now(),
formats: None,
errors: None,
}),
..QueueItem::default()
})
.await?;
let verify = queue
.get_unprocessed(String::new(), false, false, false)
.await?;
assert_eq!(verify, vec![new]);
let transcode = queue
.get_unprocessed(String::new(), true, false, false)
.await?;
assert_eq!(transcode, vec![new, verified]);
let transcode_with_failed = queue
.get_unprocessed(String::new(), true, false, true)
.await?;
assert_eq!(transcode_with_failed, vec![new, not_transcoded, verified]);
let upload = queue
.get_unprocessed(String::new(), true, true, false)
.await?;
assert_eq!(upload, vec![new, transcoded, verified]);
let upload_with_failed = queue
.get_unprocessed(String::new(), true, true, true)
.await?;
assert_eq!(
upload_with_failed,
vec![new, not_transcoded, transcoded, verified]
);
Ok(())
}
#[tokio::test]
async fn queue_get_unprocessed_filters_by_indexer() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_filter_indexer");
let queue = Queue::from_path(temp.to_path_buf());
let red_hash = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let ops_hash = Hash::<20>::from_string("0200000000000000000000000000000000000000")?;
queue
.set(QueueItem {
name: "RED Item".to_owned(),
path: PathBuf::new(),
hash: red_hash,
indexer: "red".to_owned(),
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "OPS Item".to_owned(),
path: PathBuf::new(),
hash: ops_hash,
indexer: "ops".to_owned(),
..QueueItem::default()
})
.await?;
let red_items = queue
.get_unprocessed("red".to_owned(), false, false, false)
.await?;
let ops_items = queue
.get_unprocessed("ops".to_owned(), false, false, false)
.await?;
assert_eq!(red_items.len(), 1);
assert_eq!(red_items[0], red_hash);
assert_eq!(ops_items.len(), 1);
assert_eq!(ops_items[0], ops_hash);
Ok(())
}
#[tokio::test]
async fn queue_get_unprocessed_red_includes_pth() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_red_includes_pth");
let queue = Queue::from_path(temp.to_path_buf());
let red_hash = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let pth_hash = Hash::<20>::from_string("0200000000000000000000000000000000000000")?;
queue
.set(QueueItem {
name: "RED Item".to_owned(),
path: PathBuf::new(),
hash: red_hash,
indexer: "red".to_owned(),
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "PTH Item".to_owned(),
path: PathBuf::new(),
hash: pth_hash,
indexer: "pth".to_owned(),
..QueueItem::default()
})
.await?;
let items = queue
.get_unprocessed("red".to_owned(), false, false, false)
.await?;
assert_eq!(items.len(), 2);
Ok(())
}
#[tokio::test]
async fn queue_get_unprocessed_sorts_by_name() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_sorts_by_name");
let queue = Queue::from_path(temp.to_path_buf());
let hash_z = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let hash_a = Hash::<20>::from_string("0200000000000000000000000000000000000000")?;
let hash_m = Hash::<20>::from_string("0300000000000000000000000000000000000000")?;
queue
.set(QueueItem {
name: "Zebra Album".to_owned(),
path: PathBuf::new(),
hash: hash_z,
indexer: "red".to_owned(),
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "Apple Album".to_owned(),
path: PathBuf::new(),
hash: hash_a,
indexer: "red".to_owned(),
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "Mango Album".to_owned(),
path: PathBuf::new(),
hash: hash_m,
indexer: "red".to_owned(),
..QueueItem::default()
})
.await?;
let items = queue
.get_unprocessed("red".to_owned(), false, false, false)
.await?;
assert_eq!(items.len(), 3);
assert_eq!(items[0], hash_a); assert_eq!(items[1], hash_m); assert_eq!(items[2], hash_z); Ok(())
}
#[tokio::test]
async fn queue_get_unprocessed_excludes_uploaded() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_excludes_uploaded");
let queue = Queue::from_path(temp.to_path_buf());
let uploaded_hash = Hash::<20>::from_string("0100000000000000000000000000000000000000")?;
let pending_hash = Hash::<20>::from_string("0200000000000000000000000000000000000000")?;
queue
.set(QueueItem {
name: "Uploaded Item".to_owned(),
path: PathBuf::new(),
hash: uploaded_hash,
indexer: "red".to_owned(),
upload: Some(UploadStatus {
success: true,
completed: TimeStamp::now(),
formats: None,
errors: None,
}),
..QueueItem::default()
})
.await?;
queue
.set(QueueItem {
name: "Pending Item".to_owned(),
path: PathBuf::new(),
hash: pending_hash,
indexer: "red".to_owned(),
..QueueItem::default()
})
.await?;
let items = queue
.get_unprocessed("red".to_owned(), true, true, false)
.await?;
assert_eq!(items.len(), 1);
assert_eq!(items[0], pending_hash);
Ok(())
}
#[tokio::test]
async fn queue_get_unprocessed_empty_queue() -> Result<(), TestError> {
let temp = TempDirectory::create("queue_empty");
let queue = Queue::from_path(temp.to_path_buf());
let items = queue
.get_unprocessed("red".to_owned(), true, true, false)
.await?;
assert!(items.is_empty());
Ok(())
}