Skip to content

Commit

Permalink
Update FUNCTION LOAD changes (#2139)
Browse files Browse the repository at this point in the history
  • Loading branch information
dvora-h authored Apr 27, 2022
1 parent 6ba4641 commit 6832705
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 44 deletions.
1 change: 0 additions & 1 deletion redis/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,6 @@ class AbstractRedis:
"DEBUG OBJECT": parse_debug_object,
"FUNCTION DELETE": bool_ok,
"FUNCTION FLUSH": bool_ok,
"FUNCTION LOAD": bool_ok,
"FUNCTION RESTORE": bool_ok,
"GEOHASH": lambda r: list(map(str_if_bytes, r)),
"GEOPOS": lambda r: list(
Expand Down
20 changes: 6 additions & 14 deletions redis/commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5703,28 +5703,20 @@ class FunctionCommands:

def function_load(
self,
engine: str,
library: str,
code: str,
replace: Optional[bool] = False,
description: Optional[str] = None,
) -> Union[Awaitable[str], str]:
"""
Load a library to Redis.
:param engine: the name of the execution engine for the library
:param library: the unique name of the library
:param code: the source code
:param replace: changes the behavior to replace the library if a library called
``library`` already exists
:param description: description to the library
:param code: the source code (must start with
Shebang statement that provides a metadata about the library)
:param replace: changes the behavior to overwrite the existing library
with the new contents.
Return the library name that was loaded.
For more information see https://redis.io/commands/function-load
"""
pieces = [engine, library]
if replace:
pieces.append("REPLACE")
if description is not None:
pieces.append(description)
pieces = ["REPLACE"] if replace else []
pieces.append(code)
return self.execute_command("FUNCTION LOAD", *pieces)

Expand Down
67 changes: 38 additions & 29 deletions tests/test_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@

from .conftest import skip_if_server_version_lt

function = "redis.register_function('myfunc', function(keys, args) return args[1] end)"
engine = "lua"
lib = "mylib"
lib2 = "mylib2"
function = "redis.register_function{function_name='myfunc', callback=function(keys, \
args) return args[1] end, flags={ 'no-writes' }}"
function2 = "redis.register_function('hello', function() return 'Hello World' end)"
set_function = "redis.register_function('set', function(keys, args) \
return redis.call('SET', keys[1], args[1]) end)"
get_function = "redis.register_function('get', function(keys, args) \
return redis.call('GET', keys[1]) end)"
set_function = "redis.register_function('set', function(keys, args) return \
redis.call('SET', keys[1], args[1]) end)"
get_function = "redis.register_function('get', function(keys, args) return \
redis.call('GET', keys[1]) end)"


@skip_if_server_version_lt("7.0.0")
Expand All @@ -19,25 +23,28 @@ def reset_functions(self, r):
r.function_flush()

def test_function_load(self, r):
assert r.function_load("Lua", "mylib", function)
assert r.function_load("Lua", "mylib", function, replace=True)
print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
assert lib == r.function_load(f"#!{engine} name={lib} \n {function}")
assert lib == r.function_load(
f"#!{engine} name={lib} \n {function}", replace=True
)
with pytest.raises(ResponseError):
r.function_load("Lua", "mylib", function)
r.function_load(f"#!{engine} name={lib} \n {function}")
with pytest.raises(ResponseError):
r.function_load("Lua", "mylib2", function)
r.function_load(f"#!{engine} name={lib2} \n {function}")

def test_function_delete(self, r):
r.function_load("Lua", "mylib", set_function)
r.function_load(f"#!{engine} name={lib} \n {set_function}")
with pytest.raises(ResponseError):
r.function_load("Lua", "mylib", set_function)
r.function_load(f"#!{engine} name={lib} \n {set_function}")
assert r.fcall("set", 1, "foo", "bar") == "OK"
assert r.function_delete("mylib")
with pytest.raises(ResponseError):
r.fcall("set", 1, "foo", "bar")
assert r.function_load("Lua", "mylib", set_function)
assert lib == r.function_load(f"#!{engine} name={lib} \n {set_function}")

def test_function_flush(self, r):
r.function_load("Lua", "mylib", function)
r.function_load(f"#!{engine} name={lib} \n {function}")
assert r.fcall("myfunc", 0, "hello") == "hello"
assert r.function_flush()
with pytest.raises(ResponseError):
Expand All @@ -47,36 +54,35 @@ def test_function_flush(self, r):

@pytest.mark.onlynoncluster
def test_function_list(self, r):
r.function_load("Lua", "mylib", function)
r.function_load(f"#!{engine} name={lib} \n {function}")
res = [
[
"library_name",
"mylib",
"engine",
"LUA",
"description",
None,
"functions",
[["name", "myfunc", "description", None]],
[["name", "myfunc", "description", None, "flags", ["no-writes"]]],
],
]
assert r.function_list() == res
assert r.function_list(library="*lib") == res
assert r.function_list(withcode=True)[0][9] == function
assert (
r.function_list(withcode=True)[0][7]
== f"#!{engine} name={lib} \n {function}"
)

@pytest.mark.onlycluster
def test_function_list_on_cluster(self, r):
r.function_load("Lua", "mylib", function)
r.function_load(f"#!{engine} name={lib} \n {function}")
function_list = [
[
"library_name",
"mylib",
"engine",
"LUA",
"description",
None,
"functions",
[["name", "myfunc", "description", None]],
[["name", "myfunc", "description", None, "flags", ["no-writes"]]],
],
]
primaries = r.get_primaries()
Expand All @@ -86,33 +92,36 @@ def test_function_list_on_cluster(self, r):
assert r.function_list() == res
assert r.function_list(library="*lib") == res
node = primaries[0].name
assert r.function_list(withcode=True)[node][0][9] == function
assert (
r.function_list(withcode=True)[node][0][7]
== f"#!{engine} name={lib} \n {function}"
)

def test_fcall(self, r):
r.function_load("Lua", "mylib", set_function)
r.function_load("Lua", "mylib2", get_function)
r.function_load(f"#!{engine} name={lib} \n {set_function}")
r.function_load(f"#!{engine} name={lib2} \n {get_function}")
assert r.fcall("set", 1, "foo", "bar") == "OK"
assert r.fcall("get", 1, "foo") == "bar"
with pytest.raises(ResponseError):
r.fcall("myfunc", 0, "hello")

def test_fcall_ro(self, r):
r.function_load("Lua", "mylib", function)
r.function_load(f"#!{engine} name={lib} \n {function}")
assert r.fcall_ro("myfunc", 0, "hello") == "hello"
r.function_load("Lua", "mylib2", set_function)
r.function_load(f"#!{engine} name={lib2} \n {set_function}")
with pytest.raises(ResponseError):
r.fcall_ro("set", 1, "foo", "bar")

def test_function_dump_restore(self, r):
r.function_load("Lua", "mylib", set_function)
r.function_load(f"#!{engine} name={lib} \n {set_function}")
payload = r.function_dump()
assert r.fcall("set", 1, "foo", "bar") == "OK"
r.function_delete("mylib")
with pytest.raises(ResponseError):
r.fcall("set", 1, "foo", "bar")
assert r.function_restore(payload)
assert r.fcall("set", 1, "foo", "bar") == "OK"
r.function_load("Lua", "mylib2", get_function)
r.function_load(f"#!{engine} name={lib2} \n {get_function}")
assert r.fcall("get", 1, "foo") == "bar"
r.function_delete("mylib")
assert r.function_restore(payload, "FLUSH")
Expand Down

0 comments on commit 6832705

Please sign in to comment.