Fix clippy warnings, fix rustfmt, refactor proc-run tests to use generated scripts instead of script files

pull/39/head
Chip Senkbeil 3 years ago
parent 9db9814f2b
commit 34d6b574c1
No known key found for this signature in database
GPG Key ID: 35EF1F8EC72A4131

@ -21,18 +21,12 @@ jobs:
- { rust: stable, os: windows-latest } - { rust: stable, os: windows-latest }
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install Rust ${{ matrix.rust }} - name: Install Rust ${{ matrix.rust }}
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: ${{ matrix.rust }} toolchain: ${{ matrix.rust }}
- uses: Swatinem/rust-cache@v1
- name: Check Cargo availability - name: Check Cargo availability
run: cargo --version run: cargo --version
- run: cargo test --verbose -p distant-core - run: cargo test --verbose -p distant-core
@ -49,19 +43,13 @@ jobs:
- { rust: stable, os: macos-latest } - { rust: stable, os: macos-latest }
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install Rust ${{ matrix.rust }} - name: Install Rust ${{ matrix.rust }}
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: ${{ matrix.rust }} toolchain: ${{ matrix.rust }}
components: rustfmt, clippy components: rustfmt, clippy
- uses: Swatinem/rust-cache@v1
- name: Check Cargo availability - name: Check Cargo availability
run: cargo --version run: cargo --version
- run: cargo test --verbose - run: cargo test --verbose
@ -73,19 +61,13 @@ jobs:
RUSTFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install Rust (clippy) - name: Install Rust (clippy)
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: stable toolchain: stable
components: clippy components: clippy
- uses: Swatinem/rust-cache@v1
- name: Check Cargo availability - name: Check Cargo availability
run: cargo --version run: cargo --version
- run: cargo clippy --workspace --all-targets --verbose - run: cargo clippy --workspace --all-targets --verbose
@ -96,19 +78,13 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install Rust (rustfmt) - name: Install Rust (rustfmt)
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: stable toolchain: stable
components: rustfmt components: rustfmt
- uses: Swatinem/rust-cache@v1
- name: Check Cargo availability - name: Check Cargo availability
run: cargo --version run: cargo --version
- run: cargo fmt --all -- --check - run: cargo fmt --all -- --check

17
Cargo.lock generated

@ -242,6 +242,7 @@ dependencies = [
"distant-core", "distant-core",
"flexi_logger", "flexi_logger",
"fork", "fork",
"indoc",
"lazy_static", "lazy_static",
"log", "log",
"predicates", "predicates",
@ -263,6 +264,7 @@ dependencies = [
"derive_more", "derive_more",
"futures", "futures",
"hex", "hex",
"indoc",
"k256", "k256",
"lazy_static", "lazy_static",
"log", "log",
@ -583,6 +585,15 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "indoc"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136"
dependencies = [
"unindent",
]
[[package]] [[package]]
name = "instant" name = "instant"
version = "0.1.10" version = "0.1.10"
@ -1320,6 +1331,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "unindent"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
[[package]] [[package]]
name = "vec_map" name = "vec_map"
version = "0.8.2" version = "0.8.2"

@ -36,5 +36,6 @@ whoami = "1.1.2"
[dev-dependencies] [dev-dependencies]
assert_cmd = "2.0.0" assert_cmd = "2.0.0"
assert_fs = "1.0.4" assert_fs = "1.0.4"
indoc = "1.0.3"
predicates = "2.0.2" predicates = "2.0.2"
rstest = "0.11.0" rstest = "0.11.0"

@ -33,4 +33,5 @@ structopt = { version = "0.3.22", optional = true }
[dev-dependencies] [dev-dependencies]
assert_fs = "1.0.4" assert_fs = "1.0.4"
indoc = "1.0.3"
predicates = "2.0.2" predicates = "2.0.2"

@ -184,12 +184,7 @@ where
let read_task = tokio::spawn(async move { let read_task = tokio::spawn(async move {
let mut task_buf: Option<String> = None; let mut task_buf: Option<String> = None;
loop { while let Some(data) = stream.next().await {
let data = match stream.next().await {
Some(data) => data,
None => break,
};
// Create or insert into our buffer // Create or insert into our buffer
match &mut task_buf { match &mut task_buf {
Some(buf) => buf.push_str(&data), Some(buf) => buf.push_str(&data),

@ -145,7 +145,7 @@ impl Listener for TcpListener {
where where
Self: Sync + 'a, Self: Sync + 'a,
{ {
async fn accept<'a>(_self: &'a TcpListener) -> io::Result<TcpStream> { async fn accept(_self: &TcpListener) -> io::Result<TcpStream> {
_self.accept().await.map(|(stream, _)| stream) _self.accept().await.map(|(stream, _)| stream)
} }
@ -180,8 +180,8 @@ where
where where
Self: Sync + 'a, Self: Sync + 'a,
{ {
async fn accept<'a, T>( async fn accept<T>(
_self: &'a tokio::sync::Mutex<tokio::sync::mpsc::Receiver<T>>, _self: &tokio::sync::Mutex<tokio::sync::mpsc::Receiver<T>>,
) -> io::Result<T> ) -> io::Result<T>
where where
T: DataStream + Send + Sync + 'static, T: DataStream + Send + Sync + 'static,

@ -294,15 +294,15 @@ async fn copy(src: PathBuf, dst: PathBuf) -> Result<ResponseData, ServerError> {
// Create the destination directory for the file when copying // Create the destination directory for the file when copying
tokio::fs::create_dir_all(dst_parent_dir.as_path()).await?; tokio::fs::create_dir_all(dst_parent_dir.as_path()).await?;
let dst_path = dst_parent_dir.join(local_src_file_name);
// Perform copying from entry to destination (if a file/symlink) // Perform copying from entry to destination (if a file/symlink)
if !entry.file_type().is_dir() { if !entry.file_type().is_dir() {
let dst_file = dst_parent_dir.join(local_src_file_name); tokio::fs::copy(entry.path(), dst_path).await?;
tokio::fs::copy(entry.path(), dst_file).await?;
// Otherwise, if a directory, create it // Otherwise, if a directory, create it
} else { } else {
let dst_dir = dst_parent_dir.join(local_src_file_name); tokio::fs::create_dir(dst_path).await?;
tokio::fs::create_dir(dst_dir).await?;
} }
} }
} else { } else {
@ -409,7 +409,7 @@ async fn proc_run(
None, None,
vec![ResponseData::ProcStdout { id, data }], vec![ResponseData::ProcStdout { id, data }],
); );
if let Err(_) = tx_2.send(res).await { if tx_2.send(res).await.is_err() {
error!("<Conn @ {}> Stdout channel closed", conn_id); error!("<Conn @ {}> Stdout channel closed", conn_id);
break; break;
} }
@ -445,7 +445,7 @@ async fn proc_run(
None, None,
vec![ResponseData::ProcStderr { id, data }], vec![ResponseData::ProcStderr { id, data }],
); );
if let Err(_) = tx_2.send(res).await { if tx_2.send(res).await.is_err() {
error!("<Conn @ {}> Stderr channel closed", conn_id); error!("<Conn @ {}> Stderr channel closed", conn_id);
break; break;
} }
@ -513,7 +513,7 @@ async fn proc_run(
None, None,
vec![ResponseData::ProcDone { id, success, code }] vec![ResponseData::ProcDone { id, success, code }]
); );
if let Err(_) = tx.send(res).await { if tx.send(res).await.is_err() {
error!( error!(
"<Conn @ {}> Failed to send done for process {}!", "<Conn @ {}> Failed to send done for process {}!",
conn_id, conn_id,
@ -523,7 +523,7 @@ async fn proc_run(
} }
Err(x) => { Err(x) => {
let res = Response::new(tenant.as_str(), None, vec![ResponseData::from(x)]); let res = Response::new(tenant.as_str(), None, vec![ResponseData::from(x)]);
if let Err(_) = tx.send(res).await { if tx.send(res).await.is_err() {
error!( error!(
"<Conn @ {}> Failed to send error for waiting on process {}!", "<Conn @ {}> Failed to send error for waiting on process {}!",
conn_id, conn_id,
@ -558,10 +558,7 @@ async fn proc_run(
let res = Response::new(tenant.as_str(), None, vec![ResponseData::ProcDone { let res = Response::new(tenant.as_str(), None, vec![ResponseData::ProcDone {
id, success: false, code: None id, success: false, code: None
}]); }]);
if let Err(_) = tx if tx.send(res).await.is_err() {
.send(res)
.await
{
error!("<Conn @ {}> Failed to send done for process {}!", conn_id, id); error!("<Conn @ {}> Failed to send done for process {}!", conn_id, id);
} }
} }
@ -642,22 +639,56 @@ mod tests {
use std::time::Duration; use std::time::Duration;
lazy_static::lazy_static! { lazy_static::lazy_static! {
// TODO: This is a workaround to get the workspace root directory from within a specific static ref TEMP_SCRIPT_DIR: assert_fs::TempDir = assert_fs::TempDir::new().unwrap();
// workspace member as there is no environment variable to support this. static ref SCRIPT_RUNNER: String = String::from("bash");
//
// See https://github.com/rust-lang/cargo/issues/3946 static ref ECHO_ARGS_TO_STDOUT_SH: assert_fs::fixture::ChildPath = {
static ref ROOT_DIR: PathBuf = { let script = TEMP_SCRIPT_DIR.child("echo_args_to_stdout.sh");
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..").canonicalize().unwrap() script.write_str(indoc::indoc!(r#"
#/usr/bin/env bash
printf "%s" "$@"
"#)).unwrap();
script
};
static ref ECHO_ARGS_TO_STDERR_SH: assert_fs::fixture::ChildPath = {
let script = TEMP_SCRIPT_DIR.child("echo_args_to_stderr.sh");
script.write_str(indoc::indoc!(r#"
#/usr/bin/env bash
printf "%s" "$@" 1>&2
"#)).unwrap();
script
};
static ref ECHO_STDIN_TO_STDOUT_SH: assert_fs::fixture::ChildPath = {
let script = TEMP_SCRIPT_DIR.child("echo_stdin_to_stdout.sh");
script.write_str(indoc::indoc!(r#"
#/usr/bin/env bash
while IFS= read; do echo "$REPLY"; done
"#)).unwrap();
script
};
static ref EXIT_CODE_SH: assert_fs::fixture::ChildPath = {
let script = TEMP_SCRIPT_DIR.child("exit_code.sh");
script.write_str(indoc::indoc!(r#"
#!/usr/bin/env bash
exit "$1"
"#)).unwrap();
script
}; };
static ref SCRIPT_DIR: PathBuf = ROOT_DIR.join("scripts").join("test");
static ref ECHO_ARGS_TO_STDOUT_SH: PathBuf = SCRIPT_DIR.join("echo_args_to_stdout.sh"); static ref SLEEP_SH: assert_fs::fixture::ChildPath = {
static ref ECHO_ARGS_TO_STDERR_SH: PathBuf = SCRIPT_DIR.join("echo_args_to_stderr.sh"); let script = TEMP_SCRIPT_DIR.child("sleep.sh");
static ref ECHO_STDIN_TO_STDOUT_SH: PathBuf = SCRIPT_DIR.join("echo_stdin_to_stdout.sh"); script.write_str(indoc::indoc!(r#"
static ref EXIT_CODE_SH: PathBuf = SCRIPT_DIR.join("exit_code.sh"); #!/usr/bin/env bash
static ref SLEEP_SH: PathBuf = SCRIPT_DIR.join("sleep.sh"); sleep "$1"
"#)).unwrap();
script
};
static ref DOES_NOT_EXIST_BIN: PathBuf = SCRIPT_DIR.join("does_not_exist_bin"); static ref DOES_NOT_EXIST_BIN: assert_fs::fixture::ChildPath =
TEMP_SCRIPT_DIR.child("does_not_exist_bin");
} }
fn setup( fn setup(
@ -729,10 +760,7 @@ mod tests {
let temp = assert_fs::TempDir::new().unwrap(); let temp = assert_fs::TempDir::new().unwrap();
let path = temp.child("missing-file").path().to_path_buf(); let path = temp.child("missing-file").path().to_path_buf();
let req = Request::new( let req = Request::new("test-tenant", vec![RequestData::FileReadText { path }]);
"test-tenant",
vec![RequestData::FileReadText { path: path }],
);
process(conn_id, state, req, tx).await.unwrap(); process(conn_id, state, req, tx).await.unwrap();
@ -2043,8 +2071,8 @@ mod tests {
let req = Request::new( let req = Request::new(
"test-tenant", "test-tenant",
vec![RequestData::ProcRun { vec![RequestData::ProcRun {
cmd: ECHO_ARGS_TO_STDOUT_SH.to_str().unwrap().to_string(), cmd: SCRIPT_RUNNER.to_string(),
args: Vec::new(), args: vec![ECHO_ARGS_TO_STDOUT_SH.to_str().unwrap().to_string()],
}], }],
); );
@ -2069,8 +2097,11 @@ mod tests {
let req = Request::new( let req = Request::new(
"test-tenant", "test-tenant",
vec![RequestData::ProcRun { vec![RequestData::ProcRun {
cmd: ECHO_ARGS_TO_STDOUT_SH.to_str().unwrap().to_string(), cmd: SCRIPT_RUNNER.to_string(),
args: vec![String::from("some stdout")], args: vec![
ECHO_ARGS_TO_STDOUT_SH.to_str().unwrap().to_string(),
String::from("some stdout"),
],
}], }],
); );
@ -2128,8 +2159,11 @@ mod tests {
let req = Request::new( let req = Request::new(
"test-tenant", "test-tenant",
vec![RequestData::ProcRun { vec![RequestData::ProcRun {
cmd: ECHO_ARGS_TO_STDERR_SH.to_str().unwrap().to_string(), cmd: SCRIPT_RUNNER.to_string(),
args: vec![String::from("some stderr")], args: vec![
ECHO_ARGS_TO_STDERR_SH.to_str().unwrap().to_string(),
String::from("some stderr"),
],
}], }],
); );
@ -2187,8 +2221,8 @@ mod tests {
let req = Request::new( let req = Request::new(
"test-tenant", "test-tenant",
vec![RequestData::ProcRun { vec![RequestData::ProcRun {
cmd: SLEEP_SH.to_str().unwrap().to_string(), cmd: SCRIPT_RUNNER.to_string(),
args: vec![String::from("0.1")], args: vec![SLEEP_SH.to_str().unwrap().to_string(), String::from("0.1")],
}], }],
); );
@ -2229,8 +2263,8 @@ mod tests {
let req = Request::new( let req = Request::new(
"test-tenant", "test-tenant",
vec![RequestData::ProcRun { vec![RequestData::ProcRun {
cmd: SLEEP_SH.to_str().unwrap().to_string(), cmd: SCRIPT_RUNNER.to_string(),
args: vec![String::from("1")], args: vec![SLEEP_SH.to_str().unwrap().to_string(), String::from("1")],
}], }],
); );
@ -2303,8 +2337,8 @@ mod tests {
let req = Request::new( let req = Request::new(
"test-tenant", "test-tenant",
vec![RequestData::ProcRun { vec![RequestData::ProcRun {
cmd: SLEEP_SH.to_str().unwrap().to_string(), cmd: SCRIPT_RUNNER.to_string(),
args: vec![String::from("1")], args: vec![SLEEP_SH.to_str().unwrap().to_string(), String::from("1")],
}], }],
); );
@ -2395,8 +2429,8 @@ mod tests {
let req = Request::new( let req = Request::new(
"test-tenant", "test-tenant",
vec![RequestData::ProcRun { vec![RequestData::ProcRun {
cmd: ECHO_STDIN_TO_STDOUT_SH.to_str().unwrap().to_string(), cmd: SCRIPT_RUNNER.to_string(),
args: Vec::new(), args: vec![ECHO_STDIN_TO_STDOUT_SH.to_str().unwrap().to_string()],
}], }],
); );
@ -2467,8 +2501,8 @@ mod tests {
"test-tenant", "test-tenant",
vec![ vec![
RequestData::ProcRun { RequestData::ProcRun {
cmd: SLEEP_SH.to_str().unwrap().to_string(), cmd: SCRIPT_RUNNER.to_string(),
args: vec![String::from("1")], args: vec![SLEEP_SH.to_str().unwrap().to_string(), String::from("1")],
}, },
RequestData::ProcList {}, RequestData::ProcList {},
], ],
@ -2490,8 +2524,8 @@ mod tests {
res.payload[1], res.payload[1],
ResponseData::ProcEntries { ResponseData::ProcEntries {
entries: vec![RunningProcess { entries: vec![RunningProcess {
cmd: SLEEP_SH.to_str().unwrap().to_string(), cmd: SCRIPT_RUNNER.to_string(),
args: vec![String::from("1")], args: vec![SLEEP_SH.to_str().unwrap().to_string(), String::from("1")],
id, id,
}], }],
}, },

@ -275,6 +275,7 @@ mod tests {
}; };
use std::pin::Pin; use std::pin::Pin;
#[allow(clippy::type_complexity)]
fn make_transport_stream() -> ( fn make_transport_stream() -> (
mpsc::Sender<Transport<InmemoryStream>>, mpsc::Sender<Transport<InmemoryStream>>,
Pin<Box<dyn Stream<Item = Transport<InmemoryStream>> + Send>>, Pin<Box<dyn Stream<Item = Transport<InmemoryStream>> + Send>>,

@ -25,7 +25,7 @@ impl State {
pub fn push_process(&mut self, conn_id: usize, process: Process) { pub fn push_process(&mut self, conn_id: usize, process: Process) {
self.client_processes self.client_processes
.entry(conn_id) .entry(conn_id)
.or_insert(Vec::new()) .or_insert_with(Vec::new)
.push(process.id); .push(process.id);
self.processes.insert(process.id, process); self.processes.insert(process.id, process);
} }
@ -69,7 +69,7 @@ impl State {
conn_id, conn_id,
process.id process.id
); );
if let Err(_) = process.kill_tx.send(()) { if process.kill_tx.send(()).is_err() {
error!( error!(
"Conn {} failed to send process {} kill signal", "Conn {} failed to send process {} kill signal",
id, process.id id, process.id

@ -420,6 +420,7 @@ mod tests {
(t1, Session::initialize(t2).unwrap()) (t1, Session::initialize(t2).unwrap())
} }
#[allow(clippy::type_complexity)]
fn make_transport_stream() -> ( fn make_transport_stream() -> (
mpsc::Sender<Transport<InmemoryStream>>, mpsc::Sender<Transport<InmemoryStream>>,
Pin<Box<dyn Stream<Item = Transport<InmemoryStream>> + Send>>, Pin<Box<dyn Stream<Item = Transport<InmemoryStream>> + Send>>,

@ -148,7 +148,7 @@ mod tests {
"Shutdown task unexpectedly completed" "Shutdown task unexpectedly completed"
); );
time::sleep(Duration::from_millis(15)).await; time::sleep(Duration::from_millis(50)).await;
assert!( assert!(
futures::poll!(task).is_pending(), futures::poll!(task).is_pending(),
@ -164,7 +164,7 @@ mod tests {
"Shutdown task unexpectedly completed" "Shutdown task unexpectedly completed"
); );
time::sleep(Duration::from_millis(15)).await; time::sleep(Duration::from_millis(50)).await;
assert!( assert!(
futures::poll!(task).is_ready(), futures::poll!(task).is_ready(),
@ -182,14 +182,14 @@ mod tests {
"Shutdown task unexpectedly completed" "Shutdown task unexpectedly completed"
); );
time::sleep(Duration::from_millis(15)).await; time::sleep(Duration::from_millis(50)).await;
assert!( assert!(
futures::poll!(&mut task).is_pending(), futures::poll!(&mut task).is_pending(),
"Shutdown task unexpectedly completed" "Shutdown task unexpectedly completed"
); );
task.tracker().lock().await.decrement(); task.tracker().lock().await.decrement();
time::sleep(Duration::from_millis(15)).await; time::sleep(Duration::from_millis(50)).await;
assert!( assert!(
futures::poll!(task).is_ready(), futures::poll!(task).is_ready(),
@ -199,7 +199,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn shutdown_task_should_not_resolve_before_minimum_duration() { async fn shutdown_task_should_not_resolve_before_minimum_duration() {
let mut task = ShutdownTask::initialize(Duration::from_millis(10)); let mut task = ShutdownTask::initialize(Duration::from_millis(50));
assert!( assert!(
futures::poll!(&mut task).is_pending(), futures::poll!(&mut task).is_pending(),
"Shutdown task unexpectedly completed" "Shutdown task unexpectedly completed"

@ -1,4 +1,4 @@
use distant_core::{Transport, TransportError, InmemoryStream, SecretKey}; use distant_core::{InmemoryStream, SecretKey, Transport, TransportError};
use std::{io, sync::Arc}; use std::{io, sync::Arc};
const BUFFER_SIZE: usize = 100; const BUFFER_SIZE: usize = 100;

@ -1,3 +0,0 @@
#/usr/bin/env bash
printf "%s" "$@" 1>&2

@ -1,3 +0,0 @@
#/usr/bin/env bash
printf "%s" "$@"

@ -1,3 +0,0 @@
#/usr/bin/env bash
while IFS= read; do echo "$REPLY"; done

@ -1,3 +0,0 @@
#!/usr/bin/env bash
exit "$1"

@ -1,3 +0,0 @@
#!/usr/bin/env bash
sleep "$1"

@ -1,12 +1,12 @@
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
/// Wraps a string to provide some friendly read and write methods /// Wraps a string to provide some friendly read and write methods
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct StringBuf(String); pub struct StringBuf(String);
impl StringBuf { impl StringBuf {
pub fn new() -> Self { pub fn new() -> Self {
Self(String::new()) Self::default()
} }
/// Consumes data within the buffer that represent full lines (end with a newline) and returns /// Consumes data within the buffer that represent full lines (end with a newline) and returns

@ -41,8 +41,8 @@ pub enum ExitCode {
impl ExitCode { impl ExitCode {
/// Convert into numeric exit code /// Convert into numeric exit code
pub fn to_i32(&self) -> i32 { pub fn to_i32(self) -> i32 {
match *self { match self {
Self::Usage => 64, Self::Usage => 64,
Self::DataErr => 65, Self::DataErr => 65,
Self::NoInput => 66, Self::NoInput => 66,

@ -197,21 +197,20 @@ pub enum ConvertToIpAddrError {
impl BindAddress { impl BindAddress {
/// Converts address into valid IP; in the case of "any", will leverage the /// Converts address into valid IP; in the case of "any", will leverage the
/// `use_ipv6` flag to determine if binding should use ipv4 or ipv6 /// `use_ipv6` flag to determine if binding should use ipv4 or ipv6
pub fn to_ip_addr(&self, use_ipv6: bool) -> Result<IpAddr, ConvertToIpAddrError> { pub fn to_ip_addr(self, use_ipv6: bool) -> Result<IpAddr, ConvertToIpAddrError> {
match self { match self {
Self::Ssh => { Self::Ssh => {
let ssh_connection = env::var("SSH_CONNECTION")?; let ssh_connection = env::var("SSH_CONNECTION")?;
let ip_str = ssh_connection let ip_str = ssh_connection
.split(' ') .split(' ')
.skip(2) .nth(2)
.next()
.ok_or(ConvertToIpAddrError::MissingSshAddr)?; .ok_or(ConvertToIpAddrError::MissingSshAddr)?;
let ip = ip_str.parse::<IpAddr>()?; let ip = ip_str.parse::<IpAddr>()?;
Ok(ip) Ok(ip)
} }
Self::Any if use_ipv6 => Ok(IpAddr::V6(Ipv6Addr::UNSPECIFIED)), Self::Any if use_ipv6 => Ok(IpAddr::V6(Ipv6Addr::UNSPECIFIED)),
Self::Any => Ok(IpAddr::V4(Ipv4Addr::UNSPECIFIED)), Self::Any => Ok(IpAddr::V4(Ipv4Addr::UNSPECIFIED)),
Self::Ip(addr) => Ok(*addr), Self::Ip(addr) => Ok(addr),
} }
} }
} }

@ -18,11 +18,10 @@ impl ResponseOut {
let payload_cnt = res.payload.len(); let payload_cnt = res.payload.len();
Ok(match format { Ok(match format {
Format::Json => ResponseOut::StdoutLine(format!( Format::Json => ResponseOut::StdoutLine(
"{}",
serde_json::to_string(&res) serde_json::to_string(&res)
.map_err(|x| io::Error::new(io::ErrorKind::InvalidData, x))? .map_err(|x| io::Error::new(io::ErrorKind::InvalidData, x))?,
)), ),
// NOTE: For shell, we assume a singular entry in the response's payload // NOTE: For shell, we assume a singular entry in the response's payload
Format::Shell if payload_cnt != 1 => { Format::Shell if payload_cnt != 1 => {
@ -77,8 +76,7 @@ fn format_shell(data: ResponseData) -> ResponseOut {
ResponseOut::StdoutLine(String::from_utf8_lossy(&data).to_string()) ResponseOut::StdoutLine(String::from_utf8_lossy(&data).to_string())
} }
ResponseData::Text { data } => ResponseOut::StdoutLine(data), ResponseData::Text { data } => ResponseOut::StdoutLine(data),
ResponseData::DirEntries { entries, .. } => ResponseOut::StdoutLine(format!( ResponseData::DirEntries { entries, .. } => ResponseOut::StdoutLine(
"{}",
entries entries
.into_iter() .into_iter()
.map(|entry| { .map(|entry| {
@ -100,7 +98,7 @@ fn format_shell(data: ResponseData) -> ResponseOut {
}) })
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n"), .join("\n"),
)), ),
ResponseData::Exists(exists) => { ResponseData::Exists(exists) => {
if exists { if exists {
ResponseOut::StdoutLine("true".to_string()) ResponseOut::StdoutLine("true".to_string())
@ -136,14 +134,13 @@ fn format_shell(data: ResponseData) -> ResponseOut {
accessed.unwrap_or_default(), accessed.unwrap_or_default(),
modified.unwrap_or_default(), modified.unwrap_or_default(),
)), )),
ResponseData::ProcEntries { entries } => ResponseOut::StdoutLine(format!( ResponseData::ProcEntries { entries } => ResponseOut::StdoutLine(
"{}",
entries entries
.into_iter() .into_iter()
.map(|entry| format!("{}: {} {}", entry.id, entry.cmd, entry.args.join(" "))) .map(|entry| format!("{}: {} {}", entry.id, entry.cmd, entry.args.join(" ")))
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n"), .join("\n"),
)), ),
ResponseData::ProcStart { .. } => ResponseOut::None, ResponseData::ProcStart { .. } => ResponseOut::None,
ResponseData::ProcStdout { data, .. } => ResponseOut::Stdout(data), ResponseData::ProcStdout { data, .. } => ResponseOut::Stdout(data),
ResponseData::ProcStderr { data, .. } => ResponseOut::Stderr(data), ResponseData::ProcStderr { data, .. } => ResponseOut::Stderr(data),

@ -113,7 +113,7 @@ async fn process_outgoing_requests<T, F>(
} else if line == "exit" { } else if line == "exit" {
debug!("Got exit request, so closing cli session"); debug!("Got exit request, so closing cli session");
stdin_rx.close(); stdin_rx.close();
if let Err(_) = exit_tx.send(()).await { if exit_tx.send(()).await.is_err() {
error!("Failed to close cli session"); error!("Failed to close cli session");
} }
continue; continue;

@ -38,7 +38,7 @@ pub fn run(cmd: ListenSubcommand, opt: CommonOpt) -> Result<(), Error> {
} }
Ok(Fork::Parent(pid)) => { Ok(Fork::Parent(pid)) => {
info!("[distant detached, pid = {}]", pid); info!("[distant detached, pid = {}]", pid);
if let Err(_) = fork::close_fd() { if fork::close_fd().is_err() {
return Err(Error::ForkError); return Err(Error::ForkError);
} }
} }
@ -83,10 +83,8 @@ async fn run_async(cmd: ListenSubcommand, _opt: CommonOpt, is_forked: bool) -> R
); );
// For the child, we want to fully disconnect it from pipes, which we do now // For the child, we want to fully disconnect it from pipes, which we do now
if is_forked { if is_forked && fork::close_fd().is_err() {
if let Err(_) = fork::close_fd() { return Err(Error::ForkError);
return Err(Error::ForkError);
}
} }
// Let our server run to completion // Let our server run to completion

@ -449,7 +449,7 @@ fn should_support_json_including_root_directory_if_specified(mut action_cmd: Com
ResponseData::DirEntries { ResponseData::DirEntries {
entries: vec![ entries: vec![
DirEntry { DirEntry {
path: root_path.to_path_buf(), path: root_path,
file_type: FileType::Dir, file_type: FileType::Dir,
depth: 0 depth: 0
}, },

@ -1,26 +1,55 @@
use crate::cli::{ use crate::cli::{fixtures::*, utils::random_tenant};
fixtures::*,
utils::{random_tenant, regex_pred, FAILURE_LINE},
};
use assert_cmd::Command; use assert_cmd::Command;
use assert_fs::prelude::*;
use distant::ExitCode; use distant::ExitCode;
use distant_core::{ use distant_core::{
data::{Error, ErrorKind}, data::{Error, ErrorKind},
Request, RequestData, Response, ResponseData, Request, RequestData, Response, ResponseData,
}; };
use rstest::*; use rstest::*;
use std::path::PathBuf;
lazy_static::lazy_static! { lazy_static::lazy_static! {
static ref ROOT_DIR: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); static ref TEMP_SCRIPT_DIR: assert_fs::TempDir = assert_fs::TempDir::new().unwrap();
static ref SCRIPT_DIR: PathBuf = ROOT_DIR.join("scripts").join("test"); static ref SCRIPT_RUNNER: String = String::from("bash");
static ref ECHO_ARGS_TO_STDOUT_SH: PathBuf = SCRIPT_DIR.join("echo_args_to_stdout.sh"); static ref ECHO_ARGS_TO_STDOUT_SH: assert_fs::fixture::ChildPath = {
static ref ECHO_ARGS_TO_STDERR_SH: PathBuf = SCRIPT_DIR.join("echo_args_to_stderr.sh"); let script = TEMP_SCRIPT_DIR.child("echo_args_to_stdout.sh");
static ref ECHO_STDIN_TO_STDOUT_SH: PathBuf = SCRIPT_DIR.join("echo_stdin_to_stdout.sh"); script.write_str(indoc::indoc!(r#"
static ref EXIT_CODE_SH: PathBuf = SCRIPT_DIR.join("exit_code.sh"); #/usr/bin/env bash
printf "%s" "$@"
"#)).unwrap();
script
};
static ref DOES_NOT_EXIST_BIN: PathBuf = SCRIPT_DIR.join("does_not_exist_bin"); static ref ECHO_ARGS_TO_STDERR_SH: assert_fs::fixture::ChildPath = {
let script = TEMP_SCRIPT_DIR.child("echo_args_to_stderr.sh");
script.write_str(indoc::indoc!(r#"
#/usr/bin/env bash
printf "%s" "$@" 1>&2
"#)).unwrap();
script
};
static ref ECHO_STDIN_TO_STDOUT_SH: assert_fs::fixture::ChildPath = {
let script = TEMP_SCRIPT_DIR.child("echo_stdin_to_stdout.sh");
script.write_str(indoc::indoc!(r#"
#/usr/bin/env bash
while IFS= read; do echo "$REPLY"; done
"#)).unwrap();
script
};
static ref EXIT_CODE_SH: assert_fs::fixture::ChildPath = {
let script = TEMP_SCRIPT_DIR.child("exit_code.sh");
script.write_str(indoc::indoc!(r#"
#!/usr/bin/env bash
exit "$1"
"#)).unwrap();
script
};
static ref DOES_NOT_EXIST_BIN: assert_fs::fixture::ChildPath =
TEMP_SCRIPT_DIR.child("does_not_exist_bin");
} }
#[rstest] #[rstest]
@ -28,6 +57,7 @@ fn should_execute_program_and_return_exit_status(mut action_cmd: Command) {
// distant action proc-run -- {cmd} [args] // distant action proc-run -- {cmd} [args]
action_cmd action_cmd
.args(&["proc-run", "--"]) .args(&["proc-run", "--"])
.arg(SCRIPT_RUNNER.as_str())
.arg(EXIT_CODE_SH.to_str().unwrap()) .arg(EXIT_CODE_SH.to_str().unwrap())
.arg("0") .arg("0")
.assert() .assert()
@ -41,6 +71,7 @@ fn should_capture_and_print_stdout(mut action_cmd: Command) {
// distant action proc-run {cmd} [args] // distant action proc-run {cmd} [args]
action_cmd action_cmd
.args(&["proc-run", "--"]) .args(&["proc-run", "--"])
.arg(SCRIPT_RUNNER.as_str())
.arg(ECHO_ARGS_TO_STDOUT_SH.to_str().unwrap()) .arg(ECHO_ARGS_TO_STDOUT_SH.to_str().unwrap())
.arg("hello world") .arg("hello world")
.assert() .assert()
@ -54,6 +85,7 @@ fn should_capture_and_print_stderr(mut action_cmd: Command) {
// distant action proc-run {cmd} [args] // distant action proc-run {cmd} [args]
action_cmd action_cmd
.args(&["proc-run", "--"]) .args(&["proc-run", "--"])
.arg(SCRIPT_RUNNER.as_str())
.arg(ECHO_ARGS_TO_STDERR_SH.to_str().unwrap()) .arg(ECHO_ARGS_TO_STDERR_SH.to_str().unwrap())
.arg("hello world") .arg("hello world")
.assert() .assert()
@ -67,6 +99,7 @@ fn should_forward_stdin_to_remote_process(mut action_cmd: Command) {
// distant action proc-run {cmd} [args] // distant action proc-run {cmd} [args]
action_cmd action_cmd
.args(&["proc-run", "--"]) .args(&["proc-run", "--"])
.arg(SCRIPT_RUNNER.as_str())
.arg(ECHO_STDIN_TO_STDOUT_SH.to_str().unwrap()) .arg(ECHO_STDIN_TO_STDOUT_SH.to_str().unwrap())
.write_stdin("hello world\n") .write_stdin("hello world\n")
.assert() .assert()
@ -80,6 +113,7 @@ fn reflect_the_exit_code_of_the_process(mut action_cmd: Command) {
// distant action proc-run {cmd} [args] // distant action proc-run {cmd} [args]
action_cmd action_cmd
.args(&["proc-run", "--"]) .args(&["proc-run", "--"])
.arg(SCRIPT_RUNNER.as_str())
.arg(EXIT_CODE_SH.to_str().unwrap()) .arg(EXIT_CODE_SH.to_str().unwrap())
.arg("99") .arg("99")
.assert() .assert()
@ -106,8 +140,8 @@ fn should_support_json_to_execute_program_and_return_exit_status(mut action_cmd:
id: rand::random(), id: rand::random(),
tenant: random_tenant(), tenant: random_tenant(),
payload: vec![RequestData::ProcRun { payload: vec![RequestData::ProcRun {
cmd: ECHO_ARGS_TO_STDOUT_SH.to_str().unwrap().to_string(), cmd: SCRIPT_RUNNER.to_string(),
args: Vec::new(), args: vec![ECHO_ARGS_TO_STDOUT_SH.to_str().unwrap().to_string()],
}], }],
}; };

@ -5,7 +5,7 @@ use rstest::*;
use std::{ffi::OsStr, net::SocketAddr, sync::Arc, thread}; use std::{ffi::OsStr, net::SocketAddr, sync::Arc, thread};
use tokio::{runtime::Runtime, sync::mpsc}; use tokio::{runtime::Runtime, sync::mpsc};
const LOG_PATH: &'static str = "/tmp/test.distant.server.log"; const LOG_PATH: &str = "/tmp/test.distant.server.log";
/// Context for some listening distant server /// Context for some listening distant server
pub struct DistantServerCtx { pub struct DistantServerCtx {

Loading…
Cancel
Save