summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/test/gtest
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/test/gtest')
-rw-r--r--toolkit/crashreporter/test/gtest/TestCrashThreadAnnotation.cpp362
-rw-r--r--toolkit/crashreporter/test/gtest/moz.build15
2 files changed, 377 insertions, 0 deletions
diff --git a/toolkit/crashreporter/test/gtest/TestCrashThreadAnnotation.cpp b/toolkit/crashreporter/test/gtest/TestCrashThreadAnnotation.cpp
new file mode 100644
index 0000000000..78362e2b5e
--- /dev/null
+++ b/toolkit/crashreporter/test/gtest/TestCrashThreadAnnotation.cpp
@@ -0,0 +1,362 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ThreadAnnotation.h"
+
+#include <string.h>
+
+#include "base/thread.h"
+#include "gtest/gtest.h"
+#include "mozilla/Monitor.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Unused.h"
+#include "nsIThread.h"
+#include "nsIRunnable.h"
+#include "nsThreadUtils.h"
+
+using mozilla::Monitor;
+using mozilla::MonitorAutoLock;
+using mozilla::UniquePtr;
+
+namespace CrashReporter {
+namespace {
+
+TEST(TestCrashThreadAnnotation, TestInitShutdown)
+{
+ InitThreadAnnotation();
+ ShutdownThreadAnnotation();
+}
+
+TEST(TestCrashThreadAnnotation, TestNestedInitShutdown)
+{
+ // No bad things should happen in case we have extra init/shutdown calls.
+ InitThreadAnnotation();
+ InitThreadAnnotation();
+ ShutdownThreadAnnotation();
+ ShutdownThreadAnnotation();
+}
+
+TEST(TestCrashThreadAnnotation, TestUnbalancedInit)
+{
+ // No bad things should happen in case we have unbalanced init/shutdown calls.
+ InitThreadAnnotation();
+ InitThreadAnnotation();
+ ShutdownThreadAnnotation();
+}
+
+TEST(TestCrashThreadAnnotation, TestUnbalancedShutdown)
+{
+ // No bad things should happen in case we have unbalanced init/shutdown calls.
+ InitThreadAnnotation();
+ ShutdownThreadAnnotation();
+ ShutdownThreadAnnotation();
+}
+
+TEST(TestCrashThreadAnnotation, TestGetFlatThreadAnnotation_BeforeInit)
+{
+ // GetFlatThreadAnnotation() should not return anything before init.
+ std::function<void(const char*)> getThreadAnnotationCB =
+ [&](const char* aAnnotation) -> void { ASSERT_STREQ(aAnnotation, ""); };
+ GetFlatThreadAnnotation(getThreadAnnotationCB);
+}
+
+TEST(TestCrashThreadAnnotation, TestGetFlatThreadAnnotation_AfterShutdown)
+{
+ // GetFlatThreadAnnotation() should not return anything after shutdown.
+ InitThreadAnnotation();
+ ShutdownThreadAnnotation();
+
+ std::function<void(const char*)> getThreadAnnotationCB =
+ [&](const char* aAnnotation) -> void { ASSERT_STREQ(aAnnotation, ""); };
+ GetFlatThreadAnnotation(getThreadAnnotationCB);
+}
+
+already_AddRefed<nsIThread> CreateTestThread(const char* aName,
+ Monitor& aMonitor, bool& aDone) {
+ nsCOMPtr<nsIRunnable> setNameRunnable = NS_NewRunnableFunction(
+ "CrashReporter::CreateTestThread", [aName, &aMonitor, &aDone]() -> void {
+ NS_SetCurrentThreadName(aName);
+
+ MonitorAutoLock lock(aMonitor);
+ aDone = true;
+ aMonitor.NotifyAll();
+ });
+ nsCOMPtr<nsIThread> thread;
+ mozilla::Unused << NS_NewNamedThread("Test Thread", getter_AddRefs(thread),
+ setNameRunnable);
+
+ return thread.forget();
+}
+
+TEST(TestCrashThreadAnnotation, TestGetFlatThreadAnnotation_OneThread)
+{
+ InitThreadAnnotation();
+
+ Monitor monitor("TestCrashThreadAnnotation");
+ bool threadNameSet = false;
+ nsCOMPtr<nsIThread> thread =
+ CreateTestThread("Thread1", monitor, threadNameSet);
+ ASSERT_TRUE(!!thread);
+
+ {
+ MonitorAutoLock lock(monitor);
+ while (!threadNameSet) {
+ monitor.Wait();
+ }
+ }
+
+ std::function<void(const char*)> getThreadAnnotationCB =
+ [&](const char* aAnnotation) -> void {
+ ASSERT_TRUE(!!strstr(aAnnotation, "Thread1"));
+ };
+ GetFlatThreadAnnotation(getThreadAnnotationCB);
+
+ ShutdownThreadAnnotation();
+
+ thread->Shutdown();
+}
+
+TEST(TestCrashThreadAnnotation, TestGetFlatThreadAnnotation_SetNameTwice)
+{
+ InitThreadAnnotation();
+
+ Monitor monitor("TestCrashThreadAnnotation");
+ bool threadNameSet = false;
+
+ nsCOMPtr<nsIRunnable> setNameRunnable = NS_NewRunnableFunction(
+ "CrashReporter::TestCrashThreadAnnotation_TestGetFlatThreadAnnotation_"
+ "SetNameTwice_Test::TestBody",
+ [&]() -> void {
+ NS_SetCurrentThreadName("Thread1");
+ // Set the name again. We should get the latest name.
+ NS_SetCurrentThreadName("Thread1Again");
+
+ MonitorAutoLock lock(monitor);
+ threadNameSet = true;
+ monitor.NotifyAll();
+ });
+ nsCOMPtr<nsIThread> thread;
+ nsresult rv =
+ NS_NewNamedThread("Test Thread", getter_AddRefs(thread), setNameRunnable);
+ ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+ {
+ MonitorAutoLock lock(monitor);
+ while (!threadNameSet) {
+ monitor.Wait();
+ }
+ }
+
+ std::function<void(const char*)> getThreadAnnotationCB =
+ [&](const char* aAnnotation) -> void {
+ ASSERT_TRUE(!!strstr(aAnnotation, "Thread1Again"));
+ };
+ GetFlatThreadAnnotation(getThreadAnnotationCB);
+
+ ShutdownThreadAnnotation();
+
+ thread->Shutdown();
+}
+
+TEST(TestCrashThreadAnnotation, TestGetFlatThreadAnnotation_TwoThreads)
+{
+ InitThreadAnnotation();
+
+ Monitor monitor("TestCrashThreadAnnotation");
+ bool thread1NameSet = false;
+ bool thread2NameSet = false;
+
+ nsCOMPtr<nsIThread> thread1 =
+ CreateTestThread("Thread1", monitor, thread1NameSet);
+ ASSERT_TRUE(!!thread1);
+
+ nsCOMPtr<nsIThread> thread2 =
+ CreateTestThread("Thread2", monitor, thread2NameSet);
+ ASSERT_TRUE(!!thread2);
+
+ {
+ MonitorAutoLock lock(monitor);
+ while (!(thread1NameSet && thread2NameSet)) {
+ monitor.Wait();
+ }
+ }
+
+ std::function<void(const char*)> getThreadAnnotationCB =
+ [&](const char* aAnnotation) -> void {
+ // Assert that Thread1 and Thread2 are both in the annotation data.
+ ASSERT_TRUE(!!strstr(aAnnotation, "Thread1"));
+ ASSERT_TRUE(!!strstr(aAnnotation, "Thread2"));
+ };
+ GetFlatThreadAnnotation(getThreadAnnotationCB);
+
+ ShutdownThreadAnnotation();
+
+ thread1->Shutdown();
+ thread2->Shutdown();
+}
+
+TEST(TestCrashThreadAnnotation, TestGetFlatThreadAnnotation_ShutdownOneThread)
+{
+ InitThreadAnnotation();
+
+ Monitor monitor("TestCrashThreadAnnotation");
+ bool thread1NameSet = false;
+ bool thread2NameSet = false;
+
+ nsCOMPtr<nsIThread> thread1 =
+ CreateTestThread("Thread1", monitor, thread1NameSet);
+ ASSERT_TRUE(!!thread1);
+
+ nsCOMPtr<nsIThread> thread2 =
+ CreateTestThread("Thread2", monitor, thread2NameSet);
+ ASSERT_TRUE(!!thread2);
+
+ {
+ MonitorAutoLock lock(monitor);
+ while (!(thread1NameSet && thread2NameSet)) {
+ monitor.Wait();
+ }
+ }
+
+ nsresult rv = thread1->Shutdown();
+ ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+ std::function<void(const char*)> getThreadAnnotationCB =
+ [&](const char* aAnnotation) -> void {
+ // Assert that only Thread2 is present in the annotation data.
+ ASSERT_TRUE(!strstr(aAnnotation, "Thread1"));
+ ASSERT_TRUE(!!strstr(aAnnotation, "Thread2"));
+ };
+ GetFlatThreadAnnotation(getThreadAnnotationCB);
+
+ ShutdownThreadAnnotation();
+
+ thread2->Shutdown();
+}
+
+TEST(TestCrashThreadAnnotation, TestGetFlatThreadAnnotation_ShutdownBothThreads)
+{
+ InitThreadAnnotation();
+
+ Monitor monitor("TestCrashThreadAnnotation");
+ bool thread1NameSet = false;
+ bool thread2NameSet = false;
+
+ nsCOMPtr<nsIThread> thread1 =
+ CreateTestThread("Thread1", monitor, thread1NameSet);
+ ASSERT_TRUE(!!thread1);
+
+ nsCOMPtr<nsIThread> thread2 =
+ CreateTestThread("Thread2", monitor, thread2NameSet);
+ ASSERT_TRUE(!!thread2);
+
+ {
+ MonitorAutoLock lock(monitor);
+ while (!(thread1NameSet && thread2NameSet)) {
+ monitor.Wait();
+ }
+ }
+
+ nsresult rv = thread1->Shutdown();
+ ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+ rv = thread2->Shutdown();
+ ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+ std::function<void(const char*)> getThreadAnnotationCB =
+ [&](const char* aAnnotation) -> void {
+ // No leftover in annnotation data.
+ ASSERT_STREQ(aAnnotation, "");
+ };
+ GetFlatThreadAnnotation(getThreadAnnotationCB);
+
+ ShutdownThreadAnnotation();
+}
+
+TEST(TestCrashThreadAnnotation,
+ TestGetFlatThreadAnnotation_TestNameOfBaseThread)
+{
+ InitThreadAnnotation();
+
+ Monitor monitor("TestCrashThreadAnnotation");
+
+ UniquePtr<base::Thread> thread1 =
+ mozilla::MakeUnique<base::Thread>("base thread 1");
+ ASSERT_TRUE(!!thread1 && thread1->Start());
+
+ UniquePtr<base::Thread> thread2 =
+ mozilla::MakeUnique<base::Thread>("base thread 2");
+ ASSERT_TRUE(!!thread2 && thread2->Start());
+
+ std::function<void(const char*)> getThreadAnnotationCB =
+ [&](const char* aAnnotation) -> void {
+ ASSERT_TRUE(!!strstr(aAnnotation, "base thread 1"));
+ ASSERT_TRUE(!!strstr(aAnnotation, "base thread 2"));
+ };
+ GetFlatThreadAnnotation(getThreadAnnotationCB);
+
+ thread1->Stop();
+ thread2->Stop();
+
+ ShutdownThreadAnnotation();
+}
+
+TEST(TestCrashThreadAnnotation,
+ TestGetFlatThreadAnnotation_TestShutdownBaseThread)
+{
+ InitThreadAnnotation();
+
+ Monitor monitor("TestCrashThreadAnnotation");
+
+ UniquePtr<base::Thread> thread1 =
+ mozilla::MakeUnique<base::Thread>("base thread 1");
+ ASSERT_TRUE(!!thread1 && thread1->Start());
+
+ UniquePtr<base::Thread> thread2 =
+ mozilla::MakeUnique<base::Thread>("base thread 2");
+ ASSERT_TRUE(!!thread2 && thread2->Start());
+
+ thread1->Stop();
+
+ std::function<void(const char*)> getThreadAnnotationCB =
+ [&](const char* aAnnotation) -> void {
+ ASSERT_TRUE(!strstr(aAnnotation, "base thread 1"));
+ ASSERT_TRUE(!!strstr(aAnnotation, "base thread 2"));
+ };
+ GetFlatThreadAnnotation(getThreadAnnotationCB);
+
+ thread2->Stop();
+
+ ShutdownThreadAnnotation();
+}
+
+TEST(TestCrashThreadAnnotation,
+ TestGetFlatThreadAnnotation_TestShutdownBothBaseThreads)
+{
+ InitThreadAnnotation();
+
+ Monitor monitor("TestCrashThreadAnnotation");
+
+ UniquePtr<base::Thread> thread1 =
+ mozilla::MakeUnique<base::Thread>("base thread 1");
+ ASSERT_TRUE(!!thread1 && thread1->Start());
+
+ UniquePtr<base::Thread> thread2 =
+ mozilla::MakeUnique<base::Thread>("base thread 2");
+ ASSERT_TRUE(!!thread2 && thread2->Start());
+
+ thread1->Stop();
+ thread2->Stop();
+
+ std::function<void(const char*)> getThreadAnnotationCB =
+ [&](const char* aAnnotation) -> void {
+ ASSERT_TRUE(!strlen(aAnnotation));
+ };
+ GetFlatThreadAnnotation(getThreadAnnotationCB);
+
+ ShutdownThreadAnnotation();
+}
+
+} // Anonymous namespace.
+} // namespace CrashReporter
diff --git a/toolkit/crashreporter/test/gtest/moz.build b/toolkit/crashreporter/test/gtest/moz.build
new file mode 100644
index 0000000000..576a53d3ac
--- /dev/null
+++ b/toolkit/crashreporter/test/gtest/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+UNIFIED_SOURCES += [
+ "TestCrashThreadAnnotation.cpp",
+]
+
+include("/ipc/chromium/chromium-config.mozbuild")
+
+LOCAL_INCLUDES += ["../../"]
+
+FINAL_LIBRARY = "xul-gtest"