1
# jhbuild - a build script for GNOME 1.x and 2.x
2
# Copyright (C) 2001-2006 James Henstridge
4
# testmodule.py: testmodule type definitions.
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
import os, time, signal, sys, subprocess, random, md5, tempfile
24
from jhbuild.errors import FatalError, CommandError, BuildStateError
25
from jhbuild.modtypes import \
26
Package, DownloadableModule, get_dependencies, get_branch, register_module_type
27
from jhbuild.modtypes.autotools import AutogenModule
29
import xml.dom.minidom
31
__all__ = ['TestModule']
32
__test_types__ = ['ldtp' , 'dogtail']
34
class TestModule(Package, DownloadableModule):
37
PHASE_CHECKOUT = DownloadableModule.PHASE_CHECKOUT
38
PHASE_FORCE_CHECKOUT = DownloadableModule.PHASE_FORCE_CHECKOUT
41
def __init__(self, name, branch, test_type, dependencies=[], after=[], tested_pkgs=[]):
42
Package.__init__(self, name)
44
self.test_type = test_type
45
self.dependencies = dependencies
47
self.tested_pkgs = tested_pkgs
49
### modify environ for tests to be working
50
if os.environ.has_key('LDTP_DEBUG'):
51
del os.environ['LDTP_DEBUG'] # get rid of verbose LDTP output
52
if not os.environ.has_key('GNOME_ACCESSIBILITY') or os.environ['GNOME_ACCESSIBILITY'] != 1:
53
os.environ['GNOME_ACCESSIBILITY'] = '1'
55
def get_srcdir(self, buildscript):
56
return self.branch.srcdir
58
def get_revision(self):
59
return self.branch.branchname
61
def _get_display(self):
65
if not os.path.exists('/tmp/.X%s-lock' % servernum):
70
def _set_xauth(self, servernum):
72
paths = os.environ.get('PATH').split(':')
75
if os.path.exists(os.path.join(path, 'xauth')):
78
tmpdir = tempfile.gettempdir()
79
if not flag or os.path.exists(os.path.join(tmpdir,'jhbuild.%s' % os.getpid())):
83
os.mkdir(os.path.join(tmpdir,'jhbuild.%s' % os.getpid()))
84
new_xauth = os.path.join(tmpdir, 'jhbuild.%s' % os.getpid(),'Xauthority')
85
open(new_xauth, 'w').close()
86
hexdigest = md5.md5(str(random.random())).hexdigest()
87
os.system('xauth -f "%s" add ":%s" "." "%s"' % (
88
new_xauth, servernum, hexdigest))
93
def do_test(self, buildscript):
94
buildscript.set_action('Testing', self)
95
if not buildscript.config.noxvfb:
97
old_display = os.environ.get('DISPLAY')
98
old_xauth = os.environ.get('XAUTHORITY')
99
xvfb_pid = self._start_xvfb(buildscript.config.xvfbargs)
101
raise BuildStateError('Unable to start Xvfb')
103
# either do_ldtp_test or do_dogtail_test
104
method = getattr(self, 'do_' + self.test_type + '_test')
108
if not buildscript.config.noxvfb:
109
# kill Xvfb if it has been started
110
self._stop_xvfb(xvfb_pid)
112
os.environ['DISPLAY'] = old_display
114
os.unsetenv('DISPLAY')
116
os.environ['XAUTHORITY'] = old_xauth
118
os.unsetenv('XAUTHORITY')
119
do_test.depends = [PHASE_CHECKOUT]
121
def get_ldtp_log_file(self, filename):
124
# -- <logfile>filename</logfile>
125
run_file = xml.dom.minidom.parse(filename)
127
return run_file.getElementsByTagName('ldtp')[0].getElementsByTagName(
128
'logfile')[0].childNodes[0].data
132
def _get_ldtp_info(self, node):
137
for info in node.getElementsByTagName('info'):
138
for child in info.childNodes:
139
infos.append(child.data)
140
for cause in node.getElementsByTagName('cause'):
141
for child in cause.childNodes:
142
causes.append(child.data)
143
for error in node.getElementsByTagName('error'):
144
for child in error.childNodes:
145
errors.append(child.data)
146
for warning in node.getElementsByTagName('warning'):
147
for child in warning.childNodes:
148
warnings.append(child.data)
149
return infos, errors, causes, warnings
151
def _check_ldtp_log_file(self, logfile):
152
log_file = xml.dom.minidom.parse(logfile)
153
ldtp_node = log_file.getElementsByTagName('ldtp')[0]
156
for group in ldtp_node.getElementsByTagName('group'):
158
for script in group.getElementsByTagName('script'):
160
for test in script.getElementsByTagName('test'):
161
test_name = test.getAttribute('name')
163
pass_status = test.getElementsByTagName('pass')[0].childNodes[0].data
164
infos, errors, causes, warnings = self._get_ldtp_info(test)
173
infos, errors, causes, warnings = self._get_ldtp_info(script)
179
'warning': warnings})
181
groupstatus = group.getElementsByTagName('groupstatus')[0].childNodes[0].data
182
groups.append({'script': scr, 'groupstatus': groupstatus})
185
def check_groups(self, groups):
190
status += 'In Group #%s (%s)\n' % (group_num, group['groupstatus'])
191
for script in group['script']:
192
for test in script['tests'].keys():
193
status += 'Test \'%s\' ' % test
194
if script['tests'][test]['pass'] == '0': # failed
195
status += 'failed\n\tErrors'
196
for error in script['tests'][test]['error']:
200
status += '\n\tCauses'
201
for cause in script['tests'][test]['cause']:
205
status += '\n\tWarnings'
206
for warning in script['tests'][test]['warning']:
210
status += '\n\tInfos'
211
for info in script['tests'][test]['info']:
219
if self._check_ldtp_group_status(group['groupstatus']):
223
def _check_ldtp_group_status(self, status):
224
status = status.split()
225
if status[0] != status[-1]:
229
def _start_xvfb(self, xvfbargs):
230
new_display = self._get_display()
231
new_xauth = self._set_xauth(new_display)
235
os.environ['DISPLAY'] = ':' + new_display
236
os.environ['XAUTHORITY'] = new_xauth
238
xvfb = subprocess.Popen(
239
['Xvfb',':'+new_display] + xvfbargs.split(), shell=False)
240
self.screennum = new_display
241
self.xauth = new_xauth
245
time.sleep(2) #allow Xvfb to start
246
if xvfb.poll() != None:
250
def _stop_xvfb(self, xvfb_pid):
251
os.kill(xvfb_pid, signal.SIGINT)
252
os.system('xauth remove ":%s"' % self.screennum)
253
os.system('rm -r %s' % os.path.split(self.xauth)[0])
255
def _start_ldtp(self):
257
ldtp = subprocess.Popen('ldtp', shell=False)
261
if ldtp.poll() != None:
265
def do_ldtp_test(self, buildscript):
266
src_dir = self.get_srcdir(buildscript)
267
old_debug = os.getenv('LDTP_DEBUG')
268
if old_debug != None:
269
del os.environ['LDTP_DEBUG']
271
ldtp_pid = self._start_ldtp()
273
raise BuildStateError('Unable to start ldtp server')
276
if buildscript.config.noxvfb:
277
buildscript.execute('ldtprunner run.xml', cwd=src_dir)
279
buildscript.execute('ldtprunner run.xml', cwd=src_dir,
280
extra_env={'DISPLAY': ':%s' % self.screennum})
281
except CommandError, e:
282
os.kill(ldtp_pid, signal.SIGINT)
283
if e.returncode == 32512: # ldtprunner not installed
284
raise BuildStateError('ldtprunner not available')
285
raise BuildStateError('error %s during test' % e.returncode)
286
os.kill(ldtp_pid, signal.SIGINT)
288
if old_debug != None:
289
os.environ['LDTP_DEBUG'] = old_debug
291
log_file = self.get_ldtp_log_file(os.path.join (src_dir,'run.xml'))
293
raise BuildStateError('missing log file')
295
groups = self._check_ldtp_log_file(log_file)
296
flag, status = self.check_groups(groups)
298
raise BuildStateError(status)
300
raise BuildStateError('malformed log file')
302
def do_dogtail_test(self, buildscript):
303
src_dir = self.get_srcdir(buildscript)
306
all_files = os.listdir(src_dir)
307
for file in all_files:
308
if file[-3:] == '.py':
309
test_cases.append(file)
312
if buildscript.config.noxvfb:
315
extra_env = {'DISPLAY': ':%s' % self.screennum}
317
for test_case in test_cases:
319
buildscript.execute('python %s' % test_case,
320
cwd=src_dir, extra_env=extra_env)
321
except CommandError, e:
322
if e.returncode != 0:
323
raise BuildStateError('%s failed' % test_case)
325
def xml_tag_and_attrs(self):
326
return 'testmodule', [('id', 'name', None),
327
('type', 'test_type', None)]
329
def get_tested_packages(node):
331
for tested_module in node.getElementsByTagName('testedmodules'):
332
for mod in tested_module.getElementsByTagName('tested'):
333
tested_pkgs.append(mod.getAttribute('package'))
336
def parse_testmodule(node, config, uri, repositories, default_repo):
337
id = node.getAttribute('id')
338
test_type = node.getAttribute('type')
339
if test_type not in __test_types__:
340
# FIXME: create an error here
343
dependencies, after, suggests = get_dependencies(node)
344
branch = get_branch(node, repositories, default_repo, config)
345
tested_pkgs = get_tested_packages(node)
346
return TestModule(id, branch, test_type, dependencies=dependencies,
347
after=after, suggests=suggests, tested_pkgs=tested_pkgs)
349
register_module_type('testmodule', parse_testmodule)