Skip to content

Commit c081bd3

Browse files
committed
Filter tests, ensure that tests are working after refactor
1 parent 137c931 commit c081bd3

File tree

3 files changed

+245
-548
lines changed

3 files changed

+245
-548
lines changed

redis/cluster.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2983,16 +2983,16 @@ def _determine_nodes(self, *args, **kwargs) -> List["ClusterNode"]:
29832983
return [node]
29842984

29852985
def multi(self):
2986-
raise RedisClusterException("method multi() is not implemented")
2986+
raise RedisClusterException("method multi() is not supported outside of transactional context")
29872987

29882988
def discard(self):
2989-
raise RedisClusterException("method discard() is not implemented")
2989+
raise RedisClusterException("method discard() is not supported outside of transactional context")
29902990

29912991
def watch(self, *names):
2992-
raise RedisClusterException("method watch() is not implemented")
2992+
raise RedisClusterException("method watch() is not supported outside of transactional context")
29932993

29942994
def unwatch(self, *names):
2995-
raise RedisClusterException("method unwatch() is not implemented")
2995+
raise RedisClusterException("method unwatch() is not supported outside of transactional context")
29962996

29972997
def delete(self, *names):
29982998
if len(names) != 1:
@@ -3125,6 +3125,9 @@ def _send_command_parse_response(
31253125
except (AskError, MovedError) as slot_error:
31263126
self.slot_migrating = True
31273127
raise slot_error
3128+
except ConnectionError as conn_error:
3129+
self._cluster_error = True
3130+
raise conn_error
31283131

31293132
if command_name in self.UNWATCH_COMMANDS:
31303133
self._watching = False
@@ -3134,8 +3137,6 @@ def _reinitialize_on_error(self, error):
31343137
if self._watching:
31353138
if self.slot_migrating and self._executing:
31363139
raise WatchError("Slot rebalancing ocurred while watching keys")
3137-
if self._cluster_error:
3138-
raise RedisClusterException("Cluster error ocurred while watching keys")
31393140

31403141
if self.slot_migrating or self._cluster_error:
31413142
if self._transaction_connection:
@@ -3345,11 +3346,7 @@ def unwatch(self):
33453346
return True
33463347

33473348
def discard(self):
3348-
if self._explicit_transaction:
3349-
self.reset()
3350-
return
3351-
3352-
raise RedisClusterException("DISCARD triggered without MULTI")
3349+
self.reset()
33533350

33543351
def delete(self, *names):
33553352
return self.execute_command("DEL", *names)

tests/test_cluster.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3362,6 +3362,83 @@ def test_empty_stack(self, r):
33623362
result = p.execute()
33633363
assert result == []
33643364

3365+
@pytest.mark.onlycluster
3366+
def test_exec_error_in_response(self, r):
3367+
"""
3368+
an invalid pipeline command at exec time adds the exception instance
3369+
to the list of returned values
3370+
"""
3371+
hashkey = "{key}"
3372+
r[f"{hashkey}:c"] = "a"
3373+
with r.pipeline() as pipe:
3374+
pipe.set(f"{hashkey}:a", 1).set(f"{hashkey}:b", 2)
3375+
pipe.lpush(f"{hashkey}:c", 3).set(f"{hashkey}:d", 4)
3376+
result = pipe.execute(raise_on_error=False)
3377+
3378+
assert result[0]
3379+
assert r[f"{hashkey}:a"] == b"1"
3380+
assert result[1]
3381+
assert r[f"{hashkey}:b"] == b"2"
3382+
3383+
# we can't lpush to a key that's a string value, so this should
3384+
# be a ResponseError exception
3385+
assert isinstance(result[2], redis.ResponseError)
3386+
assert r[f"{hashkey}:c"] == b"a"
3387+
3388+
# since this isn't a transaction, the other commands after the
3389+
# error are still executed
3390+
assert result[3]
3391+
assert r[f"{hashkey}:d"] == b"4"
3392+
3393+
# make sure the pipe was restored to a working state
3394+
assert pipe.set(f"{hashkey}:z", "zzz").execute() == [True]
3395+
assert r[f"{hashkey}:z"] == b"zzz"
3396+
3397+
def test_exec_error_in_no_transaction_pipeline(self, r):
3398+
r["a"] = 1
3399+
with r.pipeline(transaction=False) as pipe:
3400+
pipe.llen("a")
3401+
pipe.expire("a", 100)
3402+
3403+
with pytest.raises(redis.ResponseError) as ex:
3404+
pipe.execute()
3405+
3406+
assert str(ex.value).startswith(
3407+
"Command # 1 (LLEN a) of pipeline caused error: "
3408+
)
3409+
3410+
assert r["a"] == b"1"
3411+
3412+
@pytest.mark.onlycluster
3413+
@skip_if_server_version_lt("2.0.0")
3414+
def test_pipeline_discard(self, r):
3415+
hashkey = "{key}"
3416+
3417+
# empty pipeline should raise an error
3418+
with r.pipeline() as pipe:
3419+
pipe.set(f"{hashkey}:key", "someval")
3420+
with pytest.raises(redis.exceptions.RedisClusterException) as ex:
3421+
pipe.discard()
3422+
3423+
assert str(ex.value).startswith("method discard() is not supported outside of transactional context")
3424+
3425+
# setting a pipeline and discarding should do the same
3426+
with r.pipeline() as pipe:
3427+
pipe.set(f"{hashkey}:key", "someval")
3428+
pipe.set(f"{hashkey}:someotherkey", "val")
3429+
response = pipe.execute()
3430+
pipe.set(f"{hashkey}:key", "another value!")
3431+
with pytest.raises(redis.exceptions.RedisClusterException) as ex:
3432+
pipe.discard()
3433+
3434+
assert str(ex.value).startswith("method discard() is not supported outside of transactional context")
3435+
3436+
pipe.set(f"{hashkey}:foo", "bar")
3437+
response = pipe.execute()
3438+
3439+
assert response[0]
3440+
assert r.get(f"{hashkey}:foo") == b"bar"
3441+
33653442

33663443
@pytest.mark.onlycluster
33673444
class TestReadOnlyPipeline:

0 commit comments

Comments
 (0)