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
if variables['mode'] == 'randgen' or variables['gendatafile']:
74
print "Setting --no-secure-file-priv=True for randgen usage..."
75
variables['nosecurefilepriv']=True
76
if variables['mode'] == 'cleanup':
77
print "Setting --start-dirty=True for cleanup mode..."
78
variables['startdirty']=True
79
if variables['libeatmydata'] and os.path.exists(variables['libeatmydatapath']):
80
# We are using libeatmydata vs. shared mem for server speedup
81
print "Using libeatmydata at %s. Setting --no-shm / not using shared memory for testing..." %(variables['libeatmydatapath'])
82
variables['noshm']=True
85
def populate_defaults(variables, basedir_default):
86
""" We fill in any default values that need
87
to be put in post-parsing
90
if not variables['basedir']:
91
# We populate this value with the default now
92
# it allows us to have a default and have user
93
# supplied opts to override them
94
variables['basedir'].append(basedir_default)
97
def handle_user_opts(variables, basedir_default, testdir_default, suitepaths_default):
98
""" Some variables are dependent upon default values
99
We do the probably hacky thing of going through
100
and updating them accordingly
102
We make the assumption / decision that only
103
the first basedir value supplied should
104
be applicable when searching for tests
107
master_basedir = os.path.abspath(variables['basedir'][0])
108
if master_basedir != basedir_default:
109
new_path = os.path.join(master_basedir, 'plugin')
110
search_path = os.path.join(basedir_default,'plugin')
111
tmp = variables['suitepaths']
112
tmp[tmp.index(search_path)] = new_path
113
variables['suitepaths'] = tmp
114
if variables['testdir'] != testdir_default:
115
new_path = os.path.join(variables['testdir'],'suite')
116
search_path = os.path.join(testdir_default,'suite')
117
tmp = variables['suitepaths']
118
tmp[tmp.index(search_path)] = new_path
119
variables['suitepaths'] = tmp
123
# Create the CLI option parser
124
parser= optparse.OptionParser(version='%prog (database quality platform aka project steve austin) version 0.1.1')
126
# set some default values
127
testdir_default = os.path.abspath(os.getcwd())
128
workdir_default = os.path.join(testdir_default,'workdir')
129
clientbindir_default = os.path.abspath(os.path.join(testdir_default,'../client'))
130
basedir_default = os.path.split(testdir_default)[0]
131
server_type_default = 'drizzle'
132
valgrind_suppression_default = os.path.join(testdir_default,'valgrind.supp')
133
suitepaths_default = [ os.path.join(basedir_default,'plugin')
134
, os.path.join(testdir_default,'suite')
136
randgen_path_default = os.path.join(testdir_default,'randgen')
139
config_control_group = optparse.OptionGroup(parser,
140
"Configuration controls - allows you to specify a file with a number of options already specified")
141
config_control_group.add_option(
143
, dest="sysconfigfilepath"
145
, default=None # We want to have a file that will be our default defaults file...
146
, help="The file that specifies system configuration specs for dbqp to execute tests (not yet implemented)"
148
parser.add_option_group(config_control_group)
151
system_control_group = optparse.OptionGroup(parser,
152
"Options for the test-runner itself - defining the system under test and how to execute tests")
154
system_control_group.add_option(
157
, action="store_true"
159
, help="Set this to continue test execution beyond the first failed test"
162
system_control_group.add_option(
164
, dest="startandexit"
165
, action="store_true"
167
, help="Spin up the server(s) for the first specified test then exit (will leave servers running)"
170
system_control_group.add_option(
173
, action="store_true"
175
, help="Produces extensive output about test-runner state. Distinct from --debug"
178
system_control_group.add_option(
181
, action="store_true"
183
, help="Provide internal-level debugging output. Distinct from --verbose"
186
system_control_group.add_option(
190
, help="Testing mode. We currently support dtr, randgen, sysbench, sqlbench, crashme and cleanup modes. See docs for further details about individual modes [%default]"
193
system_control_group.add_option(
196
, action="store_true"
198
, help="Record a testcase result (if the testing mode supports it) [%default]"
201
system_control_group.add_option(
204
, action="store_true"
206
, help="Don't try to cleanup from earlier runs (currently just a placeholder) [%default]"
209
parser.add_option_group(system_control_group)
211
test_control_group = optparse.OptionGroup(parser,
212
"Options for controlling which tests are executed")
214
test_control_group.add_option(
219
, callback=comma_list_split
220
, 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]"
223
test_control_group.add_option(
228
, default = suitepaths_default
229
, help="The path containing the suite(s) you wish to execute. Use one --suitepath for each suite you want to use. [%default]"
232
test_control_group.add_option(
237
, help="input can either be a prefix or a regex. Will only execute tests that match the provided pattern"
240
test_control_group.add_option(
245
, help = "input can either be a prefix or a regex. Will exclude tests that match the provided pattern"
248
test_control_group.add_option(
251
, action="store_true"
253
, help = "sort the testcases so that they are executed optimally for the given mode [%default]"
256
test_control_group.add_option(
262
, 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]"
265
parser.add_option_group(test_control_group)
267
# test subject control group
268
# terrible name for options tht define the server / code
271
# find some default values
272
# assume we are in-tree testing in general and operating from root/test(?)
273
testdir_default = os.path.abspath(os.getcwd())
275
basedir_default = os.path.split(testdir_default)[0]
277
test_subject_control_group = optparse.OptionGroup(parser,
278
"Options for defining the code that will be under test")
280
test_subject_control_group.add_option(
286
, 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) [%basedir_default]"
289
test_subject_control_group.add_option(
290
"--default_server_type"
291
, dest="defaultservertype"
293
, default = server_type_default
295
, help = "Defines what we consider to be the default server type. We assume a server is default type unless specified otherwise. [%default]"
298
test_subject_control_group.add_option(
303
, callback=get_abspath
304
, help = "Path to the server executable. [%default]"
307
test_subject_control_group.add_option(
309
, dest="clientbindir"
312
, callback=get_abspath
313
, help = "Path to the directory containing client program binaries for use in testing [%default]"
317
test_subject_control_group.add_option(
318
"--default-storage-engine"
319
, dest="defaultengine"
321
, help="Start drizzled using the specified engine [%default]"
325
parser.add_option_group(test_subject_control_group)
326
# end test subject control group
328
# environment options
330
environment_control_group = optparse.OptionGroup(parser,
331
"Options for defining the testing environment")
333
environment_control_group.add_option(
337
, default = testdir_default
339
, callback=get_abspath
340
, help = "Path to the test dir, containing additional files for test execution. [%default]"
343
environment_control_group.add_option(
347
, default = workdir_default
349
, callback=get_abspath
350
, help = "Path to the directory test-run will use to store generated files and directories. [%default]"
353
environment_control_group.add_option(
357
, default = basedir_default
358
, help = "build option [%default]"
361
environment_control_group.add_option(
365
, default = basedir_default
366
, help = "build option [%default]"
369
environment_control_group.add_option(
372
, action='store_true'
374
, help = "By default, we symlink workdir to a location in shm. Use this flag to not symlink [%default]"
377
environment_control_group.add_option(
379
, dest="libeatmydata"
380
, action='store_true'
382
, help = "We use libeatmydata (if available) to disable fsyncs and speed up test execution. Implies --no-shm"
385
environment_control_group.add_option(
386
"--libeatmydata-path"
387
, dest="libeatmydatapath"
389
, default='/usr/local/lib/libeatmydata.so'
390
, help = "Path to the libeatmydata install you want to use [%default]"
393
environment_control_group.add_option(
396
, action='store_true'
398
, help = "Don't try to clean up working directories before test execution [%default]"
401
environment_control_group.add_option(
402
"--no-secure-file-priv"
403
, dest = "nosecurefilepriv"
404
, action='store_true'
406
, help = "Turn off the use of --secure-file-priv=vardir for started servers"
409
environment_control_group.add_option(
413
, default=randgen_path_default
414
, help = "The path to a randgen installation that can be used to execute randgen-based tests"
417
parser.add_option_group(environment_control_group)
418
# end environment control group
420
option_passing_group = optparse.OptionGroup(parser,
421
"Options to pass options on to the server")
423
option_passing_group.add_option(
425
, dest="drizzledoptions"
429
, help = "Pass additional options to the server. Will be passed to all servers for all tests (mostly for --start-and-exit)"
432
parser.add_option_group(option_passing_group)
433
# end option passing group
435
analysis_control_group = optparse.OptionGroup(parser,
436
"Options for defining the tools we use for code analysis (valgrind, gprof, gcov, etc)")
438
analysis_control_group.add_option(
441
, action='store_true'
443
, help = "Run drizzletest and drizzled executables using valgrind with default options [%default]"
446
analysis_control_group.add_option(
448
, dest="valgrindarglist"
451
, help = "Pass an option to valgrind (overrides/removes default valgrind options)"
454
analysis_control_group.add_option(
455
"--valgrind-suppressions"
456
, dest="valgrindsuppressions"
459
, default = valgrind_suppression_default
460
, help = "Point at a valgrind suppression file [%default]"
463
parser.add_option_group(analysis_control_group)
465
debugger_control_group = optparse.OptionGroup(parser,
466
"Options for controlling the use of debuggers with test execution")
468
debugger_control_group.add_option(
471
, action='store_true'
473
, help="Start the drizzled server(s) in gdb"
476
debugger_control_group.add_option(
479
, action='store_true'
481
, help="Allows you to start the drizzled server(s) in gdb manually (in another window, etc)"
484
parser.add_option_group(debugger_control_group)
486
utility_group = optparse.OptionGroup(parser,
487
"Options to call additional utilities such as datagen")
489
utility_group.add_option(
495
, help="Call the randgen's gendata utility to use the specified configuration file. This will populate the server prior to any test execution")
497
parser.add_option_group(utility_group)
499
# supplied will be those arguments matching an option,
500
# and test_cases will be everything else
501
(args, test_cases)= parser.parse_args()
504
variables = organize_options(args, test_cases)
505
variables = populate_defaults(variables, basedir_default)
506
variables = handle_user_opts(variables, basedir_default, testdir_default, suitepaths_default)