Add testing for beacon node and validator client CLI flags (#2311)

## Issue Addressed

N/A

## Proposed Changes

Add unit tests for the various CLI flags associated with the beacon node and validator client. These changes require the addition of two new flags: `dump-config` and `immediate-shutdown`.

## Additional Info

Both `dump-config` and `immediate-shutdown` are marked as hidden since they should only be used in testing and other advanced use cases.
**Note:** This requires changing `main.rs` so that the flags can adjust the program behavior as necessary.

Co-authored-by: Paul Hauner <paul@paulhauner.com>
This commit is contained in:
Mac L
2021-05-06 00:36:22 +00:00
parent 4cc613d644
commit bacc38c3da
16 changed files with 1327 additions and 47 deletions

View File

@@ -7,8 +7,10 @@ use environment::EnvironmentBuilder;
use eth2_network_config::{Eth2NetworkConfig, DEFAULT_HARDCODED_NETWORK};
use lighthouse_version::VERSION;
use slog::{crit, info, warn};
use std::fs::File;
use std::path::PathBuf;
use std::process::exit;
use task_executor::ShutdownReason;
use types::{EthSpec, EthSpecId};
use validator_client::ProductionValidatorClient;
@@ -125,6 +127,23 @@ fn main() {
.global(true)
)
.arg(
Arg::with_name("dump-config")
.long("dump-config")
.hidden(true)
.help("Dumps the config to a desired location. Used for testing only.")
.takes_value(true)
.global(true)
)
.arg(
Arg::with_name("immediate-shutdown")
.long("immediate-shutdown")
.hidden(true)
.help(
"Shuts down immediately after the Beacon Node or Validator has successfully launched. \
Used for testing only, DO NOT USE IN PRODUCTION.")
.global(true)
)
.subcommand(beacon_node::cli_app())
.subcommand(boot_node::cli_app())
.subcommand(validator_client::cli_app())
@@ -285,6 +304,15 @@ fn run<E: EthSpec>(
&context.eth2_config().spec,
context.log().clone(),
)?;
let shutdown_flag = matches.is_present("immediate-shutdown");
if let Some(dump_path) = clap_utils::parse_optional::<PathBuf>(matches, "dump-config")?
{
let mut file = File::create(dump_path)
.map_err(|e| format!("Failed to create dumped config: {:?}", e))?;
serde_json::to_writer(&mut file, &config)
.map_err(|e| format!("Error serializing config: {:?}", e))?;
};
environment.runtime().spawn(async move {
if let Err(e) = ProductionBeaconNode::new(context.clone(), config).await {
crit!(log, "Failed to start beacon node"; "reason" => e);
@@ -292,7 +320,11 @@ fn run<E: EthSpec>(
// shutting down.
let _ = executor
.shutdown_sender()
.try_send("Failed to start beacon node");
.try_send(ShutdownReason::Failure("Failed to start beacon node"));
} else if shutdown_flag {
let _ = executor.shutdown_sender().try_send(ShutdownReason::Success(
"Beacon node immediate shutdown triggered.",
));
}
});
}
@@ -302,23 +334,34 @@ fn run<E: EthSpec>(
let executor = context.executor.clone();
let config = validator_client::Config::from_cli(&matches, context.log())
.map_err(|e| format!("Unable to initialize validator config: {}", e))?;
environment.runtime().spawn(async move {
let run = async {
ProductionValidatorClient::new(context, config)
let shutdown_flag = matches.is_present("immediate-shutdown");
if let Some(dump_path) = clap_utils::parse_optional::<PathBuf>(matches, "dump-config")?
{
let mut file = File::create(dump_path)
.map_err(|e| format!("Failed to create dumped config: {:?}", e))?;
serde_json::to_writer(&mut file, &config)
.map_err(|e| format!("Error serializing config: {:?}", e))?;
};
if !shutdown_flag {
environment.runtime().spawn(async move {
if let Err(e) = ProductionValidatorClient::new(context, config)
.await?
.start_service()?;
.start_service()
{
crit!(log, "Failed to start validator client"; "reason" => e);
// Ignore the error since it always occurs during normal operation when
// shutting down.
let _ = executor
.shutdown_sender()
.try_send(ShutdownReason::Failure("Failed to start validator client"));
}
Ok::<(), String>(())
};
if let Err(e) = run.await {
crit!(log, "Failed to start validator client"; "reason" => e);
// Ignore the error since it always occurs during normal operation when
// shutting down.
let _ = executor
.shutdown_sender()
.try_send("Failed to start validator client");
}
});
});
} else {
let _ = executor.shutdown_sender().try_send(ShutdownReason::Success(
"Validator client immediate shutdown triggered.",
));
}
}
("remote_signer", Some(matches)) => {
if let Err(e) = remote_signer::run(&mut environment, matches) {
@@ -327,7 +370,7 @@ fn run<E: EthSpec>(
.core_context()
.executor
.shutdown_sender()
.try_send("Failed to start remote signer");
.try_send(ShutdownReason::Failure("Failed to start remote signer"));
}
}
_ => {
@@ -337,12 +380,16 @@ fn run<E: EthSpec>(
};
// Block this thread until we get a ctrl-c or a task sends a shutdown signal.
environment.block_until_shutdown_requested()?;
info!(log, "Shutting down..");
let shutdown_reason = environment.block_until_shutdown_requested()?;
info!(log, "Shutting down.."; "reason" => ?shutdown_reason);
environment.fire_signal();
// Shutdown the environment once all tasks have completed.
environment.shutdown_on_idle();
Ok(())
match shutdown_reason {
ShutdownReason::Success(_) => Ok(()),
ShutdownReason::Failure(msg) => Err(msg.to_string()),
}
}