1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <errno.h>
18 #include <libgen.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23
24 #include <cstring>
25 #include <string_view>
26 #include <vector>
27
28 #include <gtest/gtest.h>
29 #include <gtest_extras/IsolateMain.h>
30
31 #include "Color.h"
32 #include "Isolate.h"
33
34 namespace android {
35 namespace gtest_extras {
36
PrintHelpInfo()37 static void PrintHelpInfo() {
38 printf("Unit Test Options:\n");
39 ColoredPrintf(COLOR_GREEN, " -j ");
40 ColoredPrintf(COLOR_YELLOW, "[JOB_COUNT]");
41 printf(" or ");
42 ColoredPrintf(COLOR_GREEN, "-j");
43 ColoredPrintf(COLOR_YELLOW, "[JOB_COUNT]\n");
44 printf(
45 " Run up to JOB_COUNT tests in parallel.\n"
46 " Use isolation mode, Run each test in a separate process.\n"
47 " If JOB_COUNT is not given, it is set to the count of available processors.\n");
48 ColoredPrintf(COLOR_GREEN, " --no_isolate\n");
49 printf(
50 " Don't use isolation mode, run all tests in a single process.\n"
51 " If the test seems to be running in a debugger (based on the parent's name) this will\n"
52 " be automatically set. If this behavior is not desired use the '--force_isolate' flag\n"
53 " below.\n");
54 ColoredPrintf(COLOR_GREEN, " --force_isolate\n");
55 printf(
56 " Force the use of isolation mode, even if it looks like we are running in a\n"
57 " debugger.\n");
58 ColoredPrintf(COLOR_GREEN, " --deadline_threshold_ms=");
59 ColoredPrintf(COLOR_YELLOW, "[TIME_IN_MS]\n");
60 printf(" Run each test in no longer than ");
61 ColoredPrintf(COLOR_YELLOW, "[TIME_IN_MS]");
62 printf(
63 " time.\n"
64 " Only valid in isolation mode. Default deadline is 90000 ms.\n");
65 ColoredPrintf(COLOR_GREEN, " --slow_threshold_ms=");
66 ColoredPrintf(COLOR_YELLOW, "[TIME_IN_MS]\n");
67 printf(" Test running longer than ");
68 ColoredPrintf(COLOR_YELLOW, "[TIME_IN_MS]");
69 printf(
70 " will be called slow.\n"
71 " Only valid in isolation mode. Default slow threshold is 2000 ms.\n");
72 printf(
73 "\nIn isolation mode, you can send SIGQUIT to the parent process to show the\n"
74 "current running tests, or send SIGINT to the parent process to stop all\n"
75 "running tests.\n"
76 "\n");
77 }
78
GtestRun(std::vector<const char * > * args)79 static int GtestRun(std::vector<const char*>* args) {
80 int argc = static_cast<int>(args->size());
81 args->push_back(nullptr);
82 ::testing::InitGoogleTest(&argc, const_cast<char**>(args->data()));
83 return RUN_ALL_TESTS();
84 }
85
RunInIsolationMode(std::vector<const char * > & args)86 static bool RunInIsolationMode(std::vector<const char*>& args) {
87 // Parse arguments that can't be used in isolation mode.
88 bool isolation_forced = false;
89 for (size_t i = 1; i < args.size(); ++i) {
90 if (strcmp(args[i], "--no_isolate") == 0) {
91 return false;
92 } else if (strcmp(args[i], "--force_isolate") == 0) {
93 // We want to make sure we prioritize --no_isolate and --gtest_list_tests.
94 isolation_forced = true;
95 } else if (strcmp(args[i], "--gtest_list_tests") == 0) {
96 return false;
97 }
98 }
99 if (!isolation_forced) {
100 // Check if we are running gdb/gdbserver/lldb/lldb-server. No need to be sneaky we are assuming
101 // no one is hiding.
102 pid_t ppid = getppid();
103 std::string exe_path = std::string("/proc/") + std::to_string(ppid) + "/exe";
104 char buf[PATH_MAX + 1];
105 ssize_t len;
106 // NB We can't use things like android::base::* or std::filesystem::* due to linking
107 // issues.
108 // Since PATH_MAX is the longest a symlink can be in posix we don't need to
109 // deal with truncation. Anyway this isn't critical for correctness and is
110 // just a QOL thing so it's fine if we are wrong.
111 if ((len = TEMP_FAILURE_RETRY(readlink(exe_path.c_str(), buf, sizeof(buf) - 1))) > 0) {
112 buf[len] = '\0';
113 static std::set<std::string_view> debuggers{"gdb",
114 "gdbserver",
115 "gdbserver64",
116 "lldb",
117 "lldb-server",
118 "arm-lldb-server",
119 "arm64-lldb-server",
120 "riscv64-lldb-server",
121 "x86-lldb-server",
122 "x86_64-lldb-server"};
123 return !debuggers.contains(basename(buf));
124 }
125 // If we can't figure out what our parent was just assume we are fine to isolate.
126 }
127 return true;
128 }
129
130 } // namespace gtest_extras
131 } // namespace android
132
133 // Tests that override this weak function can add default arguments.
134 extern "C" bool __attribute__((weak)) GetInitialArgs(const char***, size_t*);
135
IsolateMain(int argc,char ** argv,char **)136 int IsolateMain(int argc, char** argv, char**) {
137 std::vector<const char*> args{argv[0]};
138
139 bool print_help = false;
140 size_t gtest_color_index = 0;
141 for (int i = 1; i < argc; ++i) {
142 args.push_back(argv[i]);
143 if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
144 print_help = true;
145 } else if (strncmp(argv[i], "--gtest_color=", 14) == 0) {
146 gtest_color_index = args.size() - 1;
147 }
148 }
149
150 if (print_help) {
151 std::vector<const char*> help_args{args[0], "--help"};
152 if (gtest_color_index != 0) {
153 // This is the only option that changes the way the help is printed.
154 help_args.push_back(args[gtest_color_index]);
155 ::testing::GTEST_FLAG(color) = args[gtest_color_index] + 14;
156 }
157 android::gtest_extras::PrintHelpInfo();
158 return android::gtest_extras::GtestRun(&help_args);
159 }
160
161 if (!android::gtest_extras::RunInIsolationMode(args)) {
162 return android::gtest_extras::GtestRun(&args);
163 }
164
165 const char** start_args;
166 size_t num_args;
167 if (GetInitialArgs != nullptr && GetInitialArgs(&start_args, &num_args)) {
168 std::vector<const char*> initial_args;
169 for (size_t i = 0; i < num_args; i++) {
170 initial_args.push_back(start_args[i]);
171 }
172 args.insert(args.begin() + 1, initial_args.begin(), initial_args.end());
173 }
174
175 std::vector<char*> child_args;
176 android::gtest_extras::Options options;
177 int return_val = 1;
178 if (options.Process(args, &child_args)) {
179 // Add the --no_isolate option to force child processes not to rerun
180 // in isolation mode.
181 child_args.push_back(strdup("--no_isolate"));
182
183 // Set the flag values.
184 ::testing::GTEST_FLAG(color) = options.color();
185 ::testing::GTEST_FLAG(print_time) = options.print_time();
186
187 android::gtest_extras::Isolate isolate(options, child_args);
188 return_val = isolate.Run();
189 } else {
190 printf("%s\n", options.error().c_str());
191 }
192
193 for (auto child_arg : child_args) {
194 free(child_arg);
195 }
196 return return_val;
197 }
198