blob: e70cc7896dafe276ebfdf9aa024cde21a3a6d7ad [file] [log] [blame]
// 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.
//! This unit tests a library which uses v2 framework APIs, so it needs to be launched as a
//! v2 component.
use {
anyhow::{format_err, Context as _, Error},
fasync::OnSignals,
fidl::endpoints::{self, Proxy},
fidl_fuchsia_io::DirectoryMarker,
fidl_fuchsia_sys2 as fsys, fidl_fuchsia_test as ftest,
fidl_fuchsia_test_manager as ftest_manager,
ftest_manager::LaunchOptions,
fuchsia_async as fasync,
fuchsia_component::client,
fuchsia_zircon as zx,
futures::{channel::mpsc, prelude::*},
maplit::hashmap,
pretty_assertions::assert_eq,
std::mem::drop,
test_executor::{DisabledTestHandling, GroupByTestCase, TestEvent, TestResult, TestRunOptions},
};
async fn connect_test_manager() -> Result<ftest_manager::HarnessProxy, Error> {
let realm = client::connect_to_protocol::<fsys::RealmMarker>()
.context("could not connect to Realm service")?;
let mut child_ref = fsys::ChildRef { name: "test_manager".to_owned(), collection: None };
let (dir, server_end) = endpoints::create_proxy::<DirectoryMarker>()?;
realm
.bind_child(&mut child_ref, server_end)
.await
.context("bind_child fidl call failed for test manager")?
.map_err(|e| format_err!("failed to create test manager: {:?}", e))?;
client::connect_to_protocol_at_dir_root::<ftest_manager::HarnessMarker>(&dir)
.context("failed to open test suite service")
}
/// Returns SuiteProxy and LegacySuiteControllerProxy. Keep LegacySuiteControllerProxy alive for
/// length of your test run so that your test doesn't die.
async fn launch_test(
test_url: &str,
) -> Result<(ftest::SuiteProxy, ftest_manager::LegacySuiteControllerProxy), Error> {
let harness = connect_test_manager().await?;
let suite_instance = test_executor::SuiteInstance::new(test_executor::SuiteInstanceOpts {
harness: &harness,
test_url,
force_log_protocol: None,
})
.await?;
Ok(suite_instance.into_proxies())
}
async fn run_test(
test_url: &str,
test_run_options: TestRunOptions,
force_log_protocol: Option<test_executor::LogStreamProtocol>,
) -> Result<(Vec<TestEvent>, Vec<String>), Error> {
let harness = connect_test_manager().await?;
let mut suite_instance = test_executor::SuiteInstance::new(test_executor::SuiteInstanceOpts {
harness: &harness,
test_url,
force_log_protocol,
})
.await?;
let log_stream = suite_instance.take_log_stream().expect("got log stream");
let (sender, recv) = mpsc::channel(1);
let results_fut = async move {
suite_instance.run_and_collect_results(sender, None, test_run_options).await?;
suite_instance.kill()?;
Ok::<(), anyhow::Error>(())
};
let (events, logs, ()) = futures::try_join!(
recv.collect::<Vec<_>>().map(Ok),
log_stream.collect::<Vec<_>>().map(Ok),
results_fut,
)
.context("running test")?;
let mut collected_logs = vec![];
for log_result in logs {
let log = log_result?;
collected_logs.push(log.msg().unwrap().to_string());
}
let mut test_events = vec![];
// break stdout messages as they can come in any order.
for event in events {
match event {
TestEvent::StdoutMessage { test_case_name, mut msg } => {
if msg.ends_with("\n") {
msg.truncate(msg.len() - 1)
}
let logs = msg.split("\n");
for log in logs {
test_events.push(TestEvent::StdoutMessage {
test_case_name: test_case_name.clone(),
msg: log.to_string(),
});
}
}
event => {
test_events.push(event);
}
};
}
Ok((test_events, collected_logs))
}
#[fuchsia_async::run_singlethreaded(test)]
async fn killing_controller_should_kill_test() {
let (suite_proxy, keep_alive) =
launch_test("fuchsia-pkg://fuchsia.com/example-tests#meta/echo_test_realm.cm")
.await
.unwrap();
drop(keep_alive);
let suite_channel = suite_proxy.into_channel().unwrap();
// wait for suite server to die.
let signals = OnSignals::new(&suite_channel, zx::Signals::OBJECT_PEER_CLOSED);
signals.await.expect("wait signal failed");
}
#[fuchsia_async::run_singlethreaded(test)]
async fn calling_kill_should_kill_test() {
let (suite_proxy, controller) =
launch_test("fuchsia-pkg://fuchsia.com/example-tests#meta/echo_test_realm.cm")
.await
.unwrap();
controller.kill().unwrap();
let suite_channel = suite_proxy.into_channel().unwrap();
// wait for suite server to die.
let signals = OnSignals::new(&suite_channel, zx::Signals::OBJECT_PEER_CLOSED);
signals.await.expect("wait signal failed");
}
#[fuchsia_async::run_singlethreaded(test)]
async fn launch_and_test_echo_test() {
let test_url = "fuchsia-pkg://fuchsia.com/example-tests#meta/echo_test_realm.cm";
let (events, logs) = run_test(
test_url,
TestRunOptions {
disabled_tests: DisabledTestHandling::Exclude,
parallel: None,
arguments: vec![],
},
None,
)
.await
.unwrap();
let events = events.into_iter().group_by_test_case_unordered();
let expected_events = hashmap! {
Some("EchoTest".to_string()) => vec![
TestEvent::test_case_started("EchoTest"),
TestEvent::test_case_finished("EchoTest", TestResult::Passed),
],
None => vec![
TestEvent::test_finished(),
]
};
assert_eq!(logs, Vec::<String>::new());
assert_eq!(&expected_events, &events);
}
#[fuchsia_async::run_singlethreaded(test)]
async fn launch_and_test_no_on_finished() {
let test_url =
"fuchsia-pkg://fuchsia.com/example-tests#meta/no-onfinished-after-test-example.cm";
let (events, logs) = run_test(
test_url,
TestRunOptions {
disabled_tests: DisabledTestHandling::Exclude,
parallel: None,
arguments: vec![],
},
None,
)
.await
.unwrap();
let events = events.into_iter().group_by_test_case_unordered();
let test_cases = ["Example.Test1", "Example.Test2", "Example.Test3"];
let mut expected_events = vec![];
for case in &test_cases {
expected_events.push(TestEvent::test_case_started(case));
for i in 1..=3 {
expected_events
.push(TestEvent::stdout_message(case, &format!("log{} for {}", i, case)));
}
expected_events.push(TestEvent::test_case_finished(case, TestResult::Passed));
}
let expected_events = expected_events.into_iter().group_by_test_case_unordered();
assert_eq!(&expected_events, &events);
assert_eq!(logs, Vec::<String>::new());
}
#[fuchsia_async::run_singlethreaded(test)]
async fn launch_and_test_gtest_runner_sample_test() {
let test_url = "fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/sample_tests.cm";
let (events, logs) = run_test(
test_url,
TestRunOptions {
disabled_tests: DisabledTestHandling::Exclude,
parallel: None,
arguments: vec![],
},
None,
)
.await
.unwrap();
let events = events.into_iter().group_by_test_case_unordered();
let expected_events =
include!("../../../test_runners/gtest/test_data/sample_tests_golden_events_legacy.rsf");
assert_eq!(logs, Vec::<String>::new());
assert_eq!(&expected_events, &events);
}
#[fuchsia_async::run_singlethreaded(test)]
async fn no_suite_service_test() {
let (suite_proxy, _keep_alive) =
launch_test("fuchsia-pkg://fuchsia.com/test_manager_test#meta/no_suite_service.cm")
.await
.unwrap();
let suite_channel = suite_proxy.into_channel().unwrap();
// wait for suite server to die as test doesn't expose suite service.
let signals = OnSignals::new(&suite_channel, zx::Signals::OBJECT_PEER_CLOSED);
signals.await.expect("wait signal failed");
}
#[fuchsia_async::run_singlethreaded(test)]
async fn test_not_resolved() {
let proxy = connect_test_manager().await.unwrap();
let (_suite_proxy, suite_server_end) = fidl::endpoints::create_proxy().unwrap();
let (_controller_proxy, controller_server_end) = fidl::endpoints::create_proxy().unwrap();
assert_eq!(
proxy
.launch_suite(
"fuchsia-pkg://fuchsia.com/test_manager_test#meta/invalid_cml.cm",
LaunchOptions::EMPTY,
suite_server_end,
controller_server_end
)
.await
.unwrap(),
Err(ftest_manager::LaunchError::InstanceCannotResolve)
);
}
#[fuchsia_async::run_singlethreaded(test)]
async fn collect_isolated_logs_using_batch() {
let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
let (_events, logs) = run_test(
test_url,
TestRunOptions {
disabled_tests: DisabledTestHandling::Exclude,
parallel: None,
arguments: vec![],
},
Some(test_executor::LogStreamProtocol::BatchIterator),
)
.await
.unwrap();
assert_eq!(
logs,
vec!["Started diagnostics publisher ".to_owned(), "Finishing through Stop ".to_owned()]
);
}
#[fuchsia_async::run_singlethreaded(test)]
async fn collect_isolated_logs_using_archive_iterator() {
let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
let (_events, logs) = run_test(
test_url,
TestRunOptions {
disabled_tests: DisabledTestHandling::Exclude,
parallel: None,
arguments: vec![],
},
Some(test_executor::LogStreamProtocol::ArchiveIterator),
)
.await
.unwrap();
assert_eq!(
logs,
vec!["Started diagnostics publisher ".to_owned(), "Finishing through Stop ".to_owned()]
);
}