From a09fb96ac0d07a783febafe2f73323fba2d69d0b Mon Sep 17 00:00:00 2001 From: Huan-Cheng Chang Date: Fri, 29 Nov 2024 15:42:35 +0000 Subject: [PATCH] feat(jstzd): launch jstzd server with cli --- Cargo.toml | 2 +- crates/jstzd/src/lib.rs | 20 +++++++++--- crates/jstzd/src/task/jstzd.rs | 13 +++++++- crates/jstzd/tests/main_test.rs | 58 ++++++++++++++++++++++++--------- 4 files changed, 71 insertions(+), 22 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2a6b3199b..a06c118e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,7 +81,7 @@ pretty_assertions = "1.4.1" proptest = "1.1" rand = "0.8" regex = "1" -reqwest = { version = "0.11.24", features = ["json"] } +reqwest = { version = "0.11.24", features = ["json", "blocking"] } reqwest-eventsource = "0.5.0" rust-embed = { version = "8.5.0", features = ["interpolate-folder-path"] } rustyline = "14.0.0" diff --git a/crates/jstzd/src/lib.rs b/crates/jstzd/src/lib.rs index 8f62b85e7..01e060c78 100644 --- a/crates/jstzd/src/lib.rs +++ b/crates/jstzd/src/lib.rs @@ -2,6 +2,7 @@ mod config; pub mod docker; pub mod task; +use crate::task::jstzd::{JstzdConfig, JstzdServer}; pub use config::BOOTSTRAP_CONTRACT_NAMES; use std::process::exit; @@ -12,10 +13,7 @@ pub const JSTZ_NATIVE_BRIDGE_ADDRESS: &str = "KT1GFiPkkTjd14oHe6MrBPiRh5djzRkVWc /// The `main` function for running jstzd pub async fn main(config_path: &Option) { match config::build_config(config_path).await { - Ok((_port, _config)) => { - // TODO: run JstzdServer here - println!("ready"); - } + Ok((port, config)) => run(port, config).await, Err(e) => { match config_path { Some(p) => eprintln!("failed to build config from {}: {:?}", p, e), @@ -25,3 +23,17 @@ pub async fn main(config_path: &Option) { } } } + +async fn run(port: u16, config: JstzdConfig) { + let mut server = JstzdServer::new(config, port); + if let Err(e) = server.run().await { + eprintln!("failed to run jstzd server: {:?}", e); + let _ = server.stop().await; + exit(1); + } + + server.wait().await; + + println!("Shutting down"); + server.stop().await.unwrap(); +} diff --git a/crates/jstzd/src/task/jstzd.rs b/crates/jstzd/src/task/jstzd.rs index b9a745a50..0a85e6c6c 100644 --- a/crates/jstzd/src/task/jstzd.rs +++ b/crates/jstzd/src/task/jstzd.rs @@ -242,7 +242,7 @@ impl JstzdServer { } pub async fn run(&mut self) -> Result<()> { - let jstzd = Jstzd::spawn( + let jstzd = Self::spawn_jstzd( self.inner .state .read() @@ -281,6 +281,17 @@ impl JstzdServer { false } } + + async fn spawn_jstzd(jstzd_config: JstzdConfig) -> Result { + let mut jstzd = Jstzd::spawn(jstzd_config).await?; + + let jstzd_healthy = retry(60, 500, || async { jstzd.health_check().await }).await; + if !jstzd_healthy { + let _ = jstzd.kill().await; + anyhow::bail!("jstzd never turns healthy"); + } + Ok(jstzd) + } } async fn health_check(state: &ServerState) -> bool { diff --git a/crates/jstzd/tests/main_test.rs b/crates/jstzd/tests/main_test.rs index 2e8bbd7fb..bc57891e4 100644 --- a/crates/jstzd/tests/main_test.rs +++ b/crates/jstzd/tests/main_test.rs @@ -1,5 +1,8 @@ use assert_cmd::prelude::{CommandCargoExt, OutputAssertExt}; +use octez::unused_port; use predicates::prelude::predicate; +use std::thread; +use std::time::Duration; use std::{io::Write, process::Command}; use tempfile::NamedTempFile; @@ -13,26 +16,49 @@ fn unknown_command() { .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 port = unused_port(); let mut tmp_file = NamedTempFile::new().unwrap(); - tmp_file.write_all(r#"{"protocol":{"bootstrap_accounts":[["edpkuSLWfVU1Vq7Jg9FucPyKmma6otcMHac9zG4oU1KMHSTBpJuGQ2","6000000000"]]}}"#.as_bytes()).unwrap(); + tmp_file.write_all(format!(r#"{{"protocol":{{"bootstrap_accounts":[["edpkuSLWfVU1Vq7Jg9FucPyKmma6otcMHac9zG4oU1KMHSTBpJuGQ2","15000000000"]]}},"server_port":{}}}"#, port).as_bytes()).unwrap(); - cmd.args(["run", &tmp_file.path().to_string_lossy()]) - .assert() - .success() - .stdout(predicate::str::contains("ready")); + let handle = thread::spawn(move || { + Command::cargo_bin("jstzd") + .unwrap() + .args(["run", &tmp_file.path().to_string_lossy()]) + .assert() + .success() + // baker log writes to stderr + .stderr(predicate::str::contains( + "block ready for delegate: activator", + )); + }); + + let client = reqwest::blocking::Client::new(); + for _ in 0..30 { + thread::sleep(Duration::from_secs(1)); + if let Ok(r) = client + .get(&format!("http://localhost:{port}/health")) + .send() + { + if r.status().is_success() { + break; + } + } + } + + // wait for 5 more seconds to ensure that the baker starts baking in order to + // observe the expected log line above + thread::sleep(Duration::from_secs(5)); + assert!(client + .put(&format!("http://localhost:{port}/shutdown")) + .send() + .unwrap() + .status() + .is_success()); + handle + .join() + .expect("jstzd should have been taken down without any error"); } #[test]