class CommandFailureTests(CommandMixin, TestCase):
    """
    Tests for correct failure of commands on a disconnected
    L{MemCacheProtocol}.
    """

    def setUp(self):
        """
        Create a disconnected memcache client, using a deterministic clock.
        """
        self.proto = MemCacheProtocol()
        self.clock = Clock()
        self.proto.callLater = self.clock.callLater
        self.transport = StringTransportWithDisconnection()
        self.transport.protocol = self.proto
        self.proto.makeConnection(self.transport)
        self.transport.loseConnection()


    def _test(self, d, send, recv, result):
        """
        Implementation of C{_test} which checks that the command fails with
        C{RuntimeError} because the transport is disconnected. All the
        parameters except C{d} are ignored.
        """
        return self.assertFailure(d, RuntimeError)
예제 #2
0
    def _testDataForward(self, data, method="GET", body=""):
        """
        Build a fake proxy connection, and send C{data} over it, checking that
        it's forwarded to the originating request.
        """
        # Connect everything
        clientTransport = StringTransportWithDisconnection()
        serverTransport = StringTransportWithDisconnection()
        channel = DummyChannel(serverTransport)
        parent = DummyParent(channel)
        serverTransport.protocol = channel

        client = ProxyClient(method, '/foo', 'HTTP/1.0',
                             {"accept": "text/html"}, body, parent)
        clientTransport.protocol = client
        client.makeConnection(clientTransport)

        # Check data sent
        self.assertEquals(clientTransport.value(),
            "%s /foo HTTP/1.0\r\n"
            "connection: close\r\n"
            "accept: text/html\r\n\r\n%s" % (method, body))

        # Fake an answer
        client.dataReceived(data)

        # Check that the data has been forwarded
        self.assertEquals(serverTransport.value(), data)

        clientTransport.loseConnection()
        self.assertIsInstance(channel.lostReason, ConnectionDone)
예제 #3
0
    def _testDataForward(self, data, method="GET", body=""):
        """
        Build a fake proxy connection, and send C{data} over it, checking that
        it's forwarded to the originating request.
        """
        # Connect everything
        clientTransport = StringTransportWithDisconnection()
        serverTransport = StringTransportWithDisconnection()
        channel = DummyChannel(serverTransport)
        parent = DummyParent(channel)
        serverTransport.protocol = channel

        client = ProxyClient(method, '/foo', 'HTTP/1.0',
                             {"accept": "text/html"}, body, parent)
        clientTransport.protocol = client
        client.makeConnection(clientTransport)

        # Check data sent
        self.assertEquals(
            clientTransport.value(), "%s /foo HTTP/1.0\r\n"
            "connection: close\r\n"
            "accept: text/html\r\n\r\n%s" % (method, body))

        # Fake an answer
        client.dataReceived(data)

        # Check that the data has been forwarded
        self.assertEquals(serverTransport.value(), data)

        clientTransport.loseConnection()
        self.assertIsInstance(channel.lostReason, ConnectionDone)
예제 #4
0
class CommandFailureTests(CommandMixin, TestCase):
    """
    Tests for correct failure of commands on a disconnected
    L{MemCacheProtocol}.
    """

    def setUp(self):
        """
        Create a disconnected memcache client, using a deterministic clock.
        """
        self.proto = MemCacheProtocol()
        self.clock = Clock()
        self.proto.callLater = self.clock.callLater
        self.transport = StringTransportWithDisconnection()
        self.transport.protocol = self.proto
        self.proto.makeConnection(self.transport)
        self.transport.loseConnection()


    def _test(self, d, send, recv, result):
        """
        Implementation of C{_test} which checks that the command fails with
        C{RuntimeError} because the transport is disconnected. All the
        parameters except C{d} are ignored.
        """
        return self.assertFailure(d, RuntimeError)
예제 #5
0
class TestProtocol(common.TestCase):

    def setUp(self):
        self.transport = StringTransportWithDisconnection()
        self.protocol = httpclient.Protocol(self, owner=None)
        self.protocol.factory = MockFactory()
        self.protocol.makeConnection(self.transport)
        self.transport.protocol = self.protocol

        self.addCleanup(self._disconnect_protocol)

    @defer.inlineCallbacks
    def testSimpleRequest(self):
        self.assertTrue(self.protocol.factory.onConnectionMade_called)
        self.assertTrue(self.protocol.is_idle())

        d = self.protocol.request(http.Methods.GET, '/',
                                  headers={'accept': 'text/html'})
        self.assertEqual('GET / HTTP/1.1\r\n'
                         'Accept: text/html\r\n\r\n', self.transport.value())

        self.assertFalse(self.protocol.is_idle())

        self.protocol.dataReceived(
            self.protocol.delimiter.join([
                "HTTP/1.1 200 OK",
                "Content-Type: text/html",
                "Content-Length: 12",
                "",
                "This is body",
                ]))
        response = yield d
        self.assertIsInstance(response, httpclient.Response)
        self.assertEqual(200, response.status)
        self.assertEqual({'content-type': 'text/html',
                          'content-length': '12'}, response.headers)
        self.assertEqual('This is body', response.body)
        self.assertTrue(self.protocol.is_idle())

        self.assertTrue(self.protocol.factory.onConnectionReset_called)

    @defer.inlineCallbacks
    def testCancelledRequest(self):
        d = self.protocol.request(http.Methods.GET, '/',
                                  headers={'accept': 'text/html'})
        d.cancel()

        self.assertFalse(self.transport.connected)
        self.assertFailure(d, httpclient.RequestCancelled)
        f = yield d
        exp = ('GET to http://10.0.0.1:12345/ was cancelled '
               '0.(\d+)s after it was sent.')
        self.assertTrue(re.match(exp, str(f)), str(f))

    def _disconnect_protocol(self):
        if self.transport.connected:
            self.transport.loseConnection()
        self.assertTrue(self.protocol.factory.onConnectionLost_called)
예제 #6
0
    def _testDataForward(self,
                         code,
                         message,
                         headers,
                         body,
                         method="GET",
                         requestBody="",
                         loseConnection=True):
        """
        Build a fake proxy connection, and send C{data} over it, checking that
        it's forwarded to the originating request.
        """
        request = DummyRequest(['foo'])

        # Connect a proxy client to a fake transport.
        clientTransport = StringTransportWithDisconnection()
        client = ProxyClient(method, '/foo', 'HTTP/1.0',
                             {"accept": "text/html"}, requestBody, request)
        clientTransport.protocol = client
        client.makeConnection(clientTransport)

        # Check data sent
        self.assertEquals(
            clientTransport.value(), "%s /foo HTTP/1.0\r\n"
            "connection: close\r\n"
            "accept: text/html\r\n\r\n%s" % (method, requestBody))

        # Fake an answer
        client.dataReceived("HTTP/1.0 %d %s\r\n" % (code, message))
        for (header, values) in headers:
            for value in values:
                client.dataReceived("%s: %s\r\n" % (header, value))
        client.dataReceived("\r\n" + body)

        # Check that the response data has been forwarded back to the original
        # requester.
        self.assertEquals(request.responseCode, code)
        self.assertEquals(request.responseMessage, message)
        receivedHeaders = list(request.responseHeaders.getAllRawHeaders())
        receivedHeaders.sort()
        expectedHeaders = headers[:]
        expectedHeaders.sort()
        self.assertEquals(receivedHeaders, expectedHeaders)
        self.assertEquals(''.join(request.written), body)

        # Check that when the response is done, the request is finished.
        if loseConnection:
            clientTransport.loseConnection()

        # Even if we didn't call loseConnection, the transport should be
        # disconnected.  This lets us not rely on the server to close our
        # sockets for us.
        self.assertFalse(clientTransport.connected)
        self.assertEquals(request.finished, 1)
예제 #7
0
파일: test_epmd.py 프로젝트: gbour/twotp
 def test_kill(self):
     """
     L{OneShotPortMapperFactory.kill} should return a L{Deferred} that
     will be called back when the kill request is complete.
     """
     d = self.factory.kill()
     transport = StringTransportWithDisconnection()
     proto = self.factory.buildProtocol(("127.0.01", 4369))
     proto.makeConnection(transport)
     transport.protocol = proto
     self.assertEqual(transport.value(), "\x00\x01k")
     proto.dataReceived("OK")
     transport.loseConnection()
     return d.addCallback(self.assertEqual, "OK")
예제 #8
0
파일: test_epmd.py 프로젝트: gbour/twotp
 def test_names(self):
     """
     L{OneShotPortMapperFactory.names} should return a L{Deferred} that
     will be called back when the names request is complete.
     """
     d = self.factory.names()
     transport = StringTransportWithDisconnection()
     proto = self.factory.buildProtocol(("127.0.01", 4369))
     proto.makeConnection(transport)
     transport.protocol = proto
     self.assertEqual(transport.value(), "\x00\x01n")
     proto.dataReceived("\x00\x00\x00\x01")
     proto.dataReceived("name %s at port %s\n" % ("foo", 1234))
     transport.loseConnection()
     return d.addCallback(self.assertEqual, [("foo", 1234)])
예제 #9
0
파일: test_proxy.py 프로젝트: Almad/twisted
    def _testDataForward(self, code, message, headers, body, method="GET",
                         requestBody="", loseConnection=True):
        """
        Build a fake proxy connection, and send C{data} over it, checking that
        it's forwarded to the originating request.
        """
        request = DummyRequest(['foo'])

        # Connect a proxy client to a fake transport.
        clientTransport = StringTransportWithDisconnection()
        client = ProxyClient(method, '/foo', 'HTTP/1.0',
                             {"accept": "text/html"}, requestBody, request)
        clientTransport.protocol = client
        client.makeConnection(clientTransport)

        # Check data sent
        self.assertEquals(clientTransport.value(),
            "%s /foo HTTP/1.0\r\n"
            "connection: close\r\n"
            "accept: text/html\r\n\r\n%s" % (method, requestBody))

        # Fake an answer
        client.dataReceived("HTTP/1.0 %d %s\r\n" % (code, message))
        for (header, values) in headers:
            for value in values:
                client.dataReceived("%s: %s\r\n" % (header, value))
        client.dataReceived("\r\n" + body)

        # Check that the response data has been forwarded back to the original
        # requester.
        self.assertEquals(request.responseCode, code)
        self.assertEquals(request.responseMessage, message)
        receivedHeaders = list(request.responseHeaders.getAllRawHeaders())
        receivedHeaders.sort()
        expectedHeaders = headers[:]
        expectedHeaders.sort()
        self.assertEquals(receivedHeaders, expectedHeaders)
        self.assertEquals(''.join(request.written), body)

        # Check that when the response is done, the request is finished.
        if loseConnection:
            clientTransport.loseConnection()

        # Even if we didn't call loseConnection, the transport should be
        # disconnected.  This lets us not rely on the server to close our
        # sockets for us.
        self.assertFalse(clientTransport.connected)
        self.assertEquals(request.finished, 1)
예제 #10
0
    def test_breakReferenceCycle(self):
        """
        L{policies.ProtocolWrapper.connectionLost} sets C{wrappedProtocol} to
        C{None} in order to break reference cycle between wrapper and wrapped
        protocols.
        :return:
        """
        wrapper = policies.ProtocolWrapper(policies.WrappingFactory(Server()),
                                           protocol.Protocol())
        transport = StringTransportWithDisconnection()
        transport.protocol = wrapper
        wrapper.makeConnection(transport)

        self.assertIsNotNone(wrapper.wrappedProtocol)
        transport.loseConnection()
        self.assertIsNone(wrapper.wrappedProtocol)
예제 #11
0
 def test_names(self):
     """
     L{Process.names} returns the list of nodes on a particular host.
     """
     d = self.process.names("spam")
     epmd = self.process.oneShotEpmds["spam"]
     transport = StringTransportWithDisconnection()
     proto = epmd.buildProtocol(("127.0.01", 4369))
     proto.makeConnection(transport)
     transport.protocol = proto
     self.assertEqual(transport.value(), "\x00\x01n")
     proto.dataReceived("\x00\x00\x00\x01")
     proto.dataReceived("name %s at port %s\n" % ("foo", 1234))
     proto.dataReceived("name %s at port %s\n" % ("egg", 4321))
     transport.loseConnection()
     return d.addCallback(self.assertEqual, [("foo", 1234), ("egg", 4321)])
예제 #12
0
파일: test_epmd.py 프로젝트: gbour/twotp
 def test_dump(self):
     """
     L{OneShotPortMapperFactory.dump} should return a L{Deferred} that
     will be called back when the dump request is complete.
     """
     d = self.factory.dump()
     transport = StringTransportWithDisconnection()
     proto = self.factory.buildProtocol(("127.0.01", 4369))
     proto.makeConnection(transport)
     transport.protocol = proto
     self.assertEqual(transport.value(), "\x00\x01d")
     proto.dataReceived("\x00\x00\x00\x01")
     proto.dataReceived(
         "active name    <%s> at port %s, fd = %s\n\x00" % ("foo", 1234, 3))
     transport.loseConnection()
     return d.addCallback(
         self.assertEqual, {"active": [("foo", 1234, 3)], "old": []})
class TestClientProtocolReconnectionAttemps(TestCase):
    def setUp(self):
        CONNECTION_INFO = {'username': '******', 'password': '******', 'udpipsend': '172.19.51.145',
                           'baudrate': '500000', 'name': 'Universidade de Vigo', 'parameters': 'yes',
                           'tcpportsend': '1234', 'tcpipsend': '127.0.0.1', 'udpipreceive': '127.0.0.1',
                           'attempts': '10', 'serverip': '172.19.51.143', 'serialport': '/dev/ttyUSB0',
                           'tcpportreceive': 4321, 'connection': 'udp', 'udpportreceive': 57008,
                           'serverport': 25345, 'reconnection': 'no', 'udpportsend': '57009',
                           'tcpipreceive': '127.0.0.1'}

        GS = 'VigoTest'

        gsi = GroundStationInterface(CONNECTION_INFO, GS, AMP)
        threads = object

        self.sp = client_amp.ClientProtocol(CONNECTION_INFO, gsi, threads)
        self.sp.factory = MockFactory()
        self.transport = StringTransportWithDisconnection()
        self.sp.makeConnection(self.transport)

        self.transport.protocol = self.sp

        self.correctFrame = ("00:82:a0:00:00:53:45:52:50:2d:42:30:91:1d:1b:03:" +
                             "8d:0b:5c:03:02:28:01:9c:01:ab:02:4c:02:98:01:da:" +
                             "02:40:00:00:00:10:0a:46:58:10:00:c4:9d:cb:a2:21:39")

        self.wrongFrame = 9

    def tearDown(self):
        pass

    # TODO Complete description
    def test_clientconnectionLost(self):
        """

        @return:
        """
        self.transport.loseConnection()
        return self.assertFalse(self.transport.connected)

    # TODO Complete description
    def test_clientConnectionFailed(self):
        """

        @return:
        """
        self.transport.loseConnection()
        return self.assertFalse(self.transport.connected)

    # TODO Complete description
    @patch.object(client_amp.ClientProtocol, 'callRemote')
    def test_clientEndConnection(self, callRemote):
        """

        @param callRemote:
        @return:
        """
        self.transport.loseConnection()
        self.sp.end_connection()
        return self.assertTrue(callRemote.called)
예제 #14
0
class TestServerProtocolConnectionEstablished(TestCase):
    """
    Testing multiple client connections
    TDOD. Test multiple valid connections
    """
    def setUp(self):
        self.sp = CredReceiver()
        self.sp.factory = CredAMPServerFactory()
        self.transport = StringTransportWithDisconnection()

    def tearDown(self):
        self.transport.loseConnection()

    def test_connectionProtocolEstablished(self):
        """
        Checks if transport is working an clients list has the last client.
        :return:
        """
        self.sp.makeConnection(self.transport)
        self.transport.protocol = self.sp

        return self.assertTrue(self.transport.connected),\
               self.assertEqual(len(self.sp.factory.clients), 1)
예제 #15
0
class Network(unittest.TestCase):

    def setUp(self):
        self.proto = Redis()
        self.clock = Clock()
        self.proto.callLater = self.clock.callLater
        self.transport = StringTransportWithDisconnection()
        self.transport.protocol = self.proto
        self.proto.makeConnection(self.transport)

    def test_request_while_disconnected(self):
        # fake disconnect
        self.proto._disconnected = True

        d = self.proto.get('foo')
        self.assertFailure(d, RuntimeError)

        def checkMessage(error):
            self.assertEquals(str(error), 'Not connected')

        return d.addCallback(checkMessage)

    def test_disconnect_during_request(self):
        d1 = self.proto.get("foo")
        d2 = self.proto.get("bar")
        self.assertEquals(len(self.proto._request_queue), 2)

        self.transport.loseConnection()
        done = defer.DeferredList([d1, d2], consumeErrors=True)

        def checkFailures(results):
            self.assertEquals(len(self.proto._request_queue), 0)
            for success, result in results:
                self.assertFalse(success)
                result.trap(error.ConnectionDone)

        return done.addCallback(checkFailures)
예제 #16
0
class NetworkTestCase(unittest.TestCase):
    def setUp(self):
        self.proto = Redis()
        self.clock = Clock()
        self.proto.callLater = self.clock.callLater
        self.transport = StringTransportWithDisconnection()
        self.transport.protocol = self.proto
        self.proto.makeConnection(self.transport)

    def test_request_while_disconnected(self):
        # fake disconnect
        self.proto._disconnected = True

        d = self.proto.get('foo')
        self.assertFailure(d, RuntimeError)

        def checkMessage(error):
            self.assertEquals(str(error), 'Not connected')

        return d.addCallback(checkMessage)

    def test_disconnect_during_request(self):
        d1 = self.proto.get("foo")
        d2 = self.proto.get("bar")
        self.assertEquals(len(self.proto._request_queue), 2)

        self.transport.loseConnection()
        done = defer.DeferredList([d1, d2], consumeErrors=True)

        def checkFailures(results):
            self.assertEquals(len(self.proto._request_queue), 0)
            for success, result in results:
                self.assertFalse(success)
                result.trap(error.ConnectionDone)

        return done.addCallback(checkFailures)
예제 #17
0
class WebSocketsProtocolWrapperTest(MAASTestCase):
    """
    Tests for L{WebSocketsProtocolWrapper}.
    """
    def setUp(self):
        super(WebSocketsProtocolWrapperTest, self).setUp()
        self.accumulatingProtocol = AccumulatingProtocol()
        self.protocol = WebSocketsProtocolWrapper(self.accumulatingProtocol)
        self.transport = StringTransportWithDisconnection()
        self.protocol.makeConnection(self.transport)
        self.transport.protocol = self.protocol

    def test_dataReceived(self):
        """
        L{WebSocketsProtocolWrapper.dataReceived} forwards frame content to the
        underlying protocol.
        """
        self.protocol.dataReceived(
            _makeFrame(b"Hello", CONTROLS.TEXT, True, mask=b"abcd"))
        self.assertEqual(b"Hello", self.accumulatingProtocol.data)

    def test_controlFrames(self):
        """
        L{WebSocketsProtocolWrapper} doesn't forward data from control frames
        to the underlying protocol.
        """
        self.protocol.dataReceived(
            _makeFrame(b"Hello", CONTROLS.PING, True, mask=b"abcd"))
        self.protocol.dataReceived(
            _makeFrame(b"Hello", CONTROLS.PONG, True, mask=b"abcd"))
        self.protocol.dataReceived(
            _makeFrame(b"", CONTROLS.CLOSE, True, mask=b"abcd"))
        self.assertEqual(b"", self.accumulatingProtocol.data)

    def test_loseConnection(self):
        """
        L{WebSocketsProtocolWrapper.loseConnection} sends a close frame and
        disconnects the transport.
        """
        self.protocol.loseConnection()
        self.assertFalse(self.transport.connected)
        self.assertEqual(b"\x88\x02\x03\xe8", self.transport.value())

    def test_write(self):
        """
        L{WebSocketsProtocolWrapper.write} creates and writes a frame from the
        payload passed.
        """
        self.accumulatingProtocol.transport.write(b"Hello")
        self.assertEqual(b"\x81\x05Hello", self.transport.value())

    def test_writeSequence(self):
        """
        L{WebSocketsProtocolWrapper.writeSequence} writes a frame for every
        chunk passed.
        """
        self.accumulatingProtocol.transport.writeSequence([b"Hello", b"World"])
        self.assertEqual(b"\x81\x05Hello\x81\x05World", self.transport.value())

    def test_getHost(self):
        """
        L{WebSocketsProtocolWrapper.getHost} returns the transport C{getHost}.
        """
        self.assertEqual(self.transport.getHost(),
                         self.accumulatingProtocol.transport.getHost())

    def test_getPeer(self):
        """
        L{WebSocketsProtocolWrapper.getPeer} returns the transport C{getPeer}.
        """
        self.assertEqual(self.transport.getPeer(),
                         self.accumulatingProtocol.transport.getPeer())

    def test_connectionLost(self):
        """
        L{WebSocketsProtocolWrapper.connectionLost} forwards the connection
        lost call to the underlying protocol.
        """
        self.transport.loseConnection()
        self.assertTrue(self.accumulatingProtocol.closed)
예제 #18
0
class WebSocketsProtocolWrapperTest(TestCase):
    """
    Tests for L{WebSocketsProtocolWrapper}.
    """

    def setUp(self):
        self.accumulatingProtocol = AccumulatingProtocol()
        self.protocol = WebSocketsProtocolWrapper(self.accumulatingProtocol)
        self.transport = StringTransportWithDisconnection()
        self.protocol.makeConnection(self.transport)
        self.transport.protocol = self.protocol


    def test_dataReceived(self):
        """
        L{WebSocketsProtocolWrapper.dataReceived} forwards frame content to the
        underlying protocol.
        """
        self.protocol.dataReceived(
            _makeFrame("Hello", CONTROLS.TEXT, True, mask="abcd"))
        self.assertEqual("Hello", self.accumulatingProtocol.data)


    def test_controlFrames(self):
        """
        L{WebSocketsProtocolWrapper} doesn't forward data from control frames
        to the underlying protocol.
        """
        self.protocol.dataReceived(
            _makeFrame("Hello", CONTROLS.PING, True, mask="abcd"))
        self.protocol.dataReceived(
            _makeFrame("Hello", CONTROLS.PONG, True, mask="abcd"))
        self.protocol.dataReceived(
            _makeFrame("", CONTROLS.CLOSE, True, mask="abcd"))
        self.assertEqual("", self.accumulatingProtocol.data)


    def test_loseConnection(self):
        """
        L{WebSocketsProtocolWrapper.loseConnection} sends a close frame and
        disconnects the transport.
        """
        self.protocol.loseConnection()
        self.assertFalse(self.transport.connected)
        self.assertEqual("\x88\x02\x03\xe8", self.transport.value())


    def test_write(self):
        """
        L{WebSocketsProtocolWrapper.write} creates and writes a frame from the
        payload passed.
        """
        self.accumulatingProtocol.transport.write("Hello")
        self.assertEqual("\x81\x05Hello", self.transport.value())


    def test_writeSequence(self):
        """
        L{WebSocketsProtocolWrapper.writeSequence} writes a frame for every
        chunk passed.
        """
        self.accumulatingProtocol.transport.writeSequence(["Hello", "World"])
        self.assertEqual("\x81\x05Hello\x81\x05World", self.transport.value())


    def test_getHost(self):
        """
        L{WebSocketsProtocolWrapper.getHost} returns the transport C{getHost}.
        """
        self.assertEqual(self.transport.getHost(),
                         self.accumulatingProtocol.transport.getHost())


    def test_getPeer(self):
        """
        L{WebSocketsProtocolWrapper.getPeer} returns the transport C{getPeer}.
        """
        self.assertEqual(self.transport.getPeer(),
                         self.accumulatingProtocol.transport.getPeer())


    def test_connectionLost(self):
        """
        L{WebSocketsProtocolWrapper.connectionLost} forwards the connection
        lost call to the underlying protocol.
        """
        self.transport.loseConnection()
        self.assertTrue(self.accumulatingProtocol.closed)
예제 #19
0
class MemCacheTests(CommandMixin, TestCase):
    """
    Test client protocol class L{MemCacheProtocol}.
    """
    def setUp(self):
        """
        Create a memcache client, connect it to a string protocol, and make it
        use a deterministic clock.
        """
        self.proto = MemCacheProtocol()
        self.clock = Clock()
        self.proto.callLater = self.clock.callLater
        self.transport = StringTransportWithDisconnection()
        self.transport.protocol = self.proto
        self.proto.makeConnection(self.transport)

    def _test(self, d, send, recv, result):
        """
        Implementation of C{_test} which checks that the command sends C{send}
        data, and that upon reception of C{recv} the result is C{result}.

        @param d: the resulting deferred from the memcache command.
        @type d: C{Deferred}

        @param send: the expected data to be sent.
        @type send: C{bytes}

        @param recv: the data to simulate as reception.
        @type recv: C{bytes}

        @param result: the expected result.
        @type result: C{any}
        """
        def cb(res):
            self.assertEqual(res, result)

        self.assertEqual(self.transport.value(), send)
        d.addCallback(cb)
        self.proto.dataReceived(recv)
        return d

    def test_invalidGetResponse(self):
        """
        If the value returned doesn't match the expected key of the current
        C{get} command, an error is raised in L{MemCacheProtocol.dataReceived}.
        """
        self.proto.get(b"foo")
        self.assertRaises(
            RuntimeError,
            self.proto.dataReceived,
            b"VALUE bar 0 7\r\nspamegg\r\nEND\r\n",
        )

    def test_invalidMultipleGetResponse(self):
        """
        If the value returned doesn't match one the expected keys of the
        current multiple C{get} command, an error is raised error in
        L{MemCacheProtocol.dataReceived}.
        """
        self.proto.getMultiple([b"foo", b"bar"])
        self.assertRaises(
            RuntimeError,
            self.proto.dataReceived,
            b"VALUE egg 0 7\r\nspamegg\r\nEND\r\n",
        )

    def test_invalidEndResponse(self):
        """
        If an END is received in response to an operation that isn't C{get},
        C{gets}, or C{stats}, an error is raised in
        L{MemCacheProtocol.dataReceived}.
        """
        self.proto.set(b"key", b"value")
        self.assertRaises(RuntimeError, self.proto.dataReceived, b"END\r\n")

    def test_timeOut(self):
        """
        Test the timeout on outgoing requests: when timeout is detected, all
        current commands fail with a L{TimeoutError}, and the connection is
        closed.
        """
        d1 = self.proto.get(b"foo")
        d2 = self.proto.get(b"bar")
        d3 = Deferred()
        self.proto.connectionLost = d3.callback

        self.clock.advance(self.proto.persistentTimeOut)
        self.assertFailure(d1, TimeoutError)
        self.assertFailure(d2, TimeoutError)

        def checkMessage(error):
            self.assertEqual(str(error), "Connection timeout")

        d1.addCallback(checkMessage)
        self.assertFailure(d3, ConnectionDone)
        return gatherResults([d1, d2, d3])

    def test_timeoutRemoved(self):
        """
        When a request gets a response, no pending timeout call remains around.
        """
        d = self.proto.get(b"foo")

        self.clock.advance(self.proto.persistentTimeOut - 1)
        self.proto.dataReceived(b"VALUE foo 0 3\r\nbar\r\nEND\r\n")

        def check(result):
            self.assertEqual(result, (0, b"bar"))
            self.assertEqual(len(self.clock.calls), 0)

        d.addCallback(check)
        return d

    def test_timeOutRaw(self):
        """
        Test the timeout when raw mode was started: the timeout is not reset
        until all the data has been received, so we can have a L{TimeoutError}
        when waiting for raw data.
        """
        d1 = self.proto.get(b"foo")
        d2 = Deferred()
        self.proto.connectionLost = d2.callback

        self.proto.dataReceived(b"VALUE foo 0 10\r\n12345")
        self.clock.advance(self.proto.persistentTimeOut)
        self.assertFailure(d1, TimeoutError)
        self.assertFailure(d2, ConnectionDone)
        return gatherResults([d1, d2])

    def test_timeOutStat(self):
        """
        Test the timeout when stat command has started: the timeout is not
        reset until the final B{END} is received.
        """
        d1 = self.proto.stats()
        d2 = Deferred()
        self.proto.connectionLost = d2.callback

        self.proto.dataReceived(b"STAT foo bar\r\n")
        self.clock.advance(self.proto.persistentTimeOut)
        self.assertFailure(d1, TimeoutError)
        self.assertFailure(d2, ConnectionDone)
        return gatherResults([d1, d2])

    def test_timeoutPipelining(self):
        """
        When two requests are sent, a timeout call remains around for the
        second request, and its timeout time is correct.
        """
        d1 = self.proto.get(b"foo")
        d2 = self.proto.get(b"bar")
        d3 = Deferred()
        self.proto.connectionLost = d3.callback

        self.clock.advance(self.proto.persistentTimeOut - 1)
        self.proto.dataReceived(b"VALUE foo 0 3\r\nbar\r\nEND\r\n")

        def check(result):
            self.assertEqual(result, (0, b"bar"))
            self.assertEqual(len(self.clock.calls), 1)
            for i in range(self.proto.persistentTimeOut):
                self.clock.advance(1)
            return self.assertFailure(d2, TimeoutError).addCallback(checkTime)

        def checkTime(ignored):
            # Check that the timeout happened C{self.proto.persistentTimeOut}
            # after the last response
            self.assertEqual(self.clock.seconds(),
                             2 * self.proto.persistentTimeOut - 1)

        d1.addCallback(check)
        self.assertFailure(d3, ConnectionDone)
        return d1

    def test_timeoutNotReset(self):
        """
        Check that timeout is not resetted for every command, but keep the
        timeout from the first command without response.
        """
        d1 = self.proto.get(b"foo")
        d3 = Deferred()
        self.proto.connectionLost = d3.callback

        self.clock.advance(self.proto.persistentTimeOut - 1)
        d2 = self.proto.get(b"bar")
        self.clock.advance(1)
        self.assertFailure(d1, TimeoutError)
        self.assertFailure(d2, TimeoutError)
        self.assertFailure(d3, ConnectionDone)
        return gatherResults([d1, d2, d3])

    def test_timeoutCleanDeferreds(self):
        """
        C{timeoutConnection} cleans the list of commands that it fires with
        C{TimeoutError}: C{connectionLost} doesn't try to fire them again, but
        sets the disconnected state so that future commands fail with a
        C{RuntimeError}.
        """
        d1 = self.proto.get(b"foo")
        self.clock.advance(self.proto.persistentTimeOut)
        self.assertFailure(d1, TimeoutError)
        d2 = self.proto.get(b"bar")
        self.assertFailure(d2, RuntimeError)
        return gatherResults([d1, d2])

    def test_connectionLost(self):
        """
        When disconnection occurs while commands are still outstanding, the
        commands fail.
        """
        d1 = self.proto.get(b"foo")
        d2 = self.proto.get(b"bar")
        self.transport.loseConnection()
        done = DeferredList([d1, d2], consumeErrors=True)

        def checkFailures(results):
            for success, result in results:
                self.assertFalse(success)
                result.trap(ConnectionDone)

        return done.addCallback(checkFailures)

    def test_tooLongKey(self):
        """
        An error is raised when trying to use a too long key: the called
        command returns a L{Deferred} which fails with a L{ClientError}.
        """
        d1 = self.assertFailure(self.proto.set(b"a" * 500, b"bar"),
                                ClientError)
        d2 = self.assertFailure(self.proto.increment(b"a" * 500), ClientError)
        d3 = self.assertFailure(self.proto.get(b"a" * 500), ClientError)
        d4 = self.assertFailure(self.proto.append(b"a" * 500, b"bar"),
                                ClientError)
        d5 = self.assertFailure(self.proto.prepend(b"a" * 500, b"bar"),
                                ClientError)
        d6 = self.assertFailure(self.proto.getMultiple([b"foo", b"a" * 500]),
                                ClientError)
        return gatherResults([d1, d2, d3, d4, d5, d6])

    def test_invalidCommand(self):
        """
        When an unknown command is sent directly (not through public API), the
        server answers with an B{ERROR} token, and the command fails with
        L{NoSuchCommand}.
        """
        d = self.proto._set(b"egg", b"foo", b"bar", 0, 0, b"")
        self.assertEqual(self.transport.value(), b"egg foo 0 0 3\r\nbar\r\n")
        self.assertFailure(d, NoSuchCommand)
        self.proto.dataReceived(b"ERROR\r\n")
        return d

    def test_clientError(self):
        """
        Test the L{ClientError} error: when the server sends a B{CLIENT_ERROR}
        token, the originating command fails with L{ClientError}, and the error
        contains the text sent by the server.
        """
        a = b"eggspamm"
        d = self.proto.set(b"foo", a)
        self.assertEqual(self.transport.value(),
                         b"set foo 0 0 8\r\neggspamm\r\n")
        self.assertFailure(d, ClientError)

        def check(err):
            self.assertEqual(str(err), repr(b"We don't like egg and spam"))

        d.addCallback(check)
        self.proto.dataReceived(b"CLIENT_ERROR We don't like egg and spam\r\n")
        return d

    def test_serverError(self):
        """
        Test the L{ServerError} error: when the server sends a B{SERVER_ERROR}
        token, the originating command fails with L{ServerError}, and the error
        contains the text sent by the server.
        """
        a = b"eggspamm"
        d = self.proto.set(b"foo", a)
        self.assertEqual(self.transport.value(),
                         b"set foo 0 0 8\r\neggspamm\r\n")
        self.assertFailure(d, ServerError)

        def check(err):
            self.assertEqual(str(err), repr(b"zomg"))

        d.addCallback(check)
        self.proto.dataReceived(b"SERVER_ERROR zomg\r\n")
        return d

    def test_unicodeKey(self):
        """
        Using a non-string key as argument to commands raises an error.
        """
        d1 = self.assertFailure(self.proto.set("foo", b"bar"), ClientError)
        d2 = self.assertFailure(self.proto.increment("egg"), ClientError)
        d3 = self.assertFailure(self.proto.get(1), ClientError)
        d4 = self.assertFailure(self.proto.delete("bar"), ClientError)
        d5 = self.assertFailure(self.proto.append("foo", b"bar"), ClientError)
        d6 = self.assertFailure(self.proto.prepend("foo", b"bar"), ClientError)
        d7 = self.assertFailure(self.proto.getMultiple([b"egg", 1]),
                                ClientError)
        return gatherResults([d1, d2, d3, d4, d5, d6, d7])

    def test_unicodeValue(self):
        """
        Using a non-string value raises an error.
        """
        return self.assertFailure(self.proto.set(b"foo", "bar"), ClientError)

    def test_pipelining(self):
        """
        Multiple requests can be sent subsequently to the server, and the
        protocol orders the responses correctly and dispatch to the
        corresponding client command.
        """
        d1 = self.proto.get(b"foo")
        d1.addCallback(self.assertEqual, (0, b"bar"))
        d2 = self.proto.set(b"bar", b"spamspamspam")
        d2.addCallback(self.assertEqual, True)
        d3 = self.proto.get(b"egg")
        d3.addCallback(self.assertEqual, (0, b"spam"))
        self.assertEqual(
            self.transport.value(),
            b"get foo\r\nset bar 0 0 12\r\nspamspamspam\r\nget egg\r\n",
        )
        self.proto.dataReceived(b"VALUE foo 0 3\r\nbar\r\nEND\r\n"
                                b"STORED\r\n"
                                b"VALUE egg 0 4\r\nspam\r\nEND\r\n")
        return gatherResults([d1, d2, d3])

    def test_getInChunks(self):
        """
        If the value retrieved by a C{get} arrive in chunks, the protocol
        is able to reconstruct it and to produce the good value.
        """
        d = self.proto.get(b"foo")
        d.addCallback(self.assertEqual, (0, b"0123456789"))
        self.assertEqual(self.transport.value(), b"get foo\r\n")
        self.proto.dataReceived(b"VALUE foo 0 10\r\n0123456")
        self.proto.dataReceived(b"789")
        self.proto.dataReceived(b"\r\nEND")
        self.proto.dataReceived(b"\r\n")
        return d

    def test_append(self):
        """
        L{MemCacheProtocol.append} behaves like a L{MemCacheProtocol.set}
        method: it returns a L{Deferred} which is called back with C{True} when
        the operation succeeds.
        """
        return self._test(
            self.proto.append(b"foo", b"bar"),
            b"append foo 0 0 3\r\nbar\r\n",
            b"STORED\r\n",
            True,
        )

    def test_prepend(self):
        """
        L{MemCacheProtocol.prepend} behaves like a L{MemCacheProtocol.set}
        method: it returns a L{Deferred} which is called back with C{True} when
        the operation succeeds.
        """
        return self._test(
            self.proto.prepend(b"foo", b"bar"),
            b"prepend foo 0 0 3\r\nbar\r\n",
            b"STORED\r\n",
            True,
        )

    def test_gets(self):
        """
        L{MemCacheProtocol.get} handles an additional cas result when
        C{withIdentifier} is C{True} and forward it in the resulting
        L{Deferred}.
        """
        return self._test(
            self.proto.get(b"foo", True),
            b"gets foo\r\n",
            b"VALUE foo 0 3 1234\r\nbar\r\nEND\r\n",
            (0, b"1234", b"bar"),
        )

    def test_emptyGets(self):
        """
        Test getting a non-available key with gets: it succeeds but return
        L{None} as value, C{0} as flag and an empty cas value.
        """
        return self._test(self.proto.get(b"foo", True), b"gets foo\r\n",
                          b"END\r\n", (0, b"", None))

    def test_getsMultiple(self):
        """
        L{MemCacheProtocol.getMultiple} handles an additional cas field in the
        returned tuples if C{withIdentifier} is C{True}.
        """
        return self._test(
            self.proto.getMultiple([b"foo", b"bar"], True),
            b"gets foo bar\r\n",
            b"VALUE foo 0 3 1234\r\negg\r\n"
            b"VALUE bar 0 4 2345\r\nspam\r\nEND\r\n",
            {
                b"bar": (0, b"2345", b"spam"),
                b"foo": (0, b"1234", b"egg")
            },
        )

    def test_getsMultipleIterableKeys(self):
        """
        L{MemCacheProtocol.getMultiple} accepts any iterable of keys.
        """
        return self._test(
            self.proto.getMultiple(iter([b"foo", b"bar"]), True),
            b"gets foo bar\r\n",
            b"VALUE foo 0 3 1234\r\negg\r\n"
            b"VALUE bar 0 4 2345\r\nspam\r\nEND\r\n",
            {
                b"bar": (0, b"2345", b"spam"),
                b"foo": (0, b"1234", b"egg")
            },
        )

    def test_getsMultipleWithEmpty(self):
        """
        When getting a non-available key with L{MemCacheProtocol.getMultiple}
        when C{withIdentifier} is C{True}, the other keys are retrieved
        correctly, and the non-available key gets a tuple of C{0} as flag,
        L{None} as value, and an empty cas value.
        """
        return self._test(
            self.proto.getMultiple([b"foo", b"bar"], True),
            b"gets foo bar\r\n",
            b"VALUE foo 0 3 1234\r\negg\r\nEND\r\n",
            {
                b"bar": (0, b"", None),
                b"foo": (0, b"1234", b"egg")
            },
        )

    def test_checkAndSet(self):
        """
        L{MemCacheProtocol.checkAndSet} passes an additional cas identifier
        that the server handles to check if the data has to be updated.
        """
        return self._test(
            self.proto.checkAndSet(b"foo", b"bar", cas=b"1234"),
            b"cas foo 0 0 3 1234\r\nbar\r\n",
            b"STORED\r\n",
            True,
        )

    def test_casUnknowKey(self):
        """
        When L{MemCacheProtocol.checkAndSet} response is C{EXISTS}, the
        resulting L{Deferred} fires with C{False}.
        """
        return self._test(
            self.proto.checkAndSet(b"foo", b"bar", cas=b"1234"),
            b"cas foo 0 0 3 1234\r\nbar\r\n",
            b"EXISTS\r\n",
            False,
        )
예제 #20
0
파일: test_epmd.py 프로젝트: gbour/twotp
class PortMapperProtocolTestCase(TestCase):
    """
    Tests for L{PortMapperProtocol}.
    """

    def setUp(self):
        """
        Create a protocol instance linked with a L{DummyPortMapperFactory}.
        """
        self.proto = PortMapperProtocol()
        self.proto.factory = DummyPortMapperFactory()
        self.transport = StringTransportWithDisconnection()
        self.proto.makeConnection(self.transport)
        self.transport.protocol = self.proto


    def test_alive2Response(self):
        """
        Test an successful alive2 response.
        """
        def cb(res):
            self.assertEqual(res, 1)
        self.proto.factory._connectDeferred.addCallback(cb)
        self.proto.dataReceived("y")
        self.proto.dataReceived("\x00")
        self.proto.dataReceived("\x00\x01")
        return self.proto.factory._connectDeferred


    def test_alive2ResponseError(self):
        """
        Test an erroneous alive2 response.
        """
        def eb(res):
            res.trap(ValueError)
        self.proto.factory._connectDeferred.addErrback(eb)
        self.proto.dataReceived("y\x01\x00\x01")
        return self.proto.factory._connectDeferred


    def test_alive2Request(self):
        """
        Test data sent by an alive2 request.
        """
        self.proto.alive2Request(1234, 77, (1, 2), "foo@bar")
        self.assertEqual(
            self.transport.value(),
            "\x00\x14x\x04\xd2M\x00\x00\x01\x00\x02\x00\x07foo@bar\x00\x00")


    def test_port2Response(self):
        """
        Test an successful port2 response.
        """
        d = Deferred()
        d.addCallback(self.assertEqual, Node(9, 77, 1, (5, 5), "bar", ""))
        self.proto.deferred = d
        self.proto.dataReceived("w")
        self.proto.dataReceived("\x00")
        self.proto.dataReceived("\x00\x09M\x01\x00\x05\x00\x05\x00\x03bar\x00")
        self.assertEqual(self.proto.received, "")
        return d


    def test_port2ResponseWithExtra(self):
        """
        Test an successful port2 response, with extra data.
        """
        d = Deferred()
        d.addCallback(
            self.assertEqual, Node(9, 77, 1, (5, 5), "bar", "spam"))
        self.proto.deferred = d
        self.proto.dataReceived(
            "w\x00\x00\x09M\x01\x00\x05\x00\x05\x00\x03bar\x00\x04spam")
        self.assertEqual(self.proto.received, "")
        return d


    def test_port2ResponseNodeNotFound(self):
        """
        Test a port2 not found response: the response deferred should be fired
        with a L{NodeNotFound} exception.
        """
        d = Deferred()
        self.proto.deferred = d
        self.proto.dataReceived("w\x01")
        self.assertEqual(self.proto.received, "")
        return self.assertFailure(d, NodeNotFound)


    def test_port2Request(self):
        """
        Test data sent by a port2 request.
        """
        d = Deferred()
        self.proto.portPlease2Request(d, "egg@spam")
        self.assertEqual(self.transport.value(), "\x00\tzegg@spam")
        self.assertEqual(self.proto.deferred, d)


    def test_names(self):
        """
        Test successful names request and response.
        """
        d = Deferred()
        d.addCallback(self.assertEqual, [("foo", 1234), ("egg", 4321)])
        self.proto.namesRequest(d)
        self.assertEqual(self.transport.value(), "\x00\x01n")
        self.proto.dataReceived("\x00\x00\x00\x01")
        self.proto.dataReceived("name %s at port %s\n" % ("foo", 1234))
        self.proto.dataReceived("name %s at port %s\n" % ("egg", 4321))
        self.transport.loseConnection()
        return d


    def test_dump(self):
        """
        Test successful dump request and response.
        """
        d = Deferred()
        d.addCallback(
            self.assertEqual, {"active": [("foo", 1234, 3)],
                               "old": [("egg", 4321, 2)]})
        self.proto.dumpRequest(d)
        self.assertEqual(self.transport.value(), "\x00\x01d")
        self.proto.dataReceived("\x00\x00\x00\x01")
        self.proto.dataReceived(
            "active name    <%s> at port %s, fd = %s\n\x00" % ("foo", 1234, 3))
        self.proto.dataReceived(
            "old/unused name, <%s>, at port %s, fd = %s\n\x00" % ("egg",
                                                                  4321, 2))
        self.transport.loseConnection()
        return d


    def test_kill(self):
        """
        Test successful kill request and response.
        """
        d = Deferred()
        d.addCallback(self.assertEqual, "OK")
        self.proto.killRequest(d)
        self.assertEqual(self.transport.value(), "\x00\x01k")
        self.proto.dataReceived("OK")
        self.transport.loseConnection()
        return d


    def test_invalidKillResponse(self):
        """
        Test a kill request with an invalid response.
        """
        d = Deferred()
        self.proto.killRequest(d)
        self.assertEqual(self.transport.value(), "\x00\x01k")
        self.proto.dataReceived("Wrong")
        self.transport.loseConnection()
        return self.assertFailure(d, ValueError)


    def test_connectionLostWithPendingDeferred(self):
        """
        Test that connectionLost errbacks the action deferred if present.
        """
        d = Deferred()
        self.proto.deferred = d
        self.transport.loseConnection()
        return self.assertFailure(d, ConnectionDone)


    def test_unhandledRequest(self):
        """
        When a unhandled data is received, the protocol should log a
        C{RuntimeError}.
        """
        self.proto.dataReceived("Wrong")
        errors = self.flushLoggedErrors()
        self.assertEqual(len(errors), 1)
        errors[0].trap(RuntimeError)
class MemCacheTestCase(CommandMixin, TestCase):
    """
    Test client protocol class L{MemCacheProtocol}.
    """

    def setUp(self):
        """
        Create a memcache client, connect it to a string protocol, and make it
        use a deterministic clock.
        """
        self.proto = MemCacheProtocol()
        self.clock = Clock()
        self.proto.callLater = self.clock.callLater
        self.transport = StringTransportWithDisconnection()
        self.transport.protocol = self.proto
        self.proto.makeConnection(self.transport)


    def _test(self, d, send, recv, result):
        """
        Implementation of C{_test} which checks that the command sends C{send}
        data, and that upon reception of C{recv} the result is C{result}.

        @param d: the resulting deferred from the memcache command.
        @type d: C{Deferred}

        @param send: the expected data to be sent.
        @type send: C{str}

        @param recv: the data to simulate as reception.
        @type recv: C{str}

        @param result: the expected result.
        @type result: C{any}
        """
        def cb(res):
            self.assertEquals(res, result)
        self.assertEquals(self.transport.value(), send)
        d.addCallback(cb)
        self.proto.dataReceived(recv)
        return d


    def test_invalidGetResponse(self):
        """
        If the value returned doesn't match the expected key of the current
        C{get} command, an error is raised in L{MemCacheProtocol.dataReceived}.
        """
        self.proto.get("foo")
        s = "spamegg"
        self.assertRaises(RuntimeError,
            self.proto.dataReceived,
            "VALUE bar 0 %s\r\n%s\r\nEND\r\n" % (len(s), s))


    def test_invalidMultipleGetResponse(self):
        """
        If the value returned doesn't match one the expected keys of the
        current multiple C{get} command, an error is raised error in
        L{MemCacheProtocol.dataReceived}.
        """
        self.proto.getMultiple(["foo", "bar"])
        s = "spamegg"
        self.assertRaises(RuntimeError,
            self.proto.dataReceived,
            "VALUE egg 0 %s\r\n%s\r\nEND\r\n" % (len(s), s))


    def test_timeOut(self):
        """
        Test the timeout on outgoing requests: when timeout is detected, all
        current commands fail with a L{TimeoutError}, and the connection is
        closed.
        """
        d1 = self.proto.get("foo")
        d2 = self.proto.get("bar")
        d3 = Deferred()
        self.proto.connectionLost = d3.callback

        self.clock.advance(self.proto.persistentTimeOut)
        self.assertFailure(d1, TimeoutError)
        self.assertFailure(d2, TimeoutError)
        def checkMessage(error):
            self.assertEquals(str(error), "Connection timeout")
        d1.addCallback(checkMessage)
        return gatherResults([d1, d2, d3])


    def test_timeoutRemoved(self):
        """
        When a request gets a response, no pending timeout call remains around.
        """
        d = self.proto.get("foo")

        self.clock.advance(self.proto.persistentTimeOut - 1)
        self.proto.dataReceived("VALUE foo 0 3\r\nbar\r\nEND\r\n")

        def check(result):
            self.assertEquals(result, (0, "bar"))
            self.assertEquals(len(self.clock.calls), 0)
        d.addCallback(check)
        return d


    def test_timeOutRaw(self):
        """
        Test the timeout when raw mode was started: the timeout is not reset
        until all the data has been received, so we can have a L{TimeoutError}
        when waiting for raw data.
        """
        d1 = self.proto.get("foo")
        d2 = Deferred()
        self.proto.connectionLost = d2.callback

        self.proto.dataReceived("VALUE foo 0 10\r\n12345")
        self.clock.advance(self.proto.persistentTimeOut)
        self.assertFailure(d1, TimeoutError)
        return gatherResults([d1, d2])


    def test_timeOutStat(self):
        """
        Test the timeout when stat command has started: the timeout is not
        reset until the final B{END} is received.
        """
        d1 = self.proto.stats()
        d2 = Deferred()
        self.proto.connectionLost = d2.callback

        self.proto.dataReceived("STAT foo bar\r\n")
        self.clock.advance(self.proto.persistentTimeOut)
        self.assertFailure(d1, TimeoutError)
        return gatherResults([d1, d2])


    def test_timeoutPipelining(self):
        """
        When two requests are sent, a timeout call remains around for the
        second request, and its timeout time is correct.
        """
        d1 = self.proto.get("foo")
        d2 = self.proto.get("bar")
        d3 = Deferred()
        self.proto.connectionLost = d3.callback

        self.clock.advance(self.proto.persistentTimeOut - 1)
        self.proto.dataReceived("VALUE foo 0 3\r\nbar\r\nEND\r\n")

        def check(result):
            self.assertEquals(result, (0, "bar"))
            self.assertEquals(len(self.clock.calls), 1)
            for i in range(self.proto.persistentTimeOut):
                self.clock.advance(1)
            return self.assertFailure(d2, TimeoutError).addCallback(checkTime)
        def checkTime(ignored):
            # Check that the timeout happened C{self.proto.persistentTimeOut}
            # after the last response
            self.assertEquals(
                self.clock.seconds(), 2 * self.proto.persistentTimeOut - 1)
        d1.addCallback(check)
        return d1


    def test_timeoutNotReset(self):
        """
        Check that timeout is not resetted for every command, but keep the
        timeout from the first command without response.
        """
        d1 = self.proto.get("foo")
        d3 = Deferred()
        self.proto.connectionLost = d3.callback

        self.clock.advance(self.proto.persistentTimeOut - 1)
        d2 = self.proto.get("bar")
        self.clock.advance(1)
        self.assertFailure(d1, TimeoutError)
        self.assertFailure(d2, TimeoutError)
        return gatherResults([d1, d2, d3])


    def test_timeoutCleanDeferreds(self):
        """
        C{timeoutConnection} cleans the list of commands that it fires with
        C{TimeoutError}: C{connectionLost} doesn't try to fire them again, but
        sets the disconnected state so that future commands fail with a
        C{RuntimeError}.
        """
        d1 = self.proto.get("foo")
        self.clock.advance(self.proto.persistentTimeOut)
        self.assertFailure(d1, TimeoutError)
        d2 = self.proto.get("bar")
        self.assertFailure(d2, RuntimeError)
        return gatherResults([d1, d2])


    def test_connectionLost(self):
        """
        When disconnection occurs while commands are still outstanding, the
        commands fail.
        """
        d1 = self.proto.get("foo")
        d2 = self.proto.get("bar")
        self.transport.loseConnection()
        done = DeferredList([d1, d2], consumeErrors=True)
        def checkFailures(results):
            for success, result in results:
                self.assertFalse(success)
                result.trap(ConnectionDone)
        return done.addCallback(checkFailures)


    def test_tooLongKey(self):
        """
        An error is raised when trying to use a too long key: the called
        command returns a L{Deferred} which fails with a L{ClientError}.
        """
        d1 = self.assertFailure(self.proto.set("a" * 500, "bar"), ClientError)
        d2 = self.assertFailure(self.proto.increment("a" * 500), ClientError)
        d3 = self.assertFailure(self.proto.get("a" * 500), ClientError)
        d4 = self.assertFailure(
            self.proto.append("a" * 500, "bar"), ClientError)
        d5 = self.assertFailure(
            self.proto.prepend("a" * 500, "bar"), ClientError)
        d6 = self.assertFailure(
            self.proto.getMultiple(["foo", "a" * 500]), ClientError)
        return gatherResults([d1, d2, d3, d4, d5, d6])


    def test_invalidCommand(self):
        """
        When an unknown command is sent directly (not through public API), the
        server answers with an B{ERROR} token, and the command fails with
        L{NoSuchCommand}.
        """
        d = self.proto._set("egg", "foo", "bar", 0, 0, "")
        self.assertEquals(self.transport.value(), "egg foo 0 0 3\r\nbar\r\n")
        self.assertFailure(d, NoSuchCommand)
        self.proto.dataReceived("ERROR\r\n")
        return d


    def test_clientError(self):
        """
        Test the L{ClientError} error: when the server sends a B{CLIENT_ERROR}
        token, the originating command fails with L{ClientError}, and the error
        contains the text sent by the server.
        """
        a = "eggspamm"
        d = self.proto.set("foo", a)
        self.assertEquals(self.transport.value(),
                          "set foo 0 0 8\r\neggspamm\r\n")
        self.assertFailure(d, ClientError)
        def check(err):
            self.assertEquals(str(err), "We don't like egg and spam")
        d.addCallback(check)
        self.proto.dataReceived("CLIENT_ERROR We don't like egg and spam\r\n")
        return d


    def test_serverError(self):
        """
        Test the L{ServerError} error: when the server sends a B{SERVER_ERROR}
        token, the originating command fails with L{ServerError}, and the error
        contains the text sent by the server.
        """
        a = "eggspamm"
        d = self.proto.set("foo", a)
        self.assertEquals(self.transport.value(),
                          "set foo 0 0 8\r\neggspamm\r\n")
        self.assertFailure(d, ServerError)
        def check(err):
            self.assertEquals(str(err), "zomg")
        d.addCallback(check)
        self.proto.dataReceived("SERVER_ERROR zomg\r\n")
        return d


    def test_unicodeKey(self):
        """
        Using a non-string key as argument to commands raises an error.
        """
        d1 = self.assertFailure(self.proto.set(u"foo", "bar"), ClientError)
        d2 = self.assertFailure(self.proto.increment(u"egg"), ClientError)
        d3 = self.assertFailure(self.proto.get(1), ClientError)
        d4 = self.assertFailure(self.proto.delete(u"bar"), ClientError)
        d5 = self.assertFailure(self.proto.append(u"foo", "bar"), ClientError)
        d6 = self.assertFailure(self.proto.prepend(u"foo", "bar"), ClientError)
        d7 = self.assertFailure(
            self.proto.getMultiple(["egg", 1]), ClientError)
        return gatherResults([d1, d2, d3, d4, d5, d6, d7])


    def test_unicodeValue(self):
        """
        Using a non-string value raises an error.
        """
        return self.assertFailure(self.proto.set("foo", u"bar"), ClientError)


    def test_pipelining(self):
        """
        Multiple requests can be sent subsequently to the server, and the
        protocol orders the responses correctly and dispatch to the
        corresponding client command.
        """
        d1 = self.proto.get("foo")
        d1.addCallback(self.assertEquals, (0, "bar"))
        d2 = self.proto.set("bar", "spamspamspam")
        d2.addCallback(self.assertEquals, True)
        d3 = self.proto.get("egg")
        d3.addCallback(self.assertEquals, (0, "spam"))
        self.assertEquals(self.transport.value(),
            "get foo\r\nset bar 0 0 12\r\nspamspamspam\r\nget egg\r\n")
        self.proto.dataReceived("VALUE foo 0 3\r\nbar\r\nEND\r\n"
                                "STORED\r\n"
                                "VALUE egg 0 4\r\nspam\r\nEND\r\n")
        return gatherResults([d1, d2, d3])


    def test_getInChunks(self):
        """
        If the value retrieved by a C{get} arrive in chunks, the protocol
        is able to reconstruct it and to produce the good value.
        """
        d = self.proto.get("foo")
        d.addCallback(self.assertEquals, (0, "0123456789"))
        self.assertEquals(self.transport.value(), "get foo\r\n")
        self.proto.dataReceived("VALUE foo 0 10\r\n0123456")
        self.proto.dataReceived("789")
        self.proto.dataReceived("\r\nEND")
        self.proto.dataReceived("\r\n")
        return d


    def test_append(self):
        """
        L{MemCacheProtocol.append} behaves like a L{MemCacheProtocol.set}
        method: it returns a L{Deferred} which is called back with C{True} when
        the operation succeeds.
        """
        return self._test(self.proto.append("foo", "bar"),
            "append foo 0 0 3\r\nbar\r\n", "STORED\r\n", True)


    def test_prepend(self):
        """
        L{MemCacheProtocol.prepend} behaves like a L{MemCacheProtocol.set}
        method: it returns a L{Deferred} which is called back with C{True} when
        the operation succeeds.
        """
        return self._test(self.proto.prepend("foo", "bar"),
            "prepend foo 0 0 3\r\nbar\r\n", "STORED\r\n", True)


    def test_gets(self):
        """
        L{MemCacheProtocol.get} handles an additional cas result when
        C{withIdentifier} is C{True} and forward it in the resulting
        L{Deferred}.
        """
        return self._test(self.proto.get("foo", True), "gets foo\r\n",
            "VALUE foo 0 3 1234\r\nbar\r\nEND\r\n", (0, "1234", "bar"))


    def test_emptyGets(self):
        """
        Test getting a non-available key with gets: it succeeds but return
        C{None} as value, C{0} as flag and an empty cas value.
        """
        return self._test(self.proto.get("foo", True), "gets foo\r\n",
            "END\r\n", (0, "", None))


    def test_getsMultiple(self):
        """
        L{MemCacheProtocol.getMultiple} handles an additional cas field in the
        returned tuples if C{withIdentifier} is C{True}.
        """
        return self._test(self.proto.getMultiple(["foo", "bar"], True),
            "gets foo bar\r\n",
            "VALUE foo 0 3 1234\r\negg\r\nVALUE bar 0 4 2345\r\nspam\r\nEND\r\n",
            {'bar': (0, '2345', 'spam'), 'foo': (0, '1234', 'egg')})


    def test_getsMultipleWithEmpty(self):
        """
        When getting a non-available key with L{MemCacheProtocol.getMultiple}
        when C{withIdentifier} is C{True}, the other keys are retrieved
        correctly, and the non-available key gets a tuple of C{0} as flag,
        C{None} as value, and an empty cas value.
        """
        return self._test(self.proto.getMultiple(["foo", "bar"], True),
            "gets foo bar\r\n",
            "VALUE foo 0 3 1234\r\negg\r\nEND\r\n",
            {'bar': (0, '', None), 'foo': (0, '1234', 'egg')})


    def test_checkAndSet(self):
        """
        L{MemCacheProtocol.checkAndSet} passes an additional cas identifier
        that the server handles to check if the data has to be updated.
        """
        return self._test(self.proto.checkAndSet("foo", "bar", cas="1234"),
            "cas foo 0 0 3 1234\r\nbar\r\n", "STORED\r\n", True)


    def test_casUnknowKey(self):
        """
        When L{MemCacheProtocol.checkAndSet} response is C{EXISTS}, the
        resulting L{Deferred} fires with C{False}.
        """
        return self._test(self.proto.checkAndSet("foo", "bar", cas="1234"),
            "cas foo 0 0 3 1234\r\nbar\r\n", "EXISTS\r\n", False)
예제 #22
0
 def loseConnection(self):
     """
     Save the connection lost state, and forward the call.
     """
     StringTransportWithDisconnection.loseConnection(self)
     self.closed = True