mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 22:16:13 +00:00
ios: Add ability to reset Crashpad client for iOS tests.
Change-Id: I83df67d77367ef01731bd9af015605cfa19e972e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3418581 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org>
This commit is contained in:
parent
36ad571862
commit
55eb7a2eaf
@ -558,6 +558,11 @@ class CrashpadClient {
|
||||
static void DumpWithoutCrashAndDeferProcessingAtPath(
|
||||
NativeCPUContext* context,
|
||||
const base::FilePath path);
|
||||
|
||||
//! \brief Unregister the Crashpad client. Intended to be used by tests so
|
||||
//! multiple Crashpad clients can be started and stopped. Not expected to
|
||||
//! be used in a shipping application.
|
||||
static void ResetForTesting();
|
||||
#endif
|
||||
|
||||
#if BUILDFLAG(IS_APPLE) || DOXYGEN
|
||||
|
@ -60,8 +60,14 @@ class CrashHandler : public Thread,
|
||||
CrashHandler& operator=(const CrashHandler&) = delete;
|
||||
|
||||
static CrashHandler* Get() {
|
||||
static CrashHandler* instance = new CrashHandler();
|
||||
return instance;
|
||||
if (!instance_)
|
||||
instance_ = new CrashHandler();
|
||||
return instance_;
|
||||
}
|
||||
|
||||
static void ResetForTesting() {
|
||||
delete instance_;
|
||||
instance_ = nullptr;
|
||||
}
|
||||
|
||||
bool Initialize(const base::FilePath& database,
|
||||
@ -148,6 +154,12 @@ class CrashHandler : public Thread,
|
||||
private:
|
||||
CrashHandler() = default;
|
||||
|
||||
~CrashHandler() {
|
||||
UninstallObjcExceptionPreprocessor();
|
||||
Signals::InstallDefaultHandler(SIGABRT);
|
||||
UninstallMachExceptionHandler();
|
||||
}
|
||||
|
||||
bool InstallMachExceptionHandler() {
|
||||
exception_port_.reset(NewMachPort(MACH_PORT_RIGHT_RECEIVE));
|
||||
if (!exception_port_.is_valid()) {
|
||||
@ -180,15 +192,22 @@ class CrashHandler : public Thread,
|
||||
return false;
|
||||
}
|
||||
|
||||
mach_handler_running_ = true;
|
||||
Start();
|
||||
return true;
|
||||
}
|
||||
|
||||
void UninstallMachExceptionHandler() {
|
||||
mach_handler_running_ = false;
|
||||
exception_port_.reset();
|
||||
Join();
|
||||
}
|
||||
|
||||
// Thread:
|
||||
|
||||
void ThreadMain() override {
|
||||
UniversalMachExcServer universal_mach_exc_server(this);
|
||||
while (true) {
|
||||
while (mach_handler_running_) {
|
||||
mach_msg_return_t mr =
|
||||
MachMessageServer::Run(&universal_mach_exc_server,
|
||||
exception_port_.get(),
|
||||
@ -196,7 +215,10 @@ class CrashHandler : public Thread,
|
||||
MachMessageServer::kPersistent,
|
||||
MachMessageServer::kReceiveLargeIgnore,
|
||||
kMachMessageTimeoutWaitIndefinitely);
|
||||
MACH_CHECK(mr == MACH_SEND_INVALID_DEST, mr) << "MachMessageServer::Run";
|
||||
MACH_CHECK(mr == (mach_handler_running_ ? MACH_SEND_INVALID_DEST
|
||||
: MACH_RCV_PORT_CHANGED),
|
||||
mr)
|
||||
<< "MachMessageServer::Run";
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,9 +335,13 @@ class CrashHandler : public Thread,
|
||||
struct sigaction old_action_ = {};
|
||||
internal::InProcessHandler in_process_handler_;
|
||||
internal::IOSSystemDataCollector system_data_;
|
||||
static CrashHandler* instance_;
|
||||
bool mach_handler_running_ = false;
|
||||
InitializationStateDcheck initialized_;
|
||||
};
|
||||
|
||||
CrashHandler* CrashHandler::instance_ = nullptr;
|
||||
|
||||
} // namespace
|
||||
|
||||
CrashpadClient::CrashpadClient() {}
|
||||
@ -380,4 +406,10 @@ void CrashpadClient::DumpWithoutCrashAndDeferProcessingAtPath(
|
||||
crash_handler->DumpWithoutCrashAtPath(context, path);
|
||||
}
|
||||
|
||||
void CrashpadClient::ResetForTesting() {
|
||||
CrashHandler* crash_handler = CrashHandler::Get();
|
||||
DCHECK(crash_handler);
|
||||
crash_handler->ResetForTesting();
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -30,45 +30,61 @@ namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
using CrashpadIOSClient = PlatformTest;
|
||||
class CrashpadIOSClient : public testing::Test {
|
||||
protected:
|
||||
// testing::Test:
|
||||
|
||||
void SetUp() override {
|
||||
ASSERT_TRUE(client_.StartCrashpadInProcessHandler(
|
||||
base::FilePath(database_dir.path()), "", {}));
|
||||
database_ = CrashReportDatabase::Initialize(database_dir.path());
|
||||
}
|
||||
|
||||
void TearDown() override { client_.ResetForTesting(); }
|
||||
|
||||
auto& Client() { return client_; }
|
||||
auto& Database() { return database_; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<CrashReportDatabase> database_;
|
||||
CrashpadClient client_;
|
||||
ScopedTempDir database_dir;
|
||||
};
|
||||
|
||||
TEST_F(CrashpadIOSClient, DumpWithoutCrash) {
|
||||
CrashpadClient client;
|
||||
ScopedTempDir database_dir;
|
||||
ASSERT_TRUE(client.StartCrashpadInProcessHandler(
|
||||
base::FilePath(database_dir.path()), "", {}));
|
||||
std::unique_ptr<CrashReportDatabase> database =
|
||||
CrashReportDatabase::Initialize(database_dir.path());
|
||||
std::vector<CrashReportDatabase::Report> reports;
|
||||
EXPECT_EQ(database->GetPendingReports(&reports),
|
||||
EXPECT_EQ(Database()->GetPendingReports(&reports),
|
||||
CrashReportDatabase::kNoError);
|
||||
ASSERT_EQ(reports.size(), 0u);
|
||||
CRASHPAD_SIMULATE_CRASH();
|
||||
reports.clear();
|
||||
EXPECT_EQ(database->GetPendingReports(&reports),
|
||||
|
||||
EXPECT_EQ(Database()->GetPendingReports(&reports),
|
||||
CrashReportDatabase::kNoError);
|
||||
ASSERT_EQ(reports.size(), 1u);
|
||||
}
|
||||
|
||||
TEST_F(CrashpadIOSClient, DumpWithoutCrashAndDefer) {
|
||||
std::vector<CrashReportDatabase::Report> reports;
|
||||
CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING();
|
||||
reports.clear();
|
||||
EXPECT_EQ(database->GetPendingReports(&reports),
|
||||
EXPECT_EQ(Database()->GetPendingReports(&reports),
|
||||
CrashReportDatabase::kNoError);
|
||||
ASSERT_EQ(reports.size(), 0u);
|
||||
Client().ProcessIntermediateDumps();
|
||||
EXPECT_EQ(Database()->GetPendingReports(&reports),
|
||||
CrashReportDatabase::kNoError);
|
||||
ASSERT_EQ(reports.size(), 1u);
|
||||
client.ProcessIntermediateDumps();
|
||||
reports.clear();
|
||||
EXPECT_EQ(database->GetPendingReports(&reports),
|
||||
CrashReportDatabase::kNoError);
|
||||
ASSERT_EQ(reports.size(), 2u);
|
||||
}
|
||||
|
||||
TEST_F(CrashpadIOSClient, DumpWithoutCrashAndDeferAtPath) {
|
||||
std::vector<CrashReportDatabase::Report> reports;
|
||||
ScopedTempDir crash_dir;
|
||||
UUID uuid;
|
||||
uuid.InitializeWithNew();
|
||||
CRASHPAD_SIMULATE_CRASH_AND_DEFER_PROCESSING_AT_PATH(
|
||||
crash_dir.path().Append(uuid.ToString()));
|
||||
reports.clear();
|
||||
EXPECT_EQ(database->GetPendingReports(&reports),
|
||||
EXPECT_EQ(Database()->GetPendingReports(&reports),
|
||||
CrashReportDatabase::kNoError);
|
||||
ASSERT_EQ(reports.size(), 2u);
|
||||
ASSERT_EQ(reports.size(), 0u);
|
||||
|
||||
NSError* error = nil;
|
||||
NSArray* paths = [[NSFileManager defaultManager]
|
||||
@ -76,12 +92,12 @@ TEST_F(CrashpadIOSClient, DumpWithoutCrash) {
|
||||
crash_dir.path().value())
|
||||
error:&error];
|
||||
ASSERT_EQ([paths count], 1u);
|
||||
client.ProcessIntermediateDump(
|
||||
Client().ProcessIntermediateDump(
|
||||
crash_dir.path().Append([paths[0] fileSystemRepresentation]));
|
||||
reports.clear();
|
||||
EXPECT_EQ(database->GetPendingReports(&reports),
|
||||
EXPECT_EQ(Database()->GetPendingReports(&reports),
|
||||
CrashReportDatabase::kNoError);
|
||||
ASSERT_EQ(reports.size(), 3u);
|
||||
ASSERT_EQ(reports.size(), 1u);
|
||||
}
|
||||
|
||||
// This test is covered by a similar XCUITest, but for development purposes it's
|
||||
@ -89,10 +105,6 @@ TEST_F(CrashpadIOSClient, DumpWithoutCrash) {
|
||||
// to correctly run this in Google Test. Leave the test here, disabled, for use
|
||||
// during development only.
|
||||
TEST_F(CrashpadIOSClient, DISABLED_ThrowNSException) {
|
||||
CrashpadClient client;
|
||||
ScopedTempDir database_dir;
|
||||
ASSERT_TRUE(client.StartCrashpadInProcessHandler(
|
||||
base::FilePath(database_dir.path()), "", {}));
|
||||
[NSException raise:@"GoogleTestNSException" format:@"ThrowException"];
|
||||
}
|
||||
|
||||
@ -101,10 +113,6 @@ TEST_F(CrashpadIOSClient, DISABLED_ThrowNSException) {
|
||||
// to correctly run this in Google Test. Leave the test here, disabled, for use
|
||||
// during development only.
|
||||
TEST_F(CrashpadIOSClient, DISABLED_ThrowException) {
|
||||
CrashpadClient client;
|
||||
ScopedTempDir database_dir;
|
||||
ASSERT_TRUE(client.StartCrashpadInProcessHandler(
|
||||
base::FilePath(database_dir.path()), "", {}));
|
||||
std::vector<int> empty_vector;
|
||||
empty_vector.at(42);
|
||||
}
|
||||
|
@ -59,6 +59,10 @@ class ObjcExceptionDelegate {
|
||||
//! signal handler. It should only be installed once.
|
||||
void InstallObjcExceptionPreprocessor(ObjcExceptionDelegate* delegate);
|
||||
|
||||
//! \brief Uninstalls the Objective-C exception preprocessor. Expected to be
|
||||
//! used by tests only.
|
||||
void UninstallObjcExceptionPreprocessor();
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_IOS_EXCEPTION_PROCESSOR_H_
|
||||
|
Loading…
x
Reference in New Issue
Block a user