From f06f245ece5d019be55f741e8cc04144475522f7 Mon Sep 17 00:00:00 2001 From: arya2 Date: Fri, 26 Aug 2022 12:33:40 -0400 Subject: [PATCH] moves EntryPoint to submodule and adds a test --- zebrad/src/application.rs | 107 ++------------------------ zebrad/src/application/entry_point.rs | 104 +++++++++++++++++++++++++ zebrad/tests/acceptance.rs | 31 ++++++++ 3 files changed, 141 insertions(+), 101 deletions(-) create mode 100644 zebrad/src/application/entry_point.rs diff --git a/zebrad/src/application.rs b/zebrad/src/application.rs index 424e4a8d3..6ebd51c98 100644 --- a/zebrad/src/application.rs +++ b/zebrad/src/application.rs @@ -1,25 +1,22 @@ //! Zebrad Abscissa Application -use std::{fmt::Write as _, io::Write as _, path::PathBuf, process}; +mod entry_point; +use self::entry_point::EntryPoint; + +use std::{fmt::Write as _, io::Write as _, process}; use abscissa_core::{ application::{self, fatal_error, AppCell}, - command::{Command, Usage}, config::{self, Configurable}, status_err, terminal::{component::Terminal, stderr, stdout, ColorChoice}, - Application, Component, FrameworkError, Options, Runnable, Shutdown, StandardPaths, - Version, + Application, Component, FrameworkError, Shutdown, StandardPaths, Version, }; use zebra_network::constants::PORT_IN_USE_ERROR; use zebra_state::constants::{DATABASE_FORMAT_VERSION, LOCK_FILE_ERROR}; -use crate::{ - commands::{StartCmd, ZebradCmd}, - components::tracing::Tracing, - config::ZebradConfig, -}; +use crate::{commands::ZebradCmd, components::tracing::Tracing, config::ZebradConfig}; /// Application state pub static APPLICATION: AppCell = AppCell::new(); @@ -43,98 +40,6 @@ pub fn app_config() -> config::Reader { config::Reader::new(&APPLICATION) } -/// Toplevel entrypoint command. -/// -/// Handles obtaining toplevel help as well as verbosity settings. -#[derive(Debug, Options)] -pub struct EntryPoint { - #[options(help = "tracing filters which override the zebrad.toml config")] - filters: Vec, - - /// Path to the configuration file - #[options(short = "c", help = "path to configuration file")] - pub config: Option, - - /// Obtain help about the current command - #[options(short = "h", help = "print help message")] - pub help: bool, - - /// Increase verbosity setting - #[options(short = "v", help = "be verbose")] - pub verbose: bool, - - /// Subcommand to execute. - /// - /// The `command` option will delegate option parsing to the command type, - /// starting at the first free argument. Defaults to start. - #[options(command, default_expr = "Some(ZebradCmd::Start(StartCmd::default()))")] - pub command: Option, -} - -impl EntryPoint { - /// Borrow the underlying command type or print usage info and exit - fn command(&self) -> &ZebradCmd { - self.command - .as_ref() - .expect("Some(ZebradCmd::Start(StartCmd::default()) as default value") - } -} - -impl Runnable for EntryPoint { - fn run(&self) { - self.command().run() - } -} - -impl Command for EntryPoint { - /// Name of this program as a string - fn name() -> &'static str { - ZebradCmd::name() - } - - /// Description of this program - fn description() -> &'static str { - ZebradCmd::description() - } - - /// Version of this program - fn version() -> &'static str { - ZebradCmd::version() - } - - /// Authors of this program - fn authors() -> &'static str { - ZebradCmd::authors() - } - - /// Get usage information for a particular subcommand (if available) - fn subcommand_usage(command: &str) -> Option { - ZebradCmd::subcommand_usage(command) - } -} - -impl Configurable for EntryPoint { - /// Path to the command's configuration file - fn config_path(&self) -> Option { - match &self.config { - // Use explicit `-c`/`--config` argument if passed - Some(cfg) => Some(cfg.clone()), - - // Otherwise defer to the toplevel command's config path logic - None => self.command.as_ref().and_then(|cmd| cmd.config_path()), - } - } - - /// Process the configuration after it has been loaded, potentially - /// modifying it or returning an error if options are incompatible - fn process_config(&self, config: ZebradConfig) -> Result { - match &self.command { - Some(cmd) => cmd.process_config(config), - None => Ok(config), - } - } -} - /// Returns the zebrad version for this build, in SemVer 2.0 format. /// /// Includes the git commit and the number of commits since the last version diff --git a/zebrad/src/application/entry_point.rs b/zebrad/src/application/entry_point.rs new file mode 100644 index 000000000..75af7f70c --- /dev/null +++ b/zebrad/src/application/entry_point.rs @@ -0,0 +1,104 @@ +//! Zebrad EntryPoint + +use crate::{ + commands::{StartCmd, ZebradCmd}, + config::ZebradConfig, +}; + +use std::path::PathBuf; + +use abscissa_core::{ + command::{Command, Usage}, + config::Configurable, + FrameworkError, Options, Runnable, +}; + +// (See https://docs.rs/abscissa_core/0.5.2/src/abscissa_core/command/entrypoint.rs.html) +/// Toplevel entrypoint command. +/// +/// Handles obtaining toplevel help as well as verbosity settings. +#[derive(Debug, Options)] +pub struct EntryPoint { + /// Path to the configuration file + #[options(short = "c", help = "path to configuration file")] + pub config: Option, + + /// Obtain help about the current command + #[options(short = "h", help = "print help message")] + pub help: bool, + + /// Increase verbosity setting + #[options(short = "v", help = "be verbose")] + pub verbose: bool, + + /// Subcommand to execute. + /// + /// The `command` option will delegate option parsing to the command type, + /// starting at the first free argument. Defaults to start. + #[options(command, default_expr = "Some(ZebradCmd::Start(StartCmd::default()))")] + pub command: Option, +} + +impl EntryPoint { + /// Borrow the underlying command type or print usage info and exit + fn command(&self) -> &ZebradCmd { + self.command + .as_ref() + .expect("Some(ZebradCmd::Start(StartCmd::default()) as default value") + } +} + +impl Runnable for EntryPoint { + fn run(&self) { + self.command().run() + } +} + +impl Command for EntryPoint { + /// Name of this program as a string + fn name() -> &'static str { + ZebradCmd::name() + } + + /// Description of this program + fn description() -> &'static str { + ZebradCmd::description() + } + + /// Version of this program + fn version() -> &'static str { + ZebradCmd::version() + } + + /// Authors of this program + fn authors() -> &'static str { + ZebradCmd::authors() + } + + /// Get usage information for a particular subcommand (if available) + fn subcommand_usage(command: &str) -> Option { + ZebradCmd::subcommand_usage(command) + } +} + +impl Configurable for EntryPoint { + /// Path to the command's configuration file + fn config_path(&self) -> Option { + match &self.config { + // Use explicit `-c`/`--config` argument if passed + Some(cfg) => Some(cfg.clone()), + + // Otherwise defer to the toplevel command's config path logic + None => self.command.as_ref().and_then(|cmd| cmd.config_path()), + } + } + + /// Process the configuration after it has been loaded, potentially + /// modifying it or returning an error if options are incompatible + fn process_config(&self, config: ZebradConfig) -> Result { + match &self.command { + Some(cmd) => cmd.process_config(config), + None => Ok(config), + } + } +} diff --git a/zebrad/tests/acceptance.rs b/zebrad/tests/acceptance.rs index 594efeabb..57151a353 100644 --- a/zebrad/tests/acceptance.rs +++ b/zebrad/tests/acceptance.rs @@ -501,6 +501,37 @@ fn config_test() -> Result<()> { // Check that an older stored configuration we have for Zebra works stored_config_works()?; + // Runs `zebrad` serially to avoid potential port conflicts + app_no_args()?; + + Ok(()) +} + +/// Test that `zebrad` runs the start command with no args +fn app_no_args() -> Result<()> { + let _init_guard = zebra_test::init(); + + // start caches state, so run one of the start tests with persistent state + let testdir = testdir()?.with_config(&mut persistent_test_config()?)?; + + let mut child = testdir.spawn_child(args![])?; + + // Run the program and kill it after a few seconds + std::thread::sleep(LAUNCH_DELAY); + child.kill()?; + + let output = child.wait_with_output()?; + let output = output.assert_failure()?; + + output.stdout_line_contains("Starting zebrad")?; + + // Make sure the command passed the legacy chain check + output.stdout_line_contains("starting legacy chain check")?; + output.stdout_line_contains("no legacy chain found")?; + + // Make sure the command was killed + output.assert_was_killed()?; + Ok(()) }