class TestEngineInstallPoller(unittest.TestCase): def setUp(self): self.engine = Engine() def test_custom_poller(self): poller = MagicMock() self.engine._poller = None self.engine._channels = {} self.engine._install_poller(poller) self.assertTrue(self.engine._poller is poller) @unittest.skip("Not yet implemented.") def test_custom_poller_with_existing_channels(self): self.fail("Not yet implemented.") @unittest.skip("Not yet implemented.") def test_custom_poller_with_existing_channels_and_poller(self): self.fail("Not yet implemented.") @unittest.skip("Not yet implemented.") @unittest.skipUnless(hasattr(select, "epoll"), "epoll-specific functionality.") def test_defaulting_to_epoll(self): self.fail("Not yet implemented.") @unittest.skip("Not yet implemented.") @unittest.skipIf(hasattr(select, "epoll"), "kqueue-specific functionality.") @unittest.skipUnless(hasattr(select, "kqueue"), "kqueue-specific functionality.") def test_defaulting_to_kqueue(self): self.fail("Not yet implemented.") @unittest.skip("Not yet implemented.") @unittest.skipIf(hasattr(select, "epoll"), "select-specific functionality.") @unittest.skipIf(hasattr(select, "kqueue"), "select-specific functionality.") def test_defaulting_to_select(self): self.fail("Not yet implemented.")
def doer(*a, **kw): if Engine.instance()._running: raise RuntimeError( "synchronous calls cannot be made while Pants is already running." ) data = [] def callback(*a, **kw): if kw: if a: a = a + (kw, ) else: a = kw if isinstance(a, tuple) and len(a) == 1: a = a[0] data.append(a) Engine.instance().stop() kw['callback'] = callback func(*a, **kw) Engine.instance().start() return data[0]
def install(app=None, timeout=0.02): """ Creates a :class:`~PySide.QtCore.QTimer` instance that will be triggered continuously to call :func:`Engine.poll() <pants.engine.Engine.poll>`, ensuring that Pants remains responsive. ========= ======== ============ Argument Default Description ========= ======== ============ app None *Optional.* The :class:`~PySide.QtCore.QCoreApplication` to attach to. If no application is provided, it will attempt to find an existing application in memory, or, failing that, create a new application instance. timeout ``0.02`` *Optional.* The maximum time to wait, in seconds, before running :func:`Engine.poll() <pants.engine.Engine.poll>`. ========= ======== ============ """ global timer global _timeout Engine.instance()._install_poller(_Qt()) if app is None: app = QCoreApplication.instance() if app is None: app = QCoreApplication([]) _timeout = timeout * 1000 timer = QTimer(app) timer.timeout.connect(do_poll) timer.start(_timeout)
def test_channel_is_modified_on_poller(self): engine = Engine() channel = MagicMock() channel.fileno = "foo" channel._events = "bar" engine._poller.modify = MagicMock() engine.modify_channel(channel) engine._poller.modify.assert_called_once_with(channel.fileno, channel._events)
def setUp(self): self.engine = Engine() self.poller = MagicMock() self.poller.add = MagicMock() self.engine._poller = self.poller self.channel = MagicMock() self.channel.fileno = "foo" self.channel._events = "bar"
def process(self): """ Block until the queued requests finish. """ if not self._requests: return self._processing = True from pants.engine import Engine Engine.instance().start()
def close(self): """ Close the channel. """ if self._socket is None: return Engine.instance().remove_channel(self) self._socket_close() self._safely_call(self.on_close)
def callback(*a,**kw): if kw: if a: a = a + (kw, ) else: a = kw if isinstance(a, tuple) and len(a) == 1: a = a[0] data.append(a) Engine.instance().stop()
def callback(*a, **kw): if kw: if a: a = a + (kw, ) else: a = kw if isinstance(a, tuple) and len(a) == 1: a = a[0] data.append(a) Engine.instance().stop()
class TestEngineRemoveChannel(unittest.TestCase): def setUp(self): self.engine = Engine() self.poller = MagicMock() self.poller.remove = MagicMock() self.engine._poller = self.poller self.channel = MagicMock() self.channel.fileno = "foo" self.channel._events = "bar" self.engine._channels[self.channel.fileno] = self.channel def test_channel_is_removed_from_engine(self): self.engine.remove_channel(self.channel) self.assertFalse(self.channel.fileno in self.engine._channels) def test_channel_is_removed_from_poller(self): self.engine.remove_channel(self.channel) self.poller.remove.assert_called_once_with(self.channel.fileno, self.channel._events) def test_removing_channel_from_poller_raises_IOError(self): self.poller.remove = MagicMock(side_effect=IOError()) self.engine.remove_channel(self.channel) self.poller.remove.assert_called_once_with(self.channel.fileno, self.channel._events) def test_removing_channel_from_poller_raises_OSError(self): self.poller.remove = MagicMock(side_effect=OSError()) self.engine.remove_channel(self.channel) self.poller.remove.assert_called_once_with(self.channel.fileno, self.channel._events) def test_removing_channel_from_poller_raises_unknown(self): self.poller.remove = MagicMock(side_effect=Exception()) self.assertRaises(Exception, self.engine.remove_channel, self.channel) self.poller.remove.assert_called_once_with(self.channel.fileno, self.channel._events)
def _handle_events(self, events): """ Handle events raised on the channel. ========= ============ Argument Description ========= ============ events The events in the form of an integer. ========= ============ """ if self._socket is None: log.warning("Received events for closed %s #%d." % (self.__class__.__name__, self.fileno)) return if events & Engine.READ: self._wait_for_read_event = False self._handle_read_event() if self._socket is None: return if events & Engine.WRITE: self._wait_for_write_event = False self._handle_write_event() if self._socket is None: return if events & Engine.ERROR: err, errstr = self._get_socket_error() if err != 0: log.error("Error on %s #%d: %s (%d)" % (self.__class__.__name__, self.fileno, errstr, err)) self.close() return if events & Engine.HANGUP: log.debug("Hang up on %s #%d." % (self.__class__.__name__, self.fileno)) self.close() return events = Engine.ERROR | Engine.HANGUP if self._wait_for_read_event: events |= Engine.READ if self._wait_for_write_event: events |= Engine.WRITE if events != self._events: self._events = events Engine.instance().modify_channel(self)
class TestEngineStop(unittest.TestCase): def setUp(self): self.engine = Engine() def test_when_running(self): self.engine._shutdown = False self.engine._running = True self.engine.stop() self.assertTrue(self.engine._shutdown) def test_when_not_running(self): self.engine._shutdown = False self.engine._running = False self.engine.stop() self.assertFalse(self.engine._shutdown)
def _handle_events(self, events): """ Args: events: The events raised on the channel. """ if not self.active(): log.warning("Received events for closed channel %d." % self.fileno) return # Read event. if events & Engine.READ: if self._listening: self._handle_accept_event() elif not self._connected: self._handle_connect_event() else: self._handle_read_event() if not self.active(): return # Write event. if events & Engine.WRITE: if not self._connected: self._handle_connect_event() else: self._handle_write_event() if not self.active(): return # Error event. if events & Engine.ERROR: self.close_immediately() return # Update events. events = Engine.ERROR if self.readable(): events |= Engine.READ if self.writable(): events |= Engine.WRITE elif self._closing: # Done writing, so close. self.close_immediately() return if events != self._events: self._events = events Engine.instance().modify_channel(self)
def install(app=None, timeout=0.02, engine=None): """ Creates a :class:`~PySide.QtCore.QTimer` instance that will be triggered continuously to call :func:`Engine.poll() <pants.engine.Engine.poll>`, ensuring that Pants remains responsive. ========= ======== ============ Argument Default Description ========= ======== ============ app None *Optional.* The :class:`~PySide.QtCore.QCoreApplication` to attach to. If no application is provided, it will attempt to find an existing application in memory, or, failing that, create a new application instance. timeout ``0.02`` *Optional.* The maximum time to wait, in seconds, before running :func:`Engine.poll() <pants.engine.Engine.poll>`. engine *Optional.* The :class:`pants.engine.Engine` instance to use. ========= ======== ============ """ global timer global _timeout global _engine _engine = engine or Engine.instance() _engine._install_poller(_Qt()) if app is None: app = QCoreApplication.instance() if app is None: app = QCoreApplication([]) _timeout = timeout * 1000 timer = QTimer(app) timer.timeout.connect(do_poll) timer.start(_timeout)
def start_event(owner, delay, event_func, data=None, arg='', *args, **kwargs): """ Schedule a new event to trigger after ``delay`` seconds. Owners may be any Python object, but should be an instance of one of: :class:`account.Account`, :class:`char.Char`, :class:`exit.Exit`, :class:`mudsock.Mudsock`, :class:`obj.Obj`, or :class:`room.Room`. If the owner *is* one of those classes, any currently pending events are de-scheduled automatically when the owner is destroyed. Event functions should take a minimum of three arguments: the event owner, ``data``, and ``arg``. This is for compatibility with NakedMud. You may provide additional positional and keyword arguments if you wish. Returns a callable that de-schedules the event when called. =========== ============ Argument Description =========== ============ owner The object that owns the event. delay How long, in seconds, to wait before the event function should be called. event_func The function to be called. data *Optional.* Any Python object to be provided to the event function. arg *Optional.* A string to be provided to the event function. =========== ============ """ if not owner in __queued__: __queued__[owner] = [] event = Engine.instance().defer(delay, event_func, owner, data, arg, *args, **kwargs) __queued__[owner].append(event) return event
def setUp(self): self.app = Application() self.init_app(self.app) engine = Engine.instance() self.server = HTTPServer(self.app, engine=engine) self.server.listen(('127.0.0.1', 4040)) PantsTestCase.setUp(self, engine)
def setUp(self): self.engine = Engine.instance() self.client = HTTPClient(self.on_response, self.on_headers, self.on_progress, self.on_ssl_error, self.on_error, engine=self.engine)
def close_immediately(self): """ Close the socket immediately. Any pending data will not be sent. """ if not self.active(): return if self._write_file: self._write_file.close() self._write_file = None self._write_file_left = None Engine.instance().remove_channel(self) self._socket_close() self._update_addr() self._safely_call(self.handle_close)
class TestEngineAddChannel(unittest.TestCase): def setUp(self): self.engine = Engine() self.poller = MagicMock() self.poller.add = MagicMock() self.engine._poller = self.poller self.channel = MagicMock() self.channel.fileno = "foo" self.channel._events = "bar" def test_channel_is_added_to_engine(self): self.engine.add_channel(self.channel) self.assertTrue(self.channel.fileno in self.engine._channels) self.assertEqual(self.engine._channels[self.channel.fileno], self.channel) def test_channel_is_added_to_poller(self): self.engine.add_channel(self.channel) self.poller.add.assert_called_once_with(self.channel.fileno, self.channel._events)
class TestEngineStart(unittest.TestCase): def setUp(self): self.engine = Engine() def test_when_shutdown_is_true(self): self.engine._shutdown = True self.engine.start() self.assertFalse(self.engine._shutdown) def test_when_shutdown_is_false_and_running_is_true(self): self.engine._shutdown = False self.engine._running = True self.engine.start() self.assertFalse(self.engine._shutdown) self.assertTrue(self.engine._running) def test_when_engine_is_stopped_normally(self): def poll(engine): self.engine.stop() self.engine.poll = poll self.engine.start() self.assertFalse(self.engine._shutdown) self.assertFalse(self.engine._running) def test_when_poll_raises_systemexit(self): def poll(engine): raise SystemExit self.engine.poll = poll self.assertRaises(SystemExit, self.engine.start) self.assertFalse(self.engine._shutdown) self.assertFalse(self.engine._running) def test_when_poll_raises_exception(self): def poll(engine): raise Exception self.engine.poll = poll self.engine.start() self.assertFalse(self.engine._shutdown) self.assertFalse(self.engine._running)
def __init__(self, servers=None, engine=None): self.servers = servers or list_dns_servers() self.engine = engine or Engine.instance() # Internal State self._messages = {} self._cache = {} self._queries = {} self._tcp = {} self._udp = None self._last_id = -1
def __init__(self, socket=None): """ Initialises the channel object. Args: socket: A pre-existing socket that this channel should wrap. Optional. """ # Socket self._socket = socket or self._socket_create() self._socket.setblocking(False) self.fileno = self._socket.fileno() self.remote_addr = (None, None) self.local_addr = (None, None) # Internal state self._connected = False self._connecting = False self._listening = False self._closing = False # Input self.read_delimiter = None # String, integer or None. self._read_amount = 4096 self._read_buffer = "" # Output self._write_buffer = "" self._secondary_write_buffer = "" self._write_file = None self._write_file_left = None self._write_file_chunk = 65536 # Initialisation self._events = Engine.ERROR if self.readable(): self._events |= Engine.READ if self.writable(): self._events |= Engine.WRITE Engine.instance().add_channel(self)
def __init__(self, **kwargs): # Keyword arguments sock_family = kwargs.get("family", socket.AF_INET) sock_type = kwargs.get("type", socket.SOCK_STREAM) sock = kwargs.get("socket", None) if sock is None: sock = socket.socket(sock_family, sock_type) # Socket self.fileno = None self._socket = None self._socket_set(sock) # Socket state self._wait_for_read_event = True self._wait_for_write_event = True # I/O attributes self._recv_amount = 4096 # Events self._events = Engine.ALL_EVENTS Engine.instance().add_channel(self)
def do_poll(): """ Here, we run the Pants event loop. Then, we set the timer interval, either to the provided timeout, or for how long it would take to reach the earliest deferred event. """ engine = Engine.instance() engine.poll(0) if engine._deferreds: timer.setInterval(min(1000 * (engine._deferreds[0].end - engine.time), _timeout)) else: timer.setInterval(_timeout * 1000)
def doer(*a, **kw): if Engine.instance()._running: raise RuntimeError("synchronous calls cannot be made while Pants is already running.") data = [] def callback(*a,**kw): if kw: if a: a = a + (kw, ) else: a = kw if isinstance(a, tuple) and len(a) == 1: a = a[0] data.append(a) Engine.instance().stop() kw['callback'] = callback func(*a, **kw) Engine.instance().start() return data[0]
def install(app=None, timeout=0.02): """ Sets up the timer. This isn't necessary if you're going to be calling poll yourself. (And, if you ARE going to be calling poll yourself: why?) Args: app: The QApplication to attach to. If None, it will attempt to find the app or, failing that, it will create a new QCoreApplication instance. timeout: The length of time, in seconds, to wait between each call to the engine's poll function. """ global timer Engine.instance()._install_poller(_Qt()) if app is None: app = QCoreApplication.instance() if app is None: app = QCoreApplication([]) timer = QTimer(app) timer.timeout.connect(functools.partial(Engine.instance().poll, 0)) timer.start(timeout * 1000)
def __init__(self, **kwargs): self.engine = kwargs.get("engine", Engine.instance()) # Socket self._socket = None self._closed = False sock = kwargs.get("socket", None) if sock: self._socket_set(sock) # I/O attributes self._recv_amount = 4096 # Internal state self._events = Engine.ALL_EVENTS if self._socket: self.engine.add_channel(self)
def run(self, address=None, ssl_options=None, engine=None): """ This function exists for convenience, and when called creates a :class:`~pants.http.HTTPServer` instance with its request handler set to this application instance, calls :func:`~pants.http.HTTPServer.listen` on that HTTPServer, and finally, starts the Pants engine to process requests. ============ ============ Argument Description ============ ============ address *Optional.* The address to listen on. If this isn't specified, it will default to ``(INADDR_ANY, 80)``. ssl_options *Optional.* A dict of SSL options for the server. See :class:`pants.contrib.ssl.SSLServer` for more information. engine *Optional.* The :class:`pants.engine.Engine` instance to use. ============ ============ """ if not engine: from pants.engine import Engine engine = Engine.instance() HTTPServer(self, ssl_options=ssl_options).listen(address) engine.start()
def test_channel_constructor_no_args(self): channel = _Channel() self.assertTrue(channel.engine is Engine.instance()) self.assertTrue(channel._socket is None)
def test_channel_constructor_engine_arg(self): engine = Engine() channel = _Channel(engine=engine) self.assertTrue(channel.engine is engine)
def test_channel_gets_added_to_engine(self): engine = Engine() engine.add_channel = MagicMock() channel = _Channel(socket=socket.socket(), engine=engine) engine.add_channel.assert_called_once_with(channel) channel.close()
def test_channel_gets_removed_from_engine(self): engine = Engine() engine.remove_channel = MagicMock() channel = _Channel(socket=socket.socket(), engine=engine) channel.close() engine.remove_channel.assert_called_once_with(channel)
"__version__", # Metadata "HAS_IPV6", "HAS_UNIX", # Constants "engine", # Core "Stream", "Server", # TCP Networking "struct_delimiter", # Utility Stuff ] ############################################################################### # Objects ############################################################################### #: Alias for pants.engine.Engine.instance engine = Engine.instance() ############################################################################### # Logging ############################################################################### class NullHandler(logging.Handler): """ A dummy handler to prevent logging errors if the user does not initialise logging. """ def emit(self, record): pass
class TestEnginePoll(unittest.TestCase): def setUp(self): self.engine = Engine() def test_poll_updates_time(self): current_time = self.engine.latest_poll_time time.sleep(0.02) self.engine.poll(0.02) self.assertTrue(self.engine.latest_poll_time > current_time) def test_poll_executes_callbacks(self): callback = MagicMock() callback.function = MagicMock() callback.requeue = False self.engine._callbacks.append(callback) self.engine.poll(0.02) callback.function.assert_called_once_with() self.assertTrue(len(self.engine._callbacks) == 0) def test_callback_exception_doesnt_break_poll(self): callback = MagicMock() callback.function = MagicMock(side_effect=Exception) callback.requeue = False self.engine._callbacks.append(callback) try: self.engine.poll(0.02) except Exception: self.fail("Exception in callback function was not caught.") def test_keyboardinterrupt_during_callback_processing_is_raised(self): callback = MagicMock() callback.function = MagicMock(side_effect=KeyboardInterrupt) callback.requeue = False self.engine._callbacks.append(callback) self.assertRaises(KeyboardInterrupt, self.engine.poll, 0.02) def test_systemexit_during_callback_processing_is_raised(self): callback = MagicMock() callback.function = MagicMock(side_effect=SystemExit) callback.requeue = False self.engine._callbacks.append(callback) self.assertRaises(SystemExit, self.engine.poll, 0.02) def test_poll_requeues_loops(self): loop = MagicMock() loop.function = MagicMock() loop.requeue = True self.engine._callbacks.append(loop) self.engine.poll(0.02) self.assertTrue(loop in self.engine._callbacks) def test_poll_executes_deferreds(self): defer = MagicMock() defer.function = MagicMock() defer.requeue = False defer.end = self.engine.latest_poll_time - 1 self.engine._deferreds.append(defer) self.engine.poll(0.02) defer.function.assert_called_once_with() def test_deferred_exception_doesnt_break_poll(self): defer = MagicMock() defer.function = MagicMock() defer.requeue = False defer.end = self.engine.latest_poll_time - 1 self.engine._deferreds.append(defer) try: self.engine.poll(0.02) except Exception: self.fail("Exception in deferred was not caught.") def test_keyboardinterrupt_during_deferred_processing_is_raised(self): defer = MagicMock() defer.function = MagicMock(side_effect=KeyboardInterrupt) defer.requeue = False defer.end = self.engine.latest_poll_time - 1 self.engine._deferreds.append(defer) self.assertRaises(KeyboardInterrupt, self.engine.poll, 0.02) def test_systemexit_during_deferred_processing_is_raised(self): defer = MagicMock() defer.function = MagicMock(side_effect=SystemExit) defer.requeue = False defer.end = self.engine.latest_poll_time - 1 self.engine._deferreds.append(defer) self.assertRaises(SystemExit, self.engine.poll, 0.02) def test_poll_requeues_deferreds(self): cycle = MagicMock() cycle.function = MagicMock() cycle.requeue = True cycle.end = self.engine.latest_poll_time - 1 cycle.delay = 10 self.engine._deferreds.append(cycle) self.engine.poll(0.02) self.assertTrue(cycle in self.engine._deferreds) def test_poll_returns_if_timer_shuts_down_engine(self): # Pretty ugly way of testing this, to be honest. self.engine._poller.poll = MagicMock() self.engine._channels = {1: None} self.engine.callback(self.engine.stop) self.engine.poll(0.02) self.assertRaises(AssertionError, self.engine._poller.poll.assert_called_once_with) def test_poll_sleeps_for_poll_timeout(self): before = time.time() self.engine.poll(0.225) after = time.time() # It's never exactly the timeout length, but it gets very close. self.assertTrue((after - before) > 0.22) def test_poll_sleeps_until_next_deferred(self): defer = MagicMock() defer.function = MagicMock() defer.requeue = False self.engine._deferreds.append(defer) before = time.time() defer.end = before + 0.225 self.engine.poll(1) after = time.time() # Again, never going to be exact. self.assertTrue((after - before) < 0.25) def test_poller_successful(self): self.engine._channels = {1: None} self.engine._poller.poll = MagicMock() self.engine.poll(0.02) self.engine._poller.poll.assert_called_once_with(0.02) def test_poller_raises_EINTR(self): self.engine._channels = {1: None} self.engine._poller.poll = MagicMock(side_effect=Exception(errno.EINTR)) try: self.engine.poll(0.02) except Exception as err: if err.args[0] == errno.EINTR: self.fail("EINTR during polling was not caught.") def test_poller_raises_unknown(self): self.engine._channels = {1: None} self.engine._poller.poll = MagicMock(side_effect=Exception) self.assertRaises(Exception, self.engine.poll, 0.02) def test_poll_processes_events(self): channel = MagicMock() channel._handle_events = MagicMock() self.engine._channels = {1: channel} self.engine._poller.poll = MagicMock(return_value={1:Engine.ALL_EVENTS}) self.engine.poll(0.02) channel._handle_events.assert_called_once_with(Engine.ALL_EVENTS) def test_event_processing_error_doesnt_break_poll(self): channel = MagicMock() channel._handle_events = MagicMock(side_effect=Exception) self.engine._channels = {1: channel} self.engine._poller.poll = MagicMock(return_value={1:Engine.ALL_EVENTS}) try: self.engine.poll(0.02) except Exception: self.fail("Exception raised during event processing was not caught.") def test_keyboardinterrupt_during_event_processing_is_raised(self): channel = MagicMock() channel._handle_events = MagicMock(side_effect=KeyboardInterrupt) self.engine._channels = {1: channel} self.engine._poller.poll = MagicMock(return_value={1:Engine.ALL_EVENTS}) self.assertRaises(KeyboardInterrupt, self.engine.poll, 0.02) def test_systemexit_during_event_processing_is_raised(self): channel = MagicMock() channel._handle_events = MagicMock(side_effect=SystemExit) self.engine._channels = {1: channel} self.engine._poller.poll = MagicMock(return_value={1:Engine.ALL_EVENTS}) self.assertRaises(SystemExit, self.engine.poll, 0.02)
def test_cancelling_timer_calls_engine_remove_timer(self): engine = Engine() engine._remove_timer = MagicMock() timer = _Timer(engine, None, None) timer.cancel() engine._remove_timer.assert_called_once_with(timer)
class TestTimers(unittest.TestCase): def setUp(self): self.times_called = [] self.engine = Engine() def timer(self): self.times_called.append(self.engine.latest_poll_time) def test_callback(self): timer = MagicMock() self.engine.callback(timer) self.engine.poll(0.01) self.engine.poll(0.01) self.engine.poll(0.01) timer.assert_called_once_with() def test_callback_cancel(self): timer = MagicMock() cancel_callback = self.engine.callback(timer) cancel_callback() self.engine.poll(0.01) self.engine.poll(0.01) self.engine.poll(0.01) self.assertRaises(AssertionError, timer.assert_called_with) def test_loop(self): timer = MagicMock() self.engine.loop(timer) self.engine.poll(0.01) self.engine.poll(0.01) self.engine.poll(0.01) timer.assert_has_calls([call() for _ in range(3)]) def test_loop_cancel(self): timer = MagicMock() cancel_loop = self.engine.loop(timer) self.engine.poll(0.01) self.engine.poll(0.01) timer.assert_has_calls([call() for _ in range(2)]) cancel_loop() self.engine.poll(0.01) timer.assert_has_calls([call() for _ in range(2)]) def test_defer(self): self.engine.poll(0.01) timer = MagicMock(side_effect=self.timer) expected_time = self.engine.latest_poll_time + 0.01 self.engine.defer(0.01, timer) self.engine.poll(0.2) self.engine.poll(0.2) self.engine.poll(0.2) timer.assert_called_once_with() self.assertLess(abs(expected_time - self.times_called[0]), 0.01) def test_defer_cancel(self): timer = MagicMock() cancel_defer = self.engine.defer(0.01, timer) cancel_defer() self.engine.poll(0.2) self.engine.poll(0.2) self.engine.poll(0.2) self.assertRaises(AssertionError, timer.assert_called_with) def test_cycle(self): self.engine.poll(0.01) timer = MagicMock(side_effect=self.timer) expected_times = [ self.engine.latest_poll_time + 0.01, self.engine.latest_poll_time + 0.02, self.engine.latest_poll_time + 0.03 ] self.engine.cycle(0.01, timer) self.engine.poll(0.2) self.engine.poll(0.2) self.engine.poll(0.2) if sys.platform == "win32": self.engine.poll(0.02) # See issue #40 timer.assert_has_calls([call() for _ in range(3)]) for i in range(3): self.assertLess(abs(expected_times[i] - self.times_called[i]), 0.01) def test_cycle_cancel(self): self.engine.poll(0.01) timer = MagicMock(side_effect=self.timer) expected_times = [ self.engine.latest_poll_time + 0.01, self.engine.latest_poll_time + 0.02 ] cancel_cycle = self.engine.cycle(0.01, timer) self.engine.poll(0.2) self.engine.poll(0.2) if sys.platform == "win32": self.engine.poll(0.02) # See issue #40 timer.assert_has_calls([call() for _ in range(2)]) cancel_cycle() self.engine.poll(0.2) timer.assert_has_calls([call() for _ in range(2)]) for i in range(2): self.assertLess(abs(expected_times[i] - self.times_called[i]), 0.01)
def test_engine_global_instance(self): engine1 = Engine.instance() engine2 = Engine.instance() self.assertTrue(engine1 is engine2)
class TestEngineTimers(unittest.TestCase): def setUp(self): self.engine = Engine() def test_callback_added(self): timer = self.engine.callback(MagicMock()) self.assertTrue(timer in self.engine._callbacks) def test_loop_added(self): timer = self.engine.loop(MagicMock()) self.assertTrue(timer in self.engine._callbacks) def test_deferred_added(self): timer = self.engine.defer(10, MagicMock()) self.assertTrue(timer in self.engine._deferreds) def test_deferred_with_zero_delay(self): self.assertRaises(ValueError, self.engine.defer, 0, MagicMock()) def test_deferred_with_negative_delay(self): self.assertRaises(ValueError, self.engine.defer, -1, MagicMock()) def test_cycle_added(self): timer = self.engine.cycle(10, MagicMock()) self.assertTrue(timer in self.engine._deferreds) def test_cycle_with_zero_delay(self): self.assertRaises(ValueError, self.engine.cycle, 0, MagicMock()) def test_cycle_with_negative_delay(self): self.assertRaises(ValueError, self.engine.cycle, -1, MagicMock()) def test_remove_timer_with_no_end(self): timer = self.engine.callback(MagicMock()) self.engine._remove_timer(timer) def test_remove_nonexistent_timer_with_no_end(self): timer = MagicMock() timer.end = None self.engine._remove_timer(timer) def test_remove_timer_with_end(self): timer = self.engine.defer(10, MagicMock()) self.engine._remove_timer(timer) def test_remove_nonexistent_timer_with_end(self): timer = MagicMock() timer.end = 1 self.engine._remove_timer(timer)
def setUp(self): engine = Engine.instance() self.server = HTTPServer(self.request_handler, engine=engine) self.server.listen(('127.0.0.1', 4040)) PantsTestCase.setUp(self, engine)
class TestEnginePoll(unittest.TestCase): def setUp(self): self.engine = Engine() def test_poll_updates_time(self): current_time = self.engine.latest_poll_time time.sleep(0.02) self.engine.poll(0.02) self.assertTrue(self.engine.latest_poll_time > current_time) def test_poll_executes_callbacks(self): callback = MagicMock() callback.function = MagicMock() callback.requeue = False self.engine._callbacks.append(callback) self.engine.poll(0.02) callback.function.assert_called_once_with() self.assertTrue(len(self.engine._callbacks) == 0) def test_callback_exception_doesnt_break_poll(self): callback = MagicMock() callback.function = MagicMock(side_effect=Exception) callback.requeue = False self.engine._callbacks.append(callback) try: self.engine.poll(0.02) except Exception: self.fail("Exception in callback function was not caught.") def test_keyboardinterrupt_during_callback_processing_is_raised(self): callback = MagicMock() callback.function = MagicMock(side_effect=KeyboardInterrupt) callback.requeue = False self.engine._callbacks.append(callback) self.assertRaises(KeyboardInterrupt, self.engine.poll, 0.02) def test_systemexit_during_callback_processing_is_raised(self): callback = MagicMock() callback.function = MagicMock(side_effect=SystemExit) callback.requeue = False self.engine._callbacks.append(callback) self.assertRaises(SystemExit, self.engine.poll, 0.02) def test_poll_requeues_loops(self): loop = MagicMock() loop.function = MagicMock() loop.requeue = True self.engine._callbacks.append(loop) self.engine.poll(0.02) self.assertTrue(loop in self.engine._callbacks) def test_poll_executes_deferreds(self): defer = MagicMock() defer.function = MagicMock() defer.requeue = False defer.end = self.engine.latest_poll_time - 1 self.engine._deferreds.append(defer) self.engine.poll(0.02) defer.function.assert_called_once_with() def test_deferred_exception_doesnt_break_poll(self): defer = MagicMock() defer.function = MagicMock() defer.requeue = False defer.end = self.engine.latest_poll_time - 1 self.engine._deferreds.append(defer) try: self.engine.poll(0.02) except Exception: self.fail("Exception in deferred was not caught.") def test_keyboardinterrupt_during_deferred_processing_is_raised(self): defer = MagicMock() defer.function = MagicMock(side_effect=KeyboardInterrupt) defer.requeue = False defer.end = self.engine.latest_poll_time - 1 self.engine._deferreds.append(defer) self.assertRaises(KeyboardInterrupt, self.engine.poll, 0.02) def test_systemexit_during_deferred_processing_is_raised(self): defer = MagicMock() defer.function = MagicMock(side_effect=SystemExit) defer.requeue = False defer.end = self.engine.latest_poll_time - 1 self.engine._deferreds.append(defer) self.assertRaises(SystemExit, self.engine.poll, 0.02) def test_poll_requeues_deferreds(self): cycle = MagicMock() cycle.function = MagicMock() cycle.requeue = True cycle.end = self.engine.latest_poll_time - 1 cycle.delay = 10 self.engine._deferreds.append(cycle) self.engine.poll(0.02) self.assertTrue(cycle in self.engine._deferreds) def test_poll_returns_if_timer_shuts_down_engine(self): # Pretty ugly way of testing this, to be honest. self.engine._poller.poll = MagicMock() self.engine._channels = {1: None} self.engine.callback(self.engine.stop) self.engine.poll(0.02) self.assertRaises(AssertionError, self.engine._poller.poll.assert_called_once_with) def test_poll_sleeps_for_poll_timeout(self): before = time.time() self.engine.poll(0.225) after = time.time() # It's never exactly the timeout length, but it gets very close. self.assertTrue((after - before) > 0.22) def test_poll_sleeps_until_next_deferred(self): defer = MagicMock() defer.function = MagicMock() defer.requeue = False self.engine._deferreds.append(defer) before = time.time() defer.end = before + 0.225 self.engine.poll(1) after = time.time() # Again, never going to be exact. self.assertTrue((after - before) < 0.25) def test_poller_successful(self): self.engine._channels = {1: None} self.engine._poller.poll = MagicMock() self.engine.poll(0.02) self.engine._poller.poll.assert_called_once_with(0.02) def test_poller_raises_EINTR(self): self.engine._channels = {1: None} self.engine._poller.poll = MagicMock( side_effect=Exception(errno.EINTR)) try: self.engine.poll(0.02) except Exception as err: if err.args[0] == errno.EINTR: self.fail("EINTR during polling was not caught.") def test_poller_raises_unknown(self): self.engine._channels = {1: None} self.engine._poller.poll = MagicMock(side_effect=Exception) self.assertRaises(Exception, self.engine.poll, 0.02) def test_poll_processes_events(self): channel = MagicMock() channel._handle_events = MagicMock() self.engine._channels = {1: channel} self.engine._poller.poll = MagicMock( return_value={1: Engine.ALL_EVENTS}) self.engine.poll(0.02) channel._handle_events.assert_called_once_with(Engine.ALL_EVENTS) def test_event_processing_error_doesnt_break_poll(self): channel = MagicMock() channel._handle_events = MagicMock(side_effect=Exception) self.engine._channels = {1: channel} self.engine._poller.poll = MagicMock( return_value={1: Engine.ALL_EVENTS}) try: self.engine.poll(0.02) except Exception: self.fail( "Exception raised during event processing was not caught.") def test_keyboardinterrupt_during_event_processing_is_raised(self): channel = MagicMock() channel._handle_events = MagicMock(side_effect=KeyboardInterrupt) self.engine._channels = {1: channel} self.engine._poller.poll = MagicMock( return_value={1: Engine.ALL_EVENTS}) self.assertRaises(KeyboardInterrupt, self.engine.poll, 0.02) def test_systemexit_during_event_processing_is_raised(self): channel = MagicMock() channel._handle_events = MagicMock(side_effect=SystemExit) self.engine._channels = {1: channel} self.engine._poller.poll = MagicMock( return_value={1: Engine.ALL_EVENTS}) self.assertRaises(SystemExit, self.engine.poll, 0.02)
def test_engine_local_instances(self): engine1 = Engine() engine2 = Engine() self.assertFalse(engine1 is engine2)
def setUp(self): self.engine = Engine()
def setUp(self): self.times_called = [] self.engine = Engine()
def setUp(self, engine=None): if not engine: engine = Engine.instance() self._engine = engine self._engine_thread = threading.Thread(target=self._engine.start) self._engine_thread.start()