Merge lp:~cprov/britney/test-refactoring into lp:~ubuntu-release/britney/britney2-ubuntu

Proposed by Celso Providelo
Status: Merged
Merged at revision: 430
Proposed branch: lp:~cprov/britney/test-refactoring
Merge into: lp:~ubuntu-release/britney/britney2-ubuntu
Diff against target: 441 lines (+209/-183)
2 files modified
tests/__init__.py (+159/-0)
tests/test_autopkgtest.py (+50/-183)
To merge this branch: bzr merge lp:~cprov/britney/test-refactoring
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Ubuntu Release Team Pending
Review via email: mp+247319@code.launchpad.net

Commit message

Basic testing refactoring before we can implement "boottest" support.

Description of the change

Basic testing refactoring before we can implement "boottest" support.

To post a comment you must log in.
lp:~cprov/britney/test-refactoring updated
431. By Celso Providelo

Reverting whitespace cleanup.

Revision history for this message
Colin Watson (cjwatson) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'tests/__init__.py'
2--- tests/__init__.py 1970-01-01 00:00:00 +0000
3+++ tests/__init__.py 2015-01-22 17:16:43 +0000
4@@ -0,0 +1,159 @@
5+# (C) 2015 Canonical Ltd.
6+#
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+import os
13+import shutil
14+import subprocess
15+import tempfile
16+import unittest
17+
18+
19+PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
20+
21+architectures = ['amd64', 'arm64', 'armhf', 'i386', 'powerpc', 'ppc64el']
22+
23+
24+class TestData:
25+
26+ def __init__(self):
27+ '''Construct local test package indexes.
28+
29+ The archive is initially empty. You can create new packages with
30+ create_deb(). self.path contains the path of the archive, and
31+ self.apt_source provides an apt source "deb" line.
32+
33+ It is kept in a temporary directory which gets removed when the Archive
34+ object gets deleted.
35+ '''
36+ self.path = tempfile.mkdtemp(prefix='testarchive.')
37+ self.apt_source = 'deb file://%s /' % self.path
38+ self.series = 'series'
39+ self.dirs = {False: os.path.join(self.path, 'data', self.series),
40+ True: os.path.join(
41+ self.path, 'data', '%s-proposed' % self.series)}
42+ os.makedirs(self.dirs[False])
43+ os.mkdir(self.dirs[True])
44+ self.added_sources = {False: set(), True: set()}
45+ self.added_binaries = {False: set(), True: set()}
46+
47+ # pre-create all files for all architectures
48+ for arch in architectures:
49+ for dir in self.dirs.values():
50+ with open(os.path.join(dir, 'Packages_' + arch), 'w'):
51+ pass
52+ for dir in self.dirs.values():
53+ for fname in ['Dates', 'Blocks']:
54+ with open(os.path.join(dir, fname), 'w'):
55+ pass
56+ for dname in ['Hints']:
57+ os.mkdir(os.path.join(dir, dname))
58+
59+ os.mkdir(os.path.join(self.path, 'output'))
60+
61+ # create temporary home dir for proposed-migration autopktest status
62+ self.home = os.path.join(self.path, 'home')
63+ os.environ['HOME'] = self.home
64+ os.makedirs(os.path.join(self.home, 'proposed-migration',
65+ 'autopkgtest', 'work'))
66+
67+ def __del__(self):
68+ shutil.rmtree(self.path)
69+
70+ def add(self, name, unstable, fields={}, add_src=True):
71+ '''Add a binary package to the index file.
72+
73+ You need to specify at least the package name and in which list to put
74+ it (unstable==True for unstable/proposed, or False for
75+ testing/release). fields specifies all additional entries, e. g.
76+ {'Depends': 'foo, bar', 'Conflicts: baz'}. There are defaults for most
77+ fields.
78+
79+ Unless add_src is set to False, this will also automatically create a
80+ source record, based on fields['Source'] and name.
81+ '''
82+ assert (name not in self.added_binaries[unstable])
83+ self.added_binaries[unstable].add(name)
84+
85+ fields.setdefault('Architecture', architectures[0])
86+ fields.setdefault('Version', '1')
87+ fields.setdefault('Priority', 'optional')
88+ fields.setdefault('Section', 'devel')
89+ fields.setdefault('Description', 'test pkg')
90+ if fields['Architecture'] == 'all':
91+ for a in architectures:
92+ self._append(name, unstable, 'Packages_' + a, fields)
93+ else:
94+ self._append(name, unstable, 'Packages_' + fields['Architecture'],
95+ fields)
96+
97+ if add_src:
98+ src = fields.get('Source', name)
99+ if src not in self.added_sources[unstable]:
100+ self.add_src(src, unstable, {'Version': fields['Version'],
101+ 'Section': fields['Section']})
102+
103+ def add_src(self, name, unstable, fields={}):
104+ '''Add a source package to the index file.
105+
106+ You need to specify at least the package name and in which list to put
107+ it (unstable==True for unstable/proposed, or False for
108+ testing/release). fields specifies all additional entries, which can be
109+ Version (default: 1), Section (default: devel), and Extra-Source-Only.
110+ '''
111+ assert (name not in self.added_sources[unstable])
112+ self.added_sources[unstable].add(name)
113+
114+ fields.setdefault('Version', '1')
115+ fields.setdefault('Section', 'devel')
116+ self._append(name, unstable, 'Sources', fields)
117+
118+ def _append(self, name, unstable, file_name, fields):
119+ with open(os.path.join(self.dirs[unstable], file_name), 'a') as f:
120+ f.write('''Package: %s
121+Maintainer: Joe <joe@example.com>
122+''' % name)
123+
124+ for k, v in fields.items():
125+ f.write('%s: %s\n' % (k, v))
126+ f.write('\n')
127+
128+
129+class TestBase(unittest.TestCase):
130+
131+ def setUp(self):
132+ super(TestBase, self).setUp()
133+ self.data = TestData()
134+ self.britney = os.path.join(PROJECT_DIR, 'britney.py')
135+ self.britney_conf = os.path.join(PROJECT_DIR, 'britney.conf')
136+ assert os.path.exists(self.britney)
137+ assert os.path.exists(self.britney_conf)
138+
139+ def tearDown(self):
140+ del self.data
141+
142+ def run_britney(self, args=[]):
143+ '''Run britney.
144+
145+ Assert that it succeeds and does not produce anything on stderr.
146+ Return (excuses.html, britney_out).
147+ '''
148+ britney = subprocess.Popen([self.britney, '-v', '-c', self.britney_conf,
149+ '--distribution=ubuntu',
150+ '--series=%s' % self.data.series],
151+ stdout=subprocess.PIPE,
152+ stderr=subprocess.PIPE,
153+ cwd=self.data.path,
154+ universal_newlines=True)
155+ (out, err) = britney.communicate()
156+ self.assertEqual(britney.returncode, 0, out + err)
157+ self.assertEqual(err, '')
158+
159+ with open(os.path.join(self.data.path, 'output', self.data.series,
160+ 'excuses.html')) as f:
161+ excuses = f.read()
162+
163+ return (excuses, out)
164
165=== modified file 'tests/test_autopkgtest.py'
166--- tests/test_autopkgtest.py 2014-12-10 10:42:27 +0000
167+++ tests/test_autopkgtest.py 2015-01-22 17:16:43 +0000
168@@ -6,133 +6,40 @@
169 # the Free Software Foundation; either version 2 of the License, or
170 # (at your option) any later version.
171
172-import tempfile
173-import shutil
174+import apt_pkg
175+import operator
176 import os
177 import sys
178 import subprocess
179 import unittest
180-import apt_pkg
181-import operator
182-
183-apt_pkg.init()
184-architectures = ['amd64', 'arm64', 'armhf', 'i386', 'powerpc', 'ppc64el']
185-
186-my_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
187+
188+PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
189+sys.path.insert(0, PROJECT_DIR)
190+
191+from autopkgtest import ADT_EXCUSES_LABELS
192+from tests import TestBase
193
194 NOT_CONSIDERED = False
195 VALID_CANDIDATE = True
196
197-sys.path.insert(0, my_dir)
198-from autopkgtest import ADT_EXCUSES_LABELS
199-
200-
201-class TestData:
202- def __init__(self):
203- '''Construct local test package indexes.
204-
205- The archive is initially empty. You can create new packages with
206- create_deb(). self.path contains the path of the archive, and
207- self.apt_source provides an apt source "deb" line.
208-
209- It is kept in a temporary directory which gets removed when the Archive
210- object gets deleted.
211- '''
212- self.path = tempfile.mkdtemp(prefix='testarchive.')
213- self.apt_source = 'deb file://%s /' % self.path
214- self.series = 'series'
215- self.dirs = {False: os.path.join(self.path, 'data', self.series),
216- True: os.path.join(self.path, 'data', '%s-proposed' % self.series)}
217- os.makedirs(self.dirs[False])
218- os.mkdir(self.dirs[True])
219- self.added_sources = {False: set(), True: set()}
220- self.added_binaries = {False: set(), True: set()}
221-
222- # pre-create all files for all architectures
223- for arch in architectures:
224- for dir in self.dirs.values():
225- with open(os.path.join(dir, 'Packages_' + arch), 'w'):
226- pass
227- for dir in self.dirs.values():
228- for fname in ['Dates', 'Blocks']:
229- with open(os.path.join(dir, fname), 'w'):
230- pass
231- for dname in ['Hints']:
232- os.mkdir(os.path.join(dir, dname))
233-
234- os.mkdir(os.path.join(self.path, 'output'))
235-
236- # create temporary home dir for proposed-migration autopktest status
237- self.home = os.path.join(self.path, 'home')
238- os.environ['HOME'] = self.home
239- os.makedirs(os.path.join(self.home, 'proposed-migration',
240- 'autopkgtest', 'work'))
241-
242- def __del__(self):
243- shutil.rmtree(self.path)
244-
245- def add(self, name, unstable, fields={}, add_src=True):
246- '''Add a binary package to the index file.
247-
248- You need to specify at least the package name and in which list to put
249- it (unstable==True for unstable/proposed, or False for
250- testing/release). fields specifies all additional entries, e. g.
251- {'Depends': 'foo, bar', 'Conflicts: baz'}. There are defaults for most
252- fields.
253-
254- Unless add_src is set to False, this will also automatically create a
255- source record, based on fields['Source'] and name.
256- '''
257- assert (name not in self.added_binaries[unstable])
258- self.added_binaries[unstable].add(name)
259-
260- fields.setdefault('Architecture', architectures[0])
261- fields.setdefault('Version', '1')
262- fields.setdefault('Priority', 'optional')
263- fields.setdefault('Section', 'devel')
264- fields.setdefault('Description', 'test pkg')
265- if fields['Architecture'] == 'all':
266- for a in architectures:
267- self._append(name, unstable, 'Packages_' + a, fields)
268- else:
269- self._append(name, unstable, 'Packages_' + fields['Architecture'],
270- fields)
271-
272- if add_src:
273- src = fields.get('Source', name)
274- if src not in self.added_sources[unstable]:
275- self.add_src(src, unstable, {'Version': fields['Version'],
276- 'Section': fields['Section']})
277-
278- def add_src(self, name, unstable, fields={}):
279- '''Add a source package to the index file.
280-
281- You need to specify at least the package name and in which list to put
282- it (unstable==True for unstable/proposed, or False for
283- testing/release). fields specifies all additional entries, which can be
284- Version (default: 1), Section (default: devel), and Extra-Source-Only.
285- '''
286- assert (name not in self.added_sources[unstable])
287- self.added_sources[unstable].add(name)
288-
289- fields.setdefault('Version', '1')
290- fields.setdefault('Section', 'devel')
291- self._append(name, unstable, 'Sources', fields)
292-
293- def _append(self, name, unstable, file_name, fields):
294- with open(os.path.join(self.dirs[unstable], file_name), 'a') as f:
295- f.write('''Package: %s
296-Maintainer: Joe <joe@example.com>
297-''' % name)
298-
299- for k, v in fields.items():
300- f.write('%s: %s\n' % (k, v))
301- f.write('\n')
302-
303-
304-class Test(unittest.TestCase):
305+
306+apt_pkg.init()
307+
308+
309+class TestAutoPkgTest(TestBase):
310+
311 def setUp(self):
312- self.data = TestData()
313+ super(TestAutoPkgTest, self).setUp()
314+
315+ # fake adt-britney script
316+ self.adt_britney = os.path.join(
317+ self.data.home, 'auto-package-testing', 'jenkins', 'adt-britney')
318+ os.makedirs(os.path.dirname(self.adt_britney))
319+
320+ with open(self.adt_britney, 'w') as f:
321+ f.write('''#!/bin/sh -e
322+echo "$@" >> /%s/adt-britney.log ''' % self.data.path)
323+ os.chmod(self.adt_britney, 0o755)
324
325 # add a bunch of packages to testing to avoid repetition
326 self.data.add('libc6', False)
327@@ -146,24 +53,6 @@
328 'Conflicts': 'green'})
329 self.data.add('justdata', False, {'Architecture': 'all'})
330
331- self.britney = os.path.join(my_dir, 'britney.py')
332- self.britney_conf = os.path.join(my_dir, 'britney.conf')
333- assert os.path.exists(self.britney)
334- assert os.path.exists(self.britney_conf)
335-
336- # fake adt-britney script
337- self.adt_britney = os.path.join(self.data.home, 'auto-package-testing',
338- 'jenkins', 'adt-britney')
339- os.makedirs(os.path.dirname(self.adt_britney))
340-
341- with open(self.adt_britney, 'w') as f:
342- f.write('''#!/bin/sh -e
343-echo "$@" >> /%s/adt-britney.log ''' % self.data.path)
344- os.chmod(self.adt_britney, 0o755)
345-
346- def tearDown(self):
347- del self.data
348-
349 def __merge_records(self, results, history=""):
350 '''Merges a list of results with records in history.
351
352@@ -235,28 +124,29 @@
353 'rq': request,
354 'res': self.__merge_records(request, history)})
355
356- def run_britney(self, args=[]):
357- '''Run britney.
358-
359- Assert that it succeeds and does not produce anything on stderr.
360- Return (excuses.html, britney_out).
361- '''
362- britney = subprocess.Popen([self.britney, '-v', '-c', self.britney_conf,
363- '--distribution=ubuntu',
364- '--series=%s' % self.data.series],
365- stdout=subprocess.PIPE,
366- stderr=subprocess.PIPE,
367- cwd=self.data.path,
368- universal_newlines=True)
369- (out, err) = britney.communicate()
370- self.assertEqual(britney.returncode, 0, out + err)
371- self.assertEqual(err, '')
372-
373- with open(os.path.join(self.data.path, 'output', self.data.series,
374- 'excuses.html')) as f:
375- excuses = f.read()
376-
377- return (excuses, out)
378+ def do_test(self, unstable_add, adt_request, considered, expect=None,
379+ no_expect=None, history=""):
380+ for (pkg, fields) in unstable_add:
381+ self.data.add(pkg, True, fields)
382+
383+ self.make_adt_britney(adt_request, history)
384+
385+ (excuses, out) = self.run_britney()
386+ #print('-------\nexcuses: %s\n-----' % excuses)
387+ #print('-------\nout: %s\n-----' % out)
388+ #print('run:\n%s -c %s\n' % (self.britney, self.britney_conf))
389+ #subprocess.call(['bash', '-i'], cwd=self.data.path)
390+ if considered:
391+ self.assertIn('Valid candidate', excuses)
392+ else:
393+ self.assertIn('Not considered', excuses)
394+
395+ if expect:
396+ for re in expect:
397+ self.assertRegexpMatches(excuses, re)
398+ if no_expect:
399+ for re in no_expect:
400+ self.assertNotRegexpMatches(excuses, re)
401
402 def test_no_request_for_uninstallable(self):
403 '''Does not request a test for an uninstallable package'''
404@@ -557,30 +447,6 @@
405 history="lightgreen 1 PASS lightgreen 1"
406 )
407
408- def do_test(self, unstable_add, adt_request, considered, expect=None,
409- no_expect=None, history=""):
410- for (pkg, fields) in unstable_add:
411- self.data.add(pkg, True, fields)
412-
413- self.make_adt_britney(adt_request, history)
414-
415- (excuses, out) = self.run_britney()
416- #print('-------\nexcuses: %s\n-----' % excuses)
417- #print('-------\nout: %s\n-----' % out)
418- #print('run:\n%s -c %s\n' % (self.britney, self.britney_conf))
419- #subprocess.call(['bash', '-i'], cwd=self.data.path)
420- if considered:
421- self.assertIn('Valid candidate', excuses)
422- else:
423- self.assertIn('Not considered', excuses)
424-
425- if expect:
426- for re in expect:
427- self.assertRegexpMatches(excuses, re)
428- if no_expect:
429- for re in no_expect:
430- self.assertNotRegexpMatches(excuses, re)
431-
432 def shell(self):
433 # uninstallable unstable version
434 self.data.add('yellow', True, {'Version': '1.1~beta',
435@@ -593,4 +459,5 @@
436 subprocess.call(['bash', '-i'], cwd=self.data.path)
437
438
439-unittest.main()
440+if __name__ == '__main__':
441+ unittest.main()

Subscribers

People subscribed via source and target branches