/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include "Color.h" #include "Isolate.h" namespace android { namespace gtest_extras { static void PrintHelpInfo() { printf("Unit Test Options:\n"); ColoredPrintf(COLOR_GREEN, " -j "); ColoredPrintf(COLOR_YELLOW, "[JOB_COUNT]"); printf(" or "); ColoredPrintf(COLOR_GREEN, "-j"); ColoredPrintf(COLOR_YELLOW, "[JOB_COUNT]\n"); printf( " Run up to JOB_COUNT tests in parallel.\n" " Use isolation mode, Run each test in a separate process.\n" " If JOB_COUNT is not given, it is set to the count of available processors.\n"); ColoredPrintf(COLOR_GREEN, " --no_isolate\n"); printf( " Don't use isolation mode, run all tests in a single process.\n" " If the test seems to be running in a debugger (based on the parent's name) this will\n" " be automatically set. If this behavior is not desired use the '--force_isolate' flag\n" " below.\n"); ColoredPrintf(COLOR_GREEN, " --force_isolate\n"); printf( " Force the use of isolation mode, even if it looks like we are running in a\n" " debugger.\n"); ColoredPrintf(COLOR_GREEN, " --deadline_threshold_ms="); ColoredPrintf(COLOR_YELLOW, "[TIME_IN_MS]\n"); printf(" Run each test in no longer than "); ColoredPrintf(COLOR_YELLOW, "[TIME_IN_MS]"); printf( " time.\n" " Only valid in isolation mode. Default deadline is 90000 ms.\n"); ColoredPrintf(COLOR_GREEN, " --slow_threshold_ms="); ColoredPrintf(COLOR_YELLOW, "[TIME_IN_MS]\n"); printf(" Test running longer than "); ColoredPrintf(COLOR_YELLOW, "[TIME_IN_MS]"); printf( " will be called slow.\n" " Only valid in isolation mode. Default slow threshold is 2000 ms.\n"); printf( "\nIn isolation mode, you can send SIGQUIT to the parent process to show the\n" "current running tests, or send SIGINT to the parent process to stop all\n" "running tests.\n" "\n"); } static int GtestRun(std::vector* args) { int argc = args->size(); args->push_back(nullptr); ::testing::InitGoogleTest(&argc, const_cast(args->data())); return RUN_ALL_TESTS(); } static bool RunInIsolationMode(std::vector& args) { // Parse arguments that can't be used in isolation mode. bool isolation_forced = false; for (size_t i = 1; i < args.size(); ++i) { if (strcmp(args[i], "--no_isolate") == 0) { return false; } else if (strcmp(args[i], "--force_isolate") == 0) { // We want to make sure we prioritize --no_isolate and --gtest_list_tests. isolation_forced = true; } else if (strcmp(args[i], "--gtest_list_tests") == 0) { return false; } } if (!isolation_forced) { // Check if we are running gdb/gdbserver/lldb/lldb-server. No need to be sneaky we are assuming // no one is hiding. pid_t ppid = getppid(); std::string exe_path = std::string("/proc/") + std::to_string(ppid) + "/exe"; char buf[PATH_MAX + 1]; size_t len; // NB We can't use things like android::base::* or std::filesystem::* due to linking // issues. // Since PATH_MAX is the longest a symlink can be in posix we don't need to // deal with truncation. Anyway this isn't critical for correctness and is // just a QOL thing so it's fine if we are wrong. if ((len = TEMP_FAILURE_RETRY(readlink(exe_path.c_str(), buf, sizeof(buf) - 1))) > 0) { buf[len] = '\0'; std::string_view file(basename(buf)); return file != "gdb" && file != "gdbserver" && file != "gdbserver64" && file != "gdbserver32" && file != "lldb" && file != "lldb-server"; } // If we can't figure out what our parent was just assume we are fine to isolate. } return true; } } // namespace gtest_extras } // namespace android // Tests that override this weak function can add default arguments. extern "C" bool __attribute__((weak)) GetInitialArgs(const char***, size_t*); int IsolateMain(int argc, char** argv, char**) { std::vector args{argv[0]}; bool print_help = false; size_t gtest_color_index = 0; for (int i = 1; i < argc; ++i) { args.push_back(argv[i]); if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) { print_help = true; } else if (strncmp(argv[i], "--gtest_color=", 14) == 0) { gtest_color_index = args.size() - 1; } } if (print_help) { std::vector help_args{args[0], "--help"}; if (gtest_color_index != 0) { // This is the only option that changes the way the help is printed. help_args.push_back(args[gtest_color_index]); ::testing::GTEST_FLAG(color) = args[gtest_color_index] + 14; } android::gtest_extras::PrintHelpInfo(); return android::gtest_extras::GtestRun(&help_args); } if (!android::gtest_extras::RunInIsolationMode(args)) { return android::gtest_extras::GtestRun(&args); } const char** start_args; size_t num_args; if (GetInitialArgs != nullptr && GetInitialArgs(&start_args, &num_args)) { std::vector initial_args; for (size_t i = 0; i < num_args; i++) { initial_args.push_back(start_args[i]); } args.insert(args.begin() + 1, initial_args.begin(), initial_args.end()); } std::vector child_args; android::gtest_extras::Options options; if (!options.Process(args, &child_args)) { return 1; } // Add the --no_isolate option to force child processes not to rerun // in isolation mode. child_args.push_back(strdup("--no_isolate")); // Set the flag values. ::testing::GTEST_FLAG(color) = options.color(); ::testing::GTEST_FLAG(print_time) = options.print_time(); android::gtest_extras::Isolate isolate(options, child_args); int return_val = isolate.Run(); for (auto child_arg : child_args) { free(child_arg); } return return_val; }