lighthouse-pulse/lighthouse/tests/boot_node.rs
Paul Hauner 0a6a8ea3b0 Engine API v1.0.0.alpha.6 + interop tests (#3024)
## Issue Addressed

NA

## Proposed Changes

This PR extends #3018 to address my review comments there and add automated integration tests with Geth (and other implementations, in the future).

I've also de-duplicated the "unused port" logic by creating an  `common/unused_port` crate.

## Additional Info

I'm not sure if we want to merge this PR, or update #3018 and merge that. I don't mind, I'm primarily opening this PR to make sure CI works.


Co-authored-by: Mark Mackey <mark@sigmaprime.io>
2022-02-17 21:47:06 +00:00

173 lines
5.5 KiB
Rust

use boot_node::config::BootNodeConfigSerialization;
use crate::exec::{CommandLineTestExec, CompletedTest};
use clap::ArgMatches;
use clap_utils::get_eth2_network_config;
use lighthouse_network::discovery::ENR_FILENAME;
use lighthouse_network::Enr;
use std::fs::File;
use std::io::Write;
use std::net::Ipv4Addr;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str::FromStr;
use tempfile::TempDir;
use unused_port::unused_udp_port;
const IP_ADDRESS: &str = "192.168.2.108";
/// Returns the `lighthouse boot_node` command.
fn base_cmd() -> Command {
let lighthouse_bin = env!("CARGO_BIN_EXE_lighthouse");
let path = lighthouse_bin
.parse::<PathBuf>()
.expect("should parse CARGO_TARGET_DIR");
let mut cmd = Command::new(path);
cmd.arg("boot_node");
cmd
}
struct CommandLineTest {
cmd: Command,
}
impl CommandLineTest {
fn new() -> CommandLineTest {
let base_cmd = base_cmd();
CommandLineTest { cmd: base_cmd }
}
fn run_with_ip(&mut self) -> CompletedTest<BootNodeConfigSerialization> {
self.cmd.arg(IP_ADDRESS);
self.run()
}
}
impl CommandLineTestExec for CommandLineTest {
type Config = BootNodeConfigSerialization;
fn cmd_mut(&mut self) -> &mut Command {
&mut self.cmd
}
}
#[test]
fn enr_address_arg() {
let mut test = CommandLineTest::new();
test.run_with_ip().with_config(|config| {
assert_eq!(config.local_enr.ip(), Some(IP_ADDRESS.parse().unwrap()));
});
}
#[test]
fn port_flag() {
let port = unused_udp_port().unwrap();
CommandLineTest::new()
.flag("port", Some(port.to_string().as_str()))
.run_with_ip()
.with_config(|config| {
assert_eq!(config.listen_socket.port(), port);
})
}
#[test]
fn listen_address_flag() {
let addr = "127.0.0.2".parse::<Ipv4Addr>().unwrap();
CommandLineTest::new()
.flag("listen-address", Some("127.0.0.2"))
.run_with_ip()
.with_config(|config| {
assert_eq!(config.listen_socket.ip(), addr);
});
}
#[test]
fn boot_nodes_flag() {
// Get hardcoded boot-nodes to verify they end up in the config.
// Pass empty `ArgMatches` to `get_eth2_network_config` as we want to
// receive the default `Eth2NetworkConfig`.
let empty_args = ArgMatches::default();
let default_enr = get_eth2_network_config(&empty_args)
.unwrap()
.boot_enr
.unwrap();
let default_enr: Vec<String> = default_enr.iter().map(|enr| enr.to_base64()).collect();
// Nodes passed via `--boot-nodes` are added to the local routing table.
let extra_nodes = "enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8,enr:-LK4QFOFWca5ABQzxiCRcy37G7wy1K6zD4qMYBSN5ozzanwze_XVvXVhCk9JvF0cHXOBZrHK1E4vU7Gn-a0bHVczoDU6h2F0dG5ldHOIAAAAAAAAAACEZXRoMpA7CIeVAAAgCf__________gmlkgnY0gmlwhNIy-4iJc2VjcDI1NmsxoQJA3AXQJ6M3NpBWtJS3HPtbXG14t7qHjXuIaL6IOz89T4N0Y3CCIyiDdWRwgiMo";
let extra_enr: Vec<&str> = extra_nodes.split(",").collect();
// Construct vector of enr expected in config.
let default_enr_str: Vec<&str> = default_enr.iter().map(|s| s.as_str()).collect();
let mut expect_enr = Vec::new();
expect_enr.extend_from_slice(&default_enr_str);
expect_enr.extend_from_slice(&extra_enr);
CommandLineTest::new()
.flag("boot-nodes", Some(extra_nodes))
.run_with_ip()
.with_config(|config| {
assert_eq!(config.boot_nodes.len(), expect_enr.len());
for (i, enr) in config.boot_nodes.iter().enumerate() {
assert_eq!(
enr.to_base64(),
expect_enr[i],
"ENR missmatch at index [{}]",
i
);
}
})
}
#[test]
fn enr_port_flag() {
let port = unused_udp_port().unwrap();
CommandLineTest::new()
.flag("enr-port", Some(port.to_string().as_str()))
.run_with_ip()
.with_config(|config| {
assert_eq!(config.local_enr.udp(), Some(port));
})
}
#[test]
fn disable_packet_filter_flag() {
CommandLineTest::new()
.flag("disable-packet-filter", None)
.run_with_ip()
.with_config(|config| {
assert_eq!(config.disable_packet_filter, true);
});
}
#[test]
fn enable_enr_auto_update_flag() {
CommandLineTest::new()
.flag("enable-enr-auto-update", None)
.run_with_ip()
.with_config(|config| {
assert_eq!(config.enable_enr_auto_update, true);
});
}
#[test]
fn network_dir_flag() {
// Save enr to temp dir.
let enr = Enr::from_str("enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8").unwrap();
let tmp_dir = TempDir::new().unwrap();
save_enr_to_disk(tmp_dir.path(), &enr).unwrap();
CommandLineTest::new()
.flag("network-dir", Some(tmp_dir.path().to_str().unwrap()))
.run()
.with_config(|config| assert_eq!(config.local_enr, enr))
}
fn save_enr_to_disk(dir: &Path, enr: &Enr) -> Result<(), String> {
let mut file = File::create(dir.join(Path::new(ENR_FILENAME)))
.map_err(|e| format!("Could not create ENR file: {:?}", e))?;
file.write_all(enr.to_base64().as_bytes())
.map_err(|e| format!("Could not write ENR to file: {:?}", e))
}