mod common;
use common::{MockResponse, MockS3Server, mock_target_args, s7cmd_cmd_clean_env};
use std::time::Duration;
const LIST_BUCKETS_XML: &str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
<ListAllMyBucketsResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">\
<Owner><ID>mock-owner</ID><DisplayName>mock</DisplayName></Owner>\
<Buckets>\
<Bucket><Name>mock-bucket-1</Name><CreationDate>2026-01-01T00:00:00.000Z</CreationDate></Bucket>\
<Bucket><Name>mock-bucket-2</Name><CreationDate>2026-01-01T00:00:00.000Z</CreationDate></Bucket>\
</Buckets>\
</ListAllMyBucketsResult>";
const LIST_OBJECTS_XML: &str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">\
<Name>mock-bucket</Name><Prefix></Prefix><KeyCount>2</KeyCount>\
<MaxKeys>1000</MaxKeys><IsTruncated>false</IsTruncated>\
<Contents><Key>key-1</Key><LastModified>2026-01-01T00:00:00.000Z</LastModified>\
<ETag>"mock-etag-1"</ETag><Size>1</Size><StorageClass>STANDARD</StorageClass></Contents>\
<Contents><Key>key-2</Key><LastModified>2026-01-01T00:00:00.000Z</LastModified>\
<ETag>"mock-etag-2"</ETag><Size>2</Size><StorageClass>STANDARD</StorageClass></Contents>\
</ListBucketResult>";
fn run_ls_with_closed_stdout(server: &MockS3Server, extra: &[&str]) -> (Option<i32>, String) {
use std::io::Read;
let mut cmd = s7cmd_cmd_clean_env();
cmd.arg("ls")
.args(mock_target_args(&server.endpoint_url()))
.args(extra);
let mut child = cmd.spawn().expect("failed to spawn s7cmd binary");
drop(child.stdout.take());
let mut stderr = String::new();
if let Some(mut pipe) = child.stderr.take() {
pipe.read_to_string(&mut stderr).ok();
}
let status = child.wait().expect("wait for s7cmd");
(status.code(), stderr)
}
#[test]
fn bucket_listing_broken_pipe_exits_0() {
let server = MockS3Server::start(vec![
MockResponse::new(200, LIST_BUCKETS_XML).with_delay(Duration::from_millis(500)),
]);
let (code, stderr) = run_ls_with_closed_stdout(&server, &[]);
assert_eq!(
code,
Some(0),
"BrokenPipe in bucket-listing mode must exit 0; stderr: {stderr}"
);
}
#[test]
fn listing_pipeline_broken_pipe_exits_0() {
let server = MockS3Server::start(vec![
MockResponse::new(200, LIST_OBJECTS_XML).with_delay(Duration::from_millis(500)),
]);
let (code, stderr) = run_ls_with_closed_stdout(&server, &["s3://mock-bucket/"]);
assert_eq!(
code,
Some(0),
"BrokenPipe in listing-pipeline mode must exit 0; stderr: {stderr}"
);
}