Merge lp:~patrick-crews/percona-xtradb-cluster/qp-integrate into lp:~percona-dev/percona-xtradb-cluster/5.5.20

Proposed by Patrick Crews
Status: Merged
Approved by: Vadim Tkachenko
Approved revision: no longer in the source branch.
Merged at revision: 3718
Proposed branch: lp:~patrick-crews/percona-xtradb-cluster/qp-integrate
Merge into: lp:~percona-dev/percona-xtradb-cluster/5.5.20
Diff against target: 323164 lines
To merge this branch: bzr merge lp:~patrick-crews/percona-xtradb-cluster/qp-integrate
Reviewer Review Type Date Requested Status
Vadim Tkachenko Approve
Review via email: mp+93648@code.launchpad.net

Description of the change

Removed dbqp and integrated kewpie (updated / improved dbqp) into the tree.
Cut down on the size to 25MB from 400+.

To execute tests, simply type ./kewpie.py from the kewpie directory (additional options may apply)

To post a comment you must log in.
Revision history for this message
Vadim Tkachenko (vadim-tk) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.bzrignore'
--- .bzrignore 2012-02-07 18:26:15 +0000
+++ .bzrignore 2012-02-17 20:55:33 +0000
@@ -656,6 +656,8 @@
656isamchk/*.ds?656isamchk/*.ds?
657isamchk/*.vcproj657isamchk/*.vcproj
658item_xmlfunc.cc658item_xmlfunc.cc
659kewpie/qp_data/uuid
660kewpie/workdir
659lib_debug/*661lib_debug/*
660lib_release/*662lib_release/*
661libmysql/*.c663libmysql/*.c
662664
=== removed directory 'dbqp'
=== removed file 'dbqp/.bzrignore'
--- dbqp/.bzrignore 2012-02-04 01:22:23 +0000
+++ dbqp/.bzrignore 1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
1dbqp
2dbqp_data/uuid
3workdir
40
=== removed file 'dbqp/dbqp.py'
--- dbqp/dbqp.py 2012-02-04 01:22:23 +0000
+++ dbqp/dbqp.py 1970-01-01 00:00:00 +0000
@@ -1,99 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010 Patrick Crews
6#
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
20
21
22""" dbqp.py
23
24DataBase Quality Platform - system for executing various
25testing systems and the helper code
26
27Designed to be a modular test-runner. Different testing tools
28and databases may be plugged into the system via hacking the
29appropriate modules
30
31Currently geared towards Drizzle / will expand to MySQL
32"""
33
34# imports
35import os
36import sys
37
38import lib.opts.test_run_options as test_run_options
39from lib.modes.test_mode import handle_mode
40from lib.server_mgmt.server_management import serverManager
41from lib.sys_mgmt.system_management import systemManager
42from lib.test_mgmt.execution_management import executionManager
43
44# functions
45
46
47# main
48variables = test_run_options.variables
49system_manager = None
50server_manager = None
51test_manager = None
52test_executor = None
53execution_manager = None
54
55try:
56 # Some system-level work is constant regardless
57 # of the test to be run
58 system_manager = systemManager(variables)
59
60 # Create our server_manager
61 server_manager = serverManager(system_manager, variables)
62
63 # Get our mode-specific test_manager and test_executor
64 (test_manager,test_executor) = handle_mode(variables, system_manager)
65
66 # Gather our tests for execution
67 test_manager.gather_tests()
68
69 # Initialize test execution manager
70 execution_manager = executionManager(server_manager, system_manager
71 , test_manager, test_executor
72 , variables)
73
74 # Execute our tests!
75 execution_manager.execute_tests()
76
77except Exception, e:
78 print Exception, e
79
80except KeyboardInterrupt:
81 print "\n\nDetected <Ctrl>+c, shutting down and cleaning up..."
82
83finally:
84# TODO - make a more robust cleanup
85# At the moment, runaway servers are our biggest concern
86 if server_manager and not variables['startandexit']:
87 if variables['gdb']:
88 server_manager.cleanup_all_servers()
89 else:
90 server_manager.cleanup()
91 if not variables['startandexit']:
92 if test_manager:
93 fail_count = test_manager.has_failing_tests()
94 sys.exit(test_manager.has_failing_tests())
95 else:
96 # return 1 as we likely have a problem if we don't have a
97 # test_manager
98 sys.exit(1)
99
1000
=== removed directory 'dbqp/dbqp_data'
=== removed directory 'dbqp/docs'
=== removed file 'dbqp/docs/dbqp.rst'
--- dbqp/docs/dbqp.rst 2012-02-04 01:22:23 +0000
+++ dbqp/docs/dbqp.rst 1970-01-01 00:00:00 +0000
@@ -1,458 +0,0 @@
1**********************************
2dbqp
3**********************************
4
5Synopsis
6========
7Drizzle testing tool
8
9**./dbqp** [ *OPTIONS* ] [ TESTCASE ]
10
11Description
12===========
13
14:program:`dbqp.py` is BETA software. It is intended to provide a standardized
15platform to facilitate Drizzle testing.
16
17The default mode is 'dtr' and is used to execute tests from the Drizzle
18test suite. These tests are included with Drizzle distributions and
19provide a way for users to verify that the system will operate according
20to expectations.
21
22The dtr tests use a diff-based paradigm, meaning that the test runner executes
23a test and then compares the results received with pre-recorded expected
24results. In the event of a test failure, the program will provide output
25highlighting the differences found between expected and actual results; this
26can be useful for troubleshooting and in bug reports.
27
28The program is also integrated with the random query generator testing tool
29and a 'rangden' mode is available - it will execute randgen tests when
30provided a path to a randgen installation. Tests are organized similar to dtr
31tests, but are .cnf file based.
32
33A 'cleanup' mode is also available as a convenience - it will simply shutdown
34any servers that may have been started via start-and-exit.
35
36While most users are concerned with ensuring general functionality, the
37program also allows a user to quickly spin up a server for ad-hoc testing
38and to run the test-suite against an already running Drizzle server.
39
40Running tests
41=========================
42
43There are several different ways to run tests using :program:`dbqp.py`.
44
45It should be noted that unless :option:`--force` is used, the program will
46stop execution upon encountering the first failing test.
47:option:`--force` is recommended if you are running several tests - it will
48allow you to view all successes and failures in one run.
49
50Running individual tests
51------------------------
52If one only wants to run a few, specific tests, they may do so this way::
53
54 ./dbqp.py [OPTIONS] test1 [test2 ... testN]
55
56Running all tests within a suite
57--------------------------------
58Many of the tests supplied with Drizzle are organized into suites.
59
60The tests within drizzle/tests/t are considered the 'main' suite.
61Other suites are located in either drizzle/tests/suite or within the various
62directories in drizzle/plugin. Tests for a specific plugin should live in
63the plugin's directory - drizzle/plugin/example_plugin/tests
64
65To run the tests in a specific suite::
66
67 ./dbqp.py [OPTIONS] --suite=SUITENAME
68
69Running specific tests within a suite
70--------------------------------------
71To run a specific set of tests within a suite::
72
73 ./dbqp.py [OPTIONS] --suite=SUITENAME TEST1 [TEST2..TESTN]
74
75Calling tests using <suitename>.<testname> currently does not work.
76One must specify the test suite via the :option:`--suite` option.
77
78
79Running all available tests
80---------------------------
81Currently, the quickest way to execute all tests in all suites is
82to use 'make test-dbqp' from the drizzle root.
83
84Otherwise, one should simply name all suites::
85
86 ./dbqp.py [OPTIONS] --suite=SUITE1, SUITE2, ...SUITEN
87
88Interpreting test results
89=========================
90The output of the test runner is quite simple. Every test should pass.
91In the event of a test failure, please take the time to file a bug here:
92*https://bugs.launchpad.net/drizzle*
93
94During a run, the program will provide the user with:
95 * test name (suite + name)
96 * test status (pass/fail/skipped)
97 * time spent executing each test
98
99At the end of a run, the program will provide the user with a listing of:
100 * how many tests were run
101 * counts and percentages of total exectuted for all test statuses
102 * a listing of failing, skipped, or disabled tests
103 * total time spent executing the tests
104
105Example output::
106
107 <snip>
108 30 Jan 2011 16:26:31 : main.small_tmp_table [ pass ] 38
109 30 Jan 2011 16:26:31 : main.snowman [ pass ] 42
110 30 Jan 2011 16:26:31 : main.statement_boundaries [ pass ] 47
111 30 Jan 2011 16:26:31 : main.status [ pass ] 51
112 30 Jan 2011 16:26:31 : main.strict [ pass ] 138
113 30 Jan 2011 16:26:43 : main.subselect [ fail ] 12361
114 30 Jan 2011 16:26:43 : --- drizzle/tests/r/subselect.result 2011-01-30 16:23:54.975776148 -0500
115 30 Jan 2011 16:26:43 : +++ drizzle/tests/r/subselect.reject 2011-01-30 16:26:43.835519303 -0500
116 30 Jan 2011 16:26:43 : @@ -5,7 +5,7 @@
117 30 Jan 2011 16:26:43 : 2
118 30 Jan 2011 16:26:43 : explain extended select (select 2);
119 30 Jan 2011 16:26:43 : id select_type table type possible_keys key key_len ref rows filtered Extra
120 30 Jan 2011 16:26:43 : -9 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used
121 30 Jan 2011 16:26:43 : +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL NULL No tables used
122 <snip>
123 30 Jan 2011 16:30:20 : ================================================================================
124 30 Jan 2011 16:30:20 INFO: Test execution complete in 314 seconds
125 30 Jan 2011 16:30:20 INFO: Summary report:
126 30 Jan 2011 16:30:20 INFO: Executed 552/552 test cases, 100.00 percent
127 30 Jan 2011 16:30:20 INFO: STATUS: FAIL, 1/552 test cases, 0.18 percent executed
128 30 Jan 2011 16:30:20 INFO: STATUS: PASS, 551/552 test cases, 99.82 percent executed
129 30 Jan 2011 16:30:20 INFO: FAIL tests: main.subselect
130 30 Jan 2011 16:30:20 INFO: Spent 308 / 314 seconds on: TEST(s)
131 30 Jan 2011 16:30:20 INFO: Test execution complete
132 30 Jan 2011 16:30:20 INFO: Stopping all running servers...
133
134
135Additional uses
136===============
137Starting a server for manual testing
138------------------------------------
139
140:program:`dbqp.py` allows a user to get a Drizzle server up and running
141quickly. This can be useful for fast ad-hoc testing.
142
143To do so call::
144
145 ./dbqp.py --start-and-exit [*OPTIONS*]
146
147This will start a Drizzle server that you can connect to and query
148
149Starting a server against a pre-populated DATADIR
150--------------------------------------------------
151
152Using :option:`--start-dirty` prevents :program:`dbqp.py` from attempting
153to initialize (clean) the datadir. This can be useful if you want to use
154an already-populated datadir for testing.
155
156NOTE: This feature is still being tested, use caution with your data!!!
157
158Randgen mode / Executing randgen tests
159---------------------------------------
160
161Using :option:`--mode` =randgen and :option:`--randgen-path` =/path/to/randgen
162will cause the randgen tests to execute. This are simple .cnf file-based
163tests that define various randgen command lines that are useful in testing
164the server. Test organization is similar to the dtr tests. Tests live in
165suites, the default suite is 'main' and they all live in
166drizzle/tests/randgen_tests::
167
168 ./dbqp.py --mode=randgen --randgen-path=/path/to/randgen
169
170A user may specify suites and individual tests to run, just as with dtr-based
171testing. Test output is the same as well::
172
173 ./dbqp --mode=randgen --randgen-path=/home/username/repos/randgen
174 Setting --no-secure-file-priv=True for randgen mode...
175 <snip>
176 23 Feb 2011 11:42:43 INFO: Using testing mode: randgen
177 <snip>
178 23 Feb 2011 11:44:58 : ================================================================================
179 23 Feb 2011 11:44:58 : TEST NAME [ RESULT ] TIME (ms)
180 23 Feb 2011 11:44:58 : ================================================================================
181 23 Feb 2011 11:44:58 : main.optimizer_subquery [ pass ] 134153
182 23 Feb 2011 11:45:03 : main.outer_join [ pass ] 5136
183 23 Feb 2011 11:45:06 : main.simple [ pass ] 2246
184 23 Feb 2011 11:45:06 : ================================================================================
185 23 Feb 2011 11:45:06 INFO: Test execution complete in 142 seconds
186 23 Feb 2011 11:45:06 INFO: Summary report:
187 23 Feb 2011 11:45:06 INFO: Executed 3/3 test cases, 100.00 percent
188 23 Feb 2011 11:45:06 INFO: STATUS: PASS, 3/3 test cases, 100.00 percent executed
189 23 Feb 2011 11:45:06 INFO: Spent 141 / 142 seconds on: TEST(s)
190 23 Feb 2011 11:45:06 INFO: Test execution complete
191 23 Feb 2011 11:45:06 INFO: Stopping all running servers...
192
193Cleanup mode
194-------------
195A cleanup mode is provided for user convenience. This simply shuts down
196any servers whose pid files are detected in the dbqp workdir. It is mainly
197intended as a quick cleanup for post-testing with :option:`--start-and-exit`::
198
199 ./dbqp.py --mode=cleanup
200
201 Setting --start-dirty=True for cleanup mode...
202 23 Feb 2011 11:35:59 INFO: Using Drizzle source tree:
203 23 Feb 2011 11:35:59 INFO: basedir: drizzle
204 23 Feb 2011 11:35:59 INFO: clientbindir: drizzle/client
205 23 Feb 2011 11:35:59 INFO: testdir: drizzle/tests
206 23 Feb 2011 11:35:59 INFO: server_version: 2011.02.2188
207 23 Feb 2011 11:35:59 INFO: server_compile_os: unknown-linux-gnu
208 23 Feb 2011 11:35:59 INFO: server_platform: x86_64
209 23 Feb 2011 11:35:59 INFO: server_comment: (Source distribution (dbqp_randgen))
210 23 Feb 2011 11:35:59 INFO: Using --start-dirty, not attempting to touch directories
211 23 Feb 2011 11:35:59 INFO: Using default-storage-engine: innodb
212 23 Feb 2011 11:35:59 INFO: Using testing mode: cleanup
213 23 Feb 2011 11:35:59 INFO: Killing pid 10484 from drizzle/tests/workdir/testbot0/server0/var/run/server0.pid
214 23 Feb 2011 11:35:59 INFO: Stopping all running servers...
215
216Program architecture
217====================
218
219:program:`dbqp.py`'s 'dtr' mode uses a simple diff-based mechanism for testing.
220This is the default mode and where the majority of Drizzle testing occurs.
221It will execute the statements contained in a test and compare the results
222to pre-recorded expected results. In the event of a test failure, you
223will be presented with a diff::
224
225 main.exp1 [ fail ]
226 --- drizzle/tests/r/exp1.result 2010-11-02 02:10:25.107013998 +0300
227 +++ drizzle/tests/r/exp1.reject 2010-11-02 02:10:32.017013999 +0300
228 @@ -5,4 +5,5 @@
229 a
230 1
231 2
232 +3
233 DROP TABLE t1;
234
235A test case consists of a .test and a .result file. The .test file includes
236the various statements to be executed for a test. The .result file lists
237the expected results for a given test file. These files live in tests/t
238and tests/r, respectively. This structure is the same for all test suites.
239
240dbqp.py options
241===================
242
243The :program:`dbqp.py` tool has several available options:
244
245./dbqp.py [ OPTIONS ] [ TESTCASE ]
246
247
248Options
249-------
250
251.. program:: dbqp.py
252
253.. option:: -h, --help
254
255 show this help message and exit
256
257Options for the test-runner itself
258----------------------------------
259
260.. program:: dbqp.py
261
262.. option:: --force
263
264 Set this to continue test execution beyond the first failed test
265
266.. option:: --start-and-exit
267
268 Spin up the server(s) for the first specified test then exit
269 (will leave servers running)
270
271.. option:: --verbose
272
273 Produces extensive output about test-runner state.
274 Distinct from --debug
275
276.. option:: --debug
277
278 Provide internal-level debugging output.
279 Distinct from --verbose
280
281.. option:: --mode=MODE
282
283 Testing mode.
284 We only support dtr...for now >;)
285 [dtr]
286
287.. option:: --record
288
289 Record a testcase result
290 (if the testing mode supports it)
291 [False]
292
293.. option:: --fast
294
295 Don't try to cleanup from earlier runs
296 (currently just a placeholder) [False]
297
298.. option:: --randgen-path=RANDGENPATH
299
300 The path to a randgen installation that can be used to
301 execute randgen-based tests
302
303
304Options for controlling which tests are executed
305------------------------------------------------
306
307.. program:: dbqp.py
308
309.. option:: --suite=SUITELIST
310
311 The name of the suite containing tests we want.
312 Can accept comma-separated list (with no spaces).
313 Additional --suite args are appended to existing list
314 [autosearch]
315
316.. option:: --suitepath=SUITEPATHS
317
318 The path containing the suite(s) you wish to execute.
319 Use on --suitepath for each suite you want to use.
320
321.. option:: --do-test=DOTEST
322
323 input can either be a prefix or a regex.
324 Will only execute tests that match the provided pattern
325
326.. option:: --skip-test=SKIPTEST
327
328 input can either be a prefix or a regex.
329 Will exclude tests that match the provided pattern
330
331.. option:: --reorder
332
333 sort the testcases so that they are executed optimally
334 for the given mode [False]
335
336.. option:: --repeat=REPEAT
337
338 Run each test case the specified number of times. For
339 a given sequence, the first test will be run n times,
340 then the second, etc [1]
341
342Options for defining the code that will be under test
343-----------------------------------------------------
344
345.. program:: dbqp.py
346
347.. option:: --basedir=BASEDIR
348
349 Pass this argument to signal to the test-runner
350 that this is an in-tree test (not required).
351 We automatically set a number of variables
352 relative to the argument (client-bindir,
353 serverdir, testdir) [../]
354
355.. option:: --serverdir=SERVERPATH
356
357 Path to the server executable. [auto-search]
358
359.. option:: --client-bindir=CLIENTBINDIR
360
361 Path to the directory containing client program
362 binaries for use in testing [auto-search]
363
364.. option:: --default-storage-engine=DEFAULTENGINE
365
366 Start drizzled using the specified engine [innodb]
367
368Options for defining the testing environment
369--------------------------------------------
370
371.. program:: dbqp.py
372
373.. option:: --testdir=TESTDIR
374
375 Path to the test dir, containing additional files for
376 test execution. [pwd]
377
378.. option:: --workdir=WORKDIR
379
380 Path to the directory test-run will use to store
381 generated files and directories.
382 [basedir/tests/dbqp_work]
383
384.. option:: --top-srcdir=TOPSRCDIR
385
386 build option [basedir_default]
387
388.. option:: --top-builddir=TOPBUILDDIR
389
390 build option [basedir_default]
391
392.. option:: --no-shm
393
394 By default, we symlink workdir to a location in shm.
395 Use this flag to not symlink [False]
396
397.. option:: --start-dirty
398
399 Don't try to clean up working directories before test
400 execution [False]
401
402.. option:: --no-secure-file-priv
403
404 Turn off the use of --secure-file-priv=vardir for
405 started servers
406
407Options to pass options on to the server
408-----------------------------------------
409
410.. program:: dbqp.py
411
412.. option:: --drizzled=DRIZZLEDOPTIONS
413
414 Pass additional options to the server. Will be passed
415 to all servers for all tests (mostly for --start-and-
416 exit)
417
418
419Options for defining the tools we use for code analysis (valgrind, gprof, gcov, etc)
420------------------------------------------------------------------------------------
421
422.. program:: dbqp.py
423
424.. option:: --valgrind
425
426 Run drizzletest and drizzled executables using
427 valgrind with default options [False]
428
429.. option:: --valgrind-option=VALGRINDARGLIST
430
431 Pass an option to valgrind (overrides/removes default
432 valgrind options)
433
434Options for controlling the use of debuggers with test execution
435----------------------------------------------------------------
436
437.. program:: dbqp.py
438
439.. option:: --gdb
440
441 Start the drizzled server(s) in gdb
442
443.. option:: --manual-gdb
444
445 Allows you to start the drizzled server(s) in gdb
446 manually (in another window, etc
447
448Options to call additional utilities such as datagen
449------------------------------------------------------
450
451.. program:: dbqp.py
452
453.. option:: --gendata=GENDATAFILE
454
455 Call the randgen's gendata utility to use the
456 specified configuration file. This will populate the
457 server prior to any test execution
458
4590
=== removed file 'dbqp/docs/index.rst'
--- dbqp/docs/index.rst 2012-02-04 01:22:23 +0000
+++ dbqp/docs/index.rst 1970-01-01 00:00:00 +0000
@@ -1,33 +0,0 @@
1.. dbqp documentation master file, created by
2 sphinx-quickstart on Fri Aug 27 08:33:41 2010.
3 You can adapt this file completely to your liking, but it should at least
4 contain the root `toctree` directive.
5
6Welcome to dbqp's documentation!
7===================================
8
9dbqp (DataBase Quality Platform) is designed to facilitate testing of MySQL-based database systems. Its aim is to provide a pluggable system that allows one to run a variety of testing tools and to share standard helper code (server allocation and management / test result reporting / etc)
10
11Introduction:
12-------------
13.. toctree::
14 :maxdepth: 2
15
16Testing:
17--------
18.. toctree::
19 :maxdepth: 2
20
21 dbqp.rst
22 test-run.rst
23 randgen.rst
24 sql-bench.rst
25 sysbench.rst
26 writing_tests.rst
27
28Indices and tables
29==================
30
31* :ref:`genindex`
32* :ref:`search`
33
340
=== removed file 'dbqp/docs/randgen.rst'
--- dbqp/docs/randgen.rst 2012-02-04 01:22:23 +0000
+++ dbqp/docs/randgen.rst 1970-01-01 00:00:00 +0000
@@ -1,197 +0,0 @@
1**********************************
2randgen (random query generator)
3**********************************
4
5
6
7Description
8===========
9
10The randgen aka the random query generator is a database
11testing tool. It uses a grammar-based stochastic model to represent
12some desired set of queries (to exercise the optimizer, for example)
13and generates random queries as allowed by the grammar
14
15The primary documentation is here: http://forge.mysql.com/wiki/RandomQueryGenerator
16
17This document is intended to help the user set up their environment so that the tool
18may be used in conjunction with the dbqp.py test-runner. The forge documentation
19contains more information on the particulars of the tool itself.
20
21Requirements
22============
23
24DBD::drizzle
25-------------
26The DBD::drizzle module is required it can be found here http://launchpad.net/dbd-drizzle/
27
28Additional information for installing the module::
29
30 Prerequisites
31 ----------------
32 * Perl
33 * Drizzle (bzr branch lp:drizzle)
34 * libdrizzle (bzr branch lp:libdrizzle)
35 * C compiler
36
37 Installation
38 -------------
39 You should only have to run the following:
40
41 perl Makefile.PL --cflags=-I/usr/local/drizzle/include/ --libs=-"L/usr/local/drizzle/lib -ldrizzle"
42
43
44 Depending on where libdrizzle is installed. Also, you'll want to make
45 sure that ldconfig has configured libdrizzle to be in your library path
46
47Additional information may be found here: http://forge.mysql.com/wiki/RandomQueryGeneratorQuickStart
48
49Installing the randgen
50=======================
51
52The code may be branched from launchpad: bzr branch lp:randgen
53
54it also may be downloaded from here http://launchpad.net/randgen/+download
55
56That is all there is : )
57
58Randgen / dbqp tests
59====================
60
61These tests are simple .cnf files that can define a few basic variables
62that are needed to execute tests. The most interesting section is test_servers. It is a simple list of python lists
63Each sub-list contains a string of server options that are needed. Each sub-list represents a server that will be started.
64Using an empty sub-list will create a server with the default options::
65
66 [test_info]
67 comment = does NOT actually test the master-slave replication yet, but it will.
68
69 [test_command]
70 command = ./gentest.pl --gendata=conf/drizzle/drizzle.zz --grammar=conf/drizzle/optimizer_subquery_drizzle.yy --queries=10 --threads=1
71
72 [test_servers]
73 servers = [[--innodb.replication-log],[--plugin-add=slave --slave.config-file=$MASTER_SERVER_SLAVE_CONFIG]]
74
75Running tests
76=========================
77
78There are several different ways to run tests using :doc:`dbqp` 's randgen mode.
79
80It should be noted that unless :option:`--force` is used, the program will
81stop execution upon encountering the first failing test.
82:option:`--force` is recommended if you are running several tests - it will
83allow you to view all successes and failures in one run.
84
85Running individual tests
86------------------------
87If one only wants to run a few, specific tests, they may do so this way::
88
89 ./dbqp --mode=randgen --randgen-path=/path/to/randgen [OPTIONS] test1 [test2 ... testN]
90
91Running all tests within a suite
92--------------------------------
93Many of the tests supplied with Drizzle are organized into suites.
94
95The tests within drizzle/tests/randgen_tests/main are considered the 'main' suite.
96Other suites are also subdirectories of drizzle/tests/randgen_tests.
97
98To run the tests in a specific suite::
99
100 ./dbqp --mode=randgen --randgen-path=/path/to/randgen [OPTIONS] --suite=SUITENAME
101
102Running specific tests within a suite
103--------------------------------------
104To run a specific set of tests within a suite::
105
106 ./dbqp --mode=randgen --randgen-path=/path/to/randgen [OPTIONS] --suite=SUITENAME TEST1 [TEST2..TESTN]
107
108Calling tests using <suitename>.<testname> currently does not work.
109One must specify the test suite via the :option:`--suite` option.
110
111
112Running all available tests
113---------------------------
114One would currently have to name all suites, but the majority of the working tests live in the main suite
115Other suites utilize more exotic server combinations and we are currently tweaking them to better integrate with the
116dbqp system. The slave-plugin suite does currently have a good config file for setting up simple replication setups for testing.
117To execute several suites' worth of tests::
118
119 ./dbqp --mode=randgen --randgen-path=/path/to/randgen [OPTIONS] --suite=SUITE1, SUITE2, ...SUITEN
120
121Interpreting test results
122=========================
123The output of the test runner is quite simple. Every test should pass.
124In the event of a test failure, please take the time to file a bug here:
125*https://bugs.launchpad.net/drizzle*
126
127During a run, the program will provide the user with:
128 * test name (suite + name)
129 * test status (pass/fail/skipped)
130 * time spent executing each test
131
132At the end of a run, the program will provide the user with a listing of:
133 * how many tests were run
134 * how many tests failed
135 * percentage of passing tests
136 * a listing of failing tests
137 * total time spent executing the tests
138
139Example output::
140
141 24 Feb 2011 17:27:36 : main.outer_join_portable [ pass ] 7019
142 24 Feb 2011 17:27:39 : main.repeatable_read [ pass ] 2764
143 24 Feb 2011 17:28:57 : main.select_stability_validator [ pass ] 77946
144 24 Feb 2011 17:29:01 : main.subquery [ pass ] 4474
145 24 Feb 2011 17:30:52 : main.subquery_semijoin [ pass ] 110355
146 24 Feb 2011 17:31:00 : main.subquery_semijoin_nested [ pass ] 8750
147 24 Feb 2011 17:31:03 : main.varchar [ pass ] 3048
148 24 Feb 2011 17:31:03 : ================================================================================
149 24 Feb 2011 17:31:03 INFO: Test execution complete in 288 seconds
150 24 Feb 2011 17:31:03 INFO: Summary report:
151 24 Feb 2011 17:31:03 INFO: Executed 18/18 test cases, 100.00 percent
152 24 Feb 2011 17:31:03 INFO: STATUS: PASS, 18/18 test cases, 100.00 percent executed
153 24 Feb 2011 17:31:03 INFO: Spent 287 / 288 seconds on: TEST(s)
154 24 Feb 2011 17:31:03 INFO: Test execution complete
155 24 Feb 2011 17:31:03 INFO: Stopping all running servers...
156
157
158Additional uses
159===============
160Starting a server for manual testing and (optionally) populating it
161--------------------------------------------------------------------
162
163:doc:`dbqp` 's randgen mode allows a user to get a Drizzle server up and running quickly. This can be useful for fast ad-hoc testing.
164
165To do so call::
166
167 ./dbqp --mode=randgen --randgen-path=/path/to/randgen --start-and-exit [*OPTIONS*]
168
169This will start a Drizzle server that you can connect to and query
170
171With the addition of the --gendata option, a user may utilize the randgen's gendata (table creation and population) tool
172to populate a test server. In the following example, the test server is now populated by the 8 tables listed below::
173
174 ./dbqp --mode=randgen --randgen-path=/randgen --start-and-exit --gendata=/randgen/conf/drizzle/drizzle.zz
175 <snip>
176 24 Feb 2011 17:48:48 INFO: NAME: server0
177 24 Feb 2011 17:48:48 INFO: MASTER_PORT: 9306
178 24 Feb 2011 17:48:48 INFO: DRIZZLE_TCP_PORT: 9307
179 24 Feb 2011 17:48:48 INFO: MC_PORT: 9308
180 24 Feb 2011 17:48:48 INFO: PBMS_PORT: 9309
181 24 Feb 2011 17:48:48 INFO: RABBITMQ_NODE_PORT: 9310
182 24 Feb 2011 17:48:48 INFO: VARDIR: /home/pcrews/bzr/work/dbqp_randgen_updates/tests/workdir/testbot0/server0/var
183 24 Feb 2011 17:48:48 INFO: STATUS: 1
184 # 2011-02-24T17:48:48 Default schema: test
185 # 2011-02-24T17:48:48 Executor initialized, id GenTest::Executor::Drizzle 2011.02.2198 ()
186 # 2011-02-24T17:48:48 # Creating Drizzle table: test.A; engine: ; rows: 0 .
187 # 2011-02-24T17:48:48 # Creating Drizzle table: test.B; engine: ; rows: 0 .
188 # 2011-02-24T17:48:48 # Creating Drizzle table: test.C; engine: ; rows: 1 .
189 # 2011-02-24T17:48:48 # Creating Drizzle table: test.D; engine: ; rows: 1 .
190 # 2011-02-24T17:48:48 # Creating Drizzle table: test.AA; engine: ; rows: 10 .
191 # 2011-02-24T17:48:48 # Creating Drizzle table: test.BB; engine: ; rows: 10 .
192 # 2011-02-24T17:48:48 # Creating Drizzle table: test.CC; engine: ; rows: 100 .
193 # 2011-02-24T17:48:49 # Creating Drizzle table: test.DD; engine: ; rows: 100 .
194 24 Feb 2011 17:48:49 INFO: User specified --start-and-exit. dbqp.py exiting and leaving servers running...
195
196
197
1980
=== removed file 'dbqp/docs/sql-bench.rst'
--- dbqp/docs/sql-bench.rst 2012-02-04 01:22:23 +0000
+++ dbqp/docs/sql-bench.rst 1970-01-01 00:00:00 +0000
@@ -1,174 +0,0 @@
1**********************************
2sql-bench
3**********************************
4
5
6
7Description
8===========
9dbqp can take advantage of two testing modes offered by the sql-bench tool.
10
11The Drizzle code has a copy of this tool set in the tree and the test-runner offers two modes::
12
13 sql-bench modes
14 ---------------
15 * sqlbench - runs the entire sql-bench test suite and can take a very long time (~45 minutes)
16 * crashme - runs the crash-me tool and reports failure if any tests should not pass
17
18
19Requirements
20============
21DBD::drizzle
22-------------
23The DBD::drizzle module is required it can be found here http://launchpad.net/dbd-drizzle/
24
25Additional information for installing the module::
26
27 Prerequisites
28 ----------------
29 * Perl
30 * Drizzle (bzr branch lp:drizzle)
31 * libdrizzle (bzr branch lp:libdrizzle)
32 * C compiler
33
34 Installation
35 -------------
36 You should only have to run the following:
37
38 perl Makefile.PL --cflags=-I/usr/local/drizzle/include/ --libs=-"L/usr/local/drizzle/lib -ldrizzle"
39
40
41 Depending on where libdrizzle is installed. Also, you'll want to make
42 sure that ldconfig has configured libdrizzle to be in your library path
43
44
45sql-bench / dbqp tests
46=======================
47
48Currently, there are only two sql-bench test cases for dbqp. As one might expect, main.all_sqlbench_tests executes::
49
50 run-all-tests --server=drizzle --dir=$DRIZZLE_TEST_WORKDIR --log --connect-options=port=$MASTER_MYPORT --create-options=ENGINE=innodb --user=root
51
52against a Drizzle server. The second test case executes the crashme tool against a running server.
53
54Test cases are defined in python .cnf files and live in tests/sqlbench_tests.
55
56Running tests
57=========================
58
59NOTE: all_sqlbench_tests can take a significant amount of time to execute (45 minutes or so on a decently provisioned laptop)
60
61There are several different ways to run tests using :doc:`dbqp` 's sql-bench mode.
62
63It should be noted that unless :option:`--force` is used, the program will
64stop execution upon encountering the first failing test.
65:option:`--force` is recommended if you are running several tests - it will
66allow you to view all successes and failures in one run.
67
68At present, sql-bench output in a work in progress. It does report a simple pass/fail, but we are working on alternate ways of viewing / storing the results (and for other testing modes as well)
69
70
71Running all tests within a suite
72--------------------------------
73At present, there is only one test case per suite for sqlbench and crashme modes - that is all that is needed for these tools.
74To execute the sql-bench test suite::
75
76 ./dbqp --mode=sqlbench
77
78To execute the crash-me test suite::
79
80 ./dbqp --mode=crashme
81
82Interpreting test results
83=========================
84The output of the test runner is quite simple. Every test should pass.
85In the event of a test failure, please take the time to file a bug here:
86*https://bugs.launchpad.net/drizzle*
87
88During a run, the program will provide the user with:
89 * test name (suite + name)
90 * test status (pass/fail/skipped)
91 * time spent executing each test
92
93Example sqlbench output::
94
95 20110608-135645 ===============================================================
96 20110608-135645 TEST NAME [ RESULT ] TIME (ms)
97 20110608-135645 ===============================================================
98 20110608-135645 main.all_sqlbench_tests [ pass ] 2732007
99 20110608-135645 Test finished. You can find the result in:
100 20110608-135645 drizzle/tests/workdir/RUN-drizzle-Linux_2.6.38_9_generic_x86_64
101 20110608-135645 Benchmark DBD suite: 2.15
102 20110608-135645 Date of test: 2011-06-08 13:11:10
103 20110608-135645 Running tests on: Linux 2.6.38-9-generic x86_64
104 20110608-135645 Arguments: --connect-options=port=9306 --create-options=ENGINE=innodb
105 20110608-135645 Comments:
106 20110608-135645 Limits from:
107 20110608-135645 Server version: Drizzle 2011.06.19.2325
108 20110608-135645 Optimization: None
109 20110608-135645 Hardware:
110 20110608-135645
111 20110608-135645 alter-table: Total time: 42 wallclock secs ( 0.06 usr 0.04 sys + 0.00 cusr 0.00 csys = 0.10 CPU)
112 20110608-135645 ATIS: Total time: 22 wallclock secs ( 4.01 usr 0.26 sys + 0.00 cusr 0.00 csys = 4.27 CPU)
113 20110608-135645 big-tables: Total time: 24 wallclock secs ( 4.16 usr 0.22 sys + 0.00 cusr 0.00 csys = 4.38 CPU)
114 20110608-135645 connect: Total time: 31 wallclock secs ( 6.81 usr 4.50 sys + 0.00 cusr 0.00 csys = 11.31 CPU)
115 20110608-135645 create: Total time: 59 wallclock secs ( 2.93 usr 1.65 sys + 0.00 cusr 0.00 csys = 4.58 CPU)
116 20110608-135645 insert: Total time: 1962 wallclock secs (270.53 usr 66.35 sys + 0.00 cusr 0.00 csys = 336.88 CPU)
117 20110608-135645 select: Total time: 560 wallclock secs (23.12 usr 4.62 sys + 0.00 cusr 0.00 csys = 27.74 CPU)
118 20110608-135645 transactions: Total time: 21 wallclock secs ( 2.43 usr 1.98 sys + 0.00 cusr 0.00 csys = 4.41 CPU)
119 20110608-135645 wisconsin: Total time: 10 wallclock secs ( 2.11 usr 0.52 sys + 0.00 cusr 0.00 csys = 2.63 CPU)
120 20110608-135645
121 20110608-135645 All 9 test executed successfully
122 20110608-135645
123 20110608-135645 Totals per operation:
124 20110608-135645 Operation seconds usr sys cpu tests
125 20110608-135645 alter_table_add 18.00 0.02 0.00 0.02 100
126 20110608-135645 alter_table_drop 17.00 0.02 0.01 0.03 91
127 20110608-135645 connect 2.00 1.02 0.51 1.53 2000
128 <snip>
129 20110608-135645 update_rollback 3.00 0.26 0.23 0.49 100
130 20110608-135645 update_with_key 73.00 6.70 5.23 11.93 300000
131 20110608-135645 update_with_key_prefix 34.00 4.45 2.30 6.75 100000
132 20110608-135645 wisc_benchmark 2.00 1.49 0.00 1.49 114
133 20110608-135645 TOTALS 2865.00 310.26 79.94 390.20 2974250
134 20110608-135645
135 20110608-135645 ===============================================================
136 20110608-135645 INFO Test execution complete in 2735 seconds
137 20110608-135645 INFO Summary report:
138 20110608-135645 INFO Executed 1/1 test cases, 100.00 percent
139 20110608-135645 INFO STATUS: PASS, 1/1 test cases, 100.00 percent executed
140 20110608-135645 INFO Spent 2732 / 2735 seconds on: TEST(s)
141 20110608-135645 INFO Test execution complete
142 20110608-135645 INFO Stopping all running servers...
143
144Example crashme output::
145
146 20110608-152759 ===============================================================
147 20110608-152759 TEST NAME [ RESULT ] TIME (ms)
148 20110608-152759 ===============================================================
149 20110608-152759 main.crashme [ fail ] 155298
150 20110608-152759 func_extra_to_days=error # Function TO_DAYS
151 20110608-152759 ###
152 20110608-152759 ###<select to_days('1996-01-01') from crash_me_d
153 20110608-152759 ###>2450084
154 20110608-152759 ###We expected '729024' but got '2450084'
155 20110608-152759 func_odbc_timestampadd=error # Function TIMESTAMPADD
156 20110608-152759 ###
157 20110608-152759 ###<select timestampadd(SQL_TSI_SECOND,1,'1997-01-01 00:00:00')
158 20110608-152759 ###>1997-01-01 00:00:01.000000
159 20110608-152759 ###We expected '1997-01-01 00:00:01' but got '1997-01-01 00:00:01.000000'
160 20110608-152759 ###
161 20110608-152759 ###<select {fn timestampadd(SQL_TSI_SECOND,1,{ts '1997-01-01 00:00:00'}) }
162 20110608-152759 ###>1997-01-01 00:00:01.000000
163 20110608-152759 ###We expected '1997-01-01 00:00:01' but got '1997-01-01 00:00:01.000000'
164 20110608-152759
165 20110608-152759 ERROR Failed test. Use --force to execute beyond the first test failure
166 20110608-152759 ===============================================================
167 20110608-152759 INFO Test execution complete in 158 seconds
168 20110608-152759 INFO Summary report:
169 20110608-152759 INFO Executed 1/1 test cases, 100.00 percent
170 20110608-152759 INFO STATUS: FAIL, 1/1 test cases, 100.00 percent executed
171 20110608-152759 INFO FAIL tests: main.crashme
172 20110608-152759 INFO Spent 155 / 158 seconds on: TEST(s)
173 20110608-152759 INFO Test execution complete
174
1750
=== removed file 'dbqp/docs/sysbench.rst'
--- dbqp/docs/sysbench.rst 2012-02-04 01:22:23 +0000
+++ dbqp/docs/sysbench.rst 1970-01-01 00:00:00 +0000
@@ -1,123 +0,0 @@
1**********************************
2sysbench
3**********************************
4
5
6
7Description
8===========
9dbqp's sysbench mode allows a user to run a specific iteration of a sysbench test (eg an oltp readonly run at concurrency = 16)
10
11
12Requirements
13============
14
15The SYSBENCH command requires that the Drizzle library header be installed. Simply build Drizzle and do::
16
17 $> sudo make install
18
19This will install the right headers.
20
21The SYSBENCH command also requires installation of the drizzle-sysbench program, which can be installed from source like so::
22
23 $> bzr branch lp:~drizzle-developers/sysbench/trunk drizzle-sysbench
24 $> cd drizzle-sysbench
25 $> ./autogen.sh && ./configure && make && sudo make install
26
27Make sure sysbench is then in your path
28
29
30sysbench / dbqp tests
31=====================
32
33A sysbench test defines a run for a particular concurrency. There are suites for readonly and readwrite.
34They are currently broken down this way as an experiment - we are open to other ways of organizing these tests::
35
36 [test_info]
37 comment = 16 threads
38
39 [test_command]
40 command = sysbench --max-time=240 --max-requests=0 --test=oltp --db-ps-mode=disable --drizzle-table-engine=innodb --oltp-read-only=on --oltp-table-size=1000000 --drizzle-mysql=on --drizzle-user=root --drizzle-db=test --drizzle-port=$MASTER_MYPORT --drizzle-host=localhost --db-driver=drizzle --num-threads=16
41
42 [test_servers]
43 servers = [[innodb.buffer-pool-size=256M innodb.log-file-size=64M innodb.log-buffer-size=8M innodb.thread-concurrency=0 innodb.additional-mem-pool-size=16M table-open-cache=4096 table-definition-cache=4096 mysql-protocol.max-connections=2048]]
44
45Running tests
46=========================
47
48There are several different ways to run tests using :doc:`dbqp` 's sysbench mode.
49
50It should be noted that unless :option:`--force` is used, the program will
51stop execution upon encountering the first failing test.
52:option:`--force` is recommended if you are running several tests - it will
53allow you to view all successes and failures in one run.
54
55Running individual tests
56------------------------
57If one only wants to run a few, specific tests, they may do so this way::
58
59 ./dbqp --mode=sysbench [OPTIONS] test1 [test2 ... testN]
60
61Running all tests within a suite
62--------------------------------
63Many of the tests supplied with Drizzle are organized into suites.
64
65The tests within drizzle/tests/randgen_tests/main are considered the 'main' suite.
66Other suites are also subdirectories of drizzle/tests/randgen_tests.
67
68To run the tests in a specific suite::
69
70 ./dbqp --mode=sysbench [OPTIONS] --suite=SUITENAME
71
72Running specific tests within a suite
73--------------------------------------
74To run a specific set of tests within a suite::
75
76 ./dbqp --mode=sysbench [OPTIONS] --suite=SUITENAME TEST1 [TEST2..TESTN]
77
78Calling tests using <suitename>.<testname> currently does not work.
79One must specify the test suite via the :option:`--suite` option.
80
81
82Running all available tests
83---------------------------
84One would currently have to name all suites, but the majority of the working tests live in the main suite
85Other suites utilize more exotic server combinations and we are currently tweaking them to better integrate with the
86dbqp system. The slave-plugin suite does currently have a good config file for setting up simple replication setups for testing.
87To execute several suites' worth of tests::
88
89 ./dbqp --mode=sysbench [OPTIONS] --suite=SUITE1, SUITE2, ...SUITEN
90
91Interpreting test results
92=========================
93The output of the test runner is quite simple. Every test should pass.
94In the event of a test failure, please take the time to file a bug here:
95*https://bugs.launchpad.net/drizzle*
96
97During a run, the program will provide the user with:
98 * test name (suite + name)
99 * test status (pass/fail/skipped)
100 * time spent executing each test
101
102Example output::
103
104 20110601-191706 ===============================================================
105 20110601-191706 TEST NAME [ RESULT ] TIME (ms)
106 20110601-191706 ===============================================================
107 20110601-191706 readonly.concurrency_16 [ pass ] 240019
108 20110601-191706 max_req_lat_ms: 21.44
109 20110601-191706 rwreqps: 4208.2
110 20110601-191706 min_req_lat_ms: 6.31
111 20110601-191706 deadlocksps: 0.0
112 20110601-191706 tps: 150.29
113 20110601-191706 avg_req_lat_ms: 6.65
114 20110601-191706 95p_req_lat_ms: 7.02
115 20110601-191706 ===============================================================
116 20110601-191706 INFO Test execution complete in 275 seconds
117 20110601-191706 INFO Summary report:
118 20110601-191706 INFO Executed 1/1 test cases, 100.00 percent
119 20110601-191706 INFO STATUS: PASS, 1/1 test cases, 100.00 percent executed
120 20110601-191706 INFO Spent 240 / 275 seconds on: TEST(s)
121 20110601-191706 INFO Test execution complete
122 20110601-191706 INFO Stopping all running servers...
123
1240
=== removed file 'dbqp/docs/test-run.rst'
--- dbqp/docs/test-run.rst 2012-02-04 01:22:23 +0000
+++ dbqp/docs/test-run.rst 1970-01-01 00:00:00 +0000
@@ -1,494 +0,0 @@
1.. _test-run-label:
2
3**********************************
4test-run.pl - Drizzle testing tool
5**********************************
6
7Synopsis
8========
9
10**./test-run** [ *OPTIONS* ] [ TESTCASE ]
11
12Description
13===========
14
15:program:`test-run.pl` (aka test-run, dtr, mtr) is used to execute tests
16from the Drizzle test suite. These tests are included with Drizzle
17distributions and provide a way for users to verify that the system will
18operate according to expectations.
19
20The tests use a diff-based paradigm, meaning that the test runner executes
21a test and then compares the results received with pre-recorded expected
22results. In the event of a test failure, the program will provide output
23highlighting the differences found between expected and actual results; this
24can be useful for troubleshooting and in bug reports.
25
26While most users are concerned with ensuring general functionality, the
27program also allows a user to quickly spin up a server for ad-hoc testing
28and to run the test-suite against an already running Drizzle server.
29
30Running tests
31=========================
32
33There are several different ways to run tests using :program:`test-run.pl`.
34
35It should be noted that unless :option:`--force` is used, the program will
36stop execution upon encountering the first failing test.
37:option:`--force` is recommended if you are running several tests - it will
38allow you to view all successes and failures in one run.
39
40Running individual tests
41------------------------
42If one only wants to run a few, specific tests, they may do so this way::
43
44 ./test-run [OPTIONS] test1 [test2 ... testN]
45
46Running all tests within a suite
47--------------------------------
48Many of the tests supplied with Drizzle are organized into suites.
49
50The tests within drizzle/tests/t are considered the 'main' suite.
51Other suites are located in either drizzle/tests/suite or within the various
52directories in drizzle/plugin. Tests for a specific plugin should live in
53the plugin's directory - drizzle/plugin/example_plugin/tests
54
55To run the tests in a specific suite::
56
57 ./test-run [OPTIONS] --suite=SUITENAME
58
59Running specific tests within a suite
60--------------------------------------
61To run a specific set of tests within a suite::
62
63 ./test-run [OPTIONS] --suite=SUITENAME TEST1 [TEST2..TESTN]
64
65Calling tests using <suitename>.<testname> currently does not work.
66One must specify the test suite via the :option:`--suite` option.
67
68
69Running all available tests
70---------------------------
71Currently, the quickest way to execute all tests in all suites is
72to use 'make test' from the drizzle root.
73
74Otherwise, one should simply name all suites::
75
76 ./test-run [OPTIONS] --suite=SUITE1, SUITE2, ...SUITEN
77
78Interpreting test results
79=========================
80The output of the test runner is quite simple. Every test should pass.
81In the event of a test failure, please take the time to file a bug here:
82*https://bugs.launchpad.net/drizzle*
83
84During a run, the program will provide the user with:
85 * test name (suite + name)
86 * test status (pass/fail/skipped)
87 * time spent executing each test
88
89At the end of a run, the program will provide the user with a listing of:
90 * how many tests were run
91 * how many tests failed
92 * percentage of passing tests
93 * a listing of failing tests
94 * total time spent executing the tests
95
96Example output::
97
98 <snip>
99 main.snowman [ pass ] 9
100 main.statement_boundaries [ pass ] 17
101 main.status [ pass ] 12
102 main.strict [ pass ] 50
103 main.subselect [ pass ] 6778
104 main.subselect2 [ pass ] 51
105 main.subselect3 [ fail ]
106 drizzletest: At line 621: query 'select a, (select max(b) from t1) into outfile
107 <snip>
108 --------------------------------------------------------------------------------
109 Stopping All Servers
110 Failed 10/231 tests, 95.67% were successful.
111
112 The log files in var/log may give you some hint
113 of what went wrong.
114 If you want to report this error, go to:
115 http://bugs.launchpad.net/drizzle
116 The servers were restarted 16 times
117 Spent 64.364 of 115 seconds executing testcases
118
119 drizzle-test-run in default mode: *** Failing the test(s): main.exp1
120 main.func_str main.loaddata main.null main.outfile main.subselect3
121 main.warnings jp.like_utf8 jp.select_utf8 jp.where_utf8
122
123Additional uses
124===============
125Starting a server for manual testing
126------------------------------------
127
128:program:`test-run.pl` allows a user to get a Drizzle server up and running
129quickly. This can be useful for fast ad-hoc testing.
130
131To do so call::
132
133 ./test-run --start-and-exit [*OPTIONS*]
134
135This will start a Drizzle server that you can connect to and query
136
137Starting a server against a pre-populated DATADIR
138--------------------------------------------------
139
140Using :option:`--start-dirty` prevents :program:`test-run.pl` from attempting
141to initialize (clean) the datadir. This can be useful if you want to use
142an already-populated datadir for testing.
143
144Program architecture
145====================
146
147:program:`test-run.pl` uses a simple diff-based mechanism for testing.
148It will execute the statements contained in a test and compare the results
149to pre-recorded expected results. In the event of a test failure, you
150will be presented with a diff::
151
152 main.exp1 [ fail ]
153 --- drizzle/tests/r/exp1.result 2010-11-02 02:10:25.107013998 +0300
154 +++ drizzle/tests/r/exp1.reject 2010-11-02 02:10:32.017013999 +0300
155 @@ -5,4 +5,5 @@
156 a
157 1
158 2
159 +3
160 DROP TABLE t1;
161
162A test case consists of a .test and a .result file. The .test file includes
163the various statements to be executed for a test. The .result file lists
164the expected results for a given test file. These files live in tests/t
165and tests/r, respectively. This structure is the same for all test suites.
166
167test-run.pl options
168===================
169
170The :program:`test-run.pl` tool has several available options:
171
172./test-run [ OPTIONS ] [ TESTCASE ]
173
174Options to control what engine/variation to run
175-----------------------------------------------
176
177.. program:: test-run
178
179.. option:: --compress
180
181 Use the compressed protocol between client and server
182
183.. option:: --bench
184
185 Run the benchmark suite
186
187.. option:: --small-bench
188
189 Run the benchmarks with --small-tests --small-tables
190
191Options to control directories to use
192-------------------------------------
193
194.. program:: test-run
195
196.. option:: --benchdir=DIR
197
198 The directory where the benchmark suite is stored
199 (default: ../../mysql-bench)
200
201.. option:: --tmpdir=DIR
202
203 The directory where temporary files are stored
204 (default: ./var/tmp).
205
206.. option:: --vardir=DIR
207
208 The directory where files generated from the test run
209 is stored (default: ./var). Specifying a ramdisk or
210 tmpfs will speed up tests.
211
212.. option:: --mem
213
214 Run testsuite in "memory" using tmpfs or ramdisk
215 Attempts to find a suitable location
216 using a builtin list of standard locations
217 for tmpfs (/dev/shm)
218 The option can also be set using environment
219 variable :envvar:`DTR_MEM` =[DIR]
220
221Options to control what test suites or cases to run
222---------------------------------------------------
223
224.. program:: test-run
225
226.. option:: --force
227
228 Continue to run the suite after failure
229
230.. option:: --do-test=PREFIX or REGEX
231
232 Run test cases which name are prefixed with PREFIX
233 or fulfills REGEX
234
235.. option:: --skip-test=PREFIX or REGEX
236
237 Skip test cases which name are prefixed with PREFIX
238 or fulfills REGEX
239
240.. option:: --start-from=PREFIX
241
242 Run test cases starting from test prefixed with PREFIX
243 suite[s]=NAME1,..,NAMEN Collect tests in suites from the comma separated
244 list of suite names.
245 The default is: "main,jp"
246
247.. option:: --skip-rpl
248
249 Skip the replication test cases.
250 combination="ARG1 .. ARG2" Specify a set of "drizzled" arguments for one
251 combination.
252
253.. option:: --skip-combination
254
255 Skip any combination options and combinations files
256
257.. option:: --repeat-test=n
258
259 How many times to repeat each test (default: 1)
260
261Options that specify ports
262--------------------------
263
264.. program:: test-run
265
266.. option:: --master_port=PORT
267
268 Specify the port number used by the first master
269
270.. option:: --slave_port=PORT
271
272 Specify the port number used by the first slave
273
274.. option:: --dtr-build-thread=#
275
276 Specify unique collection of ports. Can also be set by
277 setting the environment variable :envvar:`DTR_BUILD_THREAD`.
278
279Options for test case authoring
280-------------------------------
281
282.. program:: test-run
283
284.. option:: --record TESTNAME
285
286 (Re)genereate the result file for TESTNAME
287
288.. option:: --check-testcases
289
290 Check testcases for sideeffects
291
292.. option:: --mark-progress
293
294 Log line number and elapsed time to <testname>.progress
295
296Options that pass on options
297----------------------------
298
299.. program:: test-run
300
301.. option:: --drizzled=ARGS
302
303 Specify additional arguments to "drizzled"
304
305Options to run test on running server
306-------------------------------------
307
308.. program:: test-run
309
310.. option:: --extern
311
312 Use running server for tests
313
314.. option:: --user=USER
315
316 User for connection to extern server
317
318Options for debugging the product
319---------------------------------
320
321.. program:: test-run
322
323.. option:: --client-ddd
324
325 Start drizzletest client in ddd
326
327.. option:: --client-debugger=NAME
328
329 Start drizzletest in the selected debugger
330
331.. option:: --client-gdb
332
333 Start drizzletest client in gdb
334
335.. option:: --ddd
336
337 Start drizzled in ddd
338
339.. option:: --debug
340
341 Dump trace output for all servers and client programs
342
343.. option:: --debugger=NAME
344
345 Start drizzled in the selected debugger
346
347.. option:: --gdb
348
349 Start the drizzled(s) in gdb
350
351.. option:: --manual-debug
352
353 Let user manually start drizzled in debugger, before running test(s)
354
355.. option:: --manual-gdb
356
357 Let user manually start drizzled in gdb, before running test(s)
358
359.. option:: --manual-ddd
360
361 Let user manually start drizzled in ddd, before running test(s)
362
363.. option:: --master-binary=PATH
364
365 Specify the master "drizzled" to use
366
367.. option:: --slave-binary=PATH
368
369 Specify the slave "drizzled" to use
370
371.. option:: --strace-client
372
373 Create strace output for drizzletest client
374
375.. option:: --max-save-core
376
377 Limit the number of core files saved (to avoid filling up disks for
378 heavily crashing server). Defaults to 5, set to 0 for no limit.
379
380Options for coverage, profiling etc
381-----------------------------------
382
383.. todo::
384
385 .. option:: --gcov
386
387.. program:: test-run
388
389.. option:: --gprof
390
391 See online documentation on how to use it.
392
393.. option:: --valgrind
394
395 Run the *drizzletest* and *drizzled* executables using valgrind with
396 default options
397
398.. option:: --valgrind-all
399
400 Synonym for :option:`--valgrind`
401
402.. option:: --valgrind-drizzleslap
403
404 Run "drizzleslap" with valgrind.
405
406.. option:: --valgrind-drizzletest
407
408 Run the *drizzletest* and *drizzle_client_test* executable with valgrind
409
410.. option:: --valgrind-drizzled
411
412 Run the "drizzled" executable with valgrind
413
414.. option:: --valgrind-options=ARGS
415
416 Deprecated, use :option:`--valgrind-option`
417
418.. option:: --valgrind-option=ARGS
419
420 Option to give valgrind, replaces default option(s),
421 can be specified more then once
422
423.. option:: --valgrind-path=[EXE]
424
425 Path to the valgrind executable
426
427.. option:: --callgrind
428
429 Instruct valgrind to use callgrind
430
431.. option:: --massif
432
433 Instruct valgrind to use massif
434
435Misc options
436------------
437
438.. program:: test-run
439
440.. option:: --comment=STR
441
442 Write STR to the output
443
444.. option:: --notimer
445
446 Don't show test case execution time
447
448.. option:: --script-debug
449
450 Debug this script itself
451
452.. option:: --verbose
453
454 More verbose output
455
456.. option:: --start-and-exit
457
458 Only initialize and start the servers, using the
459 startup settings for the specified test case (if any)
460
461.. option:: --start-dirty
462
463 Only start the servers (without initialization) for
464 the specified test case (if any)
465
466.. option:: --fast
467
468 Don't try to clean up from earlier runs
469
470.. option:: --reorder
471
472 Reorder tests to get fewer server restarts
473
474.. option:: --help
475
476 Get this help text
477
478.. option:: --testcase-timeout=MINUTES
479
480 Max test case run time (default 15)
481
482.. option:: --suite-timeout=MINUTES
483
484 Max test suite run time (default 180)
485
486.. option:: --warnings | log-warnings
487
488 Pass --log-warnings to drizzled
489
490.. option:: --sleep=SECONDS
491
492 Passed to drizzletest, will be used as fixed sleep time
493
494
4950
=== removed file 'dbqp/docs/writing_tests.rst'
--- dbqp/docs/writing_tests.rst 2012-02-04 01:22:23 +0000
+++ dbqp/docs/writing_tests.rst 1970-01-01 00:00:00 +0000
@@ -1,30 +0,0 @@
1**********************************
2Writing drizzletest test cases
3**********************************
4
5Synopsis
6========
7
8Here, we discuss various topics related to writing test cases, with a focus on features
9that allow for more complex testing scenarios. Additional documentation for other testing
10tools will come later.
11
12Using a pre-populated datadir
13=============================
14The experimental test runner, dbqp allows for starting a server with a pre-populated datadir
15for a test case. This is accomplished via the use of a .cnf file (versus a master.opt file)
16Over time, this will be the direction for all drizzletest cases.
17
18The .cnf file shown below tells the test-runner to use the directory drizzle/tests/std_data/backwards_compat_data
19as the datadir for the first server. If a test uses multiple servers, the .cnf file can have additional sections ([s1]...[sN])::
20
21 [test_servers]
22 servers = [[]]
23
24 [s0]
25 load-datadir=backwards_compat_data
26
27
28All datadirs are expected to be in tests/std_data. If there is need for the ability to use datadirs outside of this location,
29it can be explored.
30
310
=== removed directory 'dbqp/lib'
=== removed file 'dbqp/lib/__init__.py'
=== removed directory 'dbqp/lib/modes'
=== removed file 'dbqp/lib/modes/__init__.py'
=== removed directory 'dbqp/lib/modes/dtr'
=== removed file 'dbqp/lib/modes/dtr/__init__.py'
=== removed file 'dbqp/lib/modes/dtr/dtr_test_execution.py'
--- dbqp/lib/modes/dtr/dtr_test_execution.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/modes/dtr/dtr_test_execution.py 1970-01-01 00:00:00 +0000
@@ -1,139 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010 Patrick Crews
6#
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
22""" dtr_test_execution:
23 code related to the execution of dtr test cases
24
25 We are provided access to a testManager with
26 dtr-specific testCases. We contact teh executionManager
27 to produce the system and server configurations we need
28 to execute a test.
29
30"""
31
32# imports
33import os
34import sys
35import subprocess
36import commands
37
38import lib.test_mgmt.test_execution as test_execution
39
40class testExecutor(test_execution.testExecutor):
41 """ dtr-specific testExecutor
42 We currently execute by sending test-case
43 data to client/drizzletest...for now
44
45 """
46
47 def execute_testCase (self):
48 """ Execute a dtr testCase via calls to drizzletest (boo)
49 Eventually, we will replace drizzletest with pythonic
50 goodness, but we have these classes stored here for the moment
51
52 """
53 test_execution.testExecutor.execute_testCase(self)
54 self.status = 0
55
56 # generate command line
57 drizzletest_cmd = self.generate_drizzletest_call()
58
59 # call drizzletest
60 self.execute_drizzletest(drizzletest_cmd)
61
62 # analyze results
63 self.current_test_status = self.process_drizzletest_output()
64 self.set_server_status(self.current_test_status)
65
66
67 def generate_drizzletest_call(self):
68 """ Produce the command line we use to call drizzletest
69 We have a healthy number of values, so we put this in a
70 nice function
71
72 """
73
74 drizzletest_arguments = [ '--no-defaults'
75 , '--silent'
76 , '--tmpdir=%s' %(self.master_server.tmpdir)
77 , '--logdir=%s' %(self.master_server.logdir)
78 , '--port=%d' %(self.master_server.master_port)
79 , '--database=test'
80 , '--user=root'
81 , '--password='
82 #, '--testdir=%s' %(self.test_manager.testdir)
83 , '--test-file=%s' %(self.current_testcase.testpath)
84 , '--tail-lines=20'
85 , '--timer-file=%s' %(self.master_server.timer_file)
86 , '--result-file=%s' %(self.current_testcase.resultpath)
87 ]
88 if self.record_flag:
89 # We want to record a new result
90 drizzletest_arguments.append('--record')
91 drizzletest_cmd = "%s %s %s" %( self.cmd_prefix
92 , self.master_server.code_tree.drizzletest
93 , " ".join(drizzletest_arguments))
94 return drizzletest_cmd
95
96 def execute_drizzletest(self, drizzletest_cmd):
97 """ Execute the commandline and return the result.
98 We use subprocess as we can pass os.environ dicts and whatnot
99
100 """
101 testcase_name = self.current_testcase.fullname
102 self.time_manager.start(testcase_name,'test')
103 #retcode, output = self.system_manager.execute_cmd( drizzletest_cmd
104 # , must_pass = 0 )
105 drizzletest_outfile = os.path.join(self.logdir,'drizzletest.out')
106 drizzletest_output = open(drizzletest_outfile,'w')
107 drizzletest_subproc = subprocess.Popen( drizzletest_cmd
108 , shell=True
109 , cwd=self.system_manager.testdir
110 , env=self.working_environment
111 , stdout = drizzletest_output
112 , stderr = subprocess.STDOUT
113 )
114 drizzletest_subproc.wait()
115 retcode = drizzletest_subproc.returncode
116 execution_time = int(self.time_manager.stop(testcase_name)*1000) # millisec
117
118 drizzletest_output.close()
119 drizzletest_file = open(drizzletest_outfile,'r')
120 output = ''.join(drizzletest_file.readlines())
121 drizzletest_file.close()
122
123 self.logging.debug("drizzletest_retcode: %d" %(retcode))
124 self.current_test_retcode = retcode
125 self.current_test_output = output
126 self.current_test_exec_time = execution_time
127
128 def process_drizzletest_output(self):
129 """ Drizzletest has run, we now check out what we have """
130 retcode = self.current_test_retcode
131 if retcode == 0:
132 return 'pass'
133 elif retcode == 62 or retcode == 15872:
134 return 'skipped'
135 elif retcode == 63 or retcode == 1:
136 return 'fail'
137 else:
138 return 'fail'
139
1400
=== removed file 'dbqp/lib/modes/dtr/dtr_test_management.py'
--- dbqp/lib/modes/dtr/dtr_test_management.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/modes/dtr/dtr_test_management.py 1970-01-01 00:00:00 +0000
@@ -1,495 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010 Patrick Crews
6#
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
20
21""" dtr_test_management:
22 code related to the gathering / analysis / management of
23 the test cases
24 ie - collecting the list of tests in each suite, then
25 gathering additional, relevant information for the test-runner's dtr
26 mode. (traditional diff-based testing)
27
28"""
29
30# imports
31import os
32import re
33import sys
34from ConfigParser import RawConfigParser
35
36import lib.test_mgmt.test_management as test_management
37
38
39
40class testCase:
41 """Holds info on a per .test file basis
42 Attributes contain information necessary to execute / validate
43 the test file when it is executed.
44
45 """
46 def __init__(self, system_manager, test_case=None, test_name=None, suite_name=None
47 , suite_path=None, test_server_options=[], test_path=None, result_path=None
48 , comment=None, master_sh=None, cnf_path=None
49 , disable=0, innodb_test=1
50 , need_debug=0, debug=0):
51 self.system_manager = system_manager
52 self.logging = self.system_manager.logging
53 self.skip_keys = ['system_manager']
54 self.testcase = test_case
55 self.testname = test_name
56 self.suitename = suite_name
57 self.suitepath = suite_path
58 self.fullname = "%s.%s" %(suite_name, test_name)
59 self.testpath = test_path
60 self.resultpath = result_path
61
62 self.skip_flag = 0
63 self.timezone = "GMT-3"
64 self.component_id = "drizzled"
65 self.slave_count = 0
66 self.master_count = 1
67 self.server_options = test_server_options
68 # We will populate this in a better fashion later on
69 # as we allow .cnf files, we need to do a bit of
70 # messing about to make this work right
71 if self.server_options == [] or type(self.server_options[0]) is not list:
72 self.server_requirements=[self.server_options]
73 else:
74 self.server_requirements = self.server_options
75 self.server_options= self.server_options[0][0]
76 self.comment = comment
77 self.master_sh = master_sh
78 self.cnf_path = cnf_path
79 self.disable = disable
80 self.innodb_test = innodb_test
81 self.need_debug = need_debug
82
83 self.system_manager.logging.debug_class(self)
84
85 def should_run(self):
86 if self.skip_flag or self.disable:
87 return 0
88 else:
89 return 1
90
91
92
93
94
95class testManager(test_management.testManager):
96 """Deals with scanning test directories, gathering test cases, and
97 collecting per-test information (opt files, etc) for use by the
98 test-runner
99
100 """
101
102 def process_suite(self,suite_dir):
103 """Process a test suite.
104 This includes searching for tests in test_list and only
105 working with the named tests (all tests in suite is the default)
106 Further processing includes reading the disabled.def file
107 to know which tests to skip, processing the suite.opt file,
108 and processing the individual test cases for data relevant
109 to the rest of the test-runner
110
111 """
112
113 self.system_manager.logging.verbose("Processing suite: %s" %(suite_dir))
114
115 # Generate our test and result files:
116 testdir = os.path.join(suite_dir, 't')
117 resultdir = os.path.join(suite_dir, 'r')
118
119 # Do basic checks to make sure this is worth further work
120 self.check_suite(suite_dir, testdir, resultdir)
121
122 # Get suite-level options
123 suite_options = []
124 cnf_path, suite_options = self.process_suite_options(suite_dir)
125
126 # Get the 'name' of the suite. This can require some processing
127 # But the name is useful for reporting and whatnot
128 suite_name = self.get_suite_name(suite_dir)
129
130 # Get the contents of the testdir and filter it accordingly
131 # This applies do-test / skip-test filters and any specific
132 # test case names
133 testlist = self.testlist_filter(os.listdir(testdir))
134 # sort our list if no individual tests were specified
135 if not self.desired_tests:
136 testlist.sort()
137
138 # gather deeper information on tests we are interested in
139 if testlist:
140 # We have tests we want to process, we gather additional information
141 # that is useful at the suite level. This includes disabled tests
142 # Gather disabled test list.
143 # This is used in process_test_file()
144 disabled_tests = {}
145 disabled_tests = self.process_disabled_test_file(testdir)
146 for test_case in testlist:
147 self.add_test(self.process_test_file(suite_dir,
148 suite_name, cnf_path, suite_options
149 , disabled_tests, testdir
150 , resultdir, test_case))
151
152 def process_test_file(self, suite_dir, suite_name, suite_cnf_path, suite_options
153 , disabled_tests, testdir
154 , resultdir, test_case):
155 """ We generate / find / store all the relevant information per-test.
156 This information will be used when actually executing the test
157 We store the data in a testCase object
158
159 """
160
161 test_server_options = suite_options
162 test_name = test_case.replace('.test','')
163 self.system_manager.logging.verbose("Processing test: %s.%s" %(suite_name,test_name))
164
165
166 # Fix this , create a testCase with gather_test_data() passed
167 # as the argument
168 # Ensure we pass everything we need and use it all
169 ( test_path
170 , result_file_name
171 , result_path
172 , comment
173 , master_sh
174 , cnf_path
175 , test_server_options
176 , disable
177 , innodb_test
178 , need_debug) = self.gather_test_data(test_case, test_name,
179 suite_name, test_server_options,testdir,
180 resultdir, disabled_tests)
181 if suite_cnf_path and not cnf_path:
182 cnf_path=suite_cnf_path
183 test_case = testCase(self.system_manager, test_case, test_name, suite_name,
184 suite_dir, test_server_options,test_path, result_path,
185 master_sh=master_sh, cnf_path=cnf_path, debug=self.debug)
186 return test_case
187
188
189########################################################################
190# utility functions
191#
192# Stuff that helps us out and simplifies our main functions
193# But isn't that important unless you need to dig deep
194########################################################################
195
196 def gather_test_data(self, test_case, test_name, suite_name,
197 test_server_options, testdir, resultdir, disabled_tests):
198 """ We gather all of the data needed to produce a testCase for
199 a given test
200
201 """
202
203 test_path = os.path.join(testdir,test_case)
204 result_file_name = test_name+'.result'
205 result_path = self.find_result_path(resultdir, result_file_name)
206 comment = None
207 master_sh_path = test_path.replace('.test','-master.sh')
208 if os.path.exists(master_sh_path):
209 master_sh = master_sh_path
210 else:
211 master_sh = None
212 master_opt_path = test_path.replace('.test', '-master.opt')
213 config_file_path = test_path.replace('.test', '.cnf')
214 # NOTE: this currently makes suite level server options additive
215 # to file-level .opt files...not sure if this is the best.
216 test_server_options = test_server_options + self.process_opt_file(
217 master_opt_path)
218 # deal with .cnf files (which supercede master.opt stuff)
219 cnf_options = []
220 cnf_flag, returned_options = self.process_cnf_file(config_file_path)
221 cnf_options += returned_options
222 if cnf_flag: # we found a proper file and need to override
223 found_options = cnf_options
224 else:
225 config_file_path = None
226 (disable, comment) = self.check_if_disabled(disabled_tests, test_name)
227 innodb_test = 0
228 need_debug = 0
229 return (test_path, result_file_name, result_path, comment, master_sh,
230 config_file_path, test_server_options, disable, innodb_test, need_debug)
231
232 def check_suite(self, suite_dir, testdir, resultdir):
233 """Handle basic checks of the suite:
234 does the suite exist?
235 is there a /t dir?
236 is there a /r dir?
237 Error and die if not
238
239 """
240 # We expect suite to be a path name, no fuzzy searching
241 if not os.path.exists(suite_dir):
242 self.system_manager.logging.error("Suite: %s does not exist" %(suite_dir))
243 sys.exit(1)
244
245 # Ensure our test and result directories are present
246 if not os.path.exists(testdir):
247 self.system_manager.logging.error("Suite: %s does not have a 't' directory (expected location for test files)" %(suite_dir))
248 sys.exit(1)
249 if not os.path.exists(resultdir):
250 self.system_manager.logging.error("Suite: %s does not have an 'r' directory (expected location for result files)" %(suite_dir))
251 sys.exit(1)
252
253 def get_suite_name(self, suite_dir):
254 """ Get the 'name' of the suite
255 This can either be the path basename or one directory up, as
256 in the case of files in the drizzle/plugins directory
257
258 """
259
260 # We trim any trailing path delimiters as python returns
261 # '' for basedir if the path ends that way
262 # BEGIN horrible hack to accomodate bad location of main suite : /
263 if suite_dir == self.testdir:
264 return 'main'
265 # END horrible hack : /
266 if suite_dir.endswith('/'):
267 suite_dir=suite_dir[:-1]
268 suite_dir_root,suite_dir_basename = os.path.split(suite_dir)
269 if suite_dir_basename == 'tests' or suite_dir_basename == 'drizzle-tests':
270 suite_name = os.path.basename(suite_dir_root)
271 else:
272 suite_name = suite_dir_basename
273 self.system_manager.logging.debug("Suite_name: %s" %(suite_name))
274 return suite_name
275
276 def process_suite_options(self, suite_dir):
277 """ Process the suite.opt and master.opt files
278 that reside at the suite-level if they exist.
279 Return a list of the options found
280
281 We also process .cnf files - this
282 is currently dbqp-only and is the proper
283 way to do things :P
284
285 """
286 found_options = []
287 opt_files = ['t/master.opt','t/suite.opt']
288 for opt_file in opt_files:
289 found_options = found_options + self.process_opt_file(os.path.join(suite_dir,opt_file))
290 # We also process the suite-level .cnf file(s). We override
291 # a master.opt file if we have a .cnf file. There is no reason they
292 # should ever be used in conjunction and I am biased towards .cnf ; )
293 cnf_files = ['t/master.cnf']
294 cnf_options = []
295 for cnf_file in cnf_files:
296 config_file_path = os.path.join(suite_dir,cnf_file)
297 cnf_flag, returned_options = self.process_cnf_file(config_file_path)
298 cnf_options += returned_options
299 if cnf_flag: # we found a proper file and need to override
300 found_options = cnf_options
301 else:
302 config_file_path = None
303 return config_file_path, found_options
304
305 def process_disabled_test_file(self, testdir):
306 """ Checks and processes the suite's disabled.def
307 file. This file must reside in the suite/t directory
308 It must be in the format:
309 test-name : comment (eg BugNNNN - bug on hold, test disabled)
310 In reality a test should *never* be disabled. EVER.
311 However, we keep this as a bit of utility
312
313 """
314 disabled_tests = {}
315 disabled_def_path = os.path.join(testdir,'disabled.def')
316 if not os.path.exists(disabled_def_path):
317 return disabled_tests
318
319 try:
320 disabled_test_file = open(disabled_def_path,'r')
321 except IOError, e:
322 self.system_manager.logging.error("Problem opening disabled.def file: %s" %(disabled_def_path))
323 sys.exit(1)
324
325 self.system_manager.logging.debug("Processing disabled.def file: %s" %(disabled_def_path))
326 disabled_bug_pattern = re.compile("[\S]+[\s]+:[\s]+[\S]")
327
328 for line in disabled_test_file:
329 line = line.strip()
330 if not line.startswith('#'): # comment
331 if re.match(disabled_test_pattern,line):
332 self.system_manager.logging.debug("found disabled test - %s" %(line))
333 test_name, test_comment = line.split(':')
334 disabled_tests[test_name.strip()]=test_comment.strip()
335
336 disabled_test_file.close()
337 return disabled_tests
338
339
340 def process_opt_file(self, opt_file_path):
341 """ Process a test-run '.opt' file.
342 These files contain test and suite-specific server options
343 (ie what options the server needs to use for the test)
344
345 Returns a list of the options (we don't really validate...yet)
346
347 NOTE: test-run.pl allows for server *and* system options
348 (eg timezone, slave_count, etc) in opt files. We don't.
349 None of our tests use this and we should probably avoid it
350 We can introduce server and system .opt files or even better
351 would be to use config files as we do with drizzle-automation
352 This would allow us to specify options for several different
353 things in a single file, but in a clean and standardized manner
354
355 """
356 found_options = []
357 if not os.path.exists(opt_file_path):
358 return found_options
359
360 try:
361 opt_file = open(opt_file_path,'r')
362 except IOError, e:
363 self.system_manager.logging.error("Problem opening option file: %s" %(opt_file_path))
364 sys.exit(1)
365
366 self.system_manager.logging.debug("Processing opt file: %s" %(opt_file_path))
367 for line in opt_file:
368 options = line.split('--')
369 if options:
370 for option in options:
371 if option:
372 if 'restart' in option or '#' in option:
373 option = 'restart'
374 found_options.append('--%s' %(option.strip()))
375 opt_file.close()
376 return found_options
377
378 def process_cnf_file(self, cnf_file_path):
379 """ We extract meaningful information from a .cnf file
380 if it exists. Currently limited to server allocation
381 needs
382
383 """
384
385 server_requirements = []
386 cnf_flag = 0
387 if os.path.exists(cnf_file_path):
388 cnf_flag = 1
389 config_reader = RawConfigParser()
390 config_reader.read(cnf_file_path)
391 server_requirements = self.process_server_reqs(config_reader.get('test_servers','servers'))
392 return ( cnf_flag, server_requirements )
393
394 def process_server_reqs(self,data_string):
395 """ We read in the list of lists as a string, so we need to
396 handle this / break it down into proper chunks
397
398 """
399 server_reqs = []
400 # We expect to see a list of lists and throw away the
401 # enclosing brackets
402 option_sets = data_string[1:-1].strip().split(',')
403 for option_set in option_sets:
404 server_reqs.append([option_set[1:-1].strip()])
405 return server_reqs
406
407 def testlist_filter(self, testlist):
408 """ Filter our list of testdir contents based on several
409 criteria. This looks for user-specified test-cases
410 and applies the do-test and skip-test filters
411
412 Returns the list of tests that we want to execute
413 for further processing
414
415 """
416
417 # We want only .test files
418 # Possible TODO: allow alternate test extensions
419 testlist = [test_file for test_file in testlist if test_file.endswith('.test')]
420
421 # Search for specific test names
422 if self.desired_tests: # We have specific, named tests we want from the suite(s)
423 tests_to_use = []
424 for test in self.desired_tests:
425 if test.endswith('.test'):
426 pass
427 else:
428 test = test+'.test'
429 if test in testlist:
430 tests_to_use.append(test)
431 testlist = tests_to_use
432
433 # TODO: Allow for regex?
434 # Apply do-test filter
435 if self.dotest:
436 testlist = [test_file for test_file in testlist if test_file.startswith(self.dotest)]
437 # Apply skip-test filter
438 if self.skiptest:
439 testlist = [test_file for test_file in testlist if not test_file.startswith(self.skiptest)]
440 return testlist
441
442 def find_result_path(self, result_dir, result_file_name):
443 """ This is copied from test-run.pl dtr_cases.pl
444 If we have an engine option passed in and the
445 path resultdir/engine/testname.result exists, that is
446 our .result file
447
448 Need to check if we really need this - maybe PBXT?
449
450 """
451 result_path = os.path.join(result_dir,result_file_name)
452 if self.default_engine:
453 candidate_path = os.path.join(result_dir, self.default_engine,
454 result_file_name)
455 if os.path.exists(candidate_path):
456 result_path = candidate_path
457 return result_path
458
459 def check_if_disabled(self, disabled_tests, test_name):
460 """ Scan the list of disabled tests if it exists to see
461 if the test is disabled.
462
463 """
464
465 if disabled_tests:
466 if test_name in disabled_tests:
467 self.system_manager.logging.debug("%s says - I'm disabled" %(test_name))
468 return (1, disabled_tests[test_name])
469 return (0,None)
470
471 def sort_testcases(self):
472 """ We sort our testcases according to the server_options they have
473 For each testcase, we sort the list of options, so if a test has
474 --plugin-add=csv --abracadabra, we would get
475 --abracadabra --plugin-add=csv
476
477 This results in tests that have similar options being run in order
478 this minimizes server restarts which can be costly
479
480 """
481 test_management.testManager.sort_testcases(self)
482 organizer = {}
483 ordered_list = []
484 for testcase in self.test_list:
485 key = " ".join(sorted(testcase.server_options))
486 if key in organizer:
487 organizer[key].append(testcase)
488 else:
489 organizer[key] = [testcase]
490 for value_list in organizer.values():
491 ordered_list = ordered_list + value_list
492 self.test_list = ordered_list
493
494
495
4960
=== removed directory 'dbqp/lib/modes/native'
=== removed file 'dbqp/lib/modes/native/__init__.py'
=== removed file 'dbqp/lib/modes/native/native_test_execution.py'
--- dbqp/lib/modes/native/native_test_execution.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/modes/native/native_test_execution.py 1970-01-01 00:00:00 +0000
@@ -1,100 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2011 Patrick Crews
6#
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
22""" native_test_execution:
23 code related to the execution of native test cases
24
25 We are provided access to a testManager with
26 native-specific testCases.
27
28"""
29
30# imports
31import os
32import re
33import imp
34import sys
35import subprocess
36import unittest
37
38import lib.test_mgmt.test_execution as test_execution
39
40class testExecutor(test_execution.testExecutor):
41 """ native-mode-specific executor """
42
43 def execute_testCase (self):
44 """ Execute a test module testCase
45
46 """
47 test_execution.testExecutor.execute_testCase(self)
48 self.status = 0
49
50 # execute test module
51 self.current_test_status = self.execute_test_module()
52
53 # analyze results
54 self.set_server_status(self.current_test_status)
55 self.server_manager.reset_servers(self.name)
56
57
58 def execute_test_module(self):
59 """ Execute the commandline and return the result.
60 We use subprocess as we can pass os.environ dicts and whatnot
61
62 """
63 output_file_path = os.path.join(self.logdir,'native.out')
64 output_file = open(output_file_path,'w')
65 testcase_name = self.current_testcase.fullname
66 test_name = self.current_testcase.name
67
68 # import our module and pass it some goodies to play with
69 test_module = imp.load_source(test_name, self.current_testcase.test_path)
70 test_module.servers = self.current_servers
71 test_module.test_executor = self
72 test_module.server_manager = self.server_manager
73
74 # start our test
75 self.time_manager.start(testcase_name,'test')
76 self.logging.subunit_start(testcase_name)
77 suite = unittest.TestLoader().loadTestsFromTestCase(test_module.basicTest)
78 test_result = unittest.TextTestRunner(stream=output_file, verbosity=2).run(suite)
79 execution_time = int(self.time_manager.stop(testcase_name)*1000) # millisec
80 self.current_test_retcode = test_result.wasSuccessful()
81 output_file.close()
82 output_file = open(output_file_path,'r')
83 self.current_test_output = ''.join(output_file.readlines())
84 output_file.close()
85
86 self.current_test_exec_time = execution_time
87 retval = None
88 if self.current_test_retcode:
89 if not self.verbose:
90 self.current_test_output = None
91 retval = 'pass'
92 else:
93 retval = 'fail'
94 self.logging.subunit_stop( testcase_name
95 , retval
96 , self.current_test_output
97 )
98 return retval
99
100
1010
=== removed file 'dbqp/lib/modes/native/native_test_management.py'
--- dbqp/lib/modes/native/native_test_management.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/modes/native/native_test_management.py 1970-01-01 00:00:00 +0000
@@ -1,160 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2011 Patrick Crews
6#
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
20
21""" crashme_test_management:
22 code related to the gathering / analysis / management of
23 the test cases
24 ie - collecting the list of tests in each suite, then
25 gathering additional, relevant information for crashme mode
26
27"""
28
29# imports
30import os
31import re
32import sys
33import imp
34
35import lib.test_mgmt.test_management as test_management
36
37
38
39class testCase:
40 """Holds info on a single crashme test
41
42 """
43 def __init__( self
44 , system_manager
45 , name=None
46 , fullname = None
47 , server_requirements=[[]]
48 , comment=None
49 , cnf_path=None
50 , request_dict=None
51 , test_path = None
52 , suitename = 'native_tests'
53 , debug=False ):
54 self.system_manager = system_manager
55 self.logging = self.system_manager.logging
56 self.skip_keys = ['system_manager','logging']
57 self.name = name
58 self.fullname = fullname
59 self.suitename = suitename
60 self.master_sh = None
61 self.comment = comment
62 self.server_requirements = server_requirements
63 self.cnf_path = cnf_path
64 self.server_requests = request_dict
65 self.test_path = test_path
66 if debug:
67 self.system_manager.logging.debug_class(self)
68
69 def should_run(self):
70 if self.skip_flag or self.disable:
71 return 0
72 else:
73 return 1
74
75
76
77
78
79class testManager(test_management.testManager):
80 """Deals with scanning test directories, gathering test cases, and
81 collecting per-test information (opt files, etc) for use by the
82 test-runner
83
84 """
85
86 def __init__( self, variables, system_manager):
87 super(testManager, self).__init__( variables, system_manager)
88 server_type = variables['defaultservertype']
89 if server_type == 'mysql' or server_type =='galera':
90 server_type = 'percona'
91 self.suitepaths = [os.path.join(self.testdir,'%s_tests' %(server_type))]
92 if variables['suitelist'] is None:
93 self.suitelist = ['main']
94 else:
95 self.suitelist = variables['suitelist']
96
97 def process_suite(self,suite_dir):
98 """Process a test suite.
99 Look for tests, which are nice clean python unittest files
100
101 """
102
103 # We know this based on how we organize native test conf files
104 suite_name = os.path.basename(suite_dir)
105 self.system_manager.logging.verbose("Processing suite: %s" %(suite_name))
106 testlist = [os.path.join(suite_dir,test_file) for test_file in sorted(os.listdir(suite_dir)) if test_file.endswith('_test.py')]
107
108 # Search for specific test names
109 if self.desired_tests: # We have specific, named tests we want from the suite(s)
110 tests_to_use = []
111 for test in self.desired_tests:
112 if test.endswith('.py'):
113 pass
114 else:
115 test = test+'.py'
116 test = os.path.join(suite_dir,test)
117 if test in testlist:
118 tests_to_use.append(test)
119 testlist = tests_to_use
120 for test_case in testlist:
121 self.add_test(self.process_test_file(suite_name, test_case))
122
123
124 def process_test_file(self, suite_name, testfile):
125 """ We convert the info in a testfile into a testCase object """
126
127 # test_name = filename - .py...simpler
128 test_name = os.path.basename(testfile).replace('.py','')
129 test_comment = None
130 test_module = imp.load_source(test_name, testfile)
131 server_requirements = test_module.server_requirements
132 try:
133 server_requests = test_module.server_requests
134 except AttributeError, NameError:
135 server_requests = None
136 return testCase( self.system_manager
137 , name = test_name
138 , fullname = "%s.%s" %(suite_name, test_name)
139 , server_requirements = server_requirements
140 , cnf_path = None
141 , request_dict = server_requests
142 , test_path = testfile
143 , debug = self.debug )
144
145
146
147 def record_test_result(self, test_case, test_status, output, exec_time):
148 """ Accept the results of an executed testCase for further
149 processing.
150
151 """
152 if test_status not in self.executed_tests:
153 self.executed_tests[test_status] = [test_case]
154 else:
155 self.executed_tests[test_status].append(test_case)
156 # report
157 self.logging.test_report( test_case.fullname, test_status
158 , str(exec_time), output
159 , report_output= True)
160
1610
=== removed directory 'dbqp/lib/modes/sysbench'
=== removed file 'dbqp/lib/modes/sysbench/__init__.py'
=== removed file 'dbqp/lib/modes/sysbench/sysbench_test_execution.py'
--- dbqp/lib/modes/sysbench/sysbench_test_execution.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/modes/sysbench/sysbench_test_execution.py 1970-01-01 00:00:00 +0000
@@ -1,162 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010 Patrick Crews
6#
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
22""" sysbench_test_execution:
23 code related to the execution of sysbench test cases
24
25 We are provided access to a testManager with
26 sysbench-specific testCases.
27
28"""
29
30# imports
31import os
32import re
33import sys
34import subprocess
35import commands
36
37import lib.test_mgmt.test_execution as test_execution
38
39class testExecutor(test_execution.testExecutor):
40 """ sysbench-specific testExecutor
41
42 """
43
44 def execute_testCase (self):
45 """ Execute a sysbench testCase
46
47 """
48 test_execution.testExecutor.execute_testCase(self)
49 self.status = 0
50
51 # prepare the server for sysbench
52 self.prepare_sysbench()
53
54 # execute sysbench
55 self.execute_sysbench()
56
57 # analyze results
58 self.current_test_status = self.process_sysbench_output()
59 self.set_server_status(self.current_test_status)
60 self.server_manager.reset_servers(self.name)
61
62 def prepare_sysbench(self):
63 """ Prepare the server for a sysbench run
64 We use subprocess as we can pass os.environ dicts and whatnot
65
66 """
67
68 sysbench_outfile = os.path.join(self.logdir,'sysbench.out')
69 sysbench_output = open(sysbench_outfile,'w')
70 sysbench_cmd = ' '.join([self.current_testcase.test_command,'prepare'])
71 self.logging.info("Preparing database for sysbench run...")
72 self.logging.debug(sysbench_cmd)
73 sysbench_subproc = subprocess.Popen( sysbench_cmd
74 , shell=True
75 #, cwd=os.getcwd()
76 , env=self.working_environment
77 , stdout = sysbench_output
78 , stderr = subprocess.STDOUT
79 )
80 sysbench_subproc.wait()
81 retcode = sysbench_subproc.returncode
82
83 sysbench_output.close()
84 sysbench_file = open(sysbench_outfile,'r')
85 output = ''.join(sysbench_file.readlines())
86 sysbench_file.close()
87 self.logging.debug("sysbench_retcode: %d" %(retcode))
88 self.logging.debug(output)
89 if retcode:
90 self.logging.error("sysbench_prepare failed with retcode %d:" %(retcode))
91 self.logging.error(output)
92 sys.exit(1)
93
94
95
96
97 def execute_sysbench(self):
98 """ Execute the commandline and return the result.
99 We use subprocess as we can pass os.environ dicts and whatnot
100
101 """
102
103 testcase_name = self.current_testcase.fullname
104 self.time_manager.start(testcase_name,'test')
105 sysbench_outfile = os.path.join(self.logdir,'sysbench.out')
106 sysbench_output = open(sysbench_outfile,'w')
107 sysbench_cmd = ' '.join([self.current_testcase.test_command, 'run'])
108 self.logging.info("Executing sysbench: %s" %(sysbench_cmd))
109
110 sysbench_subproc = subprocess.Popen( sysbench_cmd
111 , shell=True
112 #, cwd=self.system_manager.sysbench_path
113 , env=self.working_environment
114 , stdout = sysbench_output
115 , stderr = subprocess.STDOUT
116 )
117 sysbench_subproc.wait()
118 retcode = sysbench_subproc.returncode
119 execution_time = int(self.time_manager.stop(testcase_name)*1000) # millisec
120
121 sysbench_output.close()
122 sysbench_file = open(sysbench_outfile,'r')
123 output = ''.join(sysbench_file.readlines())
124 self.logging.debug(output)
125 sysbench_file.close()
126
127 self.logging.debug("sysbench_retcode: %d" %(retcode))
128 self.current_test_retcode = retcode
129 self.current_test_output = output
130 self.current_test_exec_time = execution_time
131
132 def process_sysbench_output(self):
133 """ sysbench has run, we now check out what we have
134 We also output the data from the run
135
136 """
137 # This slice code taken from drizzle-automation's sysbench handling
138 # Slice up the output report into a matrix and insert into the DB.
139 regexes= {
140 'tps': re.compile(r".*transactions\:\s+\d+\D*(\d+\.\d+).*")
141 , 'deadlocksps': re.compile(r".*deadlocks\:\s+\d+\D*(\d+\.\d+).*")
142 , 'rwreqps': re.compile(r".*read\/write\s+requests\:\s+\d+\D*(\d+\.\d+).*")
143 , 'min_req_lat_ms': re.compile(r".*min\:\s+(\d*\.\d+)ms.*")
144 , 'max_req_lat_ms': re.compile(r".*max\:\s+(\d*\.\d+)ms.*")
145 , 'avg_req_lat_ms': re.compile(r".*avg\:\s+(\d*\.\d+)ms.*")
146 , '95p_req_lat_ms': re.compile(r".*approx.\s+95\s+percentile\:\s+(\d+\.\d+)ms.*")
147 }
148 run= {}
149 for line in self.current_test_output.split("\n"):
150 for key in regexes.keys():
151 result= regexes[key].match(line)
152 if result:
153 run[key]= float(result.group(1)) # group(0) is entire match...
154 # we set our test output to the regex'd-up data
155 # we also make it a single string, separated by newlines
156 self.current_test_output = str(run)[1:-1].replace(',','\n').replace("'",'')
157
158 if self.current_test_retcode == 0:
159 return 'pass'
160 else:
161 return 'fail'
162
1630
=== removed file 'dbqp/lib/modes/sysbench/sysbench_test_management.py'
--- dbqp/lib/modes/sysbench/sysbench_test_management.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/modes/sysbench/sysbench_test_management.py 1970-01-01 00:00:00 +0000
@@ -1,159 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010 Patrick Crews
6#
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
20
21""" sysbench_test_management:
22 code related to the gathering / analysis / management of
23 the test cases
24 ie - collecting the list of tests in each suite, then
25 gathering additional, relevant information for sysbench mode
26
27"""
28
29# imports
30import os
31import re
32import sys
33from ConfigParser import RawConfigParser
34
35import lib.test_mgmt.test_management as test_management
36
37
38
39class testCase:
40 """Holds info on a single sysbench test
41
42 """
43 def __init__( self, system_manager, name=None
44 , fullname = None, server_requirements=[[]]
45 , comment=None, test_command=None, cnf_path=None
46 , debug=False ):
47 self.system_manager = system_manager
48 self.logging = self.system_manager.logging
49 self.skip_keys = ['system_manager','logging']
50 self.name = name
51 self.fullname = fullname
52 self.suitename = 'sysbench_tests'
53 self.master_sh = None
54 self.comment = comment
55 self.server_requirements = server_requirements
56 self.test_command = test_command
57 self.cnf_path = cnf_path
58
59 if debug:
60 self.system_manager.logging.debug_class(self)
61
62 def should_run(self):
63 if self.skip_flag or self.disable:
64 return 0
65 else:
66 return 1
67
68
69
70
71
72class testManager(test_management.testManager):
73 """Deals with scanning test directories, gathering test cases, and
74 collecting per-test information (opt files, etc) for use by the
75 test-runner
76
77 """
78
79 def __init__( self, variables, system_manager):
80 super(testManager, self).__init__( variables, system_manager)
81 self.suitepaths = [os.path.join(self.testdir,'sysbench_tests')]
82 if variables['suitelist'] is None:
83 self.suitelist = ['readonly']
84 else:
85 self.suitelist = variables['suitelist']
86
87 def process_suite(self,suite_dir):
88 """Process a test suite.
89 Look for sysbench tests, which are nice clean conf files
90
91 """
92
93 # We know this based on how we organize sysbench test conf files
94 suite_name = os.path.basename(suite_dir)
95 self.system_manager.logging.verbose("Processing suite: %s" %(suite_name))
96 testlist = [os.path.join(suite_dir,test_file) for test_file in sorted(os.listdir(suite_dir)) if test_file.endswith('.cnf')]
97
98 # Search for specific test names
99 if self.desired_tests: # We have specific, named tests we want from the suite(s)
100 tests_to_use = []
101 for test in self.desired_tests:
102 if test.endswith('.cnf'):
103 pass
104 else:
105 test = test+'.cnf'
106 test = os.path.join(suite_dir,test)
107 if test in testlist:
108 tests_to_use.append(test)
109 testlist = tests_to_use
110 for test_case in testlist:
111 self.add_test(self.process_test_file(suite_name, test_case))
112
113
114 def process_test_file(self, suite_name, testfile):
115 """ We convert the info in a testfile into a testCase object """
116
117 config_reader = RawConfigParser()
118 config_reader.read(testfile)
119 # test_name = filename - .cnf...simpler
120 test_name = os.path.basename(testfile).replace('.cnf','')
121 test_comment = config_reader.get('test_info','comment')
122 server_requirements = self.process_server_reqs(config_reader.get('test_servers','servers'))
123 test_command = config_reader.get('test_command','command')
124 return testCase( self.system_manager
125 , name = test_name
126 , fullname = "%s.%s" %(suite_name, test_name)
127 , server_requirements = server_requirements
128 , test_command = test_command
129 , cnf_path = testfile
130 , debug = self.debug )
131
132 #sys.exit(0)
133
134 def process_server_reqs(self,data_string):
135 """ We read in the list of lists as a string, so we need to
136 handle this / break it down into proper chunks
137
138 """
139 server_reqs = []
140 # We expect to see a list of lists and throw away the
141 # enclosing brackets
142 option_sets = data_string[1:-1].strip().split(',')
143 for option_set in option_sets:
144 server_reqs.append([option_set[1:-1].strip()])
145 return server_reqs
146
147 def record_test_result(self, test_case, test_status, output, exec_time):
148 """ Accept the results of an executed testCase for further
149 processing.
150
151 """
152 if test_status not in self.executed_tests:
153 self.executed_tests[test_status] = [test_case]
154 else:
155 self.executed_tests[test_status].append(test_case)
156 # report
157 self.logging.test_report( test_case.fullname, test_status
158 , str(exec_time), output
159 , report_output= True)
1600
=== removed file 'dbqp/lib/modes/test_mode.py'
--- dbqp/lib/modes/test_mode.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/modes/test_mode.py 1970-01-01 00:00:00 +0000
@@ -1,68 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010 Patrick Crews
6#
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
20
21"""test_mode.py
22 code for dealing with testing modes
23 A given mode should have a systemInitializer, testManager, and testExecutor
24 that define how to setup, manage, and execute test cases
25
26"""
27
28# imports
29import sys
30
31def handle_mode(variables, system_manager):
32 """ Deals with the 'mode' option and returns
33 the appropriate code objects for the test-runner to play with
34
35 """
36
37 test_mode = variables['mode'].strip()
38 system_manager.logging.info("Using testing mode: %s" %test_mode)
39
40 if test_mode == 'cleanup':
41 # cleanup mode - we try to kill any servers whose pid's we detect
42 # in our workdir. Might extend to other things (file cleanup, etc)
43 # at some later point
44 system_manager.cleanup(exit=True)
45
46 else: # we expect something from dbqp_modes
47 supported_modes = [ 'dtr'
48 , 'randgen'
49 , 'sysbench'
50 , 'sqlbench'
51 , 'crashme'
52 , 'native'
53 ]
54 if test_mode not in supported_modes:
55 system_manager.logging.error("invalid mode argument: %s" %test_mode)
56 sys.exit(1)
57
58 mgmt_module = "lib.modes.%s.%s_test_management" %(test_mode, test_mode)
59 tmp = __import__(mgmt_module, globals(), locals(), ['testManager'], -1)
60 testManager = tmp.testManager
61
62 exec_module = "%s.%s_test_execution" %(test_mode, test_mode)
63 tmp = __import__(exec_module, globals(), locals(), ['testExecutor'], -1)
64 testExecutor = tmp.testExecutor
65
66 test_manager = testManager( variables, system_manager )
67 return (test_manager, testExecutor)
68
690
=== removed directory 'dbqp/lib/opts'
=== removed file 'dbqp/lib/opts/__init__.py'
=== removed file 'dbqp/lib/opts/test_run_options.py'
--- dbqp/lib/opts/test_run_options.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/opts/test_run_options.py 1970-01-01 00:00:00 +0000
@@ -1,556 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010, 2011 Patrick Crews
6#
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
20
21
22
23"""Processes command line options for Drizzle test-runner"""
24
25import os
26import sys
27import copy
28import exceptions
29import optparse
30
31# functions
32def comma_list_split(option, opt, value, parser):
33 """Callback for splitting input expected in list form"""
34 cur_list = getattr(parser.values, option.dest,[])
35 input_list = value.split(',')
36 # this is a hack to work with make target - we
37 # don't deal with a dangling ',' in our list
38 if '' in input_list:
39 input_list.remove('')
40 if cur_list:
41 value_list = cur_list + input_list
42 else:
43 value_list = input_list
44 setattr(parser.values, option.dest, value_list)
45
46def 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
54def 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
58 ['
59 """
60 variables = {}
61 # we make a copy as the python manual on vars
62 # says we shouldn't alter the dictionary returned
63 # by vars() - could affect symbol table?
64 variables = copy.copy(vars(args))
65 variables['test_cases']= test_cases
66 # This code should become a function once
67 # enough thought has been given to it
68 if variables['manualgdb']:
69 variables['gdb']=True
70 if variables['repeat'] <= 0:
71 print "Setting --repeat=1. You chose a silly value that I will ignore :P"
72 variables['repeat'] = 1
73 if variables['mode'] == 'randgen' or variables['gendatafile']:
74 print "Setting --no-secure-file-priv=True for randgen usage..."
75 variables['nosecurefilepriv']=True
76 if variables['mode'] == 'cleanup':
77 print "Setting --start-dirty=True for cleanup mode..."
78 variables['startdirty']=True
79 if variables['libeatmydata'] and os.path.exists(variables['libeatmydatapath']):
80 # We are using libeatmydata vs. shared mem for server speedup
81 print "Using libeatmydata at %s. Setting --no-shm / not using shared memory for testing..." %(variables['libeatmydatapath'])
82 variables['noshm']=True
83 return variables
84
85def 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
97def 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].split(':type:')[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
123# Create the CLI option parser
124parser= optparse.OptionParser(version='%prog (database quality platform aka project steve austin) version 0.1.1')
125
126# set some default values
127testdir_default = os.path.abspath(os.getcwd())
128workdir_default = os.path.join(testdir_default,'workdir')
129clientbindir_default = os.path.abspath(os.path.join(testdir_default,'../client'))
130basedir_default = os.path.dirname(testdir_default)
131server_type_default = 'galera'
132valgrind_suppression_default = os.path.join(testdir_default,'valgrind.supp')
133suitepaths_default = [ os.path.join(basedir_default,'plugin')
134 , os.path.join(testdir_default,'suite')
135 ]
136randgen_path_default = os.path.join(testdir_default,'randgen')
137subunit_file_default = os.path.join(workdir_default,'test_results.subunit')
138
139
140config_control_group = optparse.OptionGroup(parser,
141 "Configuration controls - allows you to specify a file with a number of options already specified")
142config_control_group.add_option(
143 "--sys_config_file"
144 , dest="sysconfigfilepath"
145 , action='store'
146 , default=None # We want to have a file that will be our default defaults file...
147 , help="The file that specifies system configuration specs for dbqp to execute tests (not yet implemented)"
148 )
149parser.add_option_group(config_control_group)
150
151
152system_control_group = optparse.OptionGroup(parser,
153 "Options for the test-runner itself - defining the system under test and how to execute tests")
154
155system_control_group.add_option(
156 "--force"
157 , dest="force"
158 , action="store_true"
159 , default=False
160 , help="Set this to continue test execution beyond the first failed test"
161 )
162
163system_control_group.add_option(
164 "--start-and-exit"
165 , dest="startandexit"
166 , action="store_true"
167 , default=False
168 , help="Spin up the server(s) for the first specified test then exit (will leave servers running)"
169 )
170
171system_control_group.add_option(
172 "--verbose"
173 , dest="verbose"
174 , action="store_true"
175 , default = False
176 , help="Produces extensive output about test-runner state. Distinct from --debug"
177 )
178
179system_control_group.add_option(
180 "--debug"
181 , dest="debug"
182 , action="store_true"
183 , default = False
184 , help="Provide internal-level debugging output. Distinct from --verbose"
185 )
186
187system_control_group.add_option(
188 "--mode"
189 , dest="mode"
190 , default="native"
191 , help="Testing mode. We currently support dtr, randgen, sysbench, sqlbench, crashme and cleanup modes. See docs for further details about individual modes [%default]"
192 )
193
194system_control_group.add_option(
195 "--record"
196 , dest="record"
197 , action="store_true"
198 , default=False
199 , help="Record a testcase result (if the testing mode supports it) [%default]"
200 )
201
202system_control_group.add_option(
203 "--fast"
204 , dest="fast"
205 , action="store_true"
206 , default=False
207 , help="Don't try to cleanup from earlier runs (currently just a placeholder) [%default]"
208 )
209
210parser.add_option_group(system_control_group)
211
212test_control_group = optparse.OptionGroup(parser,
213 "Options for controlling which tests are executed")
214
215test_control_group.add_option(
216 "--suite"
217 , dest="suitelist"
218 , type='string'
219 , action="callback"
220 , callback=comma_list_split
221 , 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]"
222 )
223
224test_control_group.add_option(
225 "--suitepath"
226 , dest="suitepaths"
227 , type='string'
228 , action="append"
229 , default = suitepaths_default
230 , help="The path containing the suite(s) you wish to execute. Use one --suitepath for each suite you want to use. [%default]"
231 )
232
233test_control_group.add_option(
234 "--do-test"
235 , dest="dotest"
236 , type='string'
237 , default = None
238 , help="input can either be a prefix or a regex. Will only execute tests that match the provided pattern"
239 )
240
241test_control_group.add_option(
242 "--skip-test"
243 , dest="skiptest"
244 , type='string'
245 , default = None
246 , help = "input can either be a prefix or a regex. Will exclude tests that match the provided pattern"
247 )
248
249test_control_group.add_option(
250 "--reorder"
251 , dest="reorder"
252 , action="store_true"
253 , default=False
254 , help = "sort the testcases so that they are executed optimally for the given mode [%default]"
255 )
256
257test_control_group.add_option(
258 "--repeat"
259 , dest="repeat"
260 , type='int'
261 , action="store"
262 , default=1
263 , 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]"
264 )
265
266parser.add_option_group(test_control_group)
267
268# test subject control group
269# terrible name for options tht define the server / code
270# that is under test
271
272# find some default values
273# assume we are in-tree testing in general and operating from root/test(?)
274testdir_default = os.path.abspath(os.getcwd())
275
276basedir_default = os.path.split(testdir_default)[0]
277
278test_subject_control_group = optparse.OptionGroup(parser,
279 "Options for defining the code that will be under test")
280
281test_subject_control_group.add_option(
282 "--basedir"
283 , dest="basedir"
284 , type='string'
285 , default = []
286 , action="append"
287 , 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]"
288 )
289
290test_subject_control_group.add_option(
291 "--default-server-type"
292 , dest="defaultservertype"
293 , type='string'
294 , default = server_type_default
295 , action='store'
296 , help = "Defines what we consider to be the default server type. We assume a server is default type unless specified otherwise. [%default]"
297 )
298
299test_subject_control_group.add_option(
300 "--serverdir"
301 , dest="serverpath"
302 , type='string'
303 , action="callback"
304 , callback=get_abspath
305 , help = "Path to the server executable. [%default]"
306 )
307
308test_subject_control_group.add_option(
309 "--client-bindir"
310 , dest="clientbindir"
311 , type = 'string'
312 , action="callback"
313 , callback=get_abspath
314 , help = "Path to the directory containing client program binaries for use in testing [%default]"
315 )
316
317
318test_subject_control_group.add_option(
319 "--default-storage-engine"
320 , dest="defaultengine"
321 , default = 'innodb'
322 , help="Start drizzled using the specified engine [%default]"
323 )
324
325
326parser.add_option_group(test_subject_control_group)
327# end test subject control group
328
329# environment options
330
331environment_control_group = optparse.OptionGroup(parser,
332 "Options for defining the testing environment")
333
334environment_control_group.add_option(
335 "--testdir"
336 , dest="testdir"
337 , type = 'string'
338 , default = testdir_default
339 , action="callback"
340 , callback=get_abspath
341 , help = "Path to the test dir, containing additional files for test execution. [%default]"
342 )
343
344environment_control_group.add_option(
345 "--workdir"
346 , dest="workdir"
347 , type='string'
348 , default = workdir_default
349 , action="callback"
350 , callback=get_abspath
351 , help = "Path to the directory test-run will use to store generated files and directories. [%default]"
352 )
353
354environment_control_group.add_option(
355 "--top-srcdir"
356 , dest="topsrcdir"
357 , type='string'
358 , default = basedir_default
359 , help = "build option [%default]"
360 )
361
362environment_control_group.add_option(
363 "--top-builddir"
364 , dest="topbuilddir"
365 , type='string'
366 , default = basedir_default
367 , help = "build option [%default]"
368 )
369
370environment_control_group.add_option(
371 "--no-shm"
372 , dest="noshm"
373 , action='store_true'
374 , default=False
375 , help = "By default, we symlink workdir to a location in shm. Use this flag to not symlink [%default]"
376 )
377
378environment_control_group.add_option(
379 "--libeatmydata"
380 , dest="libeatmydata"
381 , action='store_true'
382 , default=False
383 , help = "We use libeatmydata (if available) to disable fsyncs and speed up test execution. Implies --no-shm"
384 )
385
386environment_control_group.add_option(
387 "--libeatmydata-path"
388 , dest="libeatmydatapath"
389 , action='store'
390 , default='/usr/local/lib/libeatmydata.so'
391 , help = "Path to the libeatmydata install you want to use [%default]"
392 )
393
394environment_control_group.add_option(
395 "--start-dirty"
396 , dest="startdirty"
397 , action='store_true'
398 , default=False
399 , help = "Don't try to clean up working directories before test execution [%default]"
400 )
401
402environment_control_group.add_option(
403 "--no-secure-file-priv"
404 , dest = "nosecurefilepriv"
405 , action='store_true'
406 , default=False
407 , help = "Turn off the use of --secure-file-priv=vardir for started servers"
408 )
409
410environment_control_group.add_option(
411 "--randgen-path"
412 , dest="randgenpath"
413 , action='store'
414 , default=randgen_path_default
415 , help = "The path to a randgen installation that can be used to execute randgen-based tests"
416 )
417
418environment_control_group.add_option(
419 "--innobackupex-path"
420 , dest="innobackupexpath"
421 , action='store'
422 , default=None
423 , help = "The path to the innobackupex script that facilitates the use of Xtrabackup"
424 )
425
426environment_control_group.add_option(
427 "--xtrabackup-path"
428 , dest="xtrabackuppath"
429 , action='store'
430 , default=None
431 , help = "The path the xtrabackup binary to be tested"
432 )
433
434environment_control_group.add_option(
435 "--wsrep-provider-path"
436 , dest="wsrepprovider"
437 , action='store'
438 , default='/usr/lib/galera/libgalera_smm.so'
439 , help = "The path to a wsrep provider library for use with mysql"
440 )
441
442environment_control_group.add_option(
443 "--cluster-cnf"
444 , dest="clustercnf"
445 , action='store'
446 , default=None
447 , help = "The path to a config file defining a running cluster (node info)"
448 )
449
450environment_control_group.add_option(
451 "--subunit-outfile"
452 , dest="subunitoutfile"
453 , action='store'
454 , default=subunit_file_default
455 , help = "File path where subunit output will be logged [%default]"
456 )
457
458parser.add_option_group(environment_control_group)
459# end environment control group
460
461option_passing_group = optparse.OptionGroup(parser,
462 "Options to pass options on to the server")
463
464option_passing_group.add_option(
465"--drizzled"
466 , dest="drizzledoptions"
467 , type='string'
468 , action='append'
469 , default = []
470 , help = "Pass additional options to the server. Will be passed to all servers for all tests (mostly for --start-and-exit)"
471 )
472
473parser.add_option_group(option_passing_group)
474# end option passing group
475
476analysis_control_group = optparse.OptionGroup(parser,
477 "Options for defining the tools we use for code analysis (valgrind, gprof, gcov, etc)")
478
479analysis_control_group.add_option(
480 "--valgrind"
481 , dest="valgrind"
482 , action='store_true'
483 , default = False
484 , help = "Run drizzletest and drizzled executables using valgrind with default options [%default]"
485 )
486
487analysis_control_group.add_option(
488 "--valgrind-option"
489 , dest="valgrindarglist"
490 , type='string'
491 , action="append"
492 , help = "Pass an option to valgrind (overrides/removes default valgrind options)"
493 )
494
495analysis_control_group.add_option(
496 "--valgrind-suppressions"
497 , dest="valgrindsuppressions"
498 , type='string'
499 , action='store'
500 , default = valgrind_suppression_default
501 , help = "Point at a valgrind suppression file [%default]"
502 )
503
504analysis_control_group.add_option(
505 "--helgrind"
506 , dest="helgrind"
507 , action='store_true'
508 , default=False
509 , help="Use the helgrind tool for valgrind. Implies / will auto-use --valgrind"
510 )
511
512parser.add_option_group(analysis_control_group)
513
514debugger_control_group = optparse.OptionGroup(parser,
515 "Options for controlling the use of debuggers with test execution")
516
517debugger_control_group.add_option(
518 "--gdb"
519 , dest="gdb"
520 , action='store_true'
521 , default=False
522 , help="Start the drizzled server(s) in gdb"
523 )
524
525debugger_control_group.add_option(
526 "--manual-gdb"
527 , dest="manualgdb"
528 , action='store_true'
529 , default=False
530 , help="Allows you to start the drizzled server(s) in gdb manually (in another window, etc)"
531 )
532
533parser.add_option_group(debugger_control_group)
534
535utility_group = optparse.OptionGroup(parser,
536 "Options to call additional utilities such as datagen")
537
538utility_group.add_option(
539 "--gendata"
540 , dest="gendatafile"
541 , action='store'
542 , type='string'
543 , default=None
544 , help="Call the randgen's gendata utility to use the specified configuration file. This will populate the server prior to any test execution")
545
546parser.add_option_group(utility_group)
547
548# supplied will be those arguments matching an option,
549# and test_cases will be everything else
550(args, test_cases)= parser.parse_args()
551
552variables = {}
553variables = organize_options(args, test_cases)
554variables = populate_defaults(variables, basedir_default)
555variables = handle_user_opts(variables, basedir_default, testdir_default, suitepaths_default)
556
5570
=== removed directory 'dbqp/lib/server_mgmt'
=== removed file 'dbqp/lib/server_mgmt/__init__.py'
=== removed file 'dbqp/lib/server_mgmt/drizzled.py'
--- dbqp/lib/server_mgmt/drizzled.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/server_mgmt/drizzled.py 1970-01-01 00:00:00 +0000
@@ -1,227 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010,2011 Patrick Crews
6#
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
20
21
22""" drizzled.py: code to allow a serverManager
23 to provision and start up a drizzled server object
24 for test execution
25
26"""
27
28# imports
29import os
30from lib.server_mgmt.server import Server
31
32class drizzleServer(Server):
33 """ represents a drizzle server, its possessions
34 (datadir, ports, etc), and methods for controlling
35 and querying it
36
37 TODO: create a base server class that contains
38 standard methods from which we can inherit
39 Currently there are definitely methods / attr
40 which are general
41
42 """
43
44 def __init__( self, name, server_manager, code_tree, default_storage_engine
45 , server_options, requester, workdir_root):
46 super(drizzleServer, self).__init__( name
47 , server_manager
48 , code_tree
49 , default_storage_engine
50 , server_options
51 , requester
52 , workdir_root)
53 self.preferred_base_port = 9306
54
55 # client files
56 self.drizzledump = self.code_tree.drizzledump
57 self.drizzle_client = self.code_tree.drizzle_client
58 self.drizzleimport = self.code_tree.drizzleimport
59 self.drizzleslap = self.code_tree.drizzleslap
60 self.server_path = self.code_tree.drizzle_server
61 self.drizzle_client_path = self.code_tree.drizzle_client
62 self.schemawriter = self.code_tree.schemawriter
63 self.trx_reader = self.code_tree.trx_reader
64
65 # Get our ports
66 self.port_block = self.system_manager.port_manager.get_port_block( self.name
67 , self.preferred_base_port
68 , 6 )
69 self.master_port = self.port_block[0]
70 self.drizzle_tcp_port = self.port_block[1]
71 self.mc_port = self.port_block[2]
72 self.pbms_port = self.port_block[3]
73 self.rabbitmq_node_port = self.port_block[4]
74 self.json_server_port = self.port_block[5]
75
76 # Generate our working directories
77 self.dirset = {'var_%s' %(self.name): {'std_data_ln':( os.path.join(self.code_tree.testdir,'std_data'))
78 ,'log':None
79 ,'run':None
80 ,'tmp':None
81 ,'master-data': {'local': { 'test':None
82 , 'mysql':None
83 }
84 }
85 }
86 }
87 self.workdir = self.system_manager.create_dirset( workdir_root
88 , self.dirset)
89 self.vardir = self.workdir
90 self.tmpdir = os.path.join(self.vardir,'tmp')
91 self.rundir = os.path.join(self.vardir,'run')
92 self.logdir = os.path.join(self.vardir,'log')
93 self.datadir = os.path.join(self.vardir,'master-data')
94
95 self.error_log = os.path.join(self.logdir,('%s.err' %(self.name)))
96 self.pid_file = os.path.join(self.rundir,('%s.pid' %(self.name)))
97 self.socket_file = os.path.join(self.vardir, ('%s.sock' %(self.name)))
98 self.timer_file = os.path.join(self.logdir,('timer'))
99
100 # Do magic to create a config file for use with the slave
101 # plugin
102 self.slave_config_file = os.path.join(self.logdir,'slave.cnf')
103 self.create_slave_config_file()
104
105 self.snapshot_path = os.path.join(self.tmpdir,('snapshot_%s' %(self.master_port)))
106 # We want to use --secure-file-priv = $vardir by default
107 # but there are times / tools when we need to shut this off
108 if self.no_secure_file_priv:
109 self.secure_file_string = ''
110 else:
111 self.secure_file_string = "--secure-file-priv='%s'" %(self.vardir)
112 self.user_string = '--user=root'
113
114 self.initialize_databases()
115 self.take_db_snapshot()
116
117 self.logging.debug_class(self)
118
119 def report(self):
120 """ We print out some general useful info """
121 report_values = [ 'name'
122 , 'master_port'
123 , 'drizzle_tcp_port'
124 , 'mc_port'
125 , 'pbms_port'
126 , 'rabbitmq_node_port'
127 , 'vardir'
128 , 'status'
129 ]
130 self.logging.info("%s server:" %(self.owner))
131 for key in report_values:
132 value = vars(self)[key]
133 self.logging.info("%s: %s" %(key.upper(), value))
134
135 def get_start_cmd(self):
136 """ Return the command string that will start up the server
137 as desired / intended
138
139 """
140
141 server_args = [ self.process_server_options()
142 , "--mysql-protocol.port=%d" %(self.master_port)
143 , "--mysql-protocol.connect-timeout=60"
144 , "--innodb.data-file-path=ibdata1:20M:autoextend"
145 , "--sort-buffer-size=256K"
146 , "--max-heap-table-size=1M"
147 , "--mysql-unix-socket-protocol.path=%s" %(self.socket_file)
148 , "--pid-file=%s" %(self.pid_file)
149 , "--drizzle-protocol.port=%d" %(self.drizzle_tcp_port)
150 , "--default-storage-engine=%s" %(self.default_storage_engine)
151 , "--datadir=%s" %(self.datadir)
152 , "--tmpdir=%s" %(self.tmpdir)
153 , self.secure_file_string
154 , self.user_string
155 ]
156
157 if self.gdb:
158 server_args.append('--gdb')
159 return self.system_manager.handle_gdb_reqs(self, server_args)
160 else:
161 return "%s %s %s & " % ( self.cmd_prefix
162 , self.server_path
163 , " ".join(server_args)
164 )
165
166
167 def get_stop_cmd(self):
168 """ Return the command that will shut us down """
169
170 return "%s --user=root --port=%d --connect-timeout=5 --silent --password= --shutdown " %(self.drizzle_client_path, self.master_port)
171
172
173 def get_ping_cmd(self):
174 """Return the command string that will
175 ping / check if the server is alive
176
177 """
178
179 return "%s --ping --port=%d --user=root" % (self.drizzle_client_path, self.master_port)
180
181 def is_started(self):
182 """ Determine if the server is up and running -
183 this may vary from server type to server type
184
185 """
186
187 # We experiment with waiting for a pid file to be created vs. pinging
188 # This is what test-run.pl does and it helps us pass logging_stats tests
189 # while not self.ping_server(server, quiet=True) and timer != timeout:
190
191 return self.system_manager.find_path( [self.pid_file]
192 , required=0)
193
194 def create_slave_config_file(self):
195 """ Create a config file suitable for use
196 with the slave-plugin. This allows
197 us to tie other servers in easily
198
199 """
200
201 config_data = [ "[master1]"
202 , "master-host=127.0.0.1"
203 , "master-port=%d" %self.master_port
204 , "master-user=root"
205 , "master-pass=''"
206 , "max-reconnects=100"
207 #, "seconds-between-reconnects=20"
208 ]
209 outfile = open(self.slave_config_file,'w')
210 for line in config_data:
211 outfile.write("%s\n" %(line))
212 outfile.close()
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
2280
=== removed file 'dbqp/lib/server_mgmt/galera.py'
--- dbqp/lib/server_mgmt/galera.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/server_mgmt/galera.py 1970-01-01 00:00:00 +0000
@@ -1,334 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010,2011 Patrick Crews
6#
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
20
21
22""" mysqld.py: code to allow a serverManager
23 to provision and start up a mysqld server object
24 for test execution
25
26"""
27
28# imports
29import os
30import sys
31import time
32import subprocess
33
34from ConfigParser import RawConfigParser
35
36from lib.server_mgmt.server import Server
37
38class mysqlServer(Server):
39 """ represents a mysql server, its possessions
40 (datadir, ports, etc), and methods for controlling
41 and querying it
42
43 TODO: create a base server class that contains
44 standard methods from which we can inherit
45 Currently there are definitely methods / attr
46 which are general
47
48 """
49
50 def __init__( self, name, server_manager, code_tree, default_storage_engine
51 , server_options, requester, workdir_root):
52 super(mysqlServer, self).__init__( name
53 , server_manager
54 , code_tree
55 , default_storage_engine
56 , server_options
57 , requester
58 , workdir_root)
59 self.preferred_base_port = 9306
60
61 # client files
62 self.mysqldump = self.code_tree.mysqldump
63 self.mysqladmin = self.code_tree.mysqladmin
64 self.mysql_client = self.code_tree.mysql_client
65 self.mysqlimport = self.code_tree.mysqlimport
66 self.mysqlslap = self.code_tree.mysqlslap
67 self.mysql_upgrade = self.code_tree.mysql_upgrade
68 self.server_path = self.code_tree.mysql_server
69 self.mysql_client_path = self.code_tree.mysql_client
70
71 # galera-specific info
72 self.wsrep_cluster_addr=''
73
74 # important stuff
75 self.langdir = self.code_tree.langdir
76 self.charsetdir = self.code_tree.charsetdir
77 self.bootstrap_file = self.code_tree.bootstrap_path
78 self.bootstrap_cmd = None
79
80 # Get our ports
81 self.port_block = self.system_manager.port_manager.get_port_block( self.name
82 , self.preferred_base_port
83 , 3 )
84 self.master_port = self.port_block[0]
85 self.galera_listen_port = self.port_block[1]
86 self.galera_recv_port = self.port_block[2]
87
88 # Generate our working directories
89 self.dirset = { 'var_%s' %(self.name): {'std_data_ln':( os.path.join(self.code_tree.testdir,'std_data'))
90 ,'log':None
91 ,'run':None
92 ,'tmp':None
93 ,'master-data': { 'test':None
94 , 'mysql':None
95 }
96 }
97 }
98 self.workdir = self.system_manager.create_dirset( workdir_root
99 , self.dirset)
100 self.vardir = self.workdir
101 self.tmpdir = os.path.join(self.vardir,'tmp')
102 self.rundir = os.path.join(self.vardir,'run')
103 self.logdir = os.path.join(self.vardir,'log')
104 self.std_data = os.path.join(self.vardir,'std_data_ln')
105 self.datadir = os.path.join(self.vardir,'master-data')
106
107 self.error_log = os.path.join(self.logdir,('error.log' ))
108 self.bootstrap_log = os.path.join(self.logdir,('bootstrap.log'))
109 self.pid_file = os.path.join(self.rundir,('my.pid'))
110 self.socket_file = os.path.join(self.vardir, ('my.sock'))
111 self.timer_file = os.path.join(self.logdir,('timer'))
112 self.general_log_file = os.path.join(self.logdir,'mysqld.log')
113 self.slow_query_log_file = os.path.join(self.logdir,'mysqld-slow.log')
114 self.cnf_file = os.path.join(self.vardir,'my.cnf')
115
116 self.snapshot_path = os.path.join(self.tmpdir,('snapshot_%s' %(self.master_port)))
117 # We want to use --secure-file-priv = $vardir by default
118 # but there are times / tools when we need to shut this off
119 if self.no_secure_file_priv:
120 self.secure_file_string = ''
121 else:
122 self.secure_file_string = "--secure-file-priv='%s'" %(self.vardir)
123 self.user_string = '--user=root'
124
125 self.initialize_databases()
126 self.take_db_snapshot()
127
128 self.logging.debug_class(self)
129
130
131 def report(self):
132 """ We print out some general useful info """
133 report_values = [ 'name'
134 , 'master_port'
135 , 'galera_listen_port'
136 , 'galera_recv_port'
137 , 'socket_file'
138 , 'vardir'
139 , 'status'
140 ]
141 self.logging.info("%s server:" %(self.owner))
142 for key in report_values:
143 value = vars(self)[key]
144 self.logging.info("%s: %s" %(key.upper(), value))
145
146 def initialize_databases(self):
147 """ Do the voodoo required to have a working database setup.
148 For MySQL, this is calling the server with the
149 --bootstrap argument. We generate the bootstrap
150 file during codeTree intialization as the file is standard for
151 all MySQL servers that are spawned from a single codeTree
152
153 """
154
155 # generate the bootstrap startup command
156 if not self.bootstrap_cmd:
157 mysqld_args = [ "--no-defaults"
158 , "--bootstrap"
159 , "--basedir=%s" %(self.code_tree.basedir)
160 , "--datadir=%s" %(self.datadir)
161 , "--loose-skip-falcon"
162 , "--loose-skip-ndbcluster"
163 , "--tmpdir=%s" %(self.tmpdir)
164 , "--core-file"
165 , "--lc-messages-dir=%s" %(self.langdir)
166 , "--character-sets-dir=%s" %(self.charsetdir)
167 ]
168 # We add server_path into the mix this way as we
169 # may alter how we store / handle server args later
170 mysqld_args.insert(0,self.server_path)
171 self.bootstrap_cmd = " ".join(mysqld_args)
172 # execute our command
173 bootstrap_log = open(self.bootstrap_log,'w')
174 # open our bootstrap file
175 bootstrap_in = open(self.bootstrap_file,'r')
176 bootstrap_subproc = subprocess.Popen( self.bootstrap_cmd
177 , shell=True
178 , stdin=bootstrap_in
179 , stdout=bootstrap_log
180 , stderr=bootstrap_log
181 )
182 bootstrap_subproc.wait()
183 bootstrap_in.close()
184 bootstrap_log.close()
185 bootstrap_retcode = bootstrap_subproc.returncode
186 if bootstrap_retcode:
187 self.logging.error("Received retcode: %s executing command: %s"
188 %(bootstrap_retcode, self.bootstrap_cmd))
189 self.logging.error("Check the bootstrap log: %s" %(self.bootstrap_log))
190 sys.exit(1)
191
192
193 def get_start_cmd(self):
194 """ Return the command string that will start up the server
195 as desired / intended
196
197 """
198
199 # we need to do some wsrep voodoo for galera rpl to work
200 self.ip_address = self.system_manager.get_ip_address()
201 self.listen_addr_string = "?gmcast.listen_addr=tcp://127.0.0.1:%d" %(self.galera_listen_port)
202 # test for wsrep_provider argument
203 wsrep_provider_string =''
204 if self.system_manager.wsrep_provider_path:
205 wsrep_provider_string = "--wsrep_provider=%s" %(self.system_manager.wsrep_provider_path)
206 # handle wsrep_cluster_address argument
207 wsrep_cluster_string ="--wsrep_cluster_address='gcomm://%s%s'" %( self.wsrep_cluster_addr
208 , self.listen_addr_string)
209 for server_opt in self.server_options:
210 if server_opt.startswith("--wsrep_cluster_address="):
211 # we have a user-specified value, so we don't
212 # try to insert something
213 wsrep_cluster_string = ''
214 # check to see if they have specified a listen port
215 # we want to use our own, so we have a better idea of
216 # what is going on
217 if '?gmcast.listen_addr' in server_opt:
218 pass
219 else:
220 server_opt = server_opt.strip()+ listen_addr
221 server_args = [ self.process_server_options()
222 , "%s" %(wsrep_cluster_string)
223 , "%s" %(wsrep_provider_string)
224 , "--wsrep_debug=ON"
225 , "--wsrep_provider_options='ist.recv_addr=%s:%d'" %(self.ip_address, self.galera_recv_port)
226 , "--wsrep_sst_receive_address='127.0.0.1:%d'" %( self.master_port)
227 , "--wsrep_sst_auth='root:'"
228 , "--wsrep_node_name='node%d'" %(self.galera_listen_port)
229 , "--bind-address=0.0.0.0"
230 , "--innodb_locks_unsafe_for_binlog=1"
231 , "--open-files-limit=1024"
232 , "--query-cache-size=0"
233 , "--local-infile"
234 , "--character-set-server=latin1"
235 , "--connect-timeout=60"
236 , "--log-bin-trust-function-creators=1"
237 , "--key_buffer_size=1M"
238 , "--sort_buffer=256K"
239 , "--max_heap_table_size=1M"
240 , "--loose-innodb_data_file_path=ibdata1:10M:autoextend"
241 , "--loose-innodb_buffer_pool_size=8M"
242 , "--loose-innodb_write_io_threads=2"
243 , "--loose-innodb_read_io_threads=2"
244 , "--loose-innodb_log_buffer_size=1M"
245 , "--loose-innodb_log_file_size=5M"
246 , "--loose-innodb_additional_mem_pool_size=1M"
247 , "--loose-innodb_log_files_in_group=2"
248 , "--loose-innodb_lock_wait_timeout=9999999"
249 , "--slave-net-timeout=120"
250 , "--log-bin=%s" %(os.path.join(self.logdir,"mysqld-bin"))
251 , "--binlog-direct-non-transactional-updates"
252 , "--general_log=1"
253 , "--general_log_file=%s" %(self.general_log_file)
254 , "--slow_query_log=1"
255 , "--slow_query_log_file=%s" %(self.slow_query_log_file)
256 , "--basedir=%s" %(self.code_tree.basedir)
257 , "--datadir=%s" %(self.datadir)
258 , "--tmpdir=%s" %(self.tmpdir)
259 , "--character-sets-dir=%s" %(self.charsetdir)
260 , "--lc-messages-dir=%s" %(self.langdir)
261 , "--port=%d" %(self.master_port)
262 , "--socket=%s" %(self.socket_file)
263 , "--pid-file=%s" %(self.pid_file)
264 , "--default-storage-engine=%s" %(self.default_storage_engine)
265 # server-id maybe needs fixing, but we want to avoid
266 # the server-id=0 and no replication thing...
267 , "--server-id=%d" %(self.get_numeric_server_id()+1)
268 , self.secure_file_string
269 , self.user_string
270 ]
271 self.gen_cnf_file(server_args)
272
273 if self.gdb:
274 server_args.append('--gdb')
275 return self.system_manager.handle_gdb_reqs(self, server_args)
276 else:
277 return "%s %s %s & " % ( self.cmd_prefix
278 , self.server_path
279 , " ".join(server_args)
280 )
281
282
283 def get_stop_cmd(self):
284 """ Return the command that will shut us down """
285
286 return "%s --no-defaults --user=root --port=%d --host=127.0.0.1 --protocol=tcp shutdown " %(self.mysqladmin, self.master_port)
287
288
289 def get_ping_cmd(self):
290 """Return the command string that will
291 ping / check if the server is alive
292
293 """
294
295 return '%s --no-defaults --user=root --port=%d --host=127.0.0.1 --protocol=tcp ping' % (self.mysqladmin, self.master_port)
296
297 def is_started(self):
298 """ Determine if the server is up and running -
299 this may vary from server type to server type
300
301 """
302
303 # We experiment with waiting for a pid file to be created vs. pinging
304 # This is what test-run.pl does and it helps us pass logging_stats tests
305 # while not self.ping_server(server, quiet=True) and timer != timeout:
306
307 return self.system_manager.find_path( [self.pid_file]
308 , required=0)
309
310 def gen_cnf_file(self, server_args):
311 """ We generate a .cnf file for the server based
312 on the arguments. We currently don't use
313 this for much, but xtrabackup uses it, so
314 we must produce one. This could also be
315 helpful for testing / etc
316
317 """
318
319 config_file = open(self.cnf_file,'w')
320 config_file.write('[mysqld]')
321 for server_arg in server_args:
322 # We currently have a list of string values
323 # We need to remove any '--' stuff
324 server_arg = server_arg.replace('--','')+'\n'
325 config_file.write(server_arg)
326 config_file.close()
327
328 def set_master(self, master_server):
329 """ We update things so that we use the provided master_server
330 as our reference point for a new cluster / etc
331
332 """
333
334 self.wsrep_cluster_addr = '127.0.0.1:%d' %(master_server.galera_listen_port)
3350
=== removed file 'dbqp/lib/server_mgmt/mysqld.py'
--- dbqp/lib/server_mgmt/mysqld.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/server_mgmt/mysqld.py 1970-01-01 00:00:00 +0000
@@ -1,295 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010,2011 Patrick Crews
6#
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
20
21
22""" mysqld.py: code to allow a serverManager
23 to provision and start up a mysqld server object
24 for test execution
25
26"""
27
28# imports
29import os
30import sys
31import time
32import subprocess
33
34from ConfigParser import RawConfigParser
35
36from lib.server_mgmt.server import Server
37
38class mysqlServer(Server):
39 """ represents a mysql server, its possessions
40 (datadir, ports, etc), and methods for controlling
41 and querying it
42
43 TODO: create a base server class that contains
44 standard methods from which we can inherit
45 Currently there are definitely methods / attr
46 which are general
47
48 """
49
50 def __init__( self, name, server_manager, code_tree, default_storage_engine
51 , server_options, requester, workdir_root):
52 super(mysqlServer, self).__init__( name
53 , server_manager
54 , code_tree
55 , default_storage_engine
56 , server_options
57 , requester
58 , workdir_root)
59 self.preferred_base_port = 9306
60
61 # client files
62 self.mysqldump = self.code_tree.mysqldump
63 self.mysqladmin = self.code_tree.mysqladmin
64 self.mysql_client = self.code_tree.mysql_client
65 self.mysqlimport = self.code_tree.mysqlimport
66 self.mysqlslap = self.code_tree.mysqlslap
67 self.mysql_upgrade = self.code_tree.mysql_upgrade
68 self.server_path = self.code_tree.mysql_server
69 self.mysql_client_path = self.code_tree.mysql_client
70
71 # important stuff
72 self.langdir = self.code_tree.langdir
73 self.charsetdir = self.code_tree.charsetdir
74 self.bootstrap_file = self.code_tree.bootstrap_path
75 self.bootstrap_cmd = None
76
77 # Get our ports
78 self.port_block = self.system_manager.port_manager.get_port_block( self.name
79 , self.preferred_base_port
80 , 1 )
81 self.master_port = self.port_block[0]
82
83 # Generate our working directories
84 self.dirset = { 'var_%s' %(self.name): {'std_data_ln':( os.path.join(self.code_tree.testdir,'std_data'))
85 ,'log':None
86 ,'run':None
87 ,'tmp':None
88 ,'master-data': { 'test':None
89 , 'mysql':None
90 }
91 }
92 }
93 self.workdir = self.system_manager.create_dirset( workdir_root
94 , self.dirset)
95 self.vardir = self.workdir
96 self.tmpdir = os.path.join(self.vardir,'tmp')
97 self.rundir = os.path.join(self.vardir,'run')
98 self.logdir = os.path.join(self.vardir,'log')
99 self.std_data = os.path.join(self.vardir,'std_data_ln')
100 self.datadir = os.path.join(self.vardir,'master-data')
101
102 self.error_log = os.path.join(self.logdir,('%s.err' %(self.name)))
103 self.bootstrap_log = os.path.join(self.logdir,('bootstrap.log'))
104 self.pid_file = os.path.join(self.rundir,('%s.pid' %(self.name)))
105 self.socket_file = os.path.join(self.vardir, ('%s.sock' %(self.name)))
106 self.timer_file = os.path.join(self.logdir,('timer'))
107 self.general_log_file = os.path.join(self.logdir,'mysqld.log')
108 self.slow_query_log_file = os.path.join(self.logdir,'mysqld-slow.log')
109 self.cnf_file = os.path.join(self.vardir,'my.cnf')
110
111 self.snapshot_path = os.path.join(self.tmpdir,('snapshot_%s' %(self.master_port)))
112 # We want to use --secure-file-priv = $vardir by default
113 # but there are times / tools when we need to shut this off
114 if self.no_secure_file_priv:
115 self.secure_file_string = ''
116 else:
117 self.secure_file_string = "--secure-file-priv='%s'" %(self.vardir)
118 self.user_string = '--user=root'
119
120 self.initialize_databases()
121 self.take_db_snapshot()
122
123 self.logging.debug_class(self)
124
125
126 def report(self):
127 """ We print out some general useful info """
128 report_values = [ 'name'
129 , 'master_port'
130 , 'socket_file'
131 , 'vardir'
132 , 'status'
133 ]
134 self.logging.info("%s server:" %(self.owner))
135 for key in report_values:
136 value = vars(self)[key]
137 self.logging.info("%s: %s" %(key.upper(), value))
138
139 def initialize_databases(self):
140 """ Do the voodoo required to have a working database setup.
141 For MySQL, this is calling the server with the
142 --bootstrap argument. We generate the bootstrap
143 file during codeTree intialization as the file is standard for
144 all MySQL servers that are spawned from a single codeTree
145
146 """
147
148 # generate the bootstrap startup command
149 if not self.bootstrap_cmd:
150 mysqld_args = [ "--no-defaults"
151 , "--bootstrap"
152 , "--basedir=%s" %(self.code_tree.basedir)
153 , "--datadir=%s" %(self.datadir)
154 , "--loose-skip-falcon"
155 , "--loose-skip-ndbcluster"
156 , "--tmpdir=%s" %(self.tmpdir)
157 , "--core-file"
158 , "--lc-messages-dir=%s" %(self.langdir)
159 , "--character-sets-dir=%s" %(self.charsetdir)
160 ]
161 # We add server_path into the mix this way as we
162 # may alter how we store / handle server args later
163 mysqld_args.insert(0,self.server_path)
164 self.bootstrap_cmd = " ".join(mysqld_args)
165 # execute our command
166 bootstrap_log = open(self.bootstrap_log,'w')
167 # open our bootstrap file
168 bootstrap_in = open(self.bootstrap_file,'r')
169 bootstrap_subproc = subprocess.Popen( self.bootstrap_cmd
170 , shell=True
171 , stdin=bootstrap_in
172 , stdout=bootstrap_log
173 , stderr=bootstrap_log
174 )
175 bootstrap_subproc.wait()
176 bootstrap_in.close()
177 bootstrap_log.close()
178 bootstrap_retcode = bootstrap_subproc.returncode
179 if bootstrap_retcode:
180 self.logging.error("Received retcode: %s executing command: %s"
181 %(bootstrap_retcode, self.bootstrap_cmd))
182 self.logging.error("Check the bootstrap log: %s" %(self.bootstrap_log))
183 sys.exit(1)
184
185
186 def get_start_cmd(self):
187 """ Return the command string that will start up the server
188 as desired / intended
189
190 """
191
192 server_args = [ self.process_server_options()
193 , "--open-files-limit=1024"
194 , "--local-infile"
195 , "--character-set-server=latin1"
196 , "--connect-timeout=60"
197 , "--log-bin-trust-function-creators=1"
198 , "--key_buffer_size=1M"
199 , "--sort_buffer=256K"
200 , "--max_heap_table_size=1M"
201 , "--loose-innodb_data_file_path=ibdata1:10M:autoextend"
202 , "--loose-innodb_buffer_pool_size=8M"
203 , "--loose-innodb_write_io_threads=2"
204 , "--loose-innodb_read_io_threads=2"
205 , "--loose-innodb_log_buffer_size=1M"
206 , "--loose-innodb_log_file_size=5M"
207 , "--loose-innodb_additional_mem_pool_size=1M"
208 , "--loose-innodb_log_files_in_group=2"
209 , "--slave-net-timeout=120"
210 , "--log-bin=%s" %(os.path.join(self.logdir,"mysqld-bin"))
211 , "--loose-enable-performance-schema"
212 , "--loose-performance-schema-max-mutex-instances=10000"
213 , "--loose-performance-schema-max-rwlock-instances=10000"
214 , "--loose-performance-schema-max-table-instances=500"
215 , "--loose-performance-schema-max-table-handles=1000"
216 , "--binlog-direct-non-transactional-updates"
217 , "--loose-enable-performance-schema"
218 , "--general_log=1"
219 , "--general_log_file=%s" %(self.general_log_file)
220 , "--slow_query_log=1"
221 , "--slow_query_log_file=%s" %(self.slow_query_log_file)
222 , "--basedir=%s" %(self.code_tree.basedir)
223 , "--datadir=%s" %(self.datadir)
224 , "--tmpdir=%s" %(self.tmpdir)
225 , "--character-sets-dir=%s" %(self.charsetdir)
226 , "--lc-messages-dir=%s" %(self.langdir)
227 , "--ssl-ca=%s" %(os.path.join(self.std_data,'cacert.pem'))
228 , "--ssl-cert=%s" %(os.path.join(self.std_data,'server-cert.pem'))
229 , "--ssl-key=%s" %(os.path.join(self.std_data,'server-key.pem'))
230 , "--port=%d" %(self.master_port)
231 , "--socket=%s" %(self.socket_file)
232 , "--pid-file=%s" %(self.pid_file)
233 , "--default-storage-engine=%s" %(self.default_storage_engine)
234 # server-id maybe needs fixing, but we want to avoid
235 # the server-id=0 and no replication thing...
236 , "--server-id=%d" %(self.get_numeric_server_id()+1)
237 , self.secure_file_string
238 , self.user_string
239 ]
240 self.gen_cnf_file(server_args)
241
242 if self.gdb:
243 server_args.append('--gdb')
244 return self.system_manager.handle_gdb_reqs(self, server_args)
245 else:
246 return "%s %s %s & " % ( self.cmd_prefix
247 , self.server_path
248 , " ".join(server_args)
249 )
250
251
252 def get_stop_cmd(self):
253 """ Return the command that will shut us down """
254
255 return "%s --no-defaults --user=root --port=%d --host=127.0.0.1 --protocol=tcp shutdown " %(self.mysqladmin, self.master_port)
256
257
258 def get_ping_cmd(self):
259 """Return the command string that will
260 ping / check if the server is alive
261
262 """
263
264 return '%s --no-defaults --user=root --port=%d --host=127.0.0.1 --protocol=tcp ping' % (self.mysqladmin, self.master_port)
265
266 def is_started(self):
267 """ Determine if the server is up and running -
268 this may vary from server type to server type
269
270 """
271
272 # We experiment with waiting for a pid file to be created vs. pinging
273 # This is what test-run.pl does and it helps us pass logging_stats tests
274 # while not self.ping_server(server, quiet=True) and timer != timeout:
275
276 return self.system_manager.find_path( [self.pid_file]
277 , required=0)
278
279 def gen_cnf_file(self, server_args):
280 """ We generate a .cnf file for the server based
281 on the arguments. We currently don't use
282 this for much, but xtrabackup uses it, so
283 we must produce one. This could also be
284 helpful for testing / etc
285
286 """
287
288 config_file = open(self.cnf_file,'w')
289 config_file.write('[mysqld]')
290 for server_arg in server_args:
291 # We currently have a list of string values
292 # We need to remove any '--' stuff
293 server_arg = server_arg.replace('--','')+'\n'
294 config_file.write(server_arg)
295 config_file.close()
2960
=== removed file 'dbqp/lib/server_mgmt/percona.py'
--- dbqp/lib/server_mgmt/percona.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/server_mgmt/percona.py 1970-01-01 00:00:00 +0000
@@ -1,273 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010,2011 Patrick Crews
6#
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
20
21
22""" mysqld.py: code to allow a serverManager
23 to provision and start up a mysqld server object
24 for test execution
25
26"""
27
28# imports
29import os
30import sys
31import subproc
32
33
34from lib.server_mgmt.server import Server
35
36class mysqlServer(Server):
37 """ represents a mysql server, its possessions
38 (datadir, ports, etc), and methods for controlling
39 and querying it
40
41 TODO: create a base server class that contains
42 standard methods from which we can inherit
43 Currently there are definitely methods / attr
44 which are general
45
46 """
47
48 def __init__( self, name, server_manager, code_tree, default_storage_engine
49 , server_options, requester, workdir_root):
50 super(mysqlServer, self).__init__( name
51 , server_manager
52 , code_tree
53 , default_storage_engine
54 , server_options
55 , requester
56 , workdir_root)
57 self.preferred_base_port = 9306
58
59 # client files
60 self.mysqldump = self.code_tree.mysqldump
61 self.mysqladmin = self.code_tree.mysqladmin
62 self.mysql_client = self.code_tree.mysql_client
63 self.mysqlimport = self.code_tree.mysqlimport
64 self.mysqlslap = self.code_tree.mysqlslap
65 self.server_path = self.code_tree.mysql_server
66 self.mysql_client_path = self.code_tree.mysql_client
67
68 # important stuff
69 self.langdir = self.code_tree.langdir
70 self.charsetdir = self.code_tree.charsetdir
71 self.bootstrap_file = self.code_tree.bootstrap_path
72 self.bootstrap_cmd = None
73
74 # Get our ports
75 self.port_block = self.system_manager.port_manager.get_port_block( self.name
76 , self.preferred_base_port
77 , 1 )
78 self.master_port = self.port_block[0]
79
80 # Generate our working directories
81 self.dirset = { self.name : { 'var': {'std_data_ln':( os.path.join(self.code_tree.testdir,'std_data'))
82 ,'log':None
83 ,'run':None
84 ,'tmp':None
85 ,'master-data': {'local': { 'test':None
86 , 'mysql':None
87 }
88 }
89 }
90 }
91 }
92 self.workdir = self.system_manager.create_dirset( workdir_root
93 , self.dirset)
94 self.vardir = os.path.join(self.workdir,'var')
95 self.tmpdir = os.path.join(self.vardir,'tmp')
96 self.rundir = os.path.join(self.vardir,'run')
97 self.logdir = os.path.join(self.vardir,'log')
98 self.std_data = os.path.join(self.vardir,'std_data_ln')
99 self.datadir = os.path.join(self.vardir,'master-data')
100
101 self.error_log = os.path.join(self.logdir,('%s.err' %(self.name)))
102 self.bootstrap_log = os.path.join(self.logdir,('bootstrap.log'))
103 self.pid_file = os.path.join(self.rundir,('%s.pid' %(self.name)))
104 self.socket_file = os.path.join(self.vardir, ('%s.sock' %(self.name)))
105 self.timer_file = os.path.join(self.logdir,('timer'))
106 self.general_log_file = os.path.join(self.logdir,'mysqld.log')
107 self.slow_query_log_file = os.path.join(self.logdir,'mysqld-slow.log')
108
109 self.snapshot_path = os.path.join(self.tmpdir,('snapshot_%s' %(self.master_port)))
110 # We want to use --secure-file-priv = $vardir by default
111 # but there are times / tools when we need to shut this off
112 if self.no_secure_file_priv:
113 self.secure_file_string = ''
114 else:
115 self.secure_file_string = "--secure-file-priv='%s'" %(self.vardir)
116 self.user_string = '--user=root'
117
118 self.initialize_databases()
119 self.take_db_snapshot()
120
121 self.logging.debug_class(self)
122
123 def report(self):
124 """ We print out some general useful info """
125 report_values = [ 'name'
126 , 'master_port'
127 , 'socket_file'
128 , 'vardir'
129 , 'status'
130 ]
131 self.logging.info("%s server:" %(self.owner))
132 for key in report_values:
133 value = vars(self)[key]
134 self.logging.info("%s: %s" %(key.upper(), value))
135
136 def initialize_databases(self):
137 """ Do the voodoo required to have a working database setup.
138 For MySQL, this is calling the server with the
139 --bootstrap argument. We generate the bootstrap
140 file during codeTree intialization as the file is standard for
141 all MySQL servers that are spawned from a single codeTree
142
143 """
144
145 # generate the bootstrap startup command
146 if not self.bootstrap_cmd:
147 mysqld_args = [ "--no-defaults"
148 , "--bootstrap"
149 , "--basedir=%s" %(self.code_tree.basedir)
150 , "--datadir=%s" %(self.datadir)
151 , "--loose-skip-falcon"
152 , "--loose-skip-ndbcluster"
153 , "--tmpdir=%s" %(self.tmpdir)
154 , "--core-file"
155 , "--lc-messages-dir=%s" %(self.langdir)
156 , "--character-sets-dir=%s" %(self.charsetdir)
157 ]
158 # We add server_path into the mix this way as we
159 # may alter how we store / handle server args later
160 mysqld_args = [self.server_path].append(mysqld_args)
161 self.bootstrap_cmd = " ".join(mysqld_args)
162 # execute our command
163 bootstrap_subproc = subprocess.Popen( self.bootstrap_cmd
164 , shell=True
165 , stdout=self.bootstrap_log
166 , stderr=self.bootstrap_log
167 )
168 bootstrap_subproc.wait()
169 bootstrap_retcode = bootstrap_subproc.returncode
170 if bootstrap_retcode:
171 self.logging.error("Received retcode: %s executing command: %s"
172 %(bootstrap_retcode, self.bootstrap_cmd))
173 self.logging.error("Check the bootstrap log: %s" %(self.bootstrap_log))
174 sys.exit(1)
175
176
177 def get_start_cmd(self):
178 """ Return the command string that will start up the server
179 as desired / intended
180
181 """
182
183 server_args = [ self.process_server_options()
184 , "--open-files-limit=1024"
185 , "--local-infile"
186 , "--character-set-server=latin1"
187 , "--connect-timeout=60"
188 , "--log-bin-trust-function-creators=1"
189 , "--key_buffer_size=1M"
190 , "--sort_buffer=256K"
191 , "--max_heap_table_size=1M"
192 , "--query-cache-size=0"
193 , "--loose-innodb_data_file_path=ibdata1:10M:autoextend"
194 , "--loose-innodb_buffer_pool_size=32M"
195 , "--loose-innodb_write_io_threads=2"
196 , "--loose-innodb_read_io_threads=2"
197 , "--loose-innodb_log_buffer_size=1M"
198 , "--loose-innodb_log_file_size=5M"
199 , "--loose-innodb_additional_mem_pool_size=1M"
200 , "--loose-innodb_log_files_in_group=2"
201 , "--slave-net-timeout=120"
202 , "--log-bin=mysqld-bin"
203 , "--loose-enable-performance-schema"
204 , "--loose-performance-schema-max-mutex-instances=10000"
205 , "--loose-performance-schema-max-rwlock-instances=10000"
206 , "--loose-performance-schema-max-table-instances=500"
207 , "--loose-performance-schema-max-table-handles=1000"
208 , "--binlog-direct-non-transactional-updates"
209 , "--loose-enable-performance-schema"
210 , "--log-bin=master-bin"
211 , "--general_log=1"
212 , "--general_log_file=%s" %(self.general_log_file)
213 , "--slow_query_log=1"
214 , "--slow_query_log_file=%s" %(self.slow_query_log_file)
215 , "--basedir=%s" %(self.codetree.basedir)
216 , "--datadir=%s" %(self.datadir)
217 , "--tmpdir=%s" %(self.tmpdir)
218 , "--character-sets-dir=%s" %(self.charsetdir)
219 , "--lc-messages-dir=%s" %(self.langdir)
220 , "--ssl-ca=%s" %(os.path.join(self.std_data,'cacert.pem'))
221 , "--ssl-cert=%s" %(os.path.join(self.std_data,'server-cert.pem'))
222 , "--ssl-key=%s" %(os.path.join(self.std_data,'server-key.pem'))
223 , "--port=%d" %(self.master_port)
224 , "--mysql-protocol.connect-timeout=60"
225 , "--innodb.data-file-path=ibdata1:20M:autoextend"
226 , "--sort-buffer-size=256K"
227 , "--max-heap-table-size=1M"
228 , "--socket=%s" %(self.socket_file)
229 , "--pid-file=%s" %(self.pid_file)
230 , "--default-storage-engine=%s" %(self.default_storage_engine)
231 , "--server-id=%d" %(self.get_numeric_server_id)
232 , self.secure_file_string
233 , self.user_string
234 ]
235
236 if self.gdb:
237 server_args.append('--gdb')
238 return self.system_manager.handle_gdb_reqs(self, server_args)
239 else:
240 return "%s %s %s & " % ( self.cmd_prefix
241 , self.server_path
242 , " ".join(server_args)
243 )
244
245
246 def get_stop_cmd(self):
247 """ Return the command that will shut us down """
248
249 return "%s --user=root --port=%d --connect-timeout=5 --silent --password= --shutdown " %(self.mysql_admin, self.master_port)
250
251
252 def get_ping_cmd(self):
253 """Return the command string that will
254 ping / check if the server is alive
255
256 """
257
258 return '%s --port=%d --user=root -hlocalhost --protocol=tcp -e ""' % (self.mysql_client_path, self.master_port)
259
260 def is_started(self):
261 """ Determine if the server is up and running -
262 this may vary from server type to server type
263
264 """
265
266 # We experiment with waiting for a pid file to be created vs. pinging
267 # This is what test-run.pl does and it helps us pass logging_stats tests
268 # while not self.ping_server(server, quiet=True) and timer != timeout:
269
270 return self.system_manager.find_path( [self.pid_file]
271 , required=0)
272
273
2740
=== removed file 'dbqp/lib/server_mgmt/server.py'
--- dbqp/lib/server_mgmt/server.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/server_mgmt/server.py 1970-01-01 00:00:00 +0000
@@ -1,170 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010,2011 Patrick Crews
6#
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
20
21
22""" server.py: generic server object used by the server
23 manager. This contains the generic methods for all
24 servers. Specific types (Drizzle, MySQL, etc) should
25 inherit from this guy
26
27"""
28
29# imports
30import os
31
32class Server(object):
33 """ the server class from which other servers
34 will inherit - contains generic methods
35 certain methods will be overridden by more
36 specific ones
37
38 """
39
40 def __init__(self
41 , name
42 , server_manager
43 , code_tree
44 , default_storage_engine
45 , server_options
46 , requester
47 , workdir_root):
48 self.skip_keys = [ 'server_manager'
49 , 'system_manager'
50 , 'dirset'
51 , 'preferred_base_port'
52 , 'no_secure_file_priv'
53 , 'secure_file_string'
54 , 'port_block'
55 ]
56 self.debug = server_manager.debug
57 self.verbose = server_manager.verbose
58 self.initial_run = 1
59 self.owner = requester
60 self.server_options = server_options
61 self.default_storage_engine = default_storage_engine
62 self.server_manager = server_manager
63 # We register with server_manager asap
64 self.server_manager.log_server(self, requester)
65
66 self.system_manager = self.server_manager.system_manager
67 self.code_tree = code_tree
68 self.type = self.code_tree.type
69 self.valgrind = self.system_manager.valgrind
70 self.gdb = self.system_manager.gdb
71 if self.valgrind:
72 self.valgrind_time_buffer = 10
73 else:
74 self.valgrind_time_buffer = 1
75 self.cmd_prefix = self.system_manager.cmd_prefix
76 self.logging = self.system_manager.logging
77 self.no_secure_file_priv = self.server_manager.no_secure_file_priv
78 self.name = name
79 self.status = 0 # stopped, 1 = running
80 self.tried_start = 0
81 self.failed_test = 0 # was the last test a failure? our state is suspect
82 self.server_start_timeout = 60 * self.valgrind_time_buffer
83 self.pid = None
84 self.ip_address = '127.0.0.1'
85 self.need_reset = False
86
87 def initialize_databases(self):
88 """ Call schemawriter to make db.opt files """
89 databases = [ 'test'
90 , 'mysql'
91 ]
92 for database in databases:
93 db_path = os.path.join(self.datadir,'local',database,'db.opt')
94 cmd = "%s %s %s" %(self.schemawriter, database, db_path)
95 self.system_manager.execute_cmd(cmd)
96
97 def process_server_options(self):
98 """Consume the list of options we have been passed.
99 Return a string with them joined
100
101 """
102
103 return " ".join(self.server_options)
104
105 def take_db_snapshot(self):
106 """ Take a snapshot of our vardir for quick restores """
107
108 self.logging.info("Taking clean db snapshot...")
109 if os.path.exists(self.snapshot_path):
110 # We need to remove an existing path as python shutil
111 # doesn't want an existing target
112 self.system_manager.remove_dir(self.snapshot_path)
113 self.system_manager.copy_dir(self.datadir, self.snapshot_path)
114
115 def restore_snapshot(self):
116 """ Restore from a stored snapshot """
117
118 if not os.path.exists(self.snapshot_path):
119 self.logging.error("Could not find snapshot: %s" %(self.snapshot_path))
120 self.system_manager.remove_dir(self.datadir)
121 self.system_manager.copy_dir(self.snapshot_path, self.datadir)
122
123 def is_started(self):
124 """ Is the server running? Particulars are server-dependent """
125
126 return "You need to implement is_started"
127
128 def get_start_cmd(self):
129 """ Return the command the server_manager can use to start me """
130
131 return "You need to implement get_start_cmd"
132
133 def get_stop_cmd(self):
134 """ Return the command the server_manager can use to stop me """
135
136 return "You need to implement get_stop_cmd"
137
138 def get_ping_cmd(self):
139 """ Return the command that can be used to 'ping' me
140 Very similar to is_started, but different
141
142 Determining if a server is still running (ping)
143 may differ from the method used to determine
144 server startup
145
146 """
147
148 return "You need to implement get_ping_cmd"
149
150 def cleanup(self):
151 """ Cleanup - just free ports for now..."""
152 self.system_manager.port_manager.free_ports(self.port_block)
153
154 def set_server_options(self, server_options):
155 """ We update our server_options to the new set """
156 self.server_options = server_options
157
158 def reset(self):
159 """ Voodoo to reset ourselves """
160 self.failed_test = 0
161 self.need_reset = False
162
163 def get_numeric_server_id(self):
164 """ Return the integer value of server-id
165 Mainly for mysql / percona, but may be useful elsewhere
166
167 """
168
169 return int(self.name.split(self.server_manager.server_base_name)[1])
170
1710
=== removed file 'dbqp/lib/server_mgmt/server_management.py'
--- dbqp/lib/server_mgmt/server_management.py 2012-02-04 01:22:23 +0000
+++ dbqp/lib/server_mgmt/server_management.py 1970-01-01 00:00:00 +0000
@@ -1,611 +0,0 @@
1#! /usr/bin/env python
2# -*- mode: python; indent-tabs-mode: nil; -*-
3# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4#
5# Copyright (C) 2010, 2011 Patrick Crews
6#
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
20
21"""server_management.py
22 code for dealing with apportioning servers
23 to suit the needs of the tests and executors
24
25"""
26# imports
27import thread
28import time
29import os
30import subprocess
31from ConfigParser import RawConfigParser
32
33class serverManager:
34 """ code that handles the server objects
35 We use this to track, do mass actions, etc
36 Single point of contact for this business
37
38 """
39
40 def __init__(self, system_manager, variables):
41 self.skip_keys = [ 'system_manager'
42 , 'env_manager'
43 , 'code_manager'
44 , 'logging'
45 , 'gdb'
46 ]
47 self.debug = variables['debug']
48 self.verbose = variables['verbose']
49 self.initial_run = 1
50 # we try this to shorten things - will see how this works
51 self.server_base_name = 's'
52 self.no_secure_file_priv = variables['nosecurefilepriv']
53 self.system_manager = system_manager
54 self.code_manager = system_manager.code_manager
55 self.env_manager = system_manager.env_manager
56 self.logging = system_manager.logging
57 self.gdb = self.system_manager.gdb
58 self.default_storage_engine = variables['defaultengine']
59 self.default_server_type = variables['defaultservertype']
60 self.user_server_opts = variables['drizzledoptions']
61 self.servers = {}
62
63 self.mutex = thread.allocate_lock()
64 self.timer_increment = .5
65 self.libeatmydata = variables['libeatmydata']
66 self.libeatmydata_path = variables['libeatmydatapath']
67
68 self.logging.info("Using default-storage-engine: %s" %(self.default_storage_engine))
69
70 self.logging.debug_class(self)
71
72 def request_servers( self, requester
73 , workdir, cnf_path
74 , server_requests
75 , server_requirements
76 , working_environ, expect_fail = 0):
77 """ We produce the server objects / start the server processes
78 as requested. We report errors and whatnot if we can't
79 That is, unless we expect the server to not start, then
80 we just return a value / message.
81
82 server_requirements is a list of lists. Each list
83 is a set of server options - we create one server
84 for each set of options requested
85
86 """
87
88 # Make sure our server is in a decent state, if the last test
89 # failed, then we reset the server
90 self.check_server_status(requester)
91
92 # Make sure we have the proper number of servers for this requester
93 self.process_server_count( requester, len(server_requirements)
94 , workdir, server_requirements)
95
96 # Make sure we are running with the correct options
97 self.evaluate_existing_servers( requester
98 , cnf_path
99 , server_requests
100 , server_requirements)
101
102 # Fire our servers up
103 bad_start = self.start_servers( requester, working_environ
104 , expect_fail)
105
106 # Return them to the requester
107 return (self.get_server_list(requester), bad_start)
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches