blob: 5aff959f261130218bcd98647ca48650c0ca0a2d [file] [log] [blame]
// Copyright 2022 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 component_events::events::{DebugStarted, EventStream, Stopped};
use component_events::matcher::EventMatcher;
use fidl_fuchsia_io as fio;
use fuchsia_async::{MonotonicDuration, MonotonicInstant, Task, Timer};
use fuchsia_component_test::ScopedInstance;
use fuchsia_fs::directory::open_file_async;
use std::mem;
#[fuchsia::test]
async fn test_debug_started() {
let mut event_stream = EventStream::open().await.unwrap();
let collection_name = "test-collection";
// ScopedInstance kills the component when it goes outside of the scope.
let instance = ScopedInstance::new(
collection_name.to_owned(),
"fuchsia-pkg://fuchsia.com/elf_runner_lifecycle_test#meta/immediate_exit_component.cm"
.to_owned(),
)
.await
.unwrap();
// connect_to_binder starts the component. Otherwise the component is only declared.
instance.connect_to_binder().unwrap();
let start = MonotonicInstant::now();
let moniker = format!("./{}:{}", collection_name, instance.child_name());
let event = EventMatcher::ok()
.moniker(moniker.clone())
.wait::<DebugStarted>(&mut event_stream)
.await
.expect("failed to observe events");
let payload = event.result().expect("debug_started should not be err");
let job_id_content = open_file_async(&payload.runtime_dir, "elf/job_id", fio::PERM_READABLE)
.expect("cannot open elf/job_id")
.read(fio::MAX_BUF)
.await
.expect("failed to read elf/job_id")
.expect("failed to read elf/job_id");
let job_id: u64 = String::from_utf8(job_id_content)
.expect("cannot parse job_id")
.parse()
.expect("cannot parse job_id");
// Ideally we want to get the job handle from the job_id, and install an exception channel
// to check that break_on_start really works. But that requires access to RootJob which is
// not available for this test.
println!("job_id: {}", job_id);
// Instead, we depends on the fact that the component exits immediately and check the arrival
// time of the Stopped event.
let _task = Task::spawn(async move {
// Drop break_on_start after 20 milliseconds.
Timer::new(MonotonicDuration::from_millis(20)).await;
// We only need to drop payload.break_on_start but it's a reference.
mem::drop(event);
});
let _stoppped_event = EventMatcher::ok()
.moniker(moniker)
.wait::<Stopped>(&mut event_stream)
.await
.expect("failed to observe events");
let elapsed = (MonotonicInstant::now() - start).into_millis();
// around 29 ms, but could be arbitrarily large so we don't check the upper limit of it.
println!("elapsed: {}", elapsed);
assert!(elapsed >= 20);
}
#[fuchsia::test]
async fn test_debug_started_with_timeout() {
let mut event_stream = EventStream::open().await.unwrap();
let collection_name = "test-collection";
// ScopedInstance kills the component when it goes outside of the scope.
let instance = ScopedInstance::new(
collection_name.to_owned(),
"fuchsia-pkg://fuchsia.com/elf_runner_lifecycle_test#meta/immediate_exit_component.cm"
.to_owned(),
)
.await
.unwrap();
// connect_to_binder starts the component. Otherwise the component is only declared.
instance.connect_to_binder().unwrap();
let moniker = format!("./{}:{}", collection_name, instance.child_name());
let _debug_started_event = EventMatcher::ok()
.moniker(moniker.clone())
.wait::<DebugStarted>(&mut event_stream)
.await
.expect("failed to observe events");
// Hold the debug_started_event indefinitely to mimic a buggy debugger.
// The component should still run and exit after certain timeout.
let _stopped_event = EventMatcher::ok()
.moniker(moniker)
.wait::<Stopped>(&mut event_stream)
.await
.expect("failed to observe events");
}