blob: 689c3ce6f51cc0c9572b9d16b3da60f38efe4de7 [file] [log] [blame]
Christopher Ferris1a993562018-08-21 12:43:50 -07001/*
2 * Copyright (C) 2017 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 <fcntl.h>
19#include <inttypes.h>
20#include <poll.h>
21#include <signal.h>
22#include <stdio.h>
Christopher Ferris4ba40d82020-05-11 13:31:11 -070023#include <stdlib.h>
Christopher Ferris1a993562018-08-21 12:43:50 -070024#include <string.h>
25#include <unistd.h>
26
27#include <atomic>
Christopher Ferris4ba40d82020-05-11 13:31:11 -070028#include <memory>
Christopher Ferris1a993562018-08-21 12:43:50 -070029#include <string>
30#include <tuple>
31#include <vector>
32
Christopher Ferris1a993562018-08-21 12:43:50 -070033#include <gtest/gtest.h>
34
35#include "Color.h"
36#include "Isolate.h"
Christopher Ferris4ba40d82020-05-11 13:31:11 -070037#include "Log.h"
Christopher Ferris1a993562018-08-21 12:43:50 -070038#include "NanoTime.h"
39#include "Test.h"
40
41namespace android {
42namespace gtest_extras {
43
44static std::atomic_int g_signal;
45
46static void SignalHandler(int sig) {
47 g_signal = sig;
48}
49
50static void RegisterSignalHandler() {
Christopher Ferris23a3db02018-09-07 07:39:18 -070051 auto ret = signal(SIGINT, SignalHandler);
Christopher Ferris1a993562018-08-21 12:43:50 -070052 if (ret == SIG_ERR) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -070053 FATAL_PLOG("Setting up SIGINT handler failed");
Christopher Ferris1a993562018-08-21 12:43:50 -070054 }
55 ret = signal(SIGQUIT, SignalHandler);
56 if (ret == SIG_ERR) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -070057 FATAL_PLOG("Setting up SIGQUIT handler failed");
Christopher Ferris1a993562018-08-21 12:43:50 -070058 }
59}
60
61static void UnregisterSignalHandler() {
Christopher Ferris23a3db02018-09-07 07:39:18 -070062 auto ret = signal(SIGINT, SIG_DFL);
Christopher Ferris1a993562018-08-21 12:43:50 -070063 if (ret == SIG_ERR) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -070064 FATAL_PLOG("Disabling SIGINT handler failed");
Christopher Ferris1a993562018-08-21 12:43:50 -070065 }
66 ret = signal(SIGQUIT, SIG_DFL);
67 if (ret == SIG_ERR) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -070068 FATAL_PLOG("Disabling SIGQUIT handler failed");
Christopher Ferris1a993562018-08-21 12:43:50 -070069 }
70}
71
72static std::string PluralizeString(size_t value, const char* name, bool uppercase = false) {
73 std::string string(std::to_string(value) + name);
74 if (value != 1) {
75 if (uppercase) {
76 string += 'S';
77 } else {
78 string += 's';
79 }
80 }
81 return string;
82}
83
Christopher Ferris4ba40d82020-05-11 13:31:11 -070084inline static bool StartsWithDisabled(const std::string& str) {
85 static constexpr char kDisabledStr[] = "DISABLED_";
86 static constexpr size_t kDisabledStrLen = sizeof(kDisabledStr) - 1;
87 return str.compare(0, kDisabledStrLen, kDisabledStr) == 0;
88}
89
Christopher Ferris1a993562018-08-21 12:43:50 -070090void Isolate::EnumerateTests() {
91 // Only apply --gtest_filter if present. This is the only option that changes
92 // what tests are listed.
93 std::string command(child_args_[0]);
94 if (!options_.filter().empty()) {
95 command += " --gtest_filter=" + options_.filter();
96 }
97 command += " --gtest_list_tests";
Christopher Ferris4ba40d82020-05-11 13:31:11 -070098#if defined(__BIONIC__)
99 // Only bionic is guaranteed to support the 'e' option.
Christopher Ferris1a993562018-08-21 12:43:50 -0700100 FILE* fp = popen(command.c_str(), "re");
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700101#else
102 FILE* fp = popen(command.c_str(), "r");
Christopher Ferris23a3db02018-09-07 07:39:18 -0700103#endif
Christopher Ferris1a993562018-08-21 12:43:50 -0700104 if (fp == nullptr) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700105 FATAL_PLOG("Unexpected failure from popen");
Christopher Ferris1a993562018-08-21 12:43:50 -0700106 }
107
Christopher Ferrisdb00a3a2021-09-20 16:09:18 -0700108 uint64_t total_shards = options_.total_shards();
Christopher Ferris3215ef12019-03-12 19:10:35 -0700109 bool sharded = total_shards > 1;
Christopher Ferrisdb00a3a2021-09-20 16:09:18 -0700110 uint64_t test_count = 0;
Christopher Ferris3215ef12019-03-12 19:10:35 -0700111 if (sharded) {
112 test_count = options_.shard_index() + 1;
113 }
114
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700115 bool skip_until_next_suite = false;
116 std::string suite_name;
Christopher Ferris1a993562018-08-21 12:43:50 -0700117 char* buffer = nullptr;
118 size_t buffer_len = 0;
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700119 bool new_suite = false;
Christopher Ferris1a993562018-08-21 12:43:50 -0700120 while (getline(&buffer, &buffer_len, fp) > 0) {
121 if (buffer[0] != ' ') {
122 // This is the case name.
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700123 suite_name = buffer;
124 auto space_index = suite_name.find(' ');
Christopher Ferris1a993562018-08-21 12:43:50 -0700125 if (space_index != std::string::npos) {
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700126 suite_name.erase(space_index);
Christopher Ferris1a993562018-08-21 12:43:50 -0700127 }
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700128 if (suite_name.back() == '\n') {
129 suite_name.resize(suite_name.size() - 1);
Christopher Ferris1a993562018-08-21 12:43:50 -0700130 }
131
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700132 if (!options_.allow_disabled_tests() && StartsWithDisabled(suite_name)) {
Christopher Ferris1a993562018-08-21 12:43:50 -0700133 // This whole set of tests have been disabled, skip them all.
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700134 skip_until_next_suite = true;
Christopher Ferris1a993562018-08-21 12:43:50 -0700135 } else {
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700136 new_suite = true;
137 skip_until_next_suite = false;
Christopher Ferris1a993562018-08-21 12:43:50 -0700138 }
139 } else if (buffer[0] == ' ' && buffer[1] == ' ') {
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700140 if (!skip_until_next_suite) {
Christopher Ferris1a993562018-08-21 12:43:50 -0700141 std::string test_name = &buffer[2];
142 auto space_index = test_name.find(' ');
143 if (space_index != std::string::npos) {
144 test_name.erase(space_index);
145 }
146 if (test_name.back() == '\n') {
147 test_name.resize(test_name.size() - 1);
148 }
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700149 if (options_.allow_disabled_tests() || !StartsWithDisabled(test_name)) {
Christopher Ferris3215ef12019-03-12 19:10:35 -0700150 if (!sharded || --test_count == 0) {
151 tests_.push_back(std::make_tuple(suite_name, test_name));
152 total_tests_++;
153 if (new_suite) {
154 // Only increment the number of suites when we find at least one test
155 // for the suites.
156 total_suites_++;
157 new_suite = false;
158 }
159 if (sharded) {
160 test_count = total_shards;
161 }
Christopher Ferris1a993562018-08-21 12:43:50 -0700162 }
163 } else {
164 total_disable_tests_++;
165 }
166 } else {
167 total_disable_tests_++;
168 }
169 } else {
170 printf("Unexpected output from test listing.\nCommand:\n%s\nLine:\n%s\n", command.c_str(),
171 buffer);
172 exit(1);
173 }
174 }
175 free(buffer);
176 if (pclose(fp) == -1) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700177 FATAL_PLOG("Unexpected failure from pclose");
Christopher Ferris1a993562018-08-21 12:43:50 -0700178 }
179}
180
181int Isolate::ChildProcessFn(const std::tuple<std::string, std::string>& test) {
182 // Make sure the filter is only coming from our command-line option.
183 unsetenv("GTEST_FILTER");
184
185 // Add the filter argument.
Christopher Ferris2b6124f2019-09-19 23:06:41 -0700186 std::vector<char*> args(child_args_);
Christopher Ferris1a993562018-08-21 12:43:50 -0700187 std::string filter("--gtest_filter=" + GetTestName(test));
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700188 args.push_back(filter.data());
Christopher Ferris1a993562018-08-21 12:43:50 -0700189
Christopher Ferrisdb00a3a2021-09-20 16:09:18 -0700190 int argc = static_cast<int>(args.size());
Christopher Ferris1a993562018-08-21 12:43:50 -0700191 // Add the null terminator.
192 args.push_back(nullptr);
Christopher Ferris2b6124f2019-09-19 23:06:41 -0700193 ::testing::InitGoogleTest(&argc, args.data());
Christopher Ferris1a993562018-08-21 12:43:50 -0700194 return RUN_ALL_TESTS();
195}
196
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700197static bool Pipe(int* read_fd, int* write_fd) {
198 int pipefd[2];
199
200#if defined(__linux__)
201 if (pipe2(pipefd, O_CLOEXEC) != 0) {
202 return false;
203 }
204#else // defined(__APPLE__)
205 if (pipe(pipefd) != 0) {
206 return false;
207 }
208 if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 || fcntl(pipefd[1], F_SETFD, FD_CLOEXEC)) {
209 close(pipefd[0]);
210 close(pipefd[1]);
211 return false;
212 }
213#endif
214
215 *read_fd = pipefd[0];
216 *write_fd = pipefd[1];
217 return true;
218}
219
Christopher Ferris1a993562018-08-21 12:43:50 -0700220void Isolate::LaunchTests() {
221 while (!running_indices_.empty() && cur_test_index_ < tests_.size()) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700222 int read_fd, write_fd;
Christopher Ferris1a993562018-08-21 12:43:50 -0700223 if (!Pipe(&read_fd, &write_fd)) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700224 FATAL_PLOG("Unexpected failure from pipe");
Christopher Ferris1a993562018-08-21 12:43:50 -0700225 }
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700226 if (fcntl(read_fd, F_SETFL, O_NONBLOCK) == -1) {
227 FATAL_PLOG("Unexpected failure from fcntl");
Christopher Ferris1a993562018-08-21 12:43:50 -0700228 }
229
230 pid_t pid = fork();
231 if (pid == -1) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700232 FATAL_PLOG("Unexpected failure from fork");
Christopher Ferris1a993562018-08-21 12:43:50 -0700233 }
234 if (pid == 0) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700235 close(read_fd);
Christopher Ferris1a993562018-08-21 12:43:50 -0700236 close(STDOUT_FILENO);
237 close(STDERR_FILENO);
238 if (dup2(write_fd, STDOUT_FILENO) == -1) {
239 exit(1);
240 }
241 if (dup2(write_fd, STDERR_FILENO) == -1) {
242 exit(1);
243 }
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700244 close(write_fd);
Christopher Ferris1a993562018-08-21 12:43:50 -0700245 UnregisterSignalHandler();
246 exit(ChildProcessFn(tests_[cur_test_index_]));
247 }
248
Christopher Ferrisee59d492018-09-17 15:52:20 -0700249 size_t run_index = running_indices_.back();
250 running_indices_.pop_back();
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700251 Test* test = new Test(tests_[cur_test_index_], cur_test_index_, run_index, read_fd);
Christopher Ferrisee59d492018-09-17 15:52:20 -0700252 running_by_pid_.emplace(pid, test);
Christopher Ferris1a993562018-08-21 12:43:50 -0700253 running_[run_index] = test;
Christopher Ferris1a993562018-08-21 12:43:50 -0700254 running_by_test_index_[cur_test_index_] = test;
255
256 pollfd* pollfd = &running_pollfds_[run_index];
257 pollfd->fd = test->fd();
258 pollfd->events = POLLIN;
259 cur_test_index_++;
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700260 close(write_fd);
Christopher Ferris1a993562018-08-21 12:43:50 -0700261 }
262}
263
264void Isolate::ReadTestsOutput() {
Christopher Ferrisdb00a3a2021-09-20 16:09:18 -0700265 int ready = poll(running_pollfds_.data(), static_cast<nfds_t>(running_pollfds_.size()), 0);
Christopher Ferris1a993562018-08-21 12:43:50 -0700266 if (ready <= 0) {
267 return;
268 }
269
270 for (size_t i = 0; i < running_pollfds_.size(); i++) {
271 pollfd* pfd = &running_pollfds_[i];
272 if (pfd->revents & POLLIN) {
273 Test* test = running_[i];
274 if (!test->Read()) {
275 test->CloseFd();
276 pfd->fd = 0;
277 pfd->events = 0;
278 }
279 }
280 pfd->revents = 0;
281 }
282}
283
284size_t Isolate::CheckTestsFinished() {
285 size_t finished_tests = 0;
286 int status;
287 pid_t pid;
Christopher Ferrisdb00a3a2021-09-20 16:09:18 -0700288 while ((pid = static_cast<pid_t>(TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG)))) > 0) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700289 if (pid == -1) {
290 FATAL_PLOG("Unexpected failure from waitpid");
291 }
Christopher Ferris1a993562018-08-21 12:43:50 -0700292 auto entry = running_by_pid_.find(pid);
293 if (entry == running_by_pid_.end()) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700294 FATAL_LOG("Found process not spawned by the isolation framework");
Christopher Ferris1a993562018-08-21 12:43:50 -0700295 }
296
Christopher Ferrisee59d492018-09-17 15:52:20 -0700297 std::unique_ptr<Test>& test_ptr = entry->second;
298 Test* test = test_ptr.get();
Christopher Ferris1a993562018-08-21 12:43:50 -0700299 test->Stop();
300
301 // Read any leftover data.
302 test->ReadUntilClosed();
303 if (test->result() == TEST_NONE) {
304 if (WIFSIGNALED(status)) {
305 std::string output(test->name() + " terminated by signal: " + strsignal(WTERMSIG(status)) +
306 ".\n");
307 test->AppendOutput(output);
308 test->set_result(TEST_FAIL);
309 } else {
310 int exit_code = WEXITSTATUS(status);
311 if (exit_code != 0) {
312 std::string output(test->name() + " exited with exitcode " + std::to_string(exit_code) +
313 ".\n");
314 test->AppendOutput(output);
315 test->set_result(TEST_FAIL);
316 } else {
Christopher Ferris849d24e2019-03-09 16:47:04 -0800317 // Set the result based on the output, since skipped tests and
318 // passing tests have the same exit status.
319 test->SetResultFromOutput();
Christopher Ferris1a993562018-08-21 12:43:50 -0700320 }
321 }
322 } else if (test->result() == TEST_TIMEOUT) {
323 uint64_t time_ms = options_.deadline_threshold_ms();
324 std::string timeout_str(test->name() + " killed because of timeout at " +
325 std::to_string(time_ms) + " ms.\n");
326 test->AppendOutput(timeout_str);
327 }
328
329 if (test->ExpectFail()) {
330 if (test->result() == TEST_FAIL) {
331 // The test is expected to fail, it failed.
332 test->set_result(TEST_XFAIL);
333 } else if (test->result() == TEST_PASS) {
334 // The test is expected to fail, it passed.
335 test->set_result(TEST_XPASS);
336 }
337 }
338
Christopher Ferrisa3827162019-06-12 19:01:56 -0700339 test->Print();
Christopher Ferris1a993562018-08-21 12:43:50 -0700340
341 switch (test->result()) {
342 case TEST_PASS:
343 total_pass_tests_++;
344 if (test->slow()) {
345 total_slow_tests_++;
346 }
347 break;
348 case TEST_XPASS:
349 total_xpass_tests_++;
350 break;
351 case TEST_FAIL:
352 total_fail_tests_++;
353 break;
354 case TEST_TIMEOUT:
355 total_timeout_tests_++;
356 break;
357 case TEST_XFAIL:
358 total_xfail_tests_++;
359 break;
Christopher Ferris849d24e2019-03-09 16:47:04 -0800360 case TEST_SKIPPED:
361 total_skipped_tests_++;
362 break;
Christopher Ferris1a993562018-08-21 12:43:50 -0700363 case TEST_NONE:
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700364 FATAL_LOG("Test result is TEST_NONE, this should not be possible");
Christopher Ferris1a993562018-08-21 12:43:50 -0700365 }
366 finished_tests++;
367 size_t test_index = test->test_index();
Christopher Ferrisee59d492018-09-17 15:52:20 -0700368 finished_.emplace(test_index, test_ptr.release());
369 running_indices_.push_back(test->run_index());
Christopher Ferris1a993562018-08-21 12:43:50 -0700370
371 // Remove it from all of the running indices.
372 size_t run_index = test->run_index();
373 if (running_by_pid_.erase(pid) != 1) {
374 printf("Internal error: Erasing pid %d from running_by_pid_ incorrect\n", pid);
375 }
376 if (running_by_test_index_.erase(test_index) == 0) {
377 printf("Internal error: Erasing test_index %zu from running_by_pid_ incorrect\n", test_index);
378 }
379 running_[run_index] = nullptr;
380 running_pollfds_[run_index] = {};
381 }
382
383 // The only valid error case is if ECHILD is returned because there are
384 // no more processes left running.
385 if (pid == -1 && errno != ECHILD) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700386 FATAL_PLOG("Unexpected failure from waitpid");
Christopher Ferris1a993562018-08-21 12:43:50 -0700387 }
388 return finished_tests;
389}
390
391void Isolate::CheckTestsTimeout() {
392 for (auto& entry : running_by_pid_) {
Christopher Ferrisee59d492018-09-17 15:52:20 -0700393 Test* test = entry.second.get();
Christopher Ferris1a993562018-08-21 12:43:50 -0700394 if (test->result() == TEST_TIMEOUT) {
395 continue;
396 }
397
398 if (NanoTime() > test->start_ns() + deadline_threshold_ns_) {
399 test->set_result(TEST_TIMEOUT);
400 // Do not mark this as slow and timed out.
401 test->set_slow(false);
402 // Test gets cleaned up in CheckTestsFinished.
403 kill(entry.first, SIGKILL);
404 } else if (!test->slow() && NanoTime() > test->start_ns() + slow_threshold_ns_) {
405 // Mark the test as running slow.
406 test->set_slow(true);
407 }
408 }
409}
410
411void Isolate::HandleSignals() {
412 int signal = g_signal.exchange(0);
413 if (signal == SIGINT) {
414 printf("Terminating due to signal...\n");
415 for (auto& entry : running_by_pid_) {
416 kill(entry.first, SIGKILL);
417 }
418 exit(1);
419 } else if (signal == SIGQUIT) {
420 printf("List of current running tests:\n");
421 for (const auto& entry : running_by_test_index_) {
422 const Test* test = entry.second;
423 uint64_t run_time_ms = (NanoTime() - test->start_ns()) / kNsPerMs;
424 printf(" %s (elapsed time %" PRId64 " ms)\n", test->name().c_str(), run_time_ms);
425 }
426 }
427}
428
429void Isolate::RunAllTests() {
430 total_pass_tests_ = 0;
431 total_xpass_tests_ = 0;
432 total_fail_tests_ = 0;
433 total_xfail_tests_ = 0;
434 total_timeout_tests_ = 0;
435 total_slow_tests_ = 0;
Christopher Ferris849d24e2019-03-09 16:47:04 -0800436 total_skipped_tests_ = 0;
Christopher Ferris1a993562018-08-21 12:43:50 -0700437
438 running_by_test_index_.clear();
439
440 size_t job_count = options_.job_count();
441 running_.clear();
442 running_.resize(job_count);
443 running_pollfds_.resize(job_count);
444 memset(running_pollfds_.data(), 0, running_pollfds_.size() * sizeof(pollfd));
Christopher Ferrisee59d492018-09-17 15:52:20 -0700445 running_indices_.clear();
Christopher Ferris1a993562018-08-21 12:43:50 -0700446 for (size_t i = 0; i < job_count; i++) {
Christopher Ferrisee59d492018-09-17 15:52:20 -0700447 running_indices_.push_back(i);
Christopher Ferris1a993562018-08-21 12:43:50 -0700448 }
449
450 finished_.clear();
451
452 size_t finished = 0;
453 cur_test_index_ = 0;
454 while (finished < tests_.size()) {
455 LaunchTests();
456
457 ReadTestsOutput();
458
459 finished += CheckTestsFinished();
460
461 CheckTestsTimeout();
462
463 HandleSignals();
464
465 usleep(MIN_USECONDS_WAIT);
466 }
467}
468
Christopher Ferrisef982172018-09-27 15:19:07 -0700469void Isolate::PrintResults(size_t total, const ResultsType& results, std::string* footer) {
470 ColoredPrintf(results.color, results.prefix);
Christopher Ferris849d24e2019-03-09 16:47:04 -0800471 if (results.list_desc != nullptr) {
472 printf(" %s %s, listed below:\n", PluralizeString(total, " test").c_str(), results.list_desc);
473 } else {
474 printf(" %s, listed below:\n", PluralizeString(total, " test").c_str());
475 }
Christopher Ferris1a993562018-08-21 12:43:50 -0700476 for (const auto& entry : finished_) {
Christopher Ferrisee59d492018-09-17 15:52:20 -0700477 const Test* test = entry.second.get();
Christopher Ferrisef982172018-09-27 15:19:07 -0700478 if (results.match_func(*test)) {
479 ColoredPrintf(results.color, results.prefix);
Christopher Ferris1a993562018-08-21 12:43:50 -0700480 printf(" %s", test->name().c_str());
Christopher Ferrisef982172018-09-27 15:19:07 -0700481 if (results.print_func != nullptr) {
482 results.print_func(options_, *test);
Christopher Ferris1a993562018-08-21 12:43:50 -0700483 }
484 printf("\n");
485 }
486 }
Christopher Ferris849d24e2019-03-09 16:47:04 -0800487
488 if (results.title == nullptr) {
489 return;
490 }
491
Christopher Ferris1a993562018-08-21 12:43:50 -0700492 if (total < 10) {
493 *footer += ' ';
494 }
Christopher Ferrisef982172018-09-27 15:19:07 -0700495 *footer +=
496 PluralizeString(total, (std::string(" ") + results.title + " TEST").c_str(), true) + '\n';
Christopher Ferris1a993562018-08-21 12:43:50 -0700497}
498
Christopher Ferrisef982172018-09-27 15:19:07 -0700499Isolate::ResultsType Isolate::SlowResults = {
500 .color = COLOR_YELLOW,
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700501 .prefix = "[ SLOW ]",
502 .list_desc = nullptr,
Christopher Ferrisef982172018-09-27 15:19:07 -0700503 .title = "SLOW",
504 .match_func = [](const Test& test) { return test.slow(); },
505 .print_func =
506 [](const Options& options, const Test& test) {
507 printf(" (%" PRIu64 " ms, exceeded %" PRIu64 " ms)", test.RunTimeNs() / kNsPerMs,
508 options.slow_threshold_ms());
509 },
510};
511
512Isolate::ResultsType Isolate::XpassFailResults = {
513 .color = COLOR_RED,
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700514 .prefix = "[ FAILED ]",
Christopher Ferrisef982172018-09-27 15:19:07 -0700515 .list_desc = "should have failed",
516 .title = "SHOULD HAVE FAILED",
517 .match_func = [](const Test& test) { return test.result() == TEST_XPASS; },
518 .print_func = nullptr,
519};
520
521Isolate::ResultsType Isolate::FailResults = {
522 .color = COLOR_RED,
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700523 .prefix = "[ FAILED ]",
524 .list_desc = nullptr,
Christopher Ferrisef982172018-09-27 15:19:07 -0700525 .title = "FAILED",
526 .match_func = [](const Test& test) { return test.result() == TEST_FAIL; },
527 .print_func = nullptr,
528};
529
530Isolate::ResultsType Isolate::TimeoutResults = {
531 .color = COLOR_RED,
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700532 .prefix = "[ TIMEOUT ]",
533 .list_desc = nullptr,
Christopher Ferrisef982172018-09-27 15:19:07 -0700534 .title = "TIMEOUT",
535 .match_func = [](const Test& test) { return test.result() == TEST_TIMEOUT; },
536 .print_func =
537 [](const Options&, const Test& test) {
538 printf(" (stopped at %" PRIu64 " ms)", test.RunTimeNs() / kNsPerMs);
539 },
540};
541
Christopher Ferris849d24e2019-03-09 16:47:04 -0800542Isolate::ResultsType Isolate::SkippedResults = {
543 .color = COLOR_GREEN,
544 .prefix = "[ SKIPPED ]",
545 .list_desc = nullptr,
546 .title = nullptr,
547 .match_func = [](const Test& test) { return test.result() == TEST_SKIPPED; },
548 .print_func = nullptr,
549};
550
Christopher Ferris1a993562018-08-21 12:43:50 -0700551void Isolate::PrintFooter(uint64_t elapsed_time_ns) {
552 ColoredPrintf(COLOR_GREEN, "[==========]");
553 printf(" %s from %s ran. (%" PRId64 " ms total)\n",
554 PluralizeString(total_tests_, " test").c_str(),
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700555 PluralizeString(total_suites_, " test suite").c_str(), elapsed_time_ns / kNsPerMs);
Christopher Ferris1a993562018-08-21 12:43:50 -0700556
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700557 ColoredPrintf(COLOR_GREEN, "[ PASSED ]");
Christopher Ferris1a993562018-08-21 12:43:50 -0700558 printf(" %s.", PluralizeString(total_pass_tests_ + total_xfail_tests_, " test").c_str());
559 if (total_xfail_tests_ != 0) {
560 printf(" (%s)", PluralizeString(total_xfail_tests_, " expected failure").c_str());
561 }
562 printf("\n");
563
564 std::string footer;
Christopher Ferris849d24e2019-03-09 16:47:04 -0800565
566 // Tests that were skipped.
567 if (total_skipped_tests_ != 0) {
568 PrintResults(total_skipped_tests_, SkippedResults, &footer);
569 }
570
Christopher Ferris1a993562018-08-21 12:43:50 -0700571 // Tests that ran slow.
572 if (total_slow_tests_ != 0) {
Christopher Ferrisef982172018-09-27 15:19:07 -0700573 PrintResults(total_slow_tests_, SlowResults, &footer);
Christopher Ferris1a993562018-08-21 12:43:50 -0700574 }
575
576 // Tests that passed but should have failed.
577 if (total_xpass_tests_ != 0) {
Christopher Ferrisef982172018-09-27 15:19:07 -0700578 PrintResults(total_xpass_tests_, XpassFailResults, &footer);
Christopher Ferris1a993562018-08-21 12:43:50 -0700579 }
580
581 // Tests that timed out.
582 if (total_timeout_tests_ != 0) {
Christopher Ferrisef982172018-09-27 15:19:07 -0700583 PrintResults(total_timeout_tests_, TimeoutResults, &footer);
Christopher Ferris1a993562018-08-21 12:43:50 -0700584 }
585
586 // Tests that failed.
587 if (total_fail_tests_ != 0) {
Christopher Ferrisef982172018-09-27 15:19:07 -0700588 PrintResults(total_fail_tests_, FailResults, &footer);
Christopher Ferris1a993562018-08-21 12:43:50 -0700589 }
590
591 if (!footer.empty()) {
592 printf("\n%s", footer.c_str());
593 }
594
595 if (total_disable_tests_ != 0) {
596 if (footer.empty()) {
597 printf("\n");
598 }
599 ColoredPrintf(COLOR_YELLOW, " YOU HAVE %s\n\n",
600 PluralizeString(total_disable_tests_, " DISABLED TEST", true).c_str());
601 }
602
603 fflush(stdout);
604}
605
606std::string XmlEscape(const std::string& xml) {
607 std::string escaped;
608 escaped.reserve(xml.size());
609
610 for (auto c : xml) {
611 switch (c) {
612 case '<':
613 escaped.append("&lt;");
614 break;
615 case '>':
616 escaped.append("&gt;");
617 break;
618 case '&':
619 escaped.append("&amp;");
620 break;
621 case '\'':
622 escaped.append("&apos;");
623 break;
624 case '"':
625 escaped.append("&quot;");
626 break;
627 default:
628 escaped.append(1, c);
629 break;
630 }
631 }
632
633 return escaped;
634}
635
636class TestResultPrinter : public ::testing::EmptyTestEventListener {
637 public:
638 TestResultPrinter() : pinfo_(nullptr) {}
639 virtual void OnTestStart(const ::testing::TestInfo& test_info) {
640 pinfo_ = &test_info; // Record test_info for use in OnTestPartResult.
641 }
642 virtual void OnTestPartResult(const ::testing::TestPartResult& result);
643
644 private:
645 const ::testing::TestInfo* pinfo_;
646};
647
648// Called after an assertion failure.
649void TestResultPrinter::OnTestPartResult(const ::testing::TestPartResult& result) {
650 // If the test part succeeded, we don't need to do anything.
651 if (result.type() == ::testing::TestPartResult::kSuccess) {
652 return;
653 }
654
Christopher Ferris7cfd24e2019-11-14 19:27:19 -0800655 if (result.type() == ::testing::TestPartResult::kSkip) {
Haibo Huang8b01e5b2020-07-15 17:35:45 -0700656 printf("%s:(%d) Skipped\n", result.file_name(), result.line_number());
657 if (*result.message()) {
658 printf("%s\n", result.message());
659 }
Christopher Ferris7cfd24e2019-11-14 19:27:19 -0800660 } else {
661 // Print failure message from the assertion (e.g. expected this and got that).
662 printf("%s:(%d) Failure in test %s.%s\n%s\n", result.file_name(), result.line_number(),
663 pinfo_->test_suite_name(), pinfo_->name(), result.message());
664 }
Christopher Ferris1a993562018-08-21 12:43:50 -0700665 fflush(stdout);
666}
667
668// Output xml file when --gtest_output is used, write this function as we can't reuse
669// gtest.cc:XmlUnitTestResultPrinter. The reason is XmlUnitTestResultPrinter is totally
670// defined in gtest.cc and not expose to outside. What's more, as we don't run gtest in
671// the parent process, we don't have gtest classes which are needed by XmlUnitTestResultPrinter.
672void Isolate::WriteXmlResults(uint64_t elapsed_time_ns, time_t start_time) {
673 FILE* fp = fopen(options_.xml_file().c_str(), "w");
674 if (fp == nullptr) {
675 printf("Cannot open xml file '%s': %s\n", options_.xml_file().c_str(), strerror(errno));
676 exit(1);
677 }
678
679 const tm* time_struct = localtime(&start_time);
680 if (time_struct == nullptr) {
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700681 FATAL_PLOG("Unexpected failure from localtime");
Christopher Ferris1a993562018-08-21 12:43:50 -0700682 }
683 char timestamp[40];
684 snprintf(timestamp, sizeof(timestamp), "%4d-%02d-%02dT%02d:%02d:%02d",
685 time_struct->tm_year + 1900, time_struct->tm_mon + 1, time_struct->tm_mday,
686 time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
687
688 fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", fp);
689 fprintf(fp, "<testsuites tests=\"%zu\" failures=\"%zu\" disabled=\"0\" errors=\"0\"",
690 tests_.size(), total_fail_tests_ + total_timeout_tests_ + total_xpass_tests_);
691 fprintf(fp, " timestamp=\"%s\" time=\"%.3lf\" name=\"AllTests\">\n", timestamp,
692 double(elapsed_time_ns) / kNsPerMs);
693
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700694 // Construct the suite information.
695 struct SuiteInfo {
696 std::string suite_name;
Christopher Ferris1a993562018-08-21 12:43:50 -0700697 size_t fails = 0;
698 double elapsed_ms = 0;
699 std::vector<const Test*> tests;
700 };
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700701 std::string last_suite_name;
702 std::vector<SuiteInfo> suites;
703 SuiteInfo* info = nullptr;
Christopher Ferris1a993562018-08-21 12:43:50 -0700704 for (const auto& entry : finished_) {
Christopher Ferrisee59d492018-09-17 15:52:20 -0700705 const Test* test = entry.second.get();
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700706 const std::string& suite_name = test->suite_name();
Christopher Ferris1a993562018-08-21 12:43:50 -0700707 if (test->result() == TEST_XFAIL) {
708 // Skip XFAIL tests.
709 continue;
710 }
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700711 if (last_suite_name != suite_name) {
712 SuiteInfo suite_info{.suite_name = suite_name.substr(0, suite_name.size() - 1)};
713 last_suite_name = suite_name;
714 suites.push_back(suite_info);
715 info = &suites.back();
Christopher Ferris1a993562018-08-21 12:43:50 -0700716 }
717 info->tests.push_back(test);
718 info->elapsed_ms += double(test->RunTimeNs()) / kNsPerMs;
719 if (test->result() != TEST_PASS) {
720 info->fails++;
721 }
722 }
723
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700724 for (auto& suite_entry : suites) {
Christopher Ferris1a993562018-08-21 12:43:50 -0700725 fprintf(fp,
726 " <testsuite name=\"%s\" tests=\"%zu\" failures=\"%zu\" disabled=\"0\" errors=\"0\"",
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700727 suite_entry.suite_name.c_str(), suite_entry.tests.size(), suite_entry.fails);
728 fprintf(fp, " time=\"%.3lf\">\n", suite_entry.elapsed_ms);
Christopher Ferris1a993562018-08-21 12:43:50 -0700729
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700730 for (auto test : suite_entry.tests) {
Christopher Ferris1a993562018-08-21 12:43:50 -0700731 fprintf(fp, " <testcase name=\"%s\" status=\"run\" time=\"%.3lf\" classname=\"%s\"",
732 test->test_name().c_str(), double(test->RunTimeNs()) / kNsPerMs,
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700733 suite_entry.suite_name.c_str());
Christopher Ferris1a993562018-08-21 12:43:50 -0700734 if (test->result() == TEST_PASS) {
735 fputs(" />\n", fp);
736 } else {
737 fputs(">\n", fp);
738 const std::string escaped_output = XmlEscape(test->output());
739 fprintf(fp, " <failure message=\"%s\" type=\"\">\n", escaped_output.c_str());
740 fputs(" </failure>\n", fp);
741 fputs(" </testcase>\n", fp);
742 }
743 }
744 fputs(" </testsuite>\n", fp);
745 }
746 fputs("</testsuites>\n", fp);
747 fclose(fp);
748}
749
750int Isolate::Run() {
751 slow_threshold_ns_ = options_.slow_threshold_ms() * kNsPerMs;
752 deadline_threshold_ns_ = options_.deadline_threshold_ms() * kNsPerMs;
753
Christopher Ferris3215ef12019-03-12 19:10:35 -0700754 bool sharding_enabled = options_.total_shards() > 1;
755 if (sharding_enabled &&
756 (options_.shard_index() < 0 || options_.shard_index() >= options_.total_shards())) {
757 ColoredPrintf(COLOR_RED,
758 "Invalid environment variables: we require 0 <= GTEST_SHARD_INDEX < "
759 "GTEST_TOTAL_SHARDS, but you have GTEST_SHARD_INDEX=%" PRId64
760 ", GTEST_TOTAL_SHARDS=%" PRId64,
761 options_.shard_index(), options_.total_shards());
762 printf("\n");
763 return 1;
764 }
765
766 if (!options_.filter().empty()) {
767 ColoredPrintf(COLOR_YELLOW, "Note: Google Test filter = %s", options_.filter().c_str());
768 printf("\n");
769 }
770
771 if (sharding_enabled) {
772 ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %" PRId64 " of %" PRId64,
773 options_.shard_index() + 1, options_.total_shards());
774 printf("\n");
775 }
776
Christopher Ferris1a993562018-08-21 12:43:50 -0700777 EnumerateTests();
778
779 // Stop default result printer to avoid environment setup/teardown information for each test.
Christopher Ferris4ba40d82020-05-11 13:31:11 -0700780 delete ::testing::UnitTest::GetInstance()->listeners().Release(
Christopher Ferris1a993562018-08-21 12:43:50 -0700781 ::testing::UnitTest::GetInstance()->listeners().default_result_printer());
782 ::testing::UnitTest::GetInstance()->listeners().Append(new TestResultPrinter);
783 RegisterSignalHandler();
784
785 std::string job_info("Running " + PluralizeString(total_tests_, " test") + " from " +
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700786 PluralizeString(total_suites_, " test suite") + " (" +
Christopher Ferris1a993562018-08-21 12:43:50 -0700787 PluralizeString(options_.job_count(), " job") + ").");
788
789 int exit_code = 0;
790 for (int i = 0; options_.num_iterations() < 0 || i < options_.num_iterations(); i++) {
791 if (i > 0) {
792 printf("\nRepeating all tests (iteration %d) . . .\n\n", i + 1);
793 }
794 ColoredPrintf(COLOR_GREEN, "[==========]");
795 printf(" %s\n", job_info.c_str());
796 fflush(stdout);
797
798 time_t start_time = time(nullptr);
799 uint64_t time_ns = NanoTime();
800 RunAllTests();
801 time_ns = NanoTime() - time_ns;
802
803 PrintFooter(time_ns);
804
805 if (!options_.xml_file().empty()) {
806 WriteXmlResults(time_ns, start_time);
807 }
808
Christopher Ferris849d24e2019-03-09 16:47:04 -0800809 if (total_pass_tests_ + total_skipped_tests_ + total_xfail_tests_ != tests_.size()) {
Christopher Ferris1a993562018-08-21 12:43:50 -0700810 exit_code = 1;
Christopher Ferris94709282021-07-27 13:54:13 -0700811 if (options_.stop_on_error() && options_.num_iterations() > 1) {
812 printf("\nTerminating repeat run due to failing tests (iteration %d).\n", i + 1);
813 break;
814 }
Christopher Ferris1a993562018-08-21 12:43:50 -0700815 }
816 }
817
818 return exit_code;
819}
820
821} // namespace gtest_extras
822} // namespace android