blob: e70f1c79865a32ae3d5e7b15ba90c11fc9420fd1 [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>
23#include <string.h>
24#include <unistd.h>
25
26#include <atomic>
27#include <string>
28#include <tuple>
29#include <vector>
30
31#include <android-base/logging.h>
32#include <android-base/strings.h>
33#include <android-base/unique_fd.h>
34#include <gtest/gtest.h>
35
36#include "Color.h"
37#include "Isolate.h"
38#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) {
53 PLOG(FATAL) << "Setting up SIGINT handler failed";
54 }
55 ret = signal(SIGQUIT, SignalHandler);
56 if (ret == SIG_ERR) {
57 PLOG(FATAL) << "Setting up SIGQUIT handler failed";
58 }
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) {
64 PLOG(FATAL) << "Disabling SIGINT handler failed";
65 }
66 ret = signal(SIGQUIT, SIG_DFL);
67 if (ret == SIG_ERR) {
68 PLOG(FATAL) << "Disabling SIGQUIT handler failed";
69 }
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
84void Isolate::EnumerateTests() {
85 // Only apply --gtest_filter if present. This is the only option that changes
86 // what tests are listed.
87 std::string command(child_args_[0]);
88 if (!options_.filter().empty()) {
89 command += " --gtest_filter=" + options_.filter();
90 }
91 command += " --gtest_list_tests";
Christopher Ferris23a3db02018-09-07 07:39:18 -070092#if defined(__APPLE__)
93 FILE* fp = popen(command.c_str(), "r");
94#else
Christopher Ferris1a993562018-08-21 12:43:50 -070095 FILE* fp = popen(command.c_str(), "re");
Christopher Ferris23a3db02018-09-07 07:39:18 -070096#endif
Christopher Ferris1a993562018-08-21 12:43:50 -070097 if (fp == nullptr) {
98 PLOG(FATAL) << "Unexpected failure from popen";
99 }
100
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700101 bool skip_until_next_suite = false;
102 std::string suite_name;
Christopher Ferris1a993562018-08-21 12:43:50 -0700103 char* buffer = nullptr;
104 size_t buffer_len = 0;
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700105 bool new_suite = false;
Christopher Ferris1a993562018-08-21 12:43:50 -0700106 while (getline(&buffer, &buffer_len, fp) > 0) {
107 if (buffer[0] != ' ') {
108 // This is the case name.
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700109 suite_name = buffer;
110 auto space_index = suite_name.find(' ');
Christopher Ferris1a993562018-08-21 12:43:50 -0700111 if (space_index != std::string::npos) {
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700112 suite_name.erase(space_index);
Christopher Ferris1a993562018-08-21 12:43:50 -0700113 }
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700114 if (suite_name.back() == '\n') {
115 suite_name.resize(suite_name.size() - 1);
Christopher Ferris1a993562018-08-21 12:43:50 -0700116 }
117
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700118 if (!options_.allow_disabled_tests() && android::base::StartsWith(suite_name, "DISABLED_")) {
Christopher Ferris1a993562018-08-21 12:43:50 -0700119 // This whole set of tests have been disabled, skip them all.
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700120 skip_until_next_suite = true;
Christopher Ferris1a993562018-08-21 12:43:50 -0700121 } else {
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700122 new_suite = true;
123 skip_until_next_suite = false;
Christopher Ferris1a993562018-08-21 12:43:50 -0700124 }
125 } else if (buffer[0] == ' ' && buffer[1] == ' ') {
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700126 if (!skip_until_next_suite) {
Christopher Ferris1a993562018-08-21 12:43:50 -0700127 std::string test_name = &buffer[2];
128 auto space_index = test_name.find(' ');
129 if (space_index != std::string::npos) {
130 test_name.erase(space_index);
131 }
132 if (test_name.back() == '\n') {
133 test_name.resize(test_name.size() - 1);
134 }
135 if (options_.allow_disabled_tests() || !android::base::StartsWith(test_name, "DISABLED_")) {
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700136 tests_.push_back(std::make_tuple(suite_name, test_name));
Christopher Ferris1a993562018-08-21 12:43:50 -0700137 total_tests_++;
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700138 if (new_suite) {
139 // Only increment the number of suites when we find at least one test
140 // for the suites.
141 total_suites_++;
142 new_suite = false;
Christopher Ferris1a993562018-08-21 12:43:50 -0700143 }
144 } else {
145 total_disable_tests_++;
146 }
147 } else {
148 total_disable_tests_++;
149 }
150 } else {
151 printf("Unexpected output from test listing.\nCommand:\n%s\nLine:\n%s\n", command.c_str(),
152 buffer);
153 exit(1);
154 }
155 }
156 free(buffer);
157 if (pclose(fp) == -1) {
158 PLOG(FATAL) << "Unexpected failure from pclose";
159 }
160}
161
162int Isolate::ChildProcessFn(const std::tuple<std::string, std::string>& test) {
163 // Make sure the filter is only coming from our command-line option.
164 unsetenv("GTEST_FILTER");
165
166 // Add the filter argument.
167 std::vector<const char*> args(child_args_);
168 std::string filter("--gtest_filter=" + GetTestName(test));
169 args.push_back(filter.c_str());
170
171 int argc = args.size();
172 // Add the null terminator.
173 args.push_back(nullptr);
174 ::testing::InitGoogleTest(&argc, const_cast<char**>(args.data()));
175 return RUN_ALL_TESTS();
176}
177
178void Isolate::LaunchTests() {
179 while (!running_indices_.empty() && cur_test_index_ < tests_.size()) {
180 android::base::unique_fd read_fd, write_fd;
181 if (!Pipe(&read_fd, &write_fd)) {
182 PLOG(FATAL) << "Unexpected failure from pipe";
183 }
184 if (fcntl(read_fd.get(), F_SETFL, O_NONBLOCK) == -1) {
185 PLOG(FATAL) << "Unexpected failure from fcntl";
186 }
187
188 pid_t pid = fork();
189 if (pid == -1) {
190 PLOG(FATAL) << "Unexpected failure from fork";
191 }
192 if (pid == 0) {
193 read_fd.reset();
194 close(STDOUT_FILENO);
195 close(STDERR_FILENO);
196 if (dup2(write_fd, STDOUT_FILENO) == -1) {
197 exit(1);
198 }
199 if (dup2(write_fd, STDERR_FILENO) == -1) {
200 exit(1);
201 }
202 UnregisterSignalHandler();
203 exit(ChildProcessFn(tests_[cur_test_index_]));
204 }
205
Christopher Ferrisee59d492018-09-17 15:52:20 -0700206 size_t run_index = running_indices_.back();
207 running_indices_.pop_back();
Christopher Ferris1a993562018-08-21 12:43:50 -0700208 Test* test = new Test(tests_[cur_test_index_], cur_test_index_, run_index, read_fd.release());
Christopher Ferrisee59d492018-09-17 15:52:20 -0700209 running_by_pid_.emplace(pid, test);
Christopher Ferris1a993562018-08-21 12:43:50 -0700210 running_[run_index] = test;
Christopher Ferris1a993562018-08-21 12:43:50 -0700211 running_by_test_index_[cur_test_index_] = test;
212
213 pollfd* pollfd = &running_pollfds_[run_index];
214 pollfd->fd = test->fd();
215 pollfd->events = POLLIN;
216 cur_test_index_++;
217 }
218}
219
220void Isolate::ReadTestsOutput() {
221 int ready = poll(running_pollfds_.data(), running_pollfds_.size(), 0);
222 if (ready <= 0) {
223 return;
224 }
225
226 for (size_t i = 0; i < running_pollfds_.size(); i++) {
227 pollfd* pfd = &running_pollfds_[i];
228 if (pfd->revents & POLLIN) {
229 Test* test = running_[i];
230 if (!test->Read()) {
231 test->CloseFd();
232 pfd->fd = 0;
233 pfd->events = 0;
234 }
235 }
236 pfd->revents = 0;
237 }
238}
239
240size_t Isolate::CheckTestsFinished() {
241 size_t finished_tests = 0;
242 int status;
243 pid_t pid;
244 while ((pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG))) > 0) {
245 auto entry = running_by_pid_.find(pid);
246 if (entry == running_by_pid_.end()) {
247 LOG(FATAL) << "Pid " << pid << " was not spawned by the isolation framework.";
248 }
249
Christopher Ferrisee59d492018-09-17 15:52:20 -0700250 std::unique_ptr<Test>& test_ptr = entry->second;
251 Test* test = test_ptr.get();
Christopher Ferris1a993562018-08-21 12:43:50 -0700252 test->Stop();
253
254 // Read any leftover data.
255 test->ReadUntilClosed();
256 if (test->result() == TEST_NONE) {
257 if (WIFSIGNALED(status)) {
258 std::string output(test->name() + " terminated by signal: " + strsignal(WTERMSIG(status)) +
259 ".\n");
260 test->AppendOutput(output);
261 test->set_result(TEST_FAIL);
262 } else {
263 int exit_code = WEXITSTATUS(status);
264 if (exit_code != 0) {
265 std::string output(test->name() + " exited with exitcode " + std::to_string(exit_code) +
266 ".\n");
267 test->AppendOutput(output);
268 test->set_result(TEST_FAIL);
269 } else {
Christopher Ferris849d24e2019-03-09 16:47:04 -0800270 // Set the result based on the output, since skipped tests and
271 // passing tests have the same exit status.
272 test->SetResultFromOutput();
Christopher Ferris1a993562018-08-21 12:43:50 -0700273 }
274 }
275 } else if (test->result() == TEST_TIMEOUT) {
276 uint64_t time_ms = options_.deadline_threshold_ms();
277 std::string timeout_str(test->name() + " killed because of timeout at " +
278 std::to_string(time_ms) + " ms.\n");
279 test->AppendOutput(timeout_str);
280 }
281
282 if (test->ExpectFail()) {
283 if (test->result() == TEST_FAIL) {
284 // The test is expected to fail, it failed.
285 test->set_result(TEST_XFAIL);
286 } else if (test->result() == TEST_PASS) {
287 // The test is expected to fail, it passed.
288 test->set_result(TEST_XPASS);
289 }
290 }
291
292 test->Print(options_.gtest_format());
293
294 switch (test->result()) {
295 case TEST_PASS:
296 total_pass_tests_++;
297 if (test->slow()) {
298 total_slow_tests_++;
299 }
300 break;
301 case TEST_XPASS:
302 total_xpass_tests_++;
303 break;
304 case TEST_FAIL:
305 total_fail_tests_++;
306 break;
307 case TEST_TIMEOUT:
308 total_timeout_tests_++;
309 break;
310 case TEST_XFAIL:
311 total_xfail_tests_++;
312 break;
Christopher Ferris849d24e2019-03-09 16:47:04 -0800313 case TEST_SKIPPED:
314 total_skipped_tests_++;
315 break;
Christopher Ferris1a993562018-08-21 12:43:50 -0700316 case TEST_NONE:
317 LOG(FATAL) << "Test result is TEST_NONE, this should not be possible.";
318 }
319 finished_tests++;
320 size_t test_index = test->test_index();
Christopher Ferrisee59d492018-09-17 15:52:20 -0700321 finished_.emplace(test_index, test_ptr.release());
322 running_indices_.push_back(test->run_index());
Christopher Ferris1a993562018-08-21 12:43:50 -0700323
324 // Remove it from all of the running indices.
325 size_t run_index = test->run_index();
326 if (running_by_pid_.erase(pid) != 1) {
327 printf("Internal error: Erasing pid %d from running_by_pid_ incorrect\n", pid);
328 }
329 if (running_by_test_index_.erase(test_index) == 0) {
330 printf("Internal error: Erasing test_index %zu from running_by_pid_ incorrect\n", test_index);
331 }
332 running_[run_index] = nullptr;
333 running_pollfds_[run_index] = {};
334 }
335
336 // The only valid error case is if ECHILD is returned because there are
337 // no more processes left running.
338 if (pid == -1 && errno != ECHILD) {
339 PLOG(FATAL) << "Unexpected failure from waitpid";
340 }
341 return finished_tests;
342}
343
344void Isolate::CheckTestsTimeout() {
345 for (auto& entry : running_by_pid_) {
Christopher Ferrisee59d492018-09-17 15:52:20 -0700346 Test* test = entry.second.get();
Christopher Ferris1a993562018-08-21 12:43:50 -0700347 if (test->result() == TEST_TIMEOUT) {
348 continue;
349 }
350
351 if (NanoTime() > test->start_ns() + deadline_threshold_ns_) {
352 test->set_result(TEST_TIMEOUT);
353 // Do not mark this as slow and timed out.
354 test->set_slow(false);
355 // Test gets cleaned up in CheckTestsFinished.
356 kill(entry.first, SIGKILL);
357 } else if (!test->slow() && NanoTime() > test->start_ns() + slow_threshold_ns_) {
358 // Mark the test as running slow.
359 test->set_slow(true);
360 }
361 }
362}
363
364void Isolate::HandleSignals() {
365 int signal = g_signal.exchange(0);
366 if (signal == SIGINT) {
367 printf("Terminating due to signal...\n");
368 for (auto& entry : running_by_pid_) {
369 kill(entry.first, SIGKILL);
370 }
371 exit(1);
372 } else if (signal == SIGQUIT) {
373 printf("List of current running tests:\n");
374 for (const auto& entry : running_by_test_index_) {
375 const Test* test = entry.second;
376 uint64_t run_time_ms = (NanoTime() - test->start_ns()) / kNsPerMs;
377 printf(" %s (elapsed time %" PRId64 " ms)\n", test->name().c_str(), run_time_ms);
378 }
379 }
380}
381
382void Isolate::RunAllTests() {
383 total_pass_tests_ = 0;
384 total_xpass_tests_ = 0;
385 total_fail_tests_ = 0;
386 total_xfail_tests_ = 0;
387 total_timeout_tests_ = 0;
388 total_slow_tests_ = 0;
Christopher Ferris849d24e2019-03-09 16:47:04 -0800389 total_skipped_tests_ = 0;
Christopher Ferris1a993562018-08-21 12:43:50 -0700390
391 running_by_test_index_.clear();
392
393 size_t job_count = options_.job_count();
394 running_.clear();
395 running_.resize(job_count);
396 running_pollfds_.resize(job_count);
397 memset(running_pollfds_.data(), 0, running_pollfds_.size() * sizeof(pollfd));
Christopher Ferrisee59d492018-09-17 15:52:20 -0700398 running_indices_.clear();
Christopher Ferris1a993562018-08-21 12:43:50 -0700399 for (size_t i = 0; i < job_count; i++) {
Christopher Ferrisee59d492018-09-17 15:52:20 -0700400 running_indices_.push_back(i);
Christopher Ferris1a993562018-08-21 12:43:50 -0700401 }
402
403 finished_.clear();
404
405 size_t finished = 0;
406 cur_test_index_ = 0;
407 while (finished < tests_.size()) {
408 LaunchTests();
409
410 ReadTestsOutput();
411
412 finished += CheckTestsFinished();
413
414 CheckTestsTimeout();
415
416 HandleSignals();
417
418 usleep(MIN_USECONDS_WAIT);
419 }
420}
421
Christopher Ferrisef982172018-09-27 15:19:07 -0700422void Isolate::PrintResults(size_t total, const ResultsType& results, std::string* footer) {
423 ColoredPrintf(results.color, results.prefix);
Christopher Ferris849d24e2019-03-09 16:47:04 -0800424 if (results.list_desc != nullptr) {
425 printf(" %s %s, listed below:\n", PluralizeString(total, " test").c_str(), results.list_desc);
426 } else {
427 printf(" %s, listed below:\n", PluralizeString(total, " test").c_str());
428 }
Christopher Ferris1a993562018-08-21 12:43:50 -0700429 for (const auto& entry : finished_) {
Christopher Ferrisee59d492018-09-17 15:52:20 -0700430 const Test* test = entry.second.get();
Christopher Ferrisef982172018-09-27 15:19:07 -0700431 if (results.match_func(*test)) {
432 ColoredPrintf(results.color, results.prefix);
Christopher Ferris1a993562018-08-21 12:43:50 -0700433 printf(" %s", test->name().c_str());
Christopher Ferrisef982172018-09-27 15:19:07 -0700434 if (results.print_func != nullptr) {
435 results.print_func(options_, *test);
Christopher Ferris1a993562018-08-21 12:43:50 -0700436 }
437 printf("\n");
438 }
439 }
Christopher Ferris849d24e2019-03-09 16:47:04 -0800440
441 if (results.title == nullptr) {
442 return;
443 }
444
Christopher Ferris1a993562018-08-21 12:43:50 -0700445 if (total < 10) {
446 *footer += ' ';
447 }
Christopher Ferrisef982172018-09-27 15:19:07 -0700448 *footer +=
449 PluralizeString(total, (std::string(" ") + results.title + " TEST").c_str(), true) + '\n';
Christopher Ferris1a993562018-08-21 12:43:50 -0700450}
451
Christopher Ferrisef982172018-09-27 15:19:07 -0700452Isolate::ResultsType Isolate::SlowResults = {
453 .color = COLOR_YELLOW,
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700454 .prefix = "[ SLOW ]",
455 .list_desc = nullptr,
Christopher Ferrisef982172018-09-27 15:19:07 -0700456 .title = "SLOW",
457 .match_func = [](const Test& test) { return test.slow(); },
458 .print_func =
459 [](const Options& options, const Test& test) {
460 printf(" (%" PRIu64 " ms, exceeded %" PRIu64 " ms)", test.RunTimeNs() / kNsPerMs,
461 options.slow_threshold_ms());
462 },
463};
464
465Isolate::ResultsType Isolate::XpassFailResults = {
466 .color = COLOR_RED,
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700467 .prefix = "[ FAILED ]",
Christopher Ferrisef982172018-09-27 15:19:07 -0700468 .list_desc = "should have failed",
469 .title = "SHOULD HAVE FAILED",
470 .match_func = [](const Test& test) { return test.result() == TEST_XPASS; },
471 .print_func = nullptr,
472};
473
474Isolate::ResultsType Isolate::FailResults = {
475 .color = COLOR_RED,
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700476 .prefix = "[ FAILED ]",
477 .list_desc = nullptr,
Christopher Ferrisef982172018-09-27 15:19:07 -0700478 .title = "FAILED",
479 .match_func = [](const Test& test) { return test.result() == TEST_FAIL; },
480 .print_func = nullptr,
481};
482
483Isolate::ResultsType Isolate::TimeoutResults = {
484 .color = COLOR_RED,
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700485 .prefix = "[ TIMEOUT ]",
486 .list_desc = nullptr,
Christopher Ferrisef982172018-09-27 15:19:07 -0700487 .title = "TIMEOUT",
488 .match_func = [](const Test& test) { return test.result() == TEST_TIMEOUT; },
489 .print_func =
490 [](const Options&, const Test& test) {
491 printf(" (stopped at %" PRIu64 " ms)", test.RunTimeNs() / kNsPerMs);
492 },
493};
494
Christopher Ferris849d24e2019-03-09 16:47:04 -0800495Isolate::ResultsType Isolate::SkippedResults = {
496 .color = COLOR_GREEN,
497 .prefix = "[ SKIPPED ]",
498 .list_desc = nullptr,
499 .title = nullptr,
500 .match_func = [](const Test& test) { return test.result() == TEST_SKIPPED; },
501 .print_func = nullptr,
502};
503
Christopher Ferris1a993562018-08-21 12:43:50 -0700504void Isolate::PrintFooter(uint64_t elapsed_time_ns) {
505 ColoredPrintf(COLOR_GREEN, "[==========]");
506 printf(" %s from %s ran. (%" PRId64 " ms total)\n",
507 PluralizeString(total_tests_, " test").c_str(),
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700508 PluralizeString(total_suites_, " test suite").c_str(), elapsed_time_ns / kNsPerMs);
Christopher Ferris1a993562018-08-21 12:43:50 -0700509
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700510 ColoredPrintf(COLOR_GREEN, "[ PASSED ]");
Christopher Ferris1a993562018-08-21 12:43:50 -0700511 printf(" %s.", PluralizeString(total_pass_tests_ + total_xfail_tests_, " test").c_str());
512 if (total_xfail_tests_ != 0) {
513 printf(" (%s)", PluralizeString(total_xfail_tests_, " expected failure").c_str());
514 }
515 printf("\n");
516
517 std::string footer;
Christopher Ferris849d24e2019-03-09 16:47:04 -0800518
519 // Tests that were skipped.
520 if (total_skipped_tests_ != 0) {
521 PrintResults(total_skipped_tests_, SkippedResults, &footer);
522 }
523
Christopher Ferris1a993562018-08-21 12:43:50 -0700524 // Tests that ran slow.
525 if (total_slow_tests_ != 0) {
Christopher Ferrisef982172018-09-27 15:19:07 -0700526 PrintResults(total_slow_tests_, SlowResults, &footer);
Christopher Ferris1a993562018-08-21 12:43:50 -0700527 }
528
529 // Tests that passed but should have failed.
530 if (total_xpass_tests_ != 0) {
Christopher Ferrisef982172018-09-27 15:19:07 -0700531 PrintResults(total_xpass_tests_, XpassFailResults, &footer);
Christopher Ferris1a993562018-08-21 12:43:50 -0700532 }
533
534 // Tests that timed out.
535 if (total_timeout_tests_ != 0) {
Christopher Ferrisef982172018-09-27 15:19:07 -0700536 PrintResults(total_timeout_tests_, TimeoutResults, &footer);
Christopher Ferris1a993562018-08-21 12:43:50 -0700537 }
538
539 // Tests that failed.
540 if (total_fail_tests_ != 0) {
Christopher Ferrisef982172018-09-27 15:19:07 -0700541 PrintResults(total_fail_tests_, FailResults, &footer);
Christopher Ferris1a993562018-08-21 12:43:50 -0700542 }
543
544 if (!footer.empty()) {
545 printf("\n%s", footer.c_str());
546 }
547
548 if (total_disable_tests_ != 0) {
549 if (footer.empty()) {
550 printf("\n");
551 }
552 ColoredPrintf(COLOR_YELLOW, " YOU HAVE %s\n\n",
553 PluralizeString(total_disable_tests_, " DISABLED TEST", true).c_str());
554 }
555
556 fflush(stdout);
557}
558
559std::string XmlEscape(const std::string& xml) {
560 std::string escaped;
561 escaped.reserve(xml.size());
562
563 for (auto c : xml) {
564 switch (c) {
565 case '<':
566 escaped.append("&lt;");
567 break;
568 case '>':
569 escaped.append("&gt;");
570 break;
571 case '&':
572 escaped.append("&amp;");
573 break;
574 case '\'':
575 escaped.append("&apos;");
576 break;
577 case '"':
578 escaped.append("&quot;");
579 break;
580 default:
581 escaped.append(1, c);
582 break;
583 }
584 }
585
586 return escaped;
587}
588
589class TestResultPrinter : public ::testing::EmptyTestEventListener {
590 public:
591 TestResultPrinter() : pinfo_(nullptr) {}
592 virtual void OnTestStart(const ::testing::TestInfo& test_info) {
593 pinfo_ = &test_info; // Record test_info for use in OnTestPartResult.
594 }
595 virtual void OnTestPartResult(const ::testing::TestPartResult& result);
596
597 private:
598 const ::testing::TestInfo* pinfo_;
599};
600
601// Called after an assertion failure.
602void TestResultPrinter::OnTestPartResult(const ::testing::TestPartResult& result) {
603 // If the test part succeeded, we don't need to do anything.
604 if (result.type() == ::testing::TestPartResult::kSuccess) {
605 return;
606 }
607
608 // Print failure message from the assertion (e.g. expected this and got that).
609 printf("%s:(%d) Failure in test %s.%s\n%s\n", result.file_name(), result.line_number(),
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700610 pinfo_->test_suite_name(), pinfo_->name(), result.message());
Christopher Ferris1a993562018-08-21 12:43:50 -0700611 fflush(stdout);
612}
613
614// Output xml file when --gtest_output is used, write this function as we can't reuse
615// gtest.cc:XmlUnitTestResultPrinter. The reason is XmlUnitTestResultPrinter is totally
616// defined in gtest.cc and not expose to outside. What's more, as we don't run gtest in
617// the parent process, we don't have gtest classes which are needed by XmlUnitTestResultPrinter.
618void Isolate::WriteXmlResults(uint64_t elapsed_time_ns, time_t start_time) {
619 FILE* fp = fopen(options_.xml_file().c_str(), "w");
620 if (fp == nullptr) {
621 printf("Cannot open xml file '%s': %s\n", options_.xml_file().c_str(), strerror(errno));
622 exit(1);
623 }
624
625 const tm* time_struct = localtime(&start_time);
626 if (time_struct == nullptr) {
627 PLOG(FATAL) << "Unexpected failure from localtime";
628 }
629 char timestamp[40];
630 snprintf(timestamp, sizeof(timestamp), "%4d-%02d-%02dT%02d:%02d:%02d",
631 time_struct->tm_year + 1900, time_struct->tm_mon + 1, time_struct->tm_mday,
632 time_struct->tm_hour, time_struct->tm_min, time_struct->tm_sec);
633
634 fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", fp);
635 fprintf(fp, "<testsuites tests=\"%zu\" failures=\"%zu\" disabled=\"0\" errors=\"0\"",
636 tests_.size(), total_fail_tests_ + total_timeout_tests_ + total_xpass_tests_);
637 fprintf(fp, " timestamp=\"%s\" time=\"%.3lf\" name=\"AllTests\">\n", timestamp,
638 double(elapsed_time_ns) / kNsPerMs);
639
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700640 // Construct the suite information.
641 struct SuiteInfo {
642 std::string suite_name;
Christopher Ferris1a993562018-08-21 12:43:50 -0700643 size_t fails = 0;
644 double elapsed_ms = 0;
645 std::vector<const Test*> tests;
646 };
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700647 std::string last_suite_name;
648 std::vector<SuiteInfo> suites;
649 SuiteInfo* info = nullptr;
Christopher Ferris1a993562018-08-21 12:43:50 -0700650 for (const auto& entry : finished_) {
Christopher Ferrisee59d492018-09-17 15:52:20 -0700651 const Test* test = entry.second.get();
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700652 const std::string& suite_name = test->suite_name();
Christopher Ferris1a993562018-08-21 12:43:50 -0700653 if (test->result() == TEST_XFAIL) {
654 // Skip XFAIL tests.
655 continue;
656 }
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700657 if (last_suite_name != suite_name) {
658 SuiteInfo suite_info{.suite_name = suite_name.substr(0, suite_name.size() - 1)};
659 last_suite_name = suite_name;
660 suites.push_back(suite_info);
661 info = &suites.back();
Christopher Ferris1a993562018-08-21 12:43:50 -0700662 }
663 info->tests.push_back(test);
664 info->elapsed_ms += double(test->RunTimeNs()) / kNsPerMs;
665 if (test->result() != TEST_PASS) {
666 info->fails++;
667 }
668 }
669
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700670 for (auto& suite_entry : suites) {
Christopher Ferris1a993562018-08-21 12:43:50 -0700671 fprintf(fp,
672 " <testsuite name=\"%s\" tests=\"%zu\" failures=\"%zu\" disabled=\"0\" errors=\"0\"",
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700673 suite_entry.suite_name.c_str(), suite_entry.tests.size(), suite_entry.fails);
674 fprintf(fp, " time=\"%.3lf\">\n", suite_entry.elapsed_ms);
Christopher Ferris1a993562018-08-21 12:43:50 -0700675
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700676 for (auto test : suite_entry.tests) {
Christopher Ferris1a993562018-08-21 12:43:50 -0700677 fprintf(fp, " <testcase name=\"%s\" status=\"run\" time=\"%.3lf\" classname=\"%s\"",
678 test->test_name().c_str(), double(test->RunTimeNs()) / kNsPerMs,
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700679 suite_entry.suite_name.c_str());
Christopher Ferris1a993562018-08-21 12:43:50 -0700680 if (test->result() == TEST_PASS) {
681 fputs(" />\n", fp);
682 } else {
683 fputs(">\n", fp);
684 const std::string escaped_output = XmlEscape(test->output());
685 fprintf(fp, " <failure message=\"%s\" type=\"\">\n", escaped_output.c_str());
686 fputs(" </failure>\n", fp);
687 fputs(" </testcase>\n", fp);
688 }
689 }
690 fputs(" </testsuite>\n", fp);
691 }
692 fputs("</testsuites>\n", fp);
693 fclose(fp);
694}
695
696int Isolate::Run() {
697 slow_threshold_ns_ = options_.slow_threshold_ms() * kNsPerMs;
698 deadline_threshold_ns_ = options_.deadline_threshold_ms() * kNsPerMs;
699
700 EnumerateTests();
701
702 // Stop default result printer to avoid environment setup/teardown information for each test.
703 ::testing::UnitTest::GetInstance()->listeners().Release(
704 ::testing::UnitTest::GetInstance()->listeners().default_result_printer());
705 ::testing::UnitTest::GetInstance()->listeners().Append(new TestResultPrinter);
706 RegisterSignalHandler();
707
708 std::string job_info("Running " + PluralizeString(total_tests_, " test") + " from " +
Christopher Ferrisc2f85d62019-03-10 13:40:40 -0700709 PluralizeString(total_suites_, " test suite") + " (" +
Christopher Ferris1a993562018-08-21 12:43:50 -0700710 PluralizeString(options_.job_count(), " job") + ").");
711
712 int exit_code = 0;
713 for (int i = 0; options_.num_iterations() < 0 || i < options_.num_iterations(); i++) {
714 if (i > 0) {
715 printf("\nRepeating all tests (iteration %d) . . .\n\n", i + 1);
716 }
717 ColoredPrintf(COLOR_GREEN, "[==========]");
718 printf(" %s\n", job_info.c_str());
719 fflush(stdout);
720
721 time_t start_time = time(nullptr);
722 uint64_t time_ns = NanoTime();
723 RunAllTests();
724 time_ns = NanoTime() - time_ns;
725
726 PrintFooter(time_ns);
727
728 if (!options_.xml_file().empty()) {
729 WriteXmlResults(time_ns, start_time);
730 }
731
Christopher Ferris849d24e2019-03-09 16:47:04 -0800732 if (total_pass_tests_ + total_skipped_tests_ + total_xfail_tests_ != tests_.size()) {
Christopher Ferris1a993562018-08-21 12:43:50 -0700733 exit_code = 1;
734 }
735 }
736
737 return exit_code;
738}
739
740} // namespace gtest_extras
741} // namespace android