blob: 6b50075c28c6f7c3dc291176476f34e990301eb8 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![cfg(test)]
use {
anyhow::Context as _,
fuchsia_component::{client::AppBuilder, server::ServiceFs},
futures::{FutureExt as _, StreamExt as _, TryStreamExt as _},
net_declare::fidl_ip_v4,
};
struct Command<'a> {
args: Vec<&'a str>,
expected_stdout: &'a str,
expected_stderr: &'a str,
}
async fn test_cli_with_config(
parameters: &mut [fidl_fuchsia_net_dhcp::Parameter],
commands: Vec<Command<'_>>,
) {
let mut fs = ServiceFs::new_local();
let mut netstack_builder =
AppBuilder::new("fuchsia-pkg://fuchsia.com/dhcpd-cli-tests#meta/netstack-debug.cmx");
let mut stash_builder =
AppBuilder::new("fuchsia-pkg://fuchsia.com/dhcpd-cli-tests#meta/stash_secure.cmx");
let mut dhcpd_builder =
AppBuilder::new("fuchsia-pkg://fuchsia.com/dhcpd-cli-tests#meta/dhcpd.cmx");
fs.add_proxy_service_to::<fidl_fuchsia_stash::SecureStoreMarker, _>(
stash_builder
.directory_request()
.expect("failed to get test stash directory request")
.clone(),
)
.add_proxy_service_to::<fidl_fuchsia_posix_socket::ProviderMarker, _>(
netstack_builder
.directory_request()
.expect("failed to get test netstack directory request")
.clone(),
)
.add_proxy_service_to::<fidl_fuchsia_net_dhcp::Server_Marker, _>(
dhcpd_builder
.directory_request()
.expect("failed to get test dhcpd directory request")
.clone(),
);
let env =
fs.create_salted_nested_environment("test_cli").expect("failed to create environment");
let fs = fs.for_each_concurrent(None, futures::future::ready);
futures::pin_mut!(fs);
let _stash = stash_builder.spawn(env.launcher()).expect("failed to launch test stash");
let dhcpd = dhcpd_builder.spawn(env.launcher()).expect("failed to launch test dhcpd");
let _netstack = netstack_builder.spawn(env.launcher()).expect("failed to launch test netstack");
let dhcp_server = dhcpd
.connect_to_service::<fidl_fuchsia_net_dhcp::Server_Marker>()
.expect("failed to connect to DHCP server");
let dhcp_server_ref = &dhcp_server;
let test_fut = async {
let () = futures::stream::iter(parameters.iter_mut())
.map(Ok)
.try_for_each_concurrent(None, |parameter| async move {
dhcp_server_ref
.set_parameter(parameter)
.await
.context("failed to call dhcp/Server.SetParameter")?
.map_err(fuchsia_zircon::Status::from_raw)
.with_context(|| {
format!("dhcp/Server.SetParameter({:?}) returned error", parameter)
})
})
.await
.expect("failed to configure DHCP server");
for Command { args, expected_stdout, expected_stderr } in commands {
let output =
AppBuilder::new("fuchsia-pkg://fuchsia.com/dhcpd-cli-tests#meta/dhcpd-cli.cmx")
.args(args)
.output(env.launcher())
.expect("failed to launch dhcpd-cli")
.await
.expect("failed to collect dhcpd-cli output");
let stdout = std::str::from_utf8(&output.stdout).expect("failed to get stdout");
let stderr = std::str::from_utf8(&output.stderr).expect("failed to get stderr");
assert_eq!(stderr, expected_stderr);
assert_eq!(stdout, expected_stdout);
}
};
futures::select! {
() = fs => panic!("request stream terminated"),
() = test_fut.fuse() => {},
};
}
async fn test_cli(commands: Vec<Command<'_>>) {
test_cli_with_config(&mut [], commands).await
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_get_option_subnet() {
test_cli(vec![Command {
args: vec!["get", "option", "subnet-mask"],
expected_stdout: "",
expected_stderr: r#"Error: get_option(SubnetMask(SubnetMask { mask: None })) failed
Caused by:
NOT_FOUND
"#,
}])
.await
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_get_parameter_lease() {
test_cli(vec![Command {
args: vec!["get", "parameter", "lease-length"],
expected_stdout: r#"Lease(
LeaseLength {
default: Some(
86400,
),
max: Some(
86400,
),
unknown_data: None,
__non_exhaustive: (),
},
)
"#,
expected_stderr: "",
}])
.await
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_set_option_subnet() {
test_cli(vec![Command {
args: vec!["set", "option", "subnet-mask", "--mask", "255.255.255.0"],
expected_stdout: "",
expected_stderr: "",
}])
.await
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_set_parameter_lease() {
test_cli(vec![Command {
args: vec!["set", "parameter", "lease-length", "--default", "42"],
expected_stdout: "",
expected_stderr: "",
}])
.await
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_list_option() {
test_cli(vec![
Command {
args: vec!["set", "option", "subnet-mask", "--mask", "255.255.255.0"],
expected_stdout: "",
expected_stderr: "",
},
Command {
args: vec!["list", "option"],
expected_stdout: r#"[
SubnetMask(
Ipv4Address {
addr: [
255,
255,
255,
0,
],
},
),
]
"#,
expected_stderr: "",
},
])
.await
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_list_parameter() {
test_cli(vec![Command {
args: vec!["list", "parameter"],
expected_stdout: r#"[
IpAddrs(
[],
),
AddressPool(
AddressPool {
network_id: Some(
Ipv4Address {
addr: [
0,
0,
0,
0,
],
},
),
broadcast: Some(
Ipv4Address {
addr: [
0,
0,
0,
0,
],
},
),
mask: Some(
Ipv4Address {
addr: [
0,
0,
0,
0,
],
},
),
pool_range_start: Some(
Ipv4Address {
addr: [
0,
0,
0,
0,
],
},
),
pool_range_stop: Some(
Ipv4Address {
addr: [
0,
0,
0,
0,
],
},
),
unknown_data: None,
__non_exhaustive: (),
},
),
Lease(
LeaseLength {
default: Some(
86400,
),
max: Some(
86400,
),
unknown_data: None,
__non_exhaustive: (),
},
),
PermittedMacs(
[],
),
StaticallyAssignedAddrs(
[],
),
ArpProbe(
false,
),
BoundDeviceNames(
[],
),
]
"#,
expected_stderr: "",
}])
.await
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_reset_option() {
test_cli(vec![
Command {
args: vec!["set", "option", "subnet-mask", "--mask", "255.255.255.0"],
expected_stdout: "",
expected_stderr: "",
},
Command {
args: vec!["list", "option"],
expected_stdout: r#"[
SubnetMask(
Ipv4Address {
addr: [
255,
255,
255,
0,
],
},
),
]
"#,
expected_stderr: "",
},
Command { args: vec!["reset", "option"], expected_stdout: "", expected_stderr: "" },
Command { args: vec!["list", "option"], expected_stdout: "[]\n", expected_stderr: "" },
])
.await
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_reset_parameter() {
test_cli(vec![
Command {
args: vec!["set", "parameter", "lease-length", "--default", "42"],
expected_stdout: "",
expected_stderr: "",
},
Command {
args: vec!["get", "parameter", "lease-length"],
expected_stdout: r#"Lease(
LeaseLength {
default: Some(
42,
),
max: Some(
42,
),
unknown_data: None,
__non_exhaustive: (),
},
)
"#,
expected_stderr: "",
},
Command { args: vec!["reset", "parameter"], expected_stdout: "", expected_stderr: "" },
Command {
args: vec!["get", "parameter", "lease-length"],
expected_stdout: r#"Lease(
LeaseLength {
default: Some(
86400,
),
max: Some(
86400,
),
unknown_data: None,
__non_exhaustive: (),
},
)
"#,
expected_stderr: "",
},
])
.await
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_clear_leases() {
test_cli(vec![Command { args: vec!["clear-leases"], expected_stdout: "", expected_stderr: "" }])
.await
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_start_fails() {
test_cli(vec![Command {
args: vec!["start"],
expected_stdout: "",
// Starting the server fails because the default configuration has an
// empty address pool.
expected_stderr: "Error: failed to start server\n\nCaused by:\n INVALID_ARGS\n",
}])
.await
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_start_succeeds() {
test_cli_with_config(
&mut [
fidl_fuchsia_net_dhcp::Parameter::IpAddrs(vec![fidl_ip_v4!("192.168.0.1")]),
fidl_fuchsia_net_dhcp::Parameter::AddressPool(fidl_fuchsia_net_dhcp::AddressPool {
network_id: Some(fidl_ip_v4!("192.168.0.0")),
broadcast: Some(fidl_ip_v4!("192.168.0.127")),
mask: Some(fidl_ip_v4!("255.255.255.128")),
pool_range_start: Some(fidl_ip_v4!("192.168.0.2")),
pool_range_stop: Some(fidl_ip_v4!("192.168.0.5")),
..fidl_fuchsia_net_dhcp::AddressPool::EMPTY
}),
fidl_fuchsia_net_dhcp::Parameter::BoundDeviceNames(vec!["lo".to_string()]),
],
vec![Command { args: vec!["start"], expected_stdout: "", expected_stderr: "" }],
)
.await
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_stop() {
test_cli(vec![Command { args: vec!["stop"], expected_stdout: "", expected_stderr: "" }]).await
}