#[tokio::test]
async fn all_groups_pinned_deletes_nothing() {
let g = crate::Global {
config: crate::Config {
categories_allowed: ["ok".into()].into(),
target_free: 1_000_000,
..crate::Config::empty()
},
now: std::time::SystemTime::UNIX_EPOCH,
qbt: crate::QbtMock {
torrents: vec![crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 60 },
crate::TorrentFile { size: 40 },
],
torrent: crate::Torrent {
category: "blocked".into(),
hash: "1111111111111111111111111111111111111111".parse().unwrap(),
selected_size: 100,
total_size: 100,
..crate::Torrent::zero()
},
}],
..Default::default()
},
};
crate::cmd_clean(&g, false).await.unwrap();
assert!(g.qbt.deleted().is_empty());
}
#[tokio::test]
async fn copies_weight_groups_two_torrents() {
let g = crate::Global {
config: crate::Config {
categories_allowed: ["ok".into()].into(),
copies_weight: 1.0,
target_free: 1,
..crate::Config::empty()
},
now: std::time::SystemTime::UNIX_EPOCH,
qbt: crate::QbtMock {
torrents: vec![
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 60 },
crate::TorrentFile { size: 40 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "1111111111111111111111111111111111111111".parse().unwrap(),
selected_size: 100,
total_size: 100,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 60 },
crate::TorrentFile { size: 40 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "2222222222222222222222222222222222222222".parse().unwrap(),
selected_size: 100,
total_size: 100,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 120 },
crate::TorrentFile { size: 80 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "3333333333333333333333333333333333333333".parse().unwrap(),
selected_size: 200,
total_size: 200,
..crate::Torrent::zero()
},
},
],
..Default::default()
},
};
crate::cmd_clean(&g, false).await.unwrap();
let mut deleted = g.qbt.deleted();
deleted.sort_unstable();
assert_eq!(deleted, vec![
"1111111111111111111111111111111111111111".parse().unwrap(),
"2222222222222222222222222222222222222222".parse().unwrap(),
]);
}
#[tokio::test]
async fn delete_limit_data_stops_early() {
let g = crate::Global {
config: crate::Config {
categories_allowed: ["ok".into()].into(),
delete_limit_data: Some(150),
size_weight: 1.0,
target_free: 1_000_000,
..crate::Config::empty()
},
now: std::time::SystemTime::UNIX_EPOCH,
qbt: crate::QbtMock {
torrents: vec![
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 60 },
crate::TorrentFile { size: 40 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "1111111111111111111111111111111111111111".parse().unwrap(),
selected_size: 100,
total_size: 100,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 55 },
crate::TorrentFile { size: 35 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "2222222222222222222222222222222222222222".parse().unwrap(),
selected_size: 90,
total_size: 90,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 50 },
crate::TorrentFile { size: 30 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "3333333333333333333333333333333333333333".parse().unwrap(),
selected_size: 80,
total_size: 80,
..crate::Torrent::zero()
},
},
],
..Default::default()
},
};
crate::cmd_clean(&g, false).await.unwrap();
assert_eq!(g.qbt.deleted(), vec![
"1111111111111111111111111111111111111111".parse().unwrap(),
"2222222222222222222222222222222222222222".parse().unwrap(),
]);
}
#[tokio::test]
async fn delete_limit_groups_stops_early() {
let g = crate::Global {
config: crate::Config {
categories_allowed: ["ok".into()].into(),
delete_limit_groups: Some(std::num::NonZeroUsize::new(2).unwrap()),
size_weight: 1.0,
target_free: 1_000_000,
..crate::Config::empty()
},
now: std::time::SystemTime::UNIX_EPOCH,
qbt: crate::QbtMock {
torrents: vec![
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 60 },
crate::TorrentFile { size: 40 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "1111111111111111111111111111111111111111".parse().unwrap(),
selected_size: 100,
total_size: 100,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 55 },
crate::TorrentFile { size: 35 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "2222222222222222222222222222222222222222".parse().unwrap(),
selected_size: 90,
total_size: 90,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 50 },
crate::TorrentFile { size: 30 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "3333333333333333333333333333333333333333".parse().unwrap(),
selected_size: 80,
total_size: 80,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 45 },
crate::TorrentFile { size: 25 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "4444444444444444444444444444444444444444".parse().unwrap(),
selected_size: 70,
total_size: 70,
..crate::Torrent::zero()
},
},
],
..Default::default()
},
};
crate::cmd_clean(&g, false).await.unwrap();
assert_eq!(g.qbt.deleted(), vec![
"1111111111111111111111111111111111111111".parse().unwrap(),
"2222222222222222222222222222222222222222".parse().unwrap(),
]);
}
#[tokio::test]
async fn deletes_everything_when_target_unreachable() {
let g = crate::Global {
config: crate::Config {
categories_allowed: ["ok".into()].into(),
size_weight: 1.0,
target_free: 1_000_000,
..crate::Config::empty()
},
now: std::time::SystemTime::UNIX_EPOCH,
qbt: crate::QbtMock {
torrents: vec![
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 60 },
crate::TorrentFile { size: 40 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "1111111111111111111111111111111111111111".parse().unwrap(),
selected_size: 100,
total_size: 100,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 30 },
crate::TorrentFile { size: 20 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "2222222222222222222222222222222222222222".parse().unwrap(),
selected_size: 50,
total_size: 50,
..crate::Torrent::zero()
},
},
],
..Default::default()
},
};
crate::cmd_clean(&g, false).await.unwrap();
assert_eq!(g.qbt.deleted(), vec![
"1111111111111111111111111111111111111111".parse().unwrap(),
"2222222222222222222222222222222222222222".parse().unwrap(),
]);
}
#[tokio::test]
async fn deletes_highest_ranked_until_target_met() {
let g = crate::Global {
config: crate::Config {
categories_allowed: ["ok".into()].into(),
size_weight: 1.0,
target_free: 120,
..crate::Config::empty()
},
now: std::time::SystemTime::UNIX_EPOCH,
qbt: crate::QbtMock {
torrents: vec![
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 60 },
crate::TorrentFile { size: 40 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "1111111111111111111111111111111111111111".parse().unwrap(),
selected_size: 100,
total_size: 100,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 30 },
crate::TorrentFile { size: 20 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "2222222222222222222222222222222222222222".parse().unwrap(),
selected_size: 50,
total_size: 50,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 20 },
crate::TorrentFile { size: 10 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "3333333333333333333333333333333333333333".parse().unwrap(),
selected_size: 30,
total_size: 30,
..crate::Torrent::zero()
},
},
],
..Default::default()
},
};
crate::cmd_clean(&g, false).await.unwrap();
assert_eq!(g.qbt.deleted(), vec![
"1111111111111111111111111111111111111111".parse().unwrap(),
"2222222222222222222222222222222222222222".parse().unwrap(),
]);
}
#[tokio::test]
async fn dry_run_deletes_nothing() {
let g = crate::Global {
config: crate::Config {
categories_allowed: ["ok".into()].into(),
size_weight: 1.0,
target_free: 1_000_000,
..crate::Config::empty()
},
now: std::time::SystemTime::UNIX_EPOCH,
qbt: crate::QbtMock {
torrents: vec![
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 60 },
crate::TorrentFile { size: 40 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "1111111111111111111111111111111111111111".parse().unwrap(),
selected_size: 100,
total_size: 100,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 30 },
crate::TorrentFile { size: 20 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "2222222222222222222222222222222222222222".parse().unwrap(),
selected_size: 50,
total_size: 50,
..crate::Torrent::zero()
},
},
],
..Default::default()
},
};
crate::cmd_clean(&g, true).await.unwrap();
assert!(g.qbt.deleted().is_empty());
}
#[tokio::test]
async fn nothing_to_do_when_free_space_above_target() {
let g = crate::Global {
config: crate::Config {
categories_allowed: ["ok".into()].into(),
target_free: 100,
..crate::Config::empty()
},
now: std::time::SystemTime::UNIX_EPOCH,
qbt: crate::QbtMock {
free_space: 200,
torrents: vec![crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 30 },
crate::TorrentFile { size: 20 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "1111111111111111111111111111111111111111".parse().unwrap(),
selected_size: 50,
total_size: 50,
..crate::Torrent::zero()
},
}],
..Default::default()
},
};
crate::cmd_clean(&g, false).await.unwrap();
assert!(g.qbt.deleted().is_empty());
}
#[tokio::test]
async fn seeder_count_weight_orders_deletion() {
let g = crate::Global {
config: crate::Config {
categories_allowed: ["ok".into()].into(),
seeder_count_weight: 1.0,
target_free: 1,
..crate::Config::empty()
},
now: std::time::SystemTime::UNIX_EPOCH,
qbt: crate::QbtMock {
torrents: vec![
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 100 },
crate::TorrentFile { size: 10 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "1111111111111111111111111111111111111111".parse().unwrap(),
seeders: 5,
selected_size: 110,
total_size: 110,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 120 },
crate::TorrentFile { size: 80 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "2222222222222222222222222222222222222222".parse().unwrap(),
seeders: 1,
selected_size: 200,
total_size: 200,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 100 },
crate::TorrentFile { size: 20 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "3333333333333333333333333333333333333333".parse().unwrap(),
seeders: 9,
selected_size: 120,
total_size: 120,
..crate::Torrent::zero()
},
},
],
..Default::default()
},
};
crate::cmd_clean(&g, false).await.unwrap();
assert_eq!(g.qbt.deleted(), vec![
"1111111111111111111111111111111111111111".parse().unwrap(),
"3333333333333333333333333333333333333333".parse().unwrap(),
]);
}
#[tokio::test]
async fn small_files_excluded_from_group_id() {
let g = crate::Global {
config: crate::Config {
categories_allowed: ["ok".into()].into(),
copies_weight: 1.0,
target_free: 1,
..crate::Config::empty()
},
now: std::time::SystemTime::UNIX_EPOCH,
qbt: crate::QbtMock {
torrents: vec![
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 100 },
crate::TorrentFile { size: 100 },
crate::TorrentFile { size: 5 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "1111111111111111111111111111111111111111".parse().unwrap(),
selected_size: 205,
total_size: 205,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 100 },
crate::TorrentFile { size: 100 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "2222222222222222222222222222222222222222".parse().unwrap(),
selected_size: 200,
total_size: 200,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 300 },
crate::TorrentFile { size: 300 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "3333333333333333333333333333333333333333".parse().unwrap(),
selected_size: 600,
total_size: 600,
..crate::Torrent::zero()
},
},
],
..Default::default()
},
};
crate::cmd_clean(&g, false).await.unwrap();
let mut deleted = g.qbt.deleted();
deleted.sort_unstable();
assert_eq!(deleted, vec![
"1111111111111111111111111111111111111111".parse().unwrap(),
"2222222222222222222222222222222222222222".parse().unwrap(),
]);
}
#[tokio::test]
async fn pinned_by_explicit_rule_never_deleted() {
let g = crate::Global {
config: crate::Config {
categories_allowed: ["keep".into(), "ok".into()].into(),
size_weight: 1.0,
target_free: 1_000_000,
rules: vec![crate::Rule {
match_: crate::Match {
categories: Some(["keep".into()].into()),
..Default::default()
},
pin: Some(true),
..Default::default()
}],
..crate::Config::empty()
},
now: std::time::SystemTime::UNIX_EPOCH,
qbt: crate::QbtMock {
torrents: vec![
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 600 },
crate::TorrentFile { size: 400 },
],
torrent: crate::Torrent {
category: "keep".into(),
hash: "1111111111111111111111111111111111111111".parse().unwrap(),
selected_size: 1000,
total_size: 1000,
..crate::Torrent::zero()
},
},
crate::MockTorrent {
files: vec![
crate::TorrentFile { size: 60 },
crate::TorrentFile { size: 40 },
],
torrent: crate::Torrent {
category: "ok".into(),
hash: "2222222222222222222222222222222222222222".parse().unwrap(),
selected_size: 100,
total_size: 100,
..crate::Torrent::zero()
},
},
],
..Default::default()
},
};
crate::cmd_clean(&g, false).await.unwrap();
assert_eq!(g.qbt.deleted(), vec![
"2222222222222222222222222222222222222222".parse().unwrap(),
]);
}