blob: 4da3f8f7eba7044be64bd8aae030c69828646ee3 [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.
#![feature(async_await, await_macro, futures_api)]
fn main() {
// We're only using this binary to show rust unit tests using the sandbox_service.
panic!("This program does nothing");
}
#[cfg(test)]
mod tests {
use {
failure::{format_err, Error, ResultExt},
fidl::endpoints::ServiceMarker,
fidl_fuchsia_netemul_environment::{
EnvironmentOptions, LaunchService, ManagedEnvironmentMarker, ManagedEnvironmentProxy,
},
fidl_fuchsia_netemul_network::{
NetworkConfig, NetworkContextMarker, NetworkManagerMarker, NetworkProxy,
},
fidl_fuchsia_netemul_sandbox::{LaunchOptions, SandboxMarker, SandboxProxy},
fidl_fuchsia_netemul_sync::{BusMarker, Event, SyncManagerMarker},
fidl_fuchsia_netstack::NetstackMarker,
fidl_fuchsia_sys::TerminationReason,
fuchsia_app::client,
fuchsia_async::{self as fasync, TimeoutExt},
fuchsia_zircon::{self as zx, DurationNum},
};
const DUMMY_PROC: &'static str =
"fuchsia-pkg://fuchsia.com/netemul_sandbox_test#meta/dummy_proc.cmx";
const TEST_TIMEOUT: i64 = 2;
const TEST_BUS: &'static str = "test-bus";
const BUS_CLIENT_NAME: &'static str = "sandbox-service";
fn create_env_with_netstack(sandbox: &SandboxProxy) -> Result<ManagedEnvironmentProxy, Error> {
let (env, env_server_end) = fidl::endpoints::create_proxy::<ManagedEnvironmentMarker>()?;
let services = vec![LaunchService {
name: String::from("fuchsia.netstack.Netstack"),
url: String::from("fuchsia-pkg://fuchsia.com/netstack#meta/netstack.cmx"),
arguments: None,
}];
sandbox.create_environment(
env_server_end,
&mut EnvironmentOptions {
name: String::from(""), // don't care about the name, let it be created by itself
services: services,
devices: vec![],
inherit_parent_launch_services: false,
},
)?;
Ok(env)
}
async fn create_network<'a>(
env: &'a ManagedEnvironmentProxy,
name: &'a str,
) -> Result<NetworkProxy, Error> {
let (netctx, netctx_server_end) = fidl::endpoints::create_proxy::<NetworkContextMarker>()?;
env.connect_to_service(NetworkContextMarker::NAME, netctx_server_end.into_channel())?;
let (netmgr, netmgr_server_end) = fidl::endpoints::create_proxy::<NetworkManagerMarker>()?;
netctx.get_network_manager(netmgr_server_end)?;
let config = NetworkConfig { latency: None, packet_loss: None, reorder: None };
let (status, network) = await!(netmgr.create_network(name, config))?;
match status {
zx::sys::ZX_OK => Ok(network.unwrap().into_proxy()?),
_ => Err(format_err!("Create network failed")),
}
}
async fn get_network<'a>(
env: &'a ManagedEnvironmentProxy,
name: &'a str,
) -> Result<NetworkProxy, Error> {
let (netctx, netctx_server_end) = fidl::endpoints::create_proxy::<NetworkContextMarker>()?;
env.connect_to_service(NetworkContextMarker::NAME, netctx_server_end.into_channel())?;
let (netmgr, netmgr_server_end) = fidl::endpoints::create_proxy::<NetworkManagerMarker>()?;
netctx.get_network_manager(netmgr_server_end)?;
let network = await!(netmgr.get_network(name))?;
Ok(network.ok_or_else(|| format_err!("can't create network"))?.into_proxy()?)
}
#[fasync::run_singlethreaded]
#[test]
async fn launch_dummy_proc_test() {
let sandbox = client::connect_to_service::<SandboxMarker>()
.context("Can't connect to sandbox")
.unwrap();
let (return_code, reason) = await!(sandbox
.run_test(
&mut LaunchOptions {
package_url: String::from(DUMMY_PROC),
arguments: vec![],
cmx_override: None,
},
None,
)
.on_timeout(TEST_TIMEOUT.seconds().after_now(), || panic!("Test timed out")))
.context("Can't run test")
.unwrap();
assert_eq!(reason, TerminationReason::Exited);
assert_eq!(return_code, 0);
}
#[fasync::run_singlethreaded]
#[test]
async fn launch_dummy_proc_test_failure() {
let sandbox = client::connect_to_service::<SandboxMarker>()
.context("Can't connect to sandbox")
.unwrap();
let (return_code, reason) = await!(sandbox
.run_test(
&mut LaunchOptions {
package_url: String::from(DUMMY_PROC),
arguments: vec![String::from("-f")],
cmx_override: None,
},
None,
)
.on_timeout(TEST_TIMEOUT.seconds().after_now(), || panic!("Test timed out")))
.context("Can't run test")
.unwrap();
assert_eq!(reason, TerminationReason::Exited);
assert_ne!(return_code, 0);
}
#[fasync::run_singlethreaded]
#[test]
async fn launch_dummy_proc_cmx_override() {
let sandbox = client::connect_to_service::<SandboxMarker>()
.context("Can't connect to sandbox")
.unwrap();
// run a test whose cmx tells it to have a child environment
// which spawns dummy_proc with "-f" flag, making if effectively fail.
let (return_code, reason) = await!(sandbox
.run_test(
&mut LaunchOptions {
package_url: String::from(DUMMY_PROC),
arguments: vec![],
cmx_override: Some(String::from(
r#"
{
"environment" : {
"children": [{
"test" : [
{ "arguments": ["-f"] }
]
}]
}
}
"#
)),
},
None,
)
.on_timeout(TEST_TIMEOUT.seconds().after_now(), || panic!("Test timed out")))
.context("Can't run test")
.unwrap();
// check that return is a failure, proving effectively that the cmx override worked.
assert_eq!(reason, TerminationReason::Exited);
assert_ne!(return_code, 0);
}
#[fasync::run_singlethreaded]
#[test]
async fn hop_on_test_environment() {
let sandbox = client::connect_to_service::<SandboxMarker>()
.context("Can't connect to sandbox")
.unwrap();
let (root_env, root_env_server_end) =
fidl::endpoints::create_proxy::<ManagedEnvironmentMarker>().unwrap();
// run dummy proc waiting for event code 1 with bus name "dummy_proc",
// and get a reference to the root environment
let fut = sandbox
.run_test(
&mut LaunchOptions {
package_url: String::from(DUMMY_PROC),
arguments: vec![
String::from("-e"),
String::from("1"),
String::from("-n"),
String::from("dummy_proc"),
],
cmx_override: None,
},
Some(root_env_server_end),
)
.on_timeout(TEST_TIMEOUT.seconds().after_now(), || panic!("Test timed out"));
// get bus service from root environment and connect to the dummy_proc bus (which is called
// test-bus)
let (sync_manager, sync_manager_server_end) =
fidl::endpoints::create_proxy::<SyncManagerMarker>().unwrap();
root_env
.connect_to_service(SyncManagerMarker::NAME, sync_manager_server_end.into_channel())
.context("Can't connect to SyncManager service")
.unwrap();
let (bus, bus_server_end) = fidl::endpoints::create_proxy::<BusMarker>().unwrap();
sync_manager
.bus_subscribe(TEST_BUS, BUS_CLIENT_NAME, bus_server_end)
.context("Can't get on bus")
.unwrap();
// wait for the dummy_proc client to show up on the bus
let (wait_ok, _) = await!(bus
.wait_for_clients(&mut vec!["dummy_proc"].drain(..), TEST_TIMEOUT.seconds().nanos(),))
.context("Can't wait for clients on bus")
.unwrap();
assert!(wait_ok, "timed out waiting for child on bus");
// publish the event that dummy_proc is waiting for
bus.publish(Event { code: Some(1), message: None, arguments: None })
.context("Failed to publish event")
.unwrap();
let (return_code, reason) = await!(fut).context("Can't run test").unwrap();
// check that return is a failure, proving effectively that the cmx override worked.
assert_eq!(reason, TerminationReason::Exited);
assert_eq!(return_code, 0);
}
#[fasync::run_singlethreaded]
#[test]
async fn can_use_environment_services() {
let sandbox = client::connect_to_service::<SandboxMarker>()
.context("Can't connect to sandbox")
.unwrap();
let env = create_env_with_netstack(&sandbox).unwrap();
let (netstack, netstack_server_end) =
fidl::endpoints::create_proxy::<NetstackMarker>().unwrap();
env.connect_to_service(NetstackMarker::NAME, netstack_server_end.into_channel())
.context("Can't connect to netstack")
.unwrap();
let ifs =
await!(netstack.get_interfaces()).context("can't list netstack interfaces").unwrap();
assert!(
ifs.len() <= 1,
"brand new netstack should not have any interfaces except for loopback"
);
}
#[fasync::run_singlethreaded]
#[test]
async fn environment_sandboxing() {
let sandbox = client::connect_to_service::<SandboxMarker>()
.context("Can't connect to sandbox")
.unwrap();
let env1 = create_env_with_netstack(&sandbox).unwrap();
let env2 = create_env_with_netstack(&sandbox).unwrap();
let _net1 = await!(create_network(&env1, "network")).unwrap();
let net1_retrieve = await!(get_network(&env1, "network"));
assert!(net1_retrieve.is_ok(), "can retrieve net1 from env1");
let net2_retrieve = await!(get_network(&env2, "network"));
assert!(net2_retrieve.is_err(), "net should not exist in env2");
}
}