| 
									
										
										
										
											2010-05-14 23:31:11 +08:00
										 |  |  | # Redis test suite. Copyright (C) 2009 Salvatore Sanfilippo antirez@gmail.com
 | 
					
						
							| 
									
										
										
										
											2014-08-01 02:25:48 +08:00
										 |  |  | # This software is released under the BSD License. See the COPYING file for
 | 
					
						
							| 
									
										
										
										
											2010-05-14 23:31:11 +08:00
										 |  |  | # more information.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-24 06:36:59 +08:00
										 |  |  | package require Tcl 8.5 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-14 23:31:11 +08:00
										 |  |  | set tcl_precision 17 | 
					
						
							| 
									
										
										
										
											2010-05-15 00:48:33 +08:00
										 |  |  | source tests/support/redis.tcl | 
					
						
							|  |  |  | source tests/support/server.tcl | 
					
						
							|  |  |  | source tests/support/tmpfile.tcl | 
					
						
							|  |  |  | source tests/support/test.tcl | 
					
						
							|  |  |  | source tests/support/util.tcl | 
					
						
							| 
									
										
										
										
											2010-05-14 23:31:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | set ::all_tests { | 
					
						
							|  |  |  |     unit/printver | 
					
						
							| 
									
										
										
										
											2012-11-14 19:12:52 +08:00
										 |  |  |     unit/dump | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     unit/auth | 
					
						
							|  |  |  |     unit/protocol | 
					
						
							| 
									
										
										
										
											2015-02-25 17:31:29 +08:00
										 |  |  |     unit/keyspace | 
					
						
							| 
									
										
										
										
											2013-10-30 18:34:01 +08:00
										 |  |  |     unit/scan | 
					
						
							| 
									
										
										
										
											2015-02-25 17:31:29 +08:00
										 |  |  |     unit/type/string | 
					
						
							|  |  |  |     unit/type/incr | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     unit/type/list | 
					
						
							| 
									
										
										
										
											2011-07-11 17:32:19 +08:00
										 |  |  |     unit/type/list-2 | 
					
						
							| 
									
										
										
										
											2011-07-11 17:41:23 +08:00
										 |  |  |     unit/type/list-3 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     unit/type/set | 
					
						
							|  |  |  |     unit/type/zset | 
					
						
							|  |  |  |     unit/type/hash | 
					
						
							| 
									
										
										
										
											2017-09-15 21:54:18 +08:00
										 |  |  |     unit/type/stream | 
					
						
							| 
									
										
										
										
											2018-02-16 18:56:31 +08:00
										 |  |  |     unit/type/stream-cgroups | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     unit/sort | 
					
						
							|  |  |  |     unit/expire | 
					
						
							|  |  |  |     unit/other | 
					
						
							| 
									
										
										
										
											2012-11-17 18:17:54 +08:00
										 |  |  |     unit/multi | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     unit/quit | 
					
						
							| 
									
										
										
										
											2011-12-12 22:34:00 +08:00
										 |  |  |     unit/aofrw | 
					
						
							| 
									
										
										
										
											2019-01-28 19:12:04 +08:00
										 |  |  |     unit/acl | 
					
						
							| 
									
										
										
										
											2018-05-15 23:33:21 +08:00
										 |  |  |     integration/block-repl | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     integration/replication | 
					
						
							| 
									
										
										
										
											2011-07-11 06:46:25 +08:00
										 |  |  |     integration/replication-2 | 
					
						
							|  |  |  |     integration/replication-3 | 
					
						
							| 
									
										
										
										
											2012-03-30 16:26:07 +08:00
										 |  |  |     integration/replication-4 | 
					
						
							| 
									
										
										
										
											2013-05-08 19:01:42 +08:00
										 |  |  |     integration/replication-psync | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     integration/aof | 
					
						
							| 
									
										
										
										
											2012-03-23 22:22:25 +08:00
										 |  |  |     integration/rdb | 
					
						
							| 
									
										
										
										
											2012-03-24 18:42:20 +08:00
										 |  |  |     integration/convert-zipmap-hash-on-load | 
					
						
							| 
									
										
										
										
											2015-02-10 21:40:27 +08:00
										 |  |  |     integration/logging | 
					
						
							| 
									
										
										
										
											2016-11-29 17:25:42 +08:00
										 |  |  |     integration/psync2 | 
					
						
							| 
									
										
										
										
											2017-04-28 16:37:07 +08:00
										 |  |  |     integration/psync2-reg | 
					
						
							| 
									
										
										
										
											2020-03-25 22:43:34 +08:00
										 |  |  |     integration/psync2-pingoff | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     unit/pubsub | 
					
						
							|  |  |  |     unit/slowlog | 
					
						
							| 
									
										
										
										
											2011-07-12 18:39:16 +08:00
										 |  |  |     unit/scripting | 
					
						
							| 
									
										
										
										
											2011-07-28 18:32:52 +08:00
										 |  |  |     unit/maxmemory | 
					
						
							| 
									
										
										
										
											2011-12-19 17:18:21 +08:00
										 |  |  |     unit/introspection | 
					
						
							| 
									
										
										
										
											2016-06-15 23:15:18 +08:00
										 |  |  |     unit/introspection-2 | 
					
						
							| 
									
										
										
										
											2012-04-08 17:16:40 +08:00
										 |  |  |     unit/limits | 
					
						
							| 
									
										
										
										
											2012-01-26 01:11:04 +08:00
										 |  |  |     unit/obuf-limits | 
					
						
							| 
									
										
										
										
											2012-05-17 21:50:44 +08:00
										 |  |  |     unit/bitops | 
					
						
							| 
									
										
										
										
											2016-03-02 22:15:18 +08:00
										 |  |  |     unit/bitfield | 
					
						
							| 
									
										
										
										
											2016-05-31 22:43:49 +08:00
										 |  |  |     unit/geo | 
					
						
							| 
									
										
										
										
											2013-08-29 22:23:57 +08:00
										 |  |  |     unit/memefficiency | 
					
						
							| 
									
										
										
										
											2014-04-04 04:15:53 +08:00
										 |  |  |     unit/hyperloglog | 
					
						
							| 
									
										
										
										
											2015-10-09 15:47:17 +08:00
										 |  |  |     unit/lazyfree | 
					
						
							| 
									
										
										
										
											2016-11-18 20:10:29 +08:00
										 |  |  |     unit/wait | 
					
						
							| 
									
										
										
										
											2018-07-01 14:43:53 +08:00
										 |  |  |     unit/pendingquerybuf | 
					
						
							| 
									
										
										
										
											2019-09-12 15:56:54 +08:00
										 |  |  |     unit/tls | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | } | 
					
						
							|  |  |  | # Index to the next test to run in the ::all_tests list.
 | 
					
						
							|  |  |  | set ::next_test 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-14 23:31:11 +08:00
										 |  |  | set ::host 127.0.0.1 | 
					
						
							| 
									
										
										
										
											2020-05-26 16:00:48 +08:00
										 |  |  | set ::port 6379; # port for external server
 | 
					
						
							|  |  |  | set ::baseport 21111; # initial port for spawned redis servers
 | 
					
						
							|  |  |  | set ::portcount 8000; # we don't wanna use more than 10000 to avoid collision with cluster bus ports
 | 
					
						
							| 
									
										
										
										
											2010-08-26 19:18:56 +08:00
										 |  |  | set ::traceleaks 0 | 
					
						
							| 
									
										
										
										
											2010-05-21 18:00:13 +08:00
										 |  |  | set ::valgrind 0 | 
					
						
							| 
									
										
										
										
											2019-09-12 15:56:54 +08:00
										 |  |  | set ::tls 0 | 
					
						
							| 
									
										
										
										
											2015-09-23 17:44:40 +08:00
										 |  |  | set ::stack_logging 0 | 
					
						
							| 
									
										
										
										
											2011-01-10 02:42:56 +08:00
										 |  |  | set ::verbose 0 | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  | set ::quiet 0 | 
					
						
							| 
									
										
										
										
											2010-06-03 04:53:22 +08:00
										 |  |  | set ::denytags {} | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  | set ::skiptests {} | 
					
						
							| 
									
										
										
										
											2010-06-03 04:53:22 +08:00
										 |  |  | set ::allowtags {} | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  | set ::only_tests {} | 
					
						
							|  |  |  | set ::single_tests {} | 
					
						
							| 
									
										
										
										
											2020-04-16 16:05:03 +08:00
										 |  |  | set ::run_solo_tests {} | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  | set ::skip_till "" | 
					
						
							| 
									
										
										
										
											2010-06-14 16:19:45 +08:00
										 |  |  | set ::external 0; # If "1" this means, we are running against external instance
 | 
					
						
							| 
									
										
										
										
											2010-10-13 15:26:44 +08:00
										 |  |  | set ::file ""; # If set, runs only the tests in this comma separated list
 | 
					
						
							| 
									
										
										
										
											2010-12-10 23:13:21 +08:00
										 |  |  | set ::curfile ""; # Hold the filename of the current suite
 | 
					
						
							| 
									
										
										
										
											2011-07-11 17:59:55 +08:00
										 |  |  | set ::accurate 0; # If true runs fuzz tests with more iterations
 | 
					
						
							| 
									
										
										
										
											2011-07-11 18:44:55 +08:00
										 |  |  | set ::force_failure 0 | 
					
						
							| 
									
										
										
										
											2020-02-21 20:48:43 +08:00
										 |  |  | set ::timeout 1200; # 20 minutes without progresses will quit the test.
 | 
					
						
							| 
									
										
										
										
											2014-11-28 18:05:58 +08:00
										 |  |  | set ::last_progress [clock seconds] | 
					
						
							| 
									
										
										
										
											2014-11-28 18:38:14 +08:00
										 |  |  | set ::active_servers {} ; # Pids of active Redis instances.
 | 
					
						
							| 
									
										
										
										
											2018-06-26 19:14:04 +08:00
										 |  |  | set ::dont_clean 0 | 
					
						
							|  |  |  | set ::wait_server 0 | 
					
						
							| 
									
										
										
										
											2018-08-03 00:49:49 +08:00
										 |  |  | set ::stop_on_failure 0 | 
					
						
							| 
									
										
										
										
											2018-08-03 01:07:17 +08:00
										 |  |  | set ::loop 0 | 
					
						
							| 
									
										
										
										
											2019-09-12 15:56:54 +08:00
										 |  |  | set ::tlsdir "tests/tls" | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | # Set to 1 when we are running in client mode. The Redis test uses a
 | 
					
						
							|  |  |  | # server-client model to run tests simultaneously. The server instance
 | 
					
						
							|  |  |  | # runs the specified number of client instances that will actually run tests.
 | 
					
						
							|  |  |  | # The server is responsible of showing the result to the user, and exit with
 | 
					
						
							|  |  |  | # the appropriate exit code depending on the test outcome.
 | 
					
						
							|  |  |  | set ::client 0 | 
					
						
							|  |  |  | set ::numclients 16 | 
					
						
							| 
									
										
										
										
											2010-05-14 23:31:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-17 16:51:12 +08:00
										 |  |  | # This function is called by one of the test clients when it receives
 | 
					
						
							|  |  |  | # a "run" command from the server, with a filename as data.
 | 
					
						
							|  |  |  | # It will run the specified test source file and signal it to the
 | 
					
						
							|  |  |  | # test server when finished.
 | 
					
						
							|  |  |  | proc execute_test_file name { | 
					
						
							| 
									
										
										
										
											2010-12-10 23:13:21 +08:00
										 |  |  |     set path "tests/$name.tcl" | 
					
						
							|  |  |  |     set ::curfile $path | 
					
						
							|  |  |  |     source $path | 
					
						
							| 
									
										
										
										
											2011-07-11 05:57:35 +08:00
										 |  |  |     send_data_packet $::test_server_fd done "$name" | 
					
						
							| 
									
										
										
										
											2010-05-14 23:31:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-17 16:51:12 +08:00
										 |  |  | # This function is called by one of the test clients when it receives
 | 
					
						
							|  |  |  | # a "run_code" command from the server, with a verbatim test source code
 | 
					
						
							|  |  |  | # as argument, and an associated name.
 | 
					
						
							|  |  |  | # It will run the specified code and signal it to the test server when
 | 
					
						
							|  |  |  | # finished.
 | 
					
						
							|  |  |  | proc execute_test_code {name code} { | 
					
						
							| 
									
										
										
										
											2020-04-16 16:05:03 +08:00
										 |  |  |     eval $code | 
					
						
							|  |  |  |     send_data_packet $::test_server_fd done "$name" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-15 02:50:32 +08:00
										 |  |  | # Setup a list to hold a stack of server configs. When calls to start_server
 | 
					
						
							|  |  |  | # are nested, use "srv 0 pid" to get the pid of the inner server. To access
 | 
					
						
							|  |  |  | # outer servers, use "srv -1 pid" etcetera.
 | 
					
						
							|  |  |  | set ::servers {} | 
					
						
							| 
									
										
										
										
											2010-08-04 20:15:52 +08:00
										 |  |  | proc srv {args} { | 
					
						
							|  |  |  |     set level 0 | 
					
						
							|  |  |  |     if {[string is integer [lindex $args 0]]} { | 
					
						
							|  |  |  |         set level [lindex $args 0] | 
					
						
							|  |  |  |         set property [lindex $args 1] | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         set property [lindex $args 0] | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-05-15 02:50:32 +08:00
										 |  |  |     set srv [lindex $::servers end+$level] | 
					
						
							|  |  |  |     dict get $srv $property | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Provide easy access to the client for the inner server. It's possible to
 | 
					
						
							|  |  |  | # prepend the argument list with a negative level to access clients for
 | 
					
						
							|  |  |  | # servers running in outer blocks.
 | 
					
						
							| 
									
										
										
										
											2010-05-14 23:31:11 +08:00
										 |  |  | proc r {args} { | 
					
						
							| 
									
										
										
										
											2010-05-15 02:50:32 +08:00
										 |  |  |     set level 0 | 
					
						
							|  |  |  |     if {[string is integer [lindex $args 0]]} { | 
					
						
							|  |  |  |         set level [lindex $args 0] | 
					
						
							|  |  |  |         set args [lrange $args 1 end] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     [srv $level "client"] {*}$args | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-10-13 17:25:40 +08:00
										 |  |  | proc reconnect {args} { | 
					
						
							|  |  |  |     set level [lindex $args 0] | 
					
						
							|  |  |  |     if {[string length $level] == 0 || ![string is integer $level]} { | 
					
						
							|  |  |  |         set level 0 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     set srv [lindex $::servers end+$level] | 
					
						
							|  |  |  |     set host [dict get $srv "host"] | 
					
						
							|  |  |  |     set port [dict get $srv "port"] | 
					
						
							|  |  |  |     set config [dict get $srv "config"] | 
					
						
							| 
									
										
										
										
											2019-09-12 15:56:54 +08:00
										 |  |  |     set client [redis $host $port 0 $::tls] | 
					
						
							| 
									
										
										
										
											2010-10-13 17:25:40 +08:00
										 |  |  |     dict set srv "client" $client | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # select the right db when we don't have to authenticate
 | 
					
						
							|  |  |  |     if {![dict exists $config "requirepass"]} { | 
					
						
							|  |  |  |         $client select 9 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # re-set $srv in the servers list
 | 
					
						
							| 
									
										
										
										
											2012-01-07 00:28:40 +08:00
										 |  |  |     lset ::servers end+$level $srv | 
					
						
							| 
									
										
										
										
											2010-10-13 17:25:40 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-16 03:16:27 +08:00
										 |  |  | proc redis_deferring_client {args} { | 
					
						
							|  |  |  |     set level 0 | 
					
						
							|  |  |  |     if {[llength $args] > 0 && [string is integer [lindex $args 0]]} { | 
					
						
							|  |  |  |         set level [lindex $args 0] | 
					
						
							|  |  |  |         set args [lrange $args 1 end] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # create client that defers reading reply
 | 
					
						
							| 
									
										
										
										
											2019-09-12 15:56:54 +08:00
										 |  |  |     set client [redis [srv $level "host"] [srv $level "port"] 1 $::tls] | 
					
						
							| 
									
										
										
										
											2010-06-16 03:16:27 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # select the right db and read the response (OK)
 | 
					
						
							|  |  |  |     $client select 9 | 
					
						
							|  |  |  |     $client read | 
					
						
							|  |  |  |     return $client | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-15 02:50:32 +08:00
										 |  |  | # Provide easy access to INFO properties. Same semantic as "proc r".
 | 
					
						
							|  |  |  | proc s {args} { | 
					
						
							|  |  |  |     set level 0 | 
					
						
							|  |  |  |     if {[string is integer [lindex $args 0]]} { | 
					
						
							|  |  |  |         set level [lindex $args 0] | 
					
						
							|  |  |  |         set args [lrange $args 1 end] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     status [srv $level "client"] [lindex $args 0] | 
					
						
							| 
									
										
										
										
											2010-05-14 23:31:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-16 16:05:03 +08:00
										 |  |  | # Test wrapped into run_solo are sent back from the client to the
 | 
					
						
							|  |  |  | # test server, so that the test server will send them again to
 | 
					
						
							|  |  |  | # clients once the clients are idle.
 | 
					
						
							|  |  |  | proc run_solo {name code} { | 
					
						
							|  |  |  |     if {$::numclients == 1 || $::loop || $::external} { | 
					
						
							|  |  |  |         # run_solo is not supported in these scenarios, just run the code.
 | 
					
						
							|  |  |  |         eval $code | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     send_data_packet $::test_server_fd run_solo [list $name $code] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-05-20 19:58:58 +08:00
										 |  |  | proc cleanup {} { | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  |     if {!$::quiet} {puts -nonewline "Cleanup: may take some time... "} | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     flush stdout | 
					
						
							| 
									
										
										
										
											2010-05-21 18:00:13 +08:00
										 |  |  |     catch {exec rm -rf {*}[glob tests/tmp/redis.conf.*]} | 
					
						
							|  |  |  |     catch {exec rm -rf {*}[glob tests/tmp/server.*]} | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  |     if {!$::quiet} {puts "OK"} | 
					
						
							| 
									
										
										
										
											2010-05-20 19:58:58 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | proc test_server_main {} { | 
					
						
							| 
									
										
										
										
											2010-10-13 15:26:44 +08:00
										 |  |  |     cleanup | 
					
						
							| 
									
										
										
										
											2013-01-24 06:37:18 +08:00
										 |  |  |     set tclsh [info nameofexecutable] | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     # Open a listening socket, trying different ports in order to find a
 | 
					
						
							|  |  |  |     # non busy one.
 | 
					
						
							| 
									
										
										
										
											2020-05-26 16:00:48 +08:00
										 |  |  |     set clientport [find_available_port 11111 32] | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  |     if {!$::quiet} { | 
					
						
							| 
									
										
										
										
											2020-05-26 16:00:48 +08:00
										 |  |  |         puts "Starting test server at port $clientport" | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-05-26 16:00:48 +08:00
										 |  |  |     socket -server accept_test_clients  -myaddr 127.0.0.1 $clientport | 
					
						
							| 
									
										
										
										
											2011-06-01 00:35:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     # Start the client instances
 | 
					
						
							| 
									
										
										
										
											2011-07-11 06:46:25 +08:00
										 |  |  |     set ::clients_pids {} | 
					
						
							| 
									
										
										
										
											2020-04-06 14:41:14 +08:00
										 |  |  |     if {$::external} { | 
					
						
							| 
									
										
										
										
											2013-01-24 06:37:18 +08:00
										 |  |  |         set p [exec $tclsh [info script] {*}$::argv \ | 
					
						
							| 
									
										
										
										
											2020-05-26 16:00:48 +08:00
										 |  |  |             --client $clientport &] | 
					
						
							| 
									
										
										
										
											2011-07-11 06:46:25 +08:00
										 |  |  |         lappend ::clients_pids $p | 
					
						
							| 
									
										
										
										
											2020-04-06 14:41:14 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2020-05-26 16:00:48 +08:00
										 |  |  |         set start_port $::baseport | 
					
						
							|  |  |  |         set port_count [expr {$::portcount / $::numclients}] | 
					
						
							| 
									
										
										
										
											2020-04-06 14:41:14 +08:00
										 |  |  |         for {set j 0} {$j < $::numclients} {incr j} { | 
					
						
							|  |  |  |             set p [exec $tclsh [info script] {*}$::argv \ | 
					
						
							| 
									
										
										
										
											2020-05-26 16:00:48 +08:00
										 |  |  |                 --client $clientport --baseport $start_port --portcount $port_count &] | 
					
						
							| 
									
										
										
										
											2020-04-06 14:41:14 +08:00
										 |  |  |             lappend ::clients_pids $p | 
					
						
							| 
									
										
										
										
											2020-05-26 16:00:48 +08:00
										 |  |  |             incr start_port $port_count | 
					
						
							| 
									
										
										
										
											2020-04-06 14:41:14 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-10-13 15:26:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     # Setup global state for the test server
 | 
					
						
							|  |  |  |     set ::idle_clients {} | 
					
						
							|  |  |  |     set ::active_clients {} | 
					
						
							| 
									
										
										
										
											2014-01-31 23:25:13 +08:00
										 |  |  |     array set ::active_clients_task {} | 
					
						
							| 
									
										
										
										
											2011-07-11 05:57:35 +08:00
										 |  |  |     array set ::clients_start_time {} | 
					
						
							|  |  |  |     set ::clients_time_history {} | 
					
						
							| 
									
										
										
										
											2011-07-11 18:44:55 +08:00
										 |  |  |     set ::failed_tests {} | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Enter the event loop to handle clients I/O
 | 
					
						
							|  |  |  |     after 100 test_server_cron | 
					
						
							|  |  |  |     vwait forever | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-28 18:05:58 +08:00
										 |  |  | # This function gets called 10 times per second.
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | proc test_server_cron {} { | 
					
						
							| 
									
										
										
										
											2014-11-28 18:05:58 +08:00
										 |  |  |     set elapsed [expr {[clock seconds]-$::last_progress}] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if {$elapsed > $::timeout} { | 
					
						
							|  |  |  |         set err "\[[colorstr red TIMEOUT]\]: clients state report follows." | 
					
						
							|  |  |  |         puts $err | 
					
						
							| 
									
										
										
										
											2018-06-26 19:14:04 +08:00
										 |  |  |         lappend ::failed_tests $err | 
					
						
							| 
									
										
										
										
											2014-11-28 18:05:58 +08:00
										 |  |  |         show_clients_state | 
					
						
							|  |  |  |         kill_clients | 
					
						
							| 
									
										
										
										
											2014-11-28 18:38:14 +08:00
										 |  |  |         force_kill_all_servers | 
					
						
							| 
									
										
										
										
											2014-11-28 18:05:58 +08:00
										 |  |  |         the_end | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-31 23:25:13 +08:00
										 |  |  |     after 100 test_server_cron | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | proc accept_test_clients {fd addr port} { | 
					
						
							| 
									
										
										
										
											2014-01-31 23:25:13 +08:00
										 |  |  |     fconfigure $fd -encoding binary | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     fileevent $fd readable [list read_from_test_client $fd] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # This is the readable handler of our test server. Clients send us messages
 | 
					
						
							|  |  |  | # in the form of a status code such and additional data. Supported
 | 
					
						
							|  |  |  | # status types are:
 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # ready: the client is ready to execute the command. Only sent at client
 | 
					
						
							|  |  |  | #        startup. The server will queue the client FD in the list of idle
 | 
					
						
							|  |  |  | #        clients.
 | 
					
						
							|  |  |  | # testing: just used to signal that a given test started.
 | 
					
						
							|  |  |  | # ok: a test was executed with success.
 | 
					
						
							|  |  |  | # err: a test was executed with an error.
 | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  | # skip: a test was skipped by skipfile or individual test options.
 | 
					
						
							|  |  |  | # ignore: a test was skipped by a group tag.
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | # exception: there was a runtime exception while executing the test.
 | 
					
						
							|  |  |  | # done: all the specified test file was processed, this test client is
 | 
					
						
							|  |  |  | #       ready to accept a new task.
 | 
					
						
							|  |  |  | proc read_from_test_client fd { | 
					
						
							|  |  |  |     set bytes [gets $fd] | 
					
						
							|  |  |  |     set payload [read $fd $bytes] | 
					
						
							|  |  |  |     foreach {status data} $payload break | 
					
						
							| 
									
										
										
										
											2014-11-28 18:05:58 +08:00
										 |  |  |     set ::last_progress [clock seconds] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     if {$status eq {ready}} { | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  |         if {!$::quiet} { | 
					
						
							|  |  |  |             puts "\[$status\]: $data" | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |         signal_idle_client $fd | 
					
						
							|  |  |  |     } elseif {$status eq {done}} { | 
					
						
							| 
									
										
										
										
											2011-07-11 05:57:35 +08:00
										 |  |  |         set elapsed [expr {[clock seconds]-$::clients_start_time($fd)}] | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  |         set all_tests_count [llength $::all_tests] | 
					
						
							|  |  |  |         set running_tests_count [expr {[llength $::active_clients]-1}] | 
					
						
							|  |  |  |         set completed_tests_count [expr {$::next_test-$running_tests_count}] | 
					
						
							|  |  |  |         puts "\[$completed_tests_count/$all_tests_count [colorstr yellow $status]\]: $data ($elapsed seconds)" | 
					
						
							| 
									
										
										
										
											2011-07-11 05:57:35 +08:00
										 |  |  |         lappend ::clients_time_history $elapsed $data | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |         signal_idle_client $fd | 
					
						
							| 
									
										
										
										
											2020-02-22 00:08:45 +08:00
										 |  |  |         set ::active_clients_task($fd) "(DONE) $data" | 
					
						
							| 
									
										
										
										
											2011-07-11 06:09:56 +08:00
										 |  |  |     } elseif {$status eq {ok}} { | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  |         if {!$::quiet} { | 
					
						
							|  |  |  |             puts "\[[colorstr green $status]\]: $data" | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-01-31 23:25:13 +08:00
										 |  |  |         set ::active_clients_task($fd) "(OK) $data" | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  |     } elseif {$status eq {skip}} { | 
					
						
							|  |  |  |         if {!$::quiet} { | 
					
						
							|  |  |  |             puts "\[[colorstr yellow $status]\]: $data" | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } elseif {$status eq {ignore}} { | 
					
						
							|  |  |  |         if {!$::quiet} { | 
					
						
							|  |  |  |             puts "\[[colorstr cyan $status]\]: $data" | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-07-11 06:09:56 +08:00
										 |  |  |     } elseif {$status eq {err}} { | 
					
						
							| 
									
										
										
										
											2011-07-11 18:44:55 +08:00
										 |  |  |         set err "\[[colorstr red $status]\]: $data" | 
					
						
							|  |  |  |         puts $err | 
					
						
							|  |  |  |         lappend ::failed_tests $err | 
					
						
							| 
									
										
										
										
											2014-01-31 23:25:13 +08:00
										 |  |  |         set ::active_clients_task($fd) "(ERR) $data" | 
					
						
							| 
									
										
										
										
											2018-08-03 00:49:49 +08:00
										 |  |  |             if {$::stop_on_failure} { | 
					
						
							|  |  |  |             puts -nonewline "(Test stopped, press enter to continue)" | 
					
						
							|  |  |  |             flush stdout | 
					
						
							|  |  |  |             gets stdin | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-07-11 06:46:25 +08:00
										 |  |  |     } elseif {$status eq {exception}} { | 
					
						
							|  |  |  |         puts "\[[colorstr red $status]\]: $data" | 
					
						
							| 
									
										
										
										
											2014-11-28 18:05:58 +08:00
										 |  |  |         kill_clients | 
					
						
							| 
									
										
										
										
											2014-11-28 18:38:14 +08:00
										 |  |  |         force_kill_all_servers | 
					
						
							| 
									
										
										
										
											2011-07-11 06:46:25 +08:00
										 |  |  |         exit 1 | 
					
						
							| 
									
										
										
										
											2011-07-11 06:53:30 +08:00
										 |  |  |     } elseif {$status eq {testing}} { | 
					
						
							| 
									
										
										
										
											2014-01-31 23:25:13 +08:00
										 |  |  |         set ::active_clients_task($fd) "(IN PROGRESS) $data" | 
					
						
							| 
									
										
										
										
											2020-02-22 00:08:45 +08:00
										 |  |  |     } elseif {$status eq {server-spawning}} { | 
					
						
							|  |  |  |         set ::active_clients_task($fd) "(SPAWNING SERVER) $data" | 
					
						
							| 
									
										
										
										
											2014-11-28 18:38:14 +08:00
										 |  |  |     } elseif {$status eq {server-spawned}} { | 
					
						
							|  |  |  |         lappend ::active_servers $data | 
					
						
							| 
									
										
										
										
											2020-02-22 00:08:45 +08:00
										 |  |  |         set ::active_clients_task($fd) "(SPAWNED SERVER) pid:$data" | 
					
						
							|  |  |  |     } elseif {$status eq {server-killing}} { | 
					
						
							|  |  |  |         set ::active_clients_task($fd) "(KILLING SERVER) pid:$data" | 
					
						
							| 
									
										
										
										
											2014-11-28 18:38:14 +08:00
										 |  |  |     } elseif {$status eq {server-killed}} { | 
					
						
							|  |  |  |         set ::active_servers [lsearch -all -inline -not -exact $::active_servers $data] | 
					
						
							| 
									
										
										
										
											2020-02-22 00:08:45 +08:00
										 |  |  |         set ::active_clients_task($fd) "(KILLED SERVER) pid:$data" | 
					
						
							| 
									
										
										
										
											2020-04-16 16:05:03 +08:00
										 |  |  |     } elseif {$status eq {run_solo}} { | 
					
						
							|  |  |  |         lappend ::run_solo_tests $data | 
					
						
							| 
									
										
										
										
											2010-10-13 15:26:44 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  |         if {!$::quiet} { | 
					
						
							|  |  |  |             puts "\[$status\]: $data" | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-10-13 15:26:44 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-07-23 19:08:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-28 18:05:58 +08:00
										 |  |  | proc show_clients_state {} { | 
					
						
							|  |  |  |     # The following loop is only useful for debugging tests that may
 | 
					
						
							| 
									
										
										
										
											2020-02-22 00:08:45 +08:00
										 |  |  |     # enter an infinite loop.
 | 
					
						
							| 
									
										
										
										
											2014-11-28 18:05:58 +08:00
										 |  |  |     foreach x $::active_clients { | 
					
						
							|  |  |  |         if {[info exist ::active_clients_task($x)]} { | 
					
						
							|  |  |  |             puts "$x => $::active_clients_task($x)" | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             puts "$x => ???" | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | proc kill_clients {} { | 
					
						
							|  |  |  |     foreach p $::clients_pids { | 
					
						
							|  |  |  |         catch {exec kill $p} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-28 18:38:14 +08:00
										 |  |  | proc force_kill_all_servers {} { | 
					
						
							|  |  |  |     foreach p $::active_servers { | 
					
						
							|  |  |  |         puts "Killing still running Redis server $p" | 
					
						
							|  |  |  |         catch {exec kill -9 $p} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-16 16:05:03 +08:00
										 |  |  | proc lpop {listVar {count 1}} { | 
					
						
							|  |  |  |     upvar 1 $listVar l | 
					
						
							|  |  |  |     set ele [lindex $l 0] | 
					
						
							|  |  |  |     set l [lrange $l 1 end] | 
					
						
							|  |  |  |     set ele | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | # A new client is idle. Remove it from the list of active clients and
 | 
					
						
							|  |  |  | # if there are still test units to run, launch them.
 | 
					
						
							|  |  |  | proc signal_idle_client fd { | 
					
						
							|  |  |  |     # Remove this fd from the list of active clients.
 | 
					
						
							|  |  |  |     set ::active_clients \ | 
					
						
							|  |  |  |         [lsearch -all -inline -not -exact $::active_clients $fd] | 
					
						
							| 
									
										
										
										
											2014-01-31 23:25:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     # New unit to process?
 | 
					
						
							|  |  |  |     if {$::next_test != [llength $::all_tests]} { | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  |         if {!$::quiet} { | 
					
						
							|  |  |  |             puts [colorstr bold-white "Testing [lindex $::all_tests $::next_test]"] | 
					
						
							| 
									
										
										
										
											2014-01-31 23:25:13 +08:00
										 |  |  |             set ::active_clients_task($fd) "ASSIGNED: $fd ([lindex $::all_tests $::next_test])" | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-07-11 05:57:35 +08:00
										 |  |  |         set ::clients_start_time($fd) [clock seconds] | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |         send_data_packet $fd run [lindex $::all_tests $::next_test] | 
					
						
							|  |  |  |         lappend ::active_clients $fd | 
					
						
							|  |  |  |         incr ::next_test | 
					
						
							| 
									
										
										
										
											2018-08-03 01:07:17 +08:00
										 |  |  |         if {$::loop && $::next_test == [llength $::all_tests]} { | 
					
						
							|  |  |  |             set ::next_test 0 | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-04-16 16:05:03 +08:00
										 |  |  |     } elseif {[llength $::run_solo_tests] != 0 && [llength $::active_clients] == 0} { | 
					
						
							|  |  |  |         if {!$::quiet} { | 
					
						
							|  |  |  |             puts [colorstr bold-white "Testing solo test"] | 
					
						
							|  |  |  |             set ::active_clients_task($fd) "ASSIGNED: $fd solo test" | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         set ::clients_start_time($fd) [clock seconds] | 
					
						
							|  |  |  |         send_data_packet $fd run_code [lpop ::run_solo_tests] | 
					
						
							|  |  |  |         lappend ::active_clients $fd | 
					
						
							| 
									
										
										
										
											2010-10-13 15:26:44 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |         lappend ::idle_clients $fd | 
					
						
							| 
									
										
										
										
											2020-02-22 00:08:45 +08:00
										 |  |  |         set ::active_clients_task($fd) "SLEEPING, no more units to assign" | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |         if {[llength $::active_clients] == 0} { | 
					
						
							|  |  |  |             the_end | 
					
						
							| 
									
										
										
										
											2010-12-10 23:13:21 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-10-13 15:26:44 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2010-12-10 23:13:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-17 12:02:38 +08:00
										 |  |  | # The the_end function gets called when all the test units were already
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | # executed, so the test finished.
 | 
					
						
							|  |  |  | proc the_end {} { | 
					
						
							|  |  |  |     # TODO: print the status, exit with the rigth exit code.
 | 
					
						
							| 
									
										
										
										
											2011-07-11 18:44:55 +08:00
										 |  |  |     puts "\n                   The End\n" | 
					
						
							| 
									
										
										
										
											2011-07-11 05:57:35 +08:00
										 |  |  |     puts "Execution time of different units:" | 
					
						
							|  |  |  |     foreach {time name} $::clients_time_history { | 
					
						
							|  |  |  |         puts "  $time seconds - $name" | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-07-11 18:44:55 +08:00
										 |  |  |     if {[llength $::failed_tests]} { | 
					
						
							| 
									
										
										
										
											2011-07-11 18:56:00 +08:00
										 |  |  |         puts "\n[colorstr bold-red {!!! WARNING}] The following tests failed:\n" | 
					
						
							| 
									
										
										
										
											2011-07-11 18:44:55 +08:00
										 |  |  |         foreach failed $::failed_tests { | 
					
						
							|  |  |  |             puts "*** $failed" | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-05-05 19:18:53 +08:00
										 |  |  |         if {!$::dont_clean} cleanup | 
					
						
							| 
									
										
										
										
											2010-07-23 19:08:35 +08:00
										 |  |  |         exit 1 | 
					
						
							| 
									
										
										
										
											2011-07-11 18:44:55 +08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         puts "\n[colorstr bold-white {\o/}] [colorstr bold-green {All tests passed without errors!}]\n" | 
					
						
							| 
									
										
										
										
											2020-05-05 19:18:53 +08:00
										 |  |  |         if {!$::dont_clean} cleanup | 
					
						
							| 
									
										
										
										
											2011-07-11 18:44:55 +08:00
										 |  |  |         exit 0 | 
					
						
							| 
									
										
										
										
											2010-05-14 23:31:11 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | # The client is not even driven (the test server is instead) as we just need
 | 
					
						
							|  |  |  | # to read the command, execute, reply... all this in a loop.
 | 
					
						
							|  |  |  | proc test_client_main server_port { | 
					
						
							|  |  |  |     set ::test_server_fd [socket localhost $server_port] | 
					
						
							| 
									
										
										
										
											2014-01-31 23:25:13 +08:00
										 |  |  |     fconfigure $::test_server_fd -encoding binary | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     send_data_packet $::test_server_fd ready [pid] | 
					
						
							|  |  |  |     while 1 { | 
					
						
							|  |  |  |         set bytes [gets $::test_server_fd] | 
					
						
							|  |  |  |         set payload [read $::test_server_fd $bytes] | 
					
						
							|  |  |  |         foreach {cmd data} $payload break | 
					
						
							|  |  |  |         if {$cmd eq {run}} { | 
					
						
							| 
									
										
										
										
											2020-04-17 16:51:12 +08:00
										 |  |  |             execute_test_file $data | 
					
						
							| 
									
										
										
										
											2020-04-16 16:05:03 +08:00
										 |  |  |         } elseif {$cmd eq {run_code}} { | 
					
						
							|  |  |  |             foreach {name code} $data break | 
					
						
							| 
									
										
										
										
											2020-04-17 16:51:12 +08:00
										 |  |  |             execute_test_code $name $code | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             error "Unknown test client command: $cmd" | 
					
						
							| 
									
										
										
										
											2010-12-10 23:13:21 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2010-05-14 23:31:11 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-07-06 21:22:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | proc send_data_packet {fd status data} { | 
					
						
							|  |  |  |     set payload [list $status $data] | 
					
						
							|  |  |  |     puts $fd [string length $payload] | 
					
						
							|  |  |  |     puts -nonewline $fd $payload | 
					
						
							|  |  |  |     flush $fd | 
					
						
							| 
									
										
										
										
											2010-05-14 23:31:11 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 19:03:22 +08:00
										 |  |  | proc print_help_screen {} { | 
					
						
							|  |  |  |     puts [join { | 
					
						
							|  |  |  |         "--valgrind         Run the test over valgrind." | 
					
						
							| 
									
										
										
										
											2015-09-23 16:34:00 +08:00
										 |  |  |         "--stack-logging    Enable OSX leaks/malloc stack logging." | 
					
						
							| 
									
										
										
										
											2011-07-11 19:03:22 +08:00
										 |  |  |         "--accurate         Run slow randomized tests for more iterations." | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  |         "--quiet            Don't show individual tests." | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  |         "--single <unit>    Just execute the specified unit (see next option). this option can be repeated." | 
					
						
							| 
									
										
										
										
											2011-07-11 19:03:22 +08:00
										 |  |  |         "--list-tests       List all the available test units." | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  |         "--only <test>      Just execute the specified test by test name. this option can be repeated." | 
					
						
							| 
									
										
										
										
											2018-07-31 23:28:30 +08:00
										 |  |  |         "--skip-till <unit> Skip all units until (and including) the specified one." | 
					
						
							| 
									
										
										
										
											2014-11-28 18:38:14 +08:00
										 |  |  |         "--clients <num>    Number of test clients (default 16)." | 
					
						
							|  |  |  |         "--timeout <sec>    Test timeout in seconds (default 10 min)." | 
					
						
							| 
									
										
										
										
											2011-07-11 19:03:22 +08:00
										 |  |  |         "--force-failure    Force the execution of a test that always fails." | 
					
						
							| 
									
										
										
										
											2018-08-03 01:07:17 +08:00
										 |  |  |         "--config <k> <v>   Extra config file argument." | 
					
						
							|  |  |  |         "--skipfile <file>  Name of a file containing test names that should be skipped (one per line)." | 
					
						
							|  |  |  |         "--dont-clean       Don't delete redis log files after the run." | 
					
						
							|  |  |  |         "--stop             Blocks once the first test fails." | 
					
						
							|  |  |  |         "--loop             Execute the specified set of tests forever." | 
					
						
							|  |  |  |         "--wait-server      Wait after server is started (so that you can attach a debugger)." | 
					
						
							| 
									
										
										
										
											2019-09-12 15:56:54 +08:00
										 |  |  |         "--tls              Run tests in TLS mode." | 
					
						
							| 
									
										
										
										
											2020-05-26 16:00:48 +08:00
										 |  |  |         "--host <addr>      Run tests against an external host." | 
					
						
							|  |  |  |         "--port <port>      TCP port to use against external host." | 
					
						
							|  |  |  |         "--baseport <port>  Initial port number for spawned redis servers." | 
					
						
							|  |  |  |         "--portcount <num>  Port range for spawned redis servers." | 
					
						
							| 
									
										
										
										
											2011-07-11 19:03:22 +08:00
										 |  |  |         "--help             Print this help screen." | 
					
						
							|  |  |  |     } "\n"] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-03 05:04:22 +08:00
										 |  |  | # parse arguments
 | 
					
						
							|  |  |  | for {set j 0} {$j < [llength $argv]} {incr j} { | 
					
						
							|  |  |  |     set opt [lindex $argv $j] | 
					
						
							|  |  |  |     set arg [lindex $argv [expr $j+1]] | 
					
						
							|  |  |  |     if {$opt eq {--tags}} { | 
					
						
							|  |  |  |         foreach tag $arg { | 
					
						
							|  |  |  |             if {[string index $tag 0] eq "-"} { | 
					
						
							|  |  |  |                 lappend ::denytags [string range $tag 1 end] | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 lappend ::allowtags $tag | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         incr j | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  |     } elseif {$opt eq {--config}} { | 
					
						
							|  |  |  |         set arg2 [lindex $argv [expr $j+2]] | 
					
						
							|  |  |  |         lappend ::global_overrides $arg | 
					
						
							|  |  |  |         lappend ::global_overrides $arg2 | 
					
						
							| 
									
										
										
										
											2018-07-31 23:28:30 +08:00
										 |  |  |         incr j 2 | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  |     } elseif {$opt eq {--skipfile}} { | 
					
						
							|  |  |  |         incr j | 
					
						
							|  |  |  |         set fp [open $arg r] | 
					
						
							|  |  |  |         set file_data [read $fp] | 
					
						
							|  |  |  |         close $fp | 
					
						
							|  |  |  |         set ::skiptests [split $file_data "\n"] | 
					
						
							| 
									
										
										
										
											2010-12-10 22:40:48 +08:00
										 |  |  |     } elseif {$opt eq {--valgrind}} { | 
					
						
							|  |  |  |         set ::valgrind 1 | 
					
						
							| 
									
										
										
										
											2015-09-23 16:34:00 +08:00
										 |  |  |     } elseif {$opt eq {--stack-logging}} { | 
					
						
							|  |  |  |         if {[string match {*Darwin*} [exec uname -a]]} { | 
					
						
							|  |  |  |             set ::stack_logging 1 | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-11-29 23:29:12 +08:00
										 |  |  |     } elseif {$opt eq {--quiet}} { | 
					
						
							|  |  |  |         set ::quiet 1 | 
					
						
							| 
									
										
										
										
											2019-09-12 15:56:54 +08:00
										 |  |  |     } elseif {$opt eq {--tls}} { | 
					
						
							|  |  |  |         package require tls 1.6 | 
					
						
							|  |  |  |         set ::tls 1 | 
					
						
							|  |  |  |         ::tls::init \ | 
					
						
							|  |  |  |             -cafile "$::tlsdir/ca.crt" \ | 
					
						
							|  |  |  |             -certfile "$::tlsdir/redis.crt" \ | 
					
						
							|  |  |  |             -keyfile "$::tlsdir/redis.key" | 
					
						
							| 
									
										
										
										
											2010-06-14 16:19:45 +08:00
										 |  |  |     } elseif {$opt eq {--host}} { | 
					
						
							|  |  |  |         set ::external 1 | 
					
						
							|  |  |  |         set ::host $arg | 
					
						
							|  |  |  |         incr j | 
					
						
							|  |  |  |     } elseif {$opt eq {--port}} { | 
					
						
							|  |  |  |         set ::port $arg | 
					
						
							|  |  |  |         incr j | 
					
						
							| 
									
										
										
										
											2020-05-26 16:00:48 +08:00
										 |  |  |     } elseif {$opt eq {--baseport}} { | 
					
						
							|  |  |  |         set ::baseport $arg | 
					
						
							|  |  |  |         incr j | 
					
						
							|  |  |  |     } elseif {$opt eq {--portcount}} { | 
					
						
							|  |  |  |         set ::portcount $arg | 
					
						
							|  |  |  |         incr j | 
					
						
							| 
									
										
										
										
											2011-07-11 17:59:55 +08:00
										 |  |  |     } elseif {$opt eq {--accurate}} { | 
					
						
							|  |  |  |         set ::accurate 1 | 
					
						
							| 
									
										
										
										
											2011-07-11 18:44:55 +08:00
										 |  |  |     } elseif {$opt eq {--force-failure}} { | 
					
						
							|  |  |  |         set ::force_failure 1 | 
					
						
							| 
									
										
										
										
											2011-07-11 17:59:55 +08:00
										 |  |  |     } elseif {$opt eq {--single}} { | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  |         lappend ::single_tests $arg | 
					
						
							|  |  |  |         incr j | 
					
						
							|  |  |  |     } elseif {$opt eq {--only}} { | 
					
						
							|  |  |  |         lappend ::only_tests $arg | 
					
						
							|  |  |  |         incr j | 
					
						
							| 
									
										
										
										
											2019-05-10 16:27:25 +08:00
										 |  |  |     } elseif {$opt eq {--skip-till}} { | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  |         set ::skip_till $arg | 
					
						
							| 
									
										
										
										
											2011-07-11 17:59:55 +08:00
										 |  |  |         incr j | 
					
						
							|  |  |  |     } elseif {$opt eq {--list-tests}} { | 
					
						
							|  |  |  |         foreach t $::all_tests { | 
					
						
							|  |  |  |             puts $t | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         exit 0 | 
					
						
							| 
									
										
										
										
											2018-02-18 23:36:21 +08:00
										 |  |  |     } elseif {$opt eq {--verbose}} { | 
					
						
							|  |  |  |         set ::verbose 1 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     } elseif {$opt eq {--client}} { | 
					
						
							|  |  |  |         set ::client 1 | 
					
						
							|  |  |  |         set ::test_server_port $arg | 
					
						
							|  |  |  |         incr j | 
					
						
							| 
									
										
										
										
											2012-04-03 19:32:49 +08:00
										 |  |  |     } elseif {$opt eq {--clients}} { | 
					
						
							|  |  |  |         set ::numclients $arg | 
					
						
							|  |  |  |         incr j | 
					
						
							| 
									
										
										
										
											2018-06-26 19:14:04 +08:00
										 |  |  |     } elseif {$opt eq {--dont-clean}} { | 
					
						
							|  |  |  |         set ::dont_clean 1 | 
					
						
							|  |  |  |     } elseif {$opt eq {--wait-server}} { | 
					
						
							|  |  |  |         set ::wait_server 1 | 
					
						
							| 
									
										
										
										
											2018-08-03 00:49:49 +08:00
										 |  |  |     } elseif {$opt eq {--stop}} { | 
					
						
							|  |  |  |         set ::stop_on_failure 1 | 
					
						
							| 
									
										
										
										
											2018-08-03 01:07:17 +08:00
										 |  |  |     } elseif {$opt eq {--loop}} { | 
					
						
							|  |  |  |         set ::loop 1 | 
					
						
							| 
									
										
										
										
											2014-11-28 18:38:14 +08:00
										 |  |  |     } elseif {$opt eq {--timeout}} { | 
					
						
							|  |  |  |         set ::timeout $arg | 
					
						
							|  |  |  |         incr j | 
					
						
							| 
									
										
										
										
											2011-07-11 17:59:55 +08:00
										 |  |  |     } elseif {$opt eq {--help}} { | 
					
						
							| 
									
										
										
										
											2011-07-11 19:03:22 +08:00
										 |  |  |         print_help_screen | 
					
						
							| 
									
										
										
										
											2011-07-11 17:59:55 +08:00
										 |  |  |         exit 0 | 
					
						
							| 
									
										
										
										
											2010-06-03 05:04:22 +08:00
										 |  |  |     } else { | 
					
						
							|  |  |  |         puts "Wrong argument: $opt" | 
					
						
							|  |  |  |         exit 1 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-31 23:28:30 +08:00
										 |  |  | # If --skil-till option was given, we populate the list of single tests
 | 
					
						
							|  |  |  | # to run with everything *after* the specified unit.
 | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  | if {$::skip_till != ""} { | 
					
						
							|  |  |  |     set skipping 1 | 
					
						
							|  |  |  |     foreach t $::all_tests { | 
					
						
							|  |  |  |         if {$skipping == 0} { | 
					
						
							|  |  |  |             lappend ::single_tests $t | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if {$t == $::skip_till} { | 
					
						
							|  |  |  |             set skipping 0 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if {$skipping} { | 
					
						
							|  |  |  |         puts "test $::skip_till not found" | 
					
						
							|  |  |  |         exit 0 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-31 23:28:30 +08:00
										 |  |  | # Override the list of tests with the specific tests we want to run
 | 
					
						
							|  |  |  | # in case there was some filter, that is --single or --skip-till options.
 | 
					
						
							| 
									
										
										
										
											2018-07-30 21:43:21 +08:00
										 |  |  | if {[llength $::single_tests] > 0} { | 
					
						
							|  |  |  |     set ::all_tests $::single_tests | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-27 18:29:47 +08:00
										 |  |  | proc attach_to_replication_stream {} { | 
					
						
							| 
									
										
										
										
											2019-09-12 15:56:54 +08:00
										 |  |  |     if {$::tls} { | 
					
						
							|  |  |  |         set s [::tls::socket [srv 0 "host"] [srv 0 "port"]] | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         set s [socket [srv 0 "host"] [srv 0 "port"]] | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-03-27 18:29:47 +08:00
										 |  |  |     fconfigure $s -translation binary | 
					
						
							|  |  |  |     puts -nonewline $s "SYNC\r\n" | 
					
						
							|  |  |  |     flush $s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Get the count
 | 
					
						
							| 
									
										
										
										
											2015-10-08 04:32:24 +08:00
										 |  |  |     while 1 { | 
					
						
							|  |  |  |         set count [gets $s] | 
					
						
							|  |  |  |         set prefix [string range $count 0 0] | 
					
						
							|  |  |  |         if {$prefix ne {}} break; # Newlines are allowed as PINGs.
 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-03-27 18:29:47 +08:00
										 |  |  |     if {$prefix ne {$}} { | 
					
						
							|  |  |  |         error "attach_to_replication_stream error. Received '$count' as count." | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     set count [string range $count 1 end] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Consume the bulk payload
 | 
					
						
							|  |  |  |     while {$count} { | 
					
						
							|  |  |  |         set buf [read $s $count] | 
					
						
							|  |  |  |         set count [expr {$count-[string length $buf]}] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return $s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | proc read_from_replication_stream {s} { | 
					
						
							|  |  |  |     fconfigure $s -blocking 0 | 
					
						
							|  |  |  |     set attempt 0 | 
					
						
							|  |  |  |     while {[gets $s count] == -1} { | 
					
						
							|  |  |  |         if {[incr attempt] == 10} return "" | 
					
						
							|  |  |  |         after 100 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     fconfigure $s -blocking 1 | 
					
						
							|  |  |  |     set count [string range $count 1 end] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Return a list of arguments for the command.
 | 
					
						
							|  |  |  |     set res {} | 
					
						
							|  |  |  |     for {set j 0} {$j < $count} {incr j} { | 
					
						
							|  |  |  |         read $s 1 | 
					
						
							|  |  |  |         set arg [::redis::redis_bulk_read $s] | 
					
						
							|  |  |  |         if {$j == 0} {set arg [string tolower $arg]} | 
					
						
							|  |  |  |         lappend res $arg | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return $res | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | proc assert_replication_stream {s patterns} { | 
					
						
							|  |  |  |     for {set j 0} {$j < [llength $patterns]} {incr j} { | 
					
						
							|  |  |  |         assert_match [lindex $patterns $j] [read_from_replication_stream $s] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | proc close_replication_stream {s} { | 
					
						
							|  |  |  |     close $s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-11 23:26:09 +08:00
										 |  |  | # With the parallel test running multiple Redis instances at the same time
 | 
					
						
							|  |  |  | # we need a fast enough computer, otherwise a lot of tests may generate
 | 
					
						
							|  |  |  | # false positives.
 | 
					
						
							| 
									
										
										
										
											2013-08-07 22:05:09 +08:00
										 |  |  | # If the computer is too slow we revert the sequential test without any
 | 
					
						
							| 
									
										
										
										
											2012-05-11 23:26:09 +08:00
										 |  |  | # parallelism, that is, clients == 1.
 | 
					
						
							|  |  |  | proc is_a_slow_computer {} { | 
					
						
							|  |  |  |     set start [clock milliseconds] | 
					
						
							|  |  |  |     for {set j 0} {$j < 1000000} {incr j} {} | 
					
						
							|  |  |  |     set elapsed [expr [clock milliseconds]-$start] | 
					
						
							|  |  |  |     expr {$elapsed > 200} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | if {$::client} { | 
					
						
							|  |  |  |     if {[catch { test_client_main $::test_server_port } err]} { | 
					
						
							|  |  |  |         set estr "Executing test client: $err.\n$::errorInfo" | 
					
						
							|  |  |  |         if {[catch {send_data_packet $::test_server_fd exception $estr}]} { | 
					
						
							|  |  |  |             puts $estr | 
					
						
							| 
									
										
										
										
											2010-06-03 03:20:29 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |         exit 1 | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  | } else { | 
					
						
							| 
									
										
										
										
											2012-05-11 23:26:09 +08:00
										 |  |  |     if {[is_a_slow_computer]} { | 
					
						
							|  |  |  |         puts "** SLOW COMPUTER ** Using a single client to avoid false positives." | 
					
						
							|  |  |  |         set ::numclients 1 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-11 05:25:48 +08:00
										 |  |  |     if {[catch { test_server_main } err]} { | 
					
						
							|  |  |  |         if {[string length $err] > 0} { | 
					
						
							|  |  |  |             # only display error when not generated by the test suite
 | 
					
						
							|  |  |  |             if {$err ne "exception"} { | 
					
						
							|  |  |  |                 puts $::errorInfo | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             exit 1 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-06-03 03:20:29 +08:00
										 |  |  | } |