~ubuntu-branches/ubuntu/lucid/jhbuild/lucid

« back to all changes in this revision

Viewing changes to jhbuild/modtypes/testmodule.py

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort, Loic Minier, Emilio Pozuelo Monfort
  • Date: 2009-11-09 20:28:48 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20091109202848-m9ec7dmzptqtchtj
Tags: 2.28.0-1
[ Loic Minier ]
* Cleanups.
* Ship scripts.
* Don't set GNOME_MODULE as it equals the name of the source package.

[ Emilio Pozuelo Monfort ]
* New upstream release. Closes: #524504.
  - Use 'git rev-parse' rather than 'git-rev-parse'. Closes: #544642.
* Ship install-check. Closes: #441008.
* Uploaders list regenerated. Closes: #523542, #554071.
* debian/control.in,
  debian/rules:
  - Stop shipping a copy of subprocess.py. Require python >= 2.4.
  - Switch to python-support.
* debian/control.in:
  - Bump Standards-Version to 3.8.3, no changes needed.
  - Build depend on intltool >= 0.35.0.
  - Build depend on pkg-config, gnome-doc-utils and rarian-compat to build
    the documentation.
  - Make jhbuild arch any since install-check is a binary. Depend on
    ${shlibs:Depends}.
  - Recommend, and not suggest, git-core. Also recommend mercurial.
* debian/watch:
  - Added.
* debian/patches/01_import_from_pkgdatadir.patch:
  - Added, import jhbuild from pkgdatadir if everything else fails.
    This way we can ship the jhbuild private modules in /usr/sharejhbuild.
* debian/jhbuild.docs:
  - Removed, the necessary docs are now installed by the upstream Makefile.
* debian/rules:
  - Include autotools.mk and gnome.mk.
  - Remove all the manual build process, autotools.mk does everything now.
  - Install the jhbuild modules in /usr/share/jhbuild.
* debian/install:
  - Install the modulesets and patches from here since the upstream build
    system doesn't install them.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# jhbuild - a build script for GNOME 1.x and 2.x
 
2
# Copyright (C) 2001-2006  James Henstridge
 
3
#
 
4
#   testmodule.py: testmodule type definitions.
 
5
#
 
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.
 
10
#
 
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.
 
15
#
 
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
 
19
 
 
20
__metaclass__ = type
 
21
 
 
22
import os, time, signal, sys, subprocess, random, md5, tempfile
 
23
 
 
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
 
28
 
 
29
import xml.dom.minidom
 
30
 
 
31
__all__ = ['TestModule']
 
32
__test_types__ = ['ldtp' , 'dogtail']
 
33
 
 
34
class TestModule(Package, DownloadableModule):
 
35
    type = 'test'
 
36
    
 
37
    PHASE_CHECKOUT = DownloadableModule.PHASE_CHECKOUT
 
38
    PHASE_FORCE_CHECKOUT = DownloadableModule.PHASE_FORCE_CHECKOUT
 
39
    PHASE_TEST           = 'test'
 
40
    
 
41
    def __init__(self, name, branch, test_type, dependencies=[], after=[], tested_pkgs=[]):
 
42
        Package.__init__(self, name)
 
43
        self.branch       = branch
 
44
        self.test_type    = test_type
 
45
        self.dependencies = dependencies
 
46
        self.after        = after
 
47
        self.tested_pkgs  = tested_pkgs
 
48
 
 
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'
 
54
 
 
55
    def get_srcdir(self, buildscript):
 
56
        return self.branch.srcdir
 
57
 
 
58
    def get_revision(self):
 
59
        return self.branch.branchname
 
60
 
 
61
    def _get_display(self):
 
62
        # get free display
 
63
        servernum = 99
 
64
        while True:
 
65
            if not os.path.exists('/tmp/.X%s-lock' % servernum):
 
66
                break
 
67
            servernum += 1
 
68
        return str(servernum)
 
69
 
 
70
    def _set_xauth(self, servernum):
 
71
        # create auth file
 
72
        paths = os.environ.get('PATH').split(':')
 
73
        flag = False
 
74
        for path in paths:
 
75
            if os.path.exists(os.path.join(path, 'xauth')):
 
76
                flag = True
 
77
                break
 
78
        tmpdir = tempfile.gettempdir()
 
79
        if not flag or os.path.exists(os.path.join(tmpdir,'jhbuild.%s' % os.getpid())):
 
80
            return ''
 
81
 
 
82
        try:
 
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))
 
89
        except OSError:
 
90
            return ''
 
91
        return new_xauth
 
92
    
 
93
    def do_test(self, buildscript):
 
94
        buildscript.set_action('Testing', self)
 
95
        if not buildscript.config.noxvfb:
 
96
            # start Xvfb
 
97
            old_display = os.environ.get('DISPLAY')
 
98
            old_xauth   = os.environ.get('XAUTHORITY')
 
99
            xvfb_pid = self._start_xvfb(buildscript.config.xvfbargs)
 
100
            if xvfb_pid == -1:
 
101
                raise BuildStateError('Unable to start Xvfb')
 
102
 
 
103
        # either do_ldtp_test or do_dogtail_test
 
104
        method = getattr(self, 'do_' + self.test_type + '_test')
 
105
        try:
 
106
            method(buildscript)
 
107
        finally:
 
108
            if not buildscript.config.noxvfb:
 
109
                # kill Xvfb if it has been started
 
110
                self._stop_xvfb(xvfb_pid)
 
111
                if old_display:
 
112
                    os.environ['DISPLAY'] = old_display
 
113
                else:
 
114
                    os.unsetenv('DISPLAY')
 
115
                if old_xauth:
 
116
                    os.environ['XAUTHORITY'] = old_xauth
 
117
                else:
 
118
                    os.unsetenv('XAUTHORITY')
 
119
    do_test.depends = [PHASE_CHECKOUT]
 
120
 
 
121
    def get_ldtp_log_file(self, filename):
 
122
        # <ldtp>
 
123
        # |
 
124
        # -- <logfile>filename</logfile>
 
125
        run_file = xml.dom.minidom.parse(filename)
 
126
        try:
 
127
            return run_file.getElementsByTagName('ldtp')[0].getElementsByTagName(
 
128
                    'logfile')[0].childNodes[0].data
 
129
        except IndexError:
 
130
            return None
 
131
 
 
132
    def _get_ldtp_info(self, node):
 
133
        infos = []
 
134
        errors = []
 
135
        warnings = []
 
136
        causes = []
 
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
 
150
        
 
151
    def _check_ldtp_log_file(self, logfile):
 
152
        log_file = xml.dom.minidom.parse(logfile)
 
153
        ldtp_node = log_file.getElementsByTagName('ldtp')[0]
 
154
 
 
155
        groups = []
 
156
        for group in ldtp_node.getElementsByTagName('group'):
 
157
            scr = []
 
158
            for script in group.getElementsByTagName('script'):
 
159
                tests = {}
 
160
                for test in script.getElementsByTagName('test'):
 
161
                    test_name = test.getAttribute('name')
 
162
                    
 
163
                    pass_status = test.getElementsByTagName('pass')[0].childNodes[0].data
 
164
                    infos, errors, causes, warnings = self._get_ldtp_info(test)
 
165
                    tests[test_name] = {
 
166
                        'pass': pass_status,
 
167
                        'info': infos,
 
168
                        'error': errors,
 
169
                        'cause': causes,
 
170
                        'warning': warnings
 
171
                    }
 
172
 
 
173
                infos, errors, causes, warnings = self._get_ldtp_info(script)
 
174
                scr.append({
 
175
                        'tests': tests,
 
176
                        'info': infos,
 
177
                        'error': errors,
 
178
                        'cause': causes,
 
179
                        'warning': warnings})
 
180
 
 
181
            groupstatus = group.getElementsByTagName('groupstatus')[0].childNodes[0].data
 
182
            groups.append({'script': scr, 'groupstatus': groupstatus})
 
183
        return groups
 
184
 
 
185
    def check_groups(self, groups):
 
186
        group_num = 1
 
187
        flag = False
 
188
        status = ''
 
189
        for group in 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']:
 
197
                            status += ', '
 
198
                            status += error
 
199
 
 
200
                        status += '\n\tCauses'
 
201
                        for cause in script['tests'][test]['cause']:
 
202
                            status += ', '
 
203
                            status += cause
 
204
 
 
205
                        status += '\n\tWarnings'
 
206
                        for warning in script['tests'][test]['warning']:
 
207
                            status += ', '
 
208
                            status += warning
 
209
 
 
210
                        status += '\n\tInfos'
 
211
                        for info in script['tests'][test]['info']:
 
212
                            status += ', '
 
213
                            status += info                        
 
214
                    else:
 
215
                        status += 'passed'
 
216
                    status += '\n'
 
217
 
 
218
            group_num += 1
 
219
            if self._check_ldtp_group_status(group['groupstatus']):
 
220
                flag = True
 
221
        return flag, status
 
222
    
 
223
    def _check_ldtp_group_status(self, status):
 
224
        status = status.split()
 
225
        if status[0] != status[-1]:
 
226
            return True
 
227
        return False
 
228
 
 
229
    def _start_xvfb(self, xvfbargs):
 
230
        new_display = self._get_display()
 
231
        new_xauth   = self._set_xauth(new_display)
 
232
        if new_xauth == '':
 
233
            return -1
 
234
 
 
235
        os.environ['DISPLAY'] = ':' + new_display
 
236
        os.environ['XAUTHORITY'] = new_xauth
 
237
        try:
 
238
            xvfb = subprocess.Popen(
 
239
                    ['Xvfb',':'+new_display] + xvfbargs.split(), shell=False)
 
240
            self.screennum = new_display
 
241
            self.xauth = new_xauth
 
242
        except OSError:
 
243
            return -1
 
244
        
 
245
        time.sleep(2) #allow Xvfb to start
 
246
        if xvfb.poll() != None:
 
247
            return -1
 
248
        return xvfb.pid
 
249
 
 
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])
 
254
            
 
255
    def _start_ldtp(self):
 
256
        try:
 
257
            ldtp = subprocess.Popen('ldtp', shell=False)
 
258
        except OSError:
 
259
            return -1
 
260
        time.sleep(1)
 
261
        if ldtp.poll() != None:
 
262
            return -1
 
263
        return ldtp.pid
 
264
    
 
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']
 
270
 
 
271
        ldtp_pid = self._start_ldtp()
 
272
        if ldtp_pid == -1:
 
273
            raise BuildStateError('Unable to start ldtp server')
 
274
 
 
275
        try:
 
276
            if buildscript.config.noxvfb:
 
277
                buildscript.execute('ldtprunner run.xml', cwd=src_dir)
 
278
            else:
 
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)
 
287
        
 
288
        if old_debug != None:
 
289
            os.environ['LDTP_DEBUG'] = old_debug
 
290
        
 
291
        log_file = self.get_ldtp_log_file(os.path.join (src_dir,'run.xml'))
 
292
        if not log_file:
 
293
            raise BuildStateError('missing log file')
 
294
        try:
 
295
            groups = self._check_ldtp_log_file(log_file)
 
296
            flag, status = self.check_groups(groups)
 
297
            if flag:
 
298
                raise BuildStateError(status)
 
299
        except:
 
300
            raise BuildStateError('malformed log file')
 
301
 
 
302
    def do_dogtail_test(self, buildscript):
 
303
        src_dir = self.get_srcdir(buildscript)
 
304
        test_cases = []
 
305
        failed = False
 
306
        all_files = os.listdir(src_dir)
 
307
        for file in all_files:
 
308
            if file[-3:] == '.py':
 
309
                test_cases.append(file)
 
310
 
 
311
        status = ''
 
312
        if buildscript.config.noxvfb:
 
313
            extra_env = {}
 
314
        else:
 
315
            extra_env = {'DISPLAY': ':%s' % self.screennum}
 
316
 
 
317
        for test_case in test_cases:
 
318
            try:
 
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)
 
324
 
 
325
    def xml_tag_and_attrs(self):
 
326
        return 'testmodule', [('id', 'name', None),
 
327
                              ('type', 'test_type', None)]
 
328
 
 
329
def get_tested_packages(node):
 
330
    tested_pkgs = []
 
331
    for tested_module in node.getElementsByTagName('testedmodules'):
 
332
        for mod in tested_module.getElementsByTagName('tested'):
 
333
            tested_pkgs.append(mod.getAttribute('package'))
 
334
    return tested_pkgs
 
335
 
 
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
 
341
        pass
 
342
 
 
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)
 
348
                                   
 
349
register_module_type('testmodule', parse_testmodule)