blob: 5a4a47dc05fb77da72045822d3dade860a9dbc40 [file] [log] [blame]
// 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 {
anyhow::{Context as _, Error},
fidl::endpoints,
fidl_fuchsia_test_manager as ftest_manager,
ftest_manager::{CaseStatus, RunOptions, SuiteStatus},
fuchsia_async as fasync,
fuchsia_component::client,
futures::{channel::mpsc, prelude::*},
pretty_assertions::assert_eq,
test_diagnostics::collect_string_from_socket,
test_manager_test_lib::{
collect_suite_events, default_run_option, AttributedLog, GroupRunEventByTestCase, RunEvent,
TestBuilder, TestRunEventPayload,
},
};
macro_rules! connect_run_builder {
() => {
client::connect_to_protocol::<ftest_manager::RunBuilderMarker>()
.context("cannot connect to run builder proxy")
};
}
macro_rules! connect_query_server {
() => {
client::connect_to_protocol::<ftest_manager::QueryMarker>()
.context("cannot connect to query proxy")
};
}
async fn run_single_test(
test_url: &str,
run_options: RunOptions,
) -> Result<(Vec<RunEvent>, Vec<AttributedLog>), Error> {
let builder = TestBuilder::new(connect_run_builder!()?);
let suite_instance =
builder.add_suite(test_url, run_options).await.context("Cannot create suite instance")?;
let builder_run = fasync::Task::spawn(async move { builder.run().await });
let ret = collect_suite_events(suite_instance).await;
builder_run.await.context("builder execution failed")?;
ret
}
#[fuchsia::test]
async fn calling_kill_should_kill_test() {
let proxy = connect_run_builder!().unwrap();
let builder = TestBuilder::new(proxy);
let suite = builder
.add_suite(
"fuchsia-pkg://fuchsia.com/test_manager_test#meta/hanging_test.cm",
default_run_option(),
)
.await
.unwrap();
let _builder_run = fasync::Task::spawn(async move { builder.run().await });
let (sender, mut recv) = mpsc::channel(1024);
let controller = suite.controller();
let task = fasync::Task::spawn(async move { suite.collect_events(sender).await });
// let the test start
let _initial_event = recv.next().await.unwrap();
controller.kill().unwrap();
// collect rest of the events
let events = recv.collect::<Vec<_>>().await;
task.await.unwrap();
let events = events
.into_iter()
.filter_map(|e| match e.payload {
test_manager_test_lib::SuiteEventPayload::RunEvent(e) => Some(e),
_ => None,
})
.collect::<Vec<_>>();
// make sure that test never finished
for event in events {
match event {
RunEvent::SuiteStopped { .. } => {
panic!("should not receive SuiteStopped event as the test was killed. ")
}
_ => {}
}
}
}
#[fuchsia::test]
async fn closing_suite_controller_should_kill_test() {
let proxy = connect_run_builder!().unwrap();
let builder = TestBuilder::new(proxy);
let suite = builder
.add_suite(
"fuchsia-pkg://fuchsia.com/test_manager_test#meta/hanging_test.cm",
default_run_option(),
)
.await
.unwrap();
let builder_run_task = fasync::Task::spawn(async move { builder.run().await });
// let the test start
// Drop events so that we are not holding on to logger channel else archivist will
// timeout during shutdown.
let _ = suite.controller().get_events().await.unwrap().unwrap();
// drop suite, which should also close the suite channel
drop(suite);
// We can't verify that the suite didn't complete, but verify that the run
// completes successfully.
builder_run_task.await.expect("Run controller failed to collect events");
}
#[fuchsia::test]
async fn calling_builder_kill_should_kill_test() {
let proxy = connect_run_builder!().unwrap();
let builder = TestBuilder::new(proxy);
let suite = builder
.add_suite(
"fuchsia-pkg://fuchsia.com/test_manager_test#meta/hanging_test.cm",
default_run_option(),
)
.await
.unwrap();
let proxy = builder.take_proxy();
let (controller_proxy, controller) = endpoints::create_proxy().unwrap();
proxy.build(controller).unwrap();
let (sender, mut recv) = mpsc::channel(1024);
let _task = fasync::Task::spawn(async move { suite.collect_events(sender).await });
// let the test start
let _initial_event = recv.next().await.unwrap();
controller_proxy.kill().unwrap();
loop {
let events = controller_proxy.get_events().await.unwrap();
if events.is_empty() {
break;
}
for event in events {
if let Some(e) = &event.payload {
match e {
// ignore, we sometimes see debugdata artifact
ftest_manager::RunEventPayload::Artifact(_) => {}
_ => panic!("should not get this event: {:?}", event),
}
}
}
}
// collect rest of the events
let events = recv.collect::<Vec<_>>().await;
let events = events
.into_iter()
.filter_map(|e| match e.payload {
test_manager_test_lib::SuiteEventPayload::RunEvent(e) => Some(e),
_ => None,
})
.collect::<Vec<_>>();
// make sure that test never finished
for event in events {
match event {
RunEvent::SuiteStopped { .. } => {
panic!("should not receive SuiteStopped event as the test was killed. ")
}
_ => {}
}
}
}
#[fuchsia::test]
async fn calling_stop_should_stop_test() {
let proxy = connect_run_builder!().unwrap();
let builder = TestBuilder::new(proxy);
// can't use hanging test here as stop will only return once current running test completes.
let suite = builder
.add_suite(
"fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/huge_gtest.cm",
default_run_option(),
)
.await
.unwrap();
let _builder_run = fasync::Task::spawn(async move { builder.run().await });
let (sender, mut recv) = mpsc::channel(1024);
let controller = suite.controller();
let task = fasync::Task::spawn(async move { suite.collect_events(sender).await });
// let the test start
let _initial_event = recv.next().await.unwrap();
controller.stop().unwrap();
// collect rest of the events
let events = recv.collect::<Vec<_>>().await;
task.await.unwrap();
// get suite finished event
let events = events
.into_iter()
.filter_map(|e| match e.payload {
test_manager_test_lib::SuiteEventPayload::RunEvent(e) => match e {
RunEvent::SuiteStopped { .. } => Some(e),
_ => None,
},
_ => None,
})
.collect::<Vec<_>>();
assert_eq!(events, vec![RunEvent::suite_stopped(SuiteStatus::Stopped)]);
}
#[fuchsia::test]
async fn launch_and_test_subpackaged_test() {
let test_url =
"fuchsia-pkg://fuchsia.com/subpackaged_echo_integration_test_cpp#meta/default.cm";
let (events, logs) = run_single_test(test_url, default_run_option()).await.unwrap();
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("EchoIntegrationTest.TestEcho"),
RunEvent::case_started("EchoIntegrationTest.TestEcho"),
RunEvent::case_stopped("EchoIntegrationTest.TestEcho", CaseStatus::Passed),
RunEvent::case_finished("EchoIntegrationTest.TestEcho"),
RunEvent::suite_stopped(SuiteStatus::Passed),
];
assert_eq!(logs, Vec::new());
assert_eq!(&expected_events, &events);
let test_url =
"fuchsia-pkg://fuchsia.com/subpackaged_echo_integration_test_rust#meta/default.cm";
let (events, logs) = run_single_test(test_url, default_run_option()).await.unwrap();
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("echo_integration_test"),
RunEvent::case_started("echo_integration_test"),
RunEvent::case_stopped("echo_integration_test", CaseStatus::Passed),
RunEvent::case_finished("echo_integration_test"),
RunEvent::suite_stopped(SuiteStatus::Passed),
];
assert_eq!(logs, Vec::new());
assert_eq!(&expected_events, &events);
}
#[fuchsia::test]
async fn launch_and_test_echo_test() {
let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/echo_test_realm.cm";
let (events, logs) = run_single_test(test_url, default_run_option()).await.unwrap();
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("EchoTest"),
RunEvent::case_started("EchoTest"),
RunEvent::case_stopped("EchoTest", CaseStatus::Passed),
RunEvent::case_finished("EchoTest"),
RunEvent::suite_stopped(SuiteStatus::Passed),
];
assert_eq!(logs, Vec::new());
assert_eq!(&expected_events, &events);
}
#[fuchsia::test]
async fn launch_and_test_no_on_finished() {
let test_url =
"fuchsia-pkg://fuchsia.com/test_manager_test#meta/no-onfinished-after-test-example.cm";
let (events, logs) = run_single_test(test_url, default_run_option()).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![RunEvent::suite_started()];
for case in test_cases {
expected_events.push(RunEvent::case_found(case));
expected_events.push(RunEvent::case_started(case));
for i in 1..=3 {
expected_events.push(RunEvent::case_stdout(case, format!("log{} for {}", i, case)));
}
expected_events.push(RunEvent::case_stopped(case, CaseStatus::Passed));
expected_events.push(RunEvent::case_finished(case));
}
expected_events.push(RunEvent::suite_stopped(SuiteStatus::DidNotFinish));
let expected_events = expected_events.into_iter().group_by_test_case_unordered();
assert_eq!(&expected_events, &events);
assert_eq!(logs, Vec::new());
}
#[fuchsia::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_single_test(test_url, default_run_option()).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.rsf")
.into_iter()
.group_by_test_case_unordered();
assert_eq!(logs, Vec::new());
assert_eq!(&expected_events, &events);
}
#[fuchsia::test]
async fn launch_and_test_isolated_data() {
let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/data_storage_test.cm";
let (events, _logs) = run_single_test(test_url, default_run_option()).await.unwrap();
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("test_data_storage"),
RunEvent::case_started("test_data_storage"),
RunEvent::case_stopped("test_data_storage", CaseStatus::Passed),
RunEvent::case_finished("test_data_storage"),
RunEvent::suite_stopped(SuiteStatus::Passed),
];
assert_eq!(&expected_events, &events);
}
#[fuchsia::test]
async fn positive_filter_test() {
let test_url = "fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/sample_tests.cm";
let mut options = default_run_option();
options.case_filters_to_run =
Some(vec!["SampleTest2.SimplePass".into(), "SampleFixture*".into()]);
let (events, logs) = run_single_test(test_url, options).await.unwrap();
let events = events.into_iter().group_by_test_case_unordered();
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("SampleTest2.SimplePass"),
RunEvent::case_started("SampleTest2.SimplePass"),
RunEvent::case_stopped("SampleTest2.SimplePass", CaseStatus::Passed),
RunEvent::case_finished("SampleTest2.SimplePass"),
RunEvent::case_found("SampleFixture.Test1"),
RunEvent::case_started("SampleFixture.Test1"),
RunEvent::case_stopped("SampleFixture.Test1", CaseStatus::Passed),
RunEvent::case_finished("SampleFixture.Test1"),
RunEvent::case_found("SampleFixture.Test2"),
RunEvent::case_started("SampleFixture.Test2"),
RunEvent::case_stopped("SampleFixture.Test2", CaseStatus::Passed),
RunEvent::case_finished("SampleFixture.Test2"),
RunEvent::suite_stopped(SuiteStatus::Passed),
]
.into_iter()
.group_by_test_case_unordered();
assert_eq!(logs, Vec::new());
assert_eq!(&expected_events, &events);
}
#[fuchsia::test]
async fn negative_filter_test() {
let test_url = "fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/sample_tests.cm";
let mut options = default_run_option();
options.case_filters_to_run = Some(vec![
"-SampleTest1.*".into(),
"-Tests/SampleParameterizedTestFixture.*".into(),
"-SampleDisabled.*".into(),
"-WriteToStd.*".into(),
]);
let (events, logs) = run_single_test(test_url, options).await.unwrap();
let events = events.into_iter().group_by_test_case_unordered();
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("SampleTest2.SimplePass"),
RunEvent::case_started("SampleTest2.SimplePass"),
RunEvent::case_stopped("SampleTest2.SimplePass", CaseStatus::Passed),
RunEvent::case_finished("SampleTest2.SimplePass"),
RunEvent::case_found("SampleFixture.Test1"),
RunEvent::case_started("SampleFixture.Test1"),
RunEvent::case_stopped("SampleFixture.Test1", CaseStatus::Passed),
RunEvent::case_finished("SampleFixture.Test1"),
RunEvent::case_found("SampleFixture.Test2"),
RunEvent::case_started("SampleFixture.Test2"),
RunEvent::case_stopped("SampleFixture.Test2", CaseStatus::Passed),
RunEvent::case_finished("SampleFixture.Test2"),
RunEvent::suite_stopped(SuiteStatus::Passed),
]
.into_iter()
.group_by_test_case_unordered();
assert_eq!(logs, Vec::new());
assert_eq!(&expected_events, &events);
}
#[fuchsia::test]
async fn positive_and_negative_filter_test() {
let test_url = "fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/sample_tests.cm";
let mut options = default_run_option();
options.case_filters_to_run =
Some(vec!["SampleFixture.*".into(), "SampleTest2.*".into(), "-*Test1".into()]);
let (events, logs) = run_single_test(test_url, options).await.unwrap();
let events = events.into_iter().group_by_test_case_unordered();
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("SampleTest2.SimplePass"),
RunEvent::case_started("SampleTest2.SimplePass"),
RunEvent::case_stopped("SampleTest2.SimplePass", CaseStatus::Passed),
RunEvent::case_finished("SampleTest2.SimplePass"),
RunEvent::case_found("SampleFixture.Test2"),
RunEvent::case_started("SampleFixture.Test2"),
RunEvent::case_stopped("SampleFixture.Test2", CaseStatus::Passed),
RunEvent::case_finished("SampleFixture.Test2"),
RunEvent::suite_stopped(SuiteStatus::Passed),
]
.into_iter()
.group_by_test_case_unordered();
assert_eq!(logs, Vec::new());
assert_eq!(&expected_events, &events);
}
#[fuchsia::test]
async fn parallel_tests() {
let test_url = "fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/sample_tests.cm";
let mut options = default_run_option();
options.parallel = Some(10);
let (events, logs) = run_single_test(test_url, options).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.rsf")
.into_iter()
.group_by_test_case_unordered();
assert_eq!(logs, Vec::new());
assert_eq!(&expected_events, &events);
}
#[fuchsia::test]
async fn multiple_test() {
let gtest_test_url =
"fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/sample_tests.cm";
let builder = TestBuilder::new(connect_run_builder!().unwrap());
let gtest_suite_instance1 = builder
.add_suite(gtest_test_url, default_run_option())
.await
.expect("Cannot create suite instance");
let gtest_suite_instance2 = builder
.add_suite(gtest_test_url, default_run_option())
.await
.expect("Cannot create suite instance");
let builder_run = fasync::Task::spawn(async move { builder.run().await });
let fut1 = collect_suite_events(gtest_suite_instance1);
let fut2 = collect_suite_events(gtest_suite_instance2);
let (ret1, ret2) = futures::join!(fut1, fut2);
let (gtest_events1, gtest_log1) = ret1.unwrap();
let (gtest_events2, gtest_log2) = ret2.unwrap();
builder_run.await.expect("builder execution failed");
let gtest_events1 = gtest_events1.into_iter().group_by_test_case_unordered();
let gtest_events2 = gtest_events2.into_iter().group_by_test_case_unordered();
let expected_events =
include!("../../../test_runners/gtest/test_data/sample_tests_golden_events.rsf")
.into_iter()
.group_by_test_case_unordered();
assert_eq!(gtest_log1, Vec::new());
assert_eq!(gtest_log2, Vec::new());
assert_eq!(&expected_events, &gtest_events1);
assert_eq!(&expected_events, &gtest_events2);
}
#[fuchsia::test]
async fn no_suite_service_test() {
let proxy = connect_run_builder!().unwrap();
let builder = TestBuilder::new(proxy);
let suite = builder
.add_suite(
"fuchsia-pkg://fuchsia.com/test_manager_test#meta/no_suite_service.cm",
default_run_option(),
)
.await
.unwrap();
let _builder_run = fasync::Task::spawn(async move { builder.run().await });
let (sender, _recv) = mpsc::channel(1024);
let err = suite
.collect_events(sender)
.await
.expect_err("this should return instance not found error");
let err = err.downcast::<test_manager_test_lib::SuiteLaunchError>().unwrap();
// as test doesn't expose suite service, enumeration of test cases will fail.
assert_eq!(err, test_manager_test_lib::SuiteLaunchError::CaseEnumeration);
}
#[fuchsia::test]
async fn test_not_resolved() {
let proxy = connect_run_builder!().unwrap();
let builder = TestBuilder::new(proxy);
let suite = builder
.add_suite(
"fuchsia-pkg://fuchsia.com/test_manager_test#meta/invalid_cml.cm",
default_run_option(),
)
.await
.unwrap();
let _builder_run = fasync::Task::spawn(async move { builder.run().await });
let (sender, _recv) = mpsc::channel(1024);
let err = suite
.collect_events(sender)
.await
.expect_err("this should return instance not found error");
let err = err.downcast::<test_manager_test_lib::SuiteLaunchError>().unwrap();
assert_eq!(err, test_manager_test_lib::SuiteLaunchError::InstanceCannotResolve);
}
#[fuchsia::test]
async fn collect_isolated_logs_using_default_log_iterator() {
let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
let (_events, logs) = run_single_test(test_url, default_run_option()).await.unwrap();
assert_eq!(
logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
vec!["Started diagnostics publisher", "Finishing through Stop"],
"{logs:#?}",
);
}
#[fuchsia::test]
async fn collect_isolated_logs_from_generated_component_manifest() {
let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/logger-test-generated-manifest.cm";
let (_events, logs) = run_single_test(test_url, default_run_option()).await.unwrap();
assert_eq!(
logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
vec!["I'm a info log from a test"],
"{logs:#?}",
);
}
fn get_stdmsgs_and_status(events: &Vec<RunEvent>) -> (Vec<String>, Option<SuiteStatus>) {
let mut stdmsgs = vec![];
let mut s = None;
for e in events {
match e {
RunEvent::CaseStdout { name, stdout_message } => {
stdmsgs.push(format!("{} - {}", name, stdout_message));
}
RunEvent::CaseStderr { name, stderr_message } => {
stdmsgs.push(format!("{} - {}", name, stderr_message));
}
RunEvent::SuiteStopped { status } => s = Some(status.clone()),
_ => {
continue;
}
}
}
(stdmsgs, s)
}
#[fuchsia::test]
async fn collect_isolated_logs_using_batch() {
let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
let mut options = default_run_option();
options.log_iterator = Some(ftest_manager::LogsIteratorOption::BatchIterator);
let (events, logs) = run_single_test(test_url, options).await.unwrap();
let (stdmsgs, status) = get_stdmsgs_and_status(&events);
assert_eq!(status, Some(SuiteStatus::Passed), "{logs:#?}\n{stdmsgs:#?}");
assert_eq!(
logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
vec!["Started diagnostics publisher", "Finishing through Stop"],
"{logs:#?}\n{stdmsgs:#?}",
);
}
#[fuchsia::test]
async fn collect_isolated_logs_using_host_socket() {
let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
let options = RunOptions {
log_iterator: Some(ftest_manager::LogsIteratorOption::SocketBatchIterator),
..default_run_option()
};
let (events, logs) = run_single_test(test_url, options).await.unwrap();
let (stdmsgs, status) = get_stdmsgs_and_status(&events);
assert_eq!(status, Some(SuiteStatus::Passed), "{logs:#?}\n{stdmsgs:#?}");
assert_eq!(
logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
vec!["Started diagnostics publisher", "Finishing through Stop"],
"{logs:#?}\n{stdmsgs:#?}",
);
}
#[fuchsia::test]
async fn update_log_severity_for_all_components() {
let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
let options = RunOptions {
log_iterator: Some(ftest_manager::LogsIteratorOption::SocketBatchIterator),
log_interest: Some(vec![
selectors::parse_log_interest_selector_or_severity("DEBUG").unwrap()
]),
..default_run_option()
};
let (_events, logs) = run_single_test(test_url, options).await.unwrap();
assert_eq!(
logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
vec![
"I'm a debug log from a test",
"Started diagnostics publisher",
"I'm a debug log from the publisher!",
"Finishing through Stop",
]
);
}
#[fuchsia::test]
async fn update_log_severity_for_the_test() {
let test_url = "fuchsia-pkg://fuchsia.com/test-manager-diagnostics-tests#meta/test-root.cm";
let options = RunOptions {
log_iterator: Some(ftest_manager::LogsIteratorOption::SocketBatchIterator),
log_interest: Some(vec![selectors::parse_log_interest_selector_or_severity(
"<root>#DEBUG",
)
.unwrap()]),
..default_run_option()
};
let (_events, logs) = run_single_test(test_url, options).await.unwrap();
assert_eq!(
logs.iter().map(|attributed| attributed.log.as_ref()).collect::<Vec<&str>>(),
vec![
"I'm a debug log from a test",
"Started diagnostics publisher",
"Finishing through Stop",
]
);
}
#[fuchsia::test]
async fn custom_artifact_test() {
let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/custom_artifact_user.cm";
let (events, _) = run_single_test(test_url, default_run_option()).await.unwrap();
let events = events.into_iter().group_by_test_case_unordered();
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("use_artifact"),
RunEvent::case_started("use_artifact"),
RunEvent::case_stopped("use_artifact", CaseStatus::Passed),
RunEvent::case_finished("use_artifact"),
RunEvent::suite_stopped(SuiteStatus::Passed),
RunEvent::suite_custom(".", "artifact.txt", "Hello, world!"),
]
.into_iter()
.group_by_test_case_unordered();
assert_eq!(&expected_events, &events);
}
#[fuchsia::test]
async fn debug_data_test() {
let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/debug_data_write_test.cm";
let builder = TestBuilder::new(connect_run_builder!().unwrap());
let suite_instance = builder
.add_suite(test_url, default_run_option())
.await
.expect("Cannot create suite instance");
let (run_events_result, suite_events_result) =
futures::future::join(builder.run(), collect_suite_events(suite_instance)).await;
let suite_events = suite_events_result.unwrap().0;
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("publish_debug_data"),
RunEvent::case_started("publish_debug_data"),
RunEvent::case_stopped("publish_debug_data", CaseStatus::Passed),
RunEvent::case_finished("publish_debug_data"),
RunEvent::suite_stopped(SuiteStatus::Passed),
];
assert_eq!(
suite_events.into_iter().group_by_test_case_unordered(),
expected_events.into_iter().group_by_test_case_unordered(),
);
let num_debug_data_events = stream::iter(run_events_result.unwrap())
.then(|run_event| async move {
let TestRunEventPayload::DebugData { socket, .. } = run_event.payload;
let content = collect_string_from_socket(socket).await.unwrap();
content == "Debug data from test\n"
})
.filter(|matches_vmo| futures::future::ready(*matches_vmo))
.count()
.await;
assert_eq!(num_debug_data_events, 1);
}
// Test that we can hook up DebugDataIterator connection for EarlyBootPrfile.
#[fuchsia::test]
async fn early_boot_profile_test() {
let proxy = client::connect_to_protocol::<ftest_manager::EarlyBootProfileMarker>()
.expect("cannot connect to run builder proxy");
let (debug_data_proxy, iterator) = endpoints::create_proxy().unwrap();
proxy.register_watcher(iterator).unwrap();
// We cannot check the returned value as it can be empty vector or bunch of socket connections.
// But we can check that our call to DebugDataIterator goes through.
let _ = debug_data_proxy.get_next().await.unwrap();
}
#[fuchsia::test]
async fn debug_data_accumulate_test() {
let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/debug_data_write_test.cm";
for iteration in 1usize..3 {
let builder = TestBuilder::new(connect_run_builder!().unwrap());
builder.set_scheduling_options(true).expect("set scheduling options");
let suite_instance = builder
.add_suite(test_url, default_run_option())
.await
.expect("Cannot create suite instance");
let (run_events_result, _) =
futures::future::join(builder.run(), collect_suite_events(suite_instance)).await;
let num_debug_data_events = stream::iter(run_events_result.unwrap())
.then(|run_event| async move {
let TestRunEventPayload::DebugData { socket, .. } = run_event.payload;
let content = collect_string_from_socket(socket).await.unwrap();
content == "Debug data from test\n"
})
.filter(|matches_vmo| futures::future::ready(*matches_vmo))
.count()
.await;
assert_eq!(num_debug_data_events, iteration);
}
// If I run the same test again, also accumulating debug_data, I should see two files
}
#[fuchsia::test]
async fn debug_data_isolated_test() {
let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/debug_data_write_test.cm";
// By default, when I run the same test twice, debug data is not accumulated.
for _ in 0..2 {
let builder = TestBuilder::new(connect_run_builder!().unwrap());
let suite_instance = builder
.add_suite(test_url, default_run_option())
.await
.expect("Cannot create suite instance");
let (run_events_result, _) =
futures::future::join(builder.run(), collect_suite_events(suite_instance)).await;
let num_debug_data_events = stream::iter(run_events_result.unwrap())
.then(|run_event| async move {
let TestRunEventPayload::DebugData { socket, .. } = run_event.payload;
let content = collect_string_from_socket(socket).await.unwrap();
content == "Debug data from test\n"
})
.filter(|matches_vmo| futures::future::ready(*matches_vmo))
.count()
.await;
assert_eq!(num_debug_data_events, 1);
}
}
#[fuchsia::test]
async fn custom_artifact_realm_test() {
let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/custom_artifact_realm_test.cm";
let (events, _) = run_single_test(test_url, default_run_option()).await.unwrap();
let events = events.into_iter().group_by_test_case_unordered();
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("use_artifact"),
RunEvent::case_started("use_artifact"),
RunEvent::case_stopped("use_artifact", CaseStatus::Passed),
RunEvent::case_finished("use_artifact"),
RunEvent::suite_stopped(SuiteStatus::Passed),
RunEvent::suite_custom("test_driver", "artifact.txt", "Hello, world!"),
]
.into_iter()
.group_by_test_case_unordered();
assert_eq!(&expected_events, &events);
}
#[fuchsia::test]
async fn enumerate_invalid_test() {
let proxy = connect_query_server!().unwrap();
let (_iterator, server_end) = endpoints::create_proxy().unwrap();
let err = proxy
.enumerate("fuchsia-pkg://fuchsia.com/test_manager_test#meta/invalid_cml.cm", server_end)
.await
.unwrap()
.expect_err("This should error out as we have invalid test");
assert_eq!(err, ftest_manager::LaunchError::InstanceCannotResolve);
}
#[fuchsia::test]
async fn enumerate_echo_test() {
let proxy = connect_query_server!().unwrap();
let (iterator, server_end) = endpoints::create_proxy().unwrap();
proxy
.enumerate(
"fuchsia-pkg://fuchsia.com/test_manager_test#meta/echo_test_realm.cm",
server_end,
)
.await
.unwrap()
.expect("This should not fail");
let mut cases = vec![];
loop {
let mut c = iterator.get_next().await.unwrap();
if c.is_empty() {
break;
}
cases.append(&mut c);
}
assert_eq!(
cases.into_iter().map(|c| c.name.unwrap()).collect::<Vec<_>>(),
vec!["EchoTest".to_string()]
);
}
#[fuchsia::test]
async fn enumerate_huge_test() {
let proxy = connect_query_server!().unwrap();
let (iterator, server_end) = endpoints::create_proxy().unwrap();
proxy
.enumerate(
"fuchsia-pkg://fuchsia.com/gtest-runner-example-tests#meta/huge_gtest.cm",
server_end,
)
.await
.unwrap()
.expect("This should not fail");
let mut cases = vec![];
loop {
let mut c = iterator.get_next().await.unwrap();
if c.is_empty() {
break;
}
cases.append(&mut c);
}
let expected_cases = (0..=999)
.into_iter()
.map(|n| format!("HugeStress/HugeTest.Test/{}", n))
.collect::<Vec<_>>();
assert_eq!(cases.into_iter().map(|c| c.name.unwrap()).collect::<Vec<_>>(), expected_cases);
}
#[fuchsia::test]
async fn capability_access_test() {
let test_url =
"fuchsia-pkg://fuchsia.com/test_manager_test#meta/nonhermetic_capability_test.cm";
let (events, _) = run_single_test(test_url, default_run_option()).await.unwrap();
let failed_suite = RunEvent::suite_stopped(SuiteStatus::Failed);
assert!(events.contains(&failed_suite));
}
#[fuchsia::test]
async fn launch_chromium_test() {
// TODO(91934): This test is launched in the chromium realm. Once we support out of tree realm
// definitions we should move the definition and test to chromium.
let test_url = "fuchsia-pkg://fuchsia.com/test_manager_test#meta/simple_chromium_realm_test.cm";
let (events, logs) = run_single_test(test_url, default_run_option()).await.unwrap();
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("noop_test"),
RunEvent::case_started("noop_test"),
RunEvent::case_stopped("noop_test", CaseStatus::Passed),
RunEvent::case_finished("noop_test"),
RunEvent::suite_stopped(SuiteStatus::Passed),
];
assert_eq!(logs, Vec::new());
assert_eq!(&expected_events, &events);
}