blob: c1d7a71bc2482ad6a9bcb1a9a9075d7a77ef6af0 [file] [log] [blame] [edit]
// Copyright 2018 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.
// Helper functions for running test binaries and recording their results.
#ifndef RUNTESTS_UTILS_RUNTESTS_UTILS_H_
#define RUNTESTS_UTILS_RUNTESTS_UTILS_H_
#include <inttypes.h>
#include <lib/zircon-internal/fnv1hash.h>
#include <zircon/types.h>
#include <string>
#include <unordered_map>
#include <vector>
#include <fbl/intrusive_hash_table.h>
#include <fbl/intrusive_single_list.h>
#include <fbl/string.h>
#include <fbl/string_piece.h>
#include <fbl/vector.h>
namespace runtests {
// Status of launching a test subprocess.
enum LaunchStatus {
SUCCESS,
FAILED_TO_LAUNCH,
FAILED_TO_WAIT,
FAILED_DURING_IO,
FAILED_TO_RETURN_CODE,
FAILED_NONZERO_RETURN_CODE,
FAILED_COLLECTING_SINK_DATA,
FAILED_UNKNOWN,
TIMED_OUT,
};
// Represents a single dumpfile element.
struct DumpFile {
std::string name; // Name of the dumpfile.
std::string file; // File name for the content.
};
// Represents the result of a single test run.
struct Result {
fbl::String name;
LaunchStatus launch_status;
int64_t return_code; // Only valid if launch_status == SUCCESS or FAILED_NONZERO_RETURN_CODE.
std::unordered_map<std::string, std::vector<DumpFile>>
data_sinks; // Mapping from data sink name to list of files.
int64_t duration_milliseconds;
// Constructor really only needed until we have C++14, which will allow call-sites to use
// aggregate initializer syntax.
Result(const char* name_arg, LaunchStatus launch_status_arg, int64_t return_code_arg,
int64_t duration_milliseconds_arg)
: name(name_arg),
launch_status(launch_status_arg),
return_code(return_code_arg),
duration_milliseconds(duration_milliseconds_arg) {}
};
// Invokes a test binary and writes its output to a file.
//
// |argv| is a null-terminated array of argument strings passed to the test
// program.
// |output_dir| is the name of a directory where debug data
// will be written. If nullptr, no debug data will be collected.
// |output_filename| is the name of the file to which the test binary's output
// will be written. May be nullptr, in which case the output will not be
// redirected.
// |test_name| is used to populate Result and in log messages.
// |timeout_msec| is a number of milliseconds to wait for the test. If 0,
// will wait indefinitely.
// |realm_label| is the realm label to be applied to calls to underlying run-test-component.
// The test will run in that realm and its run artifacts will not be cleaned up automatically
// after the completion of the test.
std::unique_ptr<Result> RunTest(const char* argv[], const char* output_dir,
const char* output_filename, const char* test_name,
uint64_t timeout_msec, const char* realm_label);
// A means of measuring how long it takes to run tests.
class Stopwatch {
public:
virtual ~Stopwatch() = default;
// Starts timing.
virtual void Start() = 0;
// Returns the elapsed time in milliseconds since invoking Start(), or else
// since initialization if Start() has not yet been called.
virtual int64_t DurationInMsecs() = 0;
};
// Splits |input| by ',' and appends the results onto |output|.
// Empty strings are not put into output.
void ParseTestNames(fbl::StringPiece input, fbl::Vector<fbl::String>* output);
// Returns true iff |name| is equal to one of strings in |whitelist|.
bool IsInWhitelist(fbl::StringPiece name, const fbl::Vector<fbl::String>& whitelist);
// Ensures |dir_name| exists by creating it and its parents if it doesn't.
// Returns 0 on success, else an error code compatible with errno.
int MkDirAll(fbl::StringPiece dir_name);
// Returns "|parent|/|child|". Unless child is absolute, in which case it returns |child|.
//
// |parent| is the parent path.
// |child| is the child path.
fbl::String JoinPath(fbl::StringPiece parent, fbl::StringPiece child);
// Writes a JSON summary of test results given a sequence of results.
//
// |results| are the run results to summarize.
// |output_file_basename| is base name of output file.
// |syslog_path| is the file path where syslogs are written.
// |summary_json| is the file stream to write the JSON summary to.
//
// Returns 0 on success, else an error code compatible with errno.
int WriteSummaryJSON(const fbl::Vector<std::unique_ptr<Result>>& results,
fbl::StringPiece output_file_basename, fbl::StringPiece syslog_path,
FILE* summary_json);
// Resolves a set of globs.
//
// |globs| is an array of glob patterns.
// |resolved| will hold the results of resolving |globs|.
//
// Returns 0 on success, else an error code from glob.h.
int ResolveGlobs(const fbl::Vector<fbl::String>& globs, fbl::Vector<fbl::String>* resolved);
// Executes all specified binaries.
//
// |test_paths| are the paths of the binaries to execute.
// |test_args| are arguments passed into the binaries under test.
// |repeat| runs the entire test suite this many times. The entire suite is repeated rather than
// each test individually so that:
// a) any flakes due to the sequencing of tests can be reproduced
// b) we can get an idea of global flake rates without waiting for all runs to complete
// |timeout_msec| is the number of milliseconds to wait for a test before considering it failed.
// ignored if 0.
// |output_dir| is the output directory for all the tests' output. May be nullptr, in which case
// output will not be captured.
// |output_file_basename| is the basename of the tests' output files. May be nullptr only if
// |output_dir| is also nullptr.
// Each test's standard output and standard error will be written to
// |output_dir|/<test binary path>/|output_file_basename|.
// |realm_label| is the realm label to be applied to calls to underlying run-test-component.
// The test will run in that realm and its run artifacts will not be cleaned up automatically
// after the completion of the test.
// |failed_count| is an output parameter which will be set to the number of test
// binaries that failed.
// |results| is an output parameter to which run results will be appended.
//
// Returns false if any test binary failed, true otherwise.
bool RunTests(const fbl::Vector<fbl::String>& test_paths, const fbl::Vector<fbl::String>& test_args,
int repeat, uint64_t timeout_msec, const char* output_dir,
fbl::StringPiece output_file_basename, const char* realm_label,
int* failed_count, fbl::Vector<std::unique_ptr<Result>>* results);
// Expands |dir_globs| and searches those directories for files.
//
// |dir_globs| are expanded as globs to directory names, and then those directories are searched.
// |ignore_dir_name| iff not null, any directory with this basename will not be searched.
// |basename_whitelist| iff not empty, only files that have a basename in this whitelist will be
// returned.
// |test_paths| is an output parameter to which absolute file paths will be appended.
//
// Returns 0 on success, else an error code compatible with errno.
int DiscoverTestsInDirGlobs(const fbl::Vector<fbl::String>& dir_globs, const char* ignore_dir_name,
const fbl::Vector<fbl::String>& basename_whitelist,
fbl::Vector<fbl::String>* test_paths);
// Discovers and runs tests based on command line arguments.
//
// |argc|: length of |argv|.
// |argv|: see //system/ulib/runtests-utils/discover-and-run-tests.cpp,
// specifically the 'Usage()' function, for documentation.
// |default_test_dirs|: directories in which to look for tests if no test
// directory globs are specified.
// |stopwatch|: for timing how long all tests took to run.
// |syslog_file_name|: if an output directory is specified ("-o"), syslog ouput
// will be written to a file under that directory and this name.
//
// Returns EXIT_SUCCESS if all tests passed; else, returns EXIT_FAILURE.
int DiscoverAndRunTests(int argc, const char* const* argv,
const fbl::Vector<fbl::String>& default_test_dirs, Stopwatch* stopwatch,
const fbl::StringPiece syslog_file_name);
// Returns true iff |s| is a fuchsia-pkg URI.
bool IsFuchsiaPkgURI(const char* s);
} // namespace runtests
#endif // RUNTESTS_UTILS_RUNTESTS_UTILS_H_