Bug 1024669 - Part 2: Test cases for thread name annotation in the crash report. r=gsvelto
☠☠ backed out by fea7bf84ef7f ☠ ☠
authorCervantes Yu <cyu@mozilla.com>
Tue, 07 Feb 2017 18:58:36 +0800
changeset 352231 cf7d1b64cc12699be55b914ac3d0cd29f82f7a49
parent 352230 7a52d887bceaf68b568bf865ba2e0d065465cee6
child 352232 fea7bf84ef7fda7370bbfc58dabbeaac23638f88
push id40446
push userkwierso@gmail.com
push dateMon, 10 Apr 2017 23:55:37 +0000
treeherderautoland@4e4bd12cc11c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgsvelto
bugs1024669
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1024669 - Part 2: Test cases for thread name annotation in the crash report. r=gsvelto MozReview-Commit-ID: 3ahk3hpkfuk
toolkit/crashreporter/moz.build
toolkit/crashreporter/test/gtest/TestCrashThreadAnnotation.cpp
toolkit/crashreporter/test/gtest/moz.build
toolkit/crashreporter/test/unit/test_crash_thread_annotation.js
toolkit/crashreporter/test/unit/xpcshell.ini
--- a/toolkit/crashreporter/moz.build
+++ b/toolkit/crashreporter/moz.build
@@ -49,16 +49,19 @@ DIRS += [
 
 if CONFIG['MOZ_CRASHREPORTER_INJECTOR']:
     DIRS += ['injector']
     UNIFIED_SOURCES += [
         'InjectCrashReporter.cpp',
         'LoadLibraryRemote.cpp',
     ]
 
+if CONFIG['ENABLE_TESTS']:
+    DIRS += ['test/gtest']
+
 TEST_DIRS += ['test']
 
 EXPORTS += [
     'nsExceptionHandler.h',
 ]
 
 UNIFIED_SOURCES += [
     'nsExceptionHandler.cpp',
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/test/gtest/TestCrashThreadAnnotation.cpp
@@ -0,0 +1,259 @@
+/* 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 "gtest/gtest.h"
+#include "mozilla/Monitor.h"
+#include "mozilla/Unused.h"
+#include "nsIThread.h"
+#include "nsIRunnable.h"
+#include "nsThreadUtils.h"
+
+using mozilla::Monitor;
+using mozilla::MonitorAutoLock;
+
+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([aName, &aMonitor, &aDone] () -> void {
+    NS_SetCurrentThreadName(aName);
+
+    MonitorAutoLock lock(aMonitor);
+    aDone = true;
+    aMonitor.NotifyAll();
+  });
+  nsCOMPtr<nsIThread> thread;
+  nsresult rv = NS_NewThread(getter_AddRefs(thread), setNameRunnable);
+  mozilla::Unused << rv;
+
+  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();
+}
+
+TEST(TestCrashThreadAnnotation, TestGetFlatThreadAnnotation_SetNameTwice)
+{
+  InitThreadAnnotation();
+
+  Monitor monitor("TestCrashThreadAnnotation");
+  bool threadNameSet = false;
+
+  nsCOMPtr<nsIRunnable> setNameRunnable = NS_NewRunnableFunction([&] () -> 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_NewThread(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();
+}
+
+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();
+}
+
+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();
+}
+
+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();
+}
+
+} // Anonymous namespace.
+} // namespace CrashReporter
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/test/gtest/moz.build
@@ -0,0 +1,17 @@
+# -*- 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'
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/test/unit/test_crash_thread_annotation.js
@@ -0,0 +1,15 @@
+function run_test() {
+  if (!("@mozilla.org/toolkit/crash-reporter;1" in Components.classes)) {
+    dump("INFO | test_crash_thread_annotation.js | Can't test crashreporter in a non-libxul build.\n");
+    return;
+  }
+
+  do_crash(
+    function() {
+      crashType = CrashTestUtils.CRASH_INVALID_POINTER_DEREF;
+    },
+    function(mdump, extra) {
+      do_check_true("ThreadIdNameMapping" in extra);
+    },
+    true);
+}
--- a/toolkit/crashreporter/test/unit/xpcshell.ini
+++ b/toolkit/crashreporter/test/unit/xpcshell.ini
@@ -18,16 +18,19 @@ skip-if = os == 'win' && bits == 64
 [test_crash_oom.js]
 [test_oom_annotation_windows.js]
 skip-if = os != 'win'
 
 [test_crash_abort.js]
 skip-if = os == 'win'
 
 [test_crash_uncaught_exception.js]
+
+[test_crash_thread_annotation.js]
+
 [test_crash_with_memory_report.js]
 [test_crashreporter.js]
 [test_crashreporter_crash.js]
 [test_override_exception_handler.js]
 skip-if = os != 'win'
 
 [test_crashreporter_appmem.js]
 # we need to skip this due to bug 838613