Merge lp:~patrick-crews/drizzle/dbqp_randgen into lp:drizzle/7.0

Proposed by Patrick Crews
Status: Merged
Approved by: Brian Aker
Approved revision: 2195
Merged at revision: 2196
Proposed branch: lp:~patrick-crews/drizzle/dbqp_randgen
Merge into: lp:drizzle/7.0
Diff against target: 1616 lines (+882/-204)
22 files modified
.bzrignore (+1/-3)
docs/testing/dbqp.rst (+87/-8)
tests/include.am (+2/-2)
tests/lib/drizzle_test_run/dtr_test_execution.py (+2/-1)
tests/lib/drizzle_test_run/dtr_test_management.py (+3/-6)
tests/lib/randgen/randgen_test_execution.py (+175/-0)
tests/lib/randgen/randgen_test_management.py (+149/-0)
tests/lib/server_mgmt/drizzled.py (+54/-90)
tests/lib/server_mgmt/server.py (+156/-0)
tests/lib/server_mgmt/server_management.py (+28/-19)
tests/lib/sys_mgmt/port_management.py (+3/-3)
tests/lib/sys_mgmt/system_management.py (+33/-0)
tests/lib/test_mgmt/execution_management.py (+1/-1)
tests/lib/test_mgmt/test_execution.py (+67/-44)
tests/lib/test_mgmt/test_management.py (+15/-11)
tests/lib/test_mode.py (+33/-14)
tests/lib/test_run_options.py (+30/-2)
tests/randgen_tests/main/optimizer_subquery.cnf (+8/-0)
tests/randgen_tests/main/outer_join.cnf (+8/-0)
tests/randgen_tests/main/simple.cnf (+9/-0)
tests/randgen_tests/slave_plugin/slave_plugin.disabled (+9/-0)
tests/randgen_tests/trx_log/simple.cnf (+9/-0)
To merge this branch: bzr merge lp:~patrick-crews/drizzle/dbqp_randgen
Reviewer Review Type Date Requested Status
Drizzle Developers Pending
Review via email: mp+50960@code.launchpad.net

Description of the change

We now have a randgen-mode : )
A variety of tweaks / changes and fixes are included.
Also added --gendata option that will call the randgen's gendata utility before executing any test - can be useful for ad-hoc or other testing.
randgen tests are organized and execute exactly as dtr tests:
http://paste.drizzle.org/show/403/

Have done some basic tests and have a separate bug for bringing drizzle-automation randgen tests to the tree.

Updated docs to reflect the changes

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2011-02-22 04:19:44 +0000
3+++ .bzrignore 2011-02-23 17:24:15 +0000
4@@ -327,6 +327,7 @@
5 tests/test-run@
6 tests/total_warning_count
7 tests/var
8+tests/workdir
9 thr_malloc.gcno
10 time.gcno
11 tmp_table.gcno
12@@ -345,6 +346,3 @@
13 drizzled/message/catalog.pb.h
14 drizzled/message/catalog_reader
15 drizzled/message/catalog_writer
16-drizzled/message/replication_options.pb.cc
17-drizzled/message/replication_options.pb.h
18-libdrizzle/mysql_password_hash
19
20=== modified file 'docs/testing/dbqp.rst'
21--- docs/testing/dbqp.rst 2011-02-14 21:47:46 +0000
22+++ docs/testing/dbqp.rst 2011-02-23 17:24:15 +0000
23@@ -13,11 +13,7 @@
24 :program:`dbqp.py` is BETA software. It is intended to provide a standardized
25 platform to facilitate Drizzle testing.
26
27-Currently, it only serves as a partial substitute for test-run.pl.
28-One can execute the test suite, record test cases, and use certain other options.
29-Other test-run.pl option such as gdb and valgrind are still in-development.
30-
31-The current mode is 'dtr' and is used to execute tests from the Drizzle
32+The default mode is 'dtr' and is used to execute tests from the Drizzle
33 test suite. These tests are included with Drizzle distributions and
34 provide a way for users to verify that the system will operate according
35 to expectations.
36@@ -28,6 +24,14 @@
37 highlighting the differences found between expected and actual results; this
38 can be useful for troubleshooting and in bug reports.
39
40+The program is also integrated with the random query generator testing tool
41+and a 'rangden' mode is available - it will execute randgen tests when
42+provided a path to a randgen installation. Tests are organized similar to dtr
43+tests, but are .cnf file based.
44+
45+A 'cleanup' mode is also available as a convenience - it will simply shutdown
46+any servers that may have been started via start-and-exit.
47+
48 While most users are concerned with ensuring general functionality, the
49 program also allows a user to quickly spin up a server for ad-hoc testing
50 and to run the test-suite against an already running Drizzle server.
51@@ -150,10 +154,69 @@
52
53 NOTE: This feature is still being tested, use caution with your data!!!
54
55+Randgen mode / Executing randgen tests
56+---------------------------------------
57+
58+Using :option:`--mode` =randgen and :option:`--randgen-path` =/path/to/randgen
59+will cause the randgen tests to execute. This are simple .cnf file-based
60+tests that define various randgen command lines that are useful in testing
61+the server. Test organization is similar to the dtr tests. Tests live in
62+suites, the default suite is 'main' and they all live in
63+drizzle/tests/randgen_tests::
64+
65+ ./dbqp.py --mode=randgen --randgen-path=/path/to/randgen
66+
67+A user may specify suites and individual tests to run, just as with dtr-based
68+testing. Test output is the same as well::
69+
70+ ./dbqp --mode=randgen --randgen-path=/home/username/repos/randgen
71+ Setting --no-secure-file-priv=True for randgen mode...
72+ <snip>
73+ 23 Feb 2011 11:42:43 INFO: Using testing mode: randgen
74+ <snip>
75+ 23 Feb 2011 11:44:58 : ================================================================================
76+ 23 Feb 2011 11:44:58 : TEST NAME [ RESULT ] TIME (ms)
77+ 23 Feb 2011 11:44:58 : ================================================================================
78+ 23 Feb 2011 11:44:58 : main.optimizer_subquery [ pass ] 134153
79+ 23 Feb 2011 11:45:03 : main.outer_join [ pass ] 5136
80+ 23 Feb 2011 11:45:06 : main.simple [ pass ] 2246
81+ 23 Feb 2011 11:45:06 : ================================================================================
82+ 23 Feb 2011 11:45:06 INFO: Test execution complete in 142 seconds
83+ 23 Feb 2011 11:45:06 INFO: Summary report:
84+ 23 Feb 2011 11:45:06 INFO: Executed 3/3 test cases, 100.00 percent
85+ 23 Feb 2011 11:45:06 INFO: STATUS: PASS, 3/3 test cases, 100.00 percent executed
86+ 23 Feb 2011 11:45:06 INFO: Spent 141 / 142 seconds on: TEST(s)
87+ 23 Feb 2011 11:45:06 INFO: Test execution complete
88+ 23 Feb 2011 11:45:06 INFO: Stopping all running servers...
89+
90+Cleanup mode
91+-------------
92+A cleanup mode is provided for user convenience. This simply shuts down
93+any servers whose pid files are detected in the dbqp workdir. It is mainly
94+intended as a quick cleanup for post-testing with :option:`--start-and-exit`::
95+
96+ ./dbqp.py --mode=cleanup
97+
98+ Setting --start-dirty=True for cleanup mode...
99+ 23 Feb 2011 11:35:59 INFO: Using Drizzle source tree:
100+ 23 Feb 2011 11:35:59 INFO: basedir: drizzle
101+ 23 Feb 2011 11:35:59 INFO: clientbindir: drizzle/client
102+ 23 Feb 2011 11:35:59 INFO: testdir: drizzle/tests
103+ 23 Feb 2011 11:35:59 INFO: server_version: 2011.02.2188
104+ 23 Feb 2011 11:35:59 INFO: server_compile_os: unknown-linux-gnu
105+ 23 Feb 2011 11:35:59 INFO: server_platform: x86_64
106+ 23 Feb 2011 11:35:59 INFO: server_comment: (Source distribution (dbqp_randgen))
107+ 23 Feb 2011 11:35:59 INFO: Using --start-dirty, not attempting to touch directories
108+ 23 Feb 2011 11:35:59 INFO: Using default-storage-engine: innodb
109+ 23 Feb 2011 11:35:59 INFO: Using testing mode: cleanup
110+ 23 Feb 2011 11:35:59 INFO: Killing pid 10484 from drizzle/tests/workdir/testbot0/server0/var/run/server0.pid
111+ 23 Feb 2011 11:35:59 INFO: Stopping all running servers...
112+
113 Program architecture
114 ====================
115
116-:program:`dbqp.py` uses a simple diff-based mechanism for testing.
117+:program:`dbqp.py`'s 'dtr' mode uses a simple diff-based mechanism for testing.
118+This is the default mode and where the majority of Drizzle testing occurs.
119 It will execute the statements contained in a test and compare the results
120 to pre-recorded expected results. In the event of a test failure, you
121 will be presented with a diff::
122@@ -225,6 +288,12 @@
123 Don't try to cleanup from earlier runs
124 (currently just a placeholder) [False]
125
126+.. option:: --randgen-path=RANDGENPATH
127+
128+ The path to a randgen installation that can be used to
129+ execute randgen-based tests
130+
131+
132 Options for controlling which tests are executed
133 ------------------------------------------------
134 .. option:: --suite=SUITELIST
135@@ -255,6 +324,7 @@
136 for the given mode [False]
137
138 .. option:: --repeat=REPEAT
139+
140 Run each test case the specified number of times. For
141 a given sequence, the first test will be run n times,
142 then the second, etc [1]
143@@ -329,7 +399,7 @@
144
145
146 Options for defining the tools we use for code analysis (valgrind, gprof, gcov, etc)
147----------------------------------------------------------------------------------------
148+------------------------------------------------------------------------------------
149 .. option:: --valgrind
150
151 Run drizzletest and drizzled executables using
152@@ -341,7 +411,7 @@
153 valgrind options)
154
155 Options for controlling the use of debuggers with test execution
156-------------------------------------------------------------------
157+----------------------------------------------------------------
158 .. option:: --gdb
159
160 Start the drizzled server(s) in gdb
161@@ -351,6 +421,15 @@
162 Allows you to start the drizzled server(s) in gdb
163 manually (in another window, etc
164
165+Options to call additional utilities such as datagen
166+------------------------------------------------------
167+.. option:: --gendata=GENDATAFILE
168+
169+ Call the randgen's gendata utility to use the
170+ specified configuration file. This will populate the
171+ server prior to any test execution
172+
173+
174
175
176
177
178=== modified file 'tests/include.am'
179--- tests/include.am 2011-02-16 17:05:26 +0000
180+++ tests/include.am 2011-02-23 17:24:15 +0000
181@@ -54,7 +54,7 @@
182 --reorder \
183 --basedir=../${top_srcdir} \
184 --testdir=../${top_srcdir}/tests \
185- --workdir=../${top_srcdir}/tests/dbqp_work
186+ --workdir=../${top_srcdir}/tests/workdir
187
188
189 EXTRA_DIST += \
190@@ -160,7 +160,7 @@
191
192 nukevar:
193 rm -rf tests/var \
194- rm -rf tests/dbqp_work \
195+ rm -rf tests/workdir \
196 rm tests/dbqp_data/*
197
198
199
200=== modified file 'tests/lib/drizzle_test_run/dtr_test_execution.py'
201--- tests/lib/drizzle_test_run/dtr_test_execution.py 2011-02-10 02:05:07 +0000
202+++ tests/lib/drizzle_test_run/dtr_test_execution.py 2011-02-23 17:24:15 +0000
203@@ -37,7 +37,7 @@
204
205 import lib.test_mgmt.test_execution as test_execution
206
207-class dtrTestExecutor(test_execution.testExecutor):
208+class testExecutor(test_execution.testExecutor):
209 """ dtr-specific testExecutor
210 We currently execute by sending test-case
211 data to client/drizzletest...for now
212@@ -172,6 +172,7 @@
213 , 'RABBITMQ_NODE_PORT': str(self.master_server.rabbitmq_node_port)
214 , 'DRIZZLE_TCP_PORT': str(self.master_server.drizzle_tcp_port)
215 , 'EXE_DRIZZLE': self.master_server.drizzle_client
216+ , 'MASTER_SERVER_SLAVE_CONFIG' : self.master_server.slave_config_file
217 , 'DRIZZLE_DUMP': "%s --no-defaults -uroot -p%d" %( self.master_server.drizzledump
218 , self.master_server.master_port)
219 , 'DRIZZLE_SLAP': "%s -uroot -p%d" %( self.master_server.drizzleslap
220
221=== modified file 'tests/lib/drizzle_test_run/dtr_test_management.py'
222--- tests/lib/drizzle_test_run/dtr_test_management.py 2011-02-04 20:41:08 +0000
223+++ tests/lib/drizzle_test_run/dtr_test_management.py 2011-02-23 17:24:15 +0000
224@@ -64,6 +64,8 @@
225 self.slave_count = 0
226 self.master_count = 1
227 self.server_options = test_server_options
228+ # We will populate this in a better fashion later on
229+ self.server_requirements=[self.server_options]
230 self.comment = comment
231 self.master_sh = master_sh
232 self.disable = disable
233@@ -188,12 +190,7 @@
234 a given test
235
236 """
237- """
238- (self, test_case=None, test_name=None, suite_name=None
239- , test_server_options=[], test_path=None, result_path=None
240- , comment=None, master_sh=None, disable=0, innodb_test=0
241- , need_debug=0, debug=0):
242- """
243+
244 test_path = os.path.join(testdir,test_case)
245 result_file_name = test_name+'.result'
246 result_path = self.find_result_path(resultdir, result_file_name)
247
248=== added directory 'tests/lib/randgen'
249=== added file 'tests/lib/randgen/__init__.py'
250=== added file 'tests/lib/randgen/randgen_test_execution.py'
251--- tests/lib/randgen/randgen_test_execution.py 1970-01-01 00:00:00 +0000
252+++ tests/lib/randgen/randgen_test_execution.py 2011-02-23 17:24:15 +0000
253@@ -0,0 +1,175 @@
254+#! /usr/bin/env python
255+# -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
256+# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
257+#
258+# Copyright (C) 2010 Patrick Crews
259+#
260+#
261+# This program is free software; you can redistribute it and/or modify
262+# it under the terms of the GNU General Public License as published by
263+# the Free Software Foundation; either version 2 of the License, or
264+# (at your option) any later version.
265+#
266+# This program is distributed in the hope that it will be useful,
267+# but WITHOUT ANY WARRANTY; without even the implied warranty of
268+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
269+# GNU General Public License for more details.
270+#
271+# You should have received a copy of the GNU General Public License
272+# along with this program; if not, write to the Free Software
273+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
274+
275+""" dtr_test_execution:
276+ code related to the execution of dtr test cases
277+
278+ We are provided access to a testManager with
279+ dtr-specific testCases. We contact teh executionManager
280+ to produce the system and server configurations we need
281+ to execute a test.
282+
283+"""
284+
285+# imports
286+import os
287+import sys
288+import subprocess
289+import commands
290+
291+import lib.test_mgmt.test_execution as test_execution
292+
293+class randgenTestExecutor(test_execution.testExecutor):
294+ """ dtr-specific testExecutor
295+ We currently execute by sending test-case
296+ data to client/randgen...for now
297+
298+ """
299+
300+ def execute_testCase (self):
301+ """ Execute a dtr testCase via calls to randgen (boo)
302+ Eventually, we will replace randgen with pythonic
303+ goodness, but we have these classes stored here for the moment
304+
305+ """
306+ test_execution.testExecutor.execute_testCase(self)
307+ self.status = 0
308+
309+ # execute the randgen
310+ self.execute_randgen()
311+
312+ # analyze results
313+ self.current_test_status = self.process_randgen_output()
314+ self.set_server_status(self.current_test_status)
315+
316+
317+
318+
319+ def execute_randgen(self):
320+ """ Execute the commandline and return the result.
321+ We use subprocess as we can pass os.environ dicts and whatnot
322+
323+ """
324+
325+ testcase_name = self.current_testcase.fullname
326+ self.time_manager.start(testcase_name,'test')
327+ randgen_outfile = os.path.join(self.logdir,'randgen.out')
328+ randgen_output = open(randgen_outfile,'w')
329+ dsn = "--dsn=dbi:drizzle:host=localhost:port=%d:user=root:password="":database=test" %(self.master_server.master_port)
330+ randgen_cmd = " ".join([self.current_testcase.test_command, dsn])
331+ randgen_subproc = subprocess.Popen( randgen_cmd
332+ , shell=True
333+ , cwd=self.system_manager.randgen_path
334+ , env=self.working_environment
335+ , stdout = randgen_output
336+ , stderr = subprocess.STDOUT
337+ )
338+ randgen_subproc.wait()
339+ retcode = randgen_subproc.returncode
340+ execution_time = int(self.time_manager.stop(testcase_name)*1000) # millisec
341+
342+ randgen_output.close()
343+ randgen_file = open(randgen_outfile,'r')
344+ output = ''.join(randgen_file.readlines())
345+ #print output
346+ randgen_file.close()
347+
348+ if self.debug:
349+ self.logging.debug("randgen_retcode: %d" %(retcode))
350+ self.current_test_retcode = retcode
351+ self.current_test_output = output
352+ self.current_test_exec_time = execution_time
353+
354+ def process_randgen_output(self):
355+ """ randgen has run, we now check out what we have """
356+ retcode = self.current_test_retcode
357+ if retcode == 0:
358+ return 'pass'
359+ else:
360+ return 'fail'
361+
362+ def handle_system_reqs(self):
363+ """ We check our test case and see what we need to do
364+ system-wise to get ready. This is likely to be
365+ mode-dependent and this is just a placeholder
366+ method
367+
368+ """
369+
370+ self.process_environment_reqs()
371+ self.process_symlink_reqs()
372+ self.process_master_sh()
373+ return
374+
375+ def process_master_sh(self):
376+ """ We do what we need to if we have a master.sh file """
377+ if self.current_testcase.master_sh:
378+ retcode, output = self.system_manager.execute_cmd("/bin/sh %s" %(self.current_testcase.master_sh))
379+ if self.debug:
380+ self.logging.info("retcode: %retcode")
381+ self.logging.info("%output")
382+
383+ def process_environment_reqs(self):
384+ """ We generate the ENV vars we need set
385+ and then ask systemManager to do so
386+
387+ """
388+ env_reqs = { 'randgen_VARDIR': self.master_server.vardir
389+ , 'DRIZZLE_TMP_DIR': self.master_server.tmpdir
390+ , 'MASTER_MYSOCK': self.master_server.socket_file
391+ , 'MASTER_MYPORT': str(self.master_server.master_port)
392+ , 'MC_PORT': str(self.master_server.mc_port)
393+ , 'PBMS_PORT': str(self.master_server.pbms_port)
394+ , 'RABBITMQ_NODE_PORT': str(self.master_server.rabbitmq_node_port)
395+ , 'DRIZZLE_TCP_PORT': str(self.master_server.drizzle_tcp_port)
396+ , 'EXE_DRIZZLE': self.master_server.drizzle_client
397+ , 'MASTER_SERVER_SLAVE_CONFIG' : self.master_server.slave_config_file
398+ , 'DRIZZLE_DUMP': "%s --no-defaults -uroot -p%d" %( self.master_server.drizzledump
399+ , self.master_server.master_port)
400+ , 'DRIZZLE_SLAP': "%s -uroot -p%d" %( self.master_server.drizzleslap
401+ , self.master_server.master_port)
402+ , 'DRIZZLE_IMPORT': "%s -uroot -p%d" %( self.master_server.drizzleimport
403+ , self.master_server.master_port)
404+ , 'DRIZZLE': "%s -uroot -p%d" %( self.master_server.drizzle_client
405+ , self.master_server.master_port)
406+ , 'DRIZZLE_ADMIN' : "%s -uroot -p%d" %( self.master_server.drizzleadmin
407+ , self.master_server.master_port)
408+ }
409+
410+ self.working_environment = self.system_manager.create_working_environment(env_reqs)
411+
412+ def process_symlink_reqs(self):
413+ """ Create any symlinks we may need """
414+ needed_symlinks = []
415+
416+ # handle filesystem_engine
417+ if self.current_testcase.suitename == 'filesystem_engine':
418+ needed_symlinks.append(( os.path.join(self.current_testcase.suitepath
419+ , 't')
420+ , os.path.join(self.master_server.vardir
421+ , "filesystem_ln")))
422+
423+ self.system_manager.create_symlinks(needed_symlinks)
424+
425+
426+
427+
428+
429
430=== added file 'tests/lib/randgen/randgen_test_management.py'
431--- tests/lib/randgen/randgen_test_management.py 1970-01-01 00:00:00 +0000
432+++ tests/lib/randgen/randgen_test_management.py 2011-02-23 17:24:15 +0000
433@@ -0,0 +1,149 @@
434+#! /usr/bin/env python
435+# -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
436+# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
437+#
438+# Copyright (C) 2010 Patrick Crews
439+#
440+## This program is free software; you can redistribute it and/or modify
441+# it under the terms of the GNU General Public License as published by
442+# the Free Software Foundation; either version 2 of the License, or
443+# (at your option) any later version.
444+#
445+# This program is distributed in the hope that it will be useful,
446+# but WITHOUT ANY WARRANTY; without even the implied warranty of
447+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
448+# GNU General Public License for more details.
449+#
450+# You should have received a copy of the GNU General Public License
451+# along with this program; if not, write to the Free Software
452+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
453+
454+""" randgen_test_management:
455+ code related to the gathering / analysis / management of
456+ the test cases
457+ ie - collecting the list of tests in each suite, then
458+ gathering additional, relevant information for randgen
459+ mode. (stocastic model-based testing)
460+
461+"""
462+
463+# imports
464+import os
465+import re
466+import sys
467+from ConfigParser import RawConfigParser
468+
469+import lib.test_mgmt.test_management as test_management
470+
471+
472+
473+class testCase:
474+ """Holds info on a single randgen test
475+
476+ """
477+ def __init__( self, system_manager, name=None
478+ , fullname = None, server_requirements=[[]]
479+ , comment=None, test_command=None, debug=False ):
480+ self.system_manager = system_manager
481+ self.logging = self.system_manager.logging
482+ self.skip_keys = ['system_manager','logging']
483+ self.name = name
484+ self.fullname = fullname
485+ self.suitename = 'randgen_tests'
486+ self.master_sh = None
487+ self.comment = comment
488+ self.server_requirements = server_requirements
489+ self.test_command = test_command
490+
491+ if debug:
492+ self.system_manager.logging.debug_class(self)
493+
494+ def should_run(self):
495+ if self.skip_flag or self.disable:
496+ return 0
497+ else:
498+ return 1
499+
500+
501+
502+
503+
504+class testManager(test_management.testManager):
505+ """Deals with scanning test directories, gathering test cases, and
506+ collecting per-test information (opt files, etc) for use by the
507+ test-runner
508+
509+ """
510+
511+ def __init__(self, verbose, debug, default_engine, dotest, skiptest
512+ , reorder, suitelist, suitepaths, system_manager
513+ , test_cases, mode):
514+ super(testManager, self).__init__( verbose, debug, default_engine
515+ , dotest, skiptest, reorder
516+ , suitelist, suitepaths
517+ , system_manager, test_cases, mode)
518+ self.suitepaths = [os.path.join(self.testdir,'randgen_tests')]
519+ if suitelist is None:
520+ self.suitelist = ['main']
521+ else:
522+ self.suitelist = suitelist
523+
524+ def process_suite(self,suite_dir):
525+ """Process a test suite.
526+ Look for randgen tests, which are nice clean conf files
527+
528+ """
529+
530+ # We know this based on how we organize randgen test conf files
531+ suite_name = os.path.basename(suite_dir)
532+ if self.verbose:
533+ self.system_manager.logging.verbose("Processing suite: %s" %(suite_name))
534+ testlist = [os.path.join(suite_dir,test_file) for test_file in sorted(os.listdir(suite_dir)) if test_file.endswith('.cnf')]
535+
536+ # Search for specific test names
537+ if self.desired_tests: # We have specific, named tests we want from the suite(s)
538+ tests_to_use = []
539+ for test in self.desired_tests:
540+ if test.endswith('.cnf'):
541+ pass
542+ else:
543+ test = test+'.cnf'
544+ test = os.path.join(suite_dir,test)
545+ if test in testlist:
546+ tests_to_use.append(test)
547+ testlist = tests_to_use
548+ for test_case in testlist:
549+ self.add_test(self.process_test_file(suite_name, test_case))
550+
551+
552+ def process_test_file(self, suite_name, testfile):
553+ """ We convert the info in a testfile into a testCase object """
554+
555+ config_reader = RawConfigParser()
556+ config_reader.read(testfile)
557+ # test_name = filename - .cnf...simpler
558+ test_name = os.path.basename(testfile).replace('.cnf','')
559+ test_comment = config_reader.get('test_info','comment')
560+ server_requirements = self.process_server_reqs(config_reader.get('test_servers','servers'))
561+ test_command = config_reader.get('test_command','command')
562+ return testCase( self.system_manager
563+ , name = test_name
564+ , fullname = "%s.%s" %(suite_name, test_name)
565+ , server_requirements = server_requirements
566+ , test_command = test_command
567+ , debug = self.debug )
568+
569+ #sys.exit(0)
570+
571+ def process_server_reqs(self,data_string):
572+ """ We read in the list of lists as a string, so we need to
573+ handle this / break it down into proper chunks
574+
575+ """
576+ server_reqs = []
577+ # We expect to see a list of lists and throw away the
578+ # enclosing brackets
579+ option_sets = data_string[1:-1].strip().split(',')
580+ for option_set in option_sets:
581+ server_reqs.append([option_set[1:-1].strip()])
582+ return server_reqs
583
584=== modified file 'tests/lib/server_mgmt/drizzled.py'
585--- tests/lib/server_mgmt/drizzled.py 2011-02-17 00:31:23 +0000
586+++ tests/lib/server_mgmt/drizzled.py 2011-02-23 17:24:15 +0000
587@@ -2,7 +2,7 @@
588 # -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
589 # vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
590 #
591-# Copyright (C) 2010 Patrick Crews
592+# Copyright (C) 2010,2011 Patrick Crews
593 #
594 # This program is free software; you can redistribute it and/or modify
595 # it under the terms of the GNU General Public License as published by
596@@ -27,8 +27,9 @@
597
598 # imports
599 import os
600+from lib.server_mgmt.server import Server
601
602-class drizzleServer():
603+class drizzleServer(Server):
604 """ represents a drizzle server, its possessions
605 (datadir, ports, etc), and methods for controlling
606 and querying it
607@@ -40,49 +41,14 @@
608
609 """
610
611- def __init__( self
612- , name
613- , server_manager
614- , default_storage_engine
615- , server_options
616- , requester
617- , workdir_root):
618- self.skip_keys = [ 'server_manager'
619- , 'system_manager'
620- , 'dirset'
621- , 'preferred_base_port'
622- , 'no_secure_file_priv'
623- , 'secure_file_string'
624- , 'port_block'
625- ]
626- self.debug = server_manager.debug
627- self.verbose = server_manager.verbose
628- self.initial_run = 1
629- self.owner = requester
630- self.server_options = server_options
631- self.default_storage_engine = default_storage_engine
632- self.server_manager = server_manager
633- # We register with server_manager asap
634- self.server_manager.log_server(self, requester)
635-
636- self.system_manager = self.server_manager.system_manager
637- self.valgrind = self.system_manager.valgrind
638- self.gdb = self.system_manager.gdb
639- if self.valgrind:
640- self.valgrind_time_buffer = 10
641- else:
642- self.valgrind_time_buffer = 1
643- self.cmd_prefix = self.system_manager.cmd_prefix
644- self.logging = self.system_manager.logging
645- self.no_secure_file_priv = self.server_manager.no_secure_file_priv
646+ def __init__( self, name, server_manager, default_storage_engine
647+ , server_options, requester, workdir_root):
648+ super(drizzleServer, self).__init__( name, server_manager
649+ , default_storage_engine
650+ , server_options, requester
651+ , workdir_root)
652 self.code_tree = self.system_manager.code_tree
653 self.preferred_base_port = 9306
654- self.name = name
655- self.status = 0 # stopped, 1 = running
656- self.tried_start = 0
657- self.failed_test = 0 # was the last test a failure? our state is suspect
658- self.server_start_timeout = 60 * self.valgrind_time_buffer
659-
660 # Get our ports
661 self.port_block = self.system_manager.port_manager.get_port_block( self.name
662 , self.preferred_base_port
663@@ -118,6 +84,12 @@
664 self.pid_file = os.path.join(self.rundir,('%s.pid' %(self.name)))
665 self.socket_file = os.path.join(self.vardir, ('%s.sock' %(self.name)))
666 self.timer_file = os.path.join(self.logdir,('timer'))
667+
668+ # Do magic to create a config file for use with the slave
669+ # plugin
670+ self.slave_config_file = os.path.join(self.logdir,'slave.cnf')
671+ self.create_slave_config_file()
672+
673 self.snapshot_path = os.path.join(self.tmpdir,('snapshot_%s' %(self.master_port)))
674 # We want to use --secure-file-priv = $vardir by default
675 # but there are times / tools when we need to shut this off
676@@ -154,7 +126,7 @@
677 , 'vardir'
678 , 'status'
679 ]
680- self.logging.info("%s master server:" %(self.owner))
681+ self.logging.info("%s server:" %(self.owner))
682 for key in report_values:
683 value = vars(self)[key]
684 self.logging.info("%s: %s" %(key.upper(), value))
685@@ -205,55 +177,47 @@
686
687 return "%s --ping --port=%d --user=root" % (self.drizzle_client_path, self.master_port)
688
689- def process_server_options(self):
690- """Consume the list of options we have been passed.
691- Return a string with them joined
692+ def is_started(self):
693+ """ Determine if the server is up and running -
694+ this may vary from server type to server type
695
696 """
697-
698- return " ".join(self.server_options)
699+
700+ # We experiment with waiting for a pid file to be created vs. pinging
701+ # This is what test-run.pl does and it helps us pass logging_stats tests
702+ # while not self.ping_server(server, quiet=True) and timer != timeout:
703+
704+ return self.system_manager.find_path( [self.pid_file]
705+ , required=0)
706+
707+ def create_slave_config_file(self):
708+ """ Create a config file suitable for use
709+ with the slave-plugin. This allows
710+ us to tie other servers in easily
711+
712+ """
713+
714+ config_data = [ "master-host=127.0.0.1"
715+ , "master-port=%d" %self.master_port
716+ , "master-user=root"
717+ , "master-pass=''"
718+ , "max-reconnects=100"
719+ , "seconds-between-reconnects=20"
720+ ]
721+ outfile = open(self.slave_config_file,'w')
722+ for line in config_data:
723+ outfile.write("%s\n" %(line))
724+ outfile.close()
725+
726+
727+
728+
729
730- def initialize_databases(self):
731- """ Call schemawriter to make db.opt files """
732- databases = [ 'test'
733- , 'mysql'
734- ]
735- for database in databases:
736- db_path = os.path.join(self.datadir,'local',database,'db.opt')
737- cmd = "%s %s %s" %(self.schemawriter, database, db_path)
738- self.system_manager.execute_cmd(cmd)
739-
740- def take_db_snapshot(self):
741- """ Take a snapshot of our vardir for quick restores """
742-
743- self.logging.info("Taking clean db snapshot...")
744- if os.path.exists(self.snapshot_path):
745- # We need to remove an existing path as python shutil
746- # doesn't want an existing target
747- self.system_manager.remove_dir(self.snapshot_path)
748- self.system_manager.copy_dir(self.datadir, self.snapshot_path)
749-
750- def restore_snapshot(self):
751- """ Restore from a stored snapshot """
752-
753- if self.verbose:
754- self.logging.verbose("Restoring from db snapshot")
755- if not os.path.exists(self.snapshot_path):
756- self.logging.error("Could not find snapshot: %s" %(self.snapshot_path))
757- self.system_manager.remove_dir(self.datadir)
758- self.system_manager.copy_dir(self.snapshot_path, self.datadir)
759-
760- def cleanup(self):
761- """ Cleanup - just free ports for now..."""
762- self.system_manager.port_manager.free_ports(self.port_block)
763-
764- def set_server_options(self, server_options):
765- """ We update our server_options to the new set """
766- self.server_options = server_options
767-
768- def reset(self):
769- """ Voodoo to reset ourselves """
770- self.failed_test = 0
771+
772+
773+
774+
775+
776
777
778
779
780=== added file 'tests/lib/server_mgmt/server.py'
781--- tests/lib/server_mgmt/server.py 1970-01-01 00:00:00 +0000
782+++ tests/lib/server_mgmt/server.py 2011-02-23 17:24:15 +0000
783@@ -0,0 +1,156 @@
784+#! /usr/bin/env python
785+# -*- mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
786+# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
787+#
788+# Copyright (C) 2010,2011 Patrick Crews
789+#
790+# This program is free software; you can redistribute it and/or modify
791+# it under the terms of the GNU General Public License as published by
792+# the Free Software Foundation; either version 2 of the License, or
793+# (at your option) any later version.
794+#
795+# This program is distributed in the hope that it will be useful,
796+# but WITHOUT ANY WARRANTY; without even the implied warranty of
797+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
798+# GNU General Public License for more details.
799+#
800+# You should have received a copy of the GNU General Public License
801+# along with this program; if not, write to the Free Software
802+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
803+
804+
805+""" server.py: generic server object used by the server
806+ manager. This contains the generic methods for all
807+ servers. Specific types (Drizzle, MySQL, etc) should
808+ inherit from this guy
809+
810+"""
811+
812+# imports
813+import os
814+
815+class Server(object):
816+ """ the server class from which other servers
817+ will inherit - contains generic methods
818+ certain methods will be overridden by more
819+ specific ones
820+
821+ """
822+
823+ def __init__(self
824+ , name
825+ , server_manager
826+ , default_storage_engine
827+ , server_options
828+ , requester
829+ , workdir_root):
830+ self.skip_keys = [ 'server_manager'
831+ , 'system_manager'
832+ , 'dirset'
833+ , 'preferred_base_port'
834+ , 'no_secure_file_priv'
835+ , 'secure_file_string'
836+ , 'port_block'
837+ ]
838+ self.debug = server_manager.debug
839+ self.verbose = server_manager.verbose
840+ self.initial_run = 1
841+ self.owner = requester
842+ self.server_options = server_options
843+ self.default_storage_engine = default_storage_engine
844+ self.server_manager = server_manager
845+ # We register with server_manager asap
846+ self.server_manager.log_server(self, requester)
847+
848+ self.system_manager = self.server_manager.system_manager
849+ self.valgrind = self.system_manager.valgrind
850+ self.gdb = self.system_manager.gdb
851+ if self.valgrind:
852+ self.valgrind_time_buffer = 10
853+ else:
854+ self.valgrind_time_buffer = 1
855+ self.cmd_prefix = self.system_manager.cmd_prefix
856+ self.logging = self.system_manager.logging
857+ self.no_secure_file_priv = self.server_manager.no_secure_file_priv
858+ self.name = name
859+ self.status = 0 # stopped, 1 = running
860+ self.tried_start = 0
861+ self.failed_test = 0 # was the last test a failure? our state is suspect
862+ self.server_start_timeout = 60 * self.valgrind_time_buffer
863+
864+ def initialize_databases(self):
865+ """ Call schemawriter to make db.opt files """
866+ databases = [ 'test'
867+ , 'mysql'
868+ ]
869+ for database in databases:
870+ db_path = os.path.join(self.datadir,'local',database,'db.opt')
871+ cmd = "%s %s %s" %(self.schemawriter, database, db_path)
872+ self.system_manager.execute_cmd(cmd)
873+
874+ def process_server_options(self):
875+ """Consume the list of options we have been passed.
876+ Return a string with them joined
877+
878+ """
879+
880+ return " ".join(self.server_options)
881+
882+ def take_db_snapshot(self):
883+ """ Take a snapshot of our vardir for quick restores """
884+
885+ self.logging.info("Taking clean db snapshot...")
886+ if os.path.exists(self.snapshot_path):
887+ # We need to remove an existing path as python shutil
888+ # doesn't want an existing target
889+ self.system_manager.remove_dir(self.snapshot_path)
890+ self.system_manager.copy_dir(self.datadir, self.snapshot_path)
891+
892+ def restore_snapshot(self):
893+ """ Restore from a stored snapshot """
894+
895+ if self.verbose:
896+ self.logging.verbose("Restoring from db snapshot")
897+ if not os.path.exists(self.snapshot_path):
898+ self.logging.error("Could not find snapshot: %s" %(self.snapshot_path))
899+ self.system_manager.remove_dir(self.datadir)
900+ self.system_manager.copy_dir(self.snapshot_path, self.datadir)
901+
902+ def is_started(self):
903+ """ Is the server running? Particulars are server-dependent """
904+
905+ return
906+
907+ def get_start_cmd(self):
908+ """ Return the command the server_manager can use to start me """
909+
910+ return "Allakazam!"
911+
912+ def get_stop_cmd(self):
913+ """ Return the command the server_manager can use to stop me """
914+
915+ return "Whoa, Nelly!"
916+
917+ def get_ping_cmd(self):
918+ """ Return the command that can be used to 'ping' me
919+ Very similar to is_started, but different
920+
921+ Determining if a server is still running (ping)
922+ may differ from the method used to determine
923+ server startup
924+
925+ """
926+
927+ return "Hello?"
928+
929+ def cleanup(self):
930+ """ Cleanup - just free ports for now..."""
931+ self.system_manager.port_manager.free_ports(self.port_block)
932+
933+ def set_server_options(self, server_options):
934+ """ We update our server_options to the new set """
935+ self.server_options = server_options
936+
937+ def reset(self):
938+ """ Voodoo to reset ourselves """
939+ self.failed_test = 0
940
941=== modified file 'tests/lib/server_mgmt/server_management.py'
942--- tests/lib/server_mgmt/server_management.py 2011-02-17 00:31:23 +0000
943+++ tests/lib/server_mgmt/server_management.py 2011-02-23 17:24:15 +0000
944@@ -65,13 +65,16 @@
945 if self.debug:
946 self.logging.debug_class(self)
947
948- def request_servers( self, requester, workdir, master_count
949- , slave_count, server_options, working_environ
950- , expect_fail = 0):
951+ def request_servers( self, requester, workdir, server_requirements
952+ , working_environ, expect_fail = 0):
953 """ We produce the server objects / start the server processes
954 as requested. We report errors and whatnot if we can't
955 That is, unless we expect the server to not start, then
956- we just return a value / message
957+ we just return a value / message.
958+
959+ server_requirements is a list of lists. Each list
960+ is a set of server options - we create one server
961+ for each set of options requested
962
963 """
964
965@@ -80,11 +83,11 @@
966 self.check_server_status(requester)
967
968 # Make sure we have the proper number of servers for this requester
969- self.process_server_count( requester, master_count+slave_count
970- , workdir, server_options)
971+ self.process_server_count( requester, len(server_requirements)
972+ , workdir, server_requirements)
973
974 # Make sure we are running with the correct options
975- self.evaluate_existing_servers(requester, server_options)
976+ self.evaluate_existing_servers(requester, server_requirements)
977
978 # Fire our servers up
979 bad_start = self.start_servers( requester, working_environ
980@@ -113,7 +116,6 @@
981 , server_options
982 , requester
983 , workdir )
984- self.add_server(requester, new_server)
985 return new_server
986
987 def start_servers(self, requester, working_environ, expect_fail):
988@@ -188,11 +190,9 @@
989 #if server_retcode: # We know we have an error, no need to wait
990 # timer = timeout
991
992- # We experiment with waiting for a pid file to be created vs. pinging
993- # This is what test-run.pl does and it helps us pass logging_stats tests
994- # while not self.ping_server(server, quiet=True) and timer != timeout:
995- while not self.system_manager.find_path( [server.pid_file]
996- , required=0) and timer != timeout:
997+
998+
999+ while not server.is_started() and timer != timeout:
1000 time.sleep(self.timer_increment)
1001 # If manual-gdb, this == None and we want to give the
1002 # user all the time they need
1003@@ -307,14 +307,17 @@
1004 def log_server(self, new_server, requester):
1005 self.servers[requester].append(new_server)
1006
1007- def evaluate_existing_servers( self, requester, server_options):
1008+ def evaluate_existing_servers( self, requester, server_requirements):
1009 """ See if the requester has any servers and if they
1010 are suitable for the current test
1011
1012+ We should have the proper number of servers at this point
1013+
1014 """
1015 current_servers = self.servers[requester]
1016-
1017- for server in current_servers:
1018+
1019+ for index,server in enumerate(current_servers):
1020+ server_options = server_requirements[index]
1021 # We add in any user-supplied options here
1022 server_options = server_options + self.user_server_opts
1023 if self.compare_options( server.server_options
1024@@ -327,6 +330,9 @@
1025 self.reset_server(server)
1026 self.update_server_options(server, server_options)
1027
1028+
1029+
1030+
1031 def filter_server_options(self, server_options):
1032 """ Remove a list of options we don't want passed to the server
1033 these are test-case specific options.
1034@@ -361,7 +367,7 @@
1035 self.reset_server(server)
1036
1037
1038- def process_server_count(self, requester, desired_count, workdir, server_options):
1039+ def process_server_count(self, requester, desired_count, workdir, server_reqs):
1040 """ We see how many servers we have. We shrink / grow
1041 the requesters set of servers as needed.
1042
1043@@ -369,11 +375,14 @@
1044 (naturally)
1045
1046 """
1047- server_options = self.filter_server_options(server_options)
1048+ if desired_count < 0: desired_count = 1
1049+
1050 current_count = self.has_servers(requester)
1051 if desired_count > current_count:
1052 for i in range(desired_count - current_count):
1053- self.allocate_server(requester, server_options, workdir)
1054+ # We pass an empty options list when allocating
1055+ # We'll update the options to what is needed elsewhere
1056+ self.allocate_server(requester,[] , workdir)
1057 elif desired_count < current_count:
1058 good_servers = self.get_server_list(requester)[:desired_count]
1059 retired_servers = self.get_server_list(requester)[desired_count - current_count:]
1060
1061=== modified file 'tests/lib/sys_mgmt/port_management.py'
1062--- tests/lib/sys_mgmt/port_management.py 2011-02-07 17:58:09 +0000
1063+++ tests/lib/sys_mgmt/port_management.py 2011-02-23 17:24:15 +0000
1064@@ -77,9 +77,9 @@
1065 This is a bit bobo, but will work for now...
1066
1067 """
1068-
1069 searching_for_port = 1
1070- attempts_remain = 100
1071+ attempt_count = 100
1072+ attempts_remain = attempt_count
1073 max_port_value = 32767
1074 min_port_value = 5001
1075 while searching_for_port and attempts_remain:
1076@@ -93,7 +93,7 @@
1077 if desired_port >= max_port_value:
1078 desired_port = min_port_value
1079 attempts_remain = attempts_remain - 1
1080- self.logging.error("Failed to assign a port in %d attempts")
1081+ self.logging.error("Failed to assign a port in %d attempts" %attempt_count)
1082 sys.exit(1)
1083
1084 def check_port_status(self, port):
1085
1086=== modified file 'tests/lib/sys_mgmt/system_management.py'
1087--- tests/lib/sys_mgmt/system_management.py 2011-02-17 00:31:23 +0000
1088+++ tests/lib/sys_mgmt/system_management.py 2011-02-23 17:24:15 +0000
1089@@ -69,6 +69,7 @@
1090 self.cur_os = os.uname()[0]
1091 self.cur_user = getpass.getuser()
1092 self.workdir = os.path.abspath(variables['workdir'])
1093+ self.testdir = os.path.abspath(variables['testdir'])
1094 self.datadir = os.path.abspath(os.path.join(variables['testdir'],'dbqp_data'))
1095 self.top_srcdir = os.path.abspath(variables['topsrcdir'])
1096 self.top_builddir = os.path.abspath(variables['topbuilddir'])
1097@@ -76,6 +77,7 @@
1098 self.valgrind = variables['valgrind']
1099 self.gdb = variables['gdb']
1100 self.manual_gdb = variables['manualgdb']
1101+ self.randgen_path = variables['randgenpath']
1102
1103 # we use this to preface commands in order to run valgrind and such
1104 self.cmd_prefix = ''
1105@@ -232,6 +234,7 @@
1106 self.logging.info("Using --start-dirty, not attempting to touch directories")
1107 return
1108 else:
1109+ self.cleanup() # We crawl / try to kill any server pids we find
1110 self.remove_dir(self.workdir)
1111 self.allocate_workdir()
1112
1113@@ -551,6 +554,36 @@
1114 self.append_env_var("LD_LIBRARY_PATH", debug_path, suffix=1)
1115 self.append_env_var("DYLD_LIBRARY_PATH", debug_path, suffix=1)
1116
1117+
1118+ def cleanup(self, exit=False):
1119+ """ We try to kill any servers whose pid files
1120+ we detect lurking about
1121+
1122+ """
1123+
1124+ self.pid_hunt_and_kill(exit)
1125+
1126+ def pid_hunt_and_kill(self, exit):
1127+ """ Crawl our workdir and look for server.pid files
1128+ We read 'em and kill 'em if we find 'em
1129+
1130+ """
1131+
1132+ for root, dirs, files in os.walk(self.workdir):
1133+ #print root, dirs, files
1134+ for found_file in files:
1135+ if found_file.endswith('.pid'):
1136+ file_path = os.path.join(root, found_file)
1137+ pid_file = open(file_path,'r')
1138+ pid = pid_file.readline().strip()
1139+ pid_file.close()
1140+ self.logging.info("Killing pid %s from %s" %( pid
1141+ , file_path
1142+ ))
1143+ self.execute_cmd("kill -9 %s" %pid, must_pass=0)
1144+ if exit:
1145+ sys.exit(0)
1146+
1147
1148
1149
1150
1151=== modified file 'tests/lib/test_mgmt/execution_management.py'
1152--- tests/lib/test_mgmt/execution_management.py 2011-02-14 21:20:36 +0000
1153+++ tests/lib/test_mgmt/execution_management.py 2011-02-23 17:24:15 +0000
1154@@ -61,6 +61,7 @@
1155 self.verbose = variables['verbose']
1156 self.force = variables['force']
1157 self.record_flag = variables['record']
1158+ self.gendata_file = variables['gendatafile']
1159 self.testcase_repeat_count = variables['repeat']
1160 # We are currently single-threaded execution-wise
1161 # but in the future, we will likely need to revamp
1162@@ -101,7 +102,6 @@
1163 self.logging.verbose("Starting executor: %s" %(executor_name))
1164 # thread.start_new(executor.execute,()) # sigh...one day...damned drizzletest!
1165 executor.execute(self.start_and_exit)
1166- time.sleep(3)
1167 while self.has_running_executors():
1168 pass
1169 self.test_manager.statistical_report()
1170
1171=== modified file 'tests/lib/test_mgmt/test_execution.py'
1172--- tests/lib/test_mgmt/test_execution.py 2011-02-17 00:31:23 +0000
1173+++ tests/lib/test_mgmt/test_execution.py 2011-02-23 17:24:15 +0000
1174@@ -78,6 +78,27 @@
1175 if self.debug:
1176 self.logging.debug_class(self)
1177
1178+ def execute(self, start_and_exit):
1179+ """ Execute a test case. The details are *very* mode specific """
1180+ self.status = 1 # we are running
1181+ keep_running = 1
1182+ if self.verbose:
1183+ self.logging.verbose("Executor: %s beginning test execution..." %(self.name))
1184+ while self.test_manager.has_tests() and keep_running == 1:
1185+ self.get_testCase()
1186+ for i in range(self.testcase_repeat_count):
1187+ self.handle_system_reqs()
1188+ self.handle_server_reqs()
1189+ self.handle_utility_reqs()
1190+ self.handle_start_and_exit(start_and_exit)
1191+ if self.current_test_status != 'fail':
1192+ self.execute_testCase()
1193+ self.record_test_result()
1194+ if self.current_test_status == 'fail' and not self.execution_manager.force:
1195+ self.logging.error("Failed test. Use --force to execute beyond the first test failure")
1196+ keep_running = 0
1197+ self.status = 0
1198+
1199 def get_testCase(self):
1200 """ Ask our execution_manager for a testCase to work on """
1201
1202@@ -86,20 +107,18 @@
1203 #self.test_manager.mutex.release()
1204
1205
1206- def handle_server_reqs(self, start_and_exit):
1207+ def handle_server_reqs(self):
1208 """ Get the servers required to execute the testCase
1209 and ensure that we have servers and they were started
1210 as expected. We take necessary steps if not
1211 We also handle --start-and-exit here
1212
1213 """
1214-
1215- master_count, slave_count, server_options = self.process_server_reqs()
1216+
1217+ server_requirements = self.current_testcase.server_requirements
1218 (self.current_servers,bad_start) = self.server_manager.request_servers( self.name
1219 , self.workdir
1220- , master_count
1221- , slave_count
1222- , server_options
1223+ , server_requirements
1224 , self.working_environment)
1225 if self.current_servers == 0 or bad_start:
1226 # error allocating servers, test is a failure
1227@@ -107,11 +126,18 @@
1228 self.current_test_status = 'fail'
1229 self.set_server_status(self.current_test_status)
1230 output = ''
1231- else:
1232- if start_and_exit:
1233- # TODO: Report out all started servers via server_manager/server objects?
1234- self.current_servers[0].report()
1235- self.logging.info("User specified --start-and-exit. dbqp.py exiting and leaving servers running...")
1236+ if self.initial_run:
1237+ self.initial_run = 0
1238+ self.current_servers[0].report()
1239+ self.master_server = self.current_servers[0]
1240+ return
1241+
1242+ def handle_start_and_exit(self, start_and_exit):
1243+ """ Do what needs to be done if we have the
1244+ --start-and-exit flag
1245+
1246+ """
1247+ if start_and_exit:
1248 # We blow away any port_management files for our ports
1249 # Technically this won't let us 'lock' any ports that
1250 # we aren't explicitly using (visible to netstat scan)
1251@@ -119,44 +145,41 @@
1252 # We shouldn't hog it ; )
1253 # We might need to do this better later
1254 for server in self.current_servers:
1255+ if server != self.master_server:
1256+ server.report()
1257 server.cleanup() # this only removes any port files
1258+ self.logging.info("User specified --start-and-exit. dbqp.py exiting and leaving servers running...")
1259 sys.exit(0)
1260- if self.initial_run:
1261- self.initial_run = 0
1262- self.current_servers[0].report()
1263- self.master_server = self.current_servers[0]
1264- return
1265
1266- def process_server_reqs(self):
1267- """ Check out our current_testcase to see what kinds of servers
1268- we need up and running. The executionManager sees to
1269- serving the reqs
1270+ def handle_utility_reqs(self):
1271+ """ Call any utilities we want to use before starting a test
1272+ At present this is envisioned for use with datagen
1273+ but there may be other things we wish to use
1274+ At that point, we may need to explore other ways of
1275+ defining our testing environment, such as with
1276+ nice config files / modules
1277
1278 """
1279-
1280- master_count = self.current_testcase.master_count
1281- slave_count = self.current_testcase.slave_count
1282- server_options = self.current_testcase.server_options
1283-
1284- return(master_count, slave_count, server_options)
1285-
1286- def execute(self, start_and_exit):
1287- """ Execute a test case. The details are *very* mode specific """
1288- self.status = 1 # we are running
1289- keep_running = 1
1290- if self.verbose:
1291- self.logging.verbose("Executor: %s beginning test execution..." %(self.name))
1292- while self.test_manager.has_tests() and keep_running == 1:
1293- self.get_testCase()
1294- self.handle_system_reqs()
1295- self.handle_server_reqs(start_and_exit)
1296- for i in range(self.testcase_repeat_count):
1297- self.execute_testCase()
1298- self.record_test_result()
1299- if self.current_test_status == 'fail' and not self.execution_manager.force:
1300- self.logging.error("Failed test. Use --force to execute beyond the first test failure")
1301- keep_running = 0
1302- self.status = 0
1303+
1304+ # We call gendata against the server(s) with the
1305+ # specified file
1306+ if self.execution_manager.gendata_file:
1307+ dsn = "--dsn=dbi:drizzle:host=localhost:port=%d:user=root:password="":database=test" %(self.master_server.master_port)
1308+ gendata_cmd = "./gendata.pl %s --spec=%s" %( dsn
1309+ , self.execution_manager.gendata_file
1310+ )
1311+ #self.system_manager.execute_cmd(gendata_cmd)
1312+ gendata_subproc = subprocess.Popen( gendata_cmd
1313+ , shell=True
1314+ , cwd=self.system_manager.randgen_path
1315+ , stdout = None
1316+ , stderr = None
1317+ )
1318+ gendata_subproc.wait()
1319+ gendata_retcode = gendata_subproc.returncode
1320+ if gendata_retcode:
1321+ self.logging.error("gendata command: %s failed with retcode: %d" %(gendata_cmd
1322+ , gendata_retcode))
1323
1324 def execute_testCase(self):
1325 """ Do whatever evil voodoo we must do to execute a testCase """
1326
1327=== modified file 'tests/lib/test_mgmt/test_management.py'
1328--- tests/lib/test_mgmt/test_management.py 2011-02-09 17:41:08 +0000
1329+++ tests/lib/test_mgmt/test_management.py 2011-02-23 17:24:15 +0000
1330@@ -18,7 +18,7 @@
1331 # along with this program; if not, write to the Free Software
1332 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1333
1334-""" dtr_test_management:
1335+""" test_management:
1336 code related to the gathering / analysis / management of
1337 the test cases
1338 ie - collecting the list of tests in each suite, then
1339@@ -33,7 +33,7 @@
1340 import sys
1341 import thread
1342
1343-class testManager:
1344+class testManager(object):
1345 """Deals with scanning test directories, gathering test cases, and
1346 collecting per-test information (opt files, etc) for use by the
1347 test-runner
1348@@ -42,7 +42,7 @@
1349
1350 def __init__( self, verbose, debug, default_engine, dotest, skiptest
1351 , reorder, suitelist, suitepaths, system_manager
1352- , test_cases):
1353+ , test_cases, mode):
1354
1355 self.system_manager = system_manager
1356 self.time_manager = system_manager.time_manager
1357@@ -68,6 +68,7 @@
1358 self.skiptest = skiptest
1359 self.reorder = reorder
1360 self.suitelist = suitelist
1361+ self.mode = mode
1362
1363 self.code_tree = self.system_manager.code_tree
1364 self.suitepaths = suitepaths + self.code_tree.suite_paths
1365@@ -87,7 +88,7 @@
1366 self.logging.info("Processing test suites...")
1367 # BEGIN terrible hack to accomodate the fact that
1368 # our 'main' suite is also our testdir : /
1369- if self.suitelist is None:
1370+ if self.suitelist is None and self.mode=='dtr':
1371 self.suitepaths = [self.testdir]
1372 self.suitelist = ['main']
1373 # END horrible hack
1374@@ -137,9 +138,10 @@
1375
1376 """
1377 # BEGIN horrible hack to accomodate bad location of main suite
1378- if self.suitepaths == [self.testdir] or suitename == 'main':
1379- # We treat this as the 'main' suite
1380- return self.testdir
1381+ if self.mode == 'dtr':
1382+ if self.suitepaths == [self.testdir] or suitename == 'main':
1383+ # We treat this as the 'main' suite
1384+ return self.testdir
1385 # END horrible hack
1386 for suitepath in self.suitepaths:
1387 suite_path = self.system_manager.find_path([ os.path.join(suitepath,suitename,'tests'),
1388@@ -216,13 +218,15 @@
1389 # This is probably hacky, but I'll think of a better
1390 # location later. When we are ready to see our
1391 # statistical report, we know to stop the total time timer
1392- total_exec_time = self.time_manager.stop('total_time')
1393- self.logging.write_thick_line()
1394- self.logging.info("Test execution complete in %d seconds" %(total_exec_time))
1395+ if not self.first_test:
1396+ total_exec_time = self.time_manager.stop('total_time')
1397+ self.logging.write_thick_line()
1398+ self.logging.info("Test execution complete in %d seconds" %(total_exec_time))
1399 self.logging.info("Summary report:")
1400 self.report_executed_tests()
1401 self.report_test_statuses()
1402- self.time_manager.summary_report()
1403+ if not self.first_test:
1404+ self.time_manager.summary_report()
1405
1406 def report_test_statuses(self):
1407 """ Method to report out various test statuses we
1408
1409=== modified file 'tests/lib/test_mode.py'
1410--- tests/lib/test_mode.py 2011-02-04 20:41:08 +0000
1411+++ tests/lib/test_mode.py 2011-02-23 17:24:15 +0000
1412@@ -33,27 +33,46 @@
1413 the appropriate code objects for the test-runner to play with
1414
1415 """
1416+
1417+ test_mode = variables['mode']
1418+ system_manager.logging.info("Using testing mode: %s" %test_mode)
1419+
1420 # drizzle-test-run mode - the default
1421- if variables['mode'] == 'dtr':
1422+ if test_mode == 'dtr':
1423 # DTR mode - this is what we are coding to initially
1424 # We are just setting the code up this way to hopefully make
1425 # other coolness easier in the future
1426
1427- system_manager.logging.info("Using testing mode: %s" %variables['mode'])
1428-
1429- # Set up our testManager
1430+ # get our mode-specific testManager
1431 from drizzle_test_run.dtr_test_management import testManager
1432- test_manager = testManager( variables['verbose'], variables['debug']
1433- , variables['defaultengine'], variables['dotest']
1434- , variables['skiptest'], variables['reorder']
1435- , variables['suitelist'], variables['suitepaths']
1436- , system_manager, variables['test_cases'])
1437-
1438+
1439 # get our mode-specific testExecutor
1440- from drizzle_test_run.dtr_test_execution import dtrTestExecutor
1441-
1442- return (test_manager, dtrTestExecutor)
1443-
1444+ from drizzle_test_run.dtr_test_execution import testExecutor as testExecutor
1445+
1446+ elif test_mode == 'randgen':
1447+ # randgen mode - we run the randgen grammar against
1448+ # the specified server configs and report the randgen error code
1449+
1450+ # get manager and executor
1451+ from randgen.randgen_test_management import testManager
1452+ from randgen.randgen_test_execution import randgenTestExecutor as testExecutor
1453+
1454+ elif test_mode == 'cleanup':
1455+ # cleanup mode - we try to kill any servers whose pid's we detect
1456+ # in our workdir. Might extend to other things (file cleanup, etc)
1457+ # at some later point
1458+ system_manager.cleanup(exit=True)
1459+
1460 else:
1461 system_manager.logging.error("unknown mode argument: %s" %variables['mode'])
1462 sys.exit(1)
1463+
1464+ test_manager = testManager( variables['verbose'], variables['debug']
1465+ , variables['defaultengine'], variables['dotest']
1466+ , variables['skiptest'], variables['reorder']
1467+ , variables['suitelist'], variables['suitepaths']
1468+ , system_manager, variables['test_cases']
1469+ , variables['mode'] )
1470+
1471+ return (test_manager, testExecutor)
1472+
1473
1474=== modified file 'tests/lib/test_run_options.py'
1475--- tests/lib/test_run_options.py 2011-02-14 21:29:35 +0000
1476+++ tests/lib/test_run_options.py 2011-02-23 17:24:15 +0000
1477@@ -58,6 +58,12 @@
1478 if variables['repeat'] <= 0:
1479 print "Setting --repeat=1. You chose a silly value that I will ignore :P"
1480 variables['repeat'] = 1
1481+ if variables['mode'] == 'randgen':
1482+ print "Setting --no-secure-file-priv=True for randgen mode..."
1483+ variables['nosecurefilepriv']=True
1484+ if variables['mode'] == 'cleanup':
1485+ print "Setting --start-dirty=True for cleanup mode..."
1486+ variables['startdirty']=True
1487 return variables
1488
1489 # Create the CLI option parser
1490@@ -70,7 +76,7 @@
1491 server_default = os.path.abspath(os.path.join(testdir_default,
1492 '../drizzled/drizzled'))
1493
1494-workdir_default = os.path.join(testdir_default,'dbqp_work')
1495+workdir_default = os.path.join(testdir_default,'workdir')
1496
1497 clientbindir_default = os.path.abspath(os.path.join(testdir_default,
1498 '../client'))
1499@@ -119,7 +125,7 @@
1500 "--mode"
1501 , dest="mode"
1502 , default="dtr"
1503- , help="Testing mode. We only support dtr...for now >;) [%default]"
1504+ , help="Testing mode. We currently support dtr, randgen, and cleanup modes. See docs for further details about individual modes [%default]"
1505 )
1506
1507 system_control_group.add_option(
1508@@ -138,6 +144,14 @@
1509 , help="Don't try to cleanup from earlier runs (currently just a placeholder) [%default]"
1510 )
1511
1512+system_control_group.add_option(
1513+ "--randgen-path"
1514+ , dest="randgenpath"
1515+ , action='store'
1516+ , default=None
1517+ , help = "The path to a randgen installation that can be used to execute randgen-based tests"
1518+ )
1519+
1520 parser.add_option_group(system_control_group)
1521
1522 # end system_control_group
1523@@ -366,6 +380,20 @@
1524 parser.add_option_group(debugger_control_group)
1525
1526
1527+utility_group = optparse.OptionGroup(parser,
1528+ "Options to call additional utilities such as datagen")
1529+
1530+utility_group.add_option(
1531+ "--gendata"
1532+ , dest="gendatafile"
1533+ , action='store'
1534+ , type='string'
1535+ , default=None
1536+ , help="Call the randgen's gendata utility to use the specified configuration file. This will populate the server prior to any test execution")
1537+
1538+parser.add_option_group(utility_group)
1539+
1540+
1541 # supplied will be those arguments matching an option,
1542 # and test_cases will be everything else
1543 (args, test_cases)= parser.parse_args()
1544
1545=== added directory 'tests/randgen_tests'
1546=== added directory 'tests/randgen_tests/innodb_trx_log'
1547=== added directory 'tests/randgen_tests/main'
1548=== added file 'tests/randgen_tests/main/optimizer_subquery.cnf'
1549--- tests/randgen_tests/main/optimizer_subquery.cnf 1970-01-01 00:00:00 +0000
1550+++ tests/randgen_tests/main/optimizer_subquery.cnf 2011-02-23 17:24:15 +0000
1551@@ -0,0 +1,8 @@
1552+[test_info]
1553+comment = optimizer subquery test
1554+
1555+[test_command]
1556+command = ./gentest.pl --gendata=conf/drizzle/drizzle.zz --grammar=conf/drizzle/optimizer_subquery_drizzle.yy --queries=500 --threads=5
1557+
1558+[test_servers]
1559+servers = [[]]
1560
1561=== added file 'tests/randgen_tests/main/outer_join.cnf'
1562--- tests/randgen_tests/main/outer_join.cnf 1970-01-01 00:00:00 +0000
1563+++ tests/randgen_tests/main/outer_join.cnf 2011-02-23 17:24:15 +0000
1564@@ -0,0 +1,8 @@
1565+[test_info]
1566+comment = optimizer subquery test
1567+
1568+[test_command]
1569+command = ./gentest.pl --gendata=conf/drizzle/outer_join_drizzle.zz --grammar=conf/drizzle/outer_join_drizzle.yy --queries=500 --threads=5
1570+
1571+[test_servers]
1572+servers = [[]]
1573
1574=== added file 'tests/randgen_tests/main/simple.cnf'
1575--- tests/randgen_tests/main/simple.cnf 1970-01-01 00:00:00 +0000
1576+++ tests/randgen_tests/main/simple.cnf 2011-02-23 17:24:15 +0000
1577@@ -0,0 +1,9 @@
1578+[test_info]
1579+name = randgen_simple
1580+comment = basic, basic randgen test
1581+
1582+[test_command]
1583+command = ./gentest.pl --gendata=conf/drizzle/drizzle.zz --grammar=conf/drizzle/optimizer_subquery_drizzle.yy --queries=10 --threads=1
1584+
1585+[test_servers]
1586+servers = [[--transaction-log.enable]]
1587
1588=== added directory 'tests/randgen_tests/slave_plugin'
1589=== added file 'tests/randgen_tests/slave_plugin/slave_plugin.disabled'
1590--- tests/randgen_tests/slave_plugin/slave_plugin.disabled 1970-01-01 00:00:00 +0000
1591+++ tests/randgen_tests/slave_plugin/slave_plugin.disabled 2011-02-23 17:24:15 +0000
1592@@ -0,0 +1,9 @@
1593+[test_info]
1594+name = randgen_slave_plugin
1595+comment = basic, basic randgen test
1596+
1597+[test_command]
1598+command = ./gentest.pl --gendata=conf/drizzle/drizzle.zz --grammar=conf/drizzle/optimizer_subquery_drizzle.yy --queries=10 --threads=1
1599+
1600+[test_servers]
1601+servers = [[--innodb.replication-log=true],[--plugin-add=slave --slave.config-file=$MASTER_SERVER_SLAVE_CONFIG]]
1602
1603=== added directory 'tests/randgen_tests/trx_log'
1604=== added file 'tests/randgen_tests/trx_log/simple.cnf'
1605--- tests/randgen_tests/trx_log/simple.cnf 1970-01-01 00:00:00 +0000
1606+++ tests/randgen_tests/trx_log/simple.cnf 2011-02-23 17:24:15 +0000
1607@@ -0,0 +1,9 @@
1608+[test_info]
1609+name = randgen_simple
1610+comment = basic, basic randgen test
1611+
1612+[test_command]
1613+command = ./gentest.pl --gendata=conf/drizzle/drizzle.zz --grammar=conf/drizzle/optimizer_subquery_drizzle.yy --queries=10 --threads=1
1614+
1615+[test_servers]
1616+servers = [[--transaction-log.enable]]

Subscribers

People subscribed via source and target branches