]> git.saurik.com Git - redis.git/blob - tests/support/util.tcl
Merge master with resolved conflict in src/redis-cli.c
[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 result {}
34 foreach line $lines {
35 if {[regexp {^\[\d+\]\s+\d+\s+\w+\s+\d{2}:\d{2}:\d{2} \#} $line]} {
36 set matched 1
37 }
38 if {$matched} {
39 lappend result $line
40 }
41 }
42 join $result "\n"
43 }
44
45 # Return value for INFO property
46 proc status {r property} {
47 if {[regexp "\r\n$property:(.*?)\r\n" [{*}$r info] _ value]} {
48 set _ $value
49 }
50 }
51
52 proc waitForBgsave r {
53 while 1 {
54 if {[status r bgsave_in_progress] eq 1} {
55 puts -nonewline "\nWaiting for background save to finish... "
56 flush stdout
57 after 1000
58 } else {
59 break
60 }
61 }
62 }
63
64 proc waitForBgrewriteaof r {
65 while 1 {
66 if {[status r bgrewriteaof_in_progress] eq 1} {
67 puts -nonewline "\nWaiting for background AOF rewrite to finish... "
68 flush stdout
69 after 1000
70 } else {
71 break
72 }
73 }
74 }
75
76 proc wait_for_sync r {
77 while 1 {
78 if {[status r master_link_status] eq "down"} {
79 after 10
80 } else {
81 break
82 }
83 }
84 }
85
86 proc randomInt {max} {
87 expr {int(rand()*$max)}
88 }
89
90 proc randpath args {
91 set path [expr {int(rand()*[llength $args])}]
92 uplevel 1 [lindex $args $path]
93 }
94
95 proc randomValue {} {
96 randpath {
97 # Small enough to likely collide
98 randomInt 1000
99 } {
100 # 32 bit compressible signed/unsigned
101 randpath {randomInt 2000000000} {randomInt 4000000000}
102 } {
103 # 64 bit
104 randpath {randomInt 1000000000000}
105 } {
106 # Random string
107 randpath {randstring 0 256 alpha} \
108 {randstring 0 256 compr} \
109 {randstring 0 256 binary}
110 }
111 }
112
113 proc randomKey {} {
114 randpath {
115 # Small enough to likely collide
116 randomInt 1000
117 } {
118 # 32 bit compressible signed/unsigned
119 randpath {randomInt 2000000000} {randomInt 4000000000}
120 } {
121 # 64 bit
122 randpath {randomInt 1000000000000}
123 } {
124 # Random string
125 randpath {randstring 1 256 alpha} \
126 {randstring 1 256 compr}
127 }
128 }
129
130 proc findKeyWithType {r type} {
131 for {set j 0} {$j < 20} {incr j} {
132 set k [{*}$r randomkey]
133 if {$k eq {}} {
134 return {}
135 }
136 if {[{*}$r type $k] eq $type} {
137 return $k
138 }
139 }
140 return {}
141 }
142
143 proc createComplexDataset {r ops {opt {}}} {
144 for {set j 0} {$j < $ops} {incr j} {
145 set k [randomKey]
146 set k2 [randomKey]
147 set f [randomValue]
148 set v [randomValue]
149
150 if {[lsearch -exact $opt useexpire] != -1} {
151 if {rand() < 0.1} {
152 {*}$r expire [randomKey] [randomInt 2]
153 }
154 }
155
156 randpath {
157 set d [expr {rand()}]
158 } {
159 set d [expr {rand()}]
160 } {
161 set d [expr {rand()}]
162 } {
163 set d [expr {rand()}]
164 } {
165 set d [expr {rand()}]
166 } {
167 randpath {set d +inf} {set d -inf}
168 }
169 set t [{*}$r type $k]
170
171 if {$t eq {none}} {
172 randpath {
173 {*}$r set $k $v
174 } {
175 {*}$r lpush $k $v
176 } {
177 {*}$r sadd $k $v
178 } {
179 {*}$r zadd $k $d $v
180 } {
181 {*}$r hset $k $f $v
182 } {
183 {*}$r del $k
184 }
185 set t [{*}$r type $k]
186 }
187
188 switch $t {
189 {string} {
190 # Nothing to do
191 }
192 {list} {
193 randpath {{*}$r lpush $k $v} \
194 {{*}$r rpush $k $v} \
195 {{*}$r lrem $k 0 $v} \
196 {{*}$r rpop $k} \
197 {{*}$r lpop $k}
198 }
199 {set} {
200 randpath {{*}$r sadd $k $v} \
201 {{*}$r srem $k $v} \
202 {
203 set otherset [findKeyWithType r set]
204 if {$otherset ne {}} {
205 randpath {
206 {*}$r sunionstore $k2 $k $otherset
207 } {
208 {*}$r sinterstore $k2 $k $otherset
209 } {
210 {*}$r sdiffstore $k2 $k $otherset
211 }
212 }
213 }
214 }
215 {zset} {
216 randpath {{*}$r zadd $k $d $v} \
217 {{*}$r zrem $k $v} \
218 {
219 set otherzset [findKeyWithType r zset]
220 if {$otherzset ne {}} {
221 randpath {
222 {*}$r zunionstore $k2 2 $k $otherzset
223 } {
224 {*}$r zinterstore $k2 2 $k $otherzset
225 }
226 }
227 }
228 }
229 {hash} {
230 randpath {{*}$r hset $k $f $v} \
231 {{*}$r hdel $k $f}
232 }
233 }
234 }
235 }
236
237 proc formatCommand {args} {
238 set cmd "*[llength $args]\r\n"
239 foreach a $args {
240 append cmd "$[string length $a]\r\n$a\r\n"
241 }
242 set _ $cmd
243 }
244
245 proc csvdump r {
246 set o {}
247 foreach k [lsort [{*}$r keys *]] {
248 set type [{*}$r type $k]
249 append o [csvstring $k] , [csvstring $type] ,
250 switch $type {
251 string {
252 append o [csvstring [{*}$r get $k]] "\n"
253 }
254 list {
255 foreach e [{*}$r lrange $k 0 -1] {
256 append o [csvstring $e] ,
257 }
258 append o "\n"
259 }
260 set {
261 foreach e [lsort [{*}$r smembers $k]] {
262 append o [csvstring $e] ,
263 }
264 append o "\n"
265 }
266 zset {
267 foreach e [{*}$r zrange $k 0 -1 withscores] {
268 append o [csvstring $e] ,
269 }
270 append o "\n"
271 }
272 hash {
273 set fields [{*}$r hgetall $k]
274 set newfields {}
275 foreach {k v} $fields {
276 lappend newfields [list $k $v]
277 }
278 set fields [lsort -index 0 $newfields]
279 foreach kv $fields {
280 append o [csvstring [lindex $kv 0]] ,
281 append o [csvstring [lindex $kv 1]] ,
282 }
283 append o "\n"
284 }
285 }
286 }
287 return $o
288 }
289
290 proc csvstring s {
291 return "\"$s\""
292 }