1 start_server
{tags
{"scripting"}} {
2 test
{EVAL
- Does Lua interpreter replies to our requests?
} {
3 r
eval {return 'hello'
} 0
6 test
{EVAL
- Lua integer
-> Redis protocol type conversion
} {
7 r
eval {return 100.5} 0
10 test
{EVAL
- Lua
string -> Redis protocol type conversion
} {
11 r
eval {return 'hello world'
} 0
14 test
{EVAL
- Lua true boolean
-> Redis protocol type conversion
} {
15 r
eval {return true
} 0
18 test
{EVAL
- Lua false boolean
-> Redis protocol type conversion
} {
19 r
eval {return false
} 0
22 test
{EVAL
- Lua status code reply
-> Redis protocol type conversion
} {
23 r
eval {return {ok
='fine'
}} 0
26 test
{EVAL
- Lua
error reply
-> Redis protocol type conversion
} {
28 r
eval {return {err
='this is an
error'
}} 0
33 test
{EVAL
- Lua table
-> Redis protocol type conversion
} {
34 r
eval {return {1,2,3,'ciao'
,{1,2}}} 0
37 test
{EVAL
- Are the KEYS and ARGS arrays populated correctly?
} {
38 r
eval {return {KEYS
[1],KEYS
[2],ARGV
[1],ARGV
[2]}} 2 a b c d
41 test
{EVAL
- is Lua able to call Redis API?
} {
43 r
eval {return redis.call
('get'
,'mykey'
)} 0
46 test
{EVALSHA
- Can we call a SHA1
if already defined?
} {
47 r evalsha
9bd632c7d33e571e9f24556ebed26c3479a87129
0
50 test
{EVALSHA
- Do we get an
error on invalid SHA1?
} {
51 catch {r evalsha NotValidShaSUM
0} e
55 test
{EVALSHA
- Do we get an
error on non defined SHA1?
} {
56 catch {r evalsha ffd632c7d33e571e9f24556ebed26c3479a87130
0} e
60 test
{EVAL
- Redis integer
-> Lua type conversion
} {
62 local foo
= redis.pcall
('
incr'
,'x'
)
63 return {type
(foo
),foo
}
67 test
{EVAL
- Redis bulk
-> Lua type conversion
} {
70 local foo
= redis.pcall
('get'
,'mykey'
)
71 return {type
(foo
),foo
}
75 test
{EVAL
- Redis multi bulk
-> Lua type conversion
} {
81 local foo
= redis.pcall
('
lrange'
,'mylist'
,0,-1)
82 return {type
(foo
),foo
[1],foo
[2],foo
[3],# foo}
86 test
{EVAL
- Redis status reply
-> Lua type conversion
} {
88 local foo
= redis.pcall
('
set'
,'mykey'
,'myval'
)
89 return {type
(foo
),foo
['ok'
]}
93 test
{EVAL
- Redis
error reply
-> Lua type conversion
} {
96 local foo
= redis.pcall
('
incr'
,'mykey'
)
97 return {type
(foo
),foo
['err'
]}
99 } {table
{ERR value is not an integer or out of range
}}
101 test
{EVAL
- Redis nil bulk reply
-> Lua type conversion
} {
104 local foo
= redis.pcall
('get'
,'mykey'
)
105 return {type
(foo
),foo
== false
}
109 test
{EVAL
- Is Lua affecting the currently selected DB?
} {
110 r
set mykey
"this is DB 9"
112 r
set mykey
"this is DB 10"
113 r
eval {return redis.pcall
('get'
,'mykey'
)} 0
116 test
{EVAL
- Is Lua seleced DB retained?
} {
117 r
eval {return redis.pcall
('select'
,'
9'
)} 0
122 test
{EVAL
- Script can't run more than configured
time limit
} {
123 r config
set lua-time-limit
1
127 while true do i
=i
+1 end
134 test
{EVAL
- Scripts can't run certain commands
} {
136 catch {r
eval {return redis.pcall
('spop'
,'x'
)} 0} e
140 test
{EVAL
- Scripts can't run certain commands
} {
143 r
eval "redis.pcall('randomkey'); return redis.pcall('set','x','ciao')" 0
146 } {*not allowed
after*}
148 test
{EVAL
- No arguments to redis.call
/pcall is considered an
error} {
150 catch {r
eval {return redis.call
()} 0} e
154 test
{EVAL
- redis.call variant raises a Lua
error on Redis cmd
error (1)} {
157 r
eval "redis.call('nosuchcommand')" 0
162 test
{EVAL
- redis.call variant raises a Lua
error on Redis cmd
error (1)} {
165 r
eval "redis.call('get','a','b','c')" 0
170 test
{EVAL
- redis.call variant raises a Lua
error on Redis cmd
error (1)} {
174 r
eval "redis.call('lpush','foo','val')" 0
179 test
{SCRIPTING FLUSH
- is able to clear the scripts cache?
} {
181 set v
[r evalsha
9bd632c7d33e571e9f24556ebed26c3479a87129
0]
182 assert_equal
$v myval
185 catch {r evalsha
9bd632c7d33e571e9f24556ebed26c3479a87129
0} e
189 test
{SCRIPT EXISTS
- can detect already defined scripts?
} {
190 r
eval "return 1+1" 0
191 r script exists a27e7e8a43702b7046d4f6a7ccf5b60cef6b9bd9 a27e7e8a43702b7046d4f6a7ccf5b60cef6b9bda
194 test
{SCRIPT LOAD
- is able to register scripts in the scripting cache
} {
196 [r script
load "return 'loaded'"] \
197 [r evalsha b534286061d4b9e4026607613b95c06c06015ae8
0]
198 } {b534286061d4b9e4026607613b95c06c06015ae8 loaded
}
200 test
"In the context of Lua the output of random commands gets ordered" {
202 r sadd myset a b c d e f g h i l m n o p q r s t u v z aa aaa azz
203 r
eval {return redis.call
('smembers'
,'myset'
)} 0
204 } {a aa aaa azz b c d e f g h i l m n o p q r s t u v z
}
206 test
"SORT is normally not alpha re-ordered for the scripting engine" {
208 r sadd myset
1 2 3 4 10
209 r
eval {return redis.call
('sort'
,'myset'
,'desc'
)} 0
212 test
"SORT BY <constant> output gets ordered for scripting" {
214 r sadd myset a b c d e f g h i l m n o p q r s t u v z aa aaa azz
215 r
eval {return redis.call
('sort'
,'myset'
,'by'
,'_'
)} 0
216 } {a aa aaa azz b c d e f g h i l m n o p q r s t u v z
}
218 test
"SORT BY <constant> with GET gets ordered for scripting" {
221 r
eval {return redis.call
('sort'
,'myset'
,'by'
,'_'
,'get'
,'
#','get','_:*')} 0
224 test
"redis.sha1hex() implementation" {
225 list [r
eval {return redis.sha1hex
(''
)} 0] \
226 [r
eval {return redis.sha1hex
('Pizza
& Mandolino'
)} 0]
227 } {da39a3ee5e6b4b0d3255bfef95601890afd80709
74822d82031af7493c20eefa13bd07ec4fada82f
}
229 test
{Globals protection reading an undeclared
global variable} {
230 catch {r
eval {return a
} 0} e
232 } {*ERR
*attempted to access unexisting
global*}
234 test
{Globals protection setting an undeclared
global*} {
235 catch {r
eval {a
=10} 0} e
237 } {*ERR
*attempted to create
global*}
239 test
{Test an example script DECR_IF_GT
} {
243 current
= redis.call
('get'
,KEYS
[1])
244 if not current then
return nil end
245 if current
> ARGV
[1] then
246 return redis.call
('decr'
,KEYS
[1])
248 return redis.call
('get'
,KEYS
[1])
253 lappend res
[r
eval $decr_if_gt 1 foo
2]
254 lappend res
[r
eval $decr_if_gt 1 foo
2]
255 lappend res
[r
eval $decr_if_gt 1 foo
2]
256 lappend res
[r
eval $decr_if_gt 1 foo
2]
257 lappend res
[r
eval $decr_if_gt 1 foo
2]
261 test
{Scripting engine resets PRNG at every script execution
} {
262 set rand1
[r
eval {return tostring
(math.random
())} 0]
263 set rand2
[r
eval {return tostring
(math.random
())} 0]
264 assert_equal
$rand1 $rand2
267 test
{Scripting engine PRNG can be seeded correctly
} {
269 math.randomseed
(ARGV
[1]); return tostring
(math.random
())
272 math.randomseed
(ARGV
[1]); return tostring
(math.random
())
275 math.randomseed
(ARGV
[1]); return tostring
(math.random
())
277 assert_equal
$rand1 $rand2
278 assert
{$rand2 ne
$rand3}
282 # Start a new server since the last test in this stanza will kill the
284 start_server
{tags
{"scripting"}} {
285 test
{Timedout read-only scripts can be killed by SCRIPT KILL
} {
286 set rd
[redis_deferring_client
]
287 r config
set lua-time-limit
10
288 $rd eval {while true do end
} 0
291 assert_match
{BUSY
*} $e
293 assert_equal
[r ping
] "PONG"
296 test
{Timedout scripts that modified data can't be killed by SCRIPT KILL
} {
297 set rd
[redis_deferring_client
]
298 r config
set lua-time-limit
10
299 $rd eval {redis.call
('
set'
,'x'
,'y'
); while true do end
} 0
302 assert_match
{BUSY
*} $e
303 catch {r script kill
} e
304 assert_match
{ERR
*} $e
306 assert_match
{BUSY
*} $e
309 test
{SHUTDOWN NOSAVE can kill a timedout script anyway
} {
310 # The server sould be still unresponding to normal commands.
312 assert_match
{BUSY
*} $e
313 catch {r shutdown nosave
}
314 # Make sure the server was killed
315 catch {set rd
[redis_deferring_client
]} e
316 assert_match
{*connection refused
*} $e
320 start_server
{tags
{"scripting repl"}} {
322 test
{Before the slave connects we issue an EVAL command
} {
323 r
eval {return redis.call
('
incr'
,'x'
)} 0
326 test
{Connect a slave to the main instance
} {
327 r
-1 slaveof
[srv
0 host
] [srv
0 port
]
328 wait_for_condition
50 100 {
329 [s
-1 role
] eq
{slave
} &&
330 [string match
{*master_link_status
:up
*} [r
-1 info replication
]]
332 fail
"Can't turn the instance into a slave"
336 test
{Now use EVALSHA against the master
} {
337 r evalsha ae3477e27be955de7e1bc9adfdca626b478d3cb2
0
340 test
{If EVALSHA was replicated as EVAL the slave should be ok
} {
341 wait_for_condition
50 100 {
344 fail
"Expected 2 in x, but value is '[r -1 get x]'"
348 test
{Replication of script multiple pushes to
list with BLPOP
} {
349 set rd
[redis_deferring_client
]
352 redis.call
("lpush","a","1");
353 redis.call
("lpush","a","2");
357 wait_for_condition
50 100 {
358 [r
-1 lrange a
0 -1] eq
[r
lrange a
0 -1]
360 fail
"Expected list 'a' in slave and master to be the same, but they are respectively '[r -1 lrange a 0 -1]' and '[r lrange a 0 -1]'"