def test_schedule_at(self): at = time.time() + (TESTING_TIMEOUT * 2) l = [] def f1(): l.append(1) greenhouse.schedule_at(at, f1) @greenhouse.schedule_at(at) def f2(): l.append(2) @greenhouse.schedule_at(at, args=(3,)) def f3(x): l.append(x) @greenhouse.schedule_at(at, kwargs={'x': 4}) def f4(x=None): l.append(x) @greenhouse.compat.greenlet def f5(): l.append(5) greenhouse.schedule_at(at, f5) greenhouse.pause() assert not l greenhouse.pause_for(TESTING_TIMEOUT * 2) assert time.time() >= at greenhouse.pause() l.sort() assert l == [1, 2, 3, 4, 5], l
def test_deleted_sock_gets_cleared(self): dmap = greenhouse.scheduler.state.descriptormap client = greenhouse.Socket() server = greenhouse.Socket() server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) temp = greenhouse.Socket() temps_fileno = temp.fileno() one_good = filter(lambda (r, w): r and w, dmap[temps_fileno]) self.assertEqual(len(one_good), 1, one_good) del temp del one_good @greenhouse.schedule def f(): server.bind(("", port())) server.listen(5) conn = server.accept()[0] assert conn.recv(8192) == "test_deleted_sock_gets_cleared" greenhouse.pause_for(TESTING_TIMEOUT) client.connect(("", port())) client.sendall("test_deleted_sock_gets_cleared") greenhouse.pause_for(TESTING_TIMEOUT) gc.collect() gone = filter(lambda (r, w): r and w, dmap[temps_fileno]) self.assertEqual(len(gone), 0, gone)
def test_join(self): ev = greenhouse.util.Event() class T(greenhouse.util.Thread): def run(self): ev.wait() threads = [T() for i in xrange(5)] [t.start() for t in threads] l = [] @greenhouse.schedule def joiner(): threads[2].join() l.append(None) greenhouse.pause_for(TESTING_TIMEOUT) self.assertEqual(len(l), 0) ev.set() greenhouse.pause() greenhouse.pause() self.assertEqual(len(l), 1)
def test_schedule(self): l = [] def f1(): l.append(1) greenhouse.schedule(f1) @greenhouse.schedule def f2(): l.append(2) @greenhouse.schedule(args=(3,)) def f3(x): l.append(x) @greenhouse.schedule(kwargs={'x': 4}) def f4(x=None): l.append(x) @greenhouse.compat.greenlet def f5(): l.append(5) greenhouse.schedule(f5) greenhouse.pause_for(TESTING_TIMEOUT) l.sort() assert l == [1, 2, 3, 4, 5], l
def test_downed_recipient_cancels_the_hub_sender_during_chunked_request(self): global PORT hub = junction.Hub(("127.0.0.1", PORT), []) PORT += 2 triggered = [False] @hub.accept_rpc('service', 0, 0, 'method') def handle(chunks): for item in chunks: pass return "all done" hub.start() hub2 = junction.Hub(("127.0.0.1", PORT), [("127.0.0.1", PORT - 2)]) PORT += 2 hub2.start() hub2.wait_connected() def gen(): try: while 1: yield None greenhouse.pause_for(TIMEOUT) finally: triggered[0] = True rpc = hub2.send_rpc('service', 0, 'method', (gen(),)) hub = [hub] greenhouse.schedule_in(TIMEOUT * 4, self.kill_hub, args=(hub,)) greenhouse.pause_for(TIMEOUT * 5) assert triggered[0]
def gen(): try: while 1: yield None greenhouse.pause_for(TIMEOUT) finally: triggered[0] = True
def chunked_response(http): http.add_header('content-type', 'text/html') yield """<!DOCTYPE html> <html> \t<body> <!--%s--!> """ % (' ' * (1024 - 40)) for i in xrange(10): greenhouse.pause_for(1) yield "\t\t<p>%d</p>\n" % i yield "\t</body>\n</html>"
def test_pauses(self): l = [False] def f(): l[0] = True timer = greenhouse.Timer(TESTING_TIMEOUT, f) timer.start() assert not l[0] greenhouse.pause_for(TESTING_TIMEOUT * 2) assert l[0]
def test_args(self): l = [False] def f(x, y): l[0] = (x, y) timer = greenhouse.Timer(TESTING_TIMEOUT, f, args=(3, 76)) timer.start() assert not l[0] greenhouse.pause_for(TESTING_TIMEOUT * 2) self.assertEqual(l[0], (3, 76))
def test_kwargs(self): l = [False] def f(**kwargs): l[0] = kwargs timer = greenhouse.Timer(TESTING_TIMEOUT, f, kwargs={'a': 1, 'b': 2}) timer.start() assert not l[0] greenhouse.pause_for(TESTING_TIMEOUT * 2) self.assertEqual(l[0], {'a': 1, 'b': 2})
def test_publish_receiver_count_includes_self(self): @self.peer.accept_publish('service', 0, 0, 'method') def handler(): return 8 @self.sender.accept_publish('service', 0, 0, 'method') def handler(): return 9 greenhouse.pause_for(TIMEOUT) self.assertEqual(2, self.sender.publish_receiver_count('service', 0))
def test_timeout_clears_waiters(self): ev = greenhouse.Event() l = [False] @greenhouse.schedule def f(): ev.wait(TESTING_TIMEOUT) l[0] = True greenhouse.pause_for(TESTING_TIMEOUT * 2) assert l[0] self.assertEqual(ev._waiters, [])
def test_timeouts_in_grlets(self): l = [False] ev = greenhouse.Event() @greenhouse.schedule def f(): ev.wait(TESTING_TIMEOUT) l[0] = True greenhouse.pause() assert not l[0] greenhouse.pause_for(TESTING_TIMEOUT * 2) assert l[0]
def test_blocking(self): rfp, wfp = greenhouse.pipe() l = [] try: @greenhouse.schedule def f(): l.append(rfp.read(4)) greenhouse.pause() assert not l wfp.write("heyo") greenhouse.pause_for(TESTING_TIMEOUT) assert l and l[0] == "heyo", l finally: rfp.close() wfp.close()
def serve(self): """run the server at the provided address forever. this method will remove the calling greenlet (generally the main greenlet) from the scheduler, so don't expect anything else to run in the calling greenlet until the server has been shut down. """ if not self.is_setup: self.setup() try: while not self.shutting_down: try: client_sock, client_address = self.socket.accept() handler = self.connection_handler( client_sock, client_address, self.address, self.killable) greenhouse.schedule(handler.serve_all) except socket.error, error: if err.args[0] == errno.EMFILE: # max open connections for the process if not self.killable: # if all connections are active, just wait a # while before accepting a new connection again greenhouse.pause_for(0.01) continue # close all the connections that are # only open for keep-alive anyway for fd in self.killable.keys(): handler = self.killable.pop(fd) handler.socket.close() handler.closed = True elif err.args[0] == errno.ENFILE: # max open connections for the machine greenhouse.pause_for(0.01) else: raise except KeyboardInterrupt: pass finally: self.socket.close()
def serve(self): """run the server at the provided address forever. this method will remove the calling greenlet (generally the main greenlet) from the scheduler, so don't expect anything else to run in the calling greenlet until the server has been shut down. """ if self.daemonize and os.environ.get('DAEMON', None) != 'yes': os.environ['DAEMON'] = 'yes' util.background() if not self.is_setup: self.setup() self.ready.set() try: while not self.shutting_down: try: client_sock, client_address = self.socket.accept() handler = self.connection_handler( client_sock, client_address, self) except socket.error, error: if error.args[0] in (errno.ENFILE, errno.EMFILE): # max open connections greenhouse.pause_for(0.01) elif error.args[0] == errno.EINVAL: # server socket was shut down break elif error.args[0] == errno.EBADF: # believe it or not, this is the graceful shutdown # case. see the comments in shutdown() below break raise else: # might be a long time before the next accept call returns greenhouse.schedule(handler.serve_all) del handler, client_sock except KeyboardInterrupt: pass finally: self._cleanup()
def test_poller_registration_rollback(self): with self.socketpair() as (client, handler): r = [False] @greenhouse.schedule def client_recv(): assert client.recv(10) == "hiya" r[0] = True greenhouse.pause() client.sendall("howdy") assert handler.recv(10) == "howdy" greenhouse.pause() assert not r[0] handler.sendall("hiya") greenhouse.pause_for(TESTING_TIMEOUT) assert r[0]
def test_schedule_recurring(self): l = [] def f1(): l.append(1) greenhouse.schedule_recurring(TESTING_TIMEOUT, f1, maxtimes=2) greenhouse.pause_for(TESTING_TIMEOUT * 3) assert l == [1, 1], l l = [] @greenhouse.schedule_recurring(TESTING_TIMEOUT, maxtimes=2) def f2(): l.append(2) greenhouse.pause_for(TESTING_TIMEOUT * 3) assert l == [2, 2], l l = [] @greenhouse.schedule_recurring(TESTING_TIMEOUT, maxtimes=2, args=(3,)) def f3(x): l.append(x) greenhouse.pause_for(TESTING_TIMEOUT * 3) assert l == [3, 3], l l = [] @greenhouse.schedule_recurring(TESTING_TIMEOUT, maxtimes=2, kwargs={'x': 4}) def f4(x=None): l.append(x) greenhouse.pause_for(TESTING_TIMEOUT * 3) assert l == [4, 4], l l = [] @greenhouse.compat.greenlet def f5(): l.append(5) greenhouse.schedule_recurring(TESTING_TIMEOUT, f5, maxtimes=2) greenhouse.pause_for(TESTING_TIMEOUT * 3) assert l == [5, 5], l
def gen(): greenhouse.pause_for(TIMEOUT) yield None greenhouse.pause_for(TIMEOUT) yield None greenhouse.pause_for(TIMEOUT) yield None
def test_unrelated_client_chunked_publishes_are_unrelated(self): global PORT hub = junction.Hub(("127.0.0.1", PORT), []) PORT += 2 d = {} @hub.accept_publish('service', 0, 0, 'method') def handle(x, source): for item in x: d.setdefault(source, 0) d[source] += 1 hub.start() c1 = junction.Client(("127.0.0.1", PORT - 2)) c1.connect() c1.wait_connected() c2 = junction.Client(("127.0.0.1", PORT - 2)) c2.connect() c2.wait_connected() def gen(): greenhouse.pause_for(TIMEOUT) yield None greenhouse.pause_for(TIMEOUT) yield None greenhouse.pause_for(TIMEOUT) yield None greenhouse.schedule(c1.publish, args=('service', 0, 'method'), kwargs={'args': (gen(),), 'kwargs': {'source': 'a'}}) greenhouse.schedule(c2.publish, args=('service', 0, 'method'), kwargs={'args': (gen(),), 'kwargs': {'source': 'b'}}) greenhouse.pause_for(TIMEOUT) c2 = [c2] self.kill_client(c2) greenhouse.pause_for(TIMEOUT) greenhouse.pause_for(TIMEOUT) greenhouse.pause_for(TIMEOUT) self.assertEquals(d, {'a': 3, 'b': 1})
def test_pause_for(self): start = time.time() greenhouse.pause_for(TESTING_TIMEOUT) assert TESTING_TIMEOUT + 0.03 > time.time() - start >= TESTING_TIMEOUT
def handle(): greenhouse.pause_for(TIMEOUT) return 1
def _pause(ms): greenhouse.pause_for(ms / 1000.0)
def glet(): try: greenhouse.pause_for(TESTING_TIMEOUT * 2) except Exception, exc: excs.append(exc) return
@greenhouse.schedule @greenhouse.greenlet def glet(): try: greenhouse.pause_for(TESTING_TIMEOUT * 2) except Exception, exc: excs.append(exc) return l[0] = True greenhouse.pause() greenhouse.schedule_exception_in( TESTING_TIMEOUT, self.CustomError(), glet) greenhouse.pause_for(TESTING_TIMEOUT * 2) assert not l[0] assert isinstance(excs[0], self.CustomError), excs def test_schedule_exception_in_rejects_funcs(self): def f(): pass self.assertRaises( TypeError, greenhouse.schedule_exception_in, 1, Exception(), f) def test_schedule_exception_in_rejects_dead_glets(self): @greenhouse.schedule @greenhouse.greenlet def g(): pass
def wait(seconds): greenhouse.pause_for(seconds)