blob: 569abfc98f1a73ce0f18eef44a9a00199add4f03 [file] [log] [blame]
// Copyright 2016 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 is a simple Fuchsia program that connects to the test_runner process,
// starts a test and exits with success or failure based on the success or
// failure of the test.
#include <iostream>
#include <lib/async-loop/cpp/loop.h>
#include <zircon/processargs.h>
#include <zircon/status.h>
#include "garnet/bin/test_runner/run_integration_tests/test_runner_config.h"
#include "lib/fxl/command_line.h"
#include "lib/fxl/strings/string_printf.h"
#include "lib/test_runner/cpp/test_runner.h"
namespace test_runner {
namespace {
class TestRunObserverImpl : public test_runner::TestRunObserver {
public:
TestRunObserverImpl(async::Loop* loop, const std::string& test_id)
: loop_(loop), test_id_(test_id) {
FXL_CHECK(loop);
}
void SendMessage(const std::string& test_id, const std::string& operation,
const std::string& msg) override {
FXL_CHECK(test_id == test_id_);
}
void Teardown(const std::string& test_id, bool success) override {
FXL_CHECK(test_id == test_id_);
success_ = success;
loop_->Quit();
}
bool success() { return success_; }
private:
async::Loop* const loop_;
std::string test_id_;
bool success_;
};
bool RunTest(async::Loop* loop,
std::shared_ptr<component::StartupContext> app_context,
const std::string& url, const std::vector<std::string>& args) {
FXL_CHECK(loop);
uint64_t random_number;
zx_cprng_draw(&random_number, sizeof random_number);
std::string test_id = fxl::StringPrintf("test_%lX", random_number);
TestRunObserverImpl observer(loop, test_id);
test_runner::TestRunContext context(app_context, &observer, test_id, url,
args);
loop->Run();
loop->ResetQuit();
return observer.success();
}
void PrintKnownTests(const TestRunnerConfig& config) {
std::cerr << "Known tests are:" << std::endl;
for (auto& test_name : config.test_names()) {
std::cerr << " " << test_name << std::endl;
}
for (auto& test_name : config.disabled_test_names()) {
std::cerr << " " << test_name << " (disabled)" << std::endl;
}
}
int RunIntegrationTestsMain(int argc, char** argv) {
async::Loop loop(&kAsyncLoopConfigAttachToThread);
fxl::CommandLine settings = fxl::CommandLineFromArgcArgv(argc, argv);
std::string test_file;
bool has_test_file = settings.GetOptionValue("test_file", &test_file);
bool requesting_help = settings.HasOption("help");
if (!has_test_file || requesting_help) {
std::cerr << R"USAGE(run_integration_tests [TEST NAME]
--test_file <file path> The JSON file defining all the tests (required).
--help This message.
If a [TEST NAME] which is listed in --test_file is provided, it is run.
Otherwise, all tests from --test_file are run.
)USAGE";
if (!test_file.empty()) {
TestRunnerConfig config(test_file);
PrintKnownTests(config);
}
if (!requesting_help && !has_test_file) {
return 1;
}
return 0;
}
TestRunnerConfig config(test_file);
std::shared_ptr<component::StartupContext> app_context =
component::StartupContext::CreateFromStartupInfo();
std::vector<std::string> test_names = settings.positional_args();
if (test_names.empty()) {
// If no tests were specified, run all tests.
test_names = config.test_names();
}
std::vector<std::string> unknown;
std::vector<std::string> failed;
std::vector<std::string> succeeded;
for (auto& test_name : test_names) {
if (!config.HasTestNamed(test_name)) {
unknown.push_back(test_name);
continue;
}
std::vector<std::string> args = config.GetTestCommand(test_name);
if (args.empty()) {
unknown.push_back(test_name);
continue;
}
auto url = args.front();
args.erase(args.begin());
std::cerr << test_name << " ...\r";
if (RunTest(&loop, app_context, url, args)) {
std::cerr << test_name << " OK" << std::endl;
succeeded.push_back(test_name);
} else {
std::cerr << test_name << " FAIL" << std::endl;
failed.push_back(test_name);
}
}
if (!succeeded.empty()) {
std::cerr << "Succeeded tests:" << std::endl;
for (auto& test_name : succeeded) {
std::cerr << " " << test_name << std::endl;
}
}
if (!failed.empty()) {
std::cerr << "Failed tests:" << std::endl;
for (auto& test_name : failed) {
std::cerr << " " << test_name << std::endl;
}
}
if (!unknown.empty()) {
std::cerr << "Unknown tests:" << std::endl;
for (auto& test_name : unknown) {
std::cerr << " " << test_name << std::endl;
}
PrintKnownTests(config);
}
if (failed.empty() && unknown.empty()) {
return 0;
} else {
return 1;
}
}
} // namespace
} // namespace test_runner
int main(int argc, char** argv) {
return test_runner::RunIntegrationTestsMain(argc, argv);
}