summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-07-15 00:08:06 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2021-07-15 00:08:06 +0000
commit6a73ec6b43d1bb4a8465b3b2019c19d00be55bf1 (patch)
tree5b82b63e08e6b34cb0895628cf81022e67a965f8
parent8e8f1e9c82c946997959642073317784627919a5 (diff)
parentc1bcf9b13e4f065ddf008fd21f959114888383de (diff)
downloadgtest_extras-6a73ec6b43d1bb4a8465b3b2019c19d00be55bf1.tar.gz
Change-Id: Ibe85a05d6e4069ed8c7002838f1c9d1f4e9ba489
-rw-r--r--Android.bp8
-rw-r--r--Isolate.cpp94
-rw-r--r--IsolateMain.cpp54
-rw-r--r--Log.h34
-rw-r--r--Options.cpp62
-rw-r--r--Test.cpp10
-rw-r--r--Test.h5
7 files changed, 196 insertions, 71 deletions
diff --git a/Android.bp b/Android.bp
index e339a4f..c728f22 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,6 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
cc_library_static {
name: "libgtest_isolated",
host_supported: true,
@@ -27,11 +31,7 @@ cc_library_static {
"Test.cpp",
],
- // NOTE: libbase is re-exported by including them below.
- // When Soong supports transitive static dependency includes, this
- // library can be removed.
whole_static_libs: [
- "libbase",
"libgtest",
],
diff --git a/Isolate.cpp b/Isolate.cpp
index 889b183..8f76f54 100644
--- a/Isolate.cpp
+++ b/Isolate.cpp
@@ -20,21 +20,21 @@
#include <poll.h>
#include <signal.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <atomic>
+#include <memory>
#include <string>
#include <tuple>
#include <vector>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
#include "Color.h"
#include "Isolate.h"
+#include "Log.h"
#include "NanoTime.h"
#include "Test.h"
@@ -50,22 +50,22 @@ static void SignalHandler(int sig) {
static void RegisterSignalHandler() {
auto ret = signal(SIGINT, SignalHandler);
if (ret == SIG_ERR) {
- PLOG(FATAL) << "Setting up SIGINT handler failed";
+ FATAL_PLOG("Setting up SIGINT handler failed");
}
ret = signal(SIGQUIT, SignalHandler);
if (ret == SIG_ERR) {
- PLOG(FATAL) << "Setting up SIGQUIT handler failed";
+ FATAL_PLOG("Setting up SIGQUIT handler failed");
}
}
static void UnregisterSignalHandler() {
auto ret = signal(SIGINT, SIG_DFL);
if (ret == SIG_ERR) {
- PLOG(FATAL) << "Disabling SIGINT handler failed";
+ FATAL_PLOG("Disabling SIGINT handler failed");
}
ret = signal(SIGQUIT, SIG_DFL);
if (ret == SIG_ERR) {
- PLOG(FATAL) << "Disabling SIGQUIT handler failed";
+ FATAL_PLOG("Disabling SIGQUIT handler failed");
}
}
@@ -81,6 +81,12 @@ static std::string PluralizeString(size_t value, const char* name, bool uppercas
return string;
}
+inline static bool StartsWithDisabled(const std::string& str) {
+ static constexpr char kDisabledStr[] = "DISABLED_";
+ static constexpr size_t kDisabledStrLen = sizeof(kDisabledStr) - 1;
+ return str.compare(0, kDisabledStrLen, kDisabledStr) == 0;
+}
+
void Isolate::EnumerateTests() {
// Only apply --gtest_filter if present. This is the only option that changes
// what tests are listed.
@@ -89,13 +95,14 @@ void Isolate::EnumerateTests() {
command += " --gtest_filter=" + options_.filter();
}
command += " --gtest_list_tests";
-#if defined(__APPLE__)
- FILE* fp = popen(command.c_str(), "r");
-#else
+#if defined(__BIONIC__)
+ // Only bionic is guaranteed to support the 'e' option.
FILE* fp = popen(command.c_str(), "re");
+#else
+ FILE* fp = popen(command.c_str(), "r");
#endif
if (fp == nullptr) {
- PLOG(FATAL) << "Unexpected failure from popen";
+ FATAL_PLOG("Unexpected failure from popen");
}
size_t total_shards = options_.total_shards();
@@ -122,7 +129,7 @@ void Isolate::EnumerateTests() {
suite_name.resize(suite_name.size() - 1);
}
- if (!options_.allow_disabled_tests() && android::base::StartsWith(suite_name, "DISABLED_")) {
+ if (!options_.allow_disabled_tests() && StartsWithDisabled(suite_name)) {
// This whole set of tests have been disabled, skip them all.
skip_until_next_suite = true;
} else {
@@ -139,7 +146,7 @@ void Isolate::EnumerateTests() {
if (test_name.back() == '\n') {
test_name.resize(test_name.size() - 1);
}
- if (options_.allow_disabled_tests() || !android::base::StartsWith(test_name, "DISABLED_")) {
+ if (options_.allow_disabled_tests() || !StartsWithDisabled(test_name)) {
if (!sharded || --test_count == 0) {
tests_.push_back(std::make_tuple(suite_name, test_name));
total_tests_++;
@@ -167,7 +174,7 @@ void Isolate::EnumerateTests() {
}
free(buffer);
if (pclose(fp) == -1) {
- PLOG(FATAL) << "Unexpected failure from pclose";
+ FATAL_PLOG("Unexpected failure from pclose");
}
}
@@ -178,7 +185,7 @@ int Isolate::ChildProcessFn(const std::tuple<std::string, std::string>& test) {
// Add the filter argument.
std::vector<char*> args(child_args_);
std::string filter("--gtest_filter=" + GetTestName(test));
- args.push_back(strdup(filter.c_str()));
+ args.push_back(filter.data());
int argc = args.size();
// Add the null terminator.
@@ -187,22 +194,45 @@ int Isolate::ChildProcessFn(const std::tuple<std::string, std::string>& test) {
return RUN_ALL_TESTS();
}
+static bool Pipe(int* read_fd, int* write_fd) {
+ int pipefd[2];
+
+#if defined(__linux__)
+ if (pipe2(pipefd, O_CLOEXEC) != 0) {
+ return false;
+ }
+#else // defined(__APPLE__)
+ if (pipe(pipefd) != 0) {
+ return false;
+ }
+ if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 || fcntl(pipefd[1], F_SETFD, FD_CLOEXEC)) {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return false;
+ }
+#endif
+
+ *read_fd = pipefd[0];
+ *write_fd = pipefd[1];
+ return true;
+}
+
void Isolate::LaunchTests() {
while (!running_indices_.empty() && cur_test_index_ < tests_.size()) {
- android::base::unique_fd read_fd, write_fd;
+ int read_fd, write_fd;
if (!Pipe(&read_fd, &write_fd)) {
- PLOG(FATAL) << "Unexpected failure from pipe";
+ FATAL_PLOG("Unexpected failure from pipe");
}
- if (fcntl(read_fd.get(), F_SETFL, O_NONBLOCK) == -1) {
- PLOG(FATAL) << "Unexpected failure from fcntl";
+ if (fcntl(read_fd, F_SETFL, O_NONBLOCK) == -1) {
+ FATAL_PLOG("Unexpected failure from fcntl");
}
pid_t pid = fork();
if (pid == -1) {
- PLOG(FATAL) << "Unexpected failure from fork";
+ FATAL_PLOG("Unexpected failure from fork");
}
if (pid == 0) {
- read_fd.reset();
+ close(read_fd);
close(STDOUT_FILENO);
close(STDERR_FILENO);
if (dup2(write_fd, STDOUT_FILENO) == -1) {
@@ -211,13 +241,14 @@ void Isolate::LaunchTests() {
if (dup2(write_fd, STDERR_FILENO) == -1) {
exit(1);
}
+ close(write_fd);
UnregisterSignalHandler();
exit(ChildProcessFn(tests_[cur_test_index_]));
}
size_t run_index = running_indices_.back();
running_indices_.pop_back();
- Test* test = new Test(tests_[cur_test_index_], cur_test_index_, run_index, read_fd.release());
+ Test* test = new Test(tests_[cur_test_index_], cur_test_index_, run_index, read_fd);
running_by_pid_.emplace(pid, test);
running_[run_index] = test;
running_by_test_index_[cur_test_index_] = test;
@@ -226,6 +257,7 @@ void Isolate::LaunchTests() {
pollfd->fd = test->fd();
pollfd->events = POLLIN;
cur_test_index_++;
+ close(write_fd);
}
}
@@ -254,9 +286,12 @@ size_t Isolate::CheckTestsFinished() {
int status;
pid_t pid;
while ((pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG))) > 0) {
+ if (pid == -1) {
+ FATAL_PLOG("Unexpected failure from waitpid");
+ }
auto entry = running_by_pid_.find(pid);
if (entry == running_by_pid_.end()) {
- LOG(FATAL) << "Pid " << pid << " was not spawned by the isolation framework.";
+ FATAL_LOG("Found process not spawned by the isolation framework");
}
std::unique_ptr<Test>& test_ptr = entry->second;
@@ -326,7 +361,7 @@ size_t Isolate::CheckTestsFinished() {
total_skipped_tests_++;
break;
case TEST_NONE:
- LOG(FATAL) << "Test result is TEST_NONE, this should not be possible.";
+ FATAL_LOG("Test result is TEST_NONE, this should not be possible");
}
finished_tests++;
size_t test_index = test->test_index();
@@ -348,7 +383,7 @@ size_t Isolate::CheckTestsFinished() {
// The only valid error case is if ECHILD is returned because there are
// no more processes left running.
if (pid == -1 && errno != ECHILD) {
- PLOG(FATAL) << "Unexpected failure from waitpid";
+ FATAL_PLOG("Unexpected failure from waitpid");
}
return finished_tests;
}
@@ -618,7 +653,10 @@ void TestResultPrinter::OnTestPartResult(const ::testing::TestPartResult& result
}
if (result.type() == ::testing::TestPartResult::kSkip) {
- printf("%s:(%d) Skipped%s\n", result.file_name(), result.line_number(), result.message());
+ printf("%s:(%d) Skipped\n", result.file_name(), result.line_number());
+ if (*result.message()) {
+ printf("%s\n", result.message());
+ }
} else {
// Print failure message from the assertion (e.g. expected this and got that).
printf("%s:(%d) Failure in test %s.%s\n%s\n", result.file_name(), result.line_number(),
@@ -640,7 +678,7 @@ void Isolate::WriteXmlResults(uint64_t elapsed_time_ns, time_t start_time) {
const tm* time_struct = localtime(&start_time);
if (time_struct == nullptr) {
- PLOG(FATAL) << "Unexpected failure from localtime";
+ FATAL_PLOG("Unexpected failure from localtime");
}
char timestamp[40];
snprintf(timestamp, sizeof(timestamp), "%4d-%02d-%02dT%02d:%02d:%02d",
@@ -739,7 +777,7 @@ int Isolate::Run() {
EnumerateTests();
// Stop default result printer to avoid environment setup/teardown information for each test.
- ::testing::UnitTest::GetInstance()->listeners().Release(
+ delete ::testing::UnitTest::GetInstance()->listeners().Release(
::testing::UnitTest::GetInstance()->listeners().default_result_printer());
::testing::UnitTest::GetInstance()->listeners().Append(new TestResultPrinter);
RegisterSignalHandler();
diff --git a/IsolateMain.cpp b/IsolateMain.cpp
index 30b871b..5b34ef5 100644
--- a/IsolateMain.cpp
+++ b/IsolateMain.cpp
@@ -15,14 +15,16 @@
*/
#include <errno.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <cstring>
+#include <string_view>
#include <vector>
-#include <android-base/file.h>
#include <gtest/gtest.h>
#include <gtest_extras/IsolateMain.h>
@@ -44,7 +46,15 @@ static void PrintHelpInfo() {
" 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");
+ 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 ");
@@ -59,10 +69,8 @@ static void PrintHelpInfo() {
printf(
" will be called slow.\n"
" Only valid in isolation mode. Default slow threshold is 2000 ms.\n");
- ColoredPrintf(COLOR_GREEN, "-j");
printf(
- ".\n"
- "In isolation mode, you can send SIGQUIT to the parent process to show the\n"
+ "\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");
@@ -77,13 +85,37 @@ static int GtestRun(std::vector<const char*>* args) {
static bool RunInIsolationMode(std::vector<const char*>& 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;
}
@@ -91,9 +123,7 @@ static bool RunInIsolationMode(std::vector<const char*>& args) {
} // namespace android
// Tests that override this weak function can add default arguments.
-extern "C" bool __attribute__((weak)) GetInitialArgs(const char***, size_t*) {
- return false;
-}
+extern "C" bool __attribute__((weak)) GetInitialArgs(const char***, size_t*);
int IsolateMain(int argc, char** argv, char**) {
std::vector<const char*> args{argv[0]};
@@ -126,7 +156,7 @@ int IsolateMain(int argc, char** argv, char**) {
const char** start_args;
size_t num_args;
- if (GetInitialArgs(&start_args, &num_args)) {
+ if (GetInitialArgs != nullptr && GetInitialArgs(&start_args, &num_args)) {
std::vector<const char*> initial_args;
for (size_t i = 0; i < num_args; i++) {
initial_args.push_back(start_args[i]);
@@ -149,5 +179,9 @@ int IsolateMain(int argc, char** argv, char**) {
::testing::GTEST_FLAG(print_time) = options.print_time();
android::gtest_extras::Isolate isolate(options, child_args);
- return isolate.Run();
+ int return_val = isolate.Run();
+ for (auto child_arg : child_args) {
+ free(child_arg);
+ }
+ return return_val;
}
diff --git a/Log.h b/Log.h
new file mode 100644
index 0000000..d424c51
--- /dev/null
+++ b/Log.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <android/log.h>
+
+#define GTEST_EXTRAS_TAG "gtest_extras"
+
+#define FATAL_PLOG(msg) \
+ __android_log_print(ANDROID_LOG_FATAL, GTEST_EXTRAS_TAG, "%s:%d] " msg ": %s", __FILE__, \
+ __LINE__, strerror(errno)); \
+ abort();
+
+#define FATAL_LOG(msg) \
+ __android_log_print(ANDROID_LOG_FATAL, GTEST_EXTRAS_TAG, "%s:%d] " msg, __FILE__, __LINE__); \
+ abort();
diff --git a/Options.cpp b/Options.cpp
index bcc4b06..96842a1 100644
--- a/Options.cpp
+++ b/Options.cpp
@@ -15,20 +15,22 @@
*/
#include <errno.h>
+#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#include <cctype>
+#include <charconv>
+#include <regex>
#include <string>
#include <unordered_map>
#include <vector>
-#include <android-base/file.h>
-#include <android-base/parseint.h>
-#include <android-base/strings.h>
#include <gtest/gtest.h>
#include "Options.h"
@@ -90,20 +92,16 @@ static void PrintError(const std::string& arg, std::string msg, bool from_env) {
}
template <typename IntType>
-static bool GetNumeric(const char* arg, const char* value, IntType* numeric_value, bool from_env) {
- bool result = false;
- if constexpr (std::is_unsigned<IntType>::value) {
- result = android::base::ParseUint<IntType>(value, numeric_value);
- } else {
- result = android::base::ParseInt<IntType>(value, numeric_value);
- }
- if (!result) {
- if (errno == ERANGE) {
- PrintError(arg, std::string("value overflows (") + value + ")", from_env);
- } else {
- PrintError(arg, std::string("value is not formatted as a numeric value (") + value + ")",
- from_env);
- }
+static bool GetNumeric(const std::string& arg, const std::string& value, IntType* numeric_value,
+ bool from_env) {
+ auto result = std::from_chars(value.c_str(), value.c_str() + value.size(), *numeric_value, 10);
+ if (result.ec == std::errc::result_out_of_range) {
+ PrintError(arg, std::string("value overflows (") + value + ")", from_env);
+ return false;
+ } else if (result.ec == std::errc::invalid_argument || result.ptr == nullptr ||
+ *result.ptr != '\0') {
+ PrintError(arg, std::string("value is not formatted as a numeric value (") + value + ")",
+ from_env);
return false;
}
return true;
@@ -118,7 +116,7 @@ bool Options::SetPrintTime(const std::string&, const std::string& value, bool) {
bool Options::SetNumeric(const std::string& arg, const std::string& value, bool from_env) {
uint64_t* numeric = &numerics_.find(arg)->second;
- if (!GetNumeric<uint64_t>(arg.c_str(), value.c_str(), numeric, from_env)) {
+ if (!GetNumeric<uint64_t>(arg, value, numeric, from_env)) {
return false;
}
if (*numeric == 0) {
@@ -134,7 +132,7 @@ bool Options::SetNumericEnvOnly(const std::string& arg, const std::string& value
return false;
}
uint64_t* numeric = &numerics_.find(arg)->second;
- if (!GetNumeric<uint64_t>(arg.c_str(), value.c_str(), numeric, from_env)) {
+ if (!GetNumeric<uint64_t>(arg, value, numeric, from_env)) {
return false;
}
return true;
@@ -146,7 +144,7 @@ bool Options::SetBool(const std::string& arg, const std::string&, bool) {
}
bool Options::SetIterations(const std::string& arg, const std::string& value, bool from_env) {
- if (!GetNumeric<int>(arg.c_str(), value.c_str(), &num_iterations_, from_env)) {
+ if (!GetNumeric<int>(arg, value, &num_iterations_, from_env)) {
return false;
}
return true;
@@ -214,13 +212,29 @@ bool Options::HandleArg(const std::string& arg, const std::string& value, const
return true;
}
+static bool ReadFileToString(const std::string& file, std::string* contents) {
+ int fd = TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC));
+ if (fd == -1) {
+ return false;
+ }
+ char buf[4096];
+ ssize_t bytes_read;
+ while ((bytes_read = TEMP_FAILURE_RETRY(read(fd, &buf, sizeof(buf)))) > 0) {
+ contents->append(buf, bytes_read);
+ }
+ close(fd);
+ return true;
+}
+
bool Options::ProcessFlagfile(const std::string& file, std::vector<char*>* child_args) {
std::string contents;
- if (!android::base::ReadFileToString(file, &contents)) {
+ if (!ReadFileToString(file, &contents)) {
printf("Unable to read data from file %s\n", file.c_str());
return false;
}
+ std::regex flag_regex("^\\s*(\\S.*\\S)\\s*$");
+ std::regex empty_line_regex("^\\s*$");
size_t idx = 0;
while (idx < contents.size()) {
size_t newline_idx = contents.find('\n', idx);
@@ -229,8 +243,10 @@ bool Options::ProcessFlagfile(const std::string& file, std::vector<char*>* child
}
std::string line(&contents[idx], newline_idx - idx);
idx = newline_idx + 1;
- line = android::base::Trim(line);
- if (line.empty()) {
+ std::smatch match;
+ if (std::regex_match(line, match, flag_regex)) {
+ line = match[1];
+ } else if (std::regex_match(line, match, empty_line_regex)) {
// Skip lines with only whitespace.
continue;
}
diff --git a/Test.cpp b/Test.cpp
index 327facd..23d139c 100644
--- a/Test.cpp
+++ b/Test.cpp
@@ -23,10 +23,11 @@
#include <tuple>
#include <vector>
-#include <android-base/logging.h>
+#include <android/log.h>
#include <gtest/gtest.h>
#include "Color.h"
+#include "Log.h"
#include "NanoTime.h"
#include "Test.h"
@@ -49,7 +50,10 @@ void Test::Stop() {
}
void Test::CloseFd() {
- fd_.reset();
+ if (fd_ != -1) {
+ close(fd_);
+ fd_ = -1;
+ }
}
void Test::Print() {
@@ -85,7 +89,7 @@ bool Test::Read() {
// Reading would block. Since this is not an error keep going.
return true;
}
- PLOG(FATAL) << "Unexpected failure from read";
+ FATAL_PLOG("Unexpected failure from read");
return false;
}
diff --git a/Test.h b/Test.h
index b4a1182..dd54dc6 100644
--- a/Test.h
+++ b/Test.h
@@ -20,8 +20,6 @@
#include <string>
#include <tuple>
-#include <android-base/unique_fd.h>
-
namespace android {
namespace gtest_extras {
@@ -38,6 +36,7 @@ enum TestResult : uint8_t {
class Test {
public:
Test(std::tuple<std::string, std::string>& test, size_t test_index, size_t run_index, int fd);
+ ~Test() { CloseFd(); }
void Print();
@@ -87,7 +86,7 @@ class Test {
std::string name_;
size_t test_index_; // Index into test list.
size_t run_index_; // Index into running list.
- android::base::unique_fd fd_;
+ int fd_ = -1;
uint64_t start_ns_;
uint64_t end_ns_ = 0;