diff --git a/tests/test_basics.py b/tests/test_basics.py new file mode 100644 index 0000000..f30132e --- /dev/null +++ b/tests/test_basics.py @@ -0,0 +1,114 @@ +# coding: utf-8 +# Copyright 2015 Jeethu Rao +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import txredisapi as redis +from twisted.internet import defer +from twisted.trial import unittest + +from .mixins import REDIS_HOST, REDIS_PORT + + +class TestBasics(unittest.TestCase): + _KEYS = ['_test_key1', '_test_key2', '_test_key3'] + skipTeardown = False + + @defer.inlineCallbacks + def setUp(self): + self.skipTeardown = False + self.db = yield redis.Connection(REDIS_HOST, REDIS_PORT, + reconnect=False) + + @defer.inlineCallbacks + def tearDown(self): + if not self.skipTeardown: + yield self.db.delete(*self._KEYS) + yield self.db.disconnect() + + def test_quit(self): + self.skipTeardown = True + return self.db.quit() + + def test_auth(self): + self.assertFailure(self.db.auth('test'), + redis.ResponseError) + + @defer.inlineCallbacks + def test_ping(self): + r = yield self.db.ping() + self.assertEqual(r, u'PONG') + + @defer.inlineCallbacks + def test_exists(self): + yield self.db.delete(self._KEYS[0]) + r = yield self.db.exists(self._KEYS[0]) + self.assertFalse(r) + yield self.db.set(self._KEYS[0], 1) + r = yield self.db.exists(self._KEYS[0]) + self.assertTrue(r) + + @defer.inlineCallbacks + def test_type(self): + yield self.db.set(self._KEYS[0], "value") + yield self.db.lpush(self._KEYS[1], 1) + yield self.db.sadd(self._KEYS[2], 1) + r = yield self.db.type(self._KEYS[0]) + self.assertEqual(r, "string") + r = yield self.db.type(self._KEYS[1]) + self.assertEqual(r, "list") + r = yield self.db.type(self._KEYS[2]) + self.assertEqual(r, "set") + + @defer.inlineCallbacks + def test_keys(self): + yield self.db.set(self._KEYS[0], "value") + yield self.db.set(self._KEYS[1], "value") + r = yield self.db.keys('_test_key*') + self.assertIn(self._KEYS[0], r) + self.assertIn(self._KEYS[1], r) + + @defer.inlineCallbacks + def test_randomkey(self): + yield self.db.set(self._KEYS[0], "value") + r = yield self.db.randomkey() + assert r is not None + + @defer.inlineCallbacks + def test_rename(self): + yield self.db.set(self._KEYS[0], "value") + yield self.db.delete(self._KEYS[1]) + r = yield self.db.rename(self._KEYS[0], self._KEYS[1]) + self.assertTrue(r) + r = yield self.db.get(self._KEYS[1]) + self.assertEqual(r, "value") + r = yield self.db.exists(self._KEYS[0]) + self.assertFalse(r) + + @defer.inlineCallbacks + def test_renamenx(self): + yield self.db.set(self._KEYS[0], "value") + yield self.db.set(self._KEYS[1], "value1") + r = yield self.db.renamenx(self._KEYS[0], self._KEYS[1]) + self.assertFalse(r) + r = yield self.db.renamenx(self._KEYS[1], self._KEYS[2]) + self.assertTrue(r) + r = yield self.db.get(self._KEYS[2]) + self.assertEqual(r, "value1") + + @defer.inlineCallbacks + def test_dbsize(self): + yield self.db.set(self._KEYS[0], "value") + yield self.db.set(self._KEYS[1], "value1") + r = yield self.db.dbsize() + assert r >= 2 diff --git a/tests/test_bitops.py b/tests/test_bitops.py index 7cbbf5c..91885a3 100644 --- a/tests/test_bitops.py +++ b/tests/test_bitops.py @@ -74,6 +74,11 @@ def test_bitcount(self): self.assertEqual(r, 4) r = yield self.db.bitcount(key, 1, 1) self.assertEqual(r, 6) + # Ensure that the error is raised + d = defer.maybeDeferred(self.db.bitcount, key, start=1) + self.assertFailure(d, redis.RedisError) + d1 = defer.maybeDeferred(self.db.bitcount, key, end=1) + self.assertFailure(d1, redis.RedisError) def test_bitop_not(self): return self._test_bitop([operator.__not__, operator.not_, @@ -103,6 +108,10 @@ def test_bitop_xor(self): '\x6c\x6c\x6c\x6c', '\xf0\xf0\xf0\xf0') + def test_bitop_invalid(self): + self.assertFailure(self.db.bitop('test', 'test', 'test'), + redis.InvalidData) + @defer.inlineCallbacks def _test_bitop(self, op_list, value1, value2, expected): self._skipCheck() diff --git a/tests/test_protocol.py b/tests/test_protocol.py new file mode 100644 index 0000000..b817315 --- /dev/null +++ b/tests/test_protocol.py @@ -0,0 +1,83 @@ +# coding: utf-8 +# Copyright 2015 Jeethu Rao +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import txredisapi as redis +from twisted.trial import unittest +from twisted.internet.protocol import ClientFactory +from twisted.test.proto_helpers import StringTransportWithDisconnection +from twisted.internet import task + + +class MockFactory(ClientFactory): + pass + + +class LineReceiverSubclass(redis.LineReceiver): + def lineReceived(self, line): + self._rcvd_line = line + + def rawDataReceived(self, data): + self._rcvd_data = data + + +class TestLineReciever(unittest.TestCase): + S = 'TEST' + + def setUp(self): + self.proto = LineReceiverSubclass() + self.transport = StringTransportWithDisconnection() + self.proto.makeConnection(self.transport) + self.transport.protocol = self.proto + self.proto.factory = MockFactory() + + def test_excess_line_length(self): + self.assertTrue(self.transport.connected) + self.proto.dataReceived('\x00' * (self.proto.MAX_LENGTH + 1)) + self.assertFalse(self.transport.connected) + + def test_excess_delimited_line(self): + self.assertTrue(self.transport.connected) + self.proto.dataReceived(self.S + self.proto.delimiter) + self.assertEqual(self.proto._rcvd_line, self.S) + s = ('\x00' * (self.proto.MAX_LENGTH + 1)) + self.proto.delimiter + self.proto._rcvd_line = None + self.proto.dataReceived(s) + self.assertFalse(self.transport.connected) + self.assertIs(self.proto._rcvd_line, None) + + def test_clear_line_buffer(self): + self.proto.dataReceived(self.S) + self.assertEqual(self.proto.clearLineBuffer(), self.S) + + def test_send_line(self): + self.proto.dataReceived(self.S + self.proto.delimiter) + self.assertEqual(self.proto._rcvd_line, self.S) + + def test_raw_data(self): + clock = task.Clock() + self.proto.callLater = clock.callLater + self.proto.setRawMode() + s = self.S + self.proto.delimiter + self.proto.dataReceived(s) + self.assertEqual(self.proto._rcvd_data, s) + self.proto._rcvd_line = None + self.proto.setLineMode(s) + clock.advance(1) + self.assertEqual(self.proto._rcvd_line, self.S) + self.proto.dataReceived(s) + self.assertEqual(self.proto._rcvd_line, self.S) + + def test_sendline(self): + self.proto.sendLine(self.S) + self.assertEqual(self.transport.value(), self.S + self.proto.delimiter) diff --git a/tests/test_sets.py b/tests/test_sets.py index 9b391f9..c38ce8b 100644 --- a/tests/test_sets.py +++ b/tests/test_sets.py @@ -160,3 +160,22 @@ def test_smove(self): self.assertEqual(r, False) r = yield self.db.smembers(self._KEYS[1]) self.assertEqual(r, set([1])) + + @defer.inlineCallbacks + def test_srandmember(self): + l = range(10) + yield self.db.sadd(self._KEYS[0], l) + for i in l: + r = yield self.db.srandmember(self._KEYS[0]) + self.assertIn(r, l) + + @defer.inlineCallbacks + def test_spop(self): + l = range(10) + yield self.db.sadd(self._KEYS[0], l) + popped = set() + for i in l: + r = yield self.db.spop(self._KEYS[0]) + self.assertNotIn(r, popped) + popped.add(r) + self.assertEqual(set(l), popped) diff --git a/txredisapi.py b/txredisapi.py index ac65628..ec8da47 100644 --- a/txredisapi.py +++ b/txredisapi.py @@ -129,6 +129,7 @@ def append(self, item): class LineReceiver(protocol.Protocol, basic._PauseableMixin): + callLater = reactor.callLater line_mode = 1 __buffer = '' delimiter = '\r\n' @@ -178,7 +179,7 @@ def setLineMode(self, extra=''): self.line_mode = 1 if extra: self.pauseProducing() - reactor.callLater(0, self.dataReceived, extra, True) + self.callLater(0, self.dataReceived, extra, True) def setRawMode(self): self.line_mode = 0