Exemplo n.º 1
0
 def test_simpleReprs(self):
     """
     Verify that the various Box objects repr properly, for debugging.
     """
     self.assertEquals(type(repr(amp._TLSBox())), str)
     self.assertEquals(type(repr(amp._SwitchBox('a'))), str)
     self.assertEquals(type(repr(amp.QuitBox())), str)
     self.assertEquals(type(repr(amp.AmpBox())), str)
     self.failUnless("AmpBox" in repr(amp.AmpBox()))
Exemplo n.º 2
0
        def formatError(error):
            if error.check(amp.RemoteAmpError):
                code = error.value.errorCode
                desc = error.value.description

                # Evennia extra logging
                desc += " (error logged on other side)"
                _get_logger().log_err(
                    f"AMP caught exception ({desc}):\n{error.value}")

                if isinstance(desc, str):
                    desc = desc.encode("utf-8", "replace")
                if error.value.fatal:
                    errorBox = amp.QuitBox()
                else:
                    errorBox = amp.AmpBox()
            else:
                errorBox = amp.QuitBox()
                _get_logger().log_err(
                    error)  # server-side logging if unhandled error
                code = UNKNOWN_ERROR_CODE
                desc = b"Unknown Error"
            errorBox[ERROR] = box[ASK]
            errorBox[ERROR_DESCRIPTION] = desc
            errorBox[ERROR_CODE] = code
            return errorBox
Exemplo n.º 3
0
class TestRPCProtocol_UnhandledErrorsWhenHandlingResponses(MAASTestCase):

    answer_seq = b"%d" % random.randrange(0, 2**32)
    answer_box = amp.AmpBox(_answer=answer_seq)

    error_seq = b"%d" % random.randrange(0, 2**32)
    error_box = amp.AmpBox(
        _error=error_seq,
        _error_code=amp.UNHANDLED_ERROR_CODE,
        _error_description=factory.make_string(),
    )

    scenarios = (
        ("_answerReceived", {
            "seq": answer_seq,
            "box": answer_box
        }),
        ("_errorReceived", {
            "seq": error_seq,
            "box": error_box
        }),
    )

    def test_unhandled_errors_logged_and_do_not_cause_disconnection(self):
        self.patch(common.log, "debug")
        protocol = common.RPCProtocol()
        protocol.makeConnection(StringTransport())
        # Poke a request into the dispatcher that will always fail.
        d = Deferred().addCallback(lambda _: 0 / 0)
        protocol._outstandingRequests[self.seq] = d
        # Push a box in response to the request.
        with TwistedLoggerFixture() as logger:
            protocol.ampBoxReceived(self.box)
        # The Deferred does not have a dangling error.
        self.assertThat(extract_result(d), Is(None))
        # The transport is still connected.
        self.assertThat(protocol.transport.disconnecting, Is(False))
        # The error has been logged.
        self.assertDocTestMatches(
            """\
            Unhandled failure during AMP request. This is probably a bug.
            Please ensure that this error is handled within application code.
            Traceback (most recent call last):
            ...
            """,
            logger.output,
        )
Exemplo n.º 4
0
    def test__replaces_missing_ask_with_none(self):
        box = amp.AmpBox(_command=b"command")

        self.patch(common, "gethostname").return_value = "host"
        self.patch(common, "getpid").return_value = 1234

        self.assertThat(common.make_command_ref(box), Equals(
            "host:pid=1234:cmd=command:ask=none"))
Exemplo n.º 5
0
    def test_unhandled_errors_do_not_cause_disconnection(self):
        self.patch(common.log, "debug")
        protocol = common.RPCProtocol()
        protocol.makeConnection(StringTransport())
        # Ensure that the superclass dispatchCommand() will fail.
        dispatchCommand = self.patch(amp.AMP, "dispatchCommand")
        dispatchCommand.side_effect = always_fail_with(ZeroDivisionError())
        # Push a command box into the protocol.
        seq = b"%d" % random.randrange(0, 2**32)
        cmd = factory.make_string().encode("ascii")
        box = amp.AmpBox(_ask=seq, _command=cmd)
        with TwistedLoggerFixture() as logger:
            protocol.ampBoxReceived(box)
        # The transport is still connected.
        self.expectThat(protocol.transport.disconnecting, Is(False))
        # The error has been logged on the originating side of the AMP
        # session, along with an explanatory message. The message includes a
        # command reference.
        cmd_ref = common.make_command_ref(box)
        self.assertDocTestMatches(
            """\
            Unhandled failure dispatching AMP command. This is probably a bug.
            Please ensure that this error is handled within application code
            or declared in the signature of the %s command. [%s]
            Traceback (most recent call last):
            ...

            """ % (cmd, cmd_ref),
            logger.output,
        )
        # A simpler error message has been transmitted over the wire. It
        # includes the same command reference as logged locally.
        protocol.transport.io.seek(0)
        observed_boxes_sent = amp.parse(protocol.transport.io)
        expected_boxes_sent = [
            amp.AmpBox(
                _error=seq,
                _error_code=amp.UNHANDLED_ERROR_CODE,
                _error_description=(b"Unknown Error [%s]" %
                                    cmd_ref.encode("ascii")),
            )
        ]
        self.assertThat(observed_boxes_sent, Equals(expected_boxes_sent))
Exemplo n.º 6
0
    def test__command_ref_includes_host_pid_command_and_ask_sequence(self):
        host = factory.make_name("hostname")
        pid = random.randint(99, 9999999)
        cmd = factory.make_name("command").encode("ascii")
        ask = str(random.randint(99, 9999999)).encode("ascii")
        box = amp.AmpBox(_command=cmd, _ask=ask)

        self.patch(common, "gethostname").return_value = host
        self.patch(common, "getpid").return_value = pid

        self.assertThat(
            common.make_command_ref(box), Equals("%s:pid=%s:cmd=%s:ask=%s" % (
                host, pid, cmd.decode("ascii"), ask.decode("ascii"))))
Exemplo n.º 7
0
    def test_brokenReturnValue(self):
        """
        It can be very confusing if you write some code which responds to a
        command, but gets the return value wrong.  Most commonly you end up
        returning None instead of a dictionary.

        Verify that if that happens, the framework logs a useful error.
        """
        L = []
        SimpleSymmetricCommandProtocol().dispatchCommand(
            amp.AmpBox(_command=BrokenReturn.commandName)).addErrback(L.append)
        blr = L[0].trap(amp.BadLocalReturn)
        self.failUnlessIn('None', repr(L[0].value))