1start_server {tags {"scripting"}} {
2    test {EVAL - Does Lua interpreter replies to our requests?} {
3        r eval {return 'hello'} 0
4    } {hello}
5
6    test {EVAL - Lua integer -> Redis protocol type conversion} {
7        r eval {return 100.5} 0
8    } {100}
9
10    test {EVAL - Lua string -> Redis protocol type conversion} {
11        r eval {return 'hello world'} 0
12    } {hello world}
13
14    test {EVAL - Lua true boolean -> Redis protocol type conversion} {
15        r eval {return true} 0
16    } {1}
17
18    test {EVAL - Lua false boolean -> Redis protocol type conversion} {
19        r eval {return false} 0
20    } {}
21
22    test {EVAL - Lua status code reply -> Redis protocol type conversion} {
23        r eval {return {ok='fine'}} 0
24    } {fine}
25
26    test {EVAL - Lua error reply -> Redis protocol type conversion} {
27        catch {
28            r eval {return {err='this is an error'}} 0
29        } e
30        set _ $e
31    } {this is an error}
32
33    test {EVAL - Lua table -> Redis protocol type conversion} {
34        r eval {return {1,2,3,'ciao',{1,2}}} 0
35    } {1 2 3 ciao {1 2}}
36
37    test {EVAL - Are the KEYS and ARGV arrays populated correctly?} {
38        r eval {return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}} 2 a{t} b{t} c{t} d{t}
39    } {a{t} b{t} c{t} d{t}}
40
41    test {EVAL - is Lua able to call Redis API?} {
42        r set mykey myval
43        r eval {return redis.call('get',KEYS[1])} 1 mykey
44    } {myval}
45
46    test {EVALSHA - Can we call a SHA1 if already defined?} {
47        r evalsha fd758d1589d044dd850a6f05d52f2eefd27f033f 1 mykey
48    } {myval}
49
50    test {EVALSHA - Can we call a SHA1 in uppercase?} {
51        r evalsha FD758D1589D044DD850A6F05D52F2EEFD27F033F 1 mykey
52    } {myval}
53
54    test {EVALSHA - Do we get an error on invalid SHA1?} {
55        catch {r evalsha NotValidShaSUM 0} e
56        set _ $e
57    } {NOSCRIPT*}
58
59    test {EVALSHA - Do we get an error on non defined SHA1?} {
60        catch {r evalsha ffd632c7d33e571e9f24556ebed26c3479a87130 0} e
61        set _ $e
62    } {NOSCRIPT*}
63
64    test {EVAL - Redis integer -> Lua type conversion} {
65        r set x 0
66        r eval {
67            local foo = redis.pcall('incr',KEYS[1])
68            return {type(foo),foo}
69        } 1 x
70    } {number 1}
71
72    test {EVAL - Redis bulk -> Lua type conversion} {
73        r set mykey myval
74        r eval {
75            local foo = redis.pcall('get',KEYS[1])
76            return {type(foo),foo}
77        } 1 mykey
78    } {string myval}
79
80    test {EVAL - Redis multi bulk -> Lua type conversion} {
81        r del mylist
82        r rpush mylist a
83        r rpush mylist b
84        r rpush mylist c
85        r eval {
86            local foo = redis.pcall('lrange',KEYS[1],0,-1)
87            return {type(foo),foo[1],foo[2],foo[3],# foo}
88        } 1 mylist
89    } {table a b c 3}
90
91    test {EVAL - Redis status reply -> Lua type conversion} {
92        r eval {
93            local foo = redis.pcall('set',KEYS[1],'myval')
94            return {type(foo),foo['ok']}
95        } 1 mykey
96    } {table OK}
97
98    test {EVAL - Redis error reply -> Lua type conversion} {
99        r set mykey myval
100        r eval {
101            local foo = redis.pcall('incr',KEYS[1])
102            return {type(foo),foo['err']}
103        } 1 mykey
104    } {table {ERR value is not an integer or out of range}}
105
106    test {EVAL - Redis nil bulk reply -> Lua type conversion} {
107        r del mykey
108        r eval {
109            local foo = redis.pcall('get',KEYS[1])
110            return {type(foo),foo == false}
111        } 1 mykey
112    } {boolean 1}
113
114    test {EVAL - Is the Lua client using the currently selected DB?} {
115        r set mykey "this is DB 9"
116        r select 10
117        r set mykey "this is DB 10"
118        r eval {return redis.pcall('get',KEYS[1])} 1 mykey
119    } {this is DB 10} {singledb:skip}
120
121    test {EVAL - SELECT inside Lua should not affect the caller} {
122        # here we DB 10 is selected
123        r set mykey "original value"
124        r eval {return redis.pcall('select','9')} 0
125        set res [r get mykey]
126        r select 9
127        set res
128    } {original value} {singledb:skip}
129
130    if 0 {
131        test {EVAL - Script can't run more than configured time limit} {
132            r config set lua-time-limit 1
133            catch {
134                r eval {
135                    local i = 0
136                    while true do i=i+1 end
137                } 0
138            } e
139            set _ $e
140        } {*execution time*}
141    }
142
143    test {EVAL - Scripts can't run blpop command} {
144        set e {}
145        catch {r eval {return redis.pcall('blpop','x',0)} 0} e
146        set e
147    } {*not allowed*}
148
149    test {EVAL - Scripts can't run brpop command} {
150        set e {}
151        catch {r eval {return redis.pcall('brpop','empty_list',0)} 0} e
152        set e
153    } {*not allowed*}
154
155    test {EVAL - Scripts can't run brpoplpush command} {
156        set e {}
157        catch {r eval {return redis.pcall('brpoplpush','empty_list1', 'empty_list2',0)} 0} e
158        set e
159    } {*not allowed*}
160
161    test {EVAL - Scripts can't run blmove command} {
162        set e {}
163        catch {r eval {return redis.pcall('blmove','empty_list1', 'empty_list2', 'LEFT', 'LEFT', 0)} 0} e
164        set e
165    } {*not allowed*}
166
167    test {EVAL - Scripts can't run bzpopmin command} {
168        set e {}
169        catch {r eval {return redis.pcall('bzpopmin','empty_zset', 0)} 0} e
170        set e
171    } {*not allowed*}
172
173    test {EVAL - Scripts can't run bzpopmax command} {
174        set e {}
175        catch {r eval {return redis.pcall('bzpopmax','empty_zset', 0)} 0} e
176        set e
177    } {*not allowed*}
178
179    test {EVAL - Scripts can't run XREAD and XREADGROUP with BLOCK option} {
180        r del s
181        r xgroup create s g $ MKSTREAM
182        set res [r eval {return redis.pcall('xread','STREAMS','s','$')} 1 s]
183        assert {$res eq {}}
184        assert_error "*xread command is not allowed with BLOCK option from scripts" {r eval {return redis.pcall('xread','BLOCK',0,'STREAMS','s','$')} 1 s}
185        set res [r eval {return redis.pcall('xreadgroup','group','g','c','STREAMS','s','>')} 1 s]
186        assert {$res eq {}}
187        assert_error "*xreadgroup command is not allowed with BLOCK option from scripts" {r eval {return redis.pcall('xreadgroup','group','g','c','BLOCK',0,'STREAMS','s','>')} 1 s}
188    }
189
190    test {EVAL - Scripts can't run certain commands} {
191        set e {}
192        r debug lua-always-replicate-commands 0
193        catch {
194            r eval "redis.pcall('randomkey'); return redis.pcall('set','x','ciao')" 0
195        } e
196        r debug lua-always-replicate-commands 1
197        set e
198    } {*not allowed after*} {needs:debug}
199
200    test {EVAL - No arguments to redis.call/pcall is considered an error} {
201        set e {}
202        catch {r eval {return redis.call()} 0} e
203        set e
204    } {*one argument*}
205
206    test {EVAL - redis.call variant raises a Lua error on Redis cmd error (1)} {
207        set e {}
208        catch {
209            r eval "redis.call('nosuchcommand')" 0
210        } e
211        set e
212    } {*Unknown Redis*}
213
214    test {EVAL - redis.call variant raises a Lua error on Redis cmd error (1)} {
215        set e {}
216        catch {
217            r eval "redis.call('get','a','b','c')" 0
218        } e
219        set e
220    } {*number of args*}
221
222    test {EVAL - redis.call variant raises a Lua error on Redis cmd error (1)} {
223        set e {}
224        r set foo bar
225        catch {
226            r eval {redis.call('lpush',KEYS[1],'val')} 1 foo
227        } e
228        set e
229    } {*against a key*}
230
231    test {EVAL - JSON numeric decoding} {
232        # We must return the table as a string because otherwise
233        # Redis converts floats to ints and we get 0 and 1023 instead
234        # of 0.0003 and 1023.2 as the parsed output.
235        r eval {return
236                 table.concat(
237                   cjson.decode(
238                    "[0.0, -5e3, -1, 0.3e-3, 1023.2, 0e10]"), " ")
239        } 0
240    } {0 -5000 -1 0.0003 1023.2 0}
241
242    test {EVAL - JSON string decoding} {
243        r eval {local decoded = cjson.decode('{"keya": "a", "keyb": "b"}')
244                return {decoded.keya, decoded.keyb}
245        } 0
246    } {a b}
247
248    test {EVAL - cmsgpack can pack double?} {
249        r eval {local encoded = cmsgpack.pack(0.1)
250                local h = ""
251                for i = 1, #encoded do
252                    h = h .. string.format("%02x",string.byte(encoded,i))
253                end
254                return h
255        } 0
256    } {cb3fb999999999999a}
257
258    test {EVAL - cmsgpack can pack negative int64?} {
259        r eval {local encoded = cmsgpack.pack(-1099511627776)
260                local h = ""
261                for i = 1, #encoded do
262                    h = h .. string.format("%02x",string.byte(encoded,i))
263                end
264                return h
265        } 0
266    } {d3ffffff0000000000}
267
268    test {EVAL - cmsgpack can pack and unpack circular references?} {
269        r eval {local a = {x=nil,y=5}
270                local b = {x=a}
271                a['x'] = b
272                local encoded = cmsgpack.pack(a)
273                local h = ""
274                -- cmsgpack encodes to a depth of 16, but can't encode
275                -- references, so the encoded object has a deep copy recursive
276                -- depth of 16.
277                for i = 1, #encoded do
278                    h = h .. string.format("%02x",string.byte(encoded,i))
279                end
280                -- when unpacked, re.x.x != re because the unpack creates
281                -- individual tables down to a depth of 16.
282                -- (that's why the encoded output is so large)
283                local re = cmsgpack.unpack(encoded)
284                assert(re)
285                assert(re.x)
286                assert(re.x.x.y == re.y)
287                assert(re.x.x.x.x.y == re.y)
288                assert(re.x.x.x.x.x.x.y == re.y)
289                assert(re.x.x.x.x.x.x.x.x.x.x.y == re.y)
290                -- maximum working depth:
291                assert(re.x.x.x.x.x.x.x.x.x.x.x.x.x.x.y == re.y)
292                -- now the last x would be b above and has no y
293                assert(re.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x)
294                -- so, the final x.x is at the depth limit and was assigned nil
295                assert(re.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x == nil)
296                return {h, re.x.x.x.x.x.x.x.x.y == re.y, re.y == 5}
297        } 0
298    } {82a17905a17881a17882a17905a17881a17882a17905a17881a17882a17905a17881a17882a17905a17881a17882a17905a17881a17882a17905a17881a17882a17905a17881a178c0 1 1}
299
300    test {EVAL - Numerical sanity check from bitop} {
301        r eval {assert(0x7fffffff == 2147483647, "broken hex literals");
302                assert(0xffffffff == -1 or 0xffffffff == 2^32-1,
303                    "broken hex literals");
304                assert(tostring(-1) == "-1", "broken tostring()");
305                assert(tostring(0xffffffff) == "-1" or
306                    tostring(0xffffffff) == "4294967295",
307                    "broken tostring()")
308        } 0
309    } {}
310
311    test {EVAL - Verify minimal bitop functionality} {
312        r eval {assert(bit.tobit(1) == 1);
313                assert(bit.band(1) == 1);
314                assert(bit.bxor(1,2) == 3);
315                assert(bit.bor(1,2,4,8,16,32,64,128) == 255)
316        } 0
317    } {}
318
319    test {EVAL - Able to parse trailing comments} {
320        r eval {return 'hello' --trailing comment} 0
321    } {hello}
322
323    test {EVAL_RO - Successful case} {
324        r set foo bar
325        assert_equal bar [r eval_ro {return redis.call('get', KEYS[1]);} 1 foo]
326    }
327
328    test {EVAL_RO - Cannot run write commands} {
329        r set foo bar
330        catch {r eval_ro {redis.call('del', KEYS[1]);} 1 foo} e
331        set e
332    } {*Write commands are not allowed from read-only scripts*}
333
334    test {SCRIPTING FLUSH - is able to clear the scripts cache?} {
335        r set mykey myval
336        set v [r evalsha fd758d1589d044dd850a6f05d52f2eefd27f033f 1 mykey]
337        assert_equal $v myval
338        set e ""
339        r script flush
340        catch {r evalsha fd758d1589d044dd850a6f05d52f2eefd27f033f 1 mykey} e
341        set e
342    } {NOSCRIPT*}
343
344    test {SCRIPTING FLUSH ASYNC} {
345        for {set j 0} {$j < 100} {incr j} {
346            r script load "return $j"
347        }
348        assert { [string match "*number_of_cached_scripts:100*" [r info Memory]] }
349        r script flush async
350        assert { [string match "*number_of_cached_scripts:0*" [r info Memory]] }
351    }
352
353    test {SCRIPT EXISTS - can detect already defined scripts?} {
354        r eval "return 1+1" 0
355        r script exists a27e7e8a43702b7046d4f6a7ccf5b60cef6b9bd9 a27e7e8a43702b7046d4f6a7ccf5b60cef6b9bda
356    } {1 0}
357
358    test {SCRIPT LOAD - is able to register scripts in the scripting cache} {
359        list \
360            [r script load "return 'loaded'"] \
361            [r evalsha b534286061d4b9e4026607613b95c06c06015ae8 0]
362    } {b534286061d4b9e4026607613b95c06c06015ae8 loaded}
363
364    test "In the context of Lua the output of random commands gets ordered" {
365        r debug lua-always-replicate-commands 0
366        r del myset
367        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
368        set res [r eval {return redis.call('smembers',KEYS[1])} 1 myset]
369        r debug lua-always-replicate-commands 1
370        set res
371    } {a aa aaa azz b c d e f g h i l m n o p q r s t u v z} {needs:debug}
372
373    test "SORT is normally not alpha re-ordered for the scripting engine" {
374        r del myset
375        r sadd myset 1 2 3 4 10
376        r eval {return redis.call('sort',KEYS[1],'desc')} 1 myset
377    } {10 4 3 2 1} {cluster:skip}
378
379    test "SORT BY <constant> output gets ordered for scripting" {
380        r del myset
381        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
382        r eval {return redis.call('sort',KEYS[1],'by','_')} 1 myset
383    } {a aa aaa azz b c d e f g h i l m n o p q r s t u v z} {cluster:skip}
384
385    test "SORT BY <constant> with GET gets ordered for scripting" {
386        r del myset
387        r sadd myset a b c
388        r eval {return redis.call('sort',KEYS[1],'by','_','get','#','get','_:*')} 1 myset
389    } {a {} b {} c {}} {cluster:skip}
390
391    test "redis.sha1hex() implementation" {
392        list [r eval {return redis.sha1hex('')} 0] \
393             [r eval {return redis.sha1hex('Pizza & Mandolino')} 0]
394    } {da39a3ee5e6b4b0d3255bfef95601890afd80709 74822d82031af7493c20eefa13bd07ec4fada82f}
395
396    test {Globals protection reading an undeclared global variable} {
397        catch {r eval {return a} 0} e
398        set e
399    } {*ERR*attempted to access * global*}
400
401    test {Globals protection setting an undeclared global*} {
402        catch {r eval {a=10} 0} e
403        set e
404    } {*ERR*attempted to create global*}
405
406    test {Test an example script DECR_IF_GT} {
407        set decr_if_gt {
408            local current
409
410            current = redis.call('get',KEYS[1])
411            if not current then return nil end
412            if current > ARGV[1] then
413                return redis.call('decr',KEYS[1])
414            else
415                return redis.call('get',KEYS[1])
416            end
417        }
418        r set foo 5
419        set res {}
420        lappend res [r eval $decr_if_gt 1 foo 2]
421        lappend res [r eval $decr_if_gt 1 foo 2]
422        lappend res [r eval $decr_if_gt 1 foo 2]
423        lappend res [r eval $decr_if_gt 1 foo 2]
424        lappend res [r eval $decr_if_gt 1 foo 2]
425        set res
426    } {4 3 2 2 2}
427
428    test {Scripting engine resets PRNG at every script execution} {
429        set rand1 [r eval {return tostring(math.random())} 0]
430        set rand2 [r eval {return tostring(math.random())} 0]
431        assert_equal $rand1 $rand2
432    }
433
434    test {Scripting engine PRNG can be seeded correctly} {
435        set rand1 [r eval {
436            math.randomseed(ARGV[1]); return tostring(math.random())
437        } 0 10]
438        set rand2 [r eval {
439            math.randomseed(ARGV[1]); return tostring(math.random())
440        } 0 10]
441        set rand3 [r eval {
442            math.randomseed(ARGV[1]); return tostring(math.random())
443        } 0 20]
444        assert_equal $rand1 $rand2
445        assert {$rand2 ne $rand3}
446    }
447
448    test {EVAL does not leak in the Lua stack} {
449        r set x 0
450        # Use a non blocking client to speedup the loop.
451        set rd [redis_deferring_client]
452        for {set j 0} {$j < 10000} {incr j} {
453            $rd eval {return redis.call("incr",KEYS[1])} 1 x
454        }
455        for {set j 0} {$j < 10000} {incr j} {
456            $rd read
457        }
458        assert {[s used_memory_lua] < 1024*100}
459        $rd close
460        r get x
461    } {10000}
462
463    test {EVAL processes writes from AOF in read-only slaves} {
464        r flushall
465        r config set appendonly yes
466        r config set aof-use-rdb-preamble no
467        r eval {redis.call("set",KEYS[1],"100")} 1 foo
468        r eval {redis.call("incr",KEYS[1])} 1 foo
469        r eval {redis.call("incr",KEYS[1])} 1 foo
470        wait_for_condition 50 100 {
471            [s aof_rewrite_in_progress] == 0
472        } else {
473            fail "AOF rewrite can't complete after CONFIG SET appendonly yes."
474        }
475        r config set slave-read-only yes
476        r slaveof 127.0.0.1 0
477        r debug loadaof
478        set res [r get foo]
479        r slaveof no one
480        r config set aof-use-rdb-preamble yes
481        set res
482    } {102} {external:skip}
483
484    test {EVAL timeout from AOF} {
485        # generate a long running script that is propagated to the AOF as script
486        # make sure that the script times out during loading
487        r config set appendonly no
488        r config set aof-use-rdb-preamble no
489        r config set lua-replicate-commands no
490        r flushall
491        r config set appendonly yes
492        wait_for_condition 50 100 {
493            [s aof_rewrite_in_progress] == 0
494        } else {
495            fail "AOF rewrite can't complete after CONFIG SET appendonly yes."
496        }
497        r config set lua-time-limit 1
498        set rd [redis_deferring_client]
499        set start [clock clicks -milliseconds]
500        $rd eval {redis.call('set',KEYS[1],'y'); for i=1,1500000 do redis.call('ping') end return 'ok'} 1 x
501        $rd flush
502        after 100
503        catch {r ping} err
504        assert_match {BUSY*} $err
505        $rd read
506        set elapsed [expr [clock clicks -milliseconds]-$start]
507        if {$::verbose} { puts "script took $elapsed milliseconds" }
508        set start [clock clicks -milliseconds]
509        $rd debug loadaof
510        $rd flush
511        after 100
512        catch {r ping} err
513        assert_match {LOADING*} $err
514        $rd read
515        set elapsed [expr [clock clicks -milliseconds]-$start]
516        if {$::verbose} { puts "loading took $elapsed milliseconds" }
517        $rd close
518        r get x
519    } {y} {external:skip}
520
521    test {We can call scripts rewriting client->argv from Lua} {
522        r del myset
523        r sadd myset a b c
524        r mset a{t} 1 b{t} 2 c{t} 3 d{t} 4
525        assert {[r spop myset] ne {}}
526        assert {[r spop myset 1] ne {}}
527        assert {[r spop myset] ne {}}
528        assert {[r mget a{t} b{t} c{t} d{t}] eq {1 2 3 4}}
529        assert {[r spop myset] eq {}}
530    }
531
532    test {Call Redis command with many args from Lua (issue #1764)} {
533        r eval {
534            local i
535            local x={}
536            redis.call('del','mylist')
537            for i=1,100 do
538                table.insert(x,i)
539            end
540            redis.call('rpush','mylist',unpack(x))
541            return redis.call('lrange','mylist',0,-1)
542        } 1 mylist
543    } {1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100}
544
545    test {Number conversion precision test (issue #1118)} {
546        r eval {
547              local value = 9007199254740991
548              redis.call("set","foo",value)
549              return redis.call("get","foo")
550        } 1 foo
551    } {9007199254740991}
552
553    test {String containing number precision test (regression of issue #1118)} {
554        r eval {
555            redis.call("set", "key", "12039611435714932082")
556            return redis.call("get", "key")
557        } 1 key
558    } {12039611435714932082}
559
560    test {Verify negative arg count is error instead of crash (issue #1842)} {
561        catch { r eval { return "hello" } -12 } e
562        set e
563    } {ERR Number of keys can't be negative}
564
565    test {Correct handling of reused argv (issue #1939)} {
566        r eval {
567              for i = 0, 10 do
568                  redis.call('SET', 'a{t}', '1')
569                  redis.call('MGET', 'a{t}', 'b{t}', 'c{t}')
570                  redis.call('EXPIRE', 'a{t}', 0)
571                  redis.call('GET', 'a{t}')
572                  redis.call('MGET', 'a{t}', 'b{t}', 'c{t}')
573              end
574        } 3 a{t} b{t} c{t}
575    }
576
577    test {Functions in the Redis namespace are able to report errors} {
578        catch {
579            r eval {
580                  redis.sha1hex()
581            } 0
582        } e
583        set e
584    } {*wrong number*}
585
586    test {Script with RESP3 map} {
587        set expected_dict [dict create field value]
588        set expected_list [list field value]
589
590        # Sanity test for RESP3 without scripts
591        r HELLO 3
592        r hset hash field value
593        set res [r hgetall hash]
594        assert_equal $res $expected_dict
595
596        # Test RESP3 client with script in both RESP2 and RESP3 modes
597        set res [r eval {redis.setresp(3); return redis.call('hgetall', KEYS[1])} 1 hash]
598        assert_equal $res $expected_dict
599        set res [r eval {redis.setresp(2); return redis.call('hgetall', KEYS[1])} 1 hash]
600        assert_equal $res $expected_list
601
602        # Test RESP2 client with script in both RESP2 and RESP3 modes
603        r HELLO 2
604        set res [r eval {redis.setresp(3); return redis.call('hgetall', KEYS[1])} 1 hash]
605        assert_equal $res $expected_list
606        set res [r eval {redis.setresp(2); return redis.call('hgetall', KEYS[1])} 1 hash]
607        assert_equal $res $expected_list
608    }
609
610    test {Script return recursive object} {
611        r readraw 1
612        set res [r eval {local a = {}; local b = {a}; a[1] = b; return a} 0]
613        # drain the response
614        while {true} {
615            if {$res == "-ERR reached lua stack limit"} {
616                break
617            }
618            assert_equal $res "*1"
619            set res [r read]
620        }
621        r readraw 0
622        # make sure the connection is still valid
623        assert_equal [r ping] {PONG}
624    }
625
626    test {Script check unpack with massive arguments} {
627        r eval {
628            local a = {}
629            for i=1,7999 do
630                a[i] = 1
631            end
632            return redis.call("lpush", "l", unpack(a))
633        } 0
634    } {7999}
635}
636
637# Start a new server since the last test in this stanza will kill the
638# instance at all.
639start_server {tags {"scripting"}} {
640    test {Timedout read-only scripts can be killed by SCRIPT KILL} {
641        set rd [redis_deferring_client]
642        r config set lua-time-limit 10
643        $rd eval {while true do end} 0
644        after 200
645        catch {r ping} e
646        assert_match {BUSY*} $e
647        r script kill
648        after 200 ; # Give some time to Lua to call the hook again...
649        assert_equal [r ping] "PONG"
650        $rd close
651    }
652
653    test {Timedout read-only scripts can be killed by SCRIPT KILL even when use pcall} {
654        set rd [redis_deferring_client]
655        r config set lua-time-limit 10
656        $rd eval {local f = function() while 1 do redis.call('ping') end end while 1 do pcall(f) end} 0
657
658        wait_for_condition 50 100 {
659            [catch {r ping} e] == 1
660        } else {
661            fail "Can't wait for script to start running"
662        }
663        catch {r ping} e
664        assert_match {BUSY*} $e
665
666        r script kill
667
668        wait_for_condition 50 100 {
669            [catch {r ping} e] == 0
670        } else {
671            fail "Can't wait for script to be killed"
672        }
673        assert_equal [r ping] "PONG"
674
675        catch {$rd read} res
676        $rd close
677
678        assert_match {*killed by user*} $res
679    }
680
681    test {Timedout script does not cause a false dead client} {
682        set rd [redis_deferring_client]
683        r config set lua-time-limit 10
684
685        # senging (in a pipeline):
686        # 1. eval "while 1 do redis.call('ping') end" 0
687        # 2. ping
688        set buf "*3\r\n\$4\r\neval\r\n\$33\r\nwhile 1 do redis.call('ping') end\r\n\$1\r\n0\r\n"
689        append buf "*1\r\n\$4\r\nping\r\n"
690        $rd write $buf
691        $rd flush
692
693        wait_for_condition 50 100 {
694            [catch {r ping} e] == 1
695        } else {
696            fail "Can't wait for script to start running"
697        }
698        catch {r ping} e
699        assert_match {BUSY*} $e
700
701        r script kill
702        wait_for_condition 50 100 {
703            [catch {r ping} e] == 0
704        } else {
705            fail "Can't wait for script to be killed"
706        }
707        assert_equal [r ping] "PONG"
708
709        catch {$rd read} res
710        assert_match {*killed by user*} $res
711
712        set res [$rd read]
713        assert_match {*PONG*} $res
714
715        $rd close
716    }
717
718    test {Timedout script link is still usable after Lua returns} {
719        r config set lua-time-limit 10
720        r eval {for i=1,100000 do redis.call('ping') end return 'ok'} 0
721        r ping
722    } {PONG}
723
724    test {Timedout scripts that modified data can't be killed by SCRIPT KILL} {
725        set rd [redis_deferring_client]
726        r config set lua-time-limit 10
727        $rd eval {redis.call('set',KEYS[1],'y'); while true do end} 1 x
728        after 200
729        catch {r ping} e
730        assert_match {BUSY*} $e
731        catch {r script kill} e
732        assert_match {UNKILLABLE*} $e
733        catch {r ping} e
734        assert_match {BUSY*} $e
735    } {} {external:skip}
736
737    # Note: keep this test at the end of this server stanza because it
738    # kills the server.
739    test {SHUTDOWN NOSAVE can kill a timedout script anyway} {
740        # The server should be still unresponding to normal commands.
741        catch {r ping} e
742        assert_match {BUSY*} $e
743        catch {r shutdown nosave}
744        # Make sure the server was killed
745        catch {set rd [redis_deferring_client]} e
746        assert_match {*connection refused*} $e
747    } {} {external:skip}
748}
749
750foreach cmdrepl {0 1} {
751    start_server {tags {"scripting repl needs:debug external:skip"}} {
752        start_server {} {
753            if {$cmdrepl == 1} {
754                set rt "(commands replication)"
755            } else {
756                set rt "(scripts replication)"
757                r debug lua-always-replicate-commands 1
758            }
759
760            test "Before the replica connects we issue two EVAL commands $rt" {
761                # One with an error, but still executing a command.
762                # SHA is: 67164fc43fa971f76fd1aaeeaf60c1c178d25876
763                catch {
764                    r eval {redis.call('incr',KEYS[1]); redis.call('nonexisting')} 1 x
765                }
766                # One command is correct:
767                # SHA is: 6f5ade10a69975e903c6d07b10ea44c6382381a5
768                r eval {return redis.call('incr',KEYS[1])} 1 x
769            } {2}
770
771            test "Connect a replica to the master instance $rt" {
772                r -1 slaveof [srv 0 host] [srv 0 port]
773                wait_for_condition 50 100 {
774                    [s -1 role] eq {slave} &&
775                    [string match {*master_link_status:up*} [r -1 info replication]]
776                } else {
777                    fail "Can't turn the instance into a replica"
778                }
779            }
780
781            test "Now use EVALSHA against the master, with both SHAs $rt" {
782                # The server should replicate successful and unsuccessful
783                # commands as EVAL instead of EVALSHA.
784                catch {
785                    r evalsha 67164fc43fa971f76fd1aaeeaf60c1c178d25876 1 x
786                }
787                r evalsha 6f5ade10a69975e903c6d07b10ea44c6382381a5 1 x
788            } {4}
789
790            test "If EVALSHA was replicated as EVAL, 'x' should be '4' $rt" {
791                wait_for_condition 50 100 {
792                    [r -1 get x] eq {4}
793                } else {
794                    fail "Expected 4 in x, but value is '[r -1 get x]'"
795                }
796            }
797
798            test "Replication of script multiple pushes to list with BLPOP $rt" {
799                set rd [redis_deferring_client]
800                $rd brpop a 0
801                r eval {
802                    redis.call("lpush",KEYS[1],"1");
803                    redis.call("lpush",KEYS[1],"2");
804                } 1 a
805                set res [$rd read]
806                $rd close
807                wait_for_condition 50 100 {
808                    [r -1 lrange a 0 -1] eq [r lrange a 0 -1]
809                } else {
810                    fail "Expected list 'a' in replica and master to be the same, but they are respectively '[r -1 lrange a 0 -1]' and '[r lrange a 0 -1]'"
811                }
812                set res
813            } {a 1}
814
815            test "EVALSHA replication when first call is readonly $rt" {
816                r del x
817                r eval {if tonumber(ARGV[1]) > 0 then redis.call('incr', KEYS[1]) end} 1 x 0
818                r evalsha 6e0e2745aa546d0b50b801a20983b70710aef3ce 1 x 0
819                r evalsha 6e0e2745aa546d0b50b801a20983b70710aef3ce 1 x 1
820                wait_for_condition 50 100 {
821                    [r -1 get x] eq {1}
822                } else {
823                    fail "Expected 1 in x, but value is '[r -1 get x]'"
824                }
825            }
826
827            test "Lua scripts using SELECT are replicated correctly $rt" {
828                r eval {
829                    redis.call("set","foo1","bar1")
830                    redis.call("select","10")
831                    redis.call("incr","x")
832                    redis.call("select","11")
833                    redis.call("incr","z")
834                } 0
835                r eval {
836                    redis.call("set","foo1","bar1")
837                    redis.call("select","10")
838                    redis.call("incr","x")
839                    redis.call("select","11")
840                    redis.call("incr","z")
841                } 0
842                wait_for_condition 50 100 {
843                    [r -1 debug digest] eq [r debug digest]
844                } else {
845                    fail "Master-Replica desync after Lua script using SELECT."
846                }
847            } {} {singledb:skip}
848        }
849    }
850}
851
852start_server {tags {"scripting repl external:skip"}} {
853    start_server {overrides {appendonly yes aof-use-rdb-preamble no}} {
854        test "Connect a replica to the master instance" {
855            r -1 slaveof [srv 0 host] [srv 0 port]
856            wait_for_condition 50 100 {
857                [s -1 role] eq {slave} &&
858                [string match {*master_link_status:up*} [r -1 info replication]]
859            } else {
860                fail "Can't turn the instance into a replica"
861            }
862        }
863
864        test "Redis.replicate_commands() must be issued before any write" {
865            r eval {
866                redis.call('set','foo','bar');
867                return redis.replicate_commands();
868            } 0
869        } {}
870
871        test "Redis.replicate_commands() must be issued before any write (2)" {
872            r eval {
873                return redis.replicate_commands();
874            } 0
875        } {1}
876
877        test "Redis.set_repl() must be issued after replicate_commands()" {
878            r debug lua-always-replicate-commands 0
879            catch {
880                r eval {
881                    redis.set_repl(redis.REPL_ALL);
882                } 0
883            } e
884            r debug lua-always-replicate-commands 1
885            set e
886        } {*only after turning on*}
887
888        test "Redis.set_repl() don't accept invalid values" {
889            catch {
890                r eval {
891                    redis.replicate_commands();
892                    redis.set_repl(12345);
893                } 0
894            } e
895            set e
896        } {*Invalid*flags*}
897
898        test "Test selective replication of certain Redis commands from Lua" {
899            r del a b c d
900            r eval {
901                redis.replicate_commands();
902                redis.call('set','a','1');
903                redis.set_repl(redis.REPL_NONE);
904                redis.call('set','b','2');
905                redis.set_repl(redis.REPL_AOF);
906                redis.call('set','c','3');
907                redis.set_repl(redis.REPL_ALL);
908                redis.call('set','d','4');
909            } 0
910
911            wait_for_condition 50 100 {
912                [r -1 mget a b c d] eq {1 {} {} 4}
913            } else {
914                fail "Only a and c should be replicated to replica"
915            }
916
917            # Master should have everything right now
918            assert {[r mget a b c d] eq {1 2 3 4}}
919
920            # After an AOF reload only a, c and d should exist
921            r debug loadaof
922
923            assert {[r mget a b c d] eq {1 {} 3 4}}
924        }
925
926        test "PRNG is seeded randomly for command replication" {
927            set a [
928                r eval {
929                    redis.replicate_commands();
930                    return math.random()*100000;
931                } 0
932            ]
933            set b [
934                r eval {
935                    redis.replicate_commands();
936                    return math.random()*100000;
937                } 0
938            ]
939            assert {$a ne $b}
940        }
941
942        test "Using side effects is not a problem with command replication" {
943            r eval {
944                redis.replicate_commands();
945                redis.call('set','time',redis.call('time')[1])
946            } 0
947
948            assert {[r get time] ne {}}
949
950            wait_for_condition 50 100 {
951                [r get time] eq [r -1 get time]
952            } else {
953                fail "Time key does not match between master and replica"
954            }
955        }
956    }
957}
958
959start_server {tags {"scripting external:skip"}} {
960    r script debug sync
961    r eval {return 'hello'} 0
962    r eval {return 'hello'} 0
963}
964
965start_server {tags {"scripting needs:debug external:skip"}} {
966    test {Test scripting debug protocol parsing} {
967        r script debug sync
968        r eval {return 'hello'} 0
969        catch {r 'hello\0world'} e
970        assert_match {*Unknown Redis Lua debugger command*} $e
971        catch {r 'hello\0'} e
972        assert_match {*Unknown Redis Lua debugger command*} $e
973        catch {r '\0hello'} e
974        assert_match {*Unknown Redis Lua debugger command*} $e
975        catch {r '\0hello\0'} e
976        assert_match {*Unknown Redis Lua debugger command*} $e
977    }
978
979    test {Test scripting debug lua stack overflow} {
980        r script debug sync
981        r eval {return 'hello'} 0
982        set cmd "*101\r\n\$5\r\nredis\r\n"
983        append cmd [string repeat "\$4\r\ntest\r\n" 100]
984        r write $cmd
985        r flush
986        set ret [r read]
987        assert_match {*Unknown Redis command called from Lua script*} $ret
988        # make sure the server is still ok
989        reconnect
990        assert_equal [r ping] {PONG}
991    }
992}
993
994start_server {tags {"scripting resp3 needs:debug"}} {
995    r debug set-disable-deny-scripts 1
996    for {set i 2} {$i <= 3} {incr i} {
997        for {set client_proto 2} {$client_proto <= 3} {incr client_proto} {
998            r hello $client_proto
999            r readraw 1
1000
1001            test {test resp3 big number protocol parsing} {
1002                set ret [r eval "redis.setresp($i);return redis.call('debug', 'protocol', 'bignum')" 0]
1003                if {$client_proto == 2 || $i == 2} {
1004                    # if either Lua or the clien is RESP2 the reply will be RESP2
1005                    assert_equal $ret {$37}
1006                    assert_equal [r read] {1234567999999999999999999999999999999}
1007                } else {
1008                    assert_equal $ret {(1234567999999999999999999999999999999}
1009                }
1010            }
1011
1012            test {test resp3 malformed big number protocol parsing} {
1013                set ret [r eval "return {big_number='123\\r\\n123'}" 0]
1014                if {$client_proto == 2} {
1015                    # if either Lua or the clien is RESP2 the reply will be RESP2
1016                    assert_equal $ret {$8}
1017                    assert_equal [r read] {123  123}
1018                } else {
1019                    assert_equal $ret {(123  123}
1020                }
1021            }
1022
1023            test {test resp3 map protocol parsing} {
1024                set ret [r eval "redis.setresp($i);return redis.call('debug', 'protocol', 'map')" 0]
1025                if {$client_proto == 2 || $i == 2} {
1026                    # if either Lua or the clien is RESP2 the reply will be RESP2
1027                    assert_equal $ret {*6}
1028                } else {
1029                    assert_equal $ret {%3}
1030                }
1031                for {set j 0} {$j < 6} {incr j} {
1032                    r read
1033                }
1034            }
1035
1036            test {test resp3 set protocol parsing} {
1037                set ret [r eval "redis.setresp($i);return redis.call('debug', 'protocol', 'set')" 0]
1038                if {$client_proto == 2 || $i == 2} {
1039                    # if either Lua or the clien is RESP2 the reply will be RESP2
1040                    assert_equal $ret {*3}
1041                } else {
1042                    assert_equal $ret {~3}
1043                }
1044                for {set j 0} {$j < 3} {incr j} {
1045                    r read
1046                }
1047            }
1048
1049            test {test resp3 double protocol parsing} {
1050                set ret [r eval "redis.setresp($i);return redis.call('debug', 'protocol', 'double')" 0]
1051                if {$client_proto == 2 || $i == 2} {
1052                    # if either Lua or the clien is RESP2 the reply will be RESP2
1053                    assert_equal $ret {$5}
1054                    assert_equal [r read] {3.141}
1055                } else {
1056                    assert_equal $ret {,3.141}
1057                }
1058            }
1059
1060            test {test resp3 null protocol parsing} {
1061                set ret [r eval "redis.setresp($i);return redis.call('debug', 'protocol', 'null')" 0]
1062                if {$client_proto == 2} {
1063                    # null is a special case in which a Lua client format does not effect the reply to the client
1064                    assert_equal $ret {$-1}
1065                } else {
1066                    assert_equal $ret {_}
1067                }
1068            } {}
1069
1070            test {test resp3 verbatim protocol parsing} {
1071                set ret [r eval "redis.setresp($i);return redis.call('debug', 'protocol', 'verbatim')" 0]
1072                if {$client_proto == 2 || $i == 2} {
1073                    # if either Lua or the clien is RESP2 the reply will be RESP2
1074                    assert_equal $ret {$25}
1075                    assert_equal [r read] {This is a verbatim}
1076                    assert_equal [r read] {string}
1077                } else {
1078                    assert_equal $ret {=29}
1079                    assert_equal [r read] {txt:This is a verbatim}
1080                    assert_equal [r read] {string}
1081                }
1082            }
1083
1084            test {test resp3 true protocol parsing} {
1085                set ret [r eval "redis.setresp($i);return redis.call('debug', 'protocol', 'true')" 0]
1086                if {$client_proto == 2 || $i == 2} {
1087                    # if either Lua or the clien is RESP2 the reply will be RESP2
1088                    assert_equal $ret {:1}
1089                } else {
1090                    assert_equal $ret {#t}
1091                }
1092            }
1093
1094            test {test resp3 false protocol parsing} {
1095                set ret [r eval "redis.setresp($i);return redis.call('debug', 'protocol', 'false')" 0]
1096                if {$client_proto == 2 || $i == 2} {
1097                    # if either Lua or the clien is RESP2 the reply will be RESP2
1098                    assert_equal $ret {:0}
1099                } else {
1100                    assert_equal $ret {#f}
1101                }
1102            }
1103
1104            r readraw 0
1105        }
1106    }
1107
1108    # attribute is not relevant to test with resp2
1109    test {test resp3 attribute protocol parsing} {
1110        # attributes are not (yet) expose to the script
1111        # So here we just check the parser handles them and they are ignored.
1112        r eval "redis.setresp(3);return redis.call('debug', 'protocol', 'attrib')" 0
1113    } {Some real reply following the attribute}
1114
1115    r debug set-disable-deny-scripts 0
1116}
1117