blob: 27e4c10550c18fcdf773a59e9c6ac4a6e26c71e8 [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.
use {
anyhow::{Context as _, Error},
async_trait::async_trait,
fidl_fidl_test_components as ftest, fidl_fuchsia_io as fio, fuchsia_async as fasync,
fuchsia_syslog as syslog, fuchsia_zircon as zx,
futures::StreamExt,
io_util::{self, OPEN_RIGHT_READABLE, OPEN_RIGHT_WRITABLE},
lazy_static::lazy_static,
std::{path::PathBuf, sync::Arc, sync::Mutex},
test_utils_lib::{events::*, test_utils::*},
};
lazy_static! {
static ref LOGGER: Logger = Logger::new();
}
struct Logger {}
impl Logger {
fn new() -> Self {
syslog::init_with_tags(&[]).expect("could not initialize logging");
Self {}
}
fn init(&self) {}
}
#[fasync::run_singlethreaded(test)]
async fn storage() -> Result<(), Error> {
LOGGER.init();
let test = OpaqueTest::default(
"fuchsia-pkg://fuchsia.com/storage_integration_test#meta/storage_realm.cm",
)
.await?;
let event_source = test.connect_to_event_source().await?;
let mut event_stream = event_source.subscribe(vec![Started::NAME]).await?;
event_source.start_component_tree().await?;
// Expect the root component to be bound to
let event =
event_stream.expect_exact::<Started>(EventMatcher::new().expect_moniker(".")).await?;
event.resume().await?;
// Expect the 2 children to be bound to
let event = event_stream.expect_type::<Started>().await?;
event.resume().await?;
let event = event_stream.expect_type::<Started>().await?;
event.resume().await?;
let component_manager_path = test.get_component_manager_path();
let memfs_path =
component_manager_path.join("out/hub/children/memfs/exec/out/svc/fuchsia.io.Directory");
let data_path = component_manager_path.join("out/hub/children/storage_user/exec/out/data");
check_storage(memfs_path, data_path, "storage_user:0").await?;
Ok(())
}
#[fasync::run_singlethreaded(test)]
async fn storage_from_collection() -> Result<(), Error> {
LOGGER.init();
let test = OpaqueTest::default(
"fuchsia-pkg://fuchsia.com/storage_integration_test#meta/storage_realm_coll.cm",
)
.await?;
let event_source = test.connect_to_event_source().await?;
let mut event_stream = event_source
.subscribe(vec![Started::NAME, Destroyed::NAME, CapabilityRouted::NAME])
.await?;
// Create a mutex that is used to hold the response from the trigger
// service until after the tests inspects the storage.
let trigger_lock = Arc::new(Mutex::new(()));
let trigger_guard = trigger_lock.lock();
// The root component connects to the Trigger capability to create a
// rendezvous so the test can inspect storage before the child is
// destroyed.
let trigger_capability = TriggerCapability::new(trigger_lock.clone());
event_source.install_injector(trigger_capability, None).await?;
event_source.start_component_tree().await?;
// Expect the root component to be started
let event =
event_stream.wait_until_exact::<Started>(EventMatcher::new().expect_moniker(".")).await?;
event.resume().await?;
// Expect 2 children to be started - one static and one dynamic
// Order is irrelevant
let event = event_stream.wait_until_type::<Started>().await?;
event.resume().await?;
let event = event_stream.wait_until_type::<Started>().await?;
event.resume().await?;
// With all children started, do the test
let component_manager_path = test.get_component_manager_path();
let memfs_path =
component_manager_path.join("out/hub/children/memfs/exec/out/svc/fuchsia.io.Directory");
let data_path = component_manager_path.join("out/hub/children/coll:storage_user/exec/out/data");
check_storage(memfs_path.clone(), data_path, "coll:storage_user:1").await?;
// The storage state is checked, drop the guard and allow the
// TriggerService to respond to the root component.
drop(trigger_guard);
// Expect the dynamic child to be destroyed
let event = event_stream
.wait_until_exact::<Destroyed>(EventMatcher::new().expect_moniker("./coll:storage_user:1"))
.await?;
println!("checking that storage was destroyed");
let memfs_proxy = io_util::open_directory_in_namespace(
memfs_path.to_str().unwrap(),
OPEN_RIGHT_READABLE | OPEN_RIGHT_WRITABLE,
)
.context("failed to open storage")?;
assert_eq!(list_directory(&memfs_proxy).await?, Vec::<String>::new());
event.resume().await?;
Ok(())
}
struct TriggerCapability {
lock: Arc<Mutex<()>>,
}
impl TriggerCapability {
fn new(l: Arc<Mutex<()>>) -> Arc<Self> {
Arc::new(Self { lock: l })
}
}
#[async_trait]
impl Injector for TriggerCapability {
type Marker = ftest::TriggerMarker;
async fn serve(
self: Arc<Self>,
mut request_stream: ftest::TriggerRequestStream,
) -> Result<(), Error> {
while let Some(Ok(ftest::TriggerRequest::Run { responder })) = request_stream.next().await {
let _guard = self.lock.lock();
responder.send("")?;
}
Ok(())
}
}
async fn check_storage(
memfs_path: PathBuf,
data_path: PathBuf,
user_moniker: &str,
) -> Result<(), Error> {
let memfs_path = memfs_path.to_str().expect("unexpected chars");
let data_path = data_path.to_str().expect("unexpected chars");
let child_data_proxy =
io_util::open_directory_in_namespace(data_path, OPEN_RIGHT_READABLE | OPEN_RIGHT_WRITABLE)
.context("failed to open storage")?;
println!("successfully opened \"storage_user\" exposed data directory");
let file_name = "hippo";
let file_contents = "hippos_are_neat";
let file = io_util::open_file(
&child_data_proxy,
&PathBuf::from(file_name),
OPEN_RIGHT_READABLE | OPEN_RIGHT_WRITABLE | fio::OPEN_FLAG_CREATE,
)
.context("failed to open file in storage")?;
let (s, _) = file.write(&file_contents.as_bytes()).await.unwrap_or_else(|_| {
println!("ERROR! Looping indefinitely");
loop {}
});
assert_eq!(zx::Status::OK, zx::Status::from_raw(s), "writing to the file failed");
println!("successfully wrote to file \"hippo\" in exposed data directory");
let memfs_proxy =
io_util::open_directory_in_namespace(memfs_path, OPEN_RIGHT_READABLE | OPEN_RIGHT_WRITABLE)
.context("failed to open storage")?;
println!("successfully opened \"memfs\" exposed directory");
let file_proxy = io_util::open_file(
&memfs_proxy,
&PathBuf::from(&format!("{}/data/hippo", user_moniker)),
OPEN_RIGHT_READABLE,
)
.context("failed to open file in memfs")?;
let read_contents =
io_util::read_file(&file_proxy).await.context("failed to read file in memfs")?;
println!("successfully read back contents of file from memfs directly");
assert_eq!(read_contents, file_contents, "file contents did not match what was written");
Ok(())
}