]> git.saurik.com Git - redis.git/blob - tests/support/util.tcl
Sentinel: do not crash against slaves not publishing the runid.
[redis.git] / tests / support / util.tcl
1 proc randstring {min max {type binary}} {
2 set len [expr {$min+int(rand()*($max-$min+1))}]
3 set output {}
4 if {$type eq {binary}} {
5 set minval 0
6 set maxval 255
7 } elseif {$type eq {alpha}} {
8 set minval 48
9 set maxval 122
10 } elseif {$type eq {compr}} {
11 set minval 48
12 set maxval 52
13 }
14 while {$len} {
15 append output [format "%c" [expr {$minval+int(rand()*($maxval-$minval+1))}]]
16 incr len -1
17 }
18 return $output
19 }
20
21 # Useful for some test
22 proc zlistAlikeSort {a b} {
23 if {[lindex $a 0] > [lindex $b 0]} {return 1}
24 if {[lindex $a 0] < [lindex $b 0]} {return -1}
25 string compare [lindex $a 1] [lindex $b 1]
26 }
27
28 # Return all log lines starting with the first line that contains a warning.
29 # Generally, this will be an assertion error with a stack trace.
30 proc warnings_from_file {filename} {
31 set lines [split [exec cat $filename] "\n"]
32 set matched 0
33 set logall 0
34 set result {}
35 foreach line $lines {
36 if {[string match {*REDIS BUG REPORT START*} $line]} {
37 set logall 1
38 }
39 if {[regexp {^\[\d+\]\s+\d+\s+\w+\s+\d{2}:\d{2}:\d{2} \#} $line]} {
40 set matched 1
41 }
42 if {$logall || $matched} {
43 lappend result $line
44 }
45 }
46 join $result "\n"
47 }
48
49 # Return value for INFO property
50 proc status {r property} {
51 if {[regexp "\r\n$property:(.*?)\r\n" [{*}$r info] _ value]} {
52 set _ $value
53 }
54 }
55
56 proc waitForBgsave r {
57 while 1 {
58 if {[status r rdb_bgsave_in_progress] eq 1} {
59 if {$::verbose} {
60 puts -nonewline "\nWaiting for background save to finish... "
61 flush stdout
62 }
63 after 1000
64 } else {
65 break
66 }
67 }
68 }
69
70 proc waitForBgrewriteaof r {
71 while 1 {
72 if {[status r aof_rewrite_in_progress] eq 1} {
73 if {$::verbose} {
74 puts -nonewline "\nWaiting for background AOF rewrite to finish... "
75 flush stdout
76 }
77 after 1000
78 } else {
79 break
80 }
81 }
82 }
83
84 proc wait_for_sync r {
85 while 1 {
86 if {[status $r master_link_status] eq "down"} {
87 after 10
88 } else {
89 break
90 }
91 }
92 }
93
94 proc randomInt {max} {
95 expr {int(rand()*$max)}
96 }
97
98 proc randomSignedInt {max} {
99 set i [randomInt $max]
100 if {rand() > 0.5} {
101 set i -$i
102 }
103 return $i
104 }
105
106 proc randpath args {
107 set path [expr {int(rand()*[llength $args])}]
108 uplevel 1 [lindex $args $path]
109 }
110
111 proc randomValue {} {
112 randpath {
113 # Small enough to likely collide
114 randomSignedInt 1000
115 } {
116 # 32 bit compressible signed/unsigned
117 randpath {randomSignedInt 2000000000} {randomSignedInt 4000000000}
118 } {
119 # 64 bit
120 randpath {randomSignedInt 1000000000000}
121 } {
122 # Random string
123 randpath {randstring 0 256 alpha} \
124 {randstring 0 256 compr} \
125 {randstring 0 256 binary}
126 }
127 }
128
129 proc randomKey {} {
130 randpath {
131 # Small enough to likely collide
132 randomInt 1000
133 } {
134 # 32 bit compressible signed/unsigned
135 randpath {randomInt 2000000000} {randomInt 4000000000}
136 } {
137 # 64 bit
138 randpath {randomInt 1000000000000}
139 } {
140 # Random string
141 randpath {randstring 1 256 alpha} \
142 {randstring 1 256 compr}
143 }
144 }
145
146 proc findKeyWithType {r type} {
147 for {set j 0} {$j < 20} {incr j} {
148 set k [{*}$r randomkey]
149 if {$k eq {}} {
150 return {}
151 }
152 if {[{*}$r type $k] eq $type} {
153 return $k
154 }
155 }
156 return {}
157 }
158
159 proc createComplexDataset {r ops {opt {}}} {
160 for {set j 0} {$j < $ops} {incr j} {
161 set k [randomKey]
162 set k2 [randomKey]
163 set f [randomValue]
164 set v [randomValue]
165
166 if {[lsearch -exact $opt useexpire] != -1} {
167 if {rand() < 0.1} {
168 {*}$r expire [randomKey] [randomInt 2]
169 }
170 }
171
172 randpath {
173 set d [expr {rand()}]
174 } {
175 set d [expr {rand()}]
176 } {
177 set d [expr {rand()}]
178 } {
179 set d [expr {rand()}]
180 } {
181 set d [expr {rand()}]
182 } {
183 randpath {set d +inf} {set d -inf}
184 }
185 set t [{*}$r type $k]
186
187 if {$t eq {none}} {
188 randpath {
189 {*}$r set $k $v
190 } {
191 {*}$r lpush $k $v
192 } {
193 {*}$r sadd $k $v
194 } {
195 {*}$r zadd $k $d $v
196 } {
197 {*}$r hset $k $f $v
198 } {
199 {*}$r del $k
200 }
201 set t [{*}$r type $k]
202 }
203
204 switch $t {
205 {string} {
206 # Nothing to do
207 }
208 {list} {
209 randpath {{*}$r lpush $k $v} \
210 {{*}$r rpush $k $v} \
211 {{*}$r lrem $k 0 $v} \
212 {{*}$r rpop $k} \
213 {{*}$r lpop $k}
214 }
215 {set} {
216 randpath {{*}$r sadd $k $v} \
217 {{*}$r srem $k $v} \
218 {
219 set otherset [findKeyWithType {*}$r set]
220 if {$otherset ne {}} {
221 randpath {
222 {*}$r sunionstore $k2 $k $otherset
223 } {
224 {*}$r sinterstore $k2 $k $otherset
225 } {
226 {*}$r sdiffstore $k2 $k $otherset
227 }
228 }
229 }
230 }
231 {zset} {
232 randpath {{*}$r zadd $k $d $v} \
233 {{*}$r zrem $k $v} \
234 {
235 set otherzset [findKeyWithType {*}$r zset]
236 if {$otherzset ne {}} {
237 randpath {
238 {*}$r zunionstore $k2 2 $k $otherzset
239 } {
240 {*}$r zinterstore $k2 2 $k $otherzset
241 }
242 }
243 }
244 }
245 {hash} {
246 randpath {{*}$r hset $k $f $v} \
247 {{*}$r hdel $k $f}
248 }
249 }
250 }
251 }
252
253 proc formatCommand {args} {
254 set cmd "*[llength $args]\r\n"
255 foreach a $args {
256 append cmd "$[string length $a]\r\n$a\r\n"
257 }
258 set _ $cmd
259 }
260
261 proc csvdump r {
262 set o {}
263 foreach k [lsort [{*}$r keys *]] {
264 set type [{*}$r type $k]
265 append o [csvstring $k] , [csvstring $type] ,
266 switch $type {
267 string {
268 append o [csvstring [{*}$r get $k]] "\n"
269 }
270 list {
271 foreach e [{*}$r lrange $k 0 -1] {
272 append o [csvstring $e] ,
273 }
274 append o "\n"
275 }
276 set {
277 foreach e [lsort [{*}$r smembers $k]] {
278 append o [csvstring $e] ,
279 }
280 append o "\n"
281 }
282 zset {
283 foreach e [{*}$r zrange $k 0 -1 withscores] {
284 append o [csvstring $e] ,
285 }
286 append o "\n"
287 }
288 hash {
289 set fields [{*}$r hgetall $k]
290 set newfields {}
291 foreach {k v} $fields {
292 lappend newfields [list $k $v]
293 }
294 set fields [lsort -index 0 $newfields]
295 foreach kv $fields {
296 append o [csvstring [lindex $kv 0]] ,
297 append o [csvstring [lindex $kv 1]] ,
298 }
299 append o "\n"
300 }
301 }
302 }
303 return $o
304 }
305
306 proc csvstring s {
307 return "\"$s\""
308 }
309
310 proc roundFloat f {
311 format "%.10g" $f
312 }