2
# -*- mode: python; indent-tabs-mode: nil; -*-
3
# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
5
# Copyright (C) 2010, 2011 Patrick Crews
7
# This program is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2 of the License, or
10
# (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
"""Processes command line options for Drizzle test-runner"""
32
def comma_list_split(option, opt, value, parser):
33
"""Callback for splitting input expected in list form"""
34
cur_list = getattr(parser.values, option.dest,[])
35
input_list = value.split(',')
36
# this is a hack to work with make target - we
37
# don't deal with a dangling ',' in our list
41
value_list = cur_list + input_list
43
value_list = input_list
44
setattr(parser.values, option.dest, value_list)
46
def get_abspath(option, opt, value, parser):
47
""" Utility function to make sure we have absolute paths
48
if the user supplies values
51
the_path = os.path.abspath(value)
52
setattr(parser.values, option.dest, the_path)
54
def organize_options(args, test_cases):
55
"""Put our arguments in a nice dictionary
56
We use option.dest as dictionary key
61
# we make a copy as the python manual on vars
62
# says we shouldn't alter the dictionary returned
63
# by vars() - could affect symbol table?
64
variables = copy.copy(vars(args))
65
variables['test_cases']= test_cases
66
# This code should become a function once
67
# enough thought has been given to it
68
if variables['manualgdb']:
70
if variables['repeat'] <= 0:
71
print "Setting --repeat=1. You chose a silly value that I will ignore :P"
72
variables['repeat'] = 1
73
# we disable the secure-file-priv option if not using dtr / mtr
74
# this might need to be changed in the future...
75
if variables['mode'] not in ['dtr','mtr']:
76
print "Setting --no-secure-file-priv=True for randgen usage..."
77
variables['nosecurefilepriv']=True
78
if variables['mode'] == 'cleanup':
79
print "Setting --start-dirty=True for cleanup mode..."
80
variables['startdirty']=True
81
if variables['libeatmydata'] and os.path.exists(variables['libeatmydatapath']):
82
# We are using libeatmydata vs. shared mem for server speedup
83
print "Using libeatmydata at %s. Setting --no-shm / not using shared memory for testing..." %(variables['libeatmydatapath'])
84
variables['noshm']=True
87
def populate_defaults(variables, basedir_default):
88
""" We fill in any default values that need
89
to be put in post-parsing
92
if not variables['basedir']:
93
# We populate this value with the default now
94
# it allows us to have a default and have user
95
# supplied opts to override them
96
variables['basedir'].append(basedir_default)
99
def handle_user_opts(variables, defaults):
100
""" Some variables are dependent upon default values
101
We do the probably hacky thing of going through
102
and updating them accordingly
104
We make the assumption / decision that only
105
the first basedir value supplied should
106
be applicable when searching for tests
109
master_basedir = os.path.abspath(variables['basedir'][0].split(':type:')[0])
110
if master_basedir != defaults['basedir']:
111
new_path = os.path.join(master_basedir, 'plugin')
112
search_path = os.path.join(defaults['basedir'],'plugin')
113
tmp = variables['suitepaths']
114
tmp[tmp.index(search_path)] = new_path
115
variables['suitepaths'] = tmp
117
if variables['testdir'] != defaults['testdir']:
118
new_path = os.path.join(variables['testdir'],'suite')
119
search_path = os.path.join(defaults['testdir'],'suite')
120
tmp = variables['suitepaths']
121
tmp[tmp.index(search_path)] = new_path
122
variables['suitepaths'] = tmp
126
def parse_qp_options(defaults):
127
""" We parse our options and do our magic based on some default values """
128
# Create the CLI option parser
129
parser= optparse.OptionParser(version='%prog (database quality platform aka project steve austin) version 0.1.1')
130
config_control_group = optparse.OptionGroup(parser,
131
"Configuration controls - allows you to specify a file with a number of options already specified")
132
config_control_group.add_option(
134
, dest="sysconfigfilepath"
136
, default=None # We want to have a file that will be our default defaults file...
137
, help="The file that specifies system configuration specs for kewpie to execute tests"
139
parser.add_option_group(config_control_group)
142
system_control_group = optparse.OptionGroup(parser,
143
"Options for the test-runner itself - defining the system under test and how to execute tests")
145
system_control_group.add_option(
148
, action="store_true"
150
, help="Set this to continue test execution beyond the first failed test"
153
system_control_group.add_option(
155
, dest="startandexit"
156
, action="store_true"
158
, help="Spin up the server(s) for the first specified test then exit (will leave servers running)"
161
system_control_group.add_option(
164
, action="store_true"
166
, help="Produces extensive output about test-runner state. Distinct from --debug"
169
system_control_group.add_option(
172
, action="store_true"
174
, help="Provide internal-level debugging output. Distinct from --verbose"
177
system_control_group.add_option(
181
, help="Testing mode. We currently support dtr, randgen, sysbench, sqlbench, crashme and cleanup modes. See docs for further details about individual modes [%default]"
184
system_control_group.add_option(
187
, action="store_true"
189
, help="Record a testcase result (if the testing mode supports it) [%default]"
192
system_control_group.add_option(
195
, action="store_true"
197
, help="Don't try to cleanup from earlier runs (currently just a placeholder) [%default]"
200
parser.add_option_group(system_control_group)
202
test_exec_control_group = optparse.OptionGroup(parser,
203
"Options for controlling how tests are executed")
205
test_exec_control_group.add_option(
208
, action="store_true"
210
, help="Toggle to control any debugging / helper output with unittest test cases [%default]"
213
test_exec_control_group.add_option(
219
, help="Alter the seed value provided to the random query generator to vary test runs. (string) [%default]"
222
parser.add_option_group(test_exec_control_group)
224
test_control_group = optparse.OptionGroup(parser,
225
"Options for controlling which tests are executed")
227
test_control_group.add_option(
232
, callback=comma_list_split
233
, default = defaults['suitelist']
234
, help="The name of the suite containing tests we want. Can accept comma-separated list (with no spaces). Additional --suite args are appended to existing list [autosearch]"
237
test_control_group.add_option(
242
, default = defaults['suitepaths']
243
, help="The path containing the suite(s) you wish to execute. Use one --suitepath for each suite you want to use. [%default]"
246
test_control_group.add_option(
251
, help="input can either be a prefix or a regex. Will only execute tests that match the provided pattern"
254
test_control_group.add_option(
259
, help = "input can either be a prefix or a regex. Will exclude tests that match the provided pattern"
262
test_control_group.add_option(
265
, action="store_true"
267
, help = "sort the testcases so that they are executed optimally for the given mode [%default]"
270
test_control_group.add_option(
276
, help = "Run each test case the specified number of times. For a given sequence, the first test will be run n times, then the second, etc [%default]"
279
parser.add_option_group(test_control_group)
281
# test subject control group
282
# terrible name for options tht define the server / code
284
test_subject_control_group = optparse.OptionGroup(parser,
285
"Options for defining the code that will be under test")
287
test_subject_control_group.add_option(
293
, help = "Pass this argument to signal to the test-runner that this is an in-tree test. We automatically set a number of variables relative to the argument (client-bindir, serverdir, testdir) [%defaults['basedir']]"
296
test_subject_control_group.add_option(
297
"--default-server-type"
298
, dest="defaultservertype"
300
, default = defaults['server_type']
302
, help = "Defines what we consider to be the default server type. We assume a server is default type unless specified otherwise. [%default]"
305
test_subject_control_group.add_option(
310
, callback=get_abspath
311
, help = "Path to the server executable. [%default]"
314
test_subject_control_group.add_option(
316
, dest="clientbindir"
319
, callback=get_abspath
320
, help = "Path to the directory containing client program binaries for use in testing [%default]"
324
test_subject_control_group.add_option(
325
"--default-storage-engine"
326
, dest="defaultengine"
328
, help="Start drizzled using the specified engine [%default]"
332
parser.add_option_group(test_subject_control_group)
333
# end test subject control group
335
# environment options
337
environment_control_group = optparse.OptionGroup(parser,
338
"Options for defining the testing environment")
340
environment_control_group.add_option(
344
, default = defaults['testdir']
346
, callback=get_abspath
347
, help = "Path to the test dir, containing additional files for test execution. [%default]"
350
environment_control_group.add_option(
354
, default = defaults['workdir']
356
, callback=get_abspath
357
, help = "Path to the directory test-run will use to store generated files and directories. [%default]"
360
environment_control_group.add_option(
364
, default = defaults['basedir']
365
, help = "build option [%default]"
368
environment_control_group.add_option(
372
, default = defaults['basedir']
373
, help = "build option [%default]"
376
environment_control_group.add_option(
379
, action='store_true'
380
, default=defaults['noshm']
381
, help = "By default, we symlink workdir to a location in shm. Use this flag to not symlink [%default]"
384
environment_control_group.add_option(
386
, dest="libeatmydata"
387
, action='store_true'
389
, help = "We use libeatmydata (if available) to disable fsyncs and speed up test execution. Implies --no-shm"
392
environment_control_group.add_option(
393
"--libeatmydata-path"
394
, dest="libeatmydatapath"
396
, default='/usr/local/lib/libeatmydata.so'
397
, help = "Path to the libeatmydata install you want to use [%default]"
400
environment_control_group.add_option(
403
, action='store_true'
405
, help = "Don't try to clean up working directories before test execution [%default]"
408
environment_control_group.add_option(
409
"--no-secure-file-priv"
410
, dest = "nosecurefilepriv"
411
, action='store_true'
413
, help = "Turn off the use of --secure-file-priv=vardir for started servers"
416
environment_control_group.add_option(
420
, default=defaults['randgen_path']
421
, help = "The path to a randgen installation that can be used to execute randgen-based tests"
424
environment_control_group.add_option(
425
"--innobackupex-path"
426
, dest="innobackupexpath"
428
, default=defaults['innobackupexpath']
429
, help = "The path to the innobackupex script that facilitates the use of Xtrabackup"
432
environment_control_group.add_option(
434
, dest="xtrabackuppath"
436
, default=defaults['xtrabackuppath']
437
, help = "The path the xtrabackup binary to be tested"
440
environment_control_group.add_option(
444
, default=defaults['tar4ibdpath']
445
, help="The path to the tar4ibd binary that will be used for any applicable tests"
448
environment_control_group.add_option(
449
"--wsrep-provider-path"
450
, dest="wsrepprovider"
452
, default=defaults['wsrep_provider_path']
453
, help = "The path to a wsrep provider library for use with mysql"
456
environment_control_group.add_option(
461
, help = "The path to a config file defining a running cluster (node info)"
464
environment_control_group.add_option(
466
, dest="subunitoutfile"
468
, default=defaults['subunit_file']
469
, help = "File path where subunit output will be logged [%default]"
472
parser.add_option_group(environment_control_group)
473
# end environment control group
475
option_passing_group = optparse.OptionGroup(parser,
476
"Options to pass options on to the server")
478
option_passing_group.add_option(
480
, dest="drizzledoptions"
484
, help = "Pass additional options to the server. Will be passed to all servers for all tests (mostly for --start-and-exit)"
487
parser.add_option_group(option_passing_group)
488
# end option passing group
490
analysis_control_group = optparse.OptionGroup(parser,
491
"Options for defining the tools we use for code analysis (valgrind, gprof, gcov, etc)")
493
analysis_control_group.add_option(
496
, action='store_true'
498
, help = "Run drizzletest and drizzled executables using valgrind with default options [%default]"
501
analysis_control_group.add_option(
503
, dest="valgrindarglist"
506
, help = "Pass an option to valgrind (overrides/removes default valgrind options)"
509
analysis_control_group.add_option(
510
"--valgrind-suppressions"
511
, dest="valgrindsuppressions"
514
, default = defaults['valgrind_suppression']
515
, help = "Point at a valgrind suppression file [%default]"
518
analysis_control_group.add_option(
521
, action='store_true'
523
, help="Use the helgrind tool for valgrind. Implies / will auto-use --valgrind"
526
parser.add_option_group(analysis_control_group)
528
debugger_control_group = optparse.OptionGroup(parser,
529
"Options for controlling the use of debuggers with test execution")
531
debugger_control_group.add_option(
534
, action='store_true'
536
, help="Start the drizzled server(s) in gdb"
539
debugger_control_group.add_option(
542
, action='store_true'
544
, help="Allows you to start the drizzled server(s) in gdb manually (in another window, etc)"
547
parser.add_option_group(debugger_control_group)
549
utility_group = optparse.OptionGroup(parser,
550
"Options to call additional utilities such as datagen")
552
utility_group.add_option(
558
, help="Call the randgen's gendata utility to use the specified configuration file. This will populate the server prior to any test execution")
560
parser.add_option_group(utility_group)
562
# supplied will be those arguments matching an option,
563
# and test_cases will be everything else
564
(args, test_cases)= parser.parse_args()
567
variables = organize_options(args, test_cases)
568
variables = populate_defaults(variables, defaults['basedir'])
569
variables = handle_user_opts(variables, defaults)