summaryrefslogtreecommitdiff
path: root/tests/unit/functions.tcl
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit/functions.tcl')
-rw-r--r--tests/unit/functions.tcl280
1 files changed, 280 insertions, 0 deletions
diff --git a/tests/unit/functions.tcl b/tests/unit/functions.tcl
new file mode 100644
index 000000000..0736a44da
--- /dev/null
+++ b/tests/unit/functions.tcl
@@ -0,0 +1,280 @@
+start_server {tags {"scripting"}} {
+ test {FUNCTION - Basic usage} {
+ r function create LUA test {return 'hello'}
+ r fcall test 0
+ } {hello}
+
+ test {FUNCTION - Create an already exiting function raise error} {
+ catch {
+ r function create LUA test {return 'hello1'}
+ } e
+ set _ $e
+ } {*Function already exists*}
+
+ test {FUNCTION - Create function with unexisting engine} {
+ catch {
+ r function create bad_engine test {return 'hello1'}
+ } e
+ set _ $e
+ } {*Engine not found*}
+
+ test {FUNCTION - Test uncompiled script} {
+ catch {
+ r function create LUA test1 {bad script}
+ } e
+ set _ $e
+ } {*Error compiling function*}
+
+ test {FUNCTION - test replace argument} {
+ r function create LUA test REPLACE {return 'hello1'}
+ r fcall test 0
+ } {hello1}
+
+ test {FUNCTION - test replace argument with function creation failure keeps old function} {
+ catch {r function create LUA test REPLACE {error}}
+ r fcall test 0
+ } {hello1}
+
+ test {FUNCTION - test function delete} {
+ r function delete test
+ catch {
+ r fcall test 0
+ } e
+ set _ $e
+ } {*Function not found*}
+
+ test {FUNCTION - test description argument} {
+ r function create LUA test DESCRIPTION {some description} {return 'hello'}
+ r function list
+ } {{name test engine LUA description {some description}}}
+
+ test {FUNCTION - test info specific function} {
+ r function info test WITHCODE
+ } {name test engine LUA description {some description} code {return 'hello'}}
+
+ test {FUNCTION - test info without code} {
+ r function info test
+ } {name test engine LUA description {some description}}
+
+ test {FUNCTION - test info on function that does not exists} {
+ catch {
+ r function info bad_function_name
+ } e
+ set _ $e
+ } {*Function does not exists*}
+
+ test {FUNCTION - test info with bad number of arguments} {
+ catch {
+ r function info test WITHCODE bad_arg
+ } e
+ set _ $e
+ } {*wrong number of arguments*}
+
+ test {FUNCTION - test fcall bad arguments} {
+ catch {
+ r fcall test bad_arg
+ } e
+ set _ $e
+ } {*Bad number of keys provided*}
+
+ test {FUNCTION - test fcall bad number of keys arguments} {
+ catch {
+ r fcall test 10 key1
+ } e
+ set _ $e
+ } {*Number of keys can't be greater than number of args*}
+
+ test {FUNCTION - test fcall negative number of keys} {
+ catch {
+ r fcall test -1 key1
+ } e
+ set _ $e
+ } {*Number of keys can't be negative*}
+
+ test {FUNCTION - test function delete on not exiting function} {
+ catch {
+ r function delete test1
+ } e
+ set _ $e
+ } {*Function not found*}
+
+ test {FUNCTION - test function kill when function is not running} {
+ catch {
+ r function kill
+ } e
+ set _ $e
+ } {*No scripts in execution*}
+
+ test {FUNCTION - test wrong subcommand} {
+ catch {
+ r function bad_subcommand
+ } e
+ set _ $e
+ } {*Unknown subcommand*}
+
+ test {FUNCTION - test loading from rdb} {
+ r debug reload
+ r fcall test 0
+ } {hello}
+
+ test {FUNCTION - test fcall_ro with write command} {
+ r function create lua test REPLACE {return redis.call('set', 'x', '1')}
+ catch { r fcall_ro test 0 } e
+ set _ $e
+ } {*Write commands are not allowed from read-only scripts*}
+
+ test {FUNCTION - test fcall_ro with read only commands} {
+ r function create lua test REPLACE {return redis.call('get', 'x')}
+ r set x 1
+ r fcall_ro test 0
+ } {1}
+
+ test {FUNCTION - test keys and argv} {
+ r function create lua test REPLACE {return redis.call('set', KEYS[1], ARGV[1])}
+ r fcall test 1 x foo
+ r get x
+ } {foo}
+
+ test {FUNCTION - test command get keys on fcall} {
+ r COMMAND GETKEYS fcall test 1 x foo
+ } {x}
+
+ test {FUNCTION - test command get keys on fcall_ro} {
+ r COMMAND GETKEYS fcall_ro test 1 x foo
+ } {x}
+
+ test {FUNCTION - test function kill} {
+ set rd [redis_deferring_client]
+ r config set script-time-limit 10
+ r function create lua test REPLACE {local a = 1 while true do a = a + 1 end}
+ $rd fcall test 0
+ after 200
+ catch {r ping} e
+ assert_match {BUSY*} $e
+ assert_match {running_script {name test command {fcall test 0} duration_ms *} engines LUA} [r FUNCTION STATS]
+ r function kill
+ after 200 ; # Give some time to Lua to call the hook again...
+ assert_equal [r ping] "PONG"
+ }
+
+ test {FUNCTION - test script kill not working on function} {
+ set rd [redis_deferring_client]
+ r config set script-time-limit 10
+ r function create lua test REPLACE {local a = 1 while true do a = a + 1 end}
+ $rd fcall test 0
+ after 200
+ catch {r ping} e
+ assert_match {BUSY*} $e
+ catch {r script kill} e
+ assert_match {BUSY*} $e
+ r function kill
+ after 200 ; # Give some time to Lua to call the hook again...
+ assert_equal [r ping] "PONG"
+ }
+
+ test {FUNCTION - test function kill not working on eval} {
+ set rd [redis_deferring_client]
+ r config set script-time-limit 10
+ $rd eval {local a = 1 while true do a = a + 1 end} 0
+ after 200
+ catch {r ping} e
+ assert_match {BUSY*} $e
+ catch {r function kill} e
+ assert_match {BUSY*} $e
+ r script kill
+ after 200 ; # Give some time to Lua to call the hook again...
+ assert_equal [r ping] "PONG"
+ }
+}
+
+start_server {tags {"scripting repl"}} {
+ start_server {} {
+ test "Connect a replica to the master instance" {
+ r -1 slaveof [srv 0 host] [srv 0 port]
+ wait_for_condition 50 100 {
+ [s -1 role] eq {slave} &&
+ [string match {*master_link_status:up*} [r -1 info replication]]
+ } else {
+ fail "Can't turn the instance into a replica"
+ }
+ }
+
+ test {FUNCTION - creation is replicated to replica} {
+ r function create LUA test DESCRIPTION {some description} {return 'hello'}
+ wait_for_condition 50 100 {
+ [r -1 function list] eq {{name test engine LUA description {some description}}}
+ } else {
+ fail "Failed waiting for function to replicate to replica"
+ }
+ }
+
+ test {FUNCTION - call on replica} {
+ r -1 fcall test 0
+ } {hello}
+
+ test {FUNCTION - delete is replicated to replica} {
+ r function delete test
+ wait_for_condition 50 100 {
+ [r -1 function list] eq {}
+ } else {
+ fail "Failed waiting for function to replicate to replica"
+ }
+ }
+
+ test "Disconnecting the replica from master instance" {
+ r -1 slaveof no one
+ # creating a function after disconnect to make sure function
+ # is replicated on rdb phase
+ r function create LUA test DESCRIPTION {some description} {return 'hello'}
+
+ # reconnect the replica
+ r -1 slaveof [srv 0 host] [srv 0 port]
+ wait_for_condition 50 100 {
+ [s -1 role] eq {slave} &&
+ [string match {*master_link_status:up*} [r -1 info replication]]
+ } else {
+ fail "Can't turn the instance into a replica"
+ }
+ }
+
+ test "FUNCTION - test replication to replica on rdb phase" {
+ r -1 fcall test 0
+ } {hello}
+
+ test "FUNCTION - test replication to replica on rdb phase info command" {
+ r -1 function info test WITHCODE
+ } {name test engine LUA description {some description} code {return 'hello'}}
+
+ test "FUNCTION - create on read only replica" {
+ catch {
+ r -1 function create LUA test DESCRIPTION {some description} {return 'hello'}
+ } e
+ set _ $e
+ } {*Can not create a function on a read only replica*}
+
+ test "FUNCTION - delete on read only replica" {
+ catch {
+ r -1 function delete test
+ } e
+ set _ $e
+ } {*Can not delete a function on a read only replica*}
+
+ test "FUNCTION - function effect is replicated to replica" {
+ r function create LUA test REPLACE {return redis.call('set', 'x', '1')}
+ r fcall test 0
+ assert {[r get x] eq {1}}
+ wait_for_condition 50 100 {
+ [r -1 get x] eq {1}
+ } else {
+ fail "Failed waiting function effect to be replicated to replica"
+ }
+ }
+
+ test "FUNCTION - modify key space of read only replica" {
+ catch {
+ r -1 fcall test 0
+ } e
+ set _ $e
+ } {*can't write against a read only replica*}
+ }
+} \ No newline at end of file