blob: 424142f8d751f0649a4a3cc2522c401af8dcc7cb [file] [log] [blame]
// Copyright 2020 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,
component_events::{
events::{
self as events, CapabilityRequested, Event, EventSource, EventStream, EventStreamError,
EventSubscription,
},
matcher::EventMatcher,
sequence::EventSequence,
},
fidl_fidl_test_components as test_protocol, fuchsia_async as fasync,
fuchsia_component_test::ScopedInstance,
futures_util::stream::TryStreamExt,
std::sync::{Arc, Mutex},
tracing::info,
};
#[fuchsia::test]
async fn test_exit_detection() {
let event_source = EventSource::new().unwrap();
let event_stream = event_source
.subscribe(vec![EventSubscription::new(vec![events::Stopped::NAME])])
.await
.unwrap();
let collection_name = String::from("test-collection");
let instance = ScopedInstance::new(
collection_name.clone(),
String::from(
"fuchsia-pkg://fuchsia.com/elf_runner_lifecycle_test#meta/immediate_exit_component.cm",
),
)
.await
.unwrap();
instance.connect_to_binder().unwrap();
let target_moniker = format!("./{}:{}", collection_name, instance.child_name());
EventSequence::new()
.then(EventMatcher::ok().r#type(events::Stopped::TYPE).moniker(&target_moniker))
.expect(event_stream)
.await
.unwrap();
}
#[fuchsia::test]
async fn test_exit_after_rendezvous() {
// Get the event source, install our service injector, and then start the
// component tree.
let event_source = EventSource::new().unwrap();
let mut event_stream = event_source
.subscribe(vec![EventSubscription::new(vec![events::Started::NAME, events::Stopped::NAME])])
.await
.unwrap();
// tests don't have access to output directory so using capability requested event to offer a
// protocol.
let capability_requested_event_stream =
event_source.take_static_event_stream("EventStream").await.unwrap();
let rendezvous_service = RendezvousService::new(capability_requested_event_stream);
// Launch the component under test.
let collection_name = String::from("test-collection");
let instance = ScopedInstance::new(
collection_name.clone(),
String::from(
"fuchsia-pkg://fuchsia.com/elf_runner_lifecycle_test#meta/rendezvous_exit_component.cm",
),
)
.await
.unwrap();
instance.connect_to_binder().unwrap();
let target_moniker = format!("./{}:{}", collection_name, instance.child_name());
// First, ensure that component has started.
EventMatcher::ok()
.moniker(&target_moniker)
.wait::<events::Started>(&mut event_stream)
.await
.expect("failed to observe events");
// Then, wait to get confirmation that the component under test exited.
EventSequence::new()
.then(EventMatcher::ok().r#type(events::Stopped::TYPE).moniker(&target_moniker))
.expect(event_stream)
.await
.unwrap();
// Check that we received a request from the component under test.
assert_eq!(*rendezvous_service.call_count.lock().unwrap(), 1);
}
struct RendezvousService {
call_count: Mutex<u32>,
}
impl RendezvousService {
// Right now we are using simple event stream. If this is used by multiple tests cases,
// this struct should use mock component from RealmBuilder.
fn new(mut event_stream: EventStream) -> Arc<Self> {
let obj = Arc::new(RendezvousService { call_count: Mutex::new(0) });
let obj_clone = obj.clone();
fasync::Task::spawn(async move {
loop {
let mut event =
match EventMatcher::ok().wait::<CapabilityRequested>(&mut event_stream).await {
Ok(e) => e,
Err(e) => match e.downcast::<EventStreamError>() {
Ok(EventStreamError::StreamClosed) => return,
Err(e) => panic!("Unknown error! {:?}", e),
},
};
let stream: test_protocol::TriggerRequestStream =
event.take_capability::<test_protocol::TriggerMarker>().unwrap();
obj_clone.clone().serve(stream).await.expect("error serving trigger");
}
})
.detach();
obj
}
async fn serve(
self: Arc<Self>,
mut stream: test_protocol::TriggerRequestStream,
) -> Result<(), Error> {
while let Some(request) = stream.try_next().await.unwrap() {
match request {
test_protocol::TriggerRequest::Run { responder } => {
{
let mut count = self.call_count.lock().unwrap();
*count += 1;
}
info!("Received rendezvous from target");
responder.send("").unwrap();
}
}
}
Ok(())
}
}