blob: bc7de0e9c4a4c7d69bf6fd62a3ca70f9e210f656 [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::{Context as _, Error};
use ftest_manager::{CaseStatus, RunOptions, SuiteStatus};
use pretty_assertions::assert_eq;
use regex::Regex;
use test_manager_test_lib::{GroupRunEventByTestCase, RunEvent};
use {fidl_fuchsia_test_manager as ftest_manager, fuchsia_async as fasync};
pub async fn run_test(
test_url: &str,
run_disabled_tests: bool,
parallel: Option<u16>,
test_args: Vec<String>,
) -> Result<Vec<RunEvent>, Error> {
let time_taken = Regex::new(r" \(.*?\)$").unwrap();
let run_builder = test_runners_test_lib::connect_to_test_manager().await?;
let builder = test_manager_test_lib::TestBuilder::new(run_builder);
let run_options = RunOptions {
run_disabled_tests: Some(run_disabled_tests),
parallel,
arguments: Some(test_args),
..Default::default()
};
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 (mut events, _logs) = test_runners_test_lib::process_events(suite_instance, false).await?;
for event in events.iter_mut() {
match event {
RunEvent::CaseStdout { name, stdout_message } => {
let log = time_taken.replace(&stdout_message, "");
*event = RunEvent::case_stdout(name.to_string(), log.to_string());
}
_ => {}
}
}
builder_run.await.context("builder execution failed")?;
Ok(events)
}
#[fuchsia_async::run_singlethreaded(test)]
async fn launch_and_test_echo_test() {
let test_url = "fuchsia-pkg://fuchsia.com/go-test-runner-example#meta/echo-test-realm.cm";
let events = run_test(test_url, false, Some(10), vec![]).await.unwrap();
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("TestEcho"),
RunEvent::case_started("TestEcho"),
RunEvent::case_stopped("TestEcho", CaseStatus::Passed),
RunEvent::case_finished("TestEcho"),
RunEvent::suite_stopped(SuiteStatus::Passed),
];
assert_eq!(expected_events, events);
}
#[fuchsia_async::run_singlethreaded(test)]
async fn launch_and_test_file_with_no_test() {
let test_url = "fuchsia-pkg://fuchsia.com/go-test-runner-example#meta/empty_go_test.cm";
let events = run_test(test_url, false, Some(10), vec![]).await.unwrap();
let expected_events =
vec![RunEvent::suite_started(), RunEvent::suite_stopped(SuiteStatus::Passed)];
assert_eq!(expected_events, events);
}
async fn launch_and_run_sample_test_helper(parallel: Option<u16>) {
let test_url = "fuchsia-pkg://fuchsia.com/go-test-runner-example#meta/sample_go_test.cm";
let mut events = run_test(test_url, false, parallel, vec!["-my_custom_flag_2".to_owned()])
.await
.unwrap()
.into_iter()
.group_by_test_case_unordered();
// handle crashing test case separately, as it contains a stack trace we can't match on.
let run_events_for_crashing = events
.remove(&Some("TestCrashing".to_string()))
.expect("Expect run events for TestCrashing test case");
assert_eq!(
run_events_for_crashing.non_artifact_events,
vec![
RunEvent::case_found("TestCrashing"),
RunEvent::case_started("TestCrashing"),
RunEvent::case_stopped("TestCrashing", CaseStatus::Failed),
RunEvent::case_finished("TestCrashing"),
]
);
assert!(run_events_for_crashing.stdout_events.is_empty());
assert_eq!(
&run_events_for_crashing.stderr_events[..5],
&vec![
RunEvent::case_stderr("TestCrashing", "panic: This will crash"),
RunEvent::case_stderr("TestCrashing", " [recovered]"),
RunEvent::case_stderr("TestCrashing", "\tpanic: This will crash"),
RunEvent::case_stderr("TestCrashing", ""),
RunEvent::case_stderr("TestCrashing", ""),
]
);
assert_eq!(
run_events_for_crashing.stderr_events.last().unwrap(),
&RunEvent::case_stderr("TestCrashing", "Test exited abnormally"),
);
let expected_events = vec![
RunEvent::suite_started(),
RunEvent::case_found("TestFailing"),
RunEvent::case_started("TestFailing"),
RunEvent::case_stdout("TestFailing", " sample_go_test.go:25: This will fail"),
RunEvent::case_stopped("TestFailing", CaseStatus::Failed),
RunEvent::case_finished("TestFailing"),
RunEvent::case_found("TestPassing"),
RunEvent::case_started("TestPassing"),
RunEvent::case_stdout("TestPassing", "This test will pass"),
RunEvent::case_stdout("TestPassing", "It will also print this line"),
RunEvent::case_stdout("TestPassing", "And this line"),
RunEvent::case_stopped("TestPassing", CaseStatus::Passed),
RunEvent::case_finished("TestPassing"),
RunEvent::case_found("TestPrefix"),
RunEvent::case_started("TestPrefix"),
RunEvent::case_stdout("TestPrefix", "Testing that given two tests where one test is prefix of another can execute independently."),
RunEvent::case_stopped("TestPrefix", CaseStatus::Passed),
RunEvent::case_finished("TestPrefix"),
RunEvent::case_found("TestSkipped"),
RunEvent::case_started("TestSkipped"),
RunEvent::case_stdout("TestSkipped", " sample_go_test.go:33: Skipping this test"),
RunEvent::case_stopped("TestSkipped", CaseStatus::Skipped),
RunEvent::case_finished("TestSkipped"),
RunEvent::case_found("TestSubtests"),
RunEvent::case_started("TestSubtests"),
RunEvent::case_stdout("TestSubtests", "=== RUN TestSubtests/Subtest1"),
RunEvent::case_stdout("TestSubtests", "=== RUN TestSubtests/Subtest2"),
RunEvent::case_stdout("TestSubtests", "=== RUN TestSubtests/Subtest3"),
RunEvent::case_stdout("TestSubtests", " --- PASS: TestSubtests/Subtest1"),
RunEvent::case_stdout("TestSubtests", " --- PASS: TestSubtests/Subtest2"),
RunEvent::case_stdout("TestSubtests", " --- PASS: TestSubtests/Subtest3"),
RunEvent::case_stopped("TestSubtests", CaseStatus::Passed),
RunEvent::case_finished("TestSubtests"),
RunEvent::case_found("TestPrefixExtra"),
RunEvent::case_started("TestPrefixExtra"),
RunEvent::case_stdout("TestPrefixExtra", "Testing that given two tests where one test is prefix of another can execute independently."),
RunEvent::case_stopped("TestPrefixExtra", CaseStatus::Passed),
RunEvent::case_finished("TestPrefixExtra"),
RunEvent::case_found("TestPrintMultiline"),
RunEvent::case_started("TestPrintMultiline"),
RunEvent::case_stdout("TestPrintMultiline", "This test will print the msg in multi-line."),
RunEvent::case_stopped("TestPrintMultiline", CaseStatus::Passed),
RunEvent::case_finished("TestPrintMultiline"),
RunEvent::case_found("TestCustomArg"),
RunEvent::case_started("TestCustomArg"),
RunEvent::case_stopped("TestCustomArg", CaseStatus::Passed),
RunEvent::case_finished("TestCustomArg"),
RunEvent::case_found("TestCustomArg2"),
RunEvent::case_started("TestCustomArg2"),
RunEvent::case_stopped("TestCustomArg2", CaseStatus::Passed),
RunEvent::case_finished("TestCustomArg2"),
RunEvent::case_found("TestEnviron"),
RunEvent::case_started("TestEnviron"),
RunEvent::case_stopped("TestEnviron", CaseStatus::Passed),
RunEvent::case_finished("TestEnviron"),
RunEvent::suite_stopped(SuiteStatus::Failed)
].into_iter().group_by_test_case_unordered();
assert_eq!(events, expected_events);
}
#[fuchsia_async::run_singlethreaded(test)]
async fn launch_and_run_sample_test() {
launch_and_run_sample_test_helper(Some(10)).await;
}
#[fuchsia_async::run_singlethreaded(test)]
async fn launch_and_run_sample_test_no_concurrent() {
launch_and_run_sample_test_helper(None).await;
}
// This test will hang if test cases are not executed in parallel.
#[fuchsia_async::run_singlethreaded(test)]
async fn test_parallel_execution() {
let test_url = "fuchsia-pkg://fuchsia.com/go-test-runner-example#meta/concurrency-test.cm";
let events = run_test(test_url, false, Some(5), vec![])
.await
.unwrap()
.into_iter()
.group_by_test_case_unordered();
let mut expected_events = vec![RunEvent::suite_started()];
for i in 1..=5 {
let s = format!("Test{}", i);
expected_events.extend(vec![
RunEvent::case_found(&s),
RunEvent::case_started(&s),
RunEvent::case_stopped(&s, CaseStatus::Passed),
RunEvent::case_finished(&s),
])
}
expected_events.push(RunEvent::suite_stopped(SuiteStatus::Passed));
let expected_events = expected_events.into_iter().group_by_test_case_unordered();
assert_eq!(events, expected_events);
}