| OLD | NEW |
| (Empty) |
| 1 # Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import threading | |
| 6 | |
| 7 class TestCollection(object): | |
| 8 """A threadsafe collection of tests. | |
| 9 | |
| 10 Args: | |
| 11 tests: List of tests to put in the collection. | |
| 12 """ | |
| 13 | |
| 14 def __init__(self, tests=None): | |
| 15 if not tests: | |
| 16 tests = [] | |
| 17 self._lock = threading.Lock() | |
| 18 self._tests = [] | |
| 19 self._tests_in_progress = 0 | |
| 20 # Used to signal that an item is available or all items have been handled. | |
| 21 self._item_available_or_all_done = threading.Event() | |
| 22 for t in tests: | |
| 23 self.add(t) | |
| 24 | |
| 25 def _pop(self): | |
| 26 """Pop a test from the collection. | |
| 27 | |
| 28 Waits until a test is available or all tests have been handled. | |
| 29 | |
| 30 Returns: | |
| 31 A test or None if all tests have been handled. | |
| 32 """ | |
| 33 while True: | |
| 34 # Wait for a test to be available or all tests to have been handled. | |
| 35 self._item_available_or_all_done.wait() | |
| 36 with self._lock: | |
| 37 # Check which of the two conditions triggered the signal. | |
| 38 if self._tests_in_progress == 0: | |
| 39 return None | |
| 40 try: | |
| 41 return self._tests.pop(0) | |
| 42 except IndexError: | |
| 43 # Another thread beat us to the available test, wait again. | |
| 44 self._item_available_or_all_done.clear() | |
| 45 | |
| 46 def add(self, test): | |
| 47 """Add a test to the collection. | |
| 48 | |
| 49 Args: | |
| 50 test: A test to add. | |
| 51 """ | |
| 52 with self._lock: | |
| 53 self._tests.append(test) | |
| 54 self._item_available_or_all_done.set() | |
| 55 self._tests_in_progress += 1 | |
| 56 | |
| 57 def test_completed(self): | |
| 58 """Indicate that a test has been fully handled.""" | |
| 59 with self._lock: | |
| 60 self._tests_in_progress -= 1 | |
| 61 if self._tests_in_progress == 0: | |
| 62 # All tests have been handled, signal all waiting threads. | |
| 63 self._item_available_or_all_done.set() | |
| 64 | |
| 65 def __iter__(self): | |
| 66 """Iterate through tests in the collection until all have been handled.""" | |
| 67 while True: | |
| 68 r = self._pop() | |
| 69 if r is None: | |
| 70 break | |
| 71 yield r | |
| 72 | |
| 73 def __len__(self): | |
| 74 """Return the number of tests currently in the collection.""" | |
| 75 return len(self._tests) | |
| 76 | |
| 77 def test_names(self): | |
| 78 """Return a list of the names of the tests currently in the collection.""" | |
| 79 with self._lock: | |
| 80 return list(t.test for t in self._tests) | |
| OLD | NEW |