コード例 #1
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)
コード例 #2
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)
コード例 #3
0
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)
コード例 #4
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.")
コード例 #5
0
    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
コード例 #6
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.")
コード例 #7
0
ファイル: test_utils.py プロジェクト: inmar/redis-py-cluster
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")
コード例 #8
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
コード例 #9
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'
コード例 #10
0
ファイル: test_utils.py プロジェクト: inmar/redis-py-cluster
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")
コード例 #11
0
    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()")
コード例 #12
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")
コード例 #13
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(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'
コード例 #14
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(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'
コード例 #15
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(ResponseError) as ex:
                pipe.execute()

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

        assert r['a'] == b'1'
コード例 #16
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(RedisCluster,
                    startup_nodes=password_protected_startup_nodes)
    assert unicode(ex.value).startswith(
        "ERROR sending 'cluster slots' command to redis server:")
    _get_client(RedisCluster,
                startup_nodes=password_protected_startup_nodes,
                password='******')

    with pytest.raises(RedisClusterException) as ex:
        _get_client(RedisCluster,
                    startup_nodes=startup_nodes,
                    password='******')
    assert unicode(ex.value).startswith(
        "ERROR sending 'cluster slots' command to redis server:")
    _get_client(RedisCluster, startup_nodes=startup_nodes)
コード例 #17
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 = RedisCluster(**params)
    assert c.connection_pool.connection_kwargs[
        "socket_timeout"] == ClusterConnectionPool.RedisClusterDefaultTimeout

    with pytest.raises(RedisClusterException) as ex:
        _get_client(RedisCluster, db=1)
    assert unicode(ex.value).startswith(
        "Argument 'db' is not possible to use in cluster mode")
コード例 #18
0
def test_cluster_slots_error_expected_responseerror():
    """
    Check that exception is not raised if initialize can't execute
    'CLUSTER SLOTS' command but can hit other nodes.
    """
    with patch.object(Redis, 'execute_command') as execute_command_mock:
        execute_command_mock.side_effect = ResponseError("MASTERDOWN")

        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)
コード例 #19
0
def test_cluster_slots_error():
    """
    Check that exception is raised if initialize can't execute
    'CLUSTER SLOTS' command.
    """
    with patch.object(Redis, 'execute_command') as execute_command_mock:
        execute_command_mock.side_effect = Exception("foobar")

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

        with pytest.raises(RedisClusterException) as e:
            n.initialize()

        assert "ERROR sending 'cluster slots' command" in unicode(e)
コード例 #20
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 Redis(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)
コード例 #21
0
    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={})

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

            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
コード例 #22
0
ファイル: test_utils.py プロジェクト: inmar/redis-py-cluster
def test_blocked_command():
    with pytest.raises(RedisClusterException) as ex:
        blocked_command(None, "SET")
    assert unicode(ex.value) == "Command: SET is blocked in redis cluster mode"