Unverified Commit fb4e0d40 authored by Oran Agra's avatar Oran Agra Committed by GitHub
Browse files

Merge pull request #10532 from oranagra/7.0-rc3

Release 7.0 rc3
parents d2b5a579 8b242ef9
......@@ -31,16 +31,23 @@ test "(post-init) Set up ACL configuration" {
test "SENTINEL CONFIG SET handles on-the-fly credentials reconfiguration" {
# Make sure we're starting with a broken state...
after 5000
catch {S 1 SENTINEL CKQUORUM mymaster} err
assert_match {*NOQUORUM*} $err
wait_for_condition 200 50 {
[catch {S 1 SENTINEL CKQUORUM mymaster}] == 1
} else {
fail "Expected: Sentinel to be disconnected from master due to wrong password"
}
assert_error "*NOQUORUM*" {S 1 SENTINEL CKQUORUM mymaster}
foreach_sentinel_id id {
assert_equal {OK} [S $id SENTINEL CONFIG SET sentinel-user $::user]
assert_equal {OK} [S $id SENTINEL CONFIG SET sentinel-pass $::password]
}
after 5000
wait_for_condition 200 50 {
[catch {S 1 SENTINEL CKQUORUM mymaster}] == 0
} else {
fail "Expected: Sentinel to be connected to master after setting password"
}
assert_match {*OK*} [S 1 SENTINEL CKQUORUM mymaster]
}
......
# Initialization tests -- most units will start including this.
proc restart_killed_instances {} {
foreach type {redis sentinel} {
foreach_${type}_id id {
if {[get_instance_attrib $type $id pid] == -1} {
puts -nonewline "$type/$id "
flush stdout
restart_instance $type $id
}
}
}
}
source "../tests/includes/utils.tcl"
test "(init) Restart killed instances" {
restart_killed_instances
......@@ -59,14 +48,7 @@ test "(init) Sentinels can talk with the master" {
}
test "(init) Sentinels are able to auto-discover other sentinels" {
set sentinels [llength $::sentinel_instances]
foreach_sentinel_id id {
wait_for_condition 1000 50 {
[dict get [S $id SENTINEL MASTER mymaster] num-other-sentinels] == ($sentinels-1)
} else {
fail "At least some sentinel can't detect some other sentinel"
}
}
verify_sentinel_auto_discovery
}
test "(init) Sentinels are able to auto-discover slaves" {
......
proc restart_killed_instances {} {
foreach type {redis sentinel} {
foreach_${type}_id id {
if {[get_instance_attrib $type $id pid] == -1} {
puts -nonewline "$type/$id "
flush stdout
restart_instance $type $id
}
}
}
}
proc verify_sentinel_auto_discovery {} {
set sentinels [llength $::sentinel_instances]
foreach_sentinel_id id {
wait_for_condition 1000 50 {
[dict get [S $id SENTINEL MASTER mymaster] num-other-sentinels] == ($sentinels-1)
} else {
fail "At least some sentinel can't detect some other sentinel"
}
}
}
......@@ -188,6 +188,10 @@ proc ::redis::__method__readraw {id fd val} {
set ::redis::readraw($id) $val
}
proc ::redis::__method__readingraw {id fd} {
return $::redis::readraw($id)
}
proc ::redis::__method__attributes {id fd} {
set _ $::redis::attributes($id)
}
......
......@@ -684,6 +684,14 @@ proc start_server {options {code undefined}} {
}
}
# Start multiple servers with the same options, run code, then stop them.
proc start_multiple_servers {num options code} {
for {set i 0} {$i < $num} {incr i} {
set code [list start_server $options $code]
}
uplevel 1 $code
}
proc restart_server {level wait_ready rotate_logs {reconnect 1} {shutdown sigterm}} {
set srv [lindex $::servers end+$level]
if {$shutdown ne {sigterm}} {
......
......@@ -122,7 +122,7 @@ proc wait_replica_online r {
wait_for_condition 50 100 {
[string match "*slave0:*,state=online*" [$r info replication]]
} else {
fail "replica didn't sync in time"
fail "replica didn't online in time"
}
}
......@@ -130,7 +130,7 @@ proc wait_for_ofs_sync {r1 r2} {
wait_for_condition 50 100 {
[status $r1 master_repl_offset] eq [status $r2 master_repl_offset]
} else {
fail "replica didn't sync in time"
fail "replica offset didn't match in time"
}
}
......
......@@ -305,13 +305,19 @@ start_server {tags {"acl external:skip"}} {
assert_equal "ERR Command 'not-a-command' not found" $e
}
test {Test various commands for command permissions} {
r ACL setuser command-test -@all
assert_equal "This user has no permissions to run the 'set' command" [r ACL DRYRUN command-test set somekey somevalue]
assert_equal "This user has no permissions to run the 'get' command" [r ACL DRYRUN command-test get somekey]
}
test {Test various odd commands for key permissions} {
r ACL setuser command-test +@all %R~read* %W~write* %RW~rw*
# Test migrate, which is marked with incomplete keys
assert_equal "OK" [r ACL DRYRUN command-test MIGRATE whatever whatever rw]
assert_equal "This user has no permissions to access the 'read' key" [r ACL DRYRUN command-test MIGRATE whatever whatever read]
assert_equal "This user has no permissions to access the 'write' key" [r ACL DRYRUN command-test MIGRATE whatever whatever write]
assert_equal "OK" [r ACL DRYRUN command-test MIGRATE whatever whatever rw 0 500]
assert_equal "This user has no permissions to access the 'read' key" [r ACL DRYRUN command-test MIGRATE whatever whatever read 0 500]
assert_equal "This user has no permissions to access the 'write' key" [r ACL DRYRUN command-test MIGRATE whatever whatever write 0 500]
assert_equal "OK" [r ACL DRYRUN command-test MIGRATE whatever whatever "" 0 5000 KEYS rw]
assert_equal "This user has no permissions to access the 'read' key" [r ACL DRYRUN command-test MIGRATE whatever whatever "" 0 5000 KEYS read]
assert_equal "This user has no permissions to access the 'write' key" [r ACL DRYRUN command-test MIGRATE whatever whatever "" 0 5000 KEYS write]
......@@ -428,6 +434,50 @@ start_server {tags {"acl external:skip"}} {
assert_equal "This user has no permissions to access the 'otherchannel' channel" [r ACL DRYRUN test-channels ssubscribe otherchannel foo]
}
test {Test sort with ACL permissions} {
r set v1 1
r lpush mylist 1
r ACL setuser test-sort-acl on nopass (+sort ~mylist)
$r2 auth test-sort-acl nopass
catch {$r2 sort mylist by v*} e
assert_equal "ERR BY option of SORT denied due to insufficient ACL permissions." $e
catch {$r2 sort mylist get v*} e
assert_equal "ERR GET option of SORT denied due to insufficient ACL permissions." $e
r ACL setuser test-sort-acl (+sort ~mylist ~v*)
catch {$r2 sort mylist by v*} e
assert_equal "ERR BY option of SORT denied due to insufficient ACL permissions." $e
catch {$r2 sort mylist get v*} e
assert_equal "ERR GET option of SORT denied due to insufficient ACL permissions." $e
r ACL setuser test-sort-acl (+sort ~mylist %W~*)
catch {$r2 sort mylist by v*} e
assert_equal "ERR BY option of SORT denied due to insufficient ACL permissions." $e
catch {$r2 sort mylist get v*} e
assert_equal "ERR GET option of SORT denied due to insufficient ACL permissions." $e
r ACL setuser test-sort-acl (+sort ~mylist %R~*)
assert_equal "1" [$r2 sort mylist by v*]
# cleanup
r ACL deluser test-sort-acl
r del v1 mylist
}
test {Test DRYRUN with wrong number of arguments} {
r ACL setuser test-dry-run +@all ~v*
assert_equal "OK" [r ACL DRYRUN test-dry-run SET v v]
catch {r ACL DRYRUN test-dry-run SET v} e
assert_equal "ERR wrong number of arguments for 'set' command" $e
catch {r ACL DRYRUN test-dry-run SET} e
assert_equal "ERR wrong number of arguments for 'set' command" $e
}
$r2 close
}
......
......@@ -185,7 +185,7 @@ start_server {tags {"aofrw external:skip"} overrides {aof-use-rdb-preamble no}}
test "AOF rewrite functions" {
r flushall
r FUNCTION LOAD LUA test DESCRIPTION {desc} {
r FUNCTION LOAD {#!lua name=test
redis.register_function('test', function() return 1 end)
}
r bgrewriteaof
......@@ -194,7 +194,7 @@ start_server {tags {"aofrw external:skip"} overrides {aof-use-rdb-preamble no}}
r debug loadaof
assert_equal [r fcall test 0] 1
r FUNCTION LIST
} {{library_name test engine LUA description desc functions {{name test description {} flags {}}}}}
} {{library_name test engine LUA functions {{name test description {} flags {}}}}}
test {BGREWRITEAOF is delayed if BGSAVE is in progress} {
r flushall
......
......@@ -433,6 +433,12 @@ start_server {tags {"bitops"}} {
r bitfield foo3{t} incrby i5 0 1
set dirty5 [s rdb_changes_since_last_save]
assert {$dirty5 == $dirty4 + 2}
# Change length only
r setbit foo{t} 90 0
r bitfield foo2{t} set i5 90 0
set dirty6 [s rdb_changes_since_last_save]
assert {$dirty6 == $dirty5 + 2}
}
test {BITPOS bit=1 fuzzy testing using SETBIT} {
......
......@@ -395,13 +395,14 @@ start_server {} {
test "evict clients only until below limit" {
set client_count 10
set client_mem [mb 1]
r debug replybuffer-peak-reset-time never
r debug replybuffer resizing 0
r config set maxmemory-clients 0
r client setname control
r client no-evict on
# Make multiple clients consume together roughly 1mb less than maxmemory_clients
set total_client_mem 0
set max_client_mem 0
set rrs {}
for {set j 0} {$j < $client_count} {incr j} {
set rr [redis_client]
......@@ -414,20 +415,27 @@ start_server {} {
} else {
fail "Failed to fill qbuf for test"
}
incr total_client_mem [client_field client$j tot-mem]
# In theory all these clients should use the same amount of memory (~1mb). But in practice
# some allocators (libc) can return different allocation sizes for the same malloc argument causing
# some clients to use slightly more memory than others. We find the largest client and make sure
# all clients are roughly the same size (+-1%). Then we can safely set the client eviction limit and
# expect consistent results in the test.
set cmem [client_field client$j tot-mem]
if {$max_client_mem > 0} {
set size_ratio [expr $max_client_mem.0/$cmem.0]
assert_range $size_ratio 0.99 1.01
}
if {$cmem > $max_client_mem} {
set max_client_mem $cmem
}
}
set client_actual_mem [expr $total_client_mem / $client_count]
# Make sure client_acutal_mem is more or equal to what we intended
assert {$client_actual_mem >= $client_mem}
# Make sure all clients are still connected
set connected_clients [llength [lsearch -all [split [string trim [r client list]] "\r\n"] *name=client*]]
assert {$connected_clients == $client_count}
# Set maxmemory-clients to accommodate half our clients (taking into account the control client)
set maxmemory_clients [expr ($client_actual_mem * $client_count) / 2 + [client_field control tot-mem]]
set maxmemory_clients [expr ($max_client_mem * $client_count) / 2 + [client_field control tot-mem]]
r config set maxmemory-clients $maxmemory_clients
# Make sure total used memory is below maxmemory_clients
......@@ -438,8 +446,8 @@ start_server {} {
set connected_clients [llength [lsearch -all [split [string trim [r client list]] "\r\n"] *name=client*]]
assert {$connected_clients == [expr $client_count / 2]}
# Restore the peak reset time to default
r debug replybuffer-peak-reset-time reset
# Restore the reply buffer resize to default
r debug replybuffer resizing 1
foreach rr $rrs {$rr close}
} {} {needs:debug}
......@@ -454,7 +462,7 @@ start_server {} {
r client setname control
r client no-evict on
r config set maxmemory-clients 0
r debug replybuffer-peak-reset-time never
r debug replybuffer resizing 0
# Run over all sizes and create some clients using up that size
set total_client_mem 0
......@@ -505,8 +513,8 @@ start_server {} {
}
}
# Restore the peak reset time to default
r debug replybuffer-peak-reset-time reset
# Restore the reply buffer resize to default
r debug replybuffer resizing 1
foreach rr $rrs {$rr close}
} {} {needs:debug}
......
......@@ -19,6 +19,7 @@ proc csi {args} {
}
# make sure the test infra won't use SELECT
set old_singledb $::singledb
set ::singledb 1
# cluster creation is complicated with TLS, and the current tests don't really need that coverage
......@@ -26,14 +27,13 @@ tags {tls:skip external:skip cluster} {
# start three servers
set base_conf [list cluster-enabled yes cluster-node-timeout 1]
start_server [list overrides $base_conf] {
start_server [list overrides $base_conf] {
start_server [list overrides $base_conf] {
start_multiple_servers 3 [list overrides $base_conf] {
set node1 [srv 0 client]
set node2 [srv -1 client]
set node3 [srv -2 client]
set node3_pid [srv -2 pid]
set node3_rd [redis_deferring_client -2]
test {Create 3 node cluster} {
exec src/redis-cli --cluster-yes --cluster create \
......@@ -52,7 +52,6 @@ start_server [list overrides $base_conf] {
test "Run blocking command on cluster node3" {
# key9184688 is mapped to slot 10923 (first slot of node 3)
set node3_rd [redis_deferring_client -2]
$node3_rd brpop key9184688 0
$node3_rd flush
......@@ -90,10 +89,11 @@ start_server [list overrides $base_conf] {
}
}
set node1_rd [redis_deferring_client 0]
test "Sanity test push cmd after resharding" {
assert_error {*MOVED*} {$node3 lpush key9184688 v1}
set node1_rd [redis_deferring_client 0]
$node1_rd brpop key9184688 0
$node1_rd flush
......@@ -109,13 +109,11 @@ start_server [list overrides $base_conf] {
assert_equal {key9184688 v2} [$node1_rd read]
}
$node1_rd close
$node3_rd close
test "Run blocking command again on cluster node1" {
$node1 del key9184688
# key9184688 is mapped to slot 10923 which has been moved to node1
set node1_rd [redis_deferring_client 0]
$node1_rd brpop key9184688 0
$node1_rd flush
......@@ -149,18 +147,11 @@ start_server [list overrides $base_conf] {
exec kill -SIGCONT $node3_pid
$node1_rd close
# stop three servers
}
}
}
} ;# stop servers
# Test redis-cli -- cluster create, add-node, call.
# Test that functions are propagated on add-node
start_server [list overrides $base_conf] {
start_server [list overrides $base_conf] {
start_server [list overrides $base_conf] {
start_server [list overrides $base_conf] {
start_server [list overrides $base_conf] {
start_multiple_servers 5 [list overrides $base_conf] {
set node4_rd [redis_client -3]
set node5_rd [redis_client -4]
......@@ -182,7 +173,9 @@ start_server [list overrides $base_conf] {
# upload a function to all the cluster
exec src/redis-cli --cluster-yes --cluster call 127.0.0.1:[srv 0 port] \
FUNCTION LOAD LUA TEST {redis.register_function('test', function() return 'hello' end)}
FUNCTION LOAD {#!lua name=TEST
redis.register_function('test', function() return 'hello' end)
}
# adding node to the cluster
exec src/redis-cli --cluster-yes --cluster add-node \
......@@ -199,13 +192,15 @@ start_server [list overrides $base_conf] {
}
# make sure 'test' function was added to the new node
assert_equal {{library_name TEST engine LUA description {} functions {{name test description {} flags {}}}}} [$node4_rd FUNCTION LIST]
assert_equal {{library_name TEST engine LUA functions {{name test description {} flags {}}}}} [$node4_rd FUNCTION LIST]
# add function to node 5
assert_equal {OK} [$node5_rd FUNCTION LOAD LUA TEST {redis.register_function('test', function() return 'hello' end)}]
assert_equal {TEST} [$node5_rd FUNCTION LOAD {#!lua name=TEST
redis.register_function('test', function() return 'hello' end)
}]
# make sure functions was added to node 5
assert_equal {{library_name TEST engine LUA description {} functions {{name test description {} flags {}}}}} [$node5_rd FUNCTION LIST]
assert_equal {{library_name TEST engine LUA functions {{name test description {} flags {}}}}} [$node5_rd FUNCTION LIST]
# adding node 5 to the cluster should failed because it already contains the 'test' function
catch {
......@@ -215,11 +210,111 @@ start_server [list overrides $base_conf] {
} e
assert_match {*node already contains functions*} $e
}
# stop 5 servers
}
}
}
}
} ;# stop servers
# Test redis-cli --cluster create, add-node.
# Test that one slot can be migrated to and then away from the new node.
test {Migrate the last slot away from a node using redis-cli} {
start_multiple_servers 4 [list overrides $base_conf] {
# Create a cluster of 3 nodes
exec src/redis-cli --cluster-yes --cluster create \
127.0.0.1:[srv 0 port] \
127.0.0.1:[srv -1 port] \
127.0.0.1:[srv -2 port]
wait_for_condition 1000 50 {
[csi 0 cluster_state] eq {ok} &&
[csi -1 cluster_state] eq {ok} &&
[csi -2 cluster_state] eq {ok}
} else {
fail "Cluster doesn't stabilize"
}
# Insert some data
assert_equal OK [exec src/redis-cli -c -p [srv 0 port] SET foo bar]
set slot [exec src/redis-cli -c -p [srv 0 port] CLUSTER KEYSLOT foo]
# Add new node to the cluster
exec src/redis-cli --cluster-yes --cluster add-node \
127.0.0.1:[srv -3 port] \
127.0.0.1:[srv 0 port]
wait_for_condition 1000 50 {
[csi 0 cluster_state] eq {ok} &&
[csi -1 cluster_state] eq {ok} &&
[csi -2 cluster_state] eq {ok} &&
[csi -3 cluster_state] eq {ok}
} else {
fail "Cluster doesn't stabilize"
}
set newnode_r [redis_client -3]
set newnode_id [$newnode_r CLUSTER MYID]
# Find out which node has the key "foo" by asking the new node for a
# redirect.
catch { $newnode_r get foo } e
assert_match "MOVED $slot *" $e
lassign [split [lindex $e 2] :] owner_host owner_port
set owner_r [redis $owner_host $owner_port 0 $::tls]
set owner_id [$owner_r CLUSTER MYID]
# Move slot to new node using plain Redis commands
assert_equal OK [$newnode_r CLUSTER SETSLOT $slot IMPORTING $owner_id]
assert_equal OK [$owner_r CLUSTER SETSLOT $slot MIGRATING $newnode_id]
assert_equal {foo} [$owner_r CLUSTER GETKEYSINSLOT $slot 10]
assert_equal OK [$owner_r MIGRATE 127.0.0.1 [srv -3 port] "" 0 5000 KEYS foo]
assert_equal OK [$newnode_r CLUSTER SETSLOT $slot NODE $newnode_id]
assert_equal OK [$owner_r CLUSTER SETSLOT $slot NODE $newnode_id]
# Using --cluster check make sure we won't get `Not all slots are covered by nodes`.
# Wait for the cluster to become stable make sure the cluster is up during MIGRATE.
wait_for_condition 1000 50 {
[catch {exec src/redis-cli --cluster check 127.0.0.1:[srv 0 port]}] == 0 &&
[catch {exec src/redis-cli --cluster check 127.0.0.1:[srv -1 port]}] == 0 &&
[catch {exec src/redis-cli --cluster check 127.0.0.1:[srv -2 port]}] == 0 &&
[catch {exec src/redis-cli --cluster check 127.0.0.1:[srv -3 port]}] == 0 &&
[csi 0 cluster_state] eq {ok} &&
[csi -1 cluster_state] eq {ok} &&
[csi -2 cluster_state] eq {ok} &&
[csi -3 cluster_state] eq {ok}
} else {
fail "Cluster doesn't stabilize"
}
# Move the only slot back to original node using redis-cli
exec src/redis-cli --cluster reshard 127.0.0.1:[srv -3 port] \
--cluster-from $newnode_id \
--cluster-to $owner_id \
--cluster-slots 1 \
--cluster-yes
# The empty node will become a replica of the new owner before the
# `MOVED` check, so let's wait for the cluster to become stable.
wait_for_condition 1000 50 {
[csi 0 cluster_state] eq {ok} &&
[csi -1 cluster_state] eq {ok} &&
[csi -2 cluster_state] eq {ok} &&
[csi -3 cluster_state] eq {ok}
} else {
fail "Cluster doesn't stabilize"
}
# Check that the key foo has been migrated back to the original owner.
catch { $newnode_r get foo } e
assert_equal "MOVED $slot $owner_host:$owner_port" $e
# Check that the empty node has turned itself into a replica of the new
# owner and that the new owner knows that.
wait_for_condition 1000 50 {
[string match "*slave*" [$owner_r CLUSTER REPLICAS $owner_id]]
} else {
fail "Empty node didn't turn itself into a replica."
}
}
}
} ;# tags
\ No newline at end of file
} ;# tags
set ::singledb $old_singledb
proc get_function_code {args} {
return [format "redis.register_function('%s', function(KEYS, ARGV)\n %s \nend)" [lindex $args 0] [lindex $args 1]]
return [format "#!%s name=%s\nredis.register_function('%s', function(KEYS, ARGV)\n %s \nend)" [lindex $args 0] [lindex $args 1] [lindex $args 2] [lindex $args 3]]
}
proc get_no_writes_function_code {args} {
return [format "redis.register_function{function_name='%s', callback=function(KEYS, ARGV)\n %s \nend, flags={'no-writes'}}" [lindex $args 0] [lindex $args 1]]
return [format "#!%s name=%s\nredis.register_function{function_name='%s', callback=function(KEYS, ARGV)\n %s \nend, flags={'no-writes'}}" [lindex $args 0] [lindex $args 1] [lindex $args 2] [lindex $args 3]]
}
start_server {tags {"scripting"}} {
test {FUNCTION - Basic usage} {
r function load LUA test [get_function_code test {return 'hello'}]
r function load [get_function_code LUA test test {return 'hello'}]
r fcall test 0
} {hello}
test {FUNCTION - Load with unknown argument} {
catch {
r function load LUA test foo bar [get_function_code test {return 'hello'}]
r function load foo bar [get_function_code LUA test test {return 'hello'}]
} e
set _ $e
} {*Unknown option given*}
test {FUNCTION - Create an already exiting library raise error} {
catch {
r function load LUA test [get_function_code test {return 'hello1'}]
r function load [get_function_code LUA test test {return 'hello1'}]
} e
set _ $e
} {*already exists*}
test {FUNCTION - Create an already exiting library raise error (case insensitive)} {
catch {
r function load LUA TEST [get_function_code test {return 'hello1'}]
r function load [get_function_code LUA test test {return 'hello1'}]
} e
set _ $e
} {*already exists*}
test {FUNCTION - Create a library with wrong name format} {
catch {
r function load LUA {bad\0foramat} [get_function_code test {return 'hello1'}]
r function load [get_function_code LUA {bad\0foramat} test {return 'hello1'}]
} e
set _ $e
} {*Library names can only contain letters and numbers*}
test {FUNCTION - Create library with unexisting engine} {
catch {
r function load bad_engine test [get_function_code test {return 'hello1'}]
r function load [get_function_code bad_engine test test {return 'hello1'}]
} e
set _ $e
} {*Engine not found*}
} {*Engine 'bad_engine' not found*}
test {FUNCTION - Test uncompiled script} {
catch {
r function load LUA test1 {bad script}
r function load replace [get_function_code LUA test test {bad script}]
} e
set _ $e
} {*Error compiling function*}
test {FUNCTION - test replace argument} {
r function load LUA test REPLACE [get_function_code test {return 'hello1'}]
r function load REPLACE [get_function_code LUA test test {return 'hello1'}]
r fcall test 0
} {hello1}
......@@ -76,12 +76,8 @@ start_server {tags {"scripting"}} {
set _ $e
} {*Function not found*}
test {FUNCTION - test description argument} {
r function load LUA test DESCRIPTION {some description} [get_function_code test {return 'hello'}]
r function list
} {{library_name test engine LUA description {some description} functions {{name test description {} flags {}}}}}
test {FUNCTION - test fcall bad arguments} {
r function load [get_function_code LUA test test {return 'hello'}]
catch {
r fcall test bad_arg
} e
......@@ -133,14 +129,14 @@ start_server {tags {"scripting"}} {
assert_match "*Error trying to load the RDB*" $e
r debug reload noflush merge
r function list
} {{library_name test engine LUA description {some description} functions {{name test description {} flags {}}}}} {needs:debug}
} {{library_name test engine LUA functions {{name test description {} flags {}}}}} {needs:debug}
test {FUNCTION - test debug reload with nosave and noflush} {
r function delete test
r set x 1
r function load LUA test1 DESCRIPTION {some description} [get_function_code test1 {return 'hello'}]
r function load [get_function_code LUA test1 test1 {return 'hello'}]
r debug reload
r function load LUA test2 DESCRIPTION {some description} [get_function_code test2 {return 'hello'}]
r function load [get_function_code LUA test2 test2 {return 'hello'}]
r debug reload nosave noflush merge
assert_equal [r fcall test1 0] {hello}
assert_equal [r fcall test2 0] {hello}
......@@ -148,21 +144,21 @@ start_server {tags {"scripting"}} {
test {FUNCTION - test flushall and flushdb do not clean functions} {
r function flush
r function load lua test REPLACE [get_function_code test {return redis.call('set', 'x', '1')}]
r function load REPLACE [get_function_code lua test test {return redis.call('set', 'x', '1')}]
r flushall
r flushdb
r function list
} {{library_name test engine LUA description {} functions {{name test description {} flags {}}}}}
} {{library_name test engine LUA functions {{name test description {} flags {}}}}}
test {FUNCTION - test function dump and restore} {
r function flush
r function load lua test description {some description} [get_function_code test {return 'hello'}]
r function load [get_function_code lua test test {return 'hello'}]
set e [r function dump]
r function delete test
assert_match {} [r function list]
r function restore $e
r function list
} {{library_name test engine LUA description {some description} functions {{name test description {} flags {}}}}}
} {{library_name test engine LUA functions {{name test description {} flags {}}}}}
test {FUNCTION - test function dump and restore with flush argument} {
set e [r function dump]
......@@ -170,17 +166,17 @@ start_server {tags {"scripting"}} {
assert_match {} [r function list]
r function restore $e FLUSH
r function list
} {{library_name test engine LUA description {some description} functions {{name test description {} flags {}}}}}
} {{library_name test engine LUA functions {{name test description {} flags {}}}}}
test {FUNCTION - test function dump and restore with append argument} {
set e [r function dump]
r function flush
assert_match {} [r function list]
r function load lua test [get_function_code test {return 'hello1'}]
r function load [get_function_code lua test test {return 'hello1'}]
catch {r function restore $e APPEND} err
assert_match {*already exists*} $err
r function flush
r function load lua test1 [get_function_code test1 {return 'hello1'}]
r function load [get_function_code lua test1 test1 {return 'hello1'}]
r function restore $e APPEND
assert_match {hello} [r fcall test 0]
assert_match {hello1} [r fcall test1 0]
......@@ -188,11 +184,11 @@ start_server {tags {"scripting"}} {
test {FUNCTION - test function dump and restore with replace argument} {
r function flush
r function load LUA test DESCRIPTION {some description} [get_function_code test {return 'hello'}]
r function load [get_function_code LUA test test {return 'hello'}]
set e [r function dump]
r function flush
assert_match {} [r function list]
r function load lua test [get_function_code test {return 'hello1'}]
r function load [get_function_code lua test test {return 'hello1'}]
assert_match {hello1} [r fcall test 0]
r function restore $e REPLACE
assert_match {hello} [r fcall test 0]
......@@ -200,11 +196,11 @@ start_server {tags {"scripting"}} {
test {FUNCTION - test function restore with bad payload do not drop existing functions} {
r function flush
r function load LUA test DESCRIPTION {some description} [get_function_code test {return 'hello'}]
r function load [get_function_code LUA test test {return 'hello'}]
catch {r function restore bad_payload} e
assert_match {*payload version or checksum are wrong*} $e
r function list
} {{library_name test engine LUA description {some description} functions {{name test description {} flags {}}}}}
} {{library_name test engine LUA functions {{name test description {} flags {}}}}}
test {FUNCTION - test function restore with wrong number of arguments} {
catch {r function restore arg1 args2 arg3} e
......@@ -212,19 +208,19 @@ start_server {tags {"scripting"}} {
} {*Unknown subcommand or wrong number of arguments for 'restore'. Try FUNCTION HELP.}
test {FUNCTION - test fcall_ro with write command} {
r function load lua test REPLACE [get_no_writes_function_code test {return redis.call('set', 'x', '1')}]
r function load REPLACE [get_no_writes_function_code lua test test {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 load lua test REPLACE [get_no_writes_function_code test {return redis.call('get', 'x')}]
r function load REPLACE [get_no_writes_function_code lua test test {return redis.call('get', 'x')}]
r set x 1
r fcall_ro test 0
} {1}
test {FUNCTION - test keys and argv} {
r function load lua test REPLACE [get_function_code test {return redis.call('set', KEYS[1], ARGV[1])}]
r function load REPLACE [get_function_code lua test test {return redis.call('set', KEYS[1], ARGV[1])}]
r fcall test 1 x foo
r get x
} {foo}
......@@ -240,7 +236,7 @@ start_server {tags {"scripting"}} {
test {FUNCTION - test function kill} {
set rd [redis_deferring_client]
r config set busy-reply-threshold 10
r function load lua test REPLACE [get_function_code test {local a = 1 while true do a = a + 1 end}]
r function load REPLACE [get_function_code lua test test {local a = 1 while true do a = a + 1 end}]
$rd fcall test 0
after 200
catch {r ping} e
......@@ -254,7 +250,7 @@ start_server {tags {"scripting"}} {
test {FUNCTION - test script kill not working on function} {
set rd [redis_deferring_client]
r config set busy-reply-threshold 10
r function load lua test REPLACE [get_function_code test {local a = 1 while true do a = a + 1 end}]
r function load REPLACE [get_function_code lua test test {local a = 1 while true do a = a + 1 end}]
$rd fcall test 0
after 200
catch {r ping} e
......@@ -281,18 +277,18 @@ start_server {tags {"scripting"}} {
}
test {FUNCTION - test function flush} {
r function load lua test REPLACE [get_function_code test {local a = 1 while true do a = a + 1 end}]
assert_match {{library_name test engine LUA description {} functions {{name test description {} flags {}}}}} [r function list]
r function load REPLACE [get_function_code lua test test {local a = 1 while true do a = a + 1 end}]
assert_match {{library_name test engine LUA functions {{name test description {} flags {}}}}} [r function list]
r function flush
assert_match {} [r function list]
r function load lua test REPLACE [get_function_code test {local a = 1 while true do a = a + 1 end}]
assert_match {{library_name test engine LUA description {} functions {{name test description {} flags {}}}}} [r function list]
r function load REPLACE [get_function_code lua test test {local a = 1 while true do a = a + 1 end}]
assert_match {{library_name test engine LUA functions {{name test description {} flags {}}}}} [r function list]
r function flush async
assert_match {} [r function list]
r function load lua test REPLACE [get_function_code test {local a = 1 while true do a = a + 1 end}]
assert_match {{library_name test engine LUA description {} functions {{name test description {} flags {}}}}} [r function list]
r function load REPLACE [get_function_code lua test test {local a = 1 while true do a = a + 1 end}]
assert_match {{library_name test engine LUA functions {{name test description {} flags {}}}}} [r function list]
r function flush sync
assert_match {} [r function list]
}
......@@ -310,7 +306,7 @@ start_server {tags {"scripting repl external:skip"}} {
start_server {} {
test "Connect a replica to the master instance" {
r -1 slaveof [srv 0 host] [srv 0 port]
wait_for_condition 50 100 {
wait_for_condition 150 100 {
[s -1 role] eq {slave} &&
[string match {*master_link_status:up*} [r -1 info replication]]
} else {
......@@ -319,9 +315,9 @@ start_server {tags {"scripting repl external:skip"}} {
}
test {FUNCTION - creation is replicated to replica} {
r function load LUA test DESCRIPTION {some description} [get_no_writes_function_code test {return 'hello'}]
wait_for_condition 50 100 {
[r -1 function list] eq {{library_name test engine LUA description {some description} functions {{name test description {} flags no-writes}}}}
r function load [get_no_writes_function_code LUA test test {return 'hello'}]
wait_for_condition 150 100 {
[r -1 function list] eq {{library_name test engine LUA functions {{name test description {} flags no-writes}}}}
} else {
fail "Failed waiting for function to replicate to replica"
}
......@@ -335,7 +331,7 @@ start_server {tags {"scripting repl external:skip"}} {
set e [r function dump]
r function delete test
wait_for_condition 50 100 {
wait_for_condition 150 100 {
[r -1 function list] eq {}
} else {
fail "Failed waiting for function to replicate to replica"
......@@ -343,8 +339,8 @@ start_server {tags {"scripting repl external:skip"}} {
assert_equal [r function restore $e] {OK}
wait_for_condition 50 100 {
[r -1 function list] eq {{library_name test engine LUA description {some description} functions {{name test description {} flags no-writes}}}}
wait_for_condition 150 100 {
[r -1 function list] eq {{library_name test engine LUA functions {{name test description {} flags no-writes}}}}
} else {
fail "Failed waiting for function to replicate to replica"
}
......@@ -352,7 +348,7 @@ start_server {tags {"scripting repl external:skip"}} {
test {FUNCTION - delete is replicated to replica} {
r function delete test
wait_for_condition 50 100 {
wait_for_condition 150 100 {
[r -1 function list] eq {}
} else {
fail "Failed waiting for function to replicate to replica"
......@@ -360,14 +356,14 @@ start_server {tags {"scripting repl external:skip"}} {
}
test {FUNCTION - flush is replicated to replica} {
r function load LUA test DESCRIPTION {some description} [get_function_code test {return 'hello'}]
wait_for_condition 50 100 {
[r -1 function list] eq {{library_name test engine LUA description {some description} functions {{name test description {} flags {}}}}}
r function load [get_function_code LUA test test {return 'hello'}]
wait_for_condition 150 100 {
[r -1 function list] eq {{library_name test engine LUA functions {{name test description {} flags {}}}}}
} else {
fail "Failed waiting for function to replicate to replica"
}
r function flush
wait_for_condition 50 100 {
wait_for_condition 150 100 {
[r -1 function list] eq {}
} else {
fail "Failed waiting for function to replicate to replica"
......@@ -378,11 +374,11 @@ start_server {tags {"scripting repl external:skip"}} {
r -1 slaveof no one
# creating a function after disconnect to make sure function
# is replicated on rdb phase
r function load LUA test DESCRIPTION {some description} [get_no_writes_function_code test {return 'hello'}]
r function load [get_no_writes_function_code LUA test test {return 'hello'}]
# reconnect the replica
r -1 slaveof [srv 0 host] [srv 0 port]
wait_for_condition 50 100 {
wait_for_condition 150 100 {
[s -1 role] eq {slave} &&
[string match {*master_link_status:up*} [r -1 info replication]]
} else {
......@@ -396,11 +392,11 @@ start_server {tags {"scripting repl external:skip"}} {
test "FUNCTION - test replication to replica on rdb phase info command" {
r -1 function list
} {{library_name test engine LUA description {some description} functions {{name test description {} flags no-writes}}}}
} {{library_name test engine LUA functions {{name test description {} flags no-writes}}}}
test "FUNCTION - create on read only replica" {
catch {
r -1 function load LUA test DESCRIPTION {some description} [get_function_code test {return 'hello'}]
r -1 function load [get_function_code LUA test test {return 'hello'}]
} e
set _ $e
} {*can't write against a read only replica*}
......@@ -413,10 +409,10 @@ start_server {tags {"scripting repl external:skip"}} {
} {*can't write against a read only replica*}
test "FUNCTION - function effect is replicated to replica" {
r function load LUA test REPLACE [get_function_code test {return redis.call('set', 'x', '1')}]
r function load REPLACE [get_function_code LUA test test {return redis.call('set', 'x', '1')}]
r fcall test 0
assert {[r get x] eq {1}}
wait_for_condition 50 100 {
wait_for_condition 150 100 {
[r -1 get x] eq {1}
} else {
fail "Failed waiting function effect to be replicated to replica"
......@@ -436,12 +432,12 @@ test {FUNCTION can processes create, delete and flush commands in AOF when doing
start_server {} {
r config set appendonly yes
waitForBgrewriteaof r
r FUNCTION LOAD lua test "redis.register_function('test', function() return 'hello' end)"
r FUNCTION LOAD "#!lua name=test\nredis.register_function('test', function() return 'hello' end)"
r config set slave-read-only yes
r slaveof 127.0.0.1 0
r debug loadaof
r slaveof no one
assert_equal [r function list] {{library_name test engine LUA description {} functions {{name test description {} flags {}}}}}
assert_equal [r function list] {{library_name test engine LUA functions {{name test description {} flags {}}}}}
r FUNCTION DELETE test
......@@ -450,7 +446,7 @@ test {FUNCTION can processes create, delete and flush commands in AOF when doing
r slaveof no one
assert_equal [r function list] {}
r FUNCTION LOAD lua test "redis.register_function('test', function() return 'hello' end)"
r FUNCTION LOAD "#!lua name=test\nredis.register_function('test', function() return 'hello' end)"
r FUNCTION FLUSH
r slaveof 127.0.0.1 0
......@@ -462,7 +458,7 @@ test {FUNCTION can processes create, delete and flush commands in AOF when doing
start_server {tags {"scripting"}} {
test {LIBRARIES - test shared function can access default globals} {
r function load LUA lib1 {
r function load {#!lua name=lib1
local function ping()
return redis.call('ping')
end
......@@ -477,7 +473,7 @@ start_server {tags {"scripting"}} {
} {PONG}
test {LIBRARIES - usage and code sharing} {
r function load LUA lib1 REPLACE {
r function load REPLACE {#!lua name=lib1
local function add1(a)
return a + 1
end
......@@ -497,11 +493,11 @@ start_server {tags {"scripting"}} {
assert_equal [r fcall f1 0] {2}
assert_equal [r fcall f2 0] {3}
r function list
} {{library_name lib1 engine LUA description {} functions {*}}}
} {{library_name lib1 engine LUA functions {*}}}
test {LIBRARIES - test registration failure revert the entire load} {
catch {
r function load LUA lib1 replace {
r function load replace {#!lua name=lib1
local function add1(a)
return a + 2
end
......@@ -524,7 +520,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - test registration function name collision} {
catch {
r function load LUA lib2 replace {
r function load replace {#!lua name=lib2
redis.register_function(
'f1',
function(keys, args)
......@@ -540,7 +536,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - test registration function name collision on same library} {
catch {
r function load LUA lib2 replace {
r function load replace {#!lua name=lib2
redis.register_function(
'f1',
function(keys, args)
......@@ -560,7 +556,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - test registration with no argument} {
catch {
r function load LUA lib2 replace {
r function load replace {#!lua name=lib2
redis.register_function()
}
} e
......@@ -569,7 +565,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - test registration with only name} {
catch {
r function load LUA lib2 replace {
r function load replace {#!lua name=lib2
redis.register_function('f1')
}
} e
......@@ -578,7 +574,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - test registration with to many arguments} {
catch {
r function load LUA lib2 replace {
r function load replace {#!lua name=lib2
redis.register_function('f1', function() return 1 end, {}, 'description', 'extra arg')
}
} e
......@@ -587,7 +583,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - test registration with no string name} {
catch {
r function load LUA lib2 replace {
r function load replace {#!lua name=lib2
redis.register_function(nil, function() return 1 end)
}
} e
......@@ -596,7 +592,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - test registration with wrong name format} {
catch {
r function load LUA lib2 replace {
r function load replace {#!lua name=lib2
redis.register_function('test\0test', function() return 1 end)
}
} e
......@@ -605,7 +601,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - test registration with empty name} {
catch {
r function load LUA lib2 replace {
r function load replace {#!lua name=lib2
redis.register_function('', function() return 1 end)
}
} e
......@@ -614,7 +610,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - math.random from function load} {
catch {
r function load LUA lib2 replace {
r function load replace {#!lua name=lib2
return math.random()
}
} e
......@@ -623,7 +619,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - redis.call from function load} {
catch {
r function load LUA lib2 replace {
r function load replace {#!lua name=lib2
return redis.call('ping')
}
} e
......@@ -632,7 +628,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - redis.call from function load} {
catch {
r function load LUA lib2 replace {
r function load replace {#!lua name=lib2
return redis.setresp(3)
}
} e
......@@ -641,7 +637,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - redis.set_repl from function load} {
catch {
r function load LUA lib2 replace {
r function load replace {#!lua name=lib2
return redis.set_repl(redis.REPL_NONE)
}
} e
......@@ -657,7 +653,7 @@ start_server {tags {"scripting"}} {
# have another level of protection on the C
# code itself and we want to test it and verify
# that it works properly.
r function load LUA lib1 replace {
r function load replace {#!lua name=lib1
local lib = redis
lib.register_function('f1', function ()
lib.redis = redis
......@@ -675,22 +671,34 @@ start_server {tags {"scripting"}} {
}
assert_equal {OK} [r fcall f1 0]
catch {[r function load LUA lib2 {redis.math.random()}]} e
catch {[r function load {#!lua name=lib2
redis.math.random()
}]} e
assert_match {*can only be called inside a script invocation*} $e
catch {[r function load LUA lib2 {redis.math.randomseed()}]} e
catch {[r function load {#!lua name=lib2
redis.math.randomseed()
}]} e
assert_match {*can only be called inside a script invocation*} $e
catch {[r function load LUA lib2 {redis.redis.call('ping')}]} e
catch {[r function load {#!lua name=lib2
redis.redis.call('ping')
}]} e
assert_match {*can only be called inside a script invocation*} $e
catch {[r function load LUA lib2 {redis.redis.pcall('ping')}]} e
catch {[r function load {#!lua name=lib2
redis.redis.pcall('ping')
}]} e
assert_match {*can only be called inside a script invocation*} $e
catch {[r function load LUA lib2 {redis.redis.setresp(3)}]} e
catch {[r function load {#!lua name=lib2
redis.redis.setresp(3)
}]} e
assert_match {*can only be called inside a script invocation*} $e
catch {[r function load LUA lib2 {redis.redis.set_repl(redis.redis.REPL_NONE)}]} e
catch {[r function load {#!lua name=lib2
redis.redis.set_repl(redis.redis.REPL_NONE)
}]} e
assert_match {*can only be called inside a script invocation*} $e
catch {[r fcall f2 0]} e
......@@ -703,7 +711,7 @@ start_server {tags {"scripting"}} {
} {}
test {LIBRARIES - register function inside a function} {
r function load LUA lib {
r function load {#!lua name=lib
redis.register_function(
'f1',
function(keys, args)
......@@ -724,7 +732,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - register library with no functions} {
r function flush
catch {
r function load LUA lib {
r function load {#!lua name=lib
return 1
}
} e
......@@ -733,7 +741,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - load timeout} {
catch {
r function load LUA lib {
r function load {#!lua name=lib
local a = 1
while 1 do a = a + 1 end
}
......@@ -743,7 +751,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - verify global protection on the load run} {
catch {
r function load LUA lib {
r function load {#!lua name=lib
a = 1
}
} e
......@@ -751,7 +759,7 @@ start_server {tags {"scripting"}} {
} {*attempted to create global variable 'a'*}
test {LIBRARIES - named arguments} {
r function load LUA lib {
r function load {#!lua name=lib
redis.register_function{
function_name='f1',
callback=function()
......@@ -761,11 +769,11 @@ start_server {tags {"scripting"}} {
}
}
r function list
} {{library_name lib engine LUA description {} functions {{name f1 description {some desc} flags {}}}}}
} {{library_name lib engine LUA functions {{name f1 description {some desc} flags {}}}}}
test {LIBRARIES - named arguments, bad function name} {
catch {
r function load LUA lib replace {
r function load replace {#!lua name=lib
redis.register_function{
function_name=function() return 1 end,
callback=function()
......@@ -780,7 +788,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - named arguments, bad callback type} {
catch {
r function load LUA lib replace {
r function load replace {#!lua name=lib
redis.register_function{
function_name='f1',
callback='bad',
......@@ -793,7 +801,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - named arguments, bad description} {
catch {
r function load LUA lib replace {
r function load replace {#!lua name=lib
redis.register_function{
function_name='f1',
callback=function()
......@@ -808,7 +816,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - named arguments, unknown argument} {
catch {
r function load LUA lib replace {
r function load replace {#!lua name=lib
redis.register_function{
function_name='f1',
callback=function()
......@@ -824,7 +832,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - named arguments, missing function name} {
catch {
r function load LUA lib replace {
r function load replace {#!lua name=lib
redis.register_function{
callback=function()
return 'hello'
......@@ -838,7 +846,7 @@ start_server {tags {"scripting"}} {
test {LIBRARIES - named arguments, missing callback} {
catch {
r function load LUA lib replace {
r function load replace {#!lua name=lib
redis.register_function{
function_name='f1',
description='desc'
......@@ -850,7 +858,7 @@ start_server {tags {"scripting"}} {
test {FUNCTION - test function restore with function name collision} {
r function flush
r function load lua lib1 {
r function load {#!lua name=lib1
local function add1(a)
return a + 1
end
......@@ -877,7 +885,7 @@ start_server {tags {"scripting"}} {
r function flush
# load a library with different name but with the same function name
r function load lua lib1 {
r function load {#!lua name=lib1
redis.register_function(
'f6',
function(keys, args)
......@@ -885,7 +893,7 @@ start_server {tags {"scripting"}} {
end
)
}
r function load lua lib2 {
r function load {#!lua name=lib2
local function add1(a)
return a + 1
end
......@@ -926,14 +934,18 @@ start_server {tags {"scripting"}} {
test {FUNCTION - test function list with code} {
r function flush
r function load lua library1 {redis.register_function('f6', function(keys, args) return 7 end)}
r function load {#!lua name=library1
redis.register_function('f6', function(keys, args) return 7 end)
}
r function list withcode
} {{library_name library1 engine LUA description {} functions {{name f6 description {} flags {}}} library_code {redis.register_function('f6', function(keys, args) return 7 end)}}}
} {{library_name library1 engine LUA functions {{name f6 description {} flags {}}} library_code {*redis.register_function('f6', function(keys, args) return 7 end)*}}}
test {FUNCTION - test function list with pattern} {
r function load lua lib1 {redis.register_function('f7', function(keys, args) return 7 end)}
r function load {#!lua name=lib1
redis.register_function('f7', function(keys, args) return 7 end)
}
r function list libraryname library*
} {{library_name library1 engine LUA description {} functions {{name f6 description {} flags {}}}}}
} {{library_name library1 engine LUA functions {{name f6 description {} flags {}}}}}
test {FUNCTION - test function list wrong argument} {
catch {r function list bad_argument} e
......@@ -957,12 +969,16 @@ start_server {tags {"scripting"}} {
test {FUNCTION - verify OOM on function load and function restore} {
r function flush
r function load lua test replace {redis.register_function('f1', function() return 1 end)}
r function load replace {#!lua name=test
redis.register_function('f1', function() return 1 end)
}
set payload [r function dump]
r config set maxmemory 1
r function flush
catch {r function load lua test replace {redis.register_function('f1', function() return 1 end)}} e
catch {r function load replace {#!lua name=test
redis.register_function('f1', function() return 1 end)
}} e
assert_match {*command not allowed when used memory*} $e
r function flush
......@@ -973,11 +989,13 @@ start_server {tags {"scripting"}} {
}
test {FUNCTION - verify allow-omm allows running any command} {
r FUNCTION load lua f1 replace { redis.register_function{
function_name='f1',
callback=function() return redis.call('set', 'x', '1') end,
flags={'allow-oom'}
}}
r FUNCTION load replace {#!lua name=f1
redis.register_function{
function_name='f1',
callback=function() return redis.call('set', 'x', '1') end,
flags={'allow-oom'}
}
}
r config set maxmemory 1
......@@ -990,53 +1008,65 @@ start_server {tags {"scripting"}} {
start_server {tags {"scripting"}} {
test {FUNCTION - wrong flags type named arguments} {
catch {r function load lua test replace {redis.register_function{
function_name = 'f1',
callback = function() return 1 end,
flags = 'bad flags type'
}}} e
catch {r function load replace {#!lua name=test
redis.register_function{
function_name = 'f1',
callback = function() return 1 end,
flags = 'bad flags type'
}
}} e
set _ $e
} {*flags argument to redis.register_function must be a table representing function flags*}
test {FUNCTION - wrong flag type} {
catch {r function load lua test replace {redis.register_function{
function_name = 'f1',
callback = function() return 1 end,
flags = {function() return 1 end}
}}} e
catch {r function load replace {#!lua name=test
redis.register_function{
function_name = 'f1',
callback = function() return 1 end,
flags = {function() return 1 end}
}
}} e
set _ $e
} {*unknown flag given*}
test {FUNCTION - unknown flag} {
catch {r function load lua test replace {redis.register_function{
function_name = 'f1',
callback = function() return 1 end,
flags = {'unknown'}
}}} e
catch {r function load replace {#!lua name=test
redis.register_function{
function_name = 'f1',
callback = function() return 1 end,
flags = {'unknown'}
}
}} e
set _ $e
} {*unknown flag given*}
test {FUNCTION - write script on fcall_ro} {
r function load lua test replace {redis.register_function{
function_name = 'f1',
callback = function() return redis.call('set', 'x', 1) end
}}
r function load replace {#!lua name=test
redis.register_function{
function_name = 'f1',
callback = function() return redis.call('set', 'x', 1) end
}
}
catch {r fcall_ro f1 0} e
set _ $e
} {*Can not execute a script with write flag using \*_ro command*}
test {FUNCTION - write script with no-writes flag} {
r function load lua test replace {redis.register_function{
function_name = 'f1',
callback = function() return redis.call('set', 'x', 1) end,
flags = {'no-writes'}
}}
r function load replace {#!lua name=test
redis.register_function{
function_name = 'f1',
callback = function() return redis.call('set', 'x', 1) end,
flags = {'no-writes'}
}
}
catch {r fcall f1 0} e
set _ $e
} {*Write commands are not allowed from read-only scripts*}
test {FUNCTION - deny oom} {
r FUNCTION load lua test replace { redis.register_function('f1', function() return redis.call('set', 'x', '1') end) }
r FUNCTION load replace {#!lua name=test
redis.register_function('f1', function() return redis.call('set', 'x', '1') end)
}
r config set maxmemory 1
......@@ -1047,7 +1077,9 @@ start_server {tags {"scripting"}} {
}
test {FUNCTION - deny oom on no-writes function} {
r FUNCTION load lua test replace {redis.register_function{function_name='f1', callback=function() return 'hello' end, flags={'no-writes'}}}
r FUNCTION load replace {#!lua name=test
redis.register_function{function_name='f1', callback=function() return 'hello' end, flags={'no-writes'}}
}
r config set maxmemory 1
......@@ -1061,7 +1093,7 @@ start_server {tags {"scripting"}} {
}
test {FUNCTION - allow stale} {
r FUNCTION load lua test replace {
r FUNCTION load replace {#!lua name=test
redis.register_function{function_name='f1', callback=function() return 'hello' end, flags={'no-writes'}}
redis.register_function{function_name='f2', callback=function() return 'hello' end, flags={'allow-stale', 'no-writes'}}
redis.register_function{function_name='f3', callback=function() return redis.call('get', 'x') end, flags={'allow-stale', 'no-writes'}}
......@@ -1087,7 +1119,7 @@ start_server {tags {"scripting"}} {
} {} {external:skip}
test {FUNCTION - redis version api} {
r FUNCTION load lua test replace {
r FUNCTION load replace {#!lua name=test
local version = redis.REDIS_VERSION_NUM
redis.register_function{function_name='get_version_v1', callback=function()
......@@ -1106,12 +1138,12 @@ start_server {tags {"scripting"}} {
test {FUNCTION - function stats} {
r FUNCTION FLUSH
r FUNCTION load lua test1 {
r FUNCTION load {#!lua name=test1
redis.register_function('f1', function() return 1 end)
redis.register_function('f2', function() return 1 end)
}
r FUNCTION load lua test2 {
r FUNCTION load {#!lua name=test2
redis.register_function('f3', function() return 1 end)
}
......@@ -1132,4 +1164,38 @@ start_server {tags {"scripting"}} {
r function flush
r function stats
} {running_script {} engines {LUA {libraries_count 0 functions_count 0}}}
test {FUNCTION - function test empty engine} {
catch {r function load replace {#! name=test
redis.register_function('foo', function() return 1 end)
}} e
set _ $e
} {ERR Engine '' not found}
test {FUNCTION - function test unknown metadata value} {
catch {r function load replace {#!lua name=test foo=bar
redis.register_function('foo', function() return 1 end)
}} e
set _ $e
} {ERR Invalid metadata value given: foo=bar}
test {FUNCTION - function test no name} {
catch {r function load replace {#!lua
redis.register_function('foo', function() return 1 end)
}} e
set _ $e
} {ERR Library name was not given}
test {FUNCTION - function test multiple names} {
catch {r function load replace {#!lua name=foo name=bar
redis.register_function('foo', function() return 1 end)
}} e
set _ $e
} {ERR Invalid metadata value, name argument was given multiple times}
test {FUNCTION - function test name with quotes} {
r function load replace {#!lua name="foo"
redis.register_function('foo', function() return 1 end)
}
} {foo}
}
......@@ -184,6 +184,7 @@ start_server {tags {"introspection"}} {
always-show-logo
syslog-enabled
cluster-enabled
disable-thp
aclfile
unixsocket
pidfile
......
......@@ -82,7 +82,7 @@ start_server {tags {"defrag external:skip"} overrides {appendonly yes auto-aof-r
fail "defrag didn't stop."
}
# Test the the fragmentation is lower.
# Test the fragmentation is lower.
after 120 ;# serverCron only updates the info once in 100ms
set frag [s allocator_frag_ratio]
set max_latency 0
......@@ -226,7 +226,7 @@ start_server {tags {"defrag external:skip"} overrides {appendonly yes auto-aof-r
fail "defrag didn't stop."
}
# test the the fragmentation is lower
# test the fragmentation is lower
after 120 ;# serverCron only updates the info once in 100ms
if {$::verbose} {
puts "used [s allocator_allocated]"
......@@ -336,7 +336,7 @@ start_server {tags {"defrag external:skip"} overrides {appendonly yes auto-aof-r
fail "defrag didn't stop."
}
# test the the fragmentation is lower
# test the fragmentation is lower
after 120 ;# serverCron only updates the info once in 100ms
set frag [s allocator_frag_ratio]
set max_latency 0
......@@ -433,7 +433,7 @@ start_server {tags {"defrag external:skip"} overrides {appendonly yes auto-aof-r
fail "defrag didn't stop."
}
# test the the fragmentation is lower
# test the fragmentation is lower
after 120 ;# serverCron only updates the info once in 100ms
set misses [s active_defrag_misses]
set hits [s active_defrag_hits]
......@@ -553,7 +553,7 @@ start_server {tags {"defrag external:skip"} overrides {appendonly yes auto-aof-r
fail "defrag didn't stop."
}
# test the the fragmentation is lower
# test the fragmentation is lower
after 120 ;# serverCron only updates the info once in 100ms
set misses [s active_defrag_misses]
set hits [s active_defrag_hits]
......
......@@ -62,10 +62,13 @@ start_server {tags {"modules acl"}} {
# rm call check for key permission (y: only WRITE)
assert_equal [r aclcheck.rm_call set y 5] OK
assert_error {*NOPERM*} {r aclcheck.rm_call set y 5 get}
assert_error {ERR acl verification failed, can't access at least one of the keys mentioned in the command arguments.} {r aclcheck.rm_call_with_errors set y 5 get}
# rm call check for key permission (z: only READ)
assert_error {*NOPERM*} {r aclcheck.rm_call set z 5}
assert_error {ERR acl verification failed, can't access at least one of the keys mentioned in the command arguments.} {r aclcheck.rm_call_with_errors set z 5}
assert_error {*NOPERM*} {r aclcheck.rm_call set z 6 get}
assert_error {ERR acl verification failed, can't access at least one of the keys mentioned in the command arguments.} {r aclcheck.rm_call_with_errors set z 6 get}
# verify that new log entry added
set entry [lindex [r ACL LOG] 0]
......@@ -77,6 +80,8 @@ start_server {tags {"modules acl"}} {
r acl setuser default -set
catch {r aclcheck.rm_call set x 5} e
assert_match {*NOPERM*} $e
catch {r aclcheck.rm_call_with_errors set x 5} e
assert_match {ERR acl verification failed, can't run this command or subcommand.} $e
# verify that new log entry added
set entry [lindex [r ACL LOG] 0]
......
......@@ -68,6 +68,22 @@ start_server {tags {"modules"}} {
assert_equal [r acl whoami] "default"
}
test {modules can redact arguments} {
r config set slowlog-log-slower-than 0
r slowlog reset
r auth.redact 1 2 3 4
r auth.redact 1 2 3
r config set slowlog-log-slower-than -1
set slowlog_resp [r slowlog get]
# There will be 3 records, slowlog reset and the
# two auth redact calls.
assert_equal 3 [llength $slowlog_resp]
assert_equal {slowlog reset} [lindex [lindex $slowlog_resp 2] 3]
assert_equal {auth.redact 1 (redacted) 3 (redacted)} [lindex [lindex $slowlog_resp 1] 3]
assert_equal {auth.redact (redacted) 2 (redacted)} [lindex [lindex $slowlog_resp 0] 3]
}
test "Unload the module - testacl" {
assert_equal {OK} [r module unload testacl]
}
......
......@@ -184,17 +184,17 @@ start_server {tags {"modules"}} {
r config resetstat
# simple module command that replies with string error
assert_error "NULL reply returned" {r do_rm_call hgetalllll}
assert_equal [errorrstat NULL r] {count=1}
assert_error "ERR Unknown Redis command 'hgetalllll'." {r do_rm_call hgetalllll}
assert_equal [errorrstat ERR r] {count=1}
# module command that replies with string error from bg thread
assert_error "NULL reply returned" {r do_bg_rm_call hgetalllll}
assert_equal [errorrstat NULL r] {count=2}
assert_equal [errorrstat NULL r] {count=1}
# module command that returns an arity error
r do_rm_call set x x
assert_error "ERR wrong number of arguments for 'do_rm_call' command" {r do_rm_call}
assert_equal [errorrstat ERR r] {count=1}
assert_equal [errorrstat ERR r] {count=2}
# RM_Call that propagates an error
assert_error "WRONGTYPE*" {r do_rm_call hgetall x}
......
......@@ -168,6 +168,38 @@ start_server {tags {"modules"}} {
assert_error "*unblocked*" {$rd read}
}
test {Module client blocked on keys, no timeout CB, CLIENT UNBLOCK TIMEOUT} {
r del k
set rd [redis_deferring_client]
$rd client id
set cid [$rd read]
$rd fsl.bpop k 0 NO_TO_CB
;# wait until clients are actually blocked
wait_for_condition 50 100 {
[s 0 blocked_clients] eq {1}
} else {
fail "Clients are not blocked"
}
assert_equal [r client unblock $cid timeout] {0}
$rd close
}
test {Module client blocked on keys, no timeout CB, CLIENT UNBLOCK ERROR} {
r del k
set rd [redis_deferring_client]
$rd client id
set cid [$rd read]
$rd fsl.bpop k 0 NO_TO_CB
;# wait until clients are actually blocked
wait_for_condition 50 100 {
[s 0 blocked_clients] eq {1}
} else {
fail "Clients are not blocked"
}
assert_equal [r client unblock $cid error] {0}
$rd close
}
test {Module client re-blocked on keys after woke up on wrong type} {
r del k
set rd [redis_deferring_client]
......
......@@ -20,8 +20,10 @@ proc csi {args} {
set testmodule [file normalize tests/modules/blockonkeys.so]
set testmodule_nokey [file normalize tests/modules/blockonbackground.so]
set testmodule_blockedclient [file normalize tests/modules/blockedclient.so]
# make sure the test infra won't use SELECT
set old_singledb $::singledb
set ::singledb 1
# cluster creation is complicated with TLS, and the current tests don't really need that coverage
......@@ -43,6 +45,10 @@ start_server [list overrides $base_conf] {
$node2 module load $testmodule_nokey
$node3 module load $testmodule_nokey
$node1 module load $testmodule_blockedclient
$node2 module load $testmodule_blockedclient
$node3 module load $testmodule_blockedclient
test {Create 3 node cluster} {
exec src/redis-cli --cluster-yes --cluster create \
127.0.0.1:[srv 0 port] \
......@@ -193,6 +199,10 @@ start_server [list overrides $base_conf] {
assert_equal [s -1 blocked_clients] {0}
}
test "Verify command RM_Call is rejected when cluster is down" {
assert_error "ERR Can not execute a command 'set' while the cluster is down" {$node1 do_rm_call set x 1}
}
exec kill -SIGCONT $node3_pid
$node1_rd close
$node2_rd close
......@@ -202,4 +212,6 @@ start_server [list overrides $base_conf] {
}
}
} ;# tags
\ No newline at end of file
} ;# tags
set ::singledb $old_singledb
......@@ -150,13 +150,17 @@ tags "modules" {
r swapdb 0 10
assert_equal [r hooks.event_last swapdb-first] 0
assert_equal [r hooks.event_last swapdb-second] 10
}
test {Test configchange hooks} {
r config set rdbcompression no
assert_equal [r hooks.event_last config-change-count] 1
assert_equal [r hooks.event_last config-change-first] rdbcompression
}
# look into the log file of the server that just exited
test {Test shutdown hook} {
assert_equal [string match {*module-event-shutdown*} [exec tail -5 < $replica_stdout]] 1
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment