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
- Can we call a SHA1 in uppercase?
} {
51 r evalsha
9BD632C7D33E571E9F24556EBED26C3479A87129
0
54 test
{EVALSHA
- Do we get an
error on invalid SHA1?
} {
55 catch {r evalsha NotValidShaSUM
0} e
59 test
{EVALSHA
- Do we get an
error on non defined SHA1?
} {
60 catch {r evalsha ffd632c7d33e571e9f24556ebed26c3479a87130
0} e
64 test
{EVAL
- Redis integer
-> Lua type conversion
} {
66 local foo
= redis.pcall
('
incr'
,'x'
)
67 return {type
(foo
),foo
}
71 test
{EVAL
- Redis bulk
-> Lua type conversion
} {
74 local foo
= redis.pcall
('get'
,'mykey'
)
75 return {type
(foo
),foo
}
79 test
{EVAL
- Redis multi bulk
-> Lua type conversion
} {
85 local foo
= redis.pcall
('
lrange'
,'mylist'
,0,-1)
86 return {type
(foo
),foo
[1],foo
[2],foo
[3],# foo}
90 test
{EVAL
- Redis status reply
-> Lua type conversion
} {
92 local foo
= redis.pcall
('
set'
,'mykey'
,'myval'
)
93 return {type
(foo
),foo
['ok'
]}
97 test
{EVAL
- Redis
error reply
-> Lua type conversion
} {
100 local foo
= redis.pcall
('
incr'
,'mykey'
)
101 return {type
(foo
),foo
['err'
]}
103 } {table
{ERR value is not an integer or out of range
}}
105 test
{EVAL
- Redis nil bulk reply
-> Lua type conversion
} {
108 local foo
= redis.pcall
('get'
,'mykey'
)
109 return {type
(foo
),foo
== false
}
113 test
{EVAL
- Is Lua affecting the currently selected DB?
} {
114 r
set mykey
"this is DB 9"
116 r
set mykey
"this is DB 10"
117 r
eval {return redis.pcall
('get'
,'mykey'
)} 0
120 test
{EVAL
- Is Lua seleced DB retained?
} {
121 r
eval {return redis.pcall
('select'
,'
9'
)} 0
126 test
{EVAL
- Script can't run more than configured
time limit
} {
127 r config
set lua-time-limit
1
131 while true do i
=i
+1 end
138 test
{EVAL
- Scripts can't run certain commands
} {
140 catch {r
eval {return redis.pcall
('spop'
,'x'
)} 0} e
144 test
{EVAL
- Scripts can't run certain commands
} {
147 r
eval "redis.pcall('randomkey'); return redis.pcall('set','x','ciao')" 0
150 } {*not allowed
after*}
152 test
{EVAL
- No arguments to redis.call
/pcall is considered an
error} {
154 catch {r
eval {return redis.call
()} 0} e
158 test
{EVAL
- redis.call variant raises a Lua
error on Redis cmd
error (1)} {
161 r
eval "redis.call('nosuchcommand')" 0
166 test
{EVAL
- redis.call variant raises a Lua
error on Redis cmd
error (1)} {
169 r
eval "redis.call('get','a','b','c')" 0
174 test
{EVAL
- redis.call variant raises a Lua
error on Redis cmd
error (1)} {
178 r
eval "redis.call('lpush','foo','val')" 0
183 test
{SCRIPTING FLUSH
- is able to clear the scripts cache?
} {
185 set v
[r evalsha
9bd632c7d33e571e9f24556ebed26c3479a87129
0]
186 assert_equal
$v myval
189 catch {r evalsha
9bd632c7d33e571e9f24556ebed26c3479a87129
0} e
193 test
{SCRIPT EXISTS
- can detect already defined scripts?
} {
194 r
eval "return 1+1" 0
195 r script exists a27e7e8a43702b7046d4f6a7ccf5b60cef6b9bd9 a27e7e8a43702b7046d4f6a7ccf5b60cef6b9bda
198 test
{SCRIPT LOAD
- is able to register scripts in the scripting cache
} {
200 [r script
load "return 'loaded'"] \
201 [r evalsha b534286061d4b9e4026607613b95c06c06015ae8
0]
202 } {b534286061d4b9e4026607613b95c06c06015ae8 loaded
}
204 test
"In the context of Lua the output of random commands gets ordered" {
206 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
207 r
eval {return redis.call
('smembers'
,'myset'
)} 0
208 } {a aa aaa azz b c d e f g h i l m n o p q r s t u v z
}
210 test
"SORT is normally not alpha re-ordered for the scripting engine" {
212 r sadd myset
1 2 3 4 10
213 r
eval {return redis.call
('sort'
,'myset'
,'desc'
)} 0
216 test
"SORT BY <constant> output gets ordered for scripting" {
218 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
219 r
eval {return redis.call
('sort'
,'myset'
,'by'
,'_'
)} 0
220 } {a aa aaa azz b c d e f g h i l m n o p q r s t u v z
}
222 test
"SORT BY <constant> with GET gets ordered for scripting" {
225 r
eval {return redis.call
('sort'
,'myset'
,'by'
,'_'
,'get'
,'
#','get','_:*')} 0
228 test
"redis.sha1hex() implementation" {
229 list [r
eval {return redis.sha1hex
(''
)} 0] \
230 [r
eval {return redis.sha1hex
('Pizza
& Mandolino'
)} 0]
231 } {da39a3ee5e6b4b0d3255bfef95601890afd80709
74822d82031af7493c20eefa13bd07ec4fada82f
}
233 test
{Globals protection reading an undeclared
global variable} {
234 catch {r
eval {return a
} 0} e
236 } {*ERR
*attempted to access unexisting
global*}
238 test
{Globals protection setting an undeclared
global*} {
239 catch {r
eval {a
=10} 0} e
241 } {*ERR
*attempted to create
global*}
243 test
{Test an example script DECR_IF_GT
} {
247 current
= redis.call
('get'
,KEYS
[1])
248 if not current then
return nil end
249 if current
> ARGV
[1] then
250 return redis.call
('decr'
,KEYS
[1])
252 return redis.call
('get'
,KEYS
[1])
257 lappend res
[r
eval $decr_if_gt 1 foo
2]
258 lappend res
[r
eval $decr_if_gt 1 foo
2]
259 lappend res
[r
eval $decr_if_gt 1 foo
2]
260 lappend res
[r
eval $decr_if_gt 1 foo
2]
261 lappend res
[r
eval $decr_if_gt 1 foo
2]
265 test
{Scripting engine resets PRNG at every script execution
} {
266 set rand1
[r
eval {return tostring
(math.random
())} 0]
267 set rand2
[r
eval {return tostring
(math.random
())} 0]
268 assert_equal
$rand1 $rand2
271 test
{Scripting engine PRNG can be seeded correctly
} {
273 math.randomseed
(ARGV
[1]); return tostring
(math.random
())
276 math.randomseed
(ARGV
[1]); return tostring
(math.random
())
279 math.randomseed
(ARGV
[1]); return tostring
(math.random
())
281 assert_equal
$rand1 $rand2
282 assert
{$rand2 ne
$rand3}
286 # Start a new server since the last test in this stanza will kill the
288 start_server
{tags
{"scripting"}} {
289 test
{Timedout read-only scripts can be killed by SCRIPT KILL
} {
290 set rd
[redis_deferring_client
]
291 r config
set lua-time-limit
10
292 $rd eval {while true do end
} 0
295 assert_match
{BUSY
*} $e
297 assert_equal
[r ping
] "PONG"
300 test
{Timedout scripts that modified data can't be killed by SCRIPT KILL
} {
301 set rd
[redis_deferring_client
]
302 r config
set lua-time-limit
10
303 $rd eval {redis.call
('
set'
,'x'
,'y'
); while true do end
} 0
306 assert_match
{BUSY
*} $e
307 catch {r script kill
} e
308 assert_match
{UNKILLABLE
*} $e
310 assert_match
{BUSY
*} $e
313 test
{SHUTDOWN NOSAVE can kill a timedout script anyway
} {
314 # The server sould be still unresponding to normal commands.
316 assert_match
{BUSY
*} $e
317 catch {r shutdown nosave
}
318 # Make sure the server was killed
319 catch {set rd
[redis_deferring_client
]} e
320 assert_match
{*connection refused
*} $e
324 start_server
{tags
{"scripting repl"}} {
326 test
{Before the slave connects we issue an EVAL command
} {
327 r
eval {return redis.call
('
incr'
,'x'
)} 0
330 test
{Connect a slave to the main instance
} {
331 r
-1 slaveof
[srv
0 host
] [srv
0 port
]
332 wait_for_condition
50 100 {
333 [s
-1 role
] eq
{slave
} &&
334 [string match
{*master_link_status
:up
*} [r
-1 info replication
]]
336 fail
"Can't turn the instance into a slave"
340 test
{Now use EVALSHA against the master
} {
341 r evalsha ae3477e27be955de7e1bc9adfdca626b478d3cb2
0
344 test
{If EVALSHA was replicated as EVAL the slave should be ok
} {
345 wait_for_condition
50 100 {
348 fail
"Expected 2 in x, but value is '[r -1 get x]'"
352 test
{Replication of script multiple pushes to
list with BLPOP
} {
353 set rd
[redis_deferring_client
]
356 redis.call
("lpush","a","1");
357 redis.call
("lpush","a","2");
361 wait_for_condition
50 100 {
362 [r
-1 lrange a
0 -1] eq
[r
lrange a
0 -1]
364 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]'"