def test_fiber_safety_timeout(self): # Test correctness of the lock in case of timeouts. lock = self.Lock() order = [] def run_test(ix): lock.acquire() order.append(ix) lock.release() fibers = [] for i in range(self.nfibers): fibers.append(gruvi.spawn(run_test, i)) # There's 5 elements in lock._waiter now. Kill the first one, and # schedule a cancel for the second one. Both conditions should be # handled appropriately and no deadlocks should happen. lock.acquire() gruvi.sleep(0) # make sure all fibers are waiting on lock.acquire() fibers[0].cancel() gruvi.sleep(0) # first one will be gone self.assertFalse(fibers[0].is_alive()) fibers[1].cancel() # a Cancelled is now scheduled for number two self.assertTrue(fibers[1].is_alive()) lock.release() for fib in fibers: fib.join() # All fibers should have gotten the lock except 1 and 2. self.assertEqual(order, list(range(2, len(fibers))))
def test_send_message_incremental(self): # Send a message byte by byte. The protocol should be able process it. transport = MockTransport() protocol = DbusProtocol(True, self.store_messages, 'foo') transport.start(protocol) authexchange = b'\0AUTH ANONYMOUS\r\nBEGIN\r\n' for i in range(len(authexchange)): protocol.data_received(authexchange[i:i+1]) auth = protocol._authenticator self.assertTrue(auth.authenticationSucceeded()) message = txdbus.MethodCallMessage('/org/freedesktop/DBus', 'Hello', interface='org.freedesktop.DBus', destination='org.freedesktop.DBus') for i in range(len(message.rawMessage)): protocol.data_received(message.rawMessage[i:i+1]) gruvi.sleep(0) self.assertIsNone(protocol._error) self.assertFalse(transport.closed) self.assertEqual(len(self.messages), 0) message = txdbus.MethodCallMessage('/my/path', 'Method') for i in range(len(message.rawMessage)): protocol.data_received(message.rawMessage[i:i+1]) gruvi.sleep(0) self.assertIsNone(protocol._error) self.assertFalse(transport.closed) self.assertEqual(len(self.messages), 1) self.assertEqual(self.messages[0].path, '/my/path') self.assertEqual(self.messages[0].member, 'Method') self.assertEqual(self.protocols, [protocol])
def test_ssl_no_handshake_on_connect(self): # Ensure that when create_connection(ssl=True) returns, that the SSL # handshake has completed. context = self.get_ssl_context() server = create_server(StreamProtocol, ('localhost', 0), ssl=context) addr = server.addresses[0] ssl_args = {'do_handshake_on_connect': False} ctrans, cproto = create_connection(StreamProtocol, addr, ssl=context, ssl_args=ssl_args) # The SSL handshake has not been established at this point. sslobj = ctrans.get_extra_info('ssl') self.assertIsNone(sslobj) # Now initiate the SSL handshake and allow it some time to complete ctrans.do_handshake() gruvi.sleep(0.1) # There should be a channel binding now. sslobj = ctrans.get_extra_info('ssl') self.assertIsNotNone(sslobj) sslcb = sslobj.get_channel_binding('tls-unique') self.assertGreater(len(sslcb), 0) strans, sproto = list(server.connections)[0] cproto.stream.write(b'foo\n') self.assertEqual(sproto.stream.readline(), b'foo\n') server.close() self.assertEqual(len(list(server.connections)), 0) self.assertEqual(cproto.stream.readline(), b'') ctrans.close()
def test_timeout(self): # Ensure that the timeout argument to acquire() works. hub = get_hub() lock = gruvi.RLock() sync = gruvi.Lock() def lock_rlock(): lock.acquire() sync.acquire() lock.release() # This needs a new fiber, as the same fiber *can* lock the same RLock twice. sync.acquire() fiber = gruvi.spawn(lock_rlock) gruvi.sleep(0) self.assertTrue(lock.locked()) t0 = hub.loop.now() self.assertFalse(lock.acquire(timeout=0.01)) t1 = hub.loop.now() # Internally the event loop uses timestamps with a 1ms granularity. So # allow for that. self.assertGreaterEqual(t1 - t0, 10) sync.release() fiber.join() self.assertFalse(lock._callbacks)
def test_send_message(self): # After the "Hello" message, it should be possible to send other # messages. transport = MockTransport() protocol = DbusProtocol(True, self.store_messages, 'foo') transport.start(protocol) protocol.data_received(b'\0AUTH ANONYMOUS\r\nBEGIN\r\n') auth = protocol._authenticator self.assertTrue(auth.authenticationSucceeded()) message = txdbus.MethodCallMessage('/org/freedesktop/DBus', 'Hello', interface='org.freedesktop.DBus', destination='org.freedesktop.DBus') protocol.data_received(message.rawMessage) gruvi.sleep(0) self.assertIsNone(protocol._error) self.assertFalse(transport.closed) self.assertTrue(protocol._name_acquired) self.assertEqual(len(self.messages), 0) message = txdbus.MethodCallMessage('/my/path', 'Method') protocol.data_received(message.rawMessage) gruvi.sleep(0) self.assertIsNone(protocol._error) self.assertFalse(transport.closed) self.assertEqual(len(self.messages), 1) self.assertEqual(self.messages[0].path, '/my/path') self.assertEqual(self.messages[0].member, 'Method') self.assertEqual(self.protocols, [protocol])
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.assertIsNone(cond._callbacks)
def test_thread_safety(self): event = gruvi.Event() result = [] def run_test(): timeout = random.choice((None, 0.1)) result.append(event.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.5) event.set() 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.assertIsNone(event._callbacks)
def test_thread_safety(self): # A Queue should be thread safe. This meanst that all entries that are # put in the queue must be returned, that no entry must be returned # twice and that the order must be respected. Also no deadlock must # ever occur. # To test, fire up a bunch of threads which each fire up a bunch of # fibers, and have the fibers do some random sleeps. Then let it run # and test the result. result = [] reference = [] lock = gruvi.Lock() def put_queue(tid, fid, count): for i in range(count): with lock: gruvi.sleep(random.randint(0, 2) / 1000) queue.put((tid, fid, count)) reference.append((tid, fid, count)) def get_queue(count): for i in range(count): with lock: result.append(queue.get()) def thread_put(tid, nfibers, count): fibers = [] for i in range(nfibers): fibers.append(gruvi.spawn(put_queue, tid, i, count)) for fib in fibers: fib.join() gruvi.get_hub().close() def thread_get(nfibers, count): fibers = [] for i in range(nfibers): fibers.append(gruvi.spawn(get_queue, count)) for fib in fibers: fib.join() gruvi.get_hub().close() queue = gruvi.Queue() threads = [] # 5 procuders and 5 consumers, each with 20 fibers for i in range(5): thread = threading.Thread(target=thread_put, args=(i, 20, 5)) thread.start() threads.append(thread) for i in range(5): thread = threading.Thread(target=thread_get, args=(20, 5)) thread.start() threads.append(thread) for thread in threads: thread.join() gruvi.sleep(0) # run callbacks self.assertEqual(len(result), 500) self.assertEqual(result, reference) # Within a (tid,fid) pair, the counts must be monotonic partial_sort = sorted(result, key=lambda el: (el[0], el[1])) full_sort = sorted(result, key=lambda el: (el[0], el[1], el[2])) self.assertEqual(partial_sort, full_sort)
def thread_sleep(): hub = gruvi.get_hub() gruvi.sleep(0) refs.append(weakref.ref(hub)) refs.append(weakref.ref(hub.loop)) hub.close() hub.switch()
def pair_step2(self, uuid, kxid, pin, certinfo): """Perform step 2 in pairing exchange. If successfull, this returns the peer certificate. On error, a SyncApiError is raised. """ if self.client is None: raise RuntimeError('Not connected') url = '/api/vaults/%s/pair' % uuid # XXX: wait until SSL is up gruvi.sleep(0.1) headers = self._get_hmac_cb_auth(kxid, pin) response = self._make_request('POST', url, headers, certinfo) if response is None: raise SyncApiError('Could not make syncapi request') status = response.status if status != 200: self._log.error('expecting HTTP status 200 (got: {})', status) raise SyncApiError('HTTP status {0}'.format(response.status)) if not self._check_hmac_cb_auth(response, pin): raise SyncApiError('Illegal syncapi response') peercert = response.entity if peercert is None or not isinstance(peercert, dict): raise SyncApiError('Illegal syncapi response') return peercert
def test_read_write_flow_control(self): # Test the read and write flow control of a stream transport. transport = MockTransport() protocol = StreamProtocol() transport.start(protocol) protocol.stream.buffer.set_buffer_limits(100) transport.set_write_buffer_limits(50) def reader(): while True: buf = protocol.stream.read(20) if not buf: break protocol.stream.write(buf) fib = gruvi.spawn(reader) buf = b'x' * 20 interrupted = 0 for i in range(100): protocol.data_received(buf) if transport._reading: continue interrupted += 1 self.assertGreater(protocol.stream.buffer.get_buffer_size(), 0) # Switch to the reader() fiber which will fill up the transport # write buffer. gruvi.sleep(0) # The transport write buffer should be full but the protocol read # buffer should still contain something. self.assertGreater(protocol.stream.buffer.get_buffer_size(), 0) self.assertFalse(transport._can_write.is_set()) # Drain write buffer and resume writing transport.drain() self.assertGreater(interrupted, 30) fib.cancel() gruvi.sleep(0)
def test_thread_safety(self): event = gruvi.Event() result = [] def run_test(): timeout = random.choice((None, 0.1)) result.append(event.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.5) event.set() 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(event._callbacks)
def fiber1(): local.foo = 10 interleaved.append(1) gruvi.sleep(0) self.assertEqual(local.foo, 10) local.foo = 30 interleaved.append(1) gruvi.sleep(0) self.assertEqual(local.foo, 30)
def fiber2(): self.assertFalse(hasattr(local, 'foo')) local.foo = 20 interleaved.append(2) gruvi.sleep(0) self.assertEqual(local.foo, 20) local.foo = 40 interleaved.append(2) gruvi.sleep(0) self.assertEqual(local.foo, 40)
def test_cancel(self): # Ensure that it's possible to cancel() a fiber. def sleeper(): gruvi.sleep(1000) fiber = gruvi.spawn(sleeper) gruvi.sleep(0) self.assertTrue(fiber.alive) fiber.cancel() gruvi.sleep(0) self.assertFalse(fiber.alive)
def test_thread_safety(self): # A Queue should be thread safe. This meanst that all entries that are # put in the queue must be returned, that no entry must be returned # twice and that the order must be respected. Also no deadlock must # ever occur. # To test, fire up a bunch of threads which each fire up a bunch of # fibers, and have the fibers do some random sleeps. Then let it run # and test the result. result = [] reference = [] lock = gruvi.Lock() def put_queue(tid, fid, count): for i in range(count): with lock: gruvi.sleep(random.randint(0, 10)/10000) queue.put((tid, fid, count)) reference.append((tid, fid, count)) def get_queue(count): for i in range(count): with lock: result.append(queue.get()) def thread_put(tid, nfibers, count): fibers = [] for i in range(nfibers): fibers.append(gruvi.spawn(put_queue, tid, i, count)) for fib in fibers: fib.join() gruvi.get_hub().close() def thread_get(nfibers, count): fibers = [] for i in range(nfibers): fibers.append(gruvi.spawn(get_queue, count)) for fib in fibers: fib.join() gruvi.get_hub().close() queue = gruvi.Queue() threads = [] # 5 procuders and 5 consumers, each with 20 fibers for i in range(5): thread = threading.Thread(target=thread_put, args=(i, 20, 5)) thread.start() threads.append(thread) for i in range(5): thread = threading.Thread(target=thread_get, args=(20, 5)) thread.start() threads.append(thread) for thread in threads: thread.join() gruvi.sleep(0) # run callbacks self.assertEqual(len(result), 500) self.assertEqual(result, reference) # Within a (tid,fid) pair, the counts must be monotonic partial_sort = sorted(result, key=lambda el: (el[0], el[1])) full_sort = sorted(result, key=lambda el: (el[0], el[1], el[2])) self.assertEqual(partial_sort, full_sort)
def test_duplicate(self): futures = [Future()] * 5 result = [] def waiter(): result.append(gruvi.wait(futures)) fib = Fiber(waiter) fib.start() gruvi.sleep(0) self.assertEqual(result, []) futures[0].set_result(None) gruvi.sleep(0) self.assertEqual(result, [(futures, [])])
def test_sleep(self): # Test that sleep() works hub = gruvi.get_hub() # use hub.now() as there's slight rounding errors with time.time() t0 = hub.loop.now() gruvi.sleep(0.01) t1 = hub.loop.now() self.assertGreaterEqual(t1 - t0, 10) t0 = hub.loop.now() gruvi.sleep(0.1) t1 = hub.loop.now() self.assertGreaterEqual(t1 - t0, 100)
def test_wait(self): event = gruvi.Event() done = [] def waiter(): done.append(False) done.append(event.wait()) gruvi.spawn(waiter) gruvi.sleep(0) self.assertEqual(done, [False]) event.set() gruvi.sleep(0) self.assertEqual(done, [False, True])
def test_sleep(self): # Test that sleep() works hub = gruvi.get_hub() # use hub.now() as there's slight rounding errors with time.time() t0 = hub.loop.now() gruvi.sleep(0.01) t1 = hub.loop.now() self.assertGreaterEqual(t1-t0, 10) t0 = hub.loop.now() gruvi.sleep(0.1) t1 = hub.loop.now() self.assertGreaterEqual(t1-t0, 100)
def test_returncode(self): # Ensure that the returncode attribute gets set when the child exits. proc = Process() proc.spawn(['sleep', '0.2']) tries = 0 while True: if proc.returncode is not None: break tries += 1 gruvi.sleep(0.02) self.assertEqual(proc.returncode, 0) self.assertGreater(tries, 5) proc.close()
def get_request(self): # Get a parsed request. # The sleep here will run the dispatcher. gruvi.sleep(0) self.assertGreaterEqual(len(self.environs), 1) env = self.environs.pop(0) self.assertIsInstance(env, dict) message = env.get('test.message') self.assertIsInstance(message, HttpMessage) self.assertEqual(message.message_type, _lib.HTTP_REQUEST) body = env.get('test.body') self.assertIsInstance(body, six.binary_type) return env
def test_cleanup(self): # After we close() a Hub, it should be garbage collectable, including # its event loop. hub = gruvi.Hub() gruvi.sleep(0) ref1 = weakref.ref(hub) ref2 = weakref.ref(hub.loop) hub.close() hub.switch() del hub gc.collect() self.assertIsNone(ref1()) self.assertIsNone(ref2())
def perf_spawn_throughput(self): # Measure the number of fibers we can spawn per second. t0 = t1 = time.time() count = [0] def dummy_fiber(): count[0] += 1 while t1 - t0 < 0.2: fiber = Fiber(dummy_fiber) fiber.start() gruvi.sleep(0) t1 = time.time() speed = count[0] / (t1 - t0) self.add_result(speed)
def lock_unlock(self, lock, count): failed = 0 timeouts = 0 for i in range(count): # the granularity of libuv's timers is 1ms. gruvi.sleep(random.randint(0, 2) / 1000) timeout = random.choice((None, 0.001)) while not lock.acquire(timeout=timeout): timeouts += 1 gruvi.sleep(random.randint(0, 2) / 1000) if lock._locked != 1 or lock._owner is not gruvi.current_fiber(): failed += 1 lock.release() return failed
def test_pipe(self): # Ensure that create_connection() and create_server() can be used to # connect to each other over a pipe. addr = self.pipename() server = create_server(StreamProtocol, addr) ctrans, cproto = create_connection(StreamProtocol, addr) gruvi.sleep(0.1) # allow Server to accept() strans, sproto = list(server.connections)[0] cproto.stream.write(b'foo\n') self.assertEqual(sproto.stream.readline(), b'foo\n') server.close() self.assertEqual(len(list(server.connections)), 0) self.assertEqual(cproto.stream.readline(), b'') ctrans.close()
def lock_unlock(self, lock, count): failed = 0 timeouts = 0 for i in range(count): # the granularity of libuv's timers is 1ms. gruvi.sleep(random.randint(0, 14)/10000) timeout = random.choice((None, None, None, 0.001)) while not lock.acquire(timeout=timeout): timeouts += 1 gruvi.sleep(random.randint(0, 14)/10000) if lock._locked != 1 or lock._owner is not gruvi.current_fiber(): failed += 1 lock.release() return failed
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_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_flow_control(self): # Write more bytes than the protocol buffers. Flow control should kick # in and alternate scheduling of the producer and the consumer. proto = self.protocol proto.read_buffer_size = 100 message = b'{ "id": 1, "method": "foo"}' for i in range(1000): proto.data_received(message) if not proto._reading: gruvi.sleep(0) # run dispatcher self.assertTrue(proto._reading) mm = self.get_messages() self.assertEqual(len(mm), 1000) message = json.loads(message.decode('utf8')) for m in mm: self.assertEqual(m, message)
def perf_switch_throughput(self): # Measure the number of switches we can do per second. t0 = t1 = time.time() count = [0] def switch_parent(): while True: gruvi.sleep(0) fiber = Fiber(switch_parent) fiber.start() while t1 - t0 < 0.2: gruvi.sleep(0) count[0] += 1 t1 = time.time() speed = count[0] / (t1 - t0) self.add_result(speed) fiber.cancel() gruvi.sleep(0)
def test_send_random(self): server = JsonRpcServer(echo_app) server.listen(('127.0.0.1', 0)) addr = server.addresses[0] client = JsonRpcClient() client.connect(addr) exc = None try: while True: chunk = os.urandom(1024) client.transport.write(chunk) gruvi.sleep(0) except Exception as e: exc = e self.assertIsInstance(exc, TransportError) server.close() client.close()
def test_non_blocking(self): # Ensure that the blocking argument to acquire() works. lock = gruvi.RLock() sync = gruvi.Lock() def lock_rlock(): lock.acquire() sync.acquire() lock.release() # This needs a new fiber, as the same fiber *can* lock the same RLock twice. sync.acquire() fiber = gruvi.spawn(lock_rlock) gruvi.sleep(0) self.assertTrue(lock.locked()) self.assertFalse(lock.acquire(blocking=False)) sync.release() fiber.join() self.assertFalse(lock._callbacks)
def sync(self, uuid, model): """Synchronize vault `uuid` with the remote peer.""" if self.client is None: raise RuntimeError('Not connected') vault = model.get_vault(uuid) if vault is None: raise SyncApiError('Vault not found') vector = model.get_vector(uuid) vector = dump_vector(vector) url = '/api/vaults/%s/items?vector=%s' % (vault['id'], vector) gruvi.sleep(0.1) # XXX: wait for ssl handshake headers = self._get_ed25519_cb_auth(uuid, model) response = self._make_request('GET', url, headers) if not response: raise SyncApiError('Could not make HTTP request') status = response.status if status != 200: self._log.error('expecting HTTP status 200 (got: {})', status) raise SyncApiError('Illegal syncapi response') if not self._check_ed25519_cb_auth(uuid, response, model): raise SyncApiError('Illegal syncapi response') initems = response.entity if initems is None or not isinstance(initems, list): raise SyncApiError('Illegal syncapi response') nitems = model.import_items(uuid, initems) self._log.debug('imported {} items into model', nitems) vector = response.get_header('X-Vector', '') try: vector = parse_vector(vector) except ValueError as e: self._log.error('illegal X-Vector header: {} ({})', vector, str(e)) raise SyncApiError('Invalid response') outitems = model.get_items(uuid, vector) url = '/api/vaults/%s/items' % uuid response = self._make_request('POST', url, headers, outitems) if not response: raise SyncApiError('Illegal syncapi response') if status != 200: self._log.error('expecting HTTP status 200 (got: {})', status) raise SyncApiError('Illegal syncapi response') if not self._check_ed25519_cb_auth(uuid, response, model): raise SyncApiError('Illegal syncapi response') self._log.debug('succesfully retrieved {} items from peer', len(initems)) self._log.debug('succesfully pushed {} items to peer', len(outitems)) return len(initems) + len(outitems)
def test_send_garbage(self): # Send random garbage and ensure the connection gets dropped. server = DbusServer(echo_app) addr = 'unix:path=' + self.pipename() server.listen(addr) client = DbusClient() client.connect(addr) exc = None try: while True: chunk = os.urandom(100) client.transport.write(chunk) gruvi.sleep(0) except Exception as e: exc = e self.assertIsInstance(exc, TransportError) server.close() client.close()
def test_partial(self): # Ensure that the "count" argument of wait() can be used to wait for a # subset of the futures to complete. futures = [Future() for i in range(10)] result = [] def waiter(): result.append(gruvi.wait(futures, count=5)) fib = Fiber(waiter) fib.start() gruvi.sleep(0) for i in range(4): futures[i].set_result(None) self.assertTrue(fib.alive) self.assertEqual(result, []) futures[4].set_result(None) gruvi.sleep(0) self.assertFalse(fib.alive) self.assertEqual(result, [(futures[:5], futures[5:])])
def test_read_write_flow_control(self): # Send a lot of messages filling up the protocol read buffer. transport = MockTransport() protocol = DbusProtocol(True, self.store_and_echo_messages) transport.start(protocol) protocol.data_received(b'\0AUTH ANONYMOUS\r\nBEGIN\r\n') auth = protocol._authenticator self.assertTrue(auth.authenticationSucceeded()) message = txdbus.MethodCallMessage('/org/freedesktop/DBus', 'Hello', interface='org.freedesktop.DBus', destination='org.freedesktop.DBus') protocol.data_received(message.rawMessage) gruvi.sleep(0) self.assertTrue(protocol._name_acquired) interrupted = 0 message = txdbus.SignalMessage('/my/path', 'Signal', 'my.iface', signature='s', body=['x'*100]) msglen = len(message.rawMessage) protocol.set_read_buffer_limits(10*msglen) transport.buffer.seek(0) transport.buffer.truncate() transport.set_write_buffer_limits(7*msglen) for i in range(100): # Fill up protocol read buffer message = txdbus.SignalMessage('/my/path', 'Signal', 'my.iface', signature='s', body=['x'*100]) protocol.data_received(message.rawMessage) if protocol._reading: continue interrupted += 1 self.assertGreater(protocol._queue.qsize(), 0) # Run the dispatcher to fill up the transport write buffer gruvi.sleep(0) # Now the write buffer is full and the read buffer still contains # some entries because it is larger. self.assertTrue(protocol._reading) self.assertGreater(protocol._queue.qsize(), 0) self.assertFalse(protocol._may_write.is_set()) # Drain write buffer and resume writing transport.buffer.seek(0) transport.buffer.truncate() protocol.resume_writing() # Should be interrupted > 10 times. The write buffer is the limiting factor # not the read buffer. self.assertGreater(interrupted, 10)
def test_lock_order(self): # Locks are fair and are granted in order. lock = self.Lock() order = [] def run_test(ix): lock.acquire() order.append(ix) lock.release() fibers = [] for i in range(self.nfibers): fibers.append(gruvi.spawn(run_test, i)) lock.acquire() gruvi.sleep(0) self.assertEqual(order, []) lock.release() for fib in fibers: fib.join() self.assertEqual(order, list(range(len(fibers))))