]> git.saurik.com Git - redis.git/blob - tests/support/server.tcl
8664b9a4305b272f8c4c67b4b4e7d043bdad6155
[redis.git] / tests / support / server.tcl
1 proc error_and_quit {config_file error} {
2 puts "!!COULD NOT START REDIS-SERVER\n"
3 puts "CONFIGURATION:"
4 puts [exec cat $config_file]
5 puts "\nERROR:"
6 puts [string trim $error]
7 exit 1
8 }
9
10 proc kill_server config {
11 # nevermind if its already dead
12 if {![is_alive $config]} { return }
13 set pid [dict get $config pid]
14
15 # check for leaks
16 catch {
17 if {[string match {*Darwin*} [exec uname -a]]} {
18 test "Check for memory leaks (pid $pid)" {
19 exec leaks $pid
20 } {*0 leaks*}
21 }
22 }
23
24 # kill server and wait for the process to be totally exited
25 while {[is_alive $config]} {
26 if {[incr wait 10] % 1000 == 0} {
27 puts "Waiting for process $pid to exit..."
28 }
29 exec kill $pid
30 after 10
31 }
32 }
33
34 proc is_alive config {
35 set pid [dict get $config pid]
36 if {[catch {exec ps -p $pid} err]} {
37 return 0
38 } else {
39 return 1
40 }
41 }
42
43 proc start_server {filename overrides {code undefined}} {
44 set data [split [exec cat "tests/assets/$filename"] "\n"]
45 set config {}
46 foreach line $data {
47 if {[string length $line] > 0 && [string index $line 0] ne "#"} {
48 set elements [split $line " "]
49 set directive [lrange $elements 0 0]
50 set arguments [lrange $elements 1 end]
51 dict set config $directive $arguments
52 }
53 }
54
55 # use a different directory every time a server is started
56 dict set config dir [tmpdir server]
57
58 # start every server on a different port
59 dict set config port [incr ::port]
60
61 # apply overrides from arguments
62 foreach override $overrides {
63 set directive [lrange $override 0 0]
64 set arguments [lrange $override 1 end]
65 dict set config $directive $arguments
66 }
67
68 # write new configuration to temporary file
69 set config_file [tmpfile redis.conf]
70 set fp [open $config_file w+]
71 foreach directive [dict keys $config] {
72 puts -nonewline $fp "$directive "
73 puts $fp [dict get $config $directive]
74 }
75 close $fp
76
77 set stdout [format "%s/%s" [dict get $config "dir"] "stdout"]
78 set stderr [format "%s/%s" [dict get $config "dir"] "stderr"]
79 exec ./redis-server $config_file > $stdout 2> $stderr &
80 after 500
81
82 # check that the server actually started
83 if {[file size $stderr] > 0} {
84 error_and_quit $config_file [exec cat $stderr]
85 }
86
87 # find out the pid
88 regexp {^\[(\d+)\]} [exec head -n1 $stdout] _ pid
89
90 # setup properties to be able to initialize a client object
91 set host $::host
92 set port $::port
93 if {[dict exists $config bind]} { set host [dict get $config bind] }
94 if {[dict exists $config port]} { set port [dict get $config port] }
95
96 # setup config dict
97 dict set srv "config" $config_file
98 dict set srv "pid" $pid
99 dict set srv "host" $host
100 dict set srv "port" $port
101 dict set srv "stdout" $stdout
102 dict set srv "stderr" $stderr
103
104 # if a block of code is supplied, we wait for the server to become
105 # available, create a client object and kill the server afterwards
106 if {$code ne "undefined"} {
107 set line [exec head -n1 $stdout]
108 if {[string match {*already in use*} $line]} {
109 error_and_quit $config_file $line
110 }
111
112 while 1 {
113 # check that the server actually started and is ready for connections
114 if {[exec cat $stdout | grep "ready to accept" | wc -l] > 0} {
115 break
116 }
117 after 10
118 }
119
120 set client [redis $host $port]
121 dict set srv "client" $client
122
123 # select the right db when we don't have to authenticate
124 if {![dict exists $config requirepass]} {
125 $client select 9
126 }
127
128 # append the server to the stack
129 lappend ::servers $srv
130
131 # execute provided block
132 catch { uplevel 1 $code } err
133
134 # pop the server object
135 set ::servers [lrange $::servers 0 end-1]
136
137 kill_server $srv
138
139 if {[string length $err] > 0} {
140 puts "Error executing the suite, aborting..."
141 puts $err
142 exit 1
143 }
144 } else {
145 set _ $srv
146 }
147 }