Add first tests for the autopkgtest integration

This currently checks that an autopkgtest is triggered for an installable
package, and that no autopkgtest is triggered for an uninstallable one
(failing, demonstrating a bug).
bzr-import-20160707
Martin Pitt 11 years ago
parent 33c441c500
commit e1dc047c7e

@ -0,0 +1,262 @@
#!/usr/bin/python
# (C) 2014 Canonical Ltd.
#
# 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; either version 2 of the License, or
# (at your option) any later version.
import tempfile
import shutil
import os
import sys
import subprocess
import unittest
architectures = ['amd64', 'arm64', 'armhf', 'i386', 'powerpc', 'ppc64el']
my_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
class TestData:
def __init__(self):
'''Construct local test package indexes.
The archive is initially empty. You can create new packages with
create_deb(). self.path contains the path of the archive, and
self.apt_source provides an apt source "deb" line.
It is kept in a temporary directory which gets removed when the Archive
object gets deleted.
'''
self.path = tempfile.mkdtemp(prefix='testarchive.')
self.apt_source = 'deb file://%s /' % self.path
self.dirs = {False: os.path.join(self.path, 'data', 'testing'),
True: os.path.join(self.path, 'data', 'unstable')}
os.makedirs(self.dirs[False])
os.mkdir(self.dirs[True])
self.added_sources = {False: set(), True: set()}
self.added_binaries = {False: set(), True: set()}
# pre-create all files for all architectures
for arch in architectures:
for dir in self.dirs.values():
with open(os.path.join(dir, 'Packages_' + arch), 'w'):
pass
for dir in self.dirs.values():
for fname in ['Dates', 'Blocks']:
with open(os.path.join(dir, fname), 'w'):
pass
for dname in ['Hints']:
os.mkdir(os.path.join(dir, dname))
os.mkdir(os.path.join(self.path, 'output'))
# create temporary home dir for proposed-migration autopktest status
self.home = os.path.join(self.path, 'home')
os.environ['HOME'] = self.home
os.makedirs(os.path.join(self.home, 'proposed-migration',
'autopkgtest', 'work'))
def __del__(self):
shutil.rmtree(self.path)
def add(self, name, unstable, fields={}, add_src=True):
'''Add a binary package to the index file.
You need to specify at least the package name and in which list to put
it (unstable==True for unstable/proposed, or False for
testing/release). fields specifies all additional entries, e. g.
{'Depends': 'foo, bar', 'Conflicts: baz'}. There are defaults for most
fields.
Unless add_src is set to False, this will also automatically create a
source record, based on fields['Source'] and name.
'''
assert (name not in self.added_binaries[unstable])
self.added_binaries[unstable].add(name)
fields.setdefault('Architecture', architectures[0])
fields.setdefault('Version', '1')
fields.setdefault('Priority', 'optional')
fields.setdefault('Section', 'devel')
fields.setdefault('Description', 'test pkg')
if fields['Architecture'] == 'all':
for a in architectures:
self._append(name, unstable, 'Packages_' + a, fields)
else:
self._append(name, unstable, 'Packages_' + fields['Architecture'],
fields)
if add_src:
src = fields.get('Source', name)
if src not in self.added_sources[unstable]:
self.add_src(src, unstable, {'Version': fields['Version'],
'Section': fields['Section']})
def add_src(self, name, unstable, fields={}):
'''Add a source package to the index file.
You need to specify at least the package name and in which list to put
it (unstable==True for unstable/proposed, or False for
testing/release). fields specifies all additional entries, which can be
Version (default: 1), Section (default: devel), and Extra-Source-Only.
'''
assert (name not in self.added_sources[unstable])
self.added_sources[unstable].add(name)
fields.setdefault('Version', '1')
fields.setdefault('Section', 'devel')
self._append(name, unstable, 'Sources', fields)
def _append(self, name, unstable, file_name, fields):
with open(os.path.join(self.dirs[unstable], file_name), 'a') as f:
f.write('''Package: %s
Maintainer: Joe <joe@example.com>
''' % name)
for k, v in fields.items():
f.write('%s: %s\n' % (k, v))
f.write('\n')
class Test(unittest.TestCase):
def setUp(self):
self.data = TestData()
# add a bunch of packages to testing to avoid repetition
self.data.add('libc6', False)
self.data.add('libgreen1', False, {'Source': 'green',
'Depends': 'libc6 (>= 0.9)'})
self.data.add('green', False, {'Depends': 'libc6 (>= 0.9), libgreen1',
'Conflicts': 'green'})
self.data.add('blue', False, {'Depends': 'libc6 (>= 0.9)',
'Conflicts': 'green'})
self.data.add('justdata', False, {'Architecture': 'all'})
self.britney = os.path.join(my_dir, 'britney.py')
self.britney_conf = os.path.join(my_dir, 'britney.conf')
assert os.path.exists(self.britney)
assert os.path.exists(self.britney_conf)
# fake adt-britney script
self.adt_britney = os.path.join(self.data.home, 'auto-package-testing',
'jenkins', 'adt-britney')
os.makedirs(os.path.dirname(self.adt_britney))
with open(self.adt_britney, 'w') as f:
f.write('''#!/bin/sh -e
echo "$@" >> /%s/adt-britney.log ''' % self.data.path)
os.chmod(self.adt_britney, 0o755)
def tearDown(self):
del self.data
def make_adt_britney(self, request):
with open(self.adt_britney, 'w') as f:
f.write('''#!%(py)s
import argparse, shutil,sys
def request():
if args.req:
shutil.copy(args.req, '%(path)s/adt-britney.requestarg')
with open(args.output, 'w') as f:
f.write("""%(rq)s""".replace('PASS', 'NEW').replace('FAIL', 'NEW'))
def submit():
with open(args.req, 'w') as f:
f.write("""%(rq)s""".replace('PASS', 'RUNNING').
replace('FAIL', 'RUNNING'))
def collect():
with open(args.output, 'w') as f:
f.write("""%(rq)s""")
p = argparse.ArgumentParser()
p.add_argument('-c', '--config')
p.add_argument('-a', '--arch')
p.add_argument('-r', '--release')
p.add_argument('-P', '--use-proposed', action='store_true')
p.add_argument('-U', '--no-update', action='store_true')
sp = p.add_subparsers()
prequest = sp.add_parser('request')
prequest.add_argument('-O', '--output')
prequest.add_argument('req', nargs='?')
prequest.set_defaults(func=request)
psubmit = sp.add_parser('submit')
psubmit.add_argument('req')
psubmit.set_defaults(func=submit)
pcollect = sp.add_parser('collect')
pcollect.add_argument('-O', '--output')
pcollect.add_argument('-n', '--new-only', action='store_true', default=False)
pcollect.set_defaults(func=collect)
args = p.parse_args()
args.func()
''' % {'py': sys.executable, 'path': self.data.path, 'rq': request})
def run_britney(self, args=[]):
'''Run britney and return (exit, out, err)'''
britney = subprocess.Popen([self.britney, '-c', self.britney_conf],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=self.data.path,
universal_newlines=True)
(out, err) = britney.communicate()
return (britney.returncode, out, err)
def test_no_request_for_uninstallable(self):
'''Does not request a test for an uninstallable package'''
# uninstallable unstable version
self.data.add('green', True,
{'Version': '1.1~beta',
'Depends': 'libc6 (>= 0.9), libgreen1 (>= 2)'})
self.make_adt_britney('green 1.1~beta FAIL green 1.1~beta\n')
(c, o, e) = self.run_britney()
self.assertEqual(e, '', e)
self.assertEqual(c, 0, o + e)
with open(os.path.join(self.data.path, 'output', 'excuses.html')) as f:
excuses = f.read()
self.assertIn('green/amd64 unsatisfiable Depends: libgreen1 (>= 2)', excuses)
# does not request autopkgtest for uninstallable package
self.assertNotIn('autopkgtest', excuses)
def test_request_for_installable(self):
'''Requests a test for an installable package'''
# installable unstable version
self.data.add('green', True,
{'Version': '1.1~beta',
'Depends': 'libc6 (>= 0.9), libgreen1'})
self.make_adt_britney('green 1.1~beta RUNNING green 1.1~beta\n')
(c, o, e) = self.run_britney()
self.assertEqual(c, 0, o + e)
self.assertEqual(e, '')
with open(os.path.join(self.data.path, 'output', 'excuses.html')) as f:
excuses = f.read()
self.assertRegexpMatches(excuses, r'\bgreen\b.*>1</a> to .*>1.1~beta<')
self.assertIn('<li>autopkgtest for green 1.1~beta: RUNNING', excuses)
def shell(self):
# uninstallable unstable version
self.data.add('yellow', True, {'Version': '1.1~beta',
'Depends': 'libc6 (>= 0.9), nosuchpkg'})
self.make_adt_britney('yellow 1.1~beta RUNNING yellow 1.1~beta\n')
print('run:\n%s -c %s\n' % (self.britney, self.britney_conf))
subprocess.call(['bash', '-i'], cwd=self.data.path)
unittest.main()
Loading…
Cancel
Save