1241 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			Perl
		
	
	
	
		
		
			
		
	
	
			1241 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			Perl
		
	
	
	
|  | #!/usr/bin/perl | ||
|  | 
 | ||
|  | # Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. | ||
|  | # | ||
|  | # This program is free software; you can redistribute it and/or | ||
|  | # modify it under the terms of the GNU Library General Public | ||
|  | # License as published by the Free Software Foundation; version 2 | ||
|  | # of the License. | ||
|  | # | ||
|  | # This program is distributed in the hope that it will be useful, | ||
|  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||
|  | # Library General Public License for more details. | ||
|  | # | ||
|  | # You should have received a copy of the GNU General Public License | ||
|  | # along with this program; if not, write to the Free Software | ||
|  | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||
|  | 
 | ||
|  | # ====================================================================== | ||
|  | #                     MySQL server stress test system  | ||
|  | # ====================================================================== | ||
|  | # | ||
|  | ########################################################################## | ||
|  | # | ||
|  | #                       SCENARIOS AND REQUIREMENTS | ||
|  | # | ||
|  | #   The system should perform stress testing of MySQL server with  | ||
|  | # following requirements and basic scenarios: | ||
|  | #  | ||
|  | # Basic requirements: | ||
|  | #  | ||
|  | # Design of stress script should allow one: | ||
|  | #  | ||
|  | #   - to use for stress testing mysqltest binary as test engine | ||
|  | #   - to use for stress testing both regular test suite and any | ||
|  | #     additional test suites (e.g. mysql-test-extra-5.0) | ||
|  | #   - to specify files with lists of tests both for initialization of | ||
|  | #     stress db and for further testing itself | ||
|  | #   - to define number of threads that will be concurrently used in testing | ||
|  | #   - to define limitations for test run. e.g. number of tests or loops | ||
|  | #     for execution or duration of testing, delay between test executions, etc. | ||
|  | #   - to get readable log file which can be used for identification of | ||
|  | #     errors arose during testing | ||
|  | #  | ||
|  | # Basic scenarios: | ||
|  | #  | ||
|  | #     * It should be possible to run stress script in standalone mode | ||
|  | #       which will allow to create various scenarios of stress workloads: | ||
|  | #  | ||
|  | #       simple ones: | ||
|  | # | ||
|  | #         box #1: | ||
|  | #           - one instance of script with list of tests #1 | ||
|  | #  | ||
|  | #       and more advanced ones: | ||
|  | #  | ||
|  | #         box #1: | ||
|  | #           - one instance of script with list of tests #1 | ||
|  | #           - another instance of script with list of tests #2 | ||
|  | #         box #2: | ||
|  | #           - one instance of script with list of tests #3 | ||
|  | #           - another instance of script with list of tests #4 | ||
|  | #             that will recreate whole database to back it to clean | ||
|  | #             state | ||
|  | #  | ||
|  | #       One kind of such complex scenarios maybe continued testing | ||
|  | #       when we want to run stress tests from many boxes with various | ||
|  | #       lists of tests that will last very long time. And in such case | ||
|  | #       we need some wrapper for MySQL server that will restart it in | ||
|  | #       case of crashes. | ||
|  | #  | ||
|  | #     * It should be possible to run stress script in ad-hoc mode from | ||
|  | #       shell or perl versions of mysql-test-run. This allows developers | ||
|  | #       to reproduce and debug errors that was found in continued stress  | ||
|  | #       testing | ||
|  | # | ||
|  | # 2009-01-28 OBN Additions and modifications per WL#4685 | ||
|  | #                 | ||
|  | ######################################################################## | ||
|  | 
 | ||
|  | use Config; | ||
|  | 
 | ||
|  | if (!defined($Config{useithreads})) | ||
|  | { | ||
|  |   die <<EOF; | ||
|  | It is unable to run threaded version of stress test on this system  | ||
|  | due to disabled ithreads. Please check that installed perl binary  | ||
|  | was built with support of ithreads.  | ||
|  | EOF | ||
|  | } | ||
|  | 
 | ||
|  | use threads; | ||
|  | use threads::shared; | ||
|  | 
 | ||
|  | use IO::Socket; | ||
|  | use Sys::Hostname; | ||
|  | use File::Copy; | ||
|  | use File::Spec; | ||
|  | use File::Find; | ||
|  | use File::Basename; | ||
|  | use File::Path; | ||
|  | use Cwd; | ||
|  | 
 | ||
|  | use Data::Dumper; | ||
|  | use Getopt::Long; | ||
|  | 
 | ||
|  | my $stress_suite_version="1.0"; | ||
|  | 
 | ||
|  | $|=1; | ||
|  | 
 | ||
|  | $opt_server_host=""; | ||
|  | $opt_server_logs_dir=""; | ||
|  | $opt_help=""; | ||
|  | $opt_server_port=""; | ||
|  | $opt_server_socket=""; | ||
|  | $opt_server_user=""; | ||
|  | $opt_server_password=""; | ||
|  | $opt_server_database=""; | ||
|  | $opt_cleanup=""; | ||
|  | $opt_verbose=""; | ||
|  | $opt_log_error_details=""; | ||
|  | 
 | ||
|  | 
 | ||
|  | $opt_suite="main"; | ||
|  | $opt_stress_suite_basedir=""; | ||
|  | $opt_stress_basedir=""; | ||
|  | $opt_stress_datadir=""; | ||
|  | $opt_test_suffix=""; | ||
|  | 
 | ||
|  | $opt_stress_mode="random"; | ||
|  | 
 | ||
|  | $opt_loop_count=0; | ||
|  | $opt_test_count=0; | ||
|  | $opt_test_duration=0; | ||
|  | # OBN: Changing abort-on-error default to -1 (for WL-4626/4685): -1 means no abort | ||
|  | $opt_abort_on_error=-1; | ||
|  | $opt_sleep_time = 0; | ||
|  | $opt_threads=1; | ||
|  | $pid_file="mysql_stress_test.pid"; | ||
|  | $opt_mysqltest= ($^O =~ /mswin32/i) ? "mysqltest.exe" : "mysqltest"; | ||
|  | $opt_check_tests_file=""; | ||
|  | # OBM adding a setting for 'max-connect-retries=20' the default of 500 is to high   | ||
|  | @mysqltest_args=("--silent", "-v", "--skip-safemalloc", "--max-connect-retries=20"); | ||
|  | 
 | ||
|  | # Client ip address | ||
|  | $client_ip=inet_ntoa((gethostbyname(hostname()))[4]); | ||
|  | $client_ip=~ s/\.//g; | ||
|  | 
 | ||
|  | %tests_files=(client => {mtime => 0, data => []}, | ||
|  |               initdb => {mtime => 0, data => []}); | ||
|  | 
 | ||
|  | # Error codes and sub-strings with corresponding severity  | ||
|  | # | ||
|  | # S1 - Critical errors - cause immediately abort of testing. These errors | ||
|  | #                        could be caused by server crash or impossibility | ||
|  | #                        of test execution.  | ||
|  | # | ||
|  | # S2 - Serious errors - these errors are bugs for sure as it knowns that  | ||
|  | #                       they shouldn't appear during stress testing   | ||
|  | # | ||
|  | # S3 - Unknown errors - Errors were returned but we don't know what they are  | ||
|  | #                       so script can't determine if they are OK or not | ||
|  | # | ||
|  | # S4 - Non-seriuos errros - these errors could be caused by fact that  | ||
|  | #                           we execute simultaneously statements that | ||
|  | #                           affect tests executed by other threads | ||
|  |                              | ||
|  | %error_strings = ( 'Failed in mysql_real_connect()' => S1, | ||
|  |                    'Can\'t connect' => S1,        | ||
|  |                    'not found (Errcode: 2)' => S1, | ||
|  |                    'does not exist' => S1, | ||
|  |                    'Could not open connection \'default\' after \d+ attempts' => S1, | ||
|  |                    'wrong errno ' => S3, | ||
|  |                    'Result length mismatch' => S4, | ||
|  |                    'Result content mismatch' => S4); | ||
|  |    | ||
|  | %error_codes = ( 1012 => S2, 1015 => S2, 1021 => S2, | ||
|  |                  1027 => S2, 1037 => S2, 1038 => S2, | ||
|  |                  1039 => S2, 1040 => S2, 1046 => S2,  | ||
|  |                  1053 => S2, 1180 => S2, 1181 => S2,  | ||
|  |                  1203 => S2, 1205 => S4, 1206 => S2,  | ||
|  |                  1207 => S2, 1213 => S4, 1223 => S2,  | ||
|  |                  2002 => S1, 2003 => S1, 2006 => S1, | ||
|  |                  2013 => S1  | ||
|  |                  ); | ||
|  | 
 | ||
|  | share(%test_counters); | ||
|  | %test_counters=( loop_count => 0, test_count=>0); | ||
|  | 
 | ||
|  | share($exiting); | ||
|  | $exiting=0; | ||
|  | 
 | ||
|  | # OBN Code and 'set_exit_code' function added by ES to set an exit code based on the error category returned  | ||
|  | #     in combination with the --abort-on-error value see WL#4685) | ||
|  | use constant ABORT_MAKEWEIGHT => 20;   | ||
|  | share($gExitCode); | ||
|  | $gExitCode = 0;   # global exit code | ||
|  | sub set_exit_code { | ||
|  | 	my $severity = shift; | ||
|  | 	my $code = 0; | ||
|  | 	if ( $severity =~ /^S(\d+)/ ) { | ||
|  | 		$severity = $1; | ||
|  | 		$code = 11 - $severity; # S1=10, S2=9, ... -- as per WL | ||
|  | 	} | ||
|  | 	else { | ||
|  | 	# we know how we call the sub: severity should be S<num>; so, we should never be here... | ||
|  | 		print STDERR "Unknown severity format: $severity; setting to S1\n"; | ||
|  | 		$severity = 1; | ||
|  | 	} | ||
|  | 	$abort = 0; | ||
|  | 	if ( $severity <= $opt_abort_on_error ) { | ||
|  | 		# the test finished with a failure severe enough to abort. We are adding the 'abort flag' to the exit code | ||
|  | 		$code += ABORT_MAKEWEIGHT; | ||
|  | 		# but are not exiting just yet -- we need to update global exit code first | ||
|  | 		$abort = 1; | ||
|  | 	} | ||
|  | 	lock $gExitCode; # we can use lock here because the script uses threads anyway | ||
|  | 	$gExitCode = $code if $code > $gExitCode; | ||
|  | 	kill INT, $$ if $abort; # this is just a way to call sig_INT_handler: it will set exiting flag, which should do the rest | ||
|  | } | ||
|  | 
 | ||
|  | share($test_counters_lock); | ||
|  | $test_counters_lock=0; | ||
|  | share($log_file_lock); | ||
|  | $log_file_lock=0; | ||
|  | 
 | ||
|  | $SIG{INT}= \&sig_INT_handler; | ||
|  | $SIG{TERM}= \&sig_TERM_handler; | ||
|  | 
 | ||
|  | 
 | ||
|  | GetOptions("server-host=s", "server-logs-dir=s", "server-port=s", | ||
|  |            "server-socket=s", "server-user=s", "server-password=s", | ||
|  |            "server-database=s", | ||
|  |            "stress-suite-basedir=s", "suite=s", "stress-init-file:s",  | ||
|  |            "stress-tests-file:s", "stress-basedir=s", "stress-mode=s", | ||
|  |            "stress-datadir=s", | ||
|  |            "threads=s", "sleep-time=s", "loop-count=i", "test-count=i", | ||
|  |            "test-duration=i", "test-suffix=s", "check-tests-file",  | ||
|  |            "verbose", "log-error-details", "cleanup", "mysqltest=s",  | ||
|  |            # OBN: (changing 'abort-on-error' to numberic for WL-4626/4685)  | ||
|  |            "abort-on-error=i" => \$opt_abort_on_error, "help") || usage(); | ||
|  | 
 | ||
|  | usage() if ($opt_help); | ||
|  | 
 | ||
|  | #$opt_abort_on_error=1; | ||
|  | 
 | ||
|  | $test_dirname=get_timestamp(); | ||
|  | $test_dirname.="-$opt_test_suffix" if ($opt_test_suffix ne ''); | ||
|  | 
 | ||
|  | print <<EOF; | ||
|  | ############################################################# | ||
|  |                   CONFIGURATION STAGE | ||
|  | ############################################################# | ||
|  | EOF | ||
|  | 
 | ||
|  | if ($opt_stress_basedir eq '' || $opt_stress_suite_basedir eq '' || | ||
|  |     $opt_server_logs_dir eq '') | ||
|  | { | ||
|  |   die <<EOF; | ||
|  | 
 | ||
|  | Options --stress-basedir, --stress-suite-basedir and --server-logs-dir are  | ||
|  | required. Please use these options to specify proper basedir for  | ||
|  | client, test suite and location of server logs. | ||
|  | 
 | ||
|  | stress-basedir: '$opt_stress_basedir' | ||
|  | stress-suite-basedir: '$opt_stress_suite_basedir' | ||
|  | server-logs-dir: '$opt_server_logs_dir' | ||
|  | 
 | ||
|  | EOF | ||
|  | } | ||
|  | 
 | ||
|  | #Workaround for case when we got relative but not absolute path  | ||
|  | $opt_stress_basedir=File::Spec->rel2abs($opt_stress_basedir); | ||
|  | $opt_stress_suite_basedir=File::Spec->rel2abs($opt_stress_suite_basedir); | ||
|  | $opt_server_logs_dir=File::Spec->rel2abs($opt_server_logs_dir); | ||
|  | 
 | ||
|  | if ($opt_stress_datadir ne '') | ||
|  | { | ||
|  |   $opt_stress_datadir=File::Spec->rel2abs($opt_stress_datadir); | ||
|  | } | ||
|  | 
 | ||
|  | if (! -d "$opt_stress_basedir") | ||
|  | { | ||
|  |   die <<EOF; | ||
|  |    | ||
|  | Directory '$opt_stress_basedir' does not exist. | ||
|  | Use --stress-basedir option to specify proper basedir for client | ||
|  | 
 | ||
|  | EOF | ||
|  | } | ||
|  | 
 | ||
|  | if (!-d $opt_stress_suite_basedir) | ||
|  | { | ||
|  |   die <<EOF; | ||
|  | 
 | ||
|  | Directory '$opt_stress_suite_basedir' does not exist. | ||
|  | Use --stress-suite-basedir option to specify proper basedir for test suite | ||
|  | 
 | ||
|  | EOF | ||
|  | } | ||
|  | 
 | ||
|  | $test_dataset_dir=$opt_stress_suite_basedir; | ||
|  | if ($opt_stress_datadir ne '') | ||
|  | { | ||
|  |   if (-d $opt_stress_datadir) | ||
|  |   { | ||
|  |     $test_dataset_dir=$opt_stress_datadir; | ||
|  | 
 | ||
|  |   } | ||
|  |   else | ||
|  |   { | ||
|  |     die <<EOF; | ||
|  | Directory '$opt_stress_datadir' not exists. Please specify proper one  | ||
|  | with --stress-datadir option. | ||
|  | EOF | ||
|  |   }   | ||
|  | } | ||
|  | 
 | ||
|  | if ($^O =~ /mswin32/i) | ||
|  | { | ||
|  |   $test_dataset_dir=~ s/\\/\\\\/g; | ||
|  | } | ||
|  | else | ||
|  | { | ||
|  |   $test_dataset_dir.="/"; | ||
|  | } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | if (!-d $opt_server_logs_dir) | ||
|  | { | ||
|  |   die <<EOF; | ||
|  | 
 | ||
|  | Directory server-logs-dir '$opt_server_logs_dir' does not exist. | ||
|  | Use --server-logs-dir option to specify proper directory for storing  | ||
|  | logs  | ||
|  | 
 | ||
|  | EOF | ||
|  | } | ||
|  | else | ||
|  | { | ||
|  |   #Create sub-directory for test session logs | ||
|  |   mkpath(File::Spec->catdir($opt_server_logs_dir, $test_dirname), 0, 0755); | ||
|  |   #Define filename of global session log file | ||
|  |   $stress_log_file=File::Spec->catfile($opt_server_logs_dir, $test_dirname, | ||
|  |                                        "mysql-stress-test.log"); | ||
|  | } | ||
|  | 
 | ||
|  | if ($opt_suite ne '' && $opt_suite ne 'main' && $opt_suite ne 'default') | ||
|  | { | ||
|  |   $test_suite_dir=File::Spec->catdir($opt_stress_suite_basedir, "suite", $opt_suite); | ||
|  | } | ||
|  | else | ||
|  | { | ||
|  |   $test_suite_dir= $opt_stress_suite_basedir; | ||
|  | } | ||
|  | 
 | ||
|  | if (!-d $test_suite_dir) | ||
|  | { | ||
|  |   die <<EOF | ||
|  | 
 | ||
|  | Directory '$test_suite_dir' does not exist. | ||
|  | Use --suite options to specify proper dir for test suite | ||
|  | 
 | ||
|  | EOF | ||
|  | } | ||
|  | 
 | ||
|  | $test_suite_t_path=File::Spec->catdir($test_suite_dir,'t'); | ||
|  | $test_suite_r_path=File::Spec->catdir($test_suite_dir,'r'); | ||
|  | 
 | ||
|  | foreach my $suite_dir ($test_suite_t_path, $test_suite_r_path) | ||
|  | { | ||
|  |   if (!-d $suite_dir) | ||
|  |   { | ||
|  |     die <<EOF; | ||
|  | 
 | ||
|  | Directory '$suite_dir' does not exist. | ||
|  | Please ensure that you specified proper source location for  | ||
|  | test/result files with --stress-suite-basedir option and name  | ||
|  | of test suite with --suite option | ||
|  | 
 | ||
|  | EOF | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | $test_t_path=File::Spec->catdir($opt_stress_basedir,'t'); | ||
|  | $test_r_path=File::Spec->catdir($opt_stress_basedir,'r'); | ||
|  | 
 | ||
|  | foreach $test_dir ($test_t_path, $test_r_path) | ||
|  | { | ||
|  |   if (-d $test_dir) | ||
|  |   { | ||
|  |     if ($opt_cleanup) | ||
|  |     { | ||
|  |       #Delete existing 't', 'r', 'r/*' subfolders in $stress_basedir | ||
|  |       rmtree("$test_dir", 0, 0); | ||
|  |       print "Cleanup $test_dir\n"; | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |       die <<EOF; | ||
|  | Directory '$test_dir' already exist.  | ||
|  | Please ensure that you specified proper location of working dir | ||
|  | for current test run with --stress-basedir option or in case of staled | ||
|  | directories use --cleanup option to remove ones | ||
|  | EOF | ||
|  |     } | ||
|  |   } | ||
|  |   #Create empty 't', 'r' subfolders that will be filled later | ||
|  |   mkpath("$test_dir", 0, 0777); | ||
|  | } | ||
|  | 
 | ||
|  | if (!defined($opt_stress_tests_file) && !defined($opt_stress_init_file)) | ||
|  | { | ||
|  |   die <<EOF; | ||
|  | You should run stress script either with --stress-tests-file or with  | ||
|  | --stress-init-file otions. See help for details. | ||
|  | EOF | ||
|  | } | ||
|  | 
 | ||
|  | if (defined($opt_stress_tests_file)) | ||
|  | {  | ||
|  |   if ($opt_stress_tests_file eq '') | ||
|  |   { | ||
|  |     #Default location of file with set of tests for current test run | ||
|  |     $tests_files{client}->{filename}= File::Spec->catfile($opt_stress_suite_basedir, | ||
|  |                                       "testslist_client.txt"); | ||
|  |   } | ||
|  |   else | ||
|  |   { | ||
|  |     $tests_files{client}->{filename}= $opt_stress_tests_file; | ||
|  |   } | ||
|  | 
 | ||
|  |   if (!-f $tests_files{client}->{filename}) | ||
|  |   { | ||
|  |     die <<EOF; | ||
|  | 
 | ||
|  | File '$tests_files{client}->{filename}' with list of tests not exists.  | ||
|  | Please ensure that this file exists, readable or specify another one with  | ||
|  | --stress-tests-file option. | ||
|  | 
 | ||
|  | EOF | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | if (defined($opt_stress_init_file)) | ||
|  | { | ||
|  |   if ($opt_stress_init_file eq '') | ||
|  |   { | ||
|  |     #Default location of file with set of tests for current test run | ||
|  |     $tests_files{initdb}->{filename}= File::Spec->catfile($opt_stress_suite_basedir, | ||
|  |                                       "testslist_initdb.txt"); | ||
|  |   } | ||
|  |   else | ||
|  |   { | ||
|  |     $tests_files{initdb}->{filename}= $opt_stress_init_file; | ||
|  |   } | ||
|  | 
 | ||
|  |   if (!-f $tests_files{initdb}->{filename}) | ||
|  |   { | ||
|  |     die <<EOF; | ||
|  | 
 | ||
|  | File '$tests_files{initdb}->{filename}' with list of tests for initialization of database | ||
|  | for stress test not exists.  | ||
|  | Please ensure that this file exists, readable or specify another one with  | ||
|  | --stress-init-file option. | ||
|  | 
 | ||
|  | EOF | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | if ($opt_stress_mode !~ /^(random|seq)$/) | ||
|  | { | ||
|  |   die <<EOF | ||
|  | Was specified wrong --stress-mode. Correct values 'random' and 'seq'. | ||
|  | EOF | ||
|  | } | ||
|  | 
 | ||
|  | if (open(TEST, "$opt_mysqltest -V |")) | ||
|  | { | ||
|  |   $mysqltest_version=join("",<TEST>); | ||
|  |   close(TEST); | ||
|  |   print "FOUND MYSQLTEST BINARY: ", $mysqltest_version,"\n"; | ||
|  | } | ||
|  | else | ||
|  | { | ||
|  |   die <<EOF; | ||
|  | ERROR: mysqltest binary $opt_mysqltest not found $!. | ||
|  | You must either specify file location explicitly using --mysqltest | ||
|  | option, or make sure path to mysqltest binary is listed  | ||
|  | in your PATH environment variable. | ||
|  | EOF | ||
|  | } | ||
|  | 
 | ||
|  | #         | ||
|  | #Adding mysql server specific command line options for mysqltest binary | ||
|  | # | ||
|  | $opt_server_host= $opt_server_host ? $opt_server_host : "localhost"; | ||
|  | $opt_server_port= $opt_server_port ? $opt_server_port : "3306"; | ||
|  | $opt_server_user= $opt_server_user ? $opt_server_user : "root"; | ||
|  | $opt_server_socket= $opt_server_socket ? $opt_server_socket : "/tmp/mysql.sock"; | ||
|  | $opt_server_database= $opt_server_database ? $opt_server_database : "test"; | ||
|  | 
 | ||
|  | unshift @mysqltest_args, "--host=$opt_server_host"; | ||
|  | unshift @mysqltest_args, "--port=$opt_server_port"; | ||
|  | unshift @mysqltest_args, "--user=$opt_server_user"; | ||
|  | unshift @mysqltest_args, "--password=$opt_server_password"; | ||
|  | unshift @mysqltest_args, "--socket=$opt_server_socket"; | ||
|  | unshift @mysqltest_args, "--database=$opt_server_database"; | ||
|  | 
 | ||
|  | #Export variables that could be used in tests | ||
|  | $ENV{MYSQL_TEST_DIR}=$test_dataset_dir; | ||
|  | $ENV{MASTER_MYPORT}=$opt_server_port; | ||
|  | $ENV{MASTER_MYSOCK}=$opt_server_socket; | ||
|  | 
 | ||
|  | print <<EOF; | ||
|  | TEST-SUITE-BASEDIR: $opt_stress_suite_basedir | ||
|  | SUITE:              $opt_suite | ||
|  | TEST-BASE-DIR:      $opt_stress_basedir | ||
|  | TEST-DATADIR:       $test_dataset_dir | ||
|  | SERVER-LOGS-DIR:    $opt_server_logs_dir | ||
|  | 
 | ||
|  | THREADS:            $opt_threads | ||
|  | TEST-MODE:          $opt_stress_mode | ||
|  | 
 | ||
|  | EOF | ||
|  | 
 | ||
|  | #------------------------------------------------------------------------------- | ||
|  | #At this stage we've already checked all needed pathes/files  | ||
|  | #and ready to start the test | ||
|  | #------------------------------------------------------------------------------- | ||
|  | 
 | ||
|  | if (defined($opt_stress_tests_file) || defined($opt_stress_init_file)) | ||
|  | { | ||
|  |   print <<EOF; | ||
|  | ############################################################# | ||
|  |                   PREPARATION STAGE | ||
|  | ############################################################# | ||
|  | EOF | ||
|  | 
 | ||
|  |   #Copy Test files from network share to 't' folder | ||
|  |   print "\nCopying Test files from $test_suite_t_path to $test_t_path folder..."; | ||
|  |   find({wanted=>\©_test_files, bydepth=>1}, "$test_suite_t_path"); | ||
|  |   print "Done\n"; | ||
|  | 
 | ||
|  |   #$test_r_path/r0 dir reserved for initdb | ||
|  |   $count_start= defined($opt_stress_init_file) ? 0 : 1; | ||
|  | 
 | ||
|  |   our $r_folder=''; | ||
|  |   print "\nCreating 'r' folder and copying Protocol files to each 'r#' sub-folder..."; | ||
|  |   for($count=$count_start; $count <= $opt_threads; $count++) | ||
|  |   { | ||
|  |     $r_folder = File::Spec->catdir($test_r_path, "r".$count); | ||
|  |     mkpath("$r_folder", 0, 0777);  | ||
|  |       | ||
|  |     find(\©_result_files,"$test_suite_r_path"); | ||
|  |   }   | ||
|  |   print "Done\n\n"; | ||
|  | } | ||
|  | 
 | ||
|  | if (defined($opt_stress_init_file)) | ||
|  | { | ||
|  |   print <<EOF; | ||
|  | ############################################################# | ||
|  |                   INITIALIZATION STAGE | ||
|  | ############################################################# | ||
|  | EOF | ||
|  | 
 | ||
|  |   #Set limits for stress db initialization  | ||
|  |   %limits=(loop_count => 1, test_count => undef); | ||
|  | 
 | ||
|  |   #Read list of tests from $opt_stress_init_file | ||
|  |   read_tests_names($tests_files{initdb}); | ||
|  |   test_loop($client_ip, 0, 'seq', $tests_files{initdb});   | ||
|  |   #print Dumper($tests_files{initdb}),"\n"; | ||
|  |   print <<EOF; | ||
|  | 
 | ||
|  | Done initialization of stress database by tests from  | ||
|  | $tests_files{initdb}->{filename} file. | ||
|  | 
 | ||
|  | EOF | ||
|  | } | ||
|  | 
 | ||
|  | if (defined($opt_stress_tests_file)) | ||
|  | { | ||
|  |   print <<EOF; | ||
|  | ############################################################# | ||
|  |                   STRESS TEST RUNNING STAGE | ||
|  | ############################################################# | ||
|  | EOF | ||
|  | 
 | ||
|  |   $exiting=0; | ||
|  |   #Read list of tests from $opt_stress_tests_file  | ||
|  |   read_tests_names($tests_files{client}); | ||
|  | 
 | ||
|  |   #Reset current counter and set limits | ||
|  |   %test_counters=( loop_count => 0, test_count=>0); | ||
|  |   %limits=(loop_count => $opt_loop_count, test_count => $opt_test_count); | ||
|  | 
 | ||
|  |   if (($opt_loop_count && $opt_threads > $opt_loop_count) ||  | ||
|  |       ($opt_test_count && $opt_threads > $opt_test_count)) | ||
|  |   { | ||
|  |     warn <<EOF; | ||
|  | 
 | ||
|  | WARNING: Possible inaccuracies in number of executed loops or  | ||
|  |          tests because number of threads bigger than number of  | ||
|  |          loops or tests: | ||
|  |           | ||
|  |          Threads will be started: $opt_threads | ||
|  |          Loops will be executed:  $opt_loop_count | ||
|  |          Tests will be executed:  $opt_test_count     | ||
|  | 
 | ||
|  | EOF | ||
|  |   } | ||
|  | 
 | ||
|  |   #Create threads (number depending on the variable ) | ||
|  |   for ($id=1; $id<=$opt_threads && !$exiting; $id++) | ||
|  |   { | ||
|  |     $thrd[$id] = threads->create("test_loop", $client_ip, $id, | ||
|  |                                  $opt_stress_mode, $tests_files{client}); | ||
|  | 
 | ||
|  |     print "main: Thread ID $id TID ",$thrd[$id]->tid," started\n"; | ||
|  |     select(undef, undef, undef, 0.5); | ||
|  |   } | ||
|  | 
 | ||
|  |   if ($opt_test_duration) | ||
|  |   { | ||
|  |   # OBN - At this point we need to wait for the duration of the test, hoever | ||
|  |   #       we need to be able to quit if an 'abort-on-error' condition has happend  | ||
|  |   #       with one of the children (WL#4685). Using solution by ES and replacing  | ||
|  |   #       the 'sleep' command with a loop checking the abort condition every second | ||
|  |    | ||
|  | 	foreach ( 1..$opt_test_duration ) {        | ||
|  | 		last if $exiting;                      | ||
|  | 		sleep 1;                               | ||
|  | 	} | ||
|  |     kill INT, $$;                             #Interrupt child threads | ||
|  |   } | ||
|  | 
 | ||
|  |   #Let other threads to process INT signal | ||
|  |   sleep(1); | ||
|  | 
 | ||
|  |   for ($id=1; $id<=$opt_threads;$id++) | ||
|  |   { | ||
|  |     if (defined($thrd[$id])) | ||
|  |     { | ||
|  |       $thrd[$id]->join(); | ||
|  |     } | ||
|  |   } | ||
|  |   print "EXIT\n"; | ||
|  | } | ||
|  | 
 | ||
|  | exit $gExitCode; # ES WL#4685: script should return a meaningful exit code | ||
|  | 
 | ||
|  | sub test_init | ||
|  | { | ||
|  |   my ($env)=@_; | ||
|  |    | ||
|  |   $env->{session_id}=$env->{ip}."_".$env->{thread_id}; | ||
|  |   $env->{r_folder}='r'.$env->{thread_id};  | ||
|  |   $env->{screen_logs}=File::Spec->catdir($opt_server_logs_dir, $test_dirname,  | ||
|  |                                          "screen_logs", $env->{session_id}); | ||
|  |   $env->{reject_logs}=File::Spec->catdir($opt_server_logs_dir, $test_dirname, | ||
|  |                                          "reject_logs", $env->{session_id}); | ||
|  |    | ||
|  |   mkpath($env->{screen_logs}, 0, 0755) unless (-d $env->{screen_logs}); | ||
|  |   mkpath($env->{reject_logs}, 0, 0755) unless (-d $env->{reject_logs}); | ||
|  | 
 | ||
|  |   $env->{session_log}= File::Spec->catfile($env->{screen_logs}, $env->{session_id}.".log");      | ||
|  | } | ||
|  | 
 | ||
|  | sub test_execute | ||
|  | { | ||
|  |   my $env= shift; | ||
|  |   my $test_name= shift; | ||
|  | 
 | ||
|  |   my $g_start= ""; | ||
|  |   my $g_end= ""; | ||
|  |   my $mysqltest_cmd= ""; | ||
|  |   my @mysqltest_test_args=(); | ||
|  |   my @stderr=(); | ||
|  | 
 | ||
|  |   #Get time stamp | ||
|  |   $g_start = get_timestamp(); | ||
|  |   $env->{errors}={}; | ||
|  |   @{$env->{test_status}}=(); | ||
|  | 
 | ||
|  |   my $test_file= $test_name.".test"; | ||
|  |   my $result_file= $test_name.".result"; | ||
|  |   my $reject_file = $test_name.'.reject'; | ||
|  |   my $output_file = $env->{session_id}.'_'.$test_name.'_'.$g_start."_".$env->{test_count}.'.txt'; | ||
|  | 
 | ||
|  |   my $test_filename = File::Spec->catfile($test_t_path, $test_file); | ||
|  |   my $result_filename = File::Spec->catdir($test_r_path, $env->{r_folder}, $result_file); | ||
|  |   my $reject_filename = File::Spec->catdir($test_r_path, $env->{r_folder}, $reject_file); | ||
|  |   my $output_filename = File::Spec->catfile($env->{screen_logs}, $output_file);      | ||
|  | 
 | ||
|  | 
 | ||
|  |   push @mysqltest_test_args, "--basedir=$opt_stress_suite_basedir/", | ||
|  |                              "--tmpdir=$opt_stress_basedir", | ||
|  |                              "-x $test_filename", | ||
|  |                              "-R $result_filename", | ||
|  |                              "2>$output_filename"; | ||
|  |                          | ||
|  |   $cmd= "$opt_mysqltest --no-defaults ".join(" ", @mysqltest_args)." ". | ||
|  |                                         join(" ", @mysqltest_test_args); | ||
|  | 
 | ||
|  |   system($cmd); | ||
|  | 
 | ||
|  |   $exit_value  = $? >> 8; | ||
|  |   $signal_num  = $? & 127; | ||
|  |   $dumped_core = $? & 128; | ||
|  | 
 | ||
|  |   my $tid= threads->self->tid; | ||
|  | 
 | ||
|  |   if (-s $output_filename > 0) | ||
|  |   {  | ||
|  |     #Read stderr for further analysis | ||
|  |     open (STDERR_LOG, $output_filename) or  | ||
|  |                              warn "Can't open file $output_filename"; | ||
|  |     @stderr=<STDERR_LOG>; | ||
|  |     close(STDERR_LOG); | ||
|  |   | ||
|  |     if ($opt_verbose) | ||
|  |     { | ||
|  |       $session_debug_file="$opt_stress_basedir/error$tid.txt"; | ||
|  |        | ||
|  |       stress_log($session_debug_file,  | ||
|  |                 "Something wrong happened during execution of this command line:"); | ||
|  |       stress_log($session_debug_file, "MYSQLTEST CMD - $cmd");     | ||
|  |       stress_log($session_debug_file, "STDERR:".join("",@stderr));       | ||
|  | 
 | ||
|  |       stress_log($session_debug_file, "EXIT STATUS:\n1. EXIT: $exit_value \n". | ||
|  |                                       "2. SIGNAL: $signal_num\n". | ||
|  |                                       "3. CORE: $dumped_core\n"); | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   #If something wrong trying to analyse stderr  | ||
|  |   if ($exit_value || $signal_num) | ||
|  |   { | ||
|  |     if (@stderr) | ||
|  |     { | ||
|  |       foreach my $line (@stderr) | ||
|  |       { | ||
|  |         #FIXME: we should handle case when for one sub-string/code  | ||
|  |         #       we have several different error messages         | ||
|  |         #       Now for both codes/substrings we assume that | ||
|  |         #       first found message will represent error | ||
|  | 
 | ||
|  |         #Check line for error codes | ||
|  |         if (($err_msg, $err_code)= $line=~/failed: ((\d+):.+?$)/) | ||
|  |         { | ||
|  |           if (!exists($error_codes{$err_code})) | ||
|  |           { | ||
|  |             # OBN Changing severity level to S4 from S3 as S3 now reserved | ||
|  |             #     for the case where the error is unknown (for WL#4626/4685 | ||
|  |             $severity="S4"; | ||
|  |             $err_code=0; | ||
|  |           } | ||
|  |           else | ||
|  |           { | ||
|  |             $severity=$error_codes{$err_code}; | ||
|  |           } | ||
|  | 
 | ||
|  |           if (!exists($env->{errors}->{$severity}->{$err_code})) | ||
|  |           { | ||
|  |             $env->{errors}->{$severity}->{$err_code}=[0, $err_msg]; | ||
|  |           } | ||
|  |           $env->{errors}->{$severity}->{$err_code}->[0]++; | ||
|  |           $env->{errors}->{$severity}->{total}++;           | ||
|  |         } | ||
|  | 
 | ||
|  |         #Check line for error patterns | ||
|  |         foreach $err_string (keys %error_strings) | ||
|  |         { | ||
|  |           $pattern= quotemeta $err_string; | ||
|  |           if ($line =~ /$pattern/i) | ||
|  |           { | ||
|  |             my $severity= $error_strings{$err_string}; | ||
|  |             if (!exists($env->{errors}->{$severity}->{$err_string})) | ||
|  |             { | ||
|  |               $env->{errors}->{$severity}->{$err_string}=[0, $line]; | ||
|  |             } | ||
|  |             $env->{errors}->{$severity}->{$err_string}->[0]++; | ||
|  |             $env->{errors}->{$severity}->{total}++;           | ||
|  |           } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |       $env->{errors}->{S3}->{'Unknown error'}= | ||
|  |                               [1,"Unknown error. Nothing was output to STDERR"]; | ||
|  |       $env->{errors}->{S3}->{total}=1; | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   # | ||
|  |   #FIXME: Here we can perform further analysis of recognized  | ||
|  |   #       error codes  | ||
|  |   # | ||
|  | 
 | ||
|  |   foreach my $severity (sort {$a cmp $b} keys %{$env->{errors}}) | ||
|  |   { | ||
|  |     my $total=$env->{errors}->{$severity}->{total}; | ||
|  |     if ($total) | ||
|  |     { | ||
|  |       push @{$env->{test_status}}, "Severity $severity: $total"; | ||
|  |       $env->{errors}->{total}=+$total; | ||
|  |       set_exit_code($severity);   | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   #FIXME: Should we take into account $exit_value here? | ||
|  |   #       Now we assume that all stringified errors(i.e. errors without  | ||
|  |   #       error codes) which are not exist in %error_string structure  | ||
|  |   #       are OK | ||
|  |   if (!$env->{errors}->{total}) | ||
|  |   { | ||
|  |     push @{$env->{test_status}},"No Errors. Test Passed OK"; | ||
|  |   } | ||
|  | 
 | ||
|  |   log_session_errors($env, $test_file); | ||
|  | 
 | ||
|  |   #OBN Removing the case of S1 and abort-on-error as that is now set  | ||
|  |   #     inside the set_exit_code function (for WL#4626/4685) | ||
|  |   #if (!$exiting && ($signal_num == 2 || $signal_num == 15 ||  | ||
|  |   #       ($opt_abort_on_error && $env->{errors}->{S1} > 0))) | ||
|  |   if (!$exiting && ($signal_num == 2 || $signal_num == 15)) | ||
|  |   { | ||
|  |     #mysqltest was interrupted with INT or TERM signals  | ||
|  |     #so we assume that we should cancel testing and exit | ||
|  |     $exiting=1; | ||
|  |     # OBN - Adjusted text to exclude case of S1 and abort-on-error that  | ||
|  |     #       was mentioned (for WL#4626/4685) | ||
|  |     print STDERR<<EOF; | ||
|  | WARNING: | ||
|  |    mysqltest was interrupted with INT or TERM signals  so we assume that  | ||
|  |    we should cancel testing and exit. Please check log file for this thread  | ||
|  |    in $stress_log_file or  | ||
|  |    inspect below output of the last test case executed with mysqltest to  | ||
|  |    find out cause of error. | ||
|  |     | ||
|  |    Output of mysqltest: | ||
|  |    @stderr | ||
|  |     | ||
|  | EOF | ||
|  |   } | ||
|  | 
 | ||
|  |   if (-e $reject_filename) | ||
|  |   {   | ||
|  |     move_to_logs($env->{reject_logs}, $reject_filename, $reject_file); | ||
|  |   }     | ||
|  |    | ||
|  |   if (-e $output_filename) | ||
|  |   {   | ||
|  |     move_to_logs($env->{screen_logs}, $output_filename, $output_file); | ||
|  |   }     | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | sub test_loop | ||
|  | {      | ||
|  |   my %client_env=(); | ||
|  |   my $test_name=""; | ||
|  | 
 | ||
|  |   # KEY for session identification: IP-THREAD_ID | ||
|  |   $client_env{ip} = shift; | ||
|  |   $client_env{thread_id} = shift; | ||
|  | 
 | ||
|  |   $client_env{mode} = shift; | ||
|  |   $client_env{tests_file}=shift;  | ||
|  | 
 | ||
|  |   $client_env{test_seq_idx}=0; | ||
|  | 
 | ||
|  |   #Initialize session variables | ||
|  |   test_init(\%client_env); | ||
|  | 
 | ||
|  | LOOP: | ||
|  | 
 | ||
|  |   while(!$exiting) | ||
|  |   { | ||
|  |     if ($opt_check_tests_file) | ||
|  |     { | ||
|  |       #Check if tests_file was modified and reread it in this case | ||
|  |       read_tests_names($client_env{tests_file}, 0); | ||
|  |     } | ||
|  | 
 | ||
|  |     { | ||
|  |       lock($test_counters_lock); | ||
|  | 
 | ||
|  |       if (($limits{loop_count} && $limits{loop_count} <= $test_counters{loop_count}*1) || | ||
|  |           ($limits{test_count} && $limits{test_count} <= $test_counters{test_count}*1) ) | ||
|  |       { | ||
|  |         $exiting=1; | ||
|  |         next LOOP; | ||
|  |       } | ||
|  |     } | ||
|  | 
 | ||
|  |     #Get random file name  | ||
|  |     if (($test_name = get_test(\%client_env)) ne '') | ||
|  |     { | ||
|  |       { | ||
|  |         lock($test_counters_lock); | ||
|  | 
 | ||
|  |         #Save current counters values  | ||
|  |         $client_env{loop_count}=$test_counters{loop_count}; | ||
|  |         $client_env{test_count}=$test_counters{test_count}; | ||
|  |       } | ||
|  |       #Run test and analyze results | ||
|  |       test_execute(\%client_env, $test_name); | ||
|  | 
 | ||
|  |       print "test_loop[".$limits{loop_count}.":". | ||
|  |              $limits{test_count}." ". | ||
|  |              $client_env{loop_count}.":". | ||
|  |              $client_env{test_count}."]:". | ||
|  |              " TID ".$client_env{thread_id}. | ||
|  |              " test: '$test_name' ". | ||
|  |              " Errors: ".join(" ",@{$client_env{test_status}}). | ||
|  |                 ( $exiting ? " (thread aborting)" : "" )."\n"; | ||
|  |     } | ||
|  |    | ||
|  |     # OBN - At this point we need to wait until the 'wait' time between test | ||
|  |     #       executions passes (in case it is specifed) passes, hoever we need | ||
|  |     #       to be able to quit and break out of the test if an 'abort-on-error'  | ||
|  |     #       condition has happend with one of the other children (WL#4685).  | ||
|  |     #       Using solution by ES and replacing the 'sleep' command with a loop  | ||
|  |     #       checking the abort condition every second | ||
|  |    | ||
|  | 	if ( $opt_sleep_time ) {                 | ||
|  | 		foreach ( 1..$opt_sleep_time ) {      | ||
|  | 			last if $exiting;                | ||
|  | 			sleep 1;                         | ||
|  | 		}                                    | ||
|  | 	}                                        | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | sub move_to_logs ($$$) | ||
|  | { | ||
|  |   my $path_to_logs = shift; | ||
|  |   my $src_file = shift; | ||
|  |   my $random_filename = shift; | ||
|  | 
 | ||
|  |   my $dst_file = File::Spec->catfile($path_to_logs, $random_filename); | ||
|  |    | ||
|  |   move ($src_file, $dst_file) or warn<<EOF; | ||
|  | ERROR: move_to_logs: File $src_file cannot be moved to $dst_file: $! | ||
|  | EOF | ||
|  | } | ||
|  | 
 | ||
|  | sub copy_test_files () | ||
|  | { | ||
|  |   if (/\.test$/) | ||
|  |   {  | ||
|  |     $src_file = $File::Find::name; | ||
|  |     #print "## $File::Find::topdir - $File::Find::dir - $src_file\n"; | ||
|  | 
 | ||
|  |     if ($File::Find::topdir eq $File::Find::dir && $src_file !~ /SCCS/) | ||
|  |     { | ||
|  |       $test_filename = basename($src_file); | ||
|  |       $dst_file = File::Spec->catfile($test_t_path, $test_filename); | ||
|  | 
 | ||
|  |       copy($src_file, $dst_file) or die "ERROR: copy_test_files: File cannot be copied. $!"; | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | sub copy_result_files () | ||
|  | { | ||
|  |   if (/\.result$/) | ||
|  |   {  | ||
|  |     $src_file = $File::Find::name; | ||
|  | 
 | ||
|  |     if ($File::Find::topdir eq $File::Find::dir && $src_file !~ /SCCS/) | ||
|  |     { | ||
|  |       $result_filename = basename($src_file) ; | ||
|  |       $dst_file = File::Spec->catfile($r_folder, $result_filename); | ||
|  | 
 | ||
|  |       copy($src_file, $dst_file) or die "ERROR: copy_result_files: File cannot be copied. $!"; | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | sub get_timestamp | ||
|  | { | ||
|  |   my ($sec,$min,$hour,$mday,$mon,$year,$wday,$ydat,$isdst) = localtime(); | ||
|  | 
 | ||
|  |   return sprintf("%04d%02d%02d%02d%02d%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec); | ||
|  | } | ||
|  | 
 | ||
|  | sub read_tests_names | ||
|  | { | ||
|  |   my $tests_file = shift; | ||
|  |   my $force_load = shift; | ||
|  | 
 | ||
|  |   if ($force_load || ( (stat($tests_file->{filename}))[9] != $tests_file->{mtime}) ) | ||
|  |   { | ||
|  |     open (TEST, $tests_file->{filename}) || die ("Could not open file <". | ||
|  |                                                   $tests_file->{filename}."> $!"); | ||
|  |     @{$tests_file->{data}}= grep {!/^[#\r\n]|^$/} map { s/[\r\n]//g; $_ } <TEST>; | ||
|  | 
 | ||
|  |     close (TEST);  | ||
|  |     $tests_file->{mtime}=(stat(_))[9]; | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | sub get_random_test | ||
|  | { | ||
|  |   my $envt=shift; | ||
|  |   my $tests= $envt->{tests_file}->{data}; | ||
|  | 
 | ||
|  |   my $random = int(rand(@{$tests})); | ||
|  |   my $test = $tests->[$random]; | ||
|  | 
 | ||
|  |   return $test; | ||
|  | } | ||
|  | 
 | ||
|  | sub get_next_test | ||
|  | { | ||
|  |   my $envt=shift; | ||
|  |   my $test; | ||
|  | 
 | ||
|  |   if (@{$envt->{tests_file}->{data}}) | ||
|  |   { | ||
|  |     $test=${$envt->{tests_file}->{data}}[$envt->{test_seq_idx}]; | ||
|  |     $envt->{test_seq_idx}++; | ||
|  |   } | ||
|  |    | ||
|  |   #If we reach bound of array, reset seq index and increment loop counter | ||
|  |   if ($envt->{test_seq_idx} == scalar(@{$envt->{tests_file}->{data}})) | ||
|  |   { | ||
|  |     $envt->{test_seq_idx}=0; | ||
|  |     { | ||
|  |       lock($test_counters_lock); | ||
|  |       $test_counters{loop_count}++;  | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   return $test;   | ||
|  | } | ||
|  | 
 | ||
|  | sub get_test | ||
|  | { | ||
|  |    my $envt=shift; | ||
|  | 
 | ||
|  |    { | ||
|  |      lock($test_counters_lock); | ||
|  |      $test_counters{test_count}++; | ||
|  |    } | ||
|  |     | ||
|  |    if ($envt->{mode} eq 'seq') | ||
|  |    { | ||
|  |      return get_next_test($envt); | ||
|  |    } | ||
|  |    elsif ($envt->{mode} eq 'random') | ||
|  |    { | ||
|  |      return get_random_test($envt); | ||
|  |    } | ||
|  | } | ||
|  | 
 | ||
|  | sub stress_log | ||
|  | { | ||
|  |   my ($log_file, $line)=@_; | ||
|  |   | ||
|  |   { | ||
|  |     open(SLOG,">>$log_file") or warn "Error during opening log file $log_file"; | ||
|  |     print SLOG $line,"\n"; | ||
|  |     close(SLOG); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | sub log_session_errors | ||
|  | { | ||
|  |   my ($env, $test_name) = @_; | ||
|  |   my $line=''; | ||
|  | 
 | ||
|  |   { | ||
|  |     lock ($log_file_lock); | ||
|  | 
 | ||
|  |     #header in the begining of log file | ||
|  |     if (!-e $stress_log_file) | ||
|  |     { | ||
|  |       stress_log($stress_log_file,  | ||
|  |                    "TestID TID      Suite         TestFileName Found Errors"); | ||
|  |       stress_log($stress_log_file,  | ||
|  |                    "=======================================================");     | ||
|  |     } | ||
|  | 
 | ||
|  |     $line=sprintf('%6d %3d %10s %20s %s', $env->{test_count}, threads->self->tid,  | ||
|  |                                           $opt_suite, $test_name,  | ||
|  |                                           join(",", @{$env->{test_status}})); | ||
|  |                                        | ||
|  |     stress_log($stress_log_file, $line); | ||
|  |     #stress_log_with_lock($stress_log_file, "\n"); | ||
|  | 
 | ||
|  |     if ($opt_log_error_details) | ||
|  |     { | ||
|  |       foreach $severity (sort {$a cmp $b} keys %{$env->{errors}}) | ||
|  |       { | ||
|  |         stress_log($stress_log_file, ""); | ||
|  |         foreach $error (keys %{$env->{errors}->{$severity}}) | ||
|  |         { | ||
|  |           if ($error ne 'total') | ||
|  |           { | ||
|  |             stress_log($stress_log_file, "$severity: Count:". | ||
|  |                       $env->{errors}->{$severity}->{$error}->[0]. | ||
|  |                       " Error:". $env->{errors}->{$severity}->{$error}->[1]); | ||
|  |           } | ||
|  |         } | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | sub sig_INT_handler | ||
|  | { | ||
|  |   $SIG{INT}= \&sig_INT_handler; | ||
|  |   $exiting=1; | ||
|  |   print STDERR "$$: Got INT signal-------------------------------------------\n"; | ||
|  | 
 | ||
|  | } | ||
|  | 
 | ||
|  | sub sig_TERM_handler | ||
|  | { | ||
|  |   $SIG{TERM}= \&sig_TERM_handler; | ||
|  |   $exiting=1; | ||
|  |   print STDERR "$$: Got TERM signal\n"; | ||
|  | } | ||
|  | 
 | ||
|  | sub usage | ||
|  | { | ||
|  |   print <<EOF; | ||
|  | 
 | ||
|  | The MySQL Stress suite Ver $stress_suite_version | ||
|  | 
 | ||
|  | mysql-stress-test.pl --stress-basedir=<dir> --stress-suite-basedir=<dir> --server-logs-dir=<dir> | ||
|  | 
 | ||
|  | --server-host | ||
|  | --server-port | ||
|  | --server-socket | ||
|  | --server-user | ||
|  | --server-password | ||
|  | --server-logs-dir | ||
|  |   Directory where all clients session logs will be stored. Usually  | ||
|  |   this is shared directory associated with server that used  | ||
|  |   in testing | ||
|  | 
 | ||
|  |   Required option. | ||
|  | 
 | ||
|  | --stress-suite-basedir=<dir> | ||
|  |   Directory that has r/ t/ subfolders with test/result files | ||
|  |   which will be used for testing. Also by default we are looking  | ||
|  |   in this directory for 'stress-tests.txt' file which contains  | ||
|  |   list of tests.  It is possible to specify other location of this  | ||
|  |   file with --stress-tests-file option. | ||
|  | 
 | ||
|  |   Required option. | ||
|  | 
 | ||
|  | --stress-basedir=<dir> | ||
|  |   Working directory for this test run. This directory will be used  | ||
|  |   as temporary location for results tracking during testing | ||
|  |    | ||
|  |   Required option. | ||
|  | 
 | ||
|  | --stress-datadir=<dir> | ||
|  |   Location of data files used which will be used in testing. | ||
|  |   By default we search for these files in <dir>/data where dir  | ||
|  |   is value of --stress-suite-basedir option. | ||
|  | 
 | ||
|  | --stress-init-file[=/path/to/file with tests for initialization of stress db] | ||
|  |   Using of this option allows to perform initialization of database | ||
|  |   by execution of test files. List of tests will be taken either from  | ||
|  |   specified file or if it omited from default file 'stress-init.txt' | ||
|  |   located in <--stress-suite-basedir/--suite> dir | ||
|  |      | ||
|  | --stress-tests-file[=/path/to/file with tests]  | ||
|  |   Using of this option allows to run stress test itself. Tests for testing  | ||
|  |   will be taken either from specified file or if it omited from default  | ||
|  |   file 'stress-tests.txt' located in <--stress-suite-basedir/--suite> dir | ||
|  | 
 | ||
|  | --stress-mode= [random|seq] | ||
|  |   There are two possible modes which affect order of selecting tests | ||
|  |   from the list: | ||
|  |     - in random mode tests will be selected in random order | ||
|  |     - in seq mode each thread will execute tests in the loop one by one as  | ||
|  |       they specified in the list file.  | ||
|  |        | ||
|  | --sleep-time=<time in seconds> | ||
|  |   Delay between test execution. Could be usefull in continued testsing  | ||
|  |   when one of instance of stress script perform periodical cleanup or | ||
|  |   recreating of some database objects | ||
|  | 
 | ||
|  | --threads=#number of threads | ||
|  |   Define number of threads | ||
|  | 
 | ||
|  | --check-tests-file | ||
|  |   Check file with list of tests. If file was modified it will force to | ||
|  |   reread list of tests. Could be usefull in continued testing for | ||
|  |   adding/removing tests without script interruption  | ||
|  | 
 | ||
|  | --mysqltest=/path/to/mysqltest binary | ||
|  | 
 | ||
|  | --verbose | ||
|  | 
 | ||
|  | --cleanup | ||
|  |   Force to clean up working directory (specified with --stress-basedir) | ||
|  | 
 | ||
|  | --abort-on-error=<number> | ||
|  |   Causes the script to abort if an error with severity <= number was encounterd | ||
|  | 
 | ||
|  | --log-error-details | ||
|  |   Enable errors details in the global error log file. (Default: off) | ||
|  | 
 | ||
|  | --test-count=<number of executed tests before we have to exit> | ||
|  | --loop-count=<number of executed loops in sequential mode before we have to exit> | ||
|  | --test-duration=<number of seconds that stress test should run> | ||
|  | 
 | ||
|  | Example of tool usage: | ||
|  | 
 | ||
|  | perl mysql-stress-test.pl \ | ||
|  | --stress-suite-basedir=/opt/qa/mysql-test-extra-5.0/mysql-test \ | ||
|  | --stress-basedir=/opt/qa/test \ | ||
|  | --server-logs-dir=/opt/qa/logs \ | ||
|  | --test-count=20  \ | ||
|  | --stress-tests-file=innodb-tests.txt \ | ||
|  | --stress-init-file=innodb-init.txt \ | ||
|  | --threads=5 \ | ||
|  | --suite=funcs_1  \ | ||
|  | --mysqltest=/opt/mysql/mysql-5.0/client/mysqltest \ | ||
|  | --server-user=root \ | ||
|  | --server-database=test \ | ||
|  | --cleanup \ | ||
|  | 
 | ||
|  | EOF | ||
|  | exit(0); | ||
|  | } | ||
|  | 
 | ||
|  | 
 |