xref: /redis-3.2.3/tests/unit/scripting.tcl (revision f2305046)
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 ARGS arrays populated correctly?} {
38        r eval {return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}} 2 a b c d
39    } {a b c d}
40
41    test {EVAL - is Lua able to call Redis API?} {
42        r set mykey myval
43        r eval {return redis.call('get','mykey')} 0
44    } {myval}
45
46    test {EVALSHA - Can we call a SHA1 if already defined?} {
47        r evalsha 9bd632c7d33e571e9f24556ebed26c3479a87129 0
48    } {myval}
49
50    test {EVALSHA - Do we get an error on invalid SHA1?} {
51        catch {r evalsha NotValidShaSUM 0} e
52        set _ $e
53    } {NOSCRIPT*}
54
55    test {EVALSHA - Do we get an error on non defined SHA1?} {
56        catch {r evalsha ffd632c7d33e571e9f24556ebed26c3479a87130 0} e
57        set _ $e
58    } {NOSCRIPT*}
59
60    test {EVAL - Redis integer -> Lua type conversion} {
61        r eval {
62            local foo = redis.pcall('incr','x')
63            return {type(foo),foo}
64        } 0
65    } {number 1}
66
67    test {EVAL - Redis bulk -> Lua type conversion} {
68        r set mykey myval
69        r eval {
70            local foo = redis.pcall('get','mykey')
71            return {type(foo),foo}
72        } 0
73    } {string myval}
74
75    test {EVAL - Redis multi bulk -> Lua type conversion} {
76        r del mylist
77        r rpush mylist a
78        r rpush mylist b
79        r rpush mylist c
80        r eval {
81            local foo = redis.pcall('lrange','mylist',0,-1)
82            return {type(foo),foo[1],foo[2],foo[3],# foo}
83        } 0
84    } {table a b c 3}
85
86    test {EVAL - Redis status reply -> Lua type conversion} {
87        r eval {
88            local foo = redis.pcall('set','mykey','myval')
89            return {type(foo),foo['ok']}
90        } 0
91    } {table OK}
92
93    test {EVAL - Redis error reply -> Lua type conversion} {
94        r set mykey myval
95        r eval {
96            local foo = redis.pcall('incr','mykey')
97            return {type(foo),foo['err']}
98        } 0
99    } {table {ERR value is not an integer or out of range}}
100
101    test {EVAL - Redis nil bulk reply -> Lua type conversion} {
102        r del mykey
103        r eval {
104            local foo = redis.pcall('get','mykey')
105            return {type(foo),foo == false}
106        } 0
107    } {boolean 1}
108
109    test {EVAL - Is Lua affecting the currently selected DB?} {
110        r set mykey "this is DB 9"
111        r select 10
112        r set mykey "this is DB 10"
113        r eval {return redis.pcall('get','mykey')} 0
114    } {this is DB 10}
115
116    test {EVAL - Is Lua seleced DB retained?} {
117        r eval {return redis.pcall('select','9')} 0
118        r get mykey
119    } {this is DB 9}
120
121    if 0 {
122        test {EVAL - Script can't run more than configured time limit} {
123            r config set lua-time-limit 1
124            catch {
125                r eval {
126                    local i = 0
127                    while true do i=i+1 end
128                } 0
129            } e
130            set _ $e
131        } {*execution time*}
132    }
133
134    test {EVAL - Scripts can't run certain commands} {
135        set e {}
136        catch {r eval {return redis.pcall('spop','x')} 0} e
137        set e
138    } {*not allowed*}
139
140    test {EVAL - Scripts can't run certain commands} {
141        set e {}
142        catch {
143            r eval "redis.pcall('randomkey'); return redis.pcall('set','x','ciao')" 0
144        } e
145        set e
146    } {*not allowed after*}
147
148    test {EVAL - redis.call variant raises a Lua error on Redis cmd error (1)} {
149        set e {}
150        catch {
151            r eval "redis.call('nosuchcommand')" 0
152        } e
153        set e
154    } {*Unknown Redis*}
155
156    test {EVAL - redis.call variant raises a Lua error on Redis cmd error (1)} {
157        set e {}
158        catch {
159            r eval "redis.call('get','a','b','c')" 0
160        } e
161        set e
162    } {*number of args*}
163
164    test {EVAL - redis.call variant raises a Lua error on Redis cmd error (1)} {
165        set e {}
166        r set foo bar
167        catch {
168            r eval "redis.call('lpush','foo','val')" 0
169        } e
170        set e
171    } {*against a key*}
172
173    test {SCRIPTING FLUSH - is able to clear the scripts cache?} {
174        r set mykey myval
175        set v [r evalsha 9bd632c7d33e571e9f24556ebed26c3479a87129 0]
176        assert_equal $v myval
177        set e ""
178        r script flush
179        catch {r evalsha 9bd632c7d33e571e9f24556ebed26c3479a87129 0} e
180        set e
181    } {NOSCRIPT*}
182
183    test {SCRIPT EXISTS - can detect already defined scripts?} {
184        r eval "return 1+1" 0
185        r script exists a27e7e8a43702b7046d4f6a7ccf5b60cef6b9bd9 a27e7e8a43702b7046d4f6a7ccf5b60cef6b9bda
186    } {1 0}
187
188    test {SCRIPT LOAD - is able to register scripts in the scripting cache} {
189        list \
190            [r script load "return 'loaded'"] \
191            [r evalsha b534286061d4b9e4026607613b95c06c06015ae8 0]
192    } {b534286061d4b9e4026607613b95c06c06015ae8 loaded}
193
194    test "In the context of Lua the output of random commands gets ordered" {
195        r del myset
196        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
197        r eval {return redis.call('smembers','myset')} 0
198    } {a aa aaa azz b c d e f g h i l m n o p q r s t u v z}
199
200    test "SORT is normally not re-ordered by the scripting engine" {
201        r del myset
202        r sadd myset 1 2 3 4 10
203        r eval {return redis.call('sort','myset','desc')} 0
204    } {10 4 3 2 1}
205
206    test "SORT BY <constant> output gets ordered by scripting" {
207        r del myset
208        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
209        r eval {return redis.call('sort','myset','by','_')} 0
210    } {a aa aaa azz b c d e f g h i l m n o p q r s t u v z}
211
212    test "SORT output containing NULLs is well handled by scripting" {
213        r del myset
214        r sadd myset a b c
215        r eval {return redis.call('sort','myset','by','_','get','#','get','_:*')} 0
216    } {{} {} {} a b c}
217
218    test "redis.sha1hex() implementation" {
219        list [r eval {return redis.sha1hex('')} 0] \
220             [r eval {return redis.sha1hex('Pizza & Mandolino')} 0]
221    } {da39a3ee5e6b4b0d3255bfef95601890afd80709 74822d82031af7493c20eefa13bd07ec4fada82f}
222}
223
224start_server {tags {"scripting repl"}} {
225    start_server {} {
226        test {Before the slave connects we issue an EVAL command} {
227            r eval {return redis.call('incr','x')} 0
228        } {1}
229
230        test {Connect a slave to the main instance} {
231            r -1 slaveof [srv 0 host] [srv 0 port]
232            after 1000
233            s -1 role
234        } {slave}
235
236        test {Now use EVALSHA against the master} {
237            r evalsha ae3477e27be955de7e1bc9adfdca626b478d3cb2 0
238        } {2}
239
240        if {$::valgrind} {after 2000} else {after 100}
241
242        test {If EVALSHA was replicated as EVAL the slave should be ok} {
243            r -1 get x
244        } {2}
245    }
246}
247