diff --git a/Cargo.lock b/Cargo.lock index 9ba22c042..f3affd04d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,6 +144,22 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "assert_cmd" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d" +dependencies = [ + "anstyle", + "bstr", + "doc-comment", + "libc", + "predicates", + "predicates-core", + "predicates-tree", + "wait-timeout", +] + [[package]] name = "async-dropper-simple" version = "0.2.6" @@ -572,6 +588,17 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "bstr" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" +dependencies = [ + "memchr", + "regex-automata 0.4.8", + "serde", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -1105,6 +1132,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "digest" version = "0.9.0" @@ -1251,6 +1284,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + [[package]] name = "ecdsa" version = "0.12.4" @@ -1539,6 +1578,15 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2924,16 +2972,19 @@ name = "jstzd" version = "0.1.0-alpha.0" dependencies = [ "anyhow", + "assert_cmd", "async-dropper-simple", "async-trait", "axum", "bollard", + "clap 4.5.20", "futures", "futures-util", "http 1.1.0", "jstz_crypto", "jstz_node", "octez", + "predicates", "rand 0.8.5", "regex", "reqwest", @@ -3269,6 +3320,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + [[package]] name = "num-bigint" version = "0.3.3" @@ -3708,6 +3765,36 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "predicates" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" +dependencies = [ + "anstyle", + "difflib", + "float-cmp", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" + +[[package]] +name = "predicates-tree" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "pretty_assertions" version = "1.4.1" @@ -4893,6 +4980,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + [[package]] name = "textwrap" version = "0.16.1" diff --git a/Cargo.toml b/Cargo.toml index 914c7e7cc..2a6b3199b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ description = "JavaScript server runtime for Tezos Smart Rollups" [workspace.dependencies] ansi_term = "0.12.1" anyhow = "1.0.82" +assert_cmd = "2.0.14" async-dropper-simple = { version = "0.2.6", features = ["tokio"] } async-trait = "0.1.82" axum = "0.7.7" @@ -74,6 +75,7 @@ nix = { version = "^0.27.1", features = ["process", "signal"] } nom = "7.1.3" num-traits = "0.2.16" parking_lot = "0.12.1" +predicates = "3.1.0" prettytable = "0.10.0" pretty_assertions = "1.4.1" proptest = "1.1" diff --git a/crates/jstzd/Cargo.toml b/crates/jstzd/Cargo.toml index bbb4f53b6..262dcc55c 100644 --- a/crates/jstzd/Cargo.toml +++ b/crates/jstzd/Cargo.toml @@ -11,6 +11,7 @@ async-dropper-simple.workspace = true async-trait.workspace = true axum.workspace = true bollard.workspace = true +clap.workspace = true futures.workspace = true futures-util.workspace = true http.workspace = true @@ -25,6 +26,8 @@ tempfile.workspace = true tokio.workspace = true [dev-dependencies] +assert_cmd.workspace = true +predicates.workspace = true rand.workspace = true tezos_crypto_rs.workspace = true diff --git a/crates/jstzd/src/config.rs b/crates/jstzd/src/config.rs index 697a9aa74..13ff0a6af 100644 --- a/crates/jstzd/src/config.rs +++ b/crates/jstzd/src/config.rs @@ -1,4 +1,3 @@ -#![allow(dead_code)] use std::path::{Path, PathBuf}; use crate::task::jstzd::JstzdConfig; @@ -47,7 +46,9 @@ async fn parse_config(path: &str) -> Result { Ok(serde_json::from_str::(&s)?) } -async fn build_config(config_path: &Option) -> Result<(u16, JstzdConfig)> { +pub(crate) async fn build_config( + config_path: &Option, +) -> Result<(u16, JstzdConfig)> { let mut config = match config_path { Some(p) => parse_config(p).await?, None => default_config(), diff --git a/crates/jstzd/src/lib.rs b/crates/jstzd/src/lib.rs index 47437595a..8f62b85e7 100644 --- a/crates/jstzd/src/lib.rs +++ b/crates/jstzd/src/lib.rs @@ -1,13 +1,27 @@ mod config; pub mod docker; pub mod task; + pub use config::BOOTSTRAP_CONTRACT_NAMES; +use std::process::exit; + pub const EXCHANGER_ADDRESS: &str = "KT1F3MuqvT9Yz57TgCS3EkDcKNZe9HpiavUJ"; pub const JSTZ_ROLLUP_ADDRESS: &str = "sr1PuFMgaRUN12rKQ3J2ae5psNtwCxPNmGNK"; pub const JSTZ_NATIVE_BRIDGE_ADDRESS: &str = "KT1GFiPkkTjd14oHe6MrBPiRh5djzRkVWcni"; /// The `main` function for running jstzd -pub async fn main() -> anyhow::Result<()> { - println!("Hello, world!"); - Ok(()) +pub async fn main(config_path: &Option) { + match config::build_config(config_path).await { + Ok((_port, _config)) => { + // TODO: run JstzdServer here + println!("ready"); + } + Err(e) => { + match config_path { + Some(p) => eprintln!("failed to build config from {}: {:?}", p, e), + None => eprintln!("failed to build default config: {:?}", e), + }; + exit(1); + } + } } diff --git a/crates/jstzd/src/main.rs b/crates/jstzd/src/main.rs index acb9c8d51..535361f45 100644 --- a/crates/jstzd/src/main.rs +++ b/crates/jstzd/src/main.rs @@ -1,7 +1,21 @@ +use clap::{Parser, Subcommand}; + +#[derive(Parser, Debug)] +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand, Debug)] +enum Commands { + /// Run the sandbox + Run { config_path: Option }, +} + #[tokio::main] async fn main() { - if let Err(e) = jstzd::main().await { - eprintln!("Error: {:?}", e); - std::process::exit(1); + let cli = Cli::parse(); + match &cli.command { + Commands::Run { config_path } => jstzd::main(config_path).await, } } diff --git a/crates/jstzd/tests/dummy.rs b/crates/jstzd/tests/dummy.rs deleted file mode 100644 index d08a980df..000000000 --- a/crates/jstzd/tests/dummy.rs +++ /dev/null @@ -1,17 +0,0 @@ -use jstzd::main; -use tokio::process::Command; - -#[tokio::test] -async fn test_main() { - main().await.unwrap(); -} - -#[tokio::test] -async fn test_octez_client() { - let output = Command::new("octez-client") - .arg("--version") - .output() - .await - .unwrap(); - println!("octez-client --version: {:?}", output); -} diff --git a/crates/jstzd/tests/main_test.rs b/crates/jstzd/tests/main_test.rs new file mode 100644 index 000000000..2e8bbd7fb --- /dev/null +++ b/crates/jstzd/tests/main_test.rs @@ -0,0 +1,50 @@ +use assert_cmd::prelude::{CommandCargoExt, OutputAssertExt}; +use predicates::prelude::predicate; +use std::{io::Write, process::Command}; +use tempfile::NamedTempFile; + +#[test] +fn unknown_command() { + let mut cmd = Command::cargo_bin("jstzd").unwrap(); + + cmd.arg("test") + .assert() + .failure() + .stderr(predicate::str::contains("unrecognized subcommand \'test\'")); +} + +#[test] +fn default_config() { + let mut cmd = Command::cargo_bin("jstzd").unwrap(); + + cmd.arg("run") + .assert() + .success() + .stdout(predicate::str::contains("ready")); +} + +#[test] +fn valid_config_file() { + let mut cmd = Command::cargo_bin("jstzd").unwrap(); + let mut tmp_file = NamedTempFile::new().unwrap(); + tmp_file.write_all(r#"{"protocol":{"bootstrap_accounts":[["edpkuSLWfVU1Vq7Jg9FucPyKmma6otcMHac9zG4oU1KMHSTBpJuGQ2","6000000000"]]}}"#.as_bytes()).unwrap(); + + cmd.args(["run", &tmp_file.path().to_string_lossy()]) + .assert() + .success() + .stdout(predicate::str::contains("ready")); +} + +#[test] +fn bad_config_file() { + let mut cmd = Command::cargo_bin("jstzd").unwrap(); + let mut tmp_file = NamedTempFile::new().unwrap(); + tmp_file.write_all("{}".as_bytes()).unwrap(); + + cmd.args(["run", &tmp_file.path().to_string_lossy()]) + .assert() + .failure() + .stderr(predicate::str::contains( + "should have at least one bootstrap account with at least 6000 tez", + )); +}