~drizzle-trunk/drizzle/development

2144.1.1 by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control
1
#! /usr/bin/env python
2235.5.2 by Stewart Smith
dbqp source (and all its libs) should use emacs python mode, not emacs C mode
2
# -*- mode: python; indent-tabs-mode: nil; -*-
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
3
# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
#
2337.1.1 by patrick crews
Cleanup of option handling + test modes. Initial work for expanding dbqp capabilities to do neat things
5
# Copyright (C) 2010, 2011 Patrick Crews
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
6
#
2121.3.2 by patrick crews
Updated license verbiage
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.
11
#
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.
16
#
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
2121.3.1 by patrick crews
Added licensing text to dbqp files
20
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
21
22
23
"""Processes command line options for Drizzle test-runner"""
24
2337.1.1 by patrick crews
Cleanup of option handling + test modes. Initial work for expanding dbqp capabilities to do neat things
25
import os
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
26
import sys
2337.1.1 by patrick crews
Cleanup of option handling + test modes. Initial work for expanding dbqp capabilities to do neat things
27
import copy
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
28
import exceptions
29
import optparse
30
31
# functions
32
def comma_list_split(option, opt, value, parser):
33
    """Callback for splitting input expected in list form"""
2121.5.2 by patrick crews
Updates to option parser to allow for comma separated lists of suites as argument to --suite. Additional --suite arguments appends the values to previously encountered --suite values
34
    cur_list = getattr(parser.values, option.dest,[])
2124.2.6 by Patrick Crews
make target for dbqp! : )
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
38
    if '' in input_list:
39
        input_list.remove('')
2121.5.2 by patrick crews
Updates to option parser to allow for comma separated lists of suites as argument to --suite. Additional --suite arguments appends the values to previously encountered --suite values
40
    if cur_list:
2124.2.6 by Patrick Crews
make target for dbqp! : )
41
        value_list = cur_list + input_list 
2121.5.2 by patrick crews
Updates to option parser to allow for comma separated lists of suites as argument to --suite. Additional --suite arguments appends the values to previously encountered --suite values
42
    else:
2124.2.6 by Patrick Crews
make target for dbqp! : )
43
        value_list = input_list 
2121.5.2 by patrick crews
Updates to option parser to allow for comma separated lists of suites as argument to --suite. Additional --suite arguments appends the values to previously encountered --suite values
44
    setattr(parser.values, option.dest, value_list)
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
45
2337.1.21 by patrick crews
Cleanup of option parser
46
def get_abspath(option, opt, value, parser):
47
    """ Utility function to make sure we have absolute paths
48
        if the user supplies values
49
50
    """
51
    the_path = os.path.abspath(value)
52
    setattr(parser.values, option.dest, the_path)
53
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
54
def organize_options(args, test_cases):
55
    """Put our arguments in a nice dictionary
56
       We use option.dest as dictionary key
57
       item = supplied input
2337.1.3 by patrick crews
Added ability to use libeatmydata as LD_PRELOAD for servers. Need to update docs
58
 ['
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
59
    """
60
    variables = {}
2337.1.1 by patrick crews
Cleanup of option handling + test modes. Initial work for expanding dbqp capabilities to do neat things
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))
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
65
    variables['test_cases']= test_cases
2167.4.2 by patrick crews
Various tweaks and fixes
66
    # This code should become a function once
67
    # enough thought has been given to it
2158.2.1 by patrick crews
Added in --gdb and --manual-gdb option as well as --drizzled option
68
    if variables['manualgdb']:
69
        variables['gdb']=True
2167.4.2 by patrick crews
Various tweaks and fixes
70
    if variables['repeat'] <= 0:
71
        print "Setting --repeat=1.  You chose a silly value that I will ignore :P"
72
        variables['repeat'] = 1
2337.1.1 by patrick crews
Cleanup of option handling + test modes. Initial work for expanding dbqp capabilities to do neat things
73
    if variables['mode'] == 'randgen' or variables['gendatafile']:
74
        print "Setting --no-secure-file-priv=True for randgen usage..."
2194.2.1 by patrick crews
Integrated randgen with dbqp. We now have mode=randgen and a set of randgen test suites (very basic now). Output = same as dtr : ) We also have mode=cleanup to kill any servers we have started. Docs updates too. Gendata utility allows us to populate test servers
75
        variables['nosecurefilepriv']=True
76
    if variables['mode'] == 'cleanup':
77
        print "Setting --start-dirty=True for cleanup mode..."
78
        variables['startdirty']=True
2337.1.3 by patrick crews
Added ability to use libeatmydata as LD_PRELOAD for servers. Need to update docs
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
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
83
    return variables
84
2337.1.17 by patrick crews
Additional work for running MySQL servers (still not ready for prime-time / working)
85
def populate_defaults(variables, basedir_default):
86
    """ We fill in any default values that need
87
        to be put in post-parsing
88
89
    """
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)
95
    return variables
96
2337.1.21 by patrick crews
Cleanup of option parser
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
101
102
        We make the assumption / decision that only
103
        the first basedir value supplied should
104
        be applicable when searching for tests
105
106
    """
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
120
    return variables
121
122
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
123
# Create the CLI option parser
2337.1.1 by patrick crews
Cleanup of option handling + test modes. Initial work for expanding dbqp capabilities to do neat things
124
parser= optparse.OptionParser(version='%prog (database quality platform aka project steve austin) version 0.1.1')
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
125
2337.1.21 by patrick crews
Cleanup of option parser
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')
135
                     ]
136
randgen_path_default = os.path.join(testdir_default,'randgen')
137
138
2337.1.2 by patrick crews
Additional tweaks
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(
2337.1.12 by patrick crews
Additional work on allowing dbqp to handle multiple server types / versions (even simultaneously)
142
   "--sys_config_file"
143
    , dest="sysconfigfilepath"
2337.1.1 by patrick crews
Cleanup of option handling + test modes. Initial work for expanding dbqp capabilities to do neat things
144
    , action='store'
145
    , default=None # We want to have a file that will be our default defaults file...
2337.1.15 by patrick crews
Code cleanup / reorganization
146
    , help="The file that specifies system configuration specs for dbqp to execute tests (not yet implemented)"
2337.1.1 by patrick crews
Cleanup of option handling + test modes. Initial work for expanding dbqp capabilities to do neat things
147
    )
2337.1.2 by patrick crews
Additional tweaks
148
parser.add_option_group(config_control_group)
2337.1.1 by patrick crews
Cleanup of option handling + test modes. Initial work for expanding dbqp capabilities to do neat things
149
2337.1.21 by patrick crews
Cleanup of option parser
150
151
system_control_group = optparse.OptionGroup(parser, 
152
                         "Options for the test-runner itself - defining the system under test and how to execute tests")
153
154
system_control_group.add_option(
155
      "--force"
156
    , dest="force"
157
    , action="store_true"
158
    , default=False
159
    , help="Set this to continue test execution beyond the first failed test"
160
    )
161
162
system_control_group.add_option(
163
       "--start-and-exit"
164
     , dest="startandexit"
165
     , action="store_true"
166
     , default=False
167
     , help="Spin up the server(s) for the first specified test then exit (will leave servers running)"
168
     )
169
170
system_control_group.add_option(
171
       "--verbose"
172
     , dest="verbose"
173
     , action="store_true"
174
     , default = False
175
     , help="Produces extensive output about test-runner state.  Distinct from --debug"
176
     )
177
   
178
system_control_group.add_option(
179
       "--debug"
180
     , dest="debug"
181
     , action="store_true"
182
     , default = False
183
     , help="Provide internal-level debugging output.  Distinct from --verbose"
184
     )
185
186
system_control_group.add_option(
187
       "--mode"
188
     , dest="mode"
189
     , default="dtr"
190
     , help="Testing mode.  We currently support dtr, randgen, sysbench, sqlbench, crashme and cleanup modes.  See docs for further details about individual modes [%default]"
191
     )
192
193
system_control_group.add_option(
194
       "--record"
195
     , dest="record"
196
     , action="store_true"
197
     , default=False
198
     , help="Record a testcase result (if the testing mode supports it) [%default]"
199
     )
200
201
system_control_group.add_option(
202
       "--fast"
203
     , dest="fast"
204
     , action="store_true"
205
     , default=False
206
     , help="Don't try to cleanup from earlier runs (currently just a placeholder) [%default]"
207
     )
208
   
209
parser.add_option_group(system_control_group)
210
211
test_control_group = optparse.OptionGroup(parser, 
212
                         "Options for controlling which tests are executed")
213
214
test_control_group.add_option(
215
    "--suite"
216
  , dest="suitelist"
217
  , type='string'
218
  , action="callback"
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]"
221
  )
222
223
test_control_group.add_option(
224
    "--suitepath"
225
  , dest="suitepaths"
226
  , type='string'
227
  , action="append"
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]"
230
  )
231
232
test_control_group.add_option(
233
    "--do-test"
234
  , dest="dotest"
235
  , type='string'
236
  , default = None
237
  , help="input can either be a prefix or a regex. Will only execute tests that match the provided pattern"
238
  )
239
240
test_control_group.add_option(
241
    "--skip-test"
242
  , dest="skiptest"
243
  , type='string'
244
  , default = None
245
  , help = "input can either be a prefix or a regex.  Will exclude tests that match the provided pattern"
246
  )
247
248
test_control_group.add_option(
249
    "--reorder"
250
  , dest="reorder"
251
  , action="store_true"
252
  , default=False
253
  , help = "sort the testcases so that they are executed optimally for the given mode [%default]"
254
  )
255
256
test_control_group.add_option(
257
    "--repeat"
258
  , dest="repeat"
259
  , type='int'
260
  , action="store"
261
  , default=1
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]"
263
  )
264
265
parser.add_option_group(test_control_group)
266
267
# test subject control group
268
# terrible name for options tht define the server / code
269
# that is under test
270
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())
274
275
basedir_default = os.path.split(testdir_default)[0]
276
277
test_subject_control_group = optparse.OptionGroup(parser,
278
                                 "Options for defining the code that will be under test")
279
280
test_subject_control_group.add_option(
281
    "--basedir"
282
  , dest="basedir"
283
  , type='string'
284
  , default = []
285
  , action="append"
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]"
287
  )
288
289
test_subject_control_group.add_option(
290
    "--default_server_type"
291
  , dest="defaultservertype"
292
  , type='string'
293
  , default = server_type_default
294
  , action='store'
295
  , help = "Defines what we consider to be the default server type.  We assume a server is default type unless specified otherwise. [%default]"
296
  )
297
298
test_subject_control_group.add_option(
299
    "--serverdir"
300
  , dest="serverpath"
301
  , type='string'
302
  , action="callback"
303
  , callback=get_abspath
304
  , help = "Path to the server executable.  [%default]"
305
  )
306
307
test_subject_control_group.add_option(
308
    "--client-bindir"
309
  , dest="clientbindir"
310
  , type = 'string'
311
  , action="callback"
312
  , callback=get_abspath
313
  , help = "Path to the directory containing client program binaries for use in testing [%default]"
314
  )
315
316
317
test_subject_control_group.add_option(
318
    "--default-storage-engine"
319
   , dest="defaultengine"
320
   , default = 'innodb'
321
   , help="Start drizzled using the specified engine [%default]"
322
   )    
323
324
325
parser.add_option_group(test_subject_control_group)
326
# end test subject control group
327
328
# environment options
329
330
environment_control_group = optparse.OptionGroup(parser, 
331
                            "Options for defining the testing environment")
332
333
environment_control_group.add_option(
334
    "--testdir"
335
  , dest="testdir"
336
  , type = 'string'
337
  , default = testdir_default
338
  , action="callback"
339
  , callback=get_abspath
340
  , help = "Path to the test dir, containing additional files for test execution. [%default]"
341
  )
342
343
environment_control_group.add_option(
344
    "--workdir"
345
  , dest="workdir"
346
  , type='string'
347
  , default = workdir_default
348
  , action="callback"
349
  , callback=get_abspath
350
  , help = "Path to the directory test-run will use to store generated files and directories. [%default]"
351
  )
352
353
environment_control_group.add_option(
354
    "--top-srcdir"
355
  , dest="topsrcdir"
356
  , type='string'
357
  , default = basedir_default
358
  , help = "build option [%default]"
359
  )
360
361
environment_control_group.add_option(
362
    "--top-builddir"
363
  , dest="topbuilddir"
364
  , type='string'
365
  , default = basedir_default
366
  , help = "build option [%default]"
367
  )
368
369
environment_control_group.add_option(
370
    "--no-shm"
371
  , dest="noshm"
372
  , action='store_true'
373
  , default=False
374
  , help = "By default, we symlink workdir to a location in shm.  Use this flag to not symlink [%default]"
375
  )
376
377
environment_control_group.add_option(
378
    "--libeatmydata"
379
  , dest="libeatmydata"
380
  , action='store_true'
381
  , default=False
382
  , help = "We use libeatmydata (if available) to disable fsyncs and speed up test execution.  Implies --no-shm"
383
  )
384
385
environment_control_group.add_option(
386
    "--libeatmydata-path"
387
  , dest="libeatmydatapath"
388
  , action='store'
389
  , default='/usr/local/lib/libeatmydata.so'
390
  , help = "Path to the libeatmydata install you want to use [%default]"
391
  )
392
393
environment_control_group.add_option(
394
    "--start-dirty"
395
  , dest="startdirty"
396
  , action='store_true'
397
  , default=False
398
  , help = "Don't try to clean up working directories before test execution [%default]"
399
  )
400
401
environment_control_group.add_option(
402
    "--no-secure-file-priv"
403
  , dest = "nosecurefilepriv"
404
  , action='store_true'
405
  , default=False
406
  , help = "Turn off the use of --secure-file-priv=vardir for started servers"
407
  )
408
409
environment_control_group.add_option(
410
       "--randgen-path"
411
     , dest="randgenpath"
412
     , action='store'
413
     , default=randgen_path_default
414
     , help = "The path to a randgen installation that can be used to execute randgen-based tests"
415
     )
416
417
parser.add_option_group(environment_control_group)
418
# end environment control group
419
420
option_passing_group = optparse.OptionGroup(parser,
421
                      "Options to pass options on to the server")
422
423
option_passing_group.add_option(
424
"--drizzled"
425
  , dest="drizzledoptions"
426
  , type='string'
427
  , action='append' 
428
  , default = []
429
  , help = "Pass additional options to the server.  Will be passed to all servers for all tests (mostly for --start-and-exit)"
430
  )
431
432
parser.add_option_group(option_passing_group)
433
# end option passing group
434
435
analysis_control_group = optparse.OptionGroup(parser, 
436
                            "Options for defining the tools we use for code analysis (valgrind, gprof, gcov, etc)")
437
438
analysis_control_group.add_option(
439
    "--valgrind"
440
  , dest="valgrind"
441
  , action='store_true'
442
  , default = False
443
  , help = "Run drizzletest and drizzled executables using valgrind with default options [%default]"
444
  )
445
446
analysis_control_group.add_option(
447
    "--valgrind-option"
448
  , dest="valgrindarglist"
449
  , type='string'
450
  , action="append"
451
  , help = "Pass an option to valgrind (overrides/removes default valgrind options)"
452
  )
453
454
analysis_control_group.add_option(
455
    "--valgrind-suppressions"
456
  , dest="valgrindsuppressions"
457
  , type='string'
458
  , action='store'
459
  , default = valgrind_suppression_default
460
  , help = "Point at a valgrind suppression file [%default]"
461
  )
462
463
parser.add_option_group(analysis_control_group)
464
465
debugger_control_group = optparse.OptionGroup(parser,
466
                           "Options for controlling the use of debuggers with test execution")
467
468
debugger_control_group.add_option(
469
    "--gdb"
470
  , dest="gdb"
471
  , action='store_true'
472
  , default=False
473
  , help="Start the drizzled server(s) in gdb"
474
  )
475
476
debugger_control_group.add_option(
477
    "--manual-gdb"
478
  , dest="manualgdb"
479
  , action='store_true'
480
  , default=False
481
  , help="Allows you to start the drizzled server(s) in gdb manually (in another window, etc)"
482
  )
483
484
parser.add_option_group(debugger_control_group)
485
486
utility_group = optparse.OptionGroup(parser,
487
                  "Options to call additional utilities such as datagen")
488
489
utility_group.add_option(
490
    "--gendata"
491
  , dest="gendatafile"
492
  , action='store'
493
  , type='string'
494
  , default=None
495
  , help="Call the randgen's gendata utility to use the specified configuration file.  This will populate the server prior to any test execution")
496
497
parser.add_option_group(utility_group)
2194.2.1 by patrick crews
Integrated randgen with dbqp. We now have mode=randgen and a set of randgen test suites (very basic now). Output = same as dtr : ) We also have mode=cleanup to kill any servers we have started. Docs updates too. Gendata utility allows us to populate test servers
498
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
499
# supplied will be those arguments matching an option, 
500
# and test_cases will be everything else
501
(args, test_cases)= parser.parse_args()
502
503
variables = {}
504
variables = organize_options(args, test_cases)
2337.1.17 by patrick crews
Additional work for running MySQL servers (still not ready for prime-time / working)
505
variables = populate_defaults(variables, basedir_default)
2337.1.21 by patrick crews
Cleanup of option parser
506
variables = handle_user_opts(variables, basedir_default, testdir_default, suitepaths_default)
2088.9.1 by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time
507