Transmission RPC client (#52)
ci / web (push) Successful in 7s
ci / rust (push) Successful in 1m22s
e2e / e2e (push) Successful in 2m21s

This commit was merged in pull request #52.
This commit is contained in:
2026-08-22 20:22:23 +01:00
parent e02a9aa813
commit 6a8051c70f
6 changed files with 561 additions and 6 deletions
+5
View File
@@ -8,5 +8,10 @@ publish = false
[dependencies]
[dev-dependencies]
arr-dl = { workspace = true }
tokio = { workspace = true }
uuid = { workspace = true }
[lints]
workspace = true
+57 -5
View File
@@ -5,9 +5,61 @@
#[cfg(test)]
mod tests {
/// Placeholder, same reason as the one in `arr-core`: `cargo nextest`
/// fails a zero-test run, and `--no-tests=pass` would let a broken filter
/// go green later. Replaced by the real harness in the e2e issue.
#[test]
fn e2e_crate_builds() {}
use std::path::PathBuf;
use arr_dl::{AddTorrent, TorrentSource, TransmissionClient};
#[tokio::test]
async fn transmission_add_list_and_remove() {
let endpoint = std::env::var("TRANSMISSION_RPC_URL")
.unwrap_or_else(|_| "http://127.0.0.1:9091/transmission/rpc".into());
let client = TransmissionClient::new(&endpoint).expect("valid endpoint");
let name = format!("arr-e2e-{}", uuid::Uuid::new_v4());
let metainfo = torrent_with_name(&name);
let download_dir = PathBuf::from("/tmp/arr-e2e");
let request = || AddTorrent {
source: TorrentSource::Metainfo(metainfo.clone()),
label: "movies-main".into(),
download_dir: download_dir.clone(),
seed_ratio_limit: 1.5,
seed_idle_limit_minutes: 60,
};
let first = client.add_torrent(request()).await.expect("add torrent");
assert!(!first.was_duplicate);
let torrents = client.list_torrents().await.expect("list torrents");
let listed = torrents
.iter()
.find(|torrent| torrent.id == first.id)
.expect("added torrent is authoritative in list");
assert_eq!(listed.name, name);
assert_eq!(listed.hash, first.hash);
assert_eq!(listed.download_dir, download_dir);
assert_eq!(listed.labels, ["movies-main"]);
assert!((0.0..=1.0).contains(&listed.progress));
client
.remove_torrent(first.id, false)
.await
.expect("remove without data");
let second = client.add_torrent(request()).await.expect("add again");
client
.remove_torrent(second.id, true)
.await
.expect("remove with data");
let torrents = client.list_torrents().await.expect("list after remove");
assert!(torrents.iter().all(|torrent| torrent.id != second.id));
}
fn torrent_with_name(name: &str) -> Vec<u8> {
let piece_hash = [0_u8; 20];
let mut bytes = format!("d4:infod6:lengthi1e4:name{}:{name}", name.len()).into_bytes();
bytes.extend_from_slice(b"12:piece lengthi16384e6:pieces20:");
bytes.extend_from_slice(&piece_hash);
bytes.extend_from_slice(b"ee");
bytes
}
}