2
# -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
3
# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
5
# Copyright (C) 2010 Patrick Crews
7
""" dtr_test_management:
8
code related to the gathering / analysis / management of
10
ie - collecting the list of tests in each suite, then
11
gathering additional, relevant information for the test-runner's dtr
12
mode. (traditional diff-based testing)
21
import lib.test_mgmt.test_management as test_management
26
"""Holds info on a per .test file basis
27
Attributes contain information necessary to execute / validate
28
the test file when it is executed.
31
def __init__(self, system_manager, test_case=None, test_name=None, suite_name=None
32
, suite_path=None, test_server_options=[], test_path=None, result_path=None
33
, comment=None, master_sh=None
34
, disable=0, innodb_test=1
35
, need_debug=0, debug=0):
36
self.system_manager = system_manager
37
self.logging = self.system_manager.logging
38
self.skip_keys = ['system_manager']
39
self.testcase = test_case
40
self.testname = test_name
41
self.suitename = suite_name
42
self.suitepath = suite_path
43
self.fullname = "%s.%s" %(suite_name, test_name)
44
self.testpath = test_path
45
self.resultpath = result_path
48
self.timezone = "GMT-3"
49
self.component_id = "drizzled"
52
self.server_options = test_server_options
53
self.comment = comment
54
self.master_sh = master_sh
55
self.disable = disable
56
self.innodb_test = innodb_test
57
self.need_debug = need_debug
59
self.system_manager.logging.debug_class(self)
62
if self.skip_flag or self.disable:
71
class testManager(test_management.testManager):
72
"""Deals with scanning test directories, gathering test cases, and
73
collecting per-test information (opt files, etc) for use by the
78
def process_suite(self,suite_dir):
79
"""Process a test suite.
80
This includes searching for tests in test_list and only
81
working with the named tests (all tests in suite is the default)
82
Further processing includes reading the disabled.def file
83
to know which tests to skip, processing the suite.opt file,
84
and processing the individual test cases for data relevant
85
to the rest of the test-runner
90
self.system_manager.logging.verbose("Processing suite: %s" %(suite_dir))
92
# Generate our test and result files:
93
testdir = os.path.join(suite_dir, 't')
94
resultdir = os.path.join(suite_dir, 'r')
96
# Do basic checks to make sure this is worth further work
97
self.check_suite(suite_dir, testdir, resultdir)
99
# Get suite-level options
101
suite_options = self.process_suite_options(suite_dir)
103
# Get the 'name' of the suite. This can require some processing
104
# But the name is useful for reporting and whatnot
105
suite_name = self.get_suite_name(suite_dir)
107
# Get the contents of the testdir and filter it accordingly
108
# This applies do-test / skip-test filters and any specific
110
testlist = self.testlist_filter(os.listdir(testdir))
111
# sort our list if no individual tests were specified
112
if not self.desired_tests:
115
# gather deeper information on tests we are interested in
117
# We have tests we want to process, we gather additional information
118
# that is useful at the suite level. This includes disabled tests
119
# Gather disabled test list.
120
# This is used in process_test_file()
122
disabled_tests = self.process_disabled_test_file(testdir)
123
for test_case in testlist:
124
self.add_test(self.process_test_file(suite_dir,
125
suite_name, suite_options
126
, disabled_tests, testdir
127
, resultdir, test_case))
129
def process_test_file(self, suite_dir, suite_name, suite_options
130
, disabled_tests, testdir
131
, resultdir, test_case):
132
""" We generate / find / store all the relevant information per-test.
133
This information will be used when actually executing the test
134
We store the data in a testCase object
138
test_server_options = suite_options
139
test_name = test_case.replace('.test','')
141
self.system_manager.logging.verbose("Processing test: %s.%s" %(suite_name,test_name))
144
# Fix this , create a testCase with gather_test_data() passed
146
# Ensure we pass everything we need and use it all
152
, test_server_options
155
, need_debug) = self.gather_test_data(test_case, test_name,
156
suite_name, test_server_options,testdir,
157
resultdir, disabled_tests)
158
test_case = testCase(self.system_manager, test_case, test_name, suite_name,
159
suite_dir, test_server_options,test_path, result_path,
164
########################################################################
167
# Stuff that helps us out and simplifies our main functions
168
# But isn't that important unless you need to dig deep
169
########################################################################
171
def gather_test_data(self, test_case, test_name, suite_name,
172
test_server_options, testdir, resultdir, disabled_tests):
173
""" We gather all of the data needed to produce a testCase for
178
(self, test_case=None, test_name=None, suite_name=None
179
, test_server_options=[], test_path=None, result_path=None
180
, comment=None, master_sh=None, disable=0, innodb_test=0
181
, need_debug=0, debug=0):
183
test_path = os.path.join(testdir,test_case)
184
result_file_name = test_name+'.result'
185
result_path = self.find_result_path(resultdir, result_file_name)
188
master_opt_path = test_path.replace('.test','-master.opt')
189
test_server_options = test_server_options + self.process_opt_file(
191
(disable, comment) = self.check_if_disabled(disabled_tests, test_name)
194
return (test_path, result_file_name, result_path, comment, master_sh,
195
test_server_options, disable, innodb_test, need_debug)
197
def check_suite(self, suite_dir, testdir, resultdir):
198
"""Handle basic checks of the suite:
199
does the suite exist?
205
# We expect suite to be a path name, no fuzzy searching
206
if not os.path.exists(suite_dir):
207
self.system_manager.logging.error("Suite: %s does not exist" %(suite_dir))
210
# Ensure our test and result directories are present
211
if not os.path.exists(testdir):
212
self.system_manager.logging.error("Suite: %s does not have a 't' directory (expected location for test files)" %(suite_dir))
214
if not os.path.exists(resultdir):
215
self.system_manager.logging.error("Suite: %s does not have an 'r' directory (expected location for result files)" %(suite_dir))
218
def get_suite_name(self, suite_dir):
219
""" Get the 'name' of the suite
220
This can either be the path basename or one directory up, as
221
in the case of files in the drizzle/plugins directory
225
# We trim any trailing path delimiters as python returns
226
# '' for basedir if the path ends that way
227
# BEGIN horrible hack to accomodate bad location of main suite : /
228
if suite_dir == self.testdir:
230
# END horrible hack : /
231
if suite_dir.endswith('/'):
232
suite_dir=suite_dir[:-1]
233
suite_dir_root,suite_dir_basename = os.path.split(suite_dir)
234
if suite_dir_basename == 'tests' or suite_dir_basename == 'drizzle-tests':
235
suite_name = os.path.basename(suite_dir_root)
237
suite_name = suite_dir_basename
239
self.system_manager.logging.debug("Suite_name: %s" %(suite_name))
242
def process_suite_options(self, suite_dir):
243
""" Process the suite.opt and master.opt files
244
that reside at the suite-level if they exist.
245
Return a list of the options found
249
opt_files = ['t/master.opt','t/suite.opt']
250
for opt_file in opt_files:
251
found_options = found_options + self.process_opt_file(os.path.join(suite_dir,opt_file))
254
def process_disabled_test_file(self, testdir):
255
""" Checks and processes the suite's disabled.def
256
file. This file must reside in the suite/t directory
257
It must be in the format:
258
test-name : comment (eg BugNNNN - bug on hold, test disabled)
259
In reality a test should *never* be disabled. EVER.
260
However, we keep this as a bit of utility
264
disabled_def_path = os.path.join(testdir,'disabled.def')
265
if not os.path.exists(disabled_def_path):
266
return disabled_tests
269
disabled_test_file = open(disabled_def_path,'r')
271
self.system_manager.logging.error("Problem opening disabled.def file: %s" %(disabled_def_path))
275
self.system_manager.logging.debug("Processing disabled.def file: %s" %(disabled_def_path))
276
disabled_bug_pattern = re.compile("[\S]+[\s]+:[\s]+[\S]")
278
for line in disabled_test_file:
280
if not line.startswith('#'): # comment
281
if re.match(disabled_test_pattern,line):
283
self.system_manager.logging.debug("found disabled test - %s" %(line))
284
test_name, test_comment = line.split(':')
285
disabled_tests[test_name.strip()]=test_comment.strip()
287
disabled_test_file.close()
288
return disabled_tests
291
def process_opt_file(self, opt_file_path):
292
""" Process a test-run '.opt' file.
293
These files contain test and suite-specific server options
294
(ie what options the server needs to use for the test)
296
Returns a list of the options (we don't really validate...yet)
298
NOTE: test-run.pl allows for server *and* system options
299
(eg timezone, slave_count, etc) in opt files. We don't.
300
None of our tests use this and we should probably avoid it
301
We can introduce server and system .opt files or even better
302
would be to use config files as we do with drizzle-automation
303
This would allow us to specify options for several different
304
things in a single file, but in a clean and standardized manner
308
if not os.path.exists(opt_file_path):
312
opt_file = open(opt_file_path,'r')
314
self.system_manager.logging.error("Problem opening option file: %s" %(opt_file_path))
318
self.system_manager.logging.debug("Processing opt file: %s" %(opt_file_path))
319
for line in opt_file:
320
options = line.split('--')
322
for option in options:
324
if 'restart' in option or '#' in option:
326
found_options.append('--%s' %(option.strip()))
330
def testlist_filter(self, testlist):
331
""" Filter our list of testdir contents based on several
332
criteria. This looks for user-specified test-cases
333
and applies the do-test and skip-test filters
335
Returns the list of tests that we want to execute
336
for further processing
340
# We want only .test files
341
# Possible TODO: allow alternate test extensions
342
testlist = [test_file for test_file in testlist if test_file.endswith('.test')]
344
# Search for specific test names
345
if self.desired_tests: # We have specific, named tests we want from the suite(s)
347
for test in self.desired_tests:
348
if test.endswith('.test'):
353
tests_to_use.append(test)
354
testlist = tests_to_use
356
# TODO: Allow for regex?
357
# Apply do-test filter
359
testlist = [test_file for test_file in testlist if test_file.startswith(self.dotest)]
360
# Apply skip-test filter
362
testlist = [test_file for test_file in testlist if not test_file.startswith(self.skiptest)]
365
def find_result_path(self, result_dir, result_file_name):
366
""" This is copied from test-run.pl dtr_cases.pl
367
If we have an engine option passed in and the
368
path resultdir/engine/testname.result exists, that is
371
Need to check if we really need this - maybe PBXT?
374
result_path = os.path.join(result_dir,result_file_name)
376
candidate_path = os.path.join(result_dir, self.engine,
378
if os.path.exists(candidate_path):
379
result_path = candidate_path
382
def check_if_disabled(self, disabled_tests, test_name):
383
""" Scan the list of disabled tests if it exists to see
384
if the test is disabled.
389
if test_name in disabled_tests:
391
self.system_manager.logging.debug("%s says - I'm disabled" %(test_name))
392
return (1, disabled_tests[test_name])