| // Copyright 2021 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 crate::{constants, test_topology, utils}; |
| use component_events::{events::*, matcher::*}; |
| use diagnostics_reader::{assert_data_tree, ArchiveReader, Logs}; |
| use fidl_fuchsia_component::BinderMarker; |
| use fidl_fuchsia_component::RealmMarker; |
| use fidl_fuchsia_component_decl::ChildRef; |
| use fidl_fuchsia_diagnostics::ArchiveAccessorMarker; |
| use fidl_fuchsia_io as fio; |
| use fidl_fuchsia_sys2::EventSourceMarker; |
| use fuchsia_async as fasync; |
| use fuchsia_component::client; |
| use fuchsia_component_test::new::RealmInstance; |
| use futures::{FutureExt, StreamExt}; |
| |
| #[fuchsia::test] |
| async fn component_selectors_filter_logs() { |
| let (builder, test_realm) = test_topology::create(test_topology::Options::default()) |
| .await |
| .expect("create base topology"); |
| test_topology::add_lazy_child(&test_realm, "a", constants::LOG_AND_EXIT_COMPONENT_URL) |
| .await |
| .expect("add log_and_exit a"); |
| test_topology::add_lazy_child(&test_realm, "b", constants::LOG_AND_EXIT_COMPONENT_URL) |
| .await |
| .expect("add log_and_exit b"); |
| |
| test_topology::expose_test_realm_protocol(&builder, &test_realm).await; |
| let instance = builder.build().await.expect("create instance"); |
| let accessor = |
| instance.root.connect_to_protocol_at_exposed_dir::<ArchiveAccessorMarker>().unwrap(); |
| |
| let event_source = |
| EventSource::from_proxy(client::connect_to_protocol::<EventSourceMarker>().unwrap()); |
| let mut event_stream = |
| event_source.subscribe(vec![EventSubscription::new(vec![Stopped::NAME])]).await.unwrap(); |
| |
| // Start a few components. |
| let mut child_ref_a = ChildRef { name: "a".to_string(), collection: None }; |
| let mut child_ref_b = ChildRef { name: "b".to_string(), collection: None }; |
| for _ in 0..3 { |
| launch_and_wait_for_exit(&instance, &mut child_ref_a, &mut event_stream).await; |
| launch_and_wait_for_exit(&instance, &mut child_ref_b, &mut event_stream).await; |
| } |
| |
| // Start listening |
| let mut reader = ArchiveReader::new(); |
| reader |
| .add_selector(format!("realm_builder\\:{}/test/a:root", instance.root.child_name())) |
| .with_archive(accessor) |
| .with_minimum_schema_count(5) |
| .retry_if_empty(true); |
| |
| let (mut stream, mut errors) = |
| reader.snapshot_then_subscribe::<Logs>().unwrap().split_streams(); |
| let _errors = fasync::Task::spawn(async move { |
| while let Some(e) = errors.next().await { |
| panic!("error in subscription: {}", e); |
| } |
| }); |
| |
| // Start a few more components |
| for _ in 0..3 { |
| launch_and_wait_for_exit(&instance, &mut child_ref_a, &mut event_stream).await; |
| launch_and_wait_for_exit(&instance, &mut child_ref_b, &mut event_stream).await; |
| } |
| |
| // We should see logs from components started before and after we began to listen. |
| for _ in 0..6 { |
| let log = stream.next().await.unwrap(); |
| assert_eq!(log.moniker, format!("realm_builder:{}/test/a", instance.root.child_name())); |
| assert_data_tree!(log.payload.unwrap(), root: { |
| message: { |
| value: "Hello, world!", |
| } |
| }); |
| } |
| // We only expect 6 logs. |
| assert!(stream.next().now_or_never().is_none()); |
| } |
| |
| async fn launch_and_wait_for_exit( |
| instance: &RealmInstance, |
| child_ref: &mut ChildRef, |
| event_stream: &mut EventStream, |
| ) { |
| let (exposed_dir, server_end) = |
| fidl::endpoints::create_proxy::<fio::DirectoryMarker>().unwrap(); |
| let realm = instance.root.connect_to_protocol_at_exposed_dir::<RealmMarker>().unwrap(); |
| realm.open_exposed_dir(child_ref, server_end).await.unwrap().unwrap(); |
| |
| let _ = client::connect_to_protocol_at_dir_root::<BinderMarker>(&exposed_dir).unwrap(); |
| |
| utils::wait_for_component_stopped_event( |
| instance.root.child_name(), |
| &child_ref.name, |
| ExitStatusMatcher::Clean, |
| event_stream, |
| ) |
| .await; |
| } |