mirror of
https://github.com/chipsenkbeil/distant.git
synced 2024-11-15 06:12:56 +00:00
Add first example of an e2e test for distant cli
This commit is contained in:
parent
54a7f567a1
commit
188b5f74e4
112
Cargo.lock
generated
112
Cargo.lock
generated
@ -34,6 +34,20 @@ dependencies = [
|
|||||||
"wait-timeout",
|
"wait-timeout",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "assert_fs"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0ca6aa3066e6c6f0357e056a25fa95e8737f15a04f9aead0b22d0d082a39465"
|
||||||
|
dependencies = [
|
||||||
|
"doc-comment",
|
||||||
|
"globwalk",
|
||||||
|
"predicates",
|
||||||
|
"predicates-core",
|
||||||
|
"predicates-tree",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@ -144,6 +158,16 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-utils"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-bigint"
|
name = "crypto-bigint"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
@ -213,6 +237,7 @@ name = "distant"
|
|||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
|
"assert_fs",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"distant-core",
|
"distant-core",
|
||||||
"flexi_logger",
|
"flexi_logger",
|
||||||
@ -220,10 +245,10 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"rand",
|
"rand",
|
||||||
|
"rstest",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"structopt",
|
"structopt",
|
||||||
"strum",
|
"strum",
|
||||||
"tempfile",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"whoami",
|
"whoami",
|
||||||
]
|
]
|
||||||
@ -318,6 +343,12 @@ dependencies = [
|
|||||||
"yansi",
|
"yansi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fork"
|
name = "fork"
|
||||||
version = "0.1.18"
|
version = "0.1.18"
|
||||||
@ -448,6 +479,30 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "globset"
|
||||||
|
version = "0.4.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"bstr",
|
||||||
|
"fnv",
|
||||||
|
"log",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "globwalk"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"ignore",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "group"
|
name = "group"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
@ -499,6 +554,24 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ignore"
|
||||||
|
version = "0.4.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
"globset",
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"memchr",
|
||||||
|
"regex",
|
||||||
|
"same-file",
|
||||||
|
"thread_local",
|
||||||
|
"walkdir",
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
@ -879,6 +952,28 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rstest"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2288c66aeafe3b2ed227c981f364f9968fa952ef0b30e84ada4486e7ee24d00a"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustc_version",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@ -900,6 +995,12 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.130"
|
version = "1.0.130"
|
||||||
@ -1105,6 +1206,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thread_local"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.1.43"
|
version = "0.1.43"
|
||||||
|
@ -35,4 +35,5 @@ whoami = "1.1.2"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cmd = "2.0.0"
|
assert_cmd = "2.0.0"
|
||||||
tempfile = "3.2.0"
|
assert_fs = "1.0.3"
|
||||||
|
rstest = "0.11.0"
|
||||||
|
31
src/lib.rs
31
src/lib.rs
@ -26,23 +26,28 @@ pub fn run() {
|
|||||||
|
|
||||||
fn init_logging(opt: &opt::CommonOpt) -> flexi_logger::LoggerHandle {
|
fn init_logging(opt: &opt::CommonOpt) -> flexi_logger::LoggerHandle {
|
||||||
use flexi_logger::{FileSpec, LevelFilter, LogSpecification, Logger};
|
use flexi_logger::{FileSpec, LevelFilter, LogSpecification, Logger};
|
||||||
let module = "distant";
|
let modules = &["distant", "distant_core"];
|
||||||
|
|
||||||
// Disable logging for everything but our binary, which is based on verbosity
|
// Disable logging for everything but our binary, which is based on verbosity
|
||||||
let mut builder = LogSpecification::builder();
|
let mut builder = LogSpecification::builder();
|
||||||
builder.default(LevelFilter::Off).module(
|
builder.default(LevelFilter::Off);
|
||||||
module,
|
|
||||||
match opt.verbose {
|
|
||||||
0 => LevelFilter::Warn,
|
|
||||||
1 => LevelFilter::Info,
|
|
||||||
2 => LevelFilter::Debug,
|
|
||||||
_ => LevelFilter::Trace,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// If quiet, we suppress all output
|
// For each module, configure logging
|
||||||
if opt.quiet {
|
for module in modules {
|
||||||
builder.module(module, LevelFilter::Off);
|
builder.module(
|
||||||
|
module,
|
||||||
|
match opt.verbose {
|
||||||
|
0 => LevelFilter::Warn,
|
||||||
|
1 => LevelFilter::Info,
|
||||||
|
2 => LevelFilter::Debug,
|
||||||
|
_ => LevelFilter::Trace,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// If quiet, we suppress all output
|
||||||
|
if opt.quiet {
|
||||||
|
builder.module(module, LevelFilter::Off);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create our logger, but don't initialize yet
|
// Create our logger, but don't initialize yet
|
||||||
|
77
tests/action/file_read_test.rs
Normal file
77
tests/action/file_read_test.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use crate::fixtures::*;
|
||||||
|
use assert_fs::prelude::*;
|
||||||
|
use distant_core::{
|
||||||
|
data::{Error, ErrorKind},
|
||||||
|
Response, ResponseData,
|
||||||
|
};
|
||||||
|
use rstest::*;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||||
|
async fn should_print_out_file_contents(#[future] ctx: DistantServerCtx) {
|
||||||
|
let temp = assert_fs::TempDir::new().unwrap();
|
||||||
|
let file = temp.child("test-file");
|
||||||
|
file.write_str("some\ntext\ncontent").unwrap();
|
||||||
|
|
||||||
|
ctx.await
|
||||||
|
.new_cmd("action")
|
||||||
|
.args(&["file-read", file.to_str().unwrap()])
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stdout("some\ntext\ncontent\n")
|
||||||
|
.stderr("");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||||
|
async fn should_support_json_output(#[future] ctx: DistantServerCtx) {
|
||||||
|
let temp = assert_fs::TempDir::new().unwrap();
|
||||||
|
let file = temp.child("test-file");
|
||||||
|
file.write_str("some\ntext\ncontent").unwrap();
|
||||||
|
|
||||||
|
let cmd = ctx
|
||||||
|
.await
|
||||||
|
.new_cmd("action")
|
||||||
|
.args(&["--format", "json"])
|
||||||
|
.args(&["file-read", file.to_str().unwrap()])
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stderr("");
|
||||||
|
|
||||||
|
let res: Response = serde_json::from_slice(&cmd.get_output().stdout).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
res.payload[0],
|
||||||
|
ResponseData::Blob {
|
||||||
|
data: b"some\ntext\ncontent".to_vec()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
|
||||||
|
async fn yield_an_error_when_fails(#[future] ctx: DistantServerCtx) {
|
||||||
|
let temp = assert_fs::TempDir::new().unwrap();
|
||||||
|
let file = temp.child("missing-file");
|
||||||
|
|
||||||
|
let cmd = ctx
|
||||||
|
.await
|
||||||
|
.new_cmd("action")
|
||||||
|
.args(&["--format", "json"])
|
||||||
|
.args(&["file-read", file.to_str().unwrap()])
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stderr("");
|
||||||
|
|
||||||
|
let res: Response = serde_json::from_slice(&cmd.get_output().stdout).unwrap();
|
||||||
|
assert!(
|
||||||
|
matches!(
|
||||||
|
res.payload[0],
|
||||||
|
ResponseData::Error(Error {
|
||||||
|
kind: ErrorKind::NotFound,
|
||||||
|
..
|
||||||
|
})
|
||||||
|
),
|
||||||
|
"Unexpected response: {:?}",
|
||||||
|
res.payload[0]
|
||||||
|
);
|
||||||
|
}
|
1
tests/action/mod.rs
Normal file
1
tests/action/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
mod file_read_test;
|
2
tests/e2e_tests.rs
Normal file
2
tests/e2e_tests.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
mod action;
|
||||||
|
mod fixtures;
|
56
tests/fixtures.rs
Normal file
56
tests/fixtures.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use assert_cmd::Command;
|
||||||
|
use distant_core::*;
|
||||||
|
use rstest::*;
|
||||||
|
use std::{ffi::OsStr, net::SocketAddr, time::Duration};
|
||||||
|
|
||||||
|
/// Timeout to wait for a command to complete
|
||||||
|
const TIMEOUT_SECS: u64 = 10;
|
||||||
|
|
||||||
|
/// Context for some listening distant server
|
||||||
|
pub struct DistantServerCtx {
|
||||||
|
pub addr: SocketAddr,
|
||||||
|
pub auth_key: String,
|
||||||
|
pub server: DistantServer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DistantServerCtx {
|
||||||
|
/// Produces a new test command that configures some distant command
|
||||||
|
/// configured with an environment that can talk to a remote distant server
|
||||||
|
pub fn new_cmd(&self, subcommand: impl AsRef<OsStr>) -> Command {
|
||||||
|
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
|
||||||
|
|
||||||
|
println!("DISTANT_HOST = {}", self.addr.ip());
|
||||||
|
println!("DISTANT_PORT = {}", self.addr.port());
|
||||||
|
println!("DISTANT_AUTH_KEY = {}", self.auth_key);
|
||||||
|
|
||||||
|
// NOTE: We define a command that has a timeout of 10s because the handshake
|
||||||
|
// involved in a non-release test can take several seconds
|
||||||
|
cmd.arg(subcommand)
|
||||||
|
.args(&["--session", "environment"])
|
||||||
|
.env("DISTANT_HOST", self.addr.ip().to_string())
|
||||||
|
.env("DISTANT_PORT", self.addr.port().to_string())
|
||||||
|
.env("DISTANT_AUTH_KEY", self.auth_key.as_str())
|
||||||
|
.timeout(Duration::from_secs(TIMEOUT_SECS));
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for DistantServerCtx {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.server.abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[fixture]
|
||||||
|
pub async fn ctx() -> DistantServerCtx {
|
||||||
|
let ip_addr = "127.0.0.1".parse().unwrap();
|
||||||
|
let server = DistantServer::bind(ip_addr, "0".parse().unwrap(), None, 100)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
DistantServerCtx {
|
||||||
|
addr: SocketAddr::new(ip_addr, server.port()),
|
||||||
|
auth_key: server.to_unprotected_hex_auth_key(),
|
||||||
|
server,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user