chore: initial sanitized public snapshot
This commit is contained in:
@@ -0,0 +1,276 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn execute_runtime_retries_http_failure_then_completes() {
|
||||
let downloader = SequencedHttpDownloader::new(vec![
|
||||
Ok(HttpResponseModel {
|
||||
status: 503,
|
||||
reason: "Service Unavailable".to_owned(),
|
||||
version: HttpVersion::Http11,
|
||||
headers: HttpResponseHeaders {
|
||||
headers: Vec::new(),
|
||||
},
|
||||
body: ResponseBody::Empty,
|
||||
content_range: None,
|
||||
partial_content: false,
|
||||
checksum: None,
|
||||
redirected_from: None,
|
||||
}),
|
||||
Ok(HttpResponseModel {
|
||||
status: 200,
|
||||
reason: "OK".to_owned(),
|
||||
version: HttpVersion::Http11,
|
||||
headers: HttpResponseHeaders {
|
||||
headers: vec![aria2_rust_pro_protocol::HttpHeader {
|
||||
name: "content-length".to_owned(),
|
||||
value: "8".to_owned(),
|
||||
kind: aria2_rust_pro_protocol::HeaderKind::Response,
|
||||
}],
|
||||
},
|
||||
body: ResponseBody::Inline(b"aaaaaaaa".to_vec()),
|
||||
content_range: None,
|
||||
partial_content: false,
|
||||
checksum: None,
|
||||
redirected_from: None,
|
||||
}),
|
||||
]);
|
||||
let temp_dir = std::env::temp_dir().join("aria2-rust-pro-cli-retry-test");
|
||||
let _ = fs::create_dir_all(&temp_dir);
|
||||
let config_path = temp_dir.join("aria2.conf");
|
||||
fs::write(&config_path, "retry-wait=1\nmax-tries=2\n").expect("config should write");
|
||||
|
||||
let report = execute_runtime_with_downloader(
|
||||
Invocation::Run {
|
||||
config_path: Some(config_path.clone()),
|
||||
uris: vec!["http://example.com/retry.bin".to_owned()],
|
||||
},
|
||||
&downloader,
|
||||
)
|
||||
.expect("runtime should recover via retry");
|
||||
|
||||
assert_eq!(report.completed_download_count, 1);
|
||||
assert_eq!(report.first_status.as_deref(), Some("complete"));
|
||||
assert_eq!(report.first_completed_length, Some(8));
|
||||
assert_eq!(report.first_connections, Some(1));
|
||||
let _ = fs::remove_file(config_path);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn execute_runtime_accepts_partial_content_as_complete_progress() {
|
||||
let downloader = SequencedHttpDownloader::new(vec![Ok(HttpResponseModel {
|
||||
status: 206,
|
||||
reason: "Partial Content".to_owned(),
|
||||
version: HttpVersion::Http11,
|
||||
headers: HttpResponseHeaders {
|
||||
headers: vec![
|
||||
aria2_rust_pro_protocol::HttpHeader {
|
||||
name: "content-length".to_owned(),
|
||||
value: "5".to_owned(),
|
||||
kind: aria2_rust_pro_protocol::HeaderKind::Response,
|
||||
},
|
||||
aria2_rust_pro_protocol::HttpHeader {
|
||||
name: "content-range".to_owned(),
|
||||
value: "bytes 0-4/10".to_owned(),
|
||||
kind: aria2_rust_pro_protocol::HeaderKind::Response,
|
||||
},
|
||||
],
|
||||
},
|
||||
body: ResponseBody::Inline(b"12345".to_vec()),
|
||||
content_range: Some(aria2_rust_pro_protocol::ContentRangeSpec {
|
||||
unit: aria2_rust_pro_protocol::RangeUnit::Bytes,
|
||||
start: 0,
|
||||
end_inclusive: 4,
|
||||
total_size: Some(10),
|
||||
unsatisfied: false,
|
||||
}),
|
||||
partial_content: true,
|
||||
checksum: None,
|
||||
redirected_from: None,
|
||||
})]);
|
||||
let temp_dir = std::env::temp_dir().join("aria2-rust-pro-cli-partial-single-test");
|
||||
let _ = fs::create_dir_all(&temp_dir);
|
||||
let config_path = temp_dir.join("aria2.conf");
|
||||
fs::write(&config_path, "split=1\n").expect("config should write");
|
||||
|
||||
let report = execute_runtime_with_downloader(
|
||||
Invocation::Run {
|
||||
config_path: Some(config_path.clone()),
|
||||
uris: vec!["http://example.com/partial.bin".to_owned()],
|
||||
},
|
||||
&downloader,
|
||||
)
|
||||
.expect("runtime should accept 206 transfer");
|
||||
|
||||
assert_eq!(report.completed_download_count, 0);
|
||||
assert_eq!(report.first_status.as_deref(), Some("active"));
|
||||
assert_eq!(report.first_total_length, Some(10));
|
||||
assert_eq!(report.first_completed_length, Some(5));
|
||||
assert_eq!(report.first_connections, Some(1));
|
||||
let _ = fs::remove_file(config_path);
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::too_many_lines,
|
||||
reason = "partial-range regression fixture keeps the response sequence and assertions together"
|
||||
)]
|
||||
#[test]
|
||||
fn execute_runtime_advances_multi_step_partial_ranges_until_complete() {
|
||||
let downloader = SequencedHttpDownloader::new(vec![
|
||||
Ok(HttpResponseModel {
|
||||
status: 206,
|
||||
reason: "Partial Content".to_owned(),
|
||||
version: HttpVersion::Http11,
|
||||
headers: HttpResponseHeaders {
|
||||
headers: vec![
|
||||
aria2_rust_pro_protocol::HttpHeader {
|
||||
name: "content-length".to_owned(),
|
||||
value: "4".to_owned(),
|
||||
kind: aria2_rust_pro_protocol::HeaderKind::Response,
|
||||
},
|
||||
aria2_rust_pro_protocol::HttpHeader {
|
||||
name: "content-range".to_owned(),
|
||||
value: "bytes 0-3/10".to_owned(),
|
||||
kind: aria2_rust_pro_protocol::HeaderKind::Response,
|
||||
},
|
||||
],
|
||||
},
|
||||
body: ResponseBody::Inline(b"1234".to_vec()),
|
||||
content_range: Some(aria2_rust_pro_protocol::ContentRangeSpec {
|
||||
unit: aria2_rust_pro_protocol::RangeUnit::Bytes,
|
||||
start: 0,
|
||||
end_inclusive: 3,
|
||||
total_size: Some(10),
|
||||
unsatisfied: false,
|
||||
}),
|
||||
partial_content: true,
|
||||
checksum: None,
|
||||
redirected_from: None,
|
||||
}),
|
||||
Ok(HttpResponseModel {
|
||||
status: 206,
|
||||
reason: "Partial Content".to_owned(),
|
||||
version: HttpVersion::Http11,
|
||||
headers: HttpResponseHeaders {
|
||||
headers: vec![
|
||||
aria2_rust_pro_protocol::HttpHeader {
|
||||
name: "content-length".to_owned(),
|
||||
value: "3".to_owned(),
|
||||
kind: aria2_rust_pro_protocol::HeaderKind::Response,
|
||||
},
|
||||
aria2_rust_pro_protocol::HttpHeader {
|
||||
name: "content-range".to_owned(),
|
||||
value: "bytes 4-6/10".to_owned(),
|
||||
kind: aria2_rust_pro_protocol::HeaderKind::Response,
|
||||
},
|
||||
],
|
||||
},
|
||||
body: ResponseBody::Inline(b"567".to_vec()),
|
||||
content_range: Some(aria2_rust_pro_protocol::ContentRangeSpec {
|
||||
unit: aria2_rust_pro_protocol::RangeUnit::Bytes,
|
||||
start: 4,
|
||||
end_inclusive: 6,
|
||||
total_size: Some(10),
|
||||
unsatisfied: false,
|
||||
}),
|
||||
partial_content: true,
|
||||
checksum: None,
|
||||
redirected_from: None,
|
||||
}),
|
||||
Ok(HttpResponseModel {
|
||||
status: 206,
|
||||
reason: "Partial Content".to_owned(),
|
||||
version: HttpVersion::Http11,
|
||||
headers: HttpResponseHeaders {
|
||||
headers: vec![
|
||||
aria2_rust_pro_protocol::HttpHeader {
|
||||
name: "content-length".to_owned(),
|
||||
value: "2".to_owned(),
|
||||
kind: aria2_rust_pro_protocol::HeaderKind::Response,
|
||||
},
|
||||
aria2_rust_pro_protocol::HttpHeader {
|
||||
name: "content-range".to_owned(),
|
||||
value: "bytes 8-9/10".to_owned(),
|
||||
kind: aria2_rust_pro_protocol::HeaderKind::Response,
|
||||
},
|
||||
],
|
||||
},
|
||||
body: ResponseBody::Inline(b"90".to_vec()),
|
||||
content_range: Some(aria2_rust_pro_protocol::ContentRangeSpec {
|
||||
unit: aria2_rust_pro_protocol::RangeUnit::Bytes,
|
||||
start: 8,
|
||||
end_inclusive: 9,
|
||||
total_size: Some(10),
|
||||
unsatisfied: false,
|
||||
}),
|
||||
partial_content: true,
|
||||
checksum: None,
|
||||
redirected_from: None,
|
||||
}),
|
||||
]);
|
||||
let temp_dir = std::env::temp_dir().join("aria2-rust-pro-cli-multipart-test");
|
||||
let _ = fs::create_dir_all(&temp_dir);
|
||||
let config_path = temp_dir.join("aria2.conf");
|
||||
fs::write(
|
||||
&config_path,
|
||||
"max-tries=3\nsplit=3\nmin-split-size=4\npiece-length=4\n",
|
||||
)
|
||||
.expect("config should write");
|
||||
|
||||
let report = execute_runtime_with_downloader(
|
||||
Invocation::Run {
|
||||
config_path: Some(config_path.clone()),
|
||||
uris: vec!["http://example.com/multipart.bin".to_owned()],
|
||||
},
|
||||
&downloader,
|
||||
)
|
||||
.expect("runtime should advance through multiple partial segments");
|
||||
|
||||
assert_eq!(report.completed_download_count, 1);
|
||||
assert_eq!(report.first_status.as_deref(), Some("complete"));
|
||||
assert_eq!(report.first_total_length, Some(10));
|
||||
assert_eq!(report.first_completed_length, Some(10));
|
||||
assert_eq!(report.first_connections, Some(1));
|
||||
|
||||
let recorded = downloader.recorded_requests();
|
||||
let [bootstrap, first_followup, second_followup] = recorded.as_slice() else {
|
||||
panic!("expected exactly three recorded requests");
|
||||
};
|
||||
assert_eq!(bootstrap.request.range, None);
|
||||
let mut followup_ranges = [first_followup, second_followup]
|
||||
.iter()
|
||||
.map(|task| task.request.range)
|
||||
.collect::<Vec<_>>();
|
||||
followup_ranges.sort_by_key(|range| range.as_ref().map(|range| range.start));
|
||||
assert_eq!(
|
||||
followup_ranges,
|
||||
vec![
|
||||
Some(aria2_rust_pro_protocol::RangeSpec {
|
||||
start: 4,
|
||||
end_inclusive: Some(9),
|
||||
unit: aria2_rust_pro_protocol::RangeUnit::Bytes,
|
||||
}),
|
||||
Some(aria2_rust_pro_protocol::RangeSpec {
|
||||
start: 7,
|
||||
end_inclusive: Some(9),
|
||||
unit: aria2_rust_pro_protocol::RangeUnit::Bytes,
|
||||
}),
|
||||
]
|
||||
);
|
||||
assert_eq!(bootstrap.retry_attempts.len(), 0);
|
||||
assert_eq!(first_followup.retry_attempts.len(), 0);
|
||||
assert_eq!(second_followup.retry_attempts.len(), 1);
|
||||
assert!(
|
||||
first_followup
|
||||
.retry_attempts
|
||||
.iter()
|
||||
.all(|attempt| attempt.status == Some(206))
|
||||
);
|
||||
assert!(
|
||||
second_followup
|
||||
.retry_attempts
|
||||
.iter()
|
||||
.all(|attempt| attempt.status == Some(206))
|
||||
);
|
||||
|
||||
let _ = fs::remove_file(config_path);
|
||||
}
|
||||
Reference in New Issue
Block a user