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