File: AutoPkgTest.py

package info (click to toggle)
debomatic 0.13-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 716 kB
  • ctags: 153
  • sloc: python: 1,653; sh: 74; makefile: 46
file content (210 lines) | stat: -rw-r--r-- 7,902 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# Deb-o-Matic - AutoPkgTest module
#
# Copyright (C) 2014 Leo Iannacone
#
# Authors: Leo Iannacone <l3on@ubuntu.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#
# Run autpkgtest and stores output on top of the built
# package in the pool directory.
#
# Can be configured by adding this section to the config file:
#
# [autopkgtest]
# options: [adt-run options]
# logging: [True|False] # enable builder log into the logs directory
# gpghome: /path/to/gnupg-home # set the gnupg home for adt-run
#

import os
from subprocess import call
from time import strftime
from shutil import rmtree
from tempfile import NamedTemporaryFile


class DebomaticModule_AutoPkgTest:

    def __init__(self):
        self.after = ['Piuparts']
        self.options = []
        self.logging = False
        self.dsc = None
        self.gpghome = '/var/cache/debomatic/autopkgtest'

    def _set_up_commons(self, args):
        """Set up common variables for pre and post build hooks"""
        # the package result dir
        self.resultdir = os.path.join(args['directory'],
                                      'pool',
                                      args['package'])
        # output is the final output file log
        self.output = os.path.join(self.resultdir,
                                   args['package']) + '.autopkgtest'

    def _set_up_testbed(self, args):
        """Performs:
         - check if dsc exists and declares a Testsuite
         - get autopkgtest options from the config
         - set up needed variables and files
        Returns True if test can be executed, False otherwise"""

        # check if dsc exists and it contains the Testsuite field
        autopkgtest_found = False
        for filename in os.listdir(self.resultdir):
            if filename.endswith('.dsc'):
                self.dsc = os.path.join(self.resultdir, filename)
                with open(self.dsc, 'r') as fd:
                    for line in fd:
                        if line.find('Testsuite: autopkgtest') >= 0:
                            autopkgtest_found = True
                            break
                break
        if not self.dsc or not autopkgtest_found:
            return False

        # get autopkgtest options
        if args['opts'].has_section('autopkgtest'):
            def get_option(o):
                if args['opts'].has_option('autopkgtest', o):
                    return args['opts'].get('autopkgtest', o).strip()
                return ''
            self.options = get_option('options').split()
            self.logging = get_option('logging').lower() == 'true'
            # gpghome is where adt has its own gpg and it is also used
            # as tmp directory to put the scripts
            gpghome = get_option('gpghome')
            if gpghome:
                self.gpghome = gpghome

        # set up atd-run output dir
        self.resultdir_adt = os.path.join(self.resultdir, 'adt_out_dir')

        # summary is where test summary is stored, relative to resultdir_adt
        self.summary = 'log_summary'

        # script is the main script launched through the builder, a tmp file
        tmpfd = NamedTemporaryFile(dir=self.gpghome, delete=False)
        tmpfd.close()
        self.script = tmpfd.name
        self._make_script()
        return True

    def _make_script(self):
        """Makes a bash script to being easily called through the builder.
        The script installs autopkgtest and then run adt-run."""
        adt = ['adt-run']
        adt += ('--gnupg-home', self.gpghome)
        adt += ('--summary', os.path.join(self.resultdir_adt, self.summary))
        adt += ('--output-dir', self.resultdir_adt)
        adt += self.options
        # add debs
        adt += (os.path.join(self.resultdir, f)
                for f in os.listdir(self.resultdir)
                if f.endswith('.deb'))
        adt += (self.dsc, '---', 'null')
        self.adt = ' '.join(adt)

        content = ["#!/bin/bash"]
        content.append('apt-get install -y autopkgtest')
        content.append(self.adt)

        if not os.path.isdir(self.gpghome):
            os.makedirs(self.gpghome)
        with open(self.script, 'w') as fd:
            fd.write('\n'.join(content))

    def _finish(self):
        """Clean up the system"""
        if os.path.isfile(self.script):
            os.remove(self.script)
        if (os.path.isdir(self.resultdir_adt)):
            rmtree(self.resultdir_adt)

    def post_build(self, args):
        if not args['success']:
            return

        self._set_up_commons(args)
        if not self._set_up_testbed(args):
            return

        # the output file descriptor
        output = open(self.output, 'w')

        def write_header(header, symbol='~'):
            header = '{}{: ^70}{}'.format(symbol, header, symbol)
            output.write(symbol * len(header) + '\n')
            output.write(header + '\n')
            output.write(symbol * len(header) + '\n')
            output.flush()

        def append_file(source, new_lines_at_the_end=True):
            if not source.startswith('/'):
                source = os.path.join(self.resultdir_adt, source)
            if os.path.isfile(source):
                with open(source, 'r') as fd:
                    for line in fd:
                        output.write(line)
                    if new_lines_at_the_end:
                        output.write('\n\n')
                output.flush()

        # write the current adt-run command
        write_header('Command')
        output.write(self.adt)
        output.write('\n\n\n')
        output.flush()

        # call the builder and run adt-run
        builder = args['opts'].get('default', 'builder')
        base = '--basepath' if builder == 'cowbuilder' else '--basetgz'
        with open(os.devnull, 'w') as fd:
            cmd = [builder, '--execute', '--override-config']
            cmd += (base, '%s/%s' % (args['directory'], args['distribution']))
            cmd += ('--architecture', args['architecture'])
            cmd += ('--buildplace', '%s/build' % args['directory'])
            cmd += ('--aptcache', '%s/aptcache' % args['directory'])
            cmd += ('--hookdir', args['opts'].get('default', 'pbuilderhooks'))
            cmd += ('--configfile', args['cfg'])
            cmd += ('--bindmount', self.gpghome)
            cmd += ('--bindmount', self.resultdir)

            if self.logging:
                cmd += ('--logfile', '%s/logs/%s.%s' % (args['directory'],
                        'autopkgtest', strftime('%Y%m%d_%H%M%S')))

            cmd += ('--', '/bin/bash', self.script)

            call(cmd, stdout=fd, stderr=fd)

        # build the log properly, first append the summary
        write_header('Tests summary')
        append_file(self.summary)

        # then the log
        write_header('Full log')
        append_file('log')

        # then the others
        all_files = [f for f in os.listdir(self.resultdir_adt) if
                     os.path.isfile(os.path.join(self.resultdir_adt, f))
                     and f not in ['log', self.summary]]
        for curr_file in all_files:
            write_header('File: %s' % curr_file)
            append_file(curr_file, curr_file != all_files[-1])

        output.close()
        self._finish()