Esempio n. 1
0
            def handle_connect_error(fail):
                unrecoverable_error = False

                # FIXME - make txaio friendly
                # Can connect_f ever be in a cancelled state?
                # if txaio.using_asyncio and isinstance(fail.value, asyncio.CancelledError):
                #     unrecoverable_error = True

                self.log.debug(u'component failed: {error}',
                               error=txaio.failure_message(fail))
                self.log.debug(u'{tb}',
                               tb=txaio.failure_format_traceback(fail))
                # If this is a "fatal error" that will never work,
                # we bail out now
                if isinstance(fail.value, ApplicationError):
                    if fail.value.error in [
                            u'wamp.error.no_such_realm',
                            u'wamp.error.no_auth_method'
                    ]:
                        unrecoverable_error = True
                        self.log.error(u"Fatal error, not reconnecting")

                    self.log.error(u"{msg}", msg=fail.value.error_message())

                elif isinstance(fail.value, OSError):
                    # failed to connect entirely, like nobody
                    # listening etc.
                    self.log.info(u"Connection failed: {msg}",
                                  msg=txaio.failure_message(fail))

                elif self._is_ssl_error(fail.value):
                    # Quoting pyOpenSSL docs: "Whenever
                    # [SSL.Error] is raised directly, it has a
                    # list of error messages from the OpenSSL
                    # error queue, where each item is a tuple
                    # (lib, function, reason). Here lib, function
                    # and reason are all strings, describing where
                    # and what the problem is. See err(3) for more
                    # information."
                    self.log.error(u"TLS failure: {reason}",
                                   reason=fail.value.args[1])
                    self.log.error(u"Marking this transport as failed")
                    transport_candidate[0].failed()
                else:
                    # This is some unknown failure, e.g. could
                    # be SyntaxError etc so we're aborting the
                    # whole mission
                    self.log.error(
                        u'Connection failed: {error}',
                        error=txaio.failure_message(fail),
                    )
                    unrecoverable_error = True

                if unrecoverable_error:
                    txaio.reject(done_f, fail)
                    return

                txaio.call_later(0, transport_check, None)
                return
Esempio n. 2
0
                    def main_success(_):
                        self.log.debug("main_success")

                        def leave():
                            try:
                                session.leave()
                            except SessionNotReady:
                                # someone may have already called
                                # leave()
                                pass
                        txaio.call_later(0, leave)
Esempio n. 3
0
                    def main_success(_):
                        self.log.debug("main_success")

                        def leave():
                            try:
                                session.leave()
                            except SessionNotReady:
                                # someone may have already called
                                # leave()
                                pass
                        txaio.call_later(0, leave)
Esempio n. 4
0
def test_default_reactor():
    """
    run the code that defaults txaio.config.loop
    """
    pytest.importorskip('twisted')

    assert txaio.config.loop is None
    txaio.call_later(1, lambda: None)

    from twisted.internet import reactor
    assert txaio.config.loop is reactor
Esempio n. 5
0
def test_default_reactor(framework_tx):
    """
    run the code that defaults txaio.config.loop
    """
    pytest.importorskip('twisted')

    assert txaio.config.loop is None
    try:
        txaio.call_later(1, lambda: None)

        from twisted.internet import reactor
        assert txaio.config.loop is reactor
    finally:
        txaio.config.loop = None
Esempio n. 6
0
            def handle_connect_error(fail):
                # FIXME - make txaio friendly
                # Can connect_f ever be in a cancelled state?
                # if txaio.using_asyncio and isinstance(fail.value, asyncio.CancelledError):
                #     unrecoverable_error = True

                self.log.debug(u'component failed: {error}',
                               error=txaio.failure_message(fail))
                self.log.debug(u'{tb}',
                               tb=txaio.failure_format_traceback(fail))
                # If this is a "fatal error" that will never work,
                # we bail out now
                if isinstance(fail.value, ApplicationError):
                    self.log.error(u"{msg}", msg=fail.value.error_message())

                elif isinstance(fail.value, OSError):
                    # failed to connect entirely, like nobody
                    # listening etc.
                    self.log.info(u"Connection failed: {msg}",
                                  msg=txaio.failure_message(fail))

                elif self._is_ssl_error(fail.value):
                    # Quoting pyOpenSSL docs: "Whenever
                    # [SSL.Error] is raised directly, it has a
                    # list of error messages from the OpenSSL
                    # error queue, where each item is a tuple
                    # (lib, function, reason). Here lib, function
                    # and reason are all strings, describing where
                    # and what the problem is. See err(3) for more
                    # information."
                    # (and 'args' is a 1-tuple containing the above
                    # 3-tuple...)
                    ssl_lib, ssl_func, ssl_reason = fail.value.args[0][0]
                    self.log.error(u"TLS failure: {reason}", reason=ssl_reason)
                else:
                    self.log.error(
                        u'Connection failed: {error}',
                        error=txaio.failure_message(fail),
                    )

                if self._is_fatal is None:
                    is_fatal = False
                else:
                    is_fatal = self._is_fatal(fail.value)
                if is_fatal:
                    self.log.info("Error was fatal; failing transport")
                    transport_candidate[0].failed()

                txaio.call_later(0, transport_check, None)
                return
Esempio n. 7
0
def test_call_later_aio(framework_aio):
    '''
    Wait for two Futures.
    '''

    # Trollius doesn't come with this, so won't work on py2
    pytest.importorskip('asyncio.test_utils')

    def time_gen():
        when = yield
        assert when == 1
        # even though we only do one call, I guess TestLoop needs
        # a "trailing" yield? "or something"
        when = yield 0
        print("Hmmm", when)
    from asyncio.test_utils import TestLoop
    new_loop = TestLoop(time_gen)

    calls = []
    with replace_loop(new_loop) as fake_loop:
        def foo(*args, **kw):
            calls.append((args, kw))

        delay = txaio.call_later(1, foo, 5, 6, 7, foo="bar")
        assert len(calls) == 0
        assert hasattr(delay, 'cancel')
        fake_loop.advance_time(2)
        fake_loop._run_once()

        assert len(calls) == 1
        assert calls[0][0] == (5, 6, 7)
        assert calls[0][1] == dict(foo="bar")
Esempio n. 8
0
def test_call_later_aio(framework_aio):
    '''
    Wait for two Futures.
    '''

    # Trollius doesn't come with this, so won't work on py2
    pytest.importorskip('asyncio.test_utils')

    def time_gen():
        when = yield
        assert when == 1
        # even though we only do one call, I guess TestLoop needs
        # a "trailing" yield? "or something"
        when = yield 0

    from asyncio.test_utils import TestLoop
    new_loop = TestLoop(time_gen)

    calls = []
    with replace_loop(new_loop) as fake_loop:

        def foo(*args, **kw):
            calls.append((args, kw))

        delay = txaio.call_later(1, foo, 5, 6, 7, foo="bar")
        assert len(calls) == 0
        assert hasattr(delay, 'cancel')
        fake_loop.advance_time(2)
        fake_loop._run_once()

        assert len(calls) == 1
        assert calls[0][0] == (5, 6, 7)
        assert calls[0][1] == dict(foo="bar")
Esempio n. 9
0
            def handle_connect_error(fail):
                # FIXME - make txaio friendly
                # Can connect_f ever be in a cancelled state?
                # if txaio.using_asyncio and isinstance(fail.value, asyncio.CancelledError):
                #     unrecoverable_error = True

                self.log.debug(u'component failed: {error}', error=txaio.failure_message(fail))
                self.log.debug(u'{tb}', tb=txaio.failure_format_traceback(fail))
                # If this is a "fatal error" that will never work,
                # we bail out now
                if isinstance(fail.value, ApplicationError):
                    self.log.error(u"{msg}", msg=fail.value.error_message())

                elif isinstance(fail.value, OSError):
                    # failed to connect entirely, like nobody
                    # listening etc.
                    self.log.info(u"Connection failed: {msg}", msg=txaio.failure_message(fail))

                elif self._is_ssl_error(fail.value):
                    # Quoting pyOpenSSL docs: "Whenever
                    # [SSL.Error] is raised directly, it has a
                    # list of error messages from the OpenSSL
                    # error queue, where each item is a tuple
                    # (lib, function, reason). Here lib, function
                    # and reason are all strings, describing where
                    # and what the problem is. See err(3) for more
                    # information."
                    # (and 'args' is a 1-tuple containing the above
                    # 3-tuple...)
                    ssl_lib, ssl_func, ssl_reason = fail.value.args[0][0]
                    self.log.error(u"TLS failure: {reason}", reason=ssl_reason)
                else:
                    self.log.error(
                        u'Connection failed: {error}',
                        error=txaio.failure_message(fail),
                    )

                if self._is_fatal is None:
                    is_fatal = False
                else:
                    is_fatal = self._is_fatal(fail.value)
                if is_fatal:
                    self.log.info("Error was fatal; failing transport")
                    transport_candidate[0].failed()

                txaio.call_later(0, transport_check, None)
                return
Esempio n. 10
0
                            def _notify_some(receivers):

                                # we do a first pass over the proposed chunk of receivers
                                # because not all of them will have a transport, and if this
                                # will be the last chunk of receivers we need to figure out
                                # which event is last...
                                receivers_this_chunk = []
                                for receiver in receivers[:chunk_size]:
                                    if receiver._session_id and receiver._transport:
                                        receivers_this_chunk.append(receiver)
                                    else:
                                        vanished_receivers.append(receiver)

                                receivers = receivers[chunk_size:]

                                # XXX note there's still going to be some edge-cases here .. if
                                # we are NOT the last chunk, but all the next chunk's receivers
                                # (could be only 1 in that chunk!) vanish before we run our next
                                # batch, then a "last" event will never go out ...

                                # we now actually do the deliveries, but now we know which
                                # receiver is the last one
                                if receivers or not self._router.is_traced:

                                    # NOT the last chunk (or we're not traced so don't care)
                                    for receiver in receivers_this_chunk:

                                        # send out WAMP msg to peer
                                        self._router.send(receiver, msg)
                                        if self._event_store or storing_event:
                                            self._event_store.store_event_history(publication, subscription.id, receiver)
                                else:
                                    # last chunk, so last receiver gets the different message
                                    for receiver in receivers_this_chunk[:-1]:
                                        self._router.send(receiver, msg)
                                        if self._event_store or storing_event:
                                            self._event_store.store_event_history(publication, subscription.id, receiver)

                                    # FIXME: I don't get the following comment and code path. when, how? and what to
                                    # do about event store? => storing_event
                                    #
                                    # we might have zero valid receivers
                                    if receivers_this_chunk:
                                        self._router.send(receivers_this_chunk[-1], last_msg)
                                        # FIXME: => storing_event

                                if receivers:
                                    # still more to do ..
                                    return txaio.call_later(0, _notify_some, receivers)
                                else:
                                    # all done! resolve all_d, which represents all receivers
                                    # to a single subscription matching the event
                                    txaio.resolve(all_d, None)
Esempio n. 11
0
                            def _notify_some(receivers):

                                # we do a first pass over the proposed chunk of receivers
                                # because not all of them will have a transport, and if this
                                # will be the last chunk of receivers we need to figure out
                                # which event is last...
                                receivers_this_chunk = []
                                for receiver in receivers[:chunk_size]:
                                    if receiver._session_id and receiver._transport:
                                        receivers_this_chunk.append(receiver)
                                    else:
                                        vanished_receivers.append(receiver)

                                receivers = receivers[chunk_size:]

                                # XXX note there's still going to be some edge-cases here .. if
                                # we are NOT the last chunk, but all the next chunk's receivers
                                # (could be only 1 in that chunk!) vanish before we run our next
                                # batch, then a "last" event will never go out ...

                                # we now actually do the deliveries, but now we know which
                                # receiver is the last one
                                if receivers or not self._router.is_traced:

                                    # NOT the last chunk (or we're not traced so don't care)
                                    for receiver in receivers_this_chunk:

                                        # send out WAMP msg to peer
                                        self._router.send(receiver, msg)
                                        if self._event_store or storing_event:
                                            self._event_store.store_event_history(publication, subscription.id, receiver)
                                else:
                                    # last chunk, so last receiver gets the different message
                                    for receiver in receivers_this_chunk[:-1]:
                                        self._router.send(receiver, msg)
                                        if self._event_store or storing_event:
                                            self._event_store.store_event_history(publication, subscription.id, receiver)

                                    # FIXME: I don't get the following comment and code path. when, how? and what to
                                    # do about event store? => storing_event
                                    #
                                    # we might have zero valid receivers
                                    if receivers_this_chunk:
                                        self._router.send(receivers_this_chunk[-1], last_msg)
                                        # FIXME: => storing_event

                                if receivers:
                                    # still more to do ..
                                    return txaio.call_later(0, _notify_some, receivers)
                                else:
                                    # all done! resolve all_d, which represents all receivers
                                    # to a single subscription matching the event
                                    txaio.resolve(all_d, None)
Esempio n. 12
0
 def _notify_some(receivers):
     for receiver in receivers[:chunk_size]:
         if (me_also or receiver != session) and receiver != self._event_store:
             # the receiving subscriber session
             # might have no transport, or no
             # longer be joined
             if receiver._session_id and receiver._transport:
                 self._router.send(receiver, msg)
     receivers = receivers[chunk_size:]
     if len(receivers) > 0:
         return txaio.call_later(0, _notify_some, receivers)
     else:
         txaio.resolve(all_d, None)
Esempio n. 13
0
    def test_asyncio_component(event_loop):
        orig_loop = txaio.config.loop
        txaio.config.loop = event_loop

        comp = Component(
            transports=[
                {
                    "url": "ws://localhost:12/bogus",
                    "max_retries": 1,
                    "max_retry_delay": 0.1,
                }
            ]
        )

        # if having trouble, try starting some logging (and use
        # "py.test -s" to get real-time output)
        # txaio.start_logging(level="debug")
        f = comp.start(loop=event_loop)
        txaio.config.loop = event_loop
        finished = txaio.create_future()

        def fail():
            finished.set_exception(AssertionError("timed out"))
            txaio.config.loop = orig_loop
        txaio.call_later(4.0, fail)

        def done(f):
            try:
                f.result()
                finished.set_exception(AssertionError("should get an error"))
            except RuntimeError as e:
                if 'Exhausted all transport connect attempts' not in str(e):
                    finished.set_exception(AssertionError("wrong exception caught"))
            finished.set_result(None)
            txaio.config.loop = orig_loop
            assert comp._done_f is None
        f.add_done_callback(done)
        return finished
Esempio n. 14
0
                            def _notify_some(receivers):

                                # we do a first pass over the proposed chunk of receivers
                                # because not all of them will have a transport, and if this
                                # will be the last chunk of receivers we need to figure out
                                # which event is last...
                                receivers_this_chunk = []
                                for receiver in receivers[:chunk_size]:
                                    if (me_also or receiver != session
                                        ) and receiver != self._event_store:
                                        # the receiving subscriber session might have no transport,
                                        # or no longer be joined
                                        if receiver._session_id and receiver._transport:
                                            receivers_this_chunk.append(
                                                receiver)
                                        else:
                                            vanished_receivers.append(receiver)

                                receivers = receivers[chunk_size:]

                                # XXX note there's still going to be some edge-cases here .. if
                                # we are NOT the last chunk, but all the next chunk's receivers
                                # (could be only 1 in that chunk!) vanish before we run our next
                                # batch, then a "last" event will never go out ...

                                # we now actually do the deliveries, but now we know which
                                # receiver is the last one
                                if receivers or not self._router.is_traced:
                                    # NOT the last chunk (or we're not traced so don't care)
                                    for receiver in receivers_this_chunk:
                                        self._router.send(receiver, msg)
                                else:
                                    # last chunk, so last receiver gets the different message
                                    for receiver in receivers_this_chunk[:-1]:
                                        self._router.send(receiver, msg)
                                    # we might have zero valid receivers
                                    if receivers_this_chunk:
                                        self._router.send(
                                            receivers_this_chunk[-1], last_msg)

                                if receivers:
                                    # still more to do ..
                                    return txaio.call_later(
                                        0, _notify_some, receivers)
                                else:
                                    # all done! resolve all_d, which represents all receivers
                                    # to a single subscription matching the event
                                    txaio.resolve(all_d, None)
Esempio n. 15
0
def test_call_later():
    '''
    Wait for two Futures.
    '''

    # set up a test reactor or event-loop depending on asyncio or
    # Twisted
    twisted = False
    try:
        from twisted.internet.task import Clock
        new_loop = Clock()
        twisted = True
    except ImportError:
        # Trollius doesn't come with this, so won't work on py2
        pytest.importorskip('asyncio.test_utils')

        def time_gen():
            when = yield
            assert when == 1
            # even though we only do one call, I guess TestLoop needs
            # a "trailing" yield? "or something"
            when = yield 0
            print("Hmmm", when)
        from asyncio.test_utils import TestLoop
        new_loop = TestLoop(time_gen)

    calls = []
    with replace_loop(new_loop) as fake_loop:
        def foo(*args, **kw):
            calls.append((args, kw))

        delay = txaio.call_later(1, foo, 5, 6, 7, foo="bar")
        assert len(calls) == 0
        assert hasattr(delay, 'cancel')
        if twisted:
            fake_loop.advance(2)
        else:
            # XXX maybe we monkey-patch a ".advance()" onto asyncio
            # loops that does both of these?
            fake_loop.advance_time(2)
            fake_loop._run_once()

        assert len(calls) == 1
        assert calls[0][0] == (5, 6, 7)
        assert calls[0][1] == dict(foo="bar")
Esempio n. 16
0
 def _notify_some(receivers):
     for receiver in receivers[:chunk_size]:
         if (
                 me_also or receiver != session
         ) and receiver != self._event_store:
             # the receiving subscriber session
             # might have no transport, or no
             # longer be joined
             if receiver._session_id and receiver._transport:
                 self._router.send(
                     receiver, msg)
     receivers = receivers[chunk_size:]
     if len(receivers) > 0:
         # still more to do ..
         return txaio.call_later(
             0, _notify_some, receivers)
     else:
         # all done! resolve all_d, which represents all receivers
         # to a single subscription matching the event
         txaio.resolve(all_d, None)
Esempio n. 17
0
def test_call_later_tx(framework_tx):
    '''
    Wait for two Futures.
    '''

    from twisted.internet.task import Clock
    new_loop = Clock()
    calls = []
    with replace_loop(new_loop) as fake_loop:
        def foo(*args, **kw):
            calls.append((args, kw))

        delay = txaio.call_later(1, foo, 5, 6, 7, foo="bar")
        assert len(calls) == 0
        assert hasattr(delay, 'cancel')
        fake_loop.advance(2)

        assert len(calls) == 1
        assert calls[0][0] == (5, 6, 7)
        assert calls[0][1] == dict(foo="bar")
Esempio n. 18
0
def test_call_later_tx(framework_tx):
    '''
    Wait for two Futures.
    '''

    from twisted.internet.task import Clock
    new_loop = Clock()
    calls = []
    with replace_loop(new_loop) as fake_loop:

        def foo(*args, **kw):
            calls.append((args, kw))

        delay = txaio.call_later(1, foo, 5, 6, 7, foo="bar")
        assert len(calls) == 0
        assert hasattr(delay, 'cancel')
        fake_loop.advance(2)

        assert len(calls) == 1
        assert calls[0][0] == (5, 6, 7)
        assert calls[0][1] == dict(foo="bar")
Esempio n. 19
0
    def callRemoteMessage(self, mcall, timeout = None):
        """
        Uses the specified L{message.MethodCallMessage} to call a remote method.

        @rtype: L{twisted.internet.defer.Deferred}
        @returns: a Deferred to the result of the remote method call
        """
        assert isinstance(mcall, message.MethodCallMessage)
        
        if mcall.expectReply:
            d = txaio.create_future()

            if timeout:
                timeout = txaio.call_later(timeout, self._onMethodTimeout, mcall.serial, d)

            self._pendingCalls[ mcall.serial ] = (d, timeout)

            self.sendMessage( mcall )

            return d
        else:
            self.sendMessage( mcall )

            return txaio.create_future_success(None)
Esempio n. 20
0
    def test_asyncio_component_404(event_loop):
        """
        If something connects but then gets aborted, it should still try
        to re-connect (in real cases this could be e.g. wrong path,
        TLS failure, WebSocket handshake failure, etc)
        """
        orig_loop = txaio.config.loop
        txaio.config.loop = event_loop

        class FakeTransport(object):
            def close(self):
                pass

            def write(self, data):
                pass

        fake_transport = FakeTransport()
        actual_protocol = [None]  # set in a closure below

        def create_connection(protocol_factory=None, server_hostname=None, host=None, port=None, ssl=False):
            if actual_protocol[0] is None:
                protocol = protocol_factory()
                actual_protocol[0] = protocol
                protocol.connection_made(fake_transport)
                return txaio.create_future_success((fake_transport, protocol))
            else:
                return txaio.create_future_error(RuntimeError("second connection fails completely"))

        with mock.patch.object(event_loop, 'create_connection', create_connection):
            event_loop.create_connection = create_connection

            comp = Component(
                transports=[
                    {
                        "url": "ws://localhost:12/bogus",
                        "max_retries": 1,
                        "max_retry_delay": 0.1,
                    }
                ]
            )

            # if having trouble, try starting some logging (and use
            # "py.test -s" to get real-time output)
            # txaio.start_logging(level="debug")
            f = comp.start(loop=event_loop)
            txaio.config.loop = event_loop

            # now that we've started connecting, we *should* be able
            # to connetion_lost our transport .. but we do a
            # call-later to ensure we're after the setup stuff in the
            # event-loop (because asyncio doesn't synchronously
            # process already-completed Futures like Twisted does)

            def nuke_transport():
                actual_protocol[0].connection_lost(None)  # asyncio can call this with None
            txaio.call_later(0.1, nuke_transport)

            finished = txaio.create_future()

            def fail():
                finished.set_exception(AssertionError("timed out"))
                txaio.config.loop = orig_loop
            txaio.call_later(1.0, fail)

            def done(f):
                try:
                    f.result()
                    finished.set_exception(AssertionError("should get an error"))
                except RuntimeError as e:
                    if 'Exhausted all transport connect attempts' not in str(e):
                        finished.set_exception(AssertionError("wrong exception caught"))
                finished.set_result(None)
                txaio.config.loop = orig_loop
            f.add_done_callback(done)
            return finished
Esempio n. 21
0
 async def generate_otp(self):
     key = str(random.randint(100000, 999999))
     self._pending_otps.append(key)
     txaio.call_later(60, self._revoke_otp, key)
     return key