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 
12 namespace {
13 
14 // The name of the file containing the syslog.
15 constexpr char kSyslogFileName[] = "syslog.txt";
16 
17 const 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 
36 class FuchsiaStopwatch final : public runtests::Stopwatch {
37 public:
FuchsiaStopwatch()38     FuchsiaStopwatch() { Start(); }
Start()39     void Start() override { start_time_ = Now(); }
DurationInMsecs()40     int64_t DurationInMsecs() override { return (Now() - start_time_).to_msecs(); }
41 
42 private:
Now() const43     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.
GetOutputDir(int argc,const char * const * argv)49 const 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 
main(int argc,char ** argv)62 int 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