def test_notify_multiple(self): # Ensure that multiple fibers can be notified, and that the order in # which they are notified is respected. cond = gruvi.Condition() waiting = [0] done = [] def wait_cond(i): with cond: waiting[0] += 1 cond.wait() waiting[0] -= 1 done.append(i) fibers = [] for i in range(10): fibers.append(gruvi.spawn(wait_cond, i)) gruvi.sleep(0) self.assertEqual(waiting[0], 10) with cond: cond.notify(1) gruvi.sleep(0) self.assertEqual(waiting[0], 9) with cond: cond.notify(3) gruvi.sleep(0) self.assertEqual(waiting[0], 6) with cond: cond.notify_all() gruvi.sleep(0) self.assertEqual(waiting[0], 0) self.assertEqual(done, list(range(10)))
def test_wait_for_timeout(self): # When a timeout occurs, wait_for() should return False cond = gruvi.Condition() waiters = [0] def notify_cond(): with cond: waiters[0] += 1 cond.notify() waiters[0] -= 1 gruvi.spawn(notify_cond) with cond: self.assertEqual(waiters[0], 0) self.assertFalse(cond.wait_for(lambda: False, timeout=0.1)) self.assertEqual(waiters[0], 0)
def test_basic(self): # Ensure that a basic wait/notify works. cond = gruvi.Condition() waiting = [0] def wait_cond(): with cond: waiting[0] += 1 cond.wait() waiting[0] -= 1 gruvi.spawn(wait_cond) gruvi.sleep(0) self.assertEqual(waiting[0], 1) with cond: cond.notify() gruvi.sleep(0) self.assertEqual(waiting[0], 0)
def test_wait_for(self): # Ensure that wait_for can wait for a predicate cond = gruvi.Condition() waiting = [0] unblock = [] done = [] def wait_cond(i): with cond: waiting[0] += 1 cond.wait_for(lambda: i in unblock) waiting[0] -= 1 done.append(i) fibers = [] for i in range(10): fibers.append(gruvi.spawn(wait_cond, i)) gruvi.sleep(0) self.assertEqual(waiting[0], 10) with cond: cond.notify(1) # no predicate matches gruvi.sleep(0) self.assertEqual(waiting[0], 10) unblock += [0] with cond: cond.notify(1) # one predicate matches gruvi.sleep(0) self.assertEqual(waiting[0], 9) unblock += [2, 3] with cond: cond.notify(3) # two match gruvi.sleep(0) self.assertEqual(waiting[0], 7) unblock += [1] with cond: cond.notify_all() # one match gruvi.sleep(0) self.assertEqual(waiting[0], 6) unblock += list(range(10)) with cond: cond.notify_all() # one match gruvi.sleep(0) self.assertEqual(waiting[0], 0) self.assertEqual(done, [0, 2, 3, 1, 4, 5, 6, 7, 8, 9])
def test_thread_safety(self): cond = gruvi.Condition() ready = [] result = [] def run_test(): with cond: ready.append(gruvi.current_fiber()) timeout = random.choice((None, 0.1)) result.append(cond.wait(timeout=timeout)) def run_thread(): fibers = [] for i in range(self.nfibers): fibers.append(gruvi.spawn(run_test)) for fib in fibers: fib.join() threads = [] for i in range(self.nthreads): thread = threading.Thread(target=run_thread) thread.start() threads.append(thread) gruvi.sleep(0.2) while len(ready) != self.nthreads * self.nfibers: gruvi.sleep(0.1) with cond: cond.notify_all() for thread in threads: thread.join() timeouts = result.count(False) notified = result.count(True) self.assertEqual(timeouts + notified, self.nthreads * self.nfibers) self.assertGreater(timeouts, 0) self.assertGreater(notified, 0) self.assertFalse(cond._callbacks)
def mem_condition(self): self.add_result(sizeof(gruvi.Condition()))
def test_wait_timeout(self): # When a timeout occurs, wait() should return False cond = gruvi.Condition() with cond: self.assertFalse(cond.wait(timeout=0.01)) self.assertFalse(cond._callbacks)
def test_call_without_lock(self): # A RuntimeError should be raised if notify or wait are called without # the lock. cond = gruvi.Condition() self.assertRaises(RuntimeError, cond.wait) self.assertRaises(RuntimeError, cond.notify)