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 |