| Index: testing_support/thread_watcher.py
|
| diff --git a/testing_support/thread_watcher.py b/testing_support/thread_watcher.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ca5180bad59f101c4da41700586ec3b6663d86b5
|
| --- /dev/null
|
| +++ b/testing_support/thread_watcher.py
|
| @@ -0,0 +1,46 @@
|
| +# Copyright (c) 2016 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +
|
| +import sys
|
| +import threading
|
| +import traceback
|
| +import unittest
|
| +
|
| +
|
| +class ThreadWatcherMixIn(object):
|
| + def setUp(self):
|
| + self._pre_test_threads = [t.ident for t in threading.enumerate()]
|
| +
|
| + def tearDown(self):
|
| + post_test_threads = threading.enumerate()
|
| + new_threads = [t for t in post_test_threads
|
| + if t.ident not in self._pre_test_threads]
|
| + if new_threads:
|
| + details = []
|
| + for th in new_threads:
|
| + details.append('\nThread %s stacktrace:\n' % th)
|
| + try:
|
| + details.extend(traceback.format_stack(sys._current_frames()[t.ident]))
|
| + except Exception:
|
| + if t.ident in sys._current_frames():
|
| + raise
|
| + # This can happen due to threads starting or stopping concurrently.
|
| + details.append(' Thread stopped while acquiring stacktrace.\n')
|
| + details = ''.join(details)
|
| +
|
| + self.fail('Found %d running thread(s) after the test.\n%s' % (
|
| + len(new_threads), details))
|
| +
|
| +
|
| +
|
| +class TestCase(unittest.TestCase, ThreadWatcherMixIn):
|
| + """Base unittest class that fails on leaked threads after the test."""
|
| + def setUp(self):
|
| + super(TestCase, self).setUp()
|
| + ThreadWatcherMixIn.setUp(self)
|
| +
|
| + def tearDown(self):
|
| + ThreadWatcherMixIn.tearDown(self)
|
| + super(TestCase, self).tearDown()
|
|
|