use std::{
io::{self, Read},
path::{Path, PathBuf},
str::FromStr,
};
use iroh_blobs::ticket::BlobTicket;
fn sendme_bin() -> &'static str {
env!("CARGO_BIN_EXE_sendme")
}
fn read_ascii_lines(mut n: usize, reader: &mut impl Read) -> io::Result<Vec<u8>> {
let mut buf = [0u8; 1];
let mut res = Vec::new();
loop {
if reader.read(&mut buf)? != 1 {
break;
}
let char = buf[0];
res.push(char);
if char != b'\n' {
continue;
}
if n > 1 {
n -= 1;
} else {
break;
}
}
Ok(res)
}
#[test]
fn send_recv_file() {
let name = "somefile.bin";
let data = vec![0u8; 100];
let src_dir = tempfile::tempdir().unwrap();
let tgt_dir = tempfile::tempdir().unwrap();
let src_file = src_dir.path().join(name);
std::fs::write(&src_file, &data).unwrap();
let mut send_cmd = duct::cmd(
sendme_bin(),
["send", src_file.as_os_str().to_str().unwrap()],
)
.dir(src_dir.path())
.env_remove("RUST_LOG") .stderr_to_stdout()
.reader()
.unwrap();
let output = read_ascii_lines(3, &mut send_cmd).unwrap();
let output = String::from_utf8(output).unwrap();
let ticket = output.split_ascii_whitespace().last().unwrap();
let ticket = BlobTicket::from_str(ticket).unwrap();
let receive_output = duct::cmd(sendme_bin(), ["receive", &ticket.to_string()])
.dir(tgt_dir.path())
.env_remove("RUST_LOG") .stderr_to_stdout()
.run()
.unwrap();
assert!(receive_output.status.success());
let tgt_file = tgt_dir.path().join(name);
let tgt_data = std::fs::read(tgt_file).unwrap();
assert_eq!(tgt_data, data);
}
#[test]
fn receive_closes_endpoint_no_iroh_socket_error() {
let name = "graceful-close.bin";
let data = vec![0xabu8; 64];
let src_dir = tempfile::tempdir().unwrap();
let tgt_dir = tempfile::tempdir().unwrap();
let src_file = src_dir.path().join(name);
std::fs::write(&src_file, &data).unwrap();
let mut send_cmd = duct::cmd(
sendme_bin(),
["send", src_file.as_os_str().to_str().unwrap()],
)
.dir(src_dir.path())
.env_remove("RUST_LOG")
.stderr_to_stdout()
.reader()
.unwrap();
let output = read_ascii_lines(3, &mut send_cmd).unwrap();
let output = String::from_utf8(output).unwrap();
let ticket = output.split_ascii_whitespace().last().unwrap();
let ticket = BlobTicket::from_str(ticket).unwrap();
let receive_output = duct::cmd(sendme_bin(), ["receive", &ticket.to_string()])
.dir(tgt_dir.path())
.env("RUST_LOG", "iroh::socket=error")
.stdout_capture()
.stderr_capture()
.run()
.unwrap();
assert!(receive_output.status.success(), "{receive_output:?}");
let stderr = String::from_utf8_lossy(&receive_output.stderr);
assert!(
!stderr.contains("Endpoint dropped"),
"unexpected iroh shutdown log on stderr: {stderr}"
);
assert!(
!stderr.contains("Aborting ungracefully"),
"unexpected iroh shutdown log on stderr: {stderr}"
);
let tgt_file = tgt_dir.path().join(name);
assert_eq!(std::fs::read(&tgt_file).unwrap(), data);
}
#[test]
fn send_recv_dir() {
fn create_file(base: &Path, i: usize, j: usize, k: usize) -> (PathBuf, Vec<u8>) {
let name = base
.join(format!("dir-{i}"))
.join(format!("subdir-{j}"))
.join(format!("file-{k}"));
let len = i * 100 + j * 10 + k;
let data = vec![0u8; len];
(name, data)
}
let src_dir = tempfile::tempdir().unwrap();
let tgt_dir = tempfile::tempdir().unwrap();
let src_data_dir = src_dir.path().join("data");
let tgt_data_dir = tgt_dir.path().join("data");
for i in 0..5 {
for j in 0..5 {
for k in 0..5 {
let (name, data) = create_file(&src_data_dir, i, j, k);
std::fs::create_dir_all(name.parent().unwrap()).unwrap();
std::fs::write(&name, &data).unwrap();
}
}
}
let mut send_cmd = duct::cmd(
sendme_bin(),
["send", src_data_dir.as_os_str().to_str().unwrap()],
)
.dir(src_dir.path())
.env_remove("RUST_LOG") .stderr_to_stdout()
.reader()
.unwrap();
let output = read_ascii_lines(3, &mut send_cmd).unwrap();
let output = String::from_utf8(output).unwrap();
let ticket = output.split_ascii_whitespace().last().unwrap();
let ticket = BlobTicket::from_str(ticket).unwrap();
let receive_output = duct::cmd(sendme_bin(), ["receive", &ticket.to_string()])
.dir(tgt_dir.path())
.env_remove("RUST_LOG") .stderr_to_stdout()
.run()
.unwrap();
assert!(receive_output.status.success());
for i in 0..5 {
for j in 0..5 {
for k in 0..5 {
let (name, data) = create_file(&tgt_data_dir, i, j, k);
let tgt_data = std::fs::read(&name).unwrap();
assert_eq!(tgt_data, data);
}
}
}
}