| // 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::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::*, injectors::*, matcher::EventMatcher, opaque_test::*}, |
| }; |
| |
| 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() { |
| LOGGER.init(); |
| |
| let test = OpaqueTest::default( |
| "fuchsia-pkg://fuchsia.com/storage_integration_test#meta/storage_realm.cm", |
| ) |
| .await |
| .unwrap(); |
| |
| let event_source = test.connect_to_event_source().await.unwrap(); |
| let mut event_stream = event_source.subscribe(vec![Started::NAME]).await.unwrap(); |
| |
| event_source.start_component_tree().await; |
| |
| // Expect the root component to be bound to |
| let event = EventMatcher::ok().moniker(".").expect_match::<Started>(&mut event_stream).await; |
| event.resume().await.unwrap(); |
| |
| // Expect the 2 children to be bound to |
| let event = EventMatcher::ok().expect_match::<Started>(&mut event_stream).await; |
| event.resume().await.unwrap(); |
| |
| let event = EventMatcher::ok().expect_match::<Started>(&mut event_stream).await; |
| event.resume().await.unwrap(); |
| |
| 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; |
| } |
| |
| #[fasync::run_singlethreaded(test)] |
| async fn storage_from_collection() { |
| LOGGER.init(); |
| |
| let test = OpaqueTest::default( |
| "fuchsia-pkg://fuchsia.com/storage_integration_test#meta/storage_realm_coll.cm", |
| ) |
| .await |
| .unwrap(); |
| |
| let event_source = test.connect_to_event_source().await.unwrap(); |
| let mut event_stream = event_source |
| .subscribe(vec![Started::NAME, Destroyed::NAME, CapabilityRouted::NAME]) |
| .await |
| .unwrap(); |
| |
| // 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()); |
| trigger_capability.inject(&event_source, EventMatcher::ok()).await; |
| |
| event_source.start_component_tree().await; |
| |
| // Expect the root component to be started |
| let event = EventMatcher::ok().moniker(".").wait::<Started>(&mut event_stream).await.unwrap(); |
| event.resume().await.unwrap(); |
| |
| // Expect 2 children to be started - one static and one dynamic |
| // Order is irrelevant |
| let event = EventMatcher::ok().wait::<Started>(&mut event_stream).await.unwrap(); |
| event.resume().await.unwrap(); |
| |
| let event = EventMatcher::ok().wait::<Started>(&mut event_stream).await.unwrap(); |
| event.resume().await.unwrap(); |
| |
| // 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 = EventMatcher::ok() |
| .moniker("./coll:storage_user:1") |
| .wait::<Destroyed>(&mut event_stream) |
| .await |
| .unwrap(); |
| |
| 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, |
| ) |
| .expect("failed to open storage"); |
| assert_eq!(list_directory(&memfs_proxy).await.unwrap(), Vec::<String>::new()); |
| |
| event.resume().await.unwrap(); |
| } |
| |
| struct TriggerCapability { |
| lock: Arc<Mutex<()>>, |
| } |
| |
| impl TriggerCapability { |
| fn new(l: Arc<Mutex<()>>) -> Arc<Self> { |
| Arc::new(Self { lock: l }) |
| } |
| } |
| |
| #[async_trait] |
| impl ProtocolInjector 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) { |
| 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) |
| .expect("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, |
| ) |
| .expect("failed to open file in storage"); |
| let (s, _) = file.write(&file_contents.as_bytes()).await.unwrap(); |
| 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) |
| .expect("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, |
| ) |
| .expect("failed to open file in memfs"); |
| let read_contents = |
| io_util::read_file(&file_proxy).await.expect("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"); |
| } |