Example #1
0
 def annotate_exception(self, exception, number, command):
     """
     """
     cmd = unicode(' ').join(imap(unicode, command))
     msg = unicode('Command # {0} ({1}) of pipeline caused error: {2}').format(
         number, cmd, unicode(exception.args[0]))
     exception.args = (msg,) + exception.args[1:]
Example #2
0
def test_init_slots_cache_slots_collision():
    """
    Test that if 2 nodes do not agree on the same slots setup it should raise an error.
    In this test both nodes will say that the first slots block should be bound to different
     servers.
    """

    n = NodeManager(startup_nodes=[
        {
            "host": "127.0.0.1",
            "port": 7000
        },
        {
            "host": "127.0.0.1",
            "port": 7001
        },
    ])

    def monkey_link(host=None, port=None, *args, **kwargs):
        """
        Helper function to return custom slots cache data from different redis nodes
        """
        if port == 7000:
            result = [[0, 5460, [b'127.0.0.1', 7000], [b'127.0.0.1', 7003]],
                      [
                          5461, 10922, [b'127.0.0.1', 7001],
                          [b'127.0.0.1', 7004]
                      ]]

        elif port == 7001:
            result = [[0, 5460, [b'127.0.0.1', 7001], [b'127.0.0.1', 7003]],
                      [
                          5461, 10922, [b'127.0.0.1', 7000],
                          [b'127.0.0.1', 7004]
                      ]]

        else:
            result = []

        r = RedisCluster(host=host, port=port, decode_responses=True)
        orig_execute_command = r.execute_command

        def execute_command(*args, **kwargs):
            if args == ("cluster", "slots"):
                return result
            elif args == ('CONFIG GET', 'cluster-require-full-coverage'):
                return {'cluster-require-full-coverage': 'yes'}
            else:
                return orig_execute_command(*args, **kwargs)

        r.execute_command = execute_command
        return r

    n.get_redis_link = monkey_link
    with pytest.raises(RedisClusterException) as ex:
        n.initialize()
    assert unicode(ex.value).startswith(
        "startup_nodes could not agree on a valid slots cache."), unicode(
            ex.value)
Example #3
0
def test_empty_startup_nodes():
    """
    Test that exception is raised when empty providing empty startup_nodes
    """
    with pytest.raises(RedisClusterException) as ex:
        r = RedisCluster(startup_nodes=[])

    assert unicode(ex.value).startswith("No startup nodes provided"), unicode(ex.value)
Example #4
0
 def annotate_exception(self, exception, number, command):
     """
     """
     cmd = unicode(' ').join(imap(unicode, command))
     msg = unicode(
         'Command # {0} ({1}) of pipeline caused error: {2}').format(
             number, cmd, unicode(exception.args[0]))
     exception.args = (msg, ) + exception.args[1:]
Example #5
0
def test_empty_startup_nodes():
    """
    Test that exception is raised when empty providing empty startup_nodes
    """
    with pytest.raises(RedisClusterException) as ex:
        _get_client(init_slot_cache=False, startup_nodes=[])

    assert unicode(ex.value).startswith("No startup nodes provided"), unicode(ex.value)
def test_empty_startup_nodes(s):
    """
    Test that exception is raised when empty providing empty startup_nodes
    """
    with pytest.raises(RedisClusterException) as ex:
        _get_client(init_slot_cache=False, startup_nodes=[])

    assert unicode(ex.value).startswith("No startup nodes provided"), unicode(ex.value)
def test_blocked_transaction(r):
    """
    Method transaction is blocked/NYI and should raise exception on use
    """
    with pytest.raises(RedisClusterException) as ex:
        r.transaction(None)
    assert unicode(ex.value).startswith(
        "method RedisCluster.transaction() is not implemented"), unicode(
            ex.value)
Example #8
0
def test_keyslot():
    """
    Test that method will compute correct key in all supported cases
    """
    n = NodeManager([{}])

    assert n.keyslot("foo") == 12182
    assert n.keyslot("{foo}bar") == 12182
    assert n.keyslot("{foo}") == 12182
    assert n.keyslot(1337) == 4314
    assert n.keyslot(b"abc") == n.keyslot("abc")
    assert n.keyslot("abc") == n.keyslot(unicode("abc"))
    assert n.keyslot(unicode("abc")) == n.keyslot(b"abc")
def test_keyslot():
    """
    Test that method will compute correct key in all supported cases
    """
    n = NodeManager([{}])

    assert n.keyslot("foo") == 12182
    assert n.keyslot("{foo}bar") == 12182
    assert n.keyslot("{foo}") == 12182
    assert n.keyslot(1337) == 4314
    assert n.keyslot(b"abc") == n.keyslot("abc")
    assert n.keyslot("abc") == n.keyslot(unicode("abc"))
    assert n.keyslot(unicode("abc")) == n.keyslot(b"abc")
Example #10
0
    def test_blocked_arguments(self, r):
        """
        Currently some arguments is blocked when using in cluster mode.
        They maybe implemented in the future.
        """
        with pytest.raises(RedisClusterException) as ex:
            r.pipeline(transaction=True)

        assert unicode(ex.value).startswith("transaction is deprecated in cluster mode"), True

        with pytest.raises(RedisClusterException) as ex:
            r.pipeline(shard_hint=True)

        assert unicode(ex.value).startswith("shard_hint is deprecated in cluster mode"), True
Example #11
0
def test_execute_command_errors(r):
    """
    If no command is given to `_determine_nodes` then exception
    should be raised.

    Test that if no key is provided then exception should be raised.
    """
    with pytest.raises(RedisClusterException) as ex:
        r.execute_command()
    assert unicode(ex.value).startswith("Unable to determine command to use")

    with pytest.raises(RedisClusterException) as ex:
        r.execute_command("GET")
    assert unicode(ex.value).startswith("No way to dispatch this command to Redis Cluster. Missing key.")
Example #12
0
    def test_exec_error_in_no_transaction_pipeline_unicode_command(self, r):
        key = unichr(3456) + u('abcd') + unichr(3421)
        r[key] = 1
        with r.pipeline(transaction=False) as pipe:
            pipe.llen(key)
            pipe.expire(key, 100)

            with pytest.raises(ResponseError) as ex:
                pipe.execute()

            expected = unicode('Command # 1 (LLEN {0}) of pipeline caused error: ').format(key)
            assert unicode(ex.value).startswith(expected)

        assert r[key] == b('1')
Example #13
0
    def test_rename(self, r):
        r['a'] = '1'
        assert r.rename('a', 'b')
        assert r.get('a') is None
        assert r['b'] == b('1')

        with pytest.raises(ResponseError) as ex:
            r.rename("foo", "foo")
        assert unicode(ex.value).startswith("source and destination objects are the same")

        assert r.get("foo") is None
        with pytest.raises(ResponseError) as ex:
            r.rename("foo", "bar")
        assert unicode(ex.value).startswith("no such key")
def test_execute_command_errors(r):
    """
    If no command is given to `_determine_nodes` then exception
    should be raised.

    Test that if no key is provided then exception should be raised.
    """
    with pytest.raises(RedisClusterException) as ex:
        r.execute_command()
    assert unicode(ex.value).startswith("Unable to determine command to use")

    with pytest.raises(RedisClusterException) as ex:
        r.execute_command("GET")
    assert unicode(ex.value).startswith("No way to dispatch this command to Redis Cluster. Missing key.")
Example #15
0
    def test_blocked_arguments(self, r):
        """
        Currently some arguments is blocked when using in cluster mode.
        They maybe implemented in the future.
        """
        with pytest.raises(RedisClusterException) as ex:
            r.pipeline(transaction=True)

        assert unicode(ex.value).startswith("transaction is deprecated in cluster mode"), True

        with pytest.raises(RedisClusterException) as ex:
            r.pipeline(shard_hint=True)

        assert unicode(ex.value).startswith("shard_hint is deprecated in cluster mode"), True
Example #16
0
    def test_exec_error_in_no_transaction_pipeline_unicode_command(self, r):
        key = unichr(3456) + u('abcd') + unichr(3421)
        r[key] = 1
        with r.pipeline(transaction=False) as pipe:
            pipe.llen(key)
            pipe.expire(key, 100)

            with pytest.raises(ResponseError) as ex:
                pipe.execute()

            expected = unicode('Command # 1 (LLEN {0}) of pipeline caused error: ').format(key)
            assert unicode(ex.value).startswith(expected)

        assert r[key] == b('1')
    def test_rename(self, r):
        r['a'] = '1'
        assert r.rename('a', 'b')
        assert r.get('a') is None
        assert r['b'] == b('1')

        with pytest.raises(ResponseError) as ex:
            r.rename("foo", "foo")
        assert unicode(ex.value).startswith("source and destination objects are the same")

        assert r.get("foo") is None
        with pytest.raises(ResponseError) as ex:
            r.rename("foo", "bar")
        assert unicode(ex.value).startswith("no such key")
    def test_exec_error_in_no_transaction_pipeline_unicode_command(self):
        key = unichr(3456) + u('abcd') + unichr(3421)
        self.rc[key] = 1
        with self.rc.pipeline(transaction=False) as pipe:
            pipe.llen(key)
            pipe.expire(key, 100)

            with pytest.raises(redis.ResponseError) as ex:
                pipe.execute()
            print ex.value
            expected = unicode('Command # 1 (LLEN %s) of pipeline caused '
                               'error: ') % key
            assert unicode(ex.value).startswith(expected)

        assert self.rc[key] == b('1')
def test_password_procted_nodes():
    """
    Test that it is possible to connect to password protected nodes
    """
    startup_nodes = [{"host": "127.0.0.1", "port": "7000"}]
    password_protected_startup_nodes = [{"host": "127.0.0.1", "port": "7100"}]
    with pytest.raises(RedisClusterException) as ex:
        _get_client(startup_nodes=password_protected_startup_nodes)
    assert unicode(ex.value).startswith("ERROR sending 'cluster slots' command to redis server:")
    _get_client(startup_nodes=password_protected_startup_nodes, password="******")

    with pytest.raises(RedisClusterException) as ex:
        _get_client(startup_nodes=startup_nodes, password="******")
    assert unicode(ex.value).startswith("ERROR sending 'cluster slots' command to redis server:")
    _get_client(startup_nodes=startup_nodes)
Example #20
0
def test_password_procted_nodes():
    """
    Test that it is possible to connect to password protected nodes
    """
    startup_nodes = [{"host": "127.0.0.1", "port": "7000"}]
    password_protected_startup_nodes = [{"host": "127.0.0.1", "port": "7100"}]
    with pytest.raises(RedisClusterException) as ex:
        _get_client(startup_nodes=password_protected_startup_nodes)
    assert unicode(ex.value).startswith("ERROR sending 'cluster slots' command to redis server:")
    _get_client(startup_nodes=password_protected_startup_nodes, password='******')

    with pytest.raises(RedisClusterException) as ex:
        _get_client(startup_nodes=startup_nodes, password='******')
    assert unicode(ex.value).startswith("ERROR sending 'cluster slots' command to redis server:")
    _get_client(startup_nodes=startup_nodes)
    def test_exec_error_in_no_transaction_pipeline_unicode_command(self, nr):
        key = unichr(3456) + u('abcd') + unichr(3421)
        nr[key] = 1
        with nr.pipeline(transaction=False) as pipe:
            pipe.llen(key)
            pipe.expire(key, 100)

            with pytest.raises(redis.ResponseError) as ex:
                pipe.execute()

            expected = unicode('Command # 1 (LLEN %s) of pipeline caused '
                               'error: ') % add_namespace(key)
            assert unicode(ex.value).startswith(expected)

        assert nr[key] == b('1')
    def test_init_slots_cache_not_all_slots(self, s):
        """
        Test that if not all slots are covered it should raise an exception
        """
        # Save the old function so we can wrap it
        old_get_link_from_node = s.get_redis_link_from_node

        # Create wrapper function so we can inject custom 'CLUSTER SLOTS' command result
        def new_get_link_from_node(node):
            link = old_get_link_from_node(node)

            # Missing slot 5460
            bad_slots_resp = [[0, 5459, [b'127.0.0.1', 7000], [b'127.0.0.1', 7003]],
                              [5461, 10922, [b'127.0.0.1', 7001], [b'127.0.0.1', 7004]],
                              [10923, 16383, [b'127.0.0.1', 7002], [b'127.0.0.1', 7005]]]

            # Missing slot 5460
            link.execute_command = lambda *args: bad_slots_resp

            return link

        s.get_redis_link_from_node = new_get_link_from_node

        with pytest.raises(RedisClusterException) as ex:
            s.initialize_slots_cache()

        assert unicode(ex.value).startswith("All slots are not covered after querry all startup_nodes."), True
Example #23
0
 def encode(self, value):
     "Return a bytestring or bytes-like representation of the value"
     if isinstance(value, (bytes, memoryview)):
         return value
     # elif isinstance(value, bool):
     #     # special case bool since it is a subclass of int
     #     raise DataError(
     #         "Invalid input of type: 'bool'. Convert to a "
     #         "bytes, string, int or float first."
     #     )
     elif isinstance(value, float):
         value = repr(value).encode()
     elif isinstance(value, (int, long)):
         # python 2 repr() on longs is '123L', so use str() instead
         value = str(value).encode()
     elif isinstance(value, (list, dict, tuple)):
         value = unicode(value)
     elif not isinstance(value, basestring):
         # a value we don't know how to deal with. throw an error
         typename = type(value).__name__
         raise DataError("Invalid input of type: '%s'. Convert to a "
                         "bytes, string, int or float first." % typename)
     if isinstance(value, unicode):
         value = value.encode(self.encoding, self.encoding_errors)
     return value
Example #24
0
def test_first_key():
    assert first_key("foobar", {"foo": 1}) == 1

    with pytest.raises(RedisClusterException) as ex:
        first_key("foobar", {"foo": 1, "bar": 2})
    assert unicode(
        ex.value).startswith("More then 1 result from command: foobar")
Example #25
0
def test_init_slots_cache_not_all_slots(s):
    """
    Test that if not all slots are covered it should raise an exception
    """

    # Create wrapper function so we can inject custom 'CLUSTER SLOTS' command result
    def get_redis_link_wrapper(host, port, decode_responses=False):
        link = StrictRedis(host="127.0.0.1", port=7000, decode_responses=True)

        # Missing slot 5460
        bad_slots_resp = [
            [0, 5459, [b'127.0.0.1', 7000], [b'127.0.0.1', 7003]],
            [5461, 10922, [b'127.0.0.1', 7001], [b'127.0.0.1', 7004]],
            [10923, 16383, [b'127.0.0.1', 7002], [b'127.0.0.1', 7005]],
        ]

        # Missing slot 5460
        link.execute_command = lambda *args: bad_slots_resp

        return link

    s.connection_pool.nodes.get_redis_link = get_redis_link_wrapper

    with pytest.raises(RedisClusterException) as ex:
        s.connection_pool.nodes.initialize()

    assert unicode(ex.value).startswith(
        "All slots are not covered after query all startup_nodes.")
Example #26
0
def test_init_with_down_node():
    """
    If I can't connect to one of the nodes, everything should still work.
    But if I can't connect to any of the nodes, exception should be thrown.
    """
    def get_redis_link(host, port, decode_responses=False):
        if port == 7000:
            raise ConnectionError('mock connection error for 7000')
        return StrictRedis(host=host,
                           port=port,
                           decode_responses=decode_responses)

    with patch.object(NodeManager,
                      'get_redis_link',
                      side_effect=get_redis_link):
        n = NodeManager(startup_nodes=[{
            "host": "127.0.0.1",
            "port": 7000
        }, {
            "host": "127.0.0.1",
            "port": 7001
        }])
        n.initialize()
        assert len(n.slots) == NodeManager.RedisClusterHashSlots
        assert len(n.nodes) == 6

        n = NodeManager(startup_nodes=[{"host": "127.0.0.1", "port": 7000}])
        with pytest.raises(RedisClusterException) as e:
            n.initialize()
        assert 'Redis Cluster cannot be connected' in unicode(e.value)
def test_init_slots_cache_not_all_slots(s):
    """
    Test that if not all slots are covered it should raise an exception
    """
    # Create wrapper function so we can inject custom 'CLUSTER SLOTS' command result
    def get_redis_link_wrapper(host, port, decode_responses=False):
        link = StrictRedis(host="127.0.0.1", port=7000, decode_responses=True)

        # Missing slot 5460
        bad_slots_resp = [
            [0, 5459, [b'127.0.0.1', 7000], [b'127.0.0.1', 7003]],
            [5461, 10922, [b'127.0.0.1', 7001], [b'127.0.0.1', 7004]],
            [10923, 16383, [b'127.0.0.1', 7002], [b'127.0.0.1', 7005]],
        ]

        # Missing slot 5460
        link.execute_command = lambda *args: bad_slots_resp

        return link

    s.connection_pool.nodes.get_redis_link = get_redis_link_wrapper

    with pytest.raises(RedisClusterException) as ex:
        s.connection_pool.nodes.initialize()

    assert unicode(ex.value).startswith("All slots are not covered after query all startup_nodes.")
    def test_init_slots_cache_not_all_slots(self, s):
        """
        Test that if not all slots are covered it should raise an exception
        """
        # Save the old function so we can wrap it
        old_get_link_from_node = s.get_redis_link_from_node

        # Create wrapper function so we can inject custom 'CLUSTER SLOTS' command result
        def new_get_link_from_node(node):
            link = old_get_link_from_node(node)

            # Missing slot 5460
            bad_slots_resp = [
                [0, 5459, [b'127.0.0.1', 7000], [b'127.0.0.1', 7003]],
                [5461, 10922, [b'127.0.0.1', 7001], [b'127.0.0.1', 7004]],
                [10923, 16383, [b'127.0.0.1', 7002], [b'127.0.0.1', 7005]]
            ]

            # Missing slot 5460
            link.execute_command = lambda *args: bad_slots_resp

            return link

        s.get_redis_link_from_node = new_get_link_from_node

        with pytest.raises(RedisClusterException) as ex:
            s.initialize_slots_cache()

        assert unicode(ex.value).startswith(
            "All slots are not covered after querry all startup_nodes."), True
    def test_get_connection_by_slot(self):
        """
        """
        pool = self.get_pool(connection_kwargs={})

        # Patch the call that is made inside the method to allow control of the returned connection object
        with patch.object(ClusterReadOnlyConnectionPool, 'get_master_connection_by_slot', autospec=True) as pool_mock:
            def side_effect(self, *args, **kwargs):
                return DummyConnection(port=1337)
            pool_mock.side_effect = side_effect

            # Try a master only command
            connection = pool.get_connection_by_key("foo", 'ZSCAN')
            assert connection.port == 1337

        with patch.object(ClusterReadOnlyConnectionPool, 'get_random_master_slave_connection_by_slot', autospec=True) as pool_mock:
            def side_effect(self, *args, **kwargs):
                return DummyConnection(port=1337)
            pool_mock.side_effect = side_effect

            # try a random node command
            connection = pool.get_connection_by_key('foo', 'GET')
            assert connection.port == 1337

        with pytest.raises(RedisClusterException) as ex:
            pool.get_connection_by_key(None, None)
        assert unicode(ex.value).startswith("No way to dispatch this command to Redis Cluster."), True
def test_blocked_transaction(r):
    """
    Method transaction is blocked/NYI and should raise exception on use
    """
    with pytest.raises(RedisClusterException) as ex:
        r.transaction(None)
    assert unicode(ex.value).startswith("method StrictRedisCluster.transaction() is not implemented"), unicode(ex.value)
Example #31
0
def test_init_slots_cache_not_all_slots(s):
    """
    Test that if not all slots are covered it should raise an exception
    """

    # Create wrapper function so we can inject custom 'CLUSTER SLOTS' command result
    def get_redis_link_wrapper(*args, **kwargs):
        link = Redis(host="127.0.0.1", port=7000, decode_responses=True)

        orig_exec_method = link.execute_command

        def patch_execute_command(*args, **kwargs):
            if args == ('cluster', 'slots'):
                # Missing slot 5460
                return [
                    [0, 5459, [b'127.0.0.1', 7000], [b'127.0.0.1', 7003]],
                    [5461, 10922, [b'127.0.0.1', 7001], [b'127.0.0.1', 7004]],
                    [10923, 16383, [b'127.0.0.1', 7002], [b'127.0.0.1', 7005]],
                ]

            return orig_exec_method(*args, **kwargs)

        # Missing slot 5460
        link.execute_command = patch_execute_command

        return link

    s.connection_pool.nodes.get_redis_link = get_redis_link_wrapper

    with pytest.raises(RedisClusterException) as ex:
        s.connection_pool.nodes.initialize()

    assert unicode(ex.value).startswith(
        "All slots are not covered after query all startup_nodes.")
def test_clusterdown_wrapper():
    @clusterdown_wrapper
    def bad_func():
        raise ClusterDownError("CLUSTERDOWN")

    with pytest.raises(ClusterDownError) as cex:
        bad_func()
    assert unicode(cex.value).startswith("CLUSTERDOWN error. Unable to rebuild the cluster")
Example #33
0
def test_clusterdown_wrapper():
    @clusterdown_wrapper
    def bad_func():
        raise ClusterDownException()

    with pytest.raises(ClusterDownException) as cex:
        bad_func()
    assert unicode(cex.value).startswith("CLUSTERDOWN error. Unable to rebuild the cluster")
    def test_init_slots_cache_slots_collision(self):
        """
        Test that if 2 nodes do not agree on the same slots setup it should raise an error.
        In this test both nodes will say that the first slots block should be bound to different
         servers.
        """
        s = _get_client(init_slot_cache=False,
                        startup_nodes=[{
                            "host": "127.0.0.1",
                            "port": "7000"
                        }, {
                            "host": "127.0.0.1",
                            "port": "7001"
                        }])

        old_get_link_from_node = s.get_redis_link_from_node

        node_1 = old_get_link_from_node({"host": "127.0.0.1", "port": "7000"})
        node_2 = old_get_link_from_node({"host": "127.0.0.1", "port": "7001"})

        node_1_slots = [[0, 5460, [b'127.0.0.1', 7000], [b'127.0.0.1', 7003]],
                        [
                            5461, 10922, [b'127.0.0.1', 7001],
                            [b'127.0.0.1', 7004]
                        ]]

        node_2_slots = [[0, 5460, [b'127.0.0.1', 7001], [b'127.0.0.1', 7003]],
                        [
                            5461, 10922, [b'127.0.0.1', 7000],
                            [b'127.0.0.1', 7004]
                        ]]

        node_1.execute_command = lambda *args: node_1_slots
        node_2.execute_command = lambda *args: node_2_slots

        def new_get_link_from_node(node):
            # TODO: This seem like a bug that we have to exclude 'name' in first use but not in second use.
            if node == {
                    "host": "127.0.0.1",
                    "port": "7000"
            }:  # , 'name': '127.0.0.1:7000'}:
                return node_1
            elif node == {
                    "host": "127.0.0.1",
                    "port": "7001",
                    'name': '127.0.0.1:7001'
            }:
                return node_2
            else:
                raise Exception("Foo")

        s.get_redis_link_from_node = new_get_link_from_node

        with pytest.raises(RedisClusterException) as ex:
            s.initialize_slots_cache()

        assert unicode(ex.value).startswith(
            "startup_nodes could not agree on a valid slots cache."), True
def test_raise_regular_exception(r):
    """
    If a non redis server exception is passed in it shold be
    raised again.
    """
    e = Exception("foobar")
    with pytest.raises(Exception) as ex:
        r.handle_cluster_command_exception(e)
    assert unicode(ex.value).startswith("foobar")
Example #36
0
def test_first_key():
    assert first_key("foobar", {"foo": 1}) == 1

    with pytest.raises(RedisClusterException) as ex:
        first_key("foobar", {"foo": 1, "bar": 2})
    assert unicode(ex.value).startswith("More then 1 result from command: foobar")

    with pytest.raises(AssertionError):
        first_key("foobar", None)
def test_raise_regular_exception(r):
    """
    If a non redis server exception is passed in it shold be
    raised again.
    """
    e = Exception("foobar")
    with pytest.raises(Exception) as ex:
        r.handle_cluster_command_exception(e)
    assert unicode(ex.value).startswith("foobar")
    def test_blocked_strict_redis_args(self):
        """
        Some arguments should explicitly be blocked because they will not work in a cluster setup
        """
        params = {'startup_nodes': [{'host': '127.0.0.1', 'port': 7000}]}
        c = RedisCluster(**params)
        assert c.opt["socket_timeout"] == RedisCluster.RedisClusterDefaultTimeout

        with pytest.raises(RedisClusterException) as ex:
            _get_client(db=1)
        assert unicode(ex.value).startswith("(error) [Remove 'db' from kwargs]"), True

        with pytest.raises(RedisClusterException) as ex:
            _get_client(host="foo.bar")
        assert unicode(ex.value).startswith("(error) [Remove 'host' from kwargs]"), True

        with pytest.raises(RedisClusterException) as ex:
            _get_client(port=1337)
        assert unicode(ex.value).startswith("(error) [Remove 'port' from kwargs]"), True
    def test_get_connection_blocked(self):
        """
        Currently get_connection() should only be used by pubsub command.
        All other commands should be blocked and exception raised.
        """
        pool = self.get_pool()

        with pytest.raises(RedisClusterException) as ex:
            pool.get_connection("GET")
        assert unicode(ex.value).startswith("Only 'pubsub' commands can be used by get_connection()")
    def test_get_connection_by_key(self, r):
        """
        This test assumes that when hashing key 'foo' will be sent to server with port 7002
        """
        connection = r.get_connection_by_key("foo")
        assert connection.connection_pool.connection_kwargs["port"] == 7002

        with pytest.raises(RedisClusterException) as ex:
            r.get_connection_by_key(None)

        assert unicode(ex.value).startswith("No way to dispatch this command to Redis Cluster."), True
Example #41
0
def test_blocked_strict_redis_args():
    """
    Some arguments should explicitly be blocked because they will not work in a cluster setup
    """
    params = {'startup_nodes': [{'host': '127.0.0.1', 'port': 7000}]}
    c = StrictRedisCluster(**params)
    assert c.connection_pool.connection_kwargs["socket_timeout"] == ClusterConnectionPool.RedisClusterDefaultTimeout

    with pytest.raises(RedisClusterException) as ex:
        _get_client(db=1)
    assert unicode(ex.value).startswith("Argument 'db' is not possible to use in cluster mode")
def test_blocked_strict_redis_args():
    """
    Some arguments should explicitly be blocked because they will not work in a cluster setup
    """
    params = {"startup_nodes": [{"host": "127.0.0.1", "port": 7000}]}
    c = StrictRedisCluster(**params)
    assert c.connection_pool.connection_kwargs["socket_timeout"] == ClusterConnectionPool.RedisClusterDefaultTimeout

    with pytest.raises(RedisClusterException) as ex:
        _get_client(db=1)
    assert unicode(ex.value).startswith("Argument 'db' is not possible to use in cluster mode")
def test_keyslot():
    """
    Test that method will compute correct key in all supported cases
    """
    n = NodeManager([{}])

    assert n.keyslot("foo") == 12182
    assert n.keyslot("{foo}bar") == 12182
    assert n.keyslot("{foo}") == 12182
    assert n.keyslot(1337) == 4314

    assert n.keyslot(125) == n.keyslot(b"125")
    assert n.keyslot(125) == n.keyslot("\x31\x32\x35")
    assert n.keyslot("大奖") == n.keyslot(b"\xe5\xa4\xa7\xe5\xa5\x96")
    assert n.keyslot(u"大奖") == n.keyslot(b"\xe5\xa4\xa7\xe5\xa5\x96")
    assert n.keyslot(1337.1234) == n.keyslot("1337.1234")
    assert n.keyslot(1337) == n.keyslot("1337")
    assert n.keyslot(b"abc") == n.keyslot("abc")
    assert n.keyslot("abc") == n.keyslot(unicode("abc"))
    assert n.keyslot(unicode("abc")) == n.keyslot(b"abc")
Example #44
0
def test_keyslot():
    """
    Test that method will compute correct key in all supported cases
    """
    n = NodeManager([{}])

    assert n.keyslot("foo") == 12182
    assert n.keyslot("{foo}bar") == 12182
    assert n.keyslot("{foo}") == 12182
    assert n.keyslot(1337) == 4314

    assert n.keyslot(125) == n.keyslot(b"125")
    assert n.keyslot(125) == n.keyslot("\x31\x32\x35")
    assert n.keyslot("大奖") == n.keyslot(b"\xe5\xa4\xa7\xe5\xa5\x96")
    assert n.keyslot(u"大奖") == n.keyslot(b"\xe5\xa4\xa7\xe5\xa5\x96")
    assert n.keyslot(1337.1234) == n.keyslot("1337.1234")
    assert n.keyslot(1337) == n.keyslot("1337")
    assert n.keyslot(b"abc") == n.keyslot("abc")
    assert n.keyslot("abc") == n.keyslot(unicode("abc"))
    assert n.keyslot(unicode("abc")) == n.keyslot(b"abc")
    def test_get_connection_by_key(self):
        """
        This test assumes that when hashing key 'foo' will be sent to server with port 7002
        """
        pool = self.get_pool(connection_kwargs={})

        connection = pool.get_connection_by_key("foo")
        assert connection.port == 7002

        with pytest.raises(RedisClusterException) as ex:
            pool.get_connection_by_key(None)
        assert unicode(ex.value).startswith("No way to dispatch this command to Redis Cluster."), True
Example #46
0
    def test_exec_error_raised(self, r, ns):
        r['c'] = 'a'
        with r.pipeline() as pipe:
            pipe.set('a', 1).set('b', 2).lpush('c', 3).set('d', 4)
            with pytest.raises(redis.ResponseError) as ex:
                pipe.execute()
            assert unicode(ex.value).startswith('Command # 3 (LPUSH %sc 3) of '
                                                'pipeline caused error: ' % ns)

            # make sure the pipe was restored to a working state
            assert pipe.set('z', 'zzz').execute() == [True]
            assert r['z'] == b'zzz'
Example #47
0
    def test_exec_error_raised(self, r):
        r['c'] = 'a'
        with r.pipeline() as pipe:
            pipe.set('a', 1).set('b', 2).lpush('c', 3).set('d', 4)
            with pytest.raises(redis.ResponseError) as ex:
                pipe.execute()
            assert unicode(ex.value).startswith('Command # 3 (LPUSH c 3) of '
                                                'pipeline caused error: ')

            # make sure the pipe was restored to a working state
            assert pipe.set('z', 'zzz').execute() == [True]
            assert r['z'] == b('zzz')
    def keyslot(self, key):
        """
        Calculate keyslot for a given key.

        This also works for binary keys that is used in python 3.
        """
        k = unicode(key)
        start = k.find("{")
        if start > -1:
            end = k.find("}", start + 1)
            if end > -1 and end != start + 1:
                k = k[start + 1:end]
        return crc16(k) % self.RedisClusterHashSlots
    def keyslot(self, key):
        """
        Calculate keyslot for a given key.

        This also works for binary keys that is used in python 3.
        """
        k = unicode(key)
        start = k.find("{")
        if start > -1:
            end = k.find("}", start + 1)
            if end > -1 and end != start + 1:
                k = k[start + 1:end]
        return crc16(k) % self.RedisClusterHashSlots
Example #50
0
    def test_exec_error_in_no_transaction_pipeline(self, r, ns):
        r['a'] = 1
        with r.pipeline(transaction=False) as pipe:
            pipe.llen('a')
            pipe.expire('a', 100)

            with pytest.raises(redis.ResponseError) as ex:
                pipe.execute()

            assert unicode(ex.value).startswith('Command # 1 (LLEN %sa) of '
                                                'pipeline caused error: ' % ns)

        assert r['a'] == b'1'
Example #51
0
    def test_parse_error_raised(self, r, ns):
        with r.pipeline() as pipe:
            # the zrem is invalid because we don't pass any keys to it
            pipe.set('a', 1).zrem('b').set('b', 2)
            with pytest.raises(redis.ResponseError) as ex:
                pipe.execute()

            assert unicode(ex.value).startswith('Command # 2 (ZREM %sb) of '
                                                'pipeline caused error: ' % ns)

            # make sure the pipe was restored to a working state
            assert pipe.set('z', 'zzz').execute() == [True]
            assert r['z'] == b'zzz'
Example #52
0
    def test_parse_error_raised(self, r):
        with r.pipeline() as pipe:
            # the zrem is invalid because we don't pass any keys to it
            pipe.set('a', 1).zrem('b').set('b', 2)
            with pytest.raises(redis.ResponseError) as ex:
                pipe.execute()

            assert unicode(ex.value).startswith('Command # 2 (ZREM b) of '
                                                'pipeline caused error: ')

            # make sure the pipe was restored to a working state
            assert pipe.set('z', 'zzz').execute() == [True]
            assert r['z'] == b('zzz')
Example #53
0
    def test_exec_error_in_no_transaction_pipeline(self, r):
        r['a'] = 1
        with r.pipeline(transaction=False) as pipe:
            pipe.llen('a')
            pipe.expire('a', 100)

            with pytest.raises(redis.ResponseError) as ex:
                pipe.execute()

            assert unicode(ex.value).startswith('Command # 1 (LLEN a) of '
                                                'pipeline caused error: ')

        assert r['a'] == b('1')
def test_init_with_down_node():
    """
    If I can't connect to one of the nodes, everything should still work.
    But if I can't connect to any of the nodes, exception should be thrown.
    """
    def get_redis_link(host, port, decode_responses=False):
        if port == 7000:
            raise ConnectionError('mock connection error for 7000')
        return StrictRedis(host=host, port=port, decode_responses=decode_responses)

    with patch.object(NodeManager, 'get_redis_link', side_effect=get_redis_link):
        n = NodeManager(startup_nodes=[{"host": "127.0.0.1", "port": 7000}])
        with pytest.raises(RedisClusterException) as e:
            n.initialize()
        assert 'Redis Cluster cannot be connected' in unicode(e.value)
Example #55
0
 def encode(self, value):
     "Return a bytestring representation of the value"
     if isinstance(value, Token):
         return b(value.value)
     elif isinstance(value, bytes):
         return value
     elif isinstance(value, (int, long)):
         value = b(str(value))
     elif isinstance(value, float):
         value = b(repr(value))
     elif not isinstance(value, basestring):
         value = unicode(value)
     if isinstance(value, unicode):
         value = value.encode(self.encoding, self.encoding_errors)
     return value
Example #56
0
    def keyslot_py_2(self, key):
        """
        Calculate keyslot for a given key.
        Tuned for compatibility with python 2.7.x
        """
        k = unicode(key)

        start = k.find("{")

        if start > -1:
            end = k.find("}", start + 1)
            if end > -1 and end != start + 1:
                k = k[start + 1:end]

        return crc16(k) % self.RedisClusterHashSlots
Example #57
0
 def encode(self, value):
     "Return a bytestring representation of the value"
     if isinstance(value, Token):
         return value.encoded_value
     elif isinstance(value, bytes):
         return value
     elif isinstance(value, (int, long)):
         value = b(str(value))
     elif isinstance(value, float):
         value = b(repr(value))
     elif not isinstance(value, basestring):
         # an object we don't know how to deal with. default to unicode()
         value = unicode(value)
     if isinstance(value, unicode):
         value = value.encode(self.encoding, self.encoding_errors)
     return value
Example #58
0
 def encode(self, value):
     """
     Return a bytestring representation of the value.
     This method is copied from Redis' connection.py:Connection.encode
     """
     if isinstance(value, bytes):
         return value
     elif isinstance(value, (int, long)):
         value = b(str(value))
     elif isinstance(value, float):
         value = b(repr(value))
     elif not isinstance(value, basestring):
         value = unicode(value)
     if isinstance(value, unicode):
         # The encoding should be configurable as in connection.py:Connection.encode
         value = value.encode('utf-8')
     return value