2144.1.1
by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control |
1 |
#! /usr/bin/env python
|
2235.5.2
by Stewart Smith
dbqp source (and all its libs) should use emacs python mode, not emacs C mode |
2 |
# -*- mode: python; indent-tabs-mode: nil; -*-
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
3 |
# vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
|
4 |
#
|
|
5 |
# Copyright (C) 2010 Patrick Crews
|
|
6 |
#
|
|
2121.3.2
by patrick crews
Updated license verbiage |
7 |
# This program is free software; you can redistribute it and/or modify
|
8 |
# it under the terms of the GNU General Public License as published by
|
|
9 |
# the Free Software Foundation; either version 2 of the License, or
|
|
10 |
# (at your option) any later version.
|
|
11 |
#
|
|
12 |
# This program is distributed in the hope that it will be useful,
|
|
13 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15 |
# GNU General Public License for more details.
|
|
16 |
#
|
|
17 |
# You should have received a copy of the GNU General Public License
|
|
18 |
# along with this program; if not, write to the Free Software
|
|
19 |
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
2121.3.1
by patrick crews
Added licensing text to dbqp files |
20 |
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
21 |
"""system_management.py
|
22 |
code for dealing with system-level 'stuff'.
|
|
23 |
This includes setting environment variables, looking for clients,
|
|
24 |
so on and so forth.
|
|
25 |
||
26 |
These things are / should be constant regardless of the testing being done
|
|
27 |
We do an initial preflight / setup, we then call the mode-specific
|
|
28 |
system_initialise() to do whatever the testing mode requires to do that
|
|
29 |
voodoo that it do so well
|
|
30 |
||
31 |
"""
|
|
32 |
||
33 |
# imports
|
|
34 |
import os |
|
35 |
import sys |
|
2144.1.1
by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control |
36 |
import copy |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
37 |
import shutil |
2124.2.1
by Patrick Crews
Updates to system_management.py to have better naming for symlinks in shm |
38 |
import getpass |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
39 |
import commands |
40 |
||
2211.3.2
by patrick crews
Including uuid module so we can work with red hat...grr. We could require packages and whatnot, but just inlcuding the small file until such time as redhat moves to python 2.5 seems good |
41 |
from lib.uuid import uuid4 |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
42 |
from lib.sys_mgmt.port_management import portManager |
43 |
from lib.sys_mgmt.logging_management import loggingManager |
|
2088.9.18
by patrick crews
Updates to allow for timing of test cases and reporting and whatnot |
44 |
from lib.sys_mgmt.time_management import timeManager |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
45 |
|
46 |
class systemManager: |
|
47 |
"""Class to deal with the basics of system-level interaction
|
|
48 |
and awareness
|
|
49 |
||
50 |
Uses other managers to handle sub-tasks like port management
|
|
51 |
||
52 |
"""
|
|
53 |
def __init__(self, variables, tree_type='drizzle'): |
|
54 |
self.logging = loggingManager(variables) |
|
55 |
if variables['verbose']: |
|
56 |
self.logging.verbose("Initializing system manager...") |
|
57 |
||
58 |
self.skip_keys = [ 'code_tree' |
|
2088.9.22
by patrick crews
Updated code to set LD_LIBRARY env vars |
59 |
, 'ld_lib_paths' |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
60 |
, 'port_manager' |
61 |
, 'logging_manager' |
|
62 |
, 'environment_reqs' |
|
63 |
, 'env_var_delimiter'] |
|
64 |
self.debug = variables['debug'] |
|
65 |
self.verbose = variables['verbose'] |
|
66 |
self.env_var_delimiter = ':' |
|
67 |
self.no_shm = variables['noshm'] |
|
68 |
self.shm_path = self.find_path(["/dev/shm", "/tmp"], required=0) |
|
2121.5.1
by patrick crews
changes to parse netstat output better on freebsd for port management |
69 |
self.cur_os = os.uname()[0] |
2124.2.1
by Patrick Crews
Updates to system_management.py to have better naming for symlinks in shm |
70 |
self.cur_user = getpass.getuser() |
2124.2.6
by Patrick Crews
make target for dbqp! : ) |
71 |
self.workdir = os.path.abspath(variables['workdir']) |
2194.2.1
by patrick crews
Integrated randgen with dbqp. We now have mode=randgen and a set of randgen test suites (very basic now). Output = same as dtr : ) We also have mode=cleanup to kill any servers we have started. Docs updates too. Gendata utility allows us to populate test servers |
72 |
self.testdir = os.path.abspath(variables['testdir']) |
2151.8.1
by patrick crews
Updates to allow several dbqp's run run on one system (via uuid) and fix to return a relevant code post-execution (ie 1 if tests failed or timed out)) |
73 |
self.datadir = os.path.abspath(os.path.join(variables['testdir'],'dbqp_data')) |
2124.2.6
by Patrick Crews
make target for dbqp! : ) |
74 |
self.top_srcdir = os.path.abspath(variables['topsrcdir']) |
75 |
self.top_builddir = os.path.abspath(variables['topbuilddir']) |
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
76 |
self.start_dirty = variables['startdirty'] |
2088.9.24
by patrick crews
Added code to handle valgrind. Currently not working - getting bad error on malloc-fill=DEADBEEF : (, checking in anyway as it is largely there |
77 |
self.valgrind = variables['valgrind'] |
2121.6.1
by patrick crews
Updates to allow for reorder option. Also added placeholder for --fast (it is one in test-run.pl as well), and a minor fix of output regarding libtool |
78 |
self.gdb = variables['gdb'] |
2158.2.1
by patrick crews
Added in --gdb and --manual-gdb option as well as --drizzled option |
79 |
self.manual_gdb = variables['manualgdb'] |
2194.2.1
by patrick crews
Integrated randgen with dbqp. We now have mode=randgen and a set of randgen test suites (very basic now). Output = same as dtr : ) We also have mode=cleanup to kill any servers we have started. Docs updates too. Gendata utility allows us to populate test servers |
80 |
self.randgen_path = variables['randgenpath'] |
2088.9.24
by patrick crews
Added code to handle valgrind. Currently not working - getting bad error on malloc-fill=DEADBEEF : (, checking in anyway as it is largely there |
81 |
|
82 |
# we use this to preface commands in order to run valgrind and such
|
|
83 |
self.cmd_prefix = '' |
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
84 |
|
85 |
self.port_manager = portManager(self,variables['debug']) |
|
2088.9.18
by patrick crews
Updates to allow for timing of test cases and reporting and whatnot |
86 |
self.time_manager = timeManager(self) |
2151.8.1
by patrick crews
Updates to allow several dbqp's run run on one system (via uuid) and fix to return a relevant code post-execution (ie 1 if tests failed or timed out)) |
87 |
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
88 |
# Make sure the tree we are testing looks good
|
89 |
self.code_tree = self.get_code_tree(variables, tree_type) |
|
90 |
||
2144.1.1
by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control |
91 |
self.ld_lib_paths = self.join_env_var_values(self.code_tree.ld_lib_paths) |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
92 |
|
93 |
# Some ENV vars are system-standard
|
|
94 |
# We describe and set them here and now
|
|
95 |
# The format is name: (value, append, suffix)
|
|
2144.1.1
by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control |
96 |
self.environment_reqs = { 'UMASK':'0660' |
97 |
, 'UMASK_DIR' : '0770' |
|
98 |
, 'LC_ALL' : 'C' |
|
99 |
, 'LC_CTYPE' : 'C' |
|
100 |
, 'LC_COLLATE' : 'C' |
|
101 |
, 'USE_RUNNING_SERVER' : "0" |
|
102 |
, 'TOP_SRCDIR' : self.top_srcdir |
|
103 |
, 'TOP_BUILDDIR' : self.top_builddir |
|
104 |
, 'DRIZZLE_TEST_DIR' : self.code_tree.testdir |
|
105 |
, 'DTR_BUILD_THREAD' : "-69.5" |
|
106 |
, 'LD_LIBRARY_PATH' : self.append_env_var( 'LD_LIBRARY_PATH' |
|
107 |
, self.ld_lib_paths |
|
108 |
, suffix = 0 |
|
109 |
, quiet = 1 |
|
110 |
)
|
|
111 |
, 'DYLD_LIBRARY_PATH' : self.append_env_var( 'DYLD_LIBRARY_PATH' |
|
112 |
, self.ld_lib_paths |
|
113 |
, suffix = 0 |
|
114 |
, quiet = 1 |
|
115 |
)
|
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
116 |
}
|
117 |
# set the env vars we need
|
|
2144.1.1
by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control |
118 |
# self.process_environment_reqs(self.environment_reqs)
|
119 |
self.update_environment_vars(self.environment_reqs) |
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
120 |
|
2151.8.1
by patrick crews
Updates to allow several dbqp's run run on one system (via uuid) and fix to return a relevant code post-execution (ie 1 if tests failed or timed out)) |
121 |
# We find or generate our id file
|
122 |
# We use a uuid to identify the symlinked
|
|
123 |
# workdirs. That way, each installation
|
|
124 |
# Will have a uuid/tmpfs workingdir
|
|
125 |
# We store in a file so we know what
|
|
126 |
# is ours
|
|
127 |
self.uuid = self.get_uuid() |
|
128 |
self.symlink_name = 'dbqp_workdir_%s_%s' %(self.cur_user, self.uuid) |
|
129 |
||
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
130 |
# initialize our workdir
|
131 |
self.process_workdir() |
|
132 |
||
2088.9.24
by patrick crews
Added code to handle valgrind. Currently not working - getting bad error on malloc-fill=DEADBEEF : (, checking in anyway as it is largely there |
133 |
# check for libtool
|
134 |
self.libtool = self.libtool_check() |
|
135 |
||
2151.8.4
by patrick crews
gdb! : ) We try to set things up to launch the native Mac Terminal if we are running on Darwin |
136 |
# See if we need to do any further processing for special
|
137 |
# options like valgrind and gdb
|
|
138 |
self.handle_additional_reqs(variables) |
|
139 |
||
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
140 |
if self.debug: |
141 |
self.logging.debug_class(self) |
|
142 |
||
143 |
def get_code_tree(self, variables, tree_type): |
|
144 |
"""Find out the important files, directories, and env. vars
|
|
145 |
for a particular type of tree. We import a definition module
|
|
146 |
depending on the tree_type. The module lets us know
|
|
147 |
what to look for, etc
|
|
148 |
||
149 |
"""
|
|
150 |
||
151 |
# Import the appropriate module that defines
|
|
152 |
# where we find what we need depending on
|
|
153 |
# tree type
|
|
154 |
test_tree = self.process_tree_type(tree_type, variables) |
|
155 |
return test_tree |
|
156 |
||
157 |
def process_tree_type(self, tree_type, variables): |
|
158 |
"""Import the appropriate module depending on the type of tree
|
|
159 |
we are testing.
|
|
160 |
||
161 |
Drizzle is the only supported type currently
|
|
162 |
||
163 |
"""
|
|
2151.8.1
by patrick crews
Updates to allow several dbqp's run run on one system (via uuid) and fix to return a relevant code post-execution (ie 1 if tests failed or timed out)) |
164 |
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
165 |
if self.verbose: |
166 |
self.logging.verbose("Processing source tree under test...") |
|
167 |
if tree_type == 'drizzle': |
|
168 |
# base_case
|
|
169 |
from lib.sys_mgmt.codeTree import drizzleTree |
|
170 |
test_tree = drizzleTree(variables,self) |
|
171 |
return test_tree |
|
172 |
else: |
|
173 |
self.logging.error("Tree_type: %s not supported yet" %(tree_type)) |
|
2144.1.1
by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control |
174 |
sys.exit(1) |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
175 |
|
2151.8.1
by patrick crews
Updates to allow several dbqp's run run on one system (via uuid) and fix to return a relevant code post-execution (ie 1 if tests failed or timed out)) |
176 |
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
177 |
def create_dirset(self, rootdir, dirset): |
178 |
""" We produce the set of directories defined in dirset
|
|
179 |
dirset is a set of dictionaries like
|
|
180 |
{'dirname': 'subdir'}
|
|
181 |
or {'dirname': {'subdir':'subsubdir}}...
|
|
182 |
||
183 |
We generally expect there to be only a single
|
|
184 |
top-level key. The intent is to produce a dirset
|
|
185 |
rooted at key[0], with various subdirs under that
|
|
186 |
subsequest dirsets should be handles in separate calls...
|
|
187 |
||
188 |
"""
|
|
189 |
for dirname in dirset.keys(): |
|
190 |
full_path = os.path.join(rootdir, dirname) |
|
191 |
subdirset = dirset[dirname] |
|
192 |
if type(subdirset) is str: |
|
193 |
self.create_symlink(subdirset,full_path) |
|
194 |
else: |
|
195 |
self.create_dir(full_path) |
|
196 |
# dirset[dirname] is a new dictionary
|
|
197 |
if subdirset is None: |
|
198 |
{}
|
|
199 |
else: |
|
200 |
self.create_dirset(full_path,subdirset) |
|
201 |
||
202 |
return full_path |
|
203 |
||
2151.8.1
by patrick crews
Updates to allow several dbqp's run run on one system (via uuid) and fix to return a relevant code post-execution (ie 1 if tests failed or timed out)) |
204 |
def get_uuid(self): |
205 |
""" We look to see if a uuid file exists
|
|
206 |
If so, we use that to know where to work
|
|
207 |
If not we produce one so future runs
|
|
208 |
have a definitive id to use
|
|
209 |
||
210 |
"""
|
|
211 |
||
212 |
uuid_file_name = os.path.join(self.datadir, 'uuid') |
|
213 |
if os.path.exists(uuid_file_name): |
|
214 |
uuid_file = open(uuid_file_name,'r') |
|
215 |
uuid = uuid_file.readline().strip() |
|
216 |
uuid_file.close() |
|
217 |
else: |
|
218 |
uuid = uuid4() |
|
219 |
uuid_file = open(uuid_file_name,'w') |
|
220 |
uuid_file.write(str(uuid)) |
|
221 |
uuid_file.close() |
|
222 |
return uuid |
|
223 |
||
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
224 |
def process_workdir(self): |
225 |
""" We create our workdir, analyze relevant variables
|
|
226 |
to see if we should/shouldn't symlink to shm
|
|
227 |
We do nothing if we have --start-dirty
|
|
228 |
||
229 |
"""
|
|
230 |
||
231 |
if os.path.exists(self.workdir): |
|
232 |
# our workdir already exists
|
|
233 |
if self.start_dirty: |
|
234 |
self.logging.info("Using --start-dirty, not attempting to touch directories") |
|
235 |
return
|
|
236 |
else: |
|
2194.2.1
by patrick crews
Integrated randgen with dbqp. We now have mode=randgen and a set of randgen test suites (very basic now). Output = same as dtr : ) We also have mode=cleanup to kill any servers we have started. Docs updates too. Gendata utility allows us to populate test servers |
237 |
self.cleanup() # We crawl / try to kill any server pids we find |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
238 |
self.remove_dir(self.workdir) |
239 |
self.allocate_workdir() |
|
240 |
||
241 |
||
242 |
def allocate_workdir(self): |
|
243 |
""" Create a workdir according to user-supplied specs """
|
|
244 |
if self.no_shm: |
|
245 |
self.logging.info("Using --no-shm, will not link workdir to shm") |
|
246 |
self.create_dir(self.workdir, subdir=0) |
|
247 |
elif self.shm_path == None: |
|
248 |
self.logging.info("Could not find shared memory path for use. Not linking workdir to shm") |
|
249 |
self.create_dir(self.workdir, subdir=0) |
|
250 |
else: |
|
251 |
shm_workdir = self.create_dir(os.path.join(self.shm_path, self.symlink_name)) |
|
252 |
self.logging.info("Linking workdir %s to %s" %(self.workdir, shm_workdir)) |
|
253 |
self.create_symlink(shm_workdir, self.workdir) |
|
254 |
||
255 |
def create_dir(self, dirname, subdir =1 ): |
|
256 |
""" Create a directory. If subdir = 1,
|
|
257 |
then the new dir should be a subdir of
|
|
258 |
self.workdir. Else, we just create dirname,
|
|
259 |
which should really be dirpath in this case
|
|
260 |
||
261 |
"""
|
|
262 |
||
263 |
if subdir: |
|
264 |
full_path = os.path.join(self.workdir, dirname) |
|
265 |
else: |
|
266 |
full_path = dirname |
|
267 |
||
268 |
if os.path.exists(full_path): |
|
269 |
if self.start_dirty: |
|
270 |
return full_path |
|
271 |
else: |
|
272 |
shutil.rmtree(full_path) |
|
273 |
if self.debug: |
|
274 |
self.logging.debug("Creating directory: %s" %(dirname)) |
|
275 |
os.makedirs(full_path) |
|
276 |
return full_path |
|
277 |
||
278 |
def remove_dir(self, dirname, require_empty=0 ): |
|
279 |
""" Remove the directory in question.
|
|
280 |
We assume we want to brute-force clean
|
|
281 |
things. If require_empty = 0, then
|
|
282 |
the dir must be empty to remove it
|
|
283 |
||
284 |
"""
|
|
285 |
if self.debug: |
|
286 |
self.logging.debug("Removing directory: %s" %(dirname)) |
|
287 |
if os.path.islink(dirname): |
|
288 |
os.remove(dirname) |
|
289 |
elif require_empty: |
|
290 |
os.rmdir(dirname) |
|
291 |
else: |
|
292 |
shutil.rmtree(dirname) |
|
293 |
||
294 |
def copy_dir(self, srcdir, tgtdir, overwrite = 1): |
|
295 |
""" Copy the contents of srcdir to tgtdir.
|
|
296 |
We overwrite (remove/recreate) tgtdir
|
|
297 |
if overwrite == 1
|
|
298 |
||
299 |
"""
|
|
300 |
if self.debug: |
|
301 |
self.logging.debug("Copying directory: %s to %s" %(srcdir, tgtdir)) |
|
302 |
if os.path.exists(tgtdir): |
|
303 |
if overwrite: |
|
304 |
self.remove_dir(tgtdir) |
|
305 |
else: |
|
306 |
self.logging.error("Cannot overwrite existing directory: %s" %(tgtdir)) |
|
307 |
sys.exit(1) |
|
308 |
shutil.copytree(srcdir, tgtdir, symlinks=True) |
|
309 |
||
310 |
def create_symlink(self, source, link_name): |
|
311 |
""" We create a symlink to source named link_name """
|
|
312 |
if self.debug: |
|
313 |
self.logging.debug("Creating symlink from %s to %s" %(source, link_name)) |
|
2088.9.10
by patrick crews
Updates to filesystem_engine and transaction_log tests to allow dbqp + test-run.pl to live together and execute all tests |
314 |
if os.path.exists(link_name) or os.path.islink(link_name): |
315 |
os.remove(link_name) |
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
316 |
return os.symlink(source, link_name) |
317 |
||
2088.9.10
by patrick crews
Updates to filesystem_engine and transaction_log tests to allow dbqp + test-run.pl to live together and execute all tests |
318 |
def create_symlinks(self, needed_symlinks): |
319 |
""" We created the symlinks in needed_symlinks
|
|
320 |
We expect it to be tuples in source, link_name format
|
|
321 |
||
322 |
"""
|
|
323 |
||
324 |
for needed_symlink in needed_symlinks: |
|
325 |
source, link_name = needed_symlink |
|
326 |
self.create_symlink(source, link_name) |
|
327 |
||
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
328 |
def join_env_var_values(self, value_list): |
329 |
""" Utility to join multiple values into a nice string
|
|
330 |
for setting an env var to
|
|
331 |
|
|
332 |
"""
|
|
333 |
||
334 |
return self.env_var_delimiter.join(value_list) |
|
335 |
||
336 |
def set_env_var(self, var_name, var_value, quiet=0): |
|
337 |
"""Set an environment variable. We really just abstract
|
|
338 |
voodoo on os.environ
|
|
339 |
||
340 |
"""
|
|
341 |
if self.debug and not quiet: |
|
342 |
self.logging.debug("Setting env var: %s" %(var_name)) |
|
343 |
try: |
|
344 |
os.environ[var_name]=var_value |
|
345 |
except Exception, e: |
|
346 |
self.logging.error("Issue setting environment variable %s to value %s" %(var_name, var_value)) |
|
347 |
self.logging.error("%s" %(e)) |
|
348 |
sys.exit(1) |
|
349 |
||
2144.1.1
by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control |
350 |
def update_environment_vars(self, desired_vars, working_environment=None): |
351 |
""" We update the environment vars with desired_vars
|
|
352 |
The expectation is that you know what you are asking for ; )
|
|
353 |
If working_environment is provided, we will update that with
|
|
354 |
desired_vars. We operate directly on os.environ by default
|
|
355 |
We return our updated environ dictionary
|
|
356 |
||
357 |
"""
|
|
358 |
||
359 |
if not working_environment: |
|
360 |
working_environment = os.environ |
|
361 |
working_environment.update(desired_vars) |
|
362 |
return working_environment |
|
363 |
||
364 |
def create_working_environment(self, desired_vars): |
|
365 |
""" We return a copy of os.environ updated with desired_vars """
|
|
366 |
||
367 |
working_copy = copy.deepcopy(os.environ) |
|
368 |
return self.update_environment_vars( desired_vars |
|
369 |
, working_environment = working_copy ) |
|
370 |
||
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
371 |
def append_env_var(self, var_name, append_string, suffix=1, quiet=0): |
372 |
""" We add the values in var_values to the environment variable
|
|
373 |
var_name. Depending on suffix value, we either append or prepend
|
|
2144.1.1
by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control |
374 |
we return a string suitable for os.putenv
|
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
375 |
|
376 |
"""
|
|
377 |
new_var_value = "" |
|
378 |
if var_name in os.environ: |
|
379 |
cur_var_value = os.environ[var_name] |
|
380 |
if suffix: # We add new values to end of existing value |
|
381 |
new_var_values = [ cur_var_value, append_string ] |
|
382 |
else: |
|
383 |
new_var_values = [ append_string, cur_var_value ] |
|
2088.9.24
by patrick crews
Added code to handle valgrind. Currently not working - getting bad error on malloc-fill=DEADBEEF : (, checking in anyway as it is largely there |
384 |
new_var_value = self.env_var_delimiter.join(new_var_values) |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
385 |
else: |
386 |
# No existing variable value
|
|
387 |
new_var_value = append_string |
|
2144.1.1
by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control |
388 |
return new_var_value |
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
389 |
|
390 |
def find_path(self, paths, required=1): |
|
391 |
"""We search for the files we need / want to be aware of
|
|
392 |
such as the drizzled binary, the various client binaries, etc
|
|
393 |
We use the required switch to determine if we die or not
|
|
394 |
if we can't find the file.
|
|
395 |
||
396 |
We expect paths to be a list of paths, ordered in terms
|
|
397 |
of preference (ie we want to use something from search-path1
|
|
398 |
before search-path2).
|
|
399 |
||
400 |
We return None if no match found and this wasn't required
|
|
401 |
||
402 |
"""
|
|
403 |
||
404 |
for test_path in paths: |
|
405 |
if self.debug: |
|
406 |
self.logging.debug("Searching for path: %s" %(test_path)) |
|
407 |
if os.path.exists(test_path): |
|
408 |
return test_path |
|
409 |
if required: |
|
410 |
self.logging.error("Required file not found out of options: %s" %(" ,".join(paths))) |
|
411 |
sys.exit(1) |
|
412 |
else: |
|
413 |
return None |
|
414 |
||
415 |
def execute_cmd(self, cmd, must_pass = 1): |
|
416 |
""" Utility function to execute a command and
|
|
417 |
return the output and retcode
|
|
418 |
||
419 |
"""
|
|
420 |
||
421 |
if self.debug: |
|
422 |
self.logging.debug("Executing command: %s" %(cmd)) |
|
423 |
(retcode, output)= commands.getstatusoutput(cmd) |
|
424 |
if not retcode == 0 and must_pass: |
|
425 |
self.logging.error("Command %s failed with retcode %d" %(cmd, retcode)) |
|
426 |
self.logging.error("%s" %(output)) |
|
427 |
sys.exit(1) |
|
428 |
return retcode, output |
|
429 |
||
2088.9.24
by patrick crews
Added code to handle valgrind. Currently not working - getting bad error on malloc-fill=DEADBEEF : (, checking in anyway as it is largely there |
430 |
def libtool_check(self): |
431 |
""" We search for libtool """
|
|
432 |
libtool_path = '../libtool' |
|
433 |
if os.path.exists(libtool_path) and os.access( libtool_path |
|
434 |
, os.X_OK): |
|
2121.6.1
by patrick crews
Updates to allow for reorder option. Also added placeholder for --fast (it is one in test-run.pl as well), and a minor fix of output regarding libtool |
435 |
if self.valgrind or self.gdb: |
436 |
self.logging.info("Using libtool when running valgrind or debugger") |
|
2088.9.24
by patrick crews
Added code to handle valgrind. Currently not working - getting bad error on malloc-fill=DEADBEEF : (, checking in anyway as it is largely there |
437 |
return libtool_path |
438 |
else: |
|
439 |
return None |
|
440 |
||
2151.8.4
by patrick crews
gdb! : ) We try to set things up to launch the native Mac Terminal if we are running on Darwin |
441 |
def handle_additional_reqs(self, variables): |
442 |
""" Do what we need to do to set things up for
|
|
443 |
options like valgrind and gdb
|
|
444 |
||
445 |
"""
|
|
446 |
||
447 |
# do we need to setup for valgrind?
|
|
448 |
if self.valgrind: |
|
449 |
self.handle_valgrind_reqs(variables['valgrindarglist']) |
|
450 |
||
451 |
def handle_gdb_reqs(self, server, server_args): |
|
452 |
""" We generate the gdb init file and whatnot so we
|
|
453 |
can run gdb properly
|
|
454 |
||
2158.2.1
by patrick crews
Added in --gdb and --manual-gdb option as well as --drizzled option |
455 |
if the user has specified manual-gdb, we provide
|
456 |
them with a message about when to start and
|
|
457 |
signal the server manager to simply wait
|
|
458 |
for the server to be started by the user
|
|
459 |
||
2151.8.4
by patrick crews
gdb! : ) We try to set things up to launch the native Mac Terminal if we are running on Darwin |
460 |
"""
|
461 |
extra_args = '' |
|
2158.2.1
by patrick crews
Added in --gdb and --manual-gdb option as well as --drizzled option |
462 |
gdb_term_cmd = "xterm -title %s.%s " %( server.owner |
463 |
, server.name |
|
464 |
)
|
|
2151.8.4
by patrick crews
gdb! : ) We try to set things up to launch the native Mac Terminal if we are running on Darwin |
465 |
gdb_file_name = "%s.gdbinit" %(server.name) |
466 |
||
467 |
if self.cur_os == 'Darwin': # Mac...ick ; P |
|
468 |
extra_args = [ "set env DYLD_INSERT_LIBRARIES /usr/lib/libgmalloc.dylib" |
|
469 |
, "set env MallocStackLogging 1" |
|
470 |
, "set env MallocScribble 1" |
|
471 |
, "set env MallocPreScribble 1" |
|
472 |
, "set env MallocStackLogging 1" |
|
473 |
, "set env MallocStackLoggingNoCompact 1" |
|
474 |
, "set env MallocGuardEdges 1" |
|
475 |
]
|
|
476 |
||
477 |
# produce our init file
|
|
478 |
if extra_args: |
|
479 |
extra_args = "\n".join(extra_args) |
|
480 |
gdb_file_contents = [ "set args %s" %(" ".join(server_args)) |
|
481 |
, "%s" % (extra_args) |
|
482 |
, "set breakpoint pending on" |
|
483 |
, "break drizzled::parse" |
|
484 |
, "commands 1" |
|
485 |
, "disable 1" |
|
486 |
, "end" |
|
487 |
, "set breakpoint pending off" |
|
488 |
, "run" |
|
489 |
]
|
|
490 |
gdb_file_path = os.path.join(server.tmpdir, gdb_file_name) |
|
491 |
gdb_init_file = open(gdb_file_path,'w') |
|
492 |
gdb_init_file.write("\n".join(gdb_file_contents)) |
|
493 |
gdb_init_file.close() |
|
494 |
||
495 |
# return our command line
|
|
496 |
if self.libtool: |
|
497 |
libtool_string = "%s --mode=execute " %(self.libtool) |
|
498 |
else: |
|
499 |
libtool_string = "" |
|
2158.2.1
by patrick crews
Added in --gdb and --manual-gdb option as well as --drizzled option |
500 |
|
501 |
if self.manual_gdb: |
|
502 |
self.logging.info("To start gdb, open another terminal and enter:") |
|
503 |
self.logging.info("%s/../libtool --mode=execute gdb -cd %s -x %s %s" %( self.code_tree.testdir |
|
504 |
, self.code_tree.testdir |
|
505 |
, gdb_file_path |
|
506 |
, server.server_path |
|
507 |
) ) |
|
508 |
return None |
|
509 |
||
510 |
else: |
|
511 |
return "%s -e %s gdb -x %s %s" %( gdb_term_cmd |
|
512 |
, libtool_string |
|
513 |
, gdb_file_path |
|
514 |
, server.server_path |
|
515 |
)
|
|
2151.8.4
by patrick crews
gdb! : ) We try to set things up to launch the native Mac Terminal if we are running on Darwin |
516 |
|
2088.9.24
by patrick crews
Added code to handle valgrind. Currently not working - getting bad error on malloc-fill=DEADBEEF : (, checking in anyway as it is largely there |
517 |
def handle_valgrind_reqs(self, optional_args, mode='valgrind'): |
518 |
""" We do what voodoo we need to do to run valgrind """
|
|
519 |
valgrind_args = [ "--show-reachable=yes" |
|
2151.8.4
by patrick crews
gdb! : ) We try to set things up to launch the native Mac Terminal if we are running on Darwin |
520 |
, "--malloc-fill=22" |
521 |
, "--free-fill=22" |
|
2088.9.24
by patrick crews
Added code to handle valgrind. Currently not working - getting bad error on malloc-fill=DEADBEEF : (, checking in anyway as it is largely there |
522 |
# , "--trace-children=yes" this is for callgrind only
|
523 |
]
|
|
524 |
if optional_args: |
|
525 |
# we override the defaults with user-specified options
|
|
526 |
valgrind_args = optional_args |
|
527 |
self.logging.info("Running valgrind with options: %s" %(" ".join(valgrind_args))) |
|
528 |
||
529 |
# set our environment variable
|
|
530 |
self.set_env_var('VALGRIND_RUN', '1', quiet=0) |
|
531 |
||
532 |
# generate command prefix to call valgrind
|
|
533 |
cmd_prefix = '' |
|
534 |
if self.libtool: |
|
535 |
cmd_prefix = "%s --mode=execute valgrind " %(self.libtool) |
|
536 |
if mode == 'valgrind': |
|
537 |
# default mode
|
|
538 |
||
539 |
args = [ "--tool=memcheck" |
|
540 |
, "--leak-check=yes" |
|
541 |
, "--num-callers=16" |
|
542 |
]
|
|
543 |
# look for our suppressions file and add it to the mix if found
|
|
544 |
suppress_file = os.path.join(self.code_tree.testdir,'valgrind.supp') |
|
545 |
if os.path.exists(suppress_file): |
|
546 |
args = args + [ "--suppressions=%s" %(suppress_file) ] |
|
547 |
||
548 |
cmd_prefix = cmd_prefix + " ".join(args + valgrind_args) |
|
549 |
self.cmd_prefix = cmd_prefix |
|
550 |
||
551 |
# add debug libraries to ld_library_path
|
|
552 |
debug_path = '/usr/lib/debug' |
|
553 |
if os.path.exists(debug_path): |
|
554 |
self.append_env_var("LD_LIBRARY_PATH", debug_path, suffix=1) |
|
555 |
self.append_env_var("DYLD_LIBRARY_PATH", debug_path, suffix=1) |
|
2144.1.1
by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control |
556 |
|
2194.2.1
by patrick crews
Integrated randgen with dbqp. We now have mode=randgen and a set of randgen test suites (very basic now). Output = same as dtr : ) We also have mode=cleanup to kill any servers we have started. Docs updates too. Gendata utility allows us to populate test servers |
557 |
|
558 |
def cleanup(self, exit=False): |
|
559 |
""" We try to kill any servers whose pid files
|
|
560 |
we detect lurking about
|
|
561 |
||
562 |
"""
|
|
563 |
||
564 |
self.pid_hunt_and_kill(exit) |
|
565 |
||
566 |
def pid_hunt_and_kill(self, exit): |
|
567 |
""" Crawl our workdir and look for server.pid files
|
|
568 |
We read 'em and kill 'em if we find 'em
|
|
569 |
||
570 |
"""
|
|
571 |
||
572 |
for root, dirs, files in os.walk(self.workdir): |
|
573 |
#print root, dirs, files
|
|
574 |
for found_file in files: |
|
575 |
if found_file.endswith('.pid'): |
|
576 |
file_path = os.path.join(root, found_file) |
|
577 |
pid_file = open(file_path,'r') |
|
578 |
pid = pid_file.readline().strip() |
|
579 |
pid_file.close() |
|
580 |
self.logging.info("Killing pid %s from %s" %( pid |
|
581 |
, file_path |
|
582 |
))
|
|
2318.1.1
by patrick crews
Added code to monitor a server pid after shutdown cmd issued - after a limited timeout, we kill -9 it. Not a proper fix, but makes dbqp a good citizen again |
583 |
self.kill_pid(pid) |
2194.2.1
by patrick crews
Integrated randgen with dbqp. We now have mode=randgen and a set of randgen test suites (very basic now). Output = same as dtr : ) We also have mode=cleanup to kill any servers we have started. Docs updates too. Gendata utility allows us to populate test servers |
584 |
if exit: |
585 |
sys.exit(0) |
|
586 |
||
2318.1.1
by patrick crews
Added code to monitor a server pid after shutdown cmd issued - after a limited timeout, we kill -9 it. Not a proper fix, but makes dbqp a good citizen again |
587 |
def find_pid(self, pid): |
588 |
""" Execute ps and see if we find the pid """
|
|
589 |
||
590 |
cmd = "ps" |
|
591 |
retcode, output = self.execute_cmd(cmd) |
|
592 |
output = output.split('\n') |
|
593 |
for line in output: |
|
594 |
found_pid = line.strip().split(' ') |
|
595 |
if str(pid) == pid: |
|
596 |
return True |
|
597 |
return False |
|
598 |
||
599 |
def kill_pid(self, pid): |
|
600 |
""" We kill the specified pid """
|
|
601 |
||
602 |
self.execute_cmd("kill -9 %s" %pid, must_pass=0) |
|
603 |
||
2144.1.1
by patrick crews
Overhaul of code. We can run rabbitmq : ) We now better encapsulate a per-executor working environment = one step closer to --parallel >: ) using subprocess goodness for server control |
604 |
|
2088.9.24
by patrick crews
Added code to handle valgrind. Currently not working - getting bad error on malloc-fill=DEADBEEF : (, checking in anyway as it is largely there |
605 |
|
606 |
||
607 |
||
2088.9.1
by patrick crews
Updated tree so that test-run.pl and test-run.py may live together in peace for a time |
608 |
|
609 |
||
610 |
||
611 |