mirror of
https://github.com/nimbold/Firelink.git
synced 2026-09-01 13:38:01 +00:00
fix(ci): cover Windows headless production contracts
- execute queue, retry, normalization, and credential-boundary contracts without the broken Tauri mock runtime\n- refresh target-specific FFmpeg source locks after provider URL and digest drift\n- document the remaining compile-only Windows GUI test limitation
This commit is contained in:
@@ -54,4 +54,7 @@ Native CI runs this failure-path smoke after staging the target-specific
|
||||
bundled engines on macOS, Windows, and Linux. Windows executes the Torrent RPC,
|
||||
atomic-storage, canonical-cache, and web-seed normalization targets, while
|
||||
compiling (but not executing) the queue-manager and library test binaries;
|
||||
the Tauri mock harness exits before running on the Windows runner.
|
||||
the Tauri mock harness exits before running on the Windows runner. The
|
||||
headless `production_contract` target still executes queue admission,
|
||||
normalization, credential-boundary, and retry contracts on Windows without
|
||||
constructing a Tauri mock application.
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
use firelink_lib::ipc::{TorrentFile, TorrentWebSeed};
|
||||
use firelink_lib::queue::{
|
||||
clamp_download_connections, normalize_aria2_disk_cache, normalize_torrent_bind_address,
|
||||
normalize_torrent_dht_message_timeout, normalize_torrent_file_allocation,
|
||||
normalize_torrent_web_seeds, EnqueueItem, QueueManager, SpawnPayload,
|
||||
};
|
||||
use firelink_lib::retry::{backoff_for, is_permanent_network_error, network_error_class};
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn headless_queue_contracts_reject_unsafe_inputs_and_preserve_bounds() {
|
||||
assert_eq!(clamp_download_connections(0), 1);
|
||||
assert_eq!(clamp_download_connections(99), 16);
|
||||
assert_eq!(normalize_aria2_disk_cache(Some(" 32m ")).unwrap(), "32M");
|
||||
assert!(normalize_aria2_disk_cache(Some("0K")).is_err());
|
||||
assert_eq!(
|
||||
normalize_torrent_bind_address(Some(" 2001:db8::1 ")).unwrap(),
|
||||
Some("2001:db8::1".to_string())
|
||||
);
|
||||
assert!(normalize_torrent_bind_address(Some("not-an-ip")).is_err());
|
||||
assert_eq!(normalize_torrent_dht_message_timeout(60).unwrap(), 60);
|
||||
assert!(normalize_torrent_dht_message_timeout(61).is_err());
|
||||
assert_eq!(normalize_torrent_file_allocation(None).unwrap(), "prealloc");
|
||||
assert!(normalize_torrent_file_allocation(Some("sparse")).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn headless_torrent_web_seed_contract_deduplicates_and_expands_per_file() {
|
||||
let files = vec![
|
||||
TorrentFile {
|
||||
index: 1,
|
||||
path: "folder/one.bin".to_string(),
|
||||
length: 10,
|
||||
},
|
||||
TorrentFile {
|
||||
index: 2,
|
||||
path: "two.bin".to_string(),
|
||||
length: 20,
|
||||
},
|
||||
];
|
||||
let seeds = vec![
|
||||
TorrentWebSeed {
|
||||
file_index: 1,
|
||||
uri: "https://mirror.example/base".to_string(),
|
||||
},
|
||||
TorrentWebSeed {
|
||||
file_index: 1,
|
||||
uri: "https://mirror.example/base".to_string(),
|
||||
},
|
||||
];
|
||||
let normalized = normalize_torrent_web_seeds(Some(&seeds), &files).unwrap();
|
||||
assert_eq!(normalized.len(), 1);
|
||||
let expanded = firelink_lib::queue::expand_torrent_web_seeds(&normalized, &files).unwrap();
|
||||
assert_eq!(
|
||||
expanded,
|
||||
vec![(1, "https://mirror.example/base/folder/one.bin".to_string())]
|
||||
);
|
||||
|
||||
let credentialed = [TorrentWebSeed {
|
||||
file_index: 1,
|
||||
uri: "https://user:pass@mirror.example/file".to_string(),
|
||||
}];
|
||||
assert!(normalize_torrent_web_seeds(Some(&credentialed), &files).is_err());
|
||||
let unknown_file = [TorrentWebSeed {
|
||||
file_index: 3,
|
||||
uri: "https://mirror.example/file".to_string(),
|
||||
}];
|
||||
assert!(normalize_torrent_web_seeds(Some(&unknown_file), &files).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn headless_enqueue_contract_strips_torrent_credentials_before_task_creation() {
|
||||
let item = EnqueueItem {
|
||||
id: "torrent".to_string(),
|
||||
queue_id: "main".to_string(),
|
||||
url: "https://example.test/file.torrent".to_string(),
|
||||
destination: "/tmp".to_string(),
|
||||
filename: "file.torrent".to_string(),
|
||||
username: Some("user".to_string()),
|
||||
password: Some("secret".to_string()),
|
||||
headers: Some("Cookie: session=secret".to_string()),
|
||||
cookies: Some("session=secret".to_string()),
|
||||
is_torrent: Some(true),
|
||||
..EnqueueItem::default()
|
||||
};
|
||||
let task = item.into_task();
|
||||
assert!(task.payload.username.is_none());
|
||||
assert!(task.payload.password.is_none());
|
||||
assert!(task.payload.headers.is_none());
|
||||
assert!(task.payload.cookies.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn headless_queue_lifecycle_eligibility_and_retry_contracts_hold() {
|
||||
assert!(QueueManager::<tauri::Wry>::aria2_allocation_phase_eligible(
|
||||
&SpawnPayload::default()
|
||||
));
|
||||
assert!(
|
||||
!QueueManager::<tauri::Wry>::aria2_allocation_phase_eligible(&SpawnPayload {
|
||||
is_media: true,
|
||||
..SpawnPayload::default()
|
||||
})
|
||||
);
|
||||
assert!(
|
||||
!QueueManager::<tauri::Wry>::aria2_allocation_phase_eligible(&SpawnPayload {
|
||||
is_torrent: true,
|
||||
torrent_file_allocation: Some("none".to_string()),
|
||||
..SpawnPayload::default()
|
||||
})
|
||||
);
|
||||
assert_eq!(backoff_for(0), Duration::from_secs(2));
|
||||
assert_eq!(backoff_for(usize::MAX), Duration::from_secs(10));
|
||||
assert_eq!(
|
||||
network_error_class("HTTP/1.1 503 Service Unavailable"),
|
||||
"http"
|
||||
);
|
||||
assert!(is_permanent_network_error("HTTP 403 Forbidden"));
|
||||
}
|
||||
Reference in New Issue
Block a user