blob: e304351248da21b4edbf6311671386fcefa5485e [file] [log] [blame]
// Copyright 2018 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.
use {
anyhow::{format_err, Context as _, Error},
fidl_fuchsia_netemul_environment::ManagedEnvironmentMarker,
fidl_fuchsia_netemul_sync::{BusMarker, BusProxy, Event, SyncManagerMarker},
fuchsia_async as fasync,
fuchsia_component::client,
fuchsia_zircon as zx,
futures::TryStreamExt,
structopt::StructOpt,
};
#[derive(StructOpt, Debug)]
struct Opt {
#[structopt(short = "f")]
fail: bool,
#[structopt(short = "n", default_value = "root")]
name: String,
#[structopt(short = "w")]
wait: Option<u64>,
#[structopt(short = "p")]
publish: Option<i32>,
#[structopt(short = "e")]
event: Option<i32>,
#[structopt(short = "P")]
check_path: Option<String>,
#[structopt(short = "s")]
service: Option<String>,
#[structopt(short = "l")]
log: Option<String>,
}
const BUS_NAME: &str = "test-bus";
pub struct BusConnection {
bus: BusProxy,
}
impl BusConnection {
pub fn new(client: &str) -> Result<BusConnection, Error> {
let busm = client::connect_to_service::<SyncManagerMarker>()
.context("SyncManager not available")?;
let (bus, busch) = fidl::endpoints::create_proxy::<BusMarker>()?;
busm.bus_subscribe(BUS_NAME, client, busch)?;
Ok(BusConnection { bus })
}
pub async fn publish_code(&self, code: i32) -> Result<(), Error> {
let () = self
.bus
.ensure_publish(Event {
code: Some(code),
message: None,
arguments: None,
..Event::EMPTY
})
.await?;
Ok(())
}
pub async fn wait_for_event(&self, code: i32) -> Result<(), Error> {
let mut stream = self.bus.take_event_stream().try_filter_map(|event| match event {
fidl_fuchsia_netemul_sync::BusEvent::OnBusData { data } => match data.code {
Some(rcv_code) => {
if rcv_code == code {
futures::future::ok(Some(()))
} else {
futures::future::ok(None)
}
}
None => futures::future::ok(None),
},
_ => futures::future::ok(None),
});
stream.try_next().await?;
Ok(())
}
pub async fn perform_bus_ops(
&self,
publish: Option<i32>,
wait: Option<i32>,
) -> Result<(), Error> {
if let Some(code) = wait {
let () = self.wait_for_event(code).await?;
}
if let Some(code) = publish {
let () = self.publish_code(code).await?;
}
Ok(())
}
}
#[fasync::run_singlethreaded]
async fn main() -> Result<(), Error> {
let opt = Opt::from_args();
// Attempt to connect to the bus early on so that we do not miss any events.
//
// We won't actually unwrap `bus` until later in case this
// test does not actually need the bus.
let bus = BusConnection::new(&opt.name);
if let Some(log) = opt.log {
println!("Initing syslog...");
let () = fuchsia_syslog::init().context("cannot init logger")?;
println!("Logging to syslog: {}", log);
log::info!("{}", log);
}
if let Some(svc) = opt.service {
println!("Connecting to service [{}]...", svc);
let env = client::connect_to_service::<ManagedEnvironmentMarker>()?;
let (_dummy, server) = zx::Channel::create()?;
env.connect_to_service(&svc, server)?;
}
if let Some(wait) = opt.wait {
println!("Sleeping for {}...", wait);
std::thread::sleep(std::time::Duration::from_millis(wait));
}
if let Some(path) = opt.check_path {
println!("Checking path existence {}...", &path);
if !std::path::Path::new(&path).exists() {
return Err(format_err!("{} is not in namespace", &path));
}
}
if opt.publish != None || opt.event != None {
// Unwrap the `bus` which should be an error
// if the test requires publish or event waiting operations.
let bus = bus.context("Failed to connect to bus")?;
println!("Publishing: {:?} | Waiting for event: {:?}", opt.publish, opt.event);
let () = bus.perform_bus_ops(opt.publish, opt.event).await?;
}
if opt.fail {
Err(format_err!("Failing because was asked to."))
} else {
println!("All done!");
Ok(())
}
}