server.tcl 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. set ::global_overrides {}
  2. set ::tags {}
  3. set ::valgrind_errors {}
  4. proc start_server_error {config_file error} {
  5. set err {}
  6. append err "Cant' start the Redis server\n"
  7. append err "CONFIGURATION:"
  8. append err [exec cat $config_file]
  9. append err "\nERROR:"
  10. append err [string trim $error]
  11. send_data_packet $::test_server_fd err $err
  12. }
  13. proc check_valgrind_errors stderr {
  14. set fd [open $stderr]
  15. set buf [read $fd]
  16. close $fd
  17. if {[regexp -- { at 0x} $buf] ||
  18. (![regexp -- {definitely lost: 0 bytes} $buf] &&
  19. ![regexp -- {no leaks are possible} $buf])} {
  20. send_data_packet $::test_server_fd err "Valgrind error: $buf\n"
  21. }
  22. }
  23. proc kill_server config {
  24. # nothing to kill when running against external server
  25. if {$::external} return
  26. # nevermind if its already dead
  27. if {![is_alive $config]} { return }
  28. set pid [dict get $config pid]
  29. # check for leaks
  30. if {![dict exists $config "skipleaks"]} {
  31. catch {
  32. if {[string match {*Darwin*} [exec uname -a]]} {
  33. tags {"leaks"} {
  34. test "Check for memory leaks (pid $pid)" {
  35. set output {0 leaks}
  36. catch {exec leaks $pid} output
  37. if {[string match {*process does not exist*} $output] ||
  38. [string match {*cannot examine*} $output]} {
  39. # In a few tests we kill the server process.
  40. set output "0 leaks"
  41. }
  42. set output
  43. } {*0 leaks*}
  44. }
  45. }
  46. }
  47. }
  48. # kill server and wait for the process to be totally exited
  49. catch {exec kill $pid}
  50. while {[is_alive $config]} {
  51. incr wait 10
  52. if {$wait >= 5000} {
  53. puts "Forcing process $pid to exit..."
  54. catch {exec kill -KILL $pid}
  55. } elseif {$wait % 1000 == 0} {
  56. puts "Waiting for process $pid to exit..."
  57. }
  58. after 10
  59. }
  60. # Check valgrind errors if needed
  61. if {$::valgrind} {
  62. check_valgrind_errors [dict get $config stderr]
  63. }
  64. # Remove this pid from the set of active pids in the test server.
  65. send_data_packet $::test_server_fd server-killed $pid
  66. }
  67. proc is_alive config {
  68. set pid [dict get $config pid]
  69. if {[catch {exec ps -p $pid} err]} {
  70. return 0
  71. } else {
  72. return 1
  73. }
  74. }
  75. proc ping_server {host port} {
  76. set retval 0
  77. if {[catch {
  78. set fd [socket $host $port]
  79. fconfigure $fd -translation binary
  80. puts $fd "PING\r\n"
  81. flush $fd
  82. set reply [gets $fd]
  83. if {[string range $reply 0 0] eq {+} ||
  84. [string range $reply 0 0] eq {-}} {
  85. set retval 1
  86. }
  87. close $fd
  88. } e]} {
  89. if {$::verbose} {
  90. puts -nonewline "."
  91. }
  92. } else {
  93. if {$::verbose} {
  94. puts -nonewline "ok"
  95. }
  96. }
  97. return $retval
  98. }
  99. # Return 1 if the server at the specified addr is reachable by PING, otherwise
  100. # returns 0. Performs a try every 50 milliseconds for the specified number
  101. # of retries.
  102. proc server_is_up {host port retrynum} {
  103. after 10 ;# Use a small delay to make likely a first-try success.
  104. set retval 0
  105. while {[incr retrynum -1]} {
  106. if {[catch {ping_server $host $port} ping]} {
  107. set ping 0
  108. }
  109. if {$ping} {return 1}
  110. after 50
  111. }
  112. return 0
  113. }
  114. # doesn't really belong here, but highly coupled to code in start_server
  115. proc tags {tags code} {
  116. set ::tags [concat $::tags $tags]
  117. uplevel 1 $code
  118. set ::tags [lrange $::tags 0 end-[llength $tags]]
  119. }
  120. proc start_server {options {code undefined}} {
  121. # If we are running against an external server, we just push the
  122. # host/port pair in the stack the first time
  123. if {$::external} {
  124. if {[llength $::servers] == 0} {
  125. set srv {}
  126. dict set srv "host" $::host
  127. dict set srv "port" $::port
  128. set client [redis $::host $::port]
  129. dict set srv "client" $client
  130. $client select 9
  131. # append the server to the stack
  132. lappend ::servers $srv
  133. }
  134. uplevel 1 $code
  135. return
  136. }
  137. # setup defaults
  138. set baseconfig "default.conf"
  139. set overrides {}
  140. set tags {}
  141. # parse options
  142. foreach {option value} $options {
  143. switch $option {
  144. "config" {
  145. set baseconfig $value }
  146. "overrides" {
  147. set overrides $value }
  148. "tags" {
  149. set tags $value
  150. set ::tags [concat $::tags $value] }
  151. default {
  152. error "Unknown option $option" }
  153. }
  154. }
  155. set data [split [exec cat "tests/assets/$baseconfig"] "\n"]
  156. set config {}
  157. foreach line $data {
  158. if {[string length $line] > 0 && [string index $line 0] ne "#"} {
  159. set elements [split $line " "]
  160. set directive [lrange $elements 0 0]
  161. set arguments [lrange $elements 1 end]
  162. dict set config $directive $arguments
  163. }
  164. }
  165. # use a different directory every time a server is started
  166. dict set config dir [tmpdir server]
  167. # start every server on a different port
  168. set ::port [find_available_port [expr {$::port+1}]]
  169. dict set config port $::port
  170. # apply overrides from global space and arguments
  171. foreach {directive arguments} [concat $::global_overrides $overrides] {
  172. dict set config $directive $arguments
  173. }
  174. # write new configuration to temporary file
  175. set config_file [tmpfile redis.conf]
  176. set fp [open $config_file w+]
  177. foreach directive [dict keys $config] {
  178. puts -nonewline $fp "$directive "
  179. puts $fp [dict get $config $directive]
  180. }
  181. close $fp
  182. set stdout [format "%s/%s" [dict get $config "dir"] "stdout"]
  183. set stderr [format "%s/%s" [dict get $config "dir"] "stderr"]
  184. if {$::valgrind} {
  185. set pid [exec valgrind --track-origins=yes --suppressions=src/valgrind.sup --show-reachable=no --show-possibly-lost=no --leak-check=full src/redis-server $config_file > $stdout 2> $stderr &]
  186. } else {
  187. set pid [exec src/redis-server $config_file > $stdout 2> $stderr &]
  188. }
  189. # Tell the test server about this new instance.
  190. send_data_packet $::test_server_fd server-spawned $pid
  191. # check that the server actually started
  192. # ugly but tries to be as fast as possible...
  193. if {$::valgrind} {set retrynum 1000} else {set retrynum 100}
  194. if {$::verbose} {
  195. puts -nonewline "=== ($tags) Starting server ${::host}:${::port} "
  196. }
  197. if {$code ne "undefined"} {
  198. set serverisup [server_is_up $::host $::port $retrynum]
  199. } else {
  200. set serverisup 1
  201. }
  202. if {$::verbose} {
  203. puts ""
  204. }
  205. if {!$serverisup} {
  206. set err {}
  207. append err [exec cat $stdout] "\n" [exec cat $stderr]
  208. start_server_error $config_file $err
  209. return
  210. }
  211. # Wait for actual startup
  212. while {![info exists _pid]} {
  213. regexp {PID:\s(\d+)} [exec cat $stdout] _ _pid
  214. after 100
  215. }
  216. # setup properties to be able to initialize a client object
  217. set host $::host
  218. set port $::port
  219. if {[dict exists $config bind]} { set host [dict get $config bind] }
  220. if {[dict exists $config port]} { set port [dict get $config port] }
  221. # setup config dict
  222. dict set srv "config_file" $config_file
  223. dict set srv "config" $config
  224. dict set srv "pid" $pid
  225. dict set srv "host" $host
  226. dict set srv "port" $port
  227. dict set srv "stdout" $stdout
  228. dict set srv "stderr" $stderr
  229. # if a block of code is supplied, we wait for the server to become
  230. # available, create a client object and kill the server afterwards
  231. if {$code ne "undefined"} {
  232. set line [exec head -n1 $stdout]
  233. if {[string match {*already in use*} $line]} {
  234. error_and_quit $config_file $line
  235. }
  236. while 1 {
  237. # check that the server actually started and is ready for connections
  238. if {[exec grep "ready to accept" | wc -l < $stdout] > 0} {
  239. break
  240. }
  241. after 10
  242. }
  243. # append the server to the stack
  244. lappend ::servers $srv
  245. # connect client (after server dict is put on the stack)
  246. reconnect
  247. # execute provided block
  248. set num_tests $::num_tests
  249. if {[catch { uplevel 1 $code } error]} {
  250. set backtrace $::errorInfo
  251. # Kill the server without checking for leaks
  252. dict set srv "skipleaks" 1
  253. kill_server $srv
  254. # Print warnings from log
  255. puts [format "\nLogged warnings (pid %d):" [dict get $srv "pid"]]
  256. set warnings [warnings_from_file [dict get $srv "stdout"]]
  257. if {[string length $warnings] > 0} {
  258. puts "$warnings"
  259. } else {
  260. puts "(none)"
  261. }
  262. puts ""
  263. error $error $backtrace
  264. }
  265. # Don't do the leak check when no tests were run
  266. if {$num_tests == $::num_tests} {
  267. dict set srv "skipleaks" 1
  268. }
  269. # pop the server object
  270. set ::servers [lrange $::servers 0 end-1]
  271. set ::tags [lrange $::tags 0 end-[llength $tags]]
  272. kill_server $srv
  273. } else {
  274. set ::tags [lrange $::tags 0 end-[llength $tags]]
  275. set _ $srv
  276. }
  277. }