flutter_flutter/testing/run_all_unittests.cc
Chinmay Garde 7c2d975b55
Gather demangled stack traces and report the same to console on crashes. (#16450)
These should only be used on host binaries for more detailed crash reports.
Installing the handler on targets (iOS/Android) may cause use to break existing
crash reporting mechanisms users may have installed themselves in the process.

This should work on Darwin & Linux for now.

Doing something like int* a = nullptr; *a = 12; or abort or tripping an
assertion should print something the following before program termination. We
can tweak the report further if necessary.

```
[ERROR:flutter/fml/backtrace.cc(110)] Caught signal SIGSEGV during program execution.
Frame 0: 0x10658342c void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*)
Frame 1: 0x106555070 void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*)
Frame 2: 0x106554f81 testing::Test::Run()
Frame 3: 0x106555dc3 testing::TestInfo::Run()
Frame 4: 0x1065570a1 testing::TestSuite::Run()
Frame 5: 0x106562a55 testing::internal::UnitTestImpl::RunAllTests()
Frame 6: 0x10658c22c bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*)
Frame 7: 0x1065625c3 bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*)
Frame 8: 0x106562445 testing::UnitTest::Run()
Frame 9: 0x105c8dc33 RUN_ALL_TESTS()
Frame 10: 0x105c8dbe6 main
Frame 11: 0x7fff7c2dc3d5 start
```

Known issue: This routines that generate the stack trace are not signal safe.
But since we only use the same before the process is terminating, this ought to
be fine. I’ll work in a separate patch to convert all the internals to be signal
safe. In the meantime, this will help us better identify the causes of flakes on
our bots.

Fixes https://github.com/flutter/flutter/issues/50244
2020-03-10 16:31:06 -07:00

71 lines
2.1 KiB
C++

// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <iostream>
#include <optional>
#include <string>
#include "flutter/fml/backtrace.h"
#include "flutter/fml/build_config.h"
#include "flutter/fml/command_line.h"
#include "flutter/testing/debugger_detection.h"
#include "flutter/testing/test_timeout_listener.h"
#include "gtest/gtest.h"
#ifdef OS_IOS
#include <asl.h>
#endif // OS_IOS
std::optional<fml::TimeDelta> GetTestTimeoutFromArgs(int argc, char** argv) {
const auto command_line = fml::CommandLineFromArgcArgv(argc, argv);
std::string timeout_seconds;
if (!command_line.GetOptionValue("timeout", &timeout_seconds)) {
// No timeout specified. Default to 30s.
return fml::TimeDelta::FromSeconds(30u);
}
const auto seconds = std::stoi(timeout_seconds);
if (seconds < 1) {
return std::nullopt;
}
return fml::TimeDelta::FromSeconds(seconds);
}
int main(int argc, char** argv) {
fml::InstallCrashHandler();
#ifdef OS_IOS
asl_log_descriptor(NULL, NULL, ASL_LEVEL_NOTICE, STDOUT_FILENO,
ASL_LOG_DESCRIPTOR_WRITE);
asl_log_descriptor(NULL, NULL, ASL_LEVEL_ERR, STDERR_FILENO,
ASL_LOG_DESCRIPTOR_WRITE);
#endif // OS_IOS
::testing::InitGoogleTest(&argc, argv);
// Check if the user has specified a timeout.
const auto timeout = GetTestTimeoutFromArgs(argc, argv);
if (!timeout.has_value()) {
FML_LOG(INFO) << "Timeouts disabled via a command line flag.";
return RUN_ALL_TESTS();
}
// Check if the user is debugging the process.
if (flutter::testing::GetDebuggerStatus() ==
flutter::testing::DebuggerStatus::kAttached) {
FML_LOG(INFO) << "Debugger is attached. Suspending test timeouts.";
return RUN_ALL_TESTS();
}
auto timeout_listener =
new flutter::testing::TestTimeoutListener(timeout.value());
auto& listeners = ::testing::UnitTest::GetInstance()->listeners();
listeners.Append(timeout_listener);
auto result = RUN_ALL_TESTS();
delete listeners.Release(timeout_listener);
return result;
}