summaryrefslogtreecommitdiff
path: root/tests/unit/functions.tcl
blob: 0736a44da0faf357963fb9b73d0d9c2fa01a0a09 (plain)
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
start_server {tags {"scripting"}} {
    test {FUNCTION - Basic usage} {
        r function create LUA test {return 'hello'}
        r fcall test 0
    } {hello}

    test {FUNCTION - Create an already exiting function raise error} {
        catch {
            r function create LUA test {return 'hello1'}
        } e
        set _ $e
    } {*Function already exists*}

    test {FUNCTION - Create function with unexisting engine} {
        catch {
            r function create bad_engine test {return 'hello1'}
        } e
        set _ $e
    } {*Engine not found*}

    test {FUNCTION - Test uncompiled script} {
        catch {
            r function create LUA test1 {bad script}
        } e
        set _ $e
    } {*Error compiling function*}

    test {FUNCTION - test replace argument} {
        r function create LUA test REPLACE {return 'hello1'}
        r fcall test 0
    } {hello1}

    test {FUNCTION - test replace argument with function creation failure keeps old function} {
         catch {r function create LUA test REPLACE {error}}
        r fcall test 0
    } {hello1}

    test {FUNCTION - test function delete} {
        r function delete test
        catch {
            r fcall test 0
        } e
        set _ $e
    } {*Function not found*}

    test {FUNCTION - test description argument} {
        r function create LUA test DESCRIPTION {some description} {return 'hello'}
        r function list
    } {{name test engine LUA description {some description}}}

    test {FUNCTION - test info specific function} {
        r function info test WITHCODE
    } {name test engine LUA description {some description} code {return 'hello'}}

    test {FUNCTION - test info without code} {
        r function info test
    } {name test engine LUA description {some description}}

    test {FUNCTION - test info on function that does not exists} {
        catch {
            r function info bad_function_name
        } e
        set _ $e
    } {*Function does not exists*}

    test {FUNCTION - test info with bad number of arguments} {
        catch {
            r function info test WITHCODE bad_arg
        } e
        set _ $e
    } {*wrong number of arguments*}

    test {FUNCTION - test fcall bad arguments} {
        catch {
            r fcall test bad_arg
        } e
        set _ $e
    } {*Bad number of keys provided*}

    test {FUNCTION - test fcall bad number of keys arguments} {
        catch {
            r fcall test 10 key1
        } e
        set _ $e
    } {*Number of keys can't be greater than number of args*}

    test {FUNCTION - test fcall negative number of keys} {
        catch {
            r fcall test -1 key1
        } e
        set _ $e
    } {*Number of keys can't be negative*}

    test {FUNCTION - test function delete on not exiting function} {
        catch {
            r function delete test1
        } e
        set _ $e
    } {*Function not found*}

    test {FUNCTION - test function kill when function is not running} {
        catch {
            r function kill
        } e
        set _ $e
    } {*No scripts in execution*}

    test {FUNCTION - test wrong subcommand} {
        catch {
            r function bad_subcommand
        } e
        set _ $e
    } {*Unknown subcommand*}

    test {FUNCTION - test loading from rdb} {
        r debug reload
        r fcall test 0
    } {hello}

    test {FUNCTION - test fcall_ro with write command} {
        r function create lua test REPLACE {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 create lua test REPLACE {return redis.call('get', 'x')}
        r set x 1
        r fcall_ro test 0
    } {1}

    test {FUNCTION - test keys and argv} {
        r function create lua test REPLACE {return redis.call('set', KEYS[1], ARGV[1])}
        r fcall test 1 x foo
        r get x
    } {foo}

    test {FUNCTION - test command get keys on fcall} {
        r COMMAND GETKEYS fcall test 1 x foo
    } {x}

    test {FUNCTION - test command get keys on fcall_ro} {
        r COMMAND GETKEYS fcall_ro test 1 x foo
    } {x}

    test {FUNCTION - test function kill} {
        set rd [redis_deferring_client]
        r config set script-time-limit 10
        r function create lua test REPLACE {local a = 1 while true do a = a + 1 end}
        $rd fcall test 0
        after 200
        catch {r ping} e
        assert_match {BUSY*} $e
        assert_match {running_script {name test command {fcall test 0} duration_ms *} engines LUA} [r FUNCTION STATS]
        r function kill
        after 200 ; # Give some time to Lua to call the hook again...
        assert_equal [r ping] "PONG"
    }

    test {FUNCTION - test script kill not working on function} {
        set rd [redis_deferring_client]
        r config set script-time-limit 10
        r function create lua test REPLACE {local a = 1 while true do a = a + 1 end}
        $rd fcall test 0
        after 200
        catch {r ping} e
        assert_match {BUSY*} $e
        catch {r script kill} e
        assert_match {BUSY*} $e
        r function kill
        after 200 ; # Give some time to Lua to call the hook again...
        assert_equal [r ping] "PONG"
    }

    test {FUNCTION - test function kill not working on eval} {
        set rd [redis_deferring_client]
        r config set script-time-limit 10
        $rd eval {local a = 1 while true do a = a + 1 end} 0
        after 200
        catch {r ping} e
        assert_match {BUSY*} $e
        catch {r function kill} e
        assert_match {BUSY*} $e
        r script kill
        after 200 ; # Give some time to Lua to call the hook again...
        assert_equal [r ping] "PONG"
    }
}

start_server {tags {"scripting repl"}} {
    start_server {} {
        test "Connect a replica to the master instance" {
            r -1 slaveof [srv 0 host] [srv 0 port]
            wait_for_condition 50 100 {
                [s -1 role] eq {slave} &&
                [string match {*master_link_status:up*} [r -1 info replication]]
            } else {
                fail "Can't turn the instance into a replica"
            }
        }

        test {FUNCTION - creation is replicated to replica} {
            r function create LUA test DESCRIPTION {some description} {return 'hello'}
            wait_for_condition 50 100 {
                [r -1 function list] eq {{name test engine LUA description {some description}}}
            } else {
                fail "Failed waiting for function to replicate to replica"
            }
        }

        test {FUNCTION - call on replica} {
            r -1 fcall test 0
        } {hello}

        test {FUNCTION - delete is replicated to replica} {
            r function delete test
            wait_for_condition 50 100 {
                [r -1 function list] eq {}
            } else {
                fail "Failed waiting for function to replicate to replica"
            }
        }

        test "Disconnecting the replica from master instance" {
            r -1 slaveof no one
            # creating a function after disconnect to make sure function
            # is replicated on rdb phase
            r function create LUA test DESCRIPTION {some description} {return 'hello'}

            # reconnect the replica
            r -1 slaveof [srv 0 host] [srv 0 port]
            wait_for_condition 50 100 {
                [s -1 role] eq {slave} &&
                [string match {*master_link_status:up*} [r -1 info replication]]
            } else {
                fail "Can't turn the instance into a replica"
            }
        }

        test "FUNCTION - test replication to replica on rdb phase" {
            r -1 fcall test 0
        } {hello}

        test "FUNCTION - test replication to replica on rdb phase info command" {
            r -1 function info test WITHCODE
        } {name test engine LUA description {some description} code {return 'hello'}}

        test "FUNCTION - create on read only replica" {
            catch {
                r -1 function create LUA test DESCRIPTION {some description} {return 'hello'}
            } e
            set _ $e
        } {*Can not create a function on a read only replica*}

        test "FUNCTION - delete on read only replica" {
            catch {
                r -1 function delete test
            } e
            set _ $e
        } {*Can not delete a function on a read only replica*}

        test "FUNCTION - function effect is replicated to replica" {
            r function create LUA test REPLACE {return redis.call('set', 'x', '1')}
            r fcall test 0
            assert {[r get x] eq {1}}
            wait_for_condition 50 100 {
                [r -1 get x] eq {1}
            } else {
                fail "Failed waiting function effect to be replicated to replica"
            }
        }

        test "FUNCTION - modify key space of read only replica" {
            catch {
                r -1 fcall test 0
            } e
            set _ $e
        } {*can't write against a read only replica*}
    }
}