bt_test_harness/
inspect.rs1use anyhow::{Context, Error};
6use diagnostics_reader::{ArchiveReader, ComponentSelector, DiagnosticsHierarchy};
7use fidl_fuchsia_bluetooth_sys::{AccessMarker, AccessProxy};
8use fuchsia_async::DurationExt;
9use fuchsia_bluetooth::expectation::asynchronous::{
10 expectable, Expectable, ExpectableExt, ExpectableState, ExpectableStateExt,
11};
12use fuchsia_bluetooth::expectation::Predicate;
13use futures::future::BoxFuture;
14use futures::FutureExt;
15use std::ops::{Deref, DerefMut};
16use std::sync::Arc;
17use test_harness::{SharedState, TestHarness, SHARED_STATE_TEST_COMPONENT_INDEX};
18use zx::MonotonicDuration;
19
20use crate::core_realm::{CoreRealm, SHARED_STATE_INDEX};
21use crate::host_watcher::ActivatedFakeHost;
22use crate::timeout_duration;
23
24const SNAPSHOT_INSPECT_EVERY_N_SECONDS: MonotonicDuration = MonotonicDuration::from_seconds(1);
27
28#[derive(Clone)]
29pub struct InspectState {
30 pub moniker_to_track: Vec<String>,
39 pub hierarchies: Vec<DiagnosticsHierarchy>,
41 realm_child_name: String,
42}
43
44#[derive(Clone)]
45pub struct InspectHarness(Expectable<InspectState, AccessProxy>);
46
47impl InspectHarness {
48 pub async fn expect_n_hierarchies(&self, min_num: usize) -> Result<InspectState, Error> {
51 self.when_satisfied(
52 Predicate::<InspectState>::predicate(
53 move |state| state.hierarchies.len() >= min_num,
54 "Expected number of hierarchies received",
55 ),
56 timeout_duration(),
57 )
58 .await
59 }
60
61 fn get_component_selector(&self) -> ComponentSelector {
62 let realm_child_moniker = format!("realm_builder\\:{}", self.read().realm_child_name);
63 let mut complete_moniker = self.read().moniker_to_track;
64 complete_moniker.insert(0, realm_child_moniker);
65 return ComponentSelector::new(complete_moniker);
66 }
67}
68
69impl Deref for InspectHarness {
70 type Target = Expectable<InspectState, AccessProxy>;
71
72 fn deref(&self) -> &Self::Target {
73 &self.0
74 }
75}
76
77impl DerefMut for InspectHarness {
78 fn deref_mut(&mut self) -> &mut Self::Target {
79 &mut self.0
80 }
81}
82
83pub async fn handle_inspect_updates(harness: InspectHarness) -> Result<(), Error> {
84 loop {
85 if harness.read().moniker_to_track.len() > 0 {
86 let mut reader = ArchiveReader::inspect();
87 let _ = reader.add_selector(harness.get_component_selector());
88 harness.write_state().hierarchies =
89 reader.snapshot().await?.into_iter().flat_map(|result| result.payload).collect();
90 harness.notify_state_changed();
91 }
92 fuchsia_async::Timer::new(SNAPSHOT_INSPECT_EVERY_N_SECONDS.after_now()).await;
93 }
94}
95
96impl TestHarness for InspectHarness {
97 type Env = (ActivatedFakeHost, Arc<CoreRealm>);
98 type Runner = BoxFuture<'static, Result<(), Error>>;
99
100 fn init(
101 shared_state: &Arc<SharedState>,
102 ) -> BoxFuture<'static, Result<(Self, Self::Env, Self::Runner), Error>> {
103 let shared_state = shared_state.clone();
104 async move {
105 let test_component: Arc<String> = shared_state
106 .get(SHARED_STATE_TEST_COMPONENT_INDEX)
107 .expect("SharedState must have TEST-COMPONENT")?;
108 let inserter = move || CoreRealm::create(test_component.to_string());
109 let realm = shared_state.get_or_insert_with(SHARED_STATE_INDEX, inserter).await?;
110 let fake_host = ActivatedFakeHost::new(realm.clone()).await?;
112
113 let access_proxy = realm
114 .instance()
115 .connect_to_protocol_at_exposed_dir::<AccessMarker>()
116 .context("Failed to connect to Access service")?;
117 let state = InspectState {
118 moniker_to_track: Vec::new(),
119 hierarchies: Vec::new(),
120 realm_child_name: realm.instance().child_name().to_string(),
121 };
122
123 let harness = InspectHarness(expectable(state, access_proxy));
124 let run_inspect = handle_inspect_updates(harness.clone()).boxed();
125 Ok((harness, (fake_host, realm), run_inspect))
126 }
127 .boxed()
128 }
129
130 fn terminate((emulator, realm): Self::Env) -> BoxFuture<'static, Result<(), Error>> {
131 async move {
133 let _realm = realm;
134 emulator.release().await
135 }
136 .boxed()
137 }
138}