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 <limits.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.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 = 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     size_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       std::string_view file(basename(buf));
114       return file != "gdb" && file != "gdbserver" && file != "gdbserver64" &&
115              file != "gdbserver32" && file != "lldb" && file != "lldb-server";
116     }
117     // If we can't figure out what our parent was just assume we are fine to isolate.
118   }
119   return true;
120 }
121 
122 }  // namespace gtest_extras
123 }  // namespace android
124 
125 // Tests that override this weak function can add default arguments.
126 extern "C" bool __attribute__((weak)) GetInitialArgs(const char***, size_t*);
127 
IsolateMain(int argc,char ** argv,char **)128 int IsolateMain(int argc, char** argv, char**) {
129   std::vector<const char*> args{argv[0]};
130 
131   bool print_help = false;
132   size_t gtest_color_index = 0;
133   for (int i = 1; i < argc; ++i) {
134     args.push_back(argv[i]);
135     if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
136       print_help = true;
137     } else if (strncmp(argv[i], "--gtest_color=", 14) == 0) {
138       gtest_color_index = args.size() - 1;
139     }
140   }
141 
142   if (print_help) {
143     std::vector<const char*> help_args{args[0], "--help"};
144     if (gtest_color_index != 0) {
145       // This is the only option that changes the way the help is printed.
146       help_args.push_back(args[gtest_color_index]);
147       ::testing::GTEST_FLAG(color) = args[gtest_color_index] + 14;
148     }
149     android::gtest_extras::PrintHelpInfo();
150     return android::gtest_extras::GtestRun(&help_args);
151   }
152 
153   if (!android::gtest_extras::RunInIsolationMode(args)) {
154     return android::gtest_extras::GtestRun(&args);
155   }
156 
157   const char** start_args;
158   size_t num_args;
159   if (GetInitialArgs != nullptr && GetInitialArgs(&start_args, &num_args)) {
160     std::vector<const char*> initial_args;
161     for (size_t i = 0; i < num_args; i++) {
162       initial_args.push_back(start_args[i]);
163     }
164     args.insert(args.begin() + 1, initial_args.begin(), initial_args.end());
165   }
166 
167   std::vector<char*> child_args;
168   android::gtest_extras::Options options;
169   if (!options.Process(args, &child_args)) {
170     return 1;
171   }
172 
173   // Add the --no_isolate option to force child processes not to rerun
174   // in isolation mode.
175   child_args.push_back(strdup("--no_isolate"));
176 
177   // Set the flag values.
178   ::testing::GTEST_FLAG(color) = options.color();
179   ::testing::GTEST_FLAG(print_time) = options.print_time();
180 
181   android::gtest_extras::Isolate isolate(options, child_args);
182   int return_val = isolate.Run();
183   for (auto child_arg : child_args) {
184     free(child_arg);
185   }
186   return return_val;
187 }
188