summaryrefslogtreecommitdiff
path: root/tests/test_scripting.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_scripting.py')
-rw-r--r--tests/test_scripting.py94
1 files changed, 92 insertions, 2 deletions
diff --git a/tests/test_scripting.py b/tests/test_scripting.py
index dcf8a78..4635f95 100644
--- a/tests/test_scripting.py
+++ b/tests/test_scripting.py
@@ -2,6 +2,7 @@ import pytest
import redis
from redis import exceptions
+from redis.commands.core import Script
from tests.conftest import skip_if_server_version_lt
multiply_script = """
@@ -21,24 +22,103 @@ return "hello " .. name
"""
-@pytest.mark.onlynoncluster
+class TestScript:
+ """
+ We have a few tests to directly test the Script class.
+
+ However, most of the behavioral tests are covered by `TestScripting`.
+ """
+
+ @pytest.fixture()
+ def script_str(self):
+ return "fake-script"
+
+ @pytest.fixture()
+ def script_bytes(self):
+ return b"\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82"
+
+ def test_script_text(self, r, script_str, script_bytes):
+ assert Script(r, script_str).script == "fake-script"
+ assert Script(r, script_bytes).script == b"\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82"
+
+ def test_string_script_sha(self, r, script_str):
+ script = Script(r, script_str)
+ assert script.sha == "505e4245f0866b60552741b3cce9a0c3d3b66a87"
+
+ def test_bytes_script_sha(self, r, script_bytes):
+ script = Script(r, script_bytes)
+ assert script.sha == "1329344e6bf995a35a8dc57ab1a6af8b2d54a763"
+
+ def test_encoder(self, r, script_bytes):
+ encoder = Script(r, script_bytes).get_encoder()
+ assert encoder is not None
+ assert encoder.encode("fake-script") == b"fake-script"
+
+
class TestScripting:
@pytest.fixture(autouse=True)
def reset_scripts(self, r):
r.script_flush()
- def test_eval(self, r):
+ def test_eval_multiply(self, r):
r.set("a", 2)
# 2 * 3 == 6
assert r.eval(multiply_script, 1, "a", 3) == 6
# @skip_if_server_version_lt("7.0.0") turn on after redis 7 release
+ @pytest.mark.onlynoncluster
def test_eval_ro(self, unstable_r):
unstable_r.set("a", "b")
assert unstable_r.eval_ro("return redis.call('GET', KEYS[1])", 1, "a") == "b"
with pytest.raises(redis.ResponseError):
unstable_r.eval_ro("return redis.call('DEL', KEYS[1])", 1, "a")
+ def test_eval_msgpack(self, r):
+ msgpack_message_dumped = b"\x81\xa4name\xa3Joe"
+ # this is msgpack.dumps({"name": "joe"})
+ assert r.eval(msgpack_hello_script, 0, msgpack_message_dumped) == b"hello Joe"
+
+ def test_eval_same_slot(self, r):
+ """
+ In a clustered redis, the script keys must be in the same slot.
+
+ This test isn't very interesting for standalone redis, but it doesn't
+ hurt anything.
+ """
+ r.set("A{foo}", 2)
+ r.set("B{foo}", 4)
+ # 2 * 4 == 8
+
+ script = """
+ local value = redis.call('GET', KEYS[1])
+ local value2 = redis.call('GET', KEYS[2])
+ return value * value2
+ """
+ result = r.eval(script, 2, "A{foo}", "B{foo}")
+ assert result == 8
+
+ @pytest.mark.onlycluster
+ def test_eval_crossslot(self, r):
+ """
+ In a clustered redis, the script keys must be in the same slot.
+
+ This test should fail, because the two keys we send are in different
+ slots. This test assumes that {foo} and {bar} will not go to the same
+ server when used. In a setup with 3 primaries and 3 secondaries, this
+ assumption holds.
+ """
+ r.set("A{foo}", 2)
+ r.set("B{bar}", 4)
+ # 2 * 4 == 8
+
+ script = """
+ local value = redis.call('GET', KEYS[1])
+ local value2 = redis.call('GET', KEYS[2])
+ return value * value2
+ """
+ with pytest.raises(exceptions.RedisClusterException):
+ r.eval(script, 2, "A{foo}", "B{bar}")
+
@skip_if_server_version_lt("6.2.0")
def test_script_flush_620(self, r):
r.set("a", 2)
@@ -75,6 +155,7 @@ class TestScripting:
assert r.evalsha(sha, 1, "a", 3) == 6
# @skip_if_server_version_lt("7.0.0") turn on after redis 7 release
+ @pytest.mark.onlynoncluster
def test_evalsha_ro(self, unstable_r):
unstable_r.set("a", "b")
get_sha = unstable_r.script_load("return redis.call('GET', KEYS[1])")
@@ -99,6 +180,11 @@ class TestScripting:
r.script_load(multiply_script)
assert r.script_exists(sha) == [True]
+ def test_flush_response(self, r):
+ r.script_load(multiply_script)
+ flush_response = r.script_flush()
+ assert flush_response is True
+
def test_script_object(self, r):
r.set("a", 2)
multiply = r.register_script(multiply_script)
@@ -114,6 +200,8 @@ class TestScripting:
# Test first evalsha block
assert multiply(keys=["a"], args=[3]) == 6
+ # Scripting is not supported in cluster pipelines
+ @pytest.mark.onlynoncluster
def test_script_object_in_pipeline(self, r):
multiply = r.register_script(multiply_script)
precalculated_sha = multiply.sha
@@ -142,6 +230,8 @@ class TestScripting:
assert pipe.execute() == [True, b"2", 6]
assert r.script_exists(multiply.sha) == [True]
+ # Scripting is not supported in cluster pipelines
+ @pytest.mark.onlynoncluster
def test_eval_msgpack_pipeline_error_in_lua(self, r):
msgpack_hello = r.register_script(msgpack_hello_script)
assert msgpack_hello.sha