1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <fbl/string.h>
6#include <fbl/vector.h>
7#include <lib/zx/time.h>
8#include <runtests-utils/fuchsia-run-test.h>
9#include <runtests-utils/log-exporter.h>
10#include <runtests-utils/runtests-utils.h>
11
12namespace {
13
14// The name of the file containing the syslog.
15constexpr char kSyslogFileName[] = "syslog.txt";
16
17const char* kDefaultTestDirs[] = {
18    // zircon builds place everything in ramdisks so tests are located in /boot
19    "/boot/test/core",
20    "/boot/test/libc",
21    "/boot/test/ddk",
22    "/boot/test/sys",
23    "/boot/test/fs",
24    // /pkgfs is where test binaries should be found in garnet and above.
25    "/pkgfs/packages/*/*/test",
26    // Moreover, for the higher layers, there are still tests using the deprecated /system image.
27    // Soon they will all be moved under /pkgfs.
28    "/system/test",
29    "/system/test/core",
30    "/system/test/libc",
31    "/system/test/ddk",
32    "/system/test/sys",
33    "/system/test/fs",
34};
35
36class FuchsiaStopwatch final : public runtests::Stopwatch {
37public:
38    FuchsiaStopwatch() { Start(); }
39    void Start() override { start_time_ = Now(); }
40    int64_t DurationInMsecs() override { return (Now() - start_time_).to_msecs(); }
41
42private:
43    zx::time Now() const { return zx::clock::get_monotonic(); }
44
45    zx::time start_time_;
46};
47
48// Parse |argv| for an output directory argument.
49const char* GetOutputDir(int argc, const char* const* argv) {
50    int i = 1;
51    while (i < argc - 1 && strcmp(argv[i], "-o") != 0) {
52        ++i;
53    }
54    if (i >= argc - 1) {
55        return nullptr;
56    }
57    return argv[i + 1];
58}
59
60} // namespace
61
62int main(int argc, char** argv) {
63    const char* output_dir = GetOutputDir(argc, argv);
64
65    // Start Log Listener.
66    fbl::unique_ptr<runtests::LogExporter> log_exporter_ptr;
67    if (output_dir != nullptr) {
68        int error = runtests::MkDirAll(output_dir);
69        if (error) {
70            printf("Error: Could not create output directory: %s, %s\n", output_dir,
71                   strerror(error));
72            return -1;
73        }
74
75        runtests::ExporterLaunchError exporter_error;
76        log_exporter_ptr = runtests::LaunchLogExporter(
77            runtests::JoinPath(output_dir, kSyslogFileName), &exporter_error);
78        // Don't fail if logger service is not available because it is only
79        // available in garnet layer and above.
80        if (!log_exporter_ptr && exporter_error != runtests::CONNECT_TO_LOGGER_SERVICE) {
81            printf("Error: Failed to launch log listener: %d", exporter_error);
82            return -1;
83        }
84    }
85
86    fbl::Vector<fbl::String> default_test_dirs;
87    const int num_default_test_dirs = sizeof(kDefaultTestDirs) / sizeof(char*);
88    for (int i = 0; i < num_default_test_dirs; ++i) {
89        default_test_dirs.push_back(kDefaultTestDirs[i]);
90    }
91
92    FuchsiaStopwatch stopwatch;
93    return runtests::DiscoverAndRunTests(&runtests::FuchsiaRunTest, argc, argv, default_test_dirs,
94                                         &stopwatch, kSyslogFileName);
95}
96