Merge lp:~psivaa/utah/utah-upgrade2 into lp:~utah/utah/jenkins-upgradetest-setup
- utah-upgrade2
- Merge into jenkins-upgradetest-setup
Status: | Merged |
---|---|
Approved by: | Max Brustkern |
Approved revision: | 44 |
Merged at revision: | 25 |
Proposed branch: | lp:~psivaa/utah/utah-upgrade2 |
Merge into: | lp:~utah/utah/jenkins-upgradetest-setup |
Diff against target: |
893 lines (+763/-2) 22 files modified
jenkins/jenkins.sh (+2/-0) main/install_main/install_all_main.py (+89/-0) main/install_main/tc_control (+3/-2) post-upgrade/README (+8/-0) post-upgrade/conffiles/tc_control (+9/-0) post-upgrade/conffiles/test_conffiles.py (+77/-0) post-upgrade/debconf/debconf_test.py (+68/-0) post-upgrade/debconf/tc_control (+9/-0) post-upgrade/debsums/debsums_lite.py (+21/-0) post-upgrade/debsums/tc_control (+9/-0) post-upgrade/kernel/tc_control (+11/-0) post-upgrade/kernel/test_kernel.py (+47/-0) post-upgrade/lts_upgrade_system/tc_control (+11/-0) post-upgrade/lts_upgrade_system/test_lts_upgrade_system.py (+73/-0) post-upgrade/lts_upgrade_user/tc_control (+10/-0) post-upgrade/lts_upgrade_user/test_lts_upgrade_user.py (+107/-0) post-upgrade/python_import/tc_control (+10/-0) post-upgrade/python_import/test_python_import.py (+131/-0) post-upgrade/tslist.run (+7/-0) post-upgrade/xserver/tc_control (+9/-0) post-upgrade/xserver/test_xserver.py (+48/-0) upgrade.run (+4/-0) |
To merge this branch: | bzr merge lp:~psivaa/utah/utah-upgrade2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Max Brustkern (community) | Approve | ||
Para Siva (community) | Needs Resubmitting | ||
Review via email:
|
Commit message
Description of the change
As per the comment in https:/
Contains the following changes:
1. Incorporate install_all_main.py rather than using it from the old location with some modification, for ease of maintenance
2. Changed the number of post upgrade tests
3. Added a line to destroy VMs at the end of the test.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Max Brustkern (nuclearbob) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Para Siva (psivaa) wrote : | # |
I am not in favour of cleaning up the disks because that way we could manually restart the VM to investigate the VMs for any information that are not captured from the client logs in case of any failures. Destroying the VMs was introduced to reduce the processor load on the servers.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Max Brustkern (nuclearbob) wrote : | # |
I forgot that 'destroy' in libvirt doesn't mean destroy in the way I usually think of it. Keeping them around for that makes sense.
On line 34, should redhat-cluster-suit be redhat-
Do the commented lines on 44, 52, 66, 74, and 176 need to stay in?
If it would be useful for the block starting on 629, we can work on doing a display-capable automated test, but I don't think that should hold up this merge.
post-upgrade/
All of the actual important bits seem reasonable enough to me.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Para Siva (psivaa) : | # |
Preview Diff
1 | === modified file 'jenkins/jenkins.sh' |
2 | --- jenkins/jenkins.sh 2013-05-31 20:03:27 +0000 |
3 | +++ jenkins/jenkins.sh 2013-08-12 10:37:39 +0000 |
4 | @@ -92,4 +92,6 @@ |
5 | ${SCP} root@${MACHINE}:/var/log/dist-upgrade/* ${LOG_DIR}/ |
6 | ${SCP} root@${MACHINE}:/var/crash/* ${LOG_DIR}/ |
7 | |
8 | +virsh destroy $MACHINE |
9 | + |
10 | exit $RETCODE |
11 | |
12 | === added file 'main/install_main/install_all_main.py' |
13 | --- main/install_main/install_all_main.py 1970-01-01 00:00:00 +0000 |
14 | +++ main/install_main/install_all_main.py 2013-08-12 10:37:39 +0000 |
15 | @@ -0,0 +1,89 @@ |
16 | +#!/usr/bin/python3 |
17 | + |
18 | +from __future__ import print_function |
19 | + |
20 | +import apt |
21 | +import apt_pkg |
22 | +import platform |
23 | + |
24 | + |
25 | +def blacklisted(name): |
26 | + # we need to blacklist linux-image-* as it does not install |
27 | + # cleanly in the chroot (postinst failes) |
28 | + blacklist = ["libkdc2", "libkdc", "libjpeg", "libgpod", "libapache2", |
29 | + "libgd", "heimdal", "bacula", "grub", "linux-image-", |
30 | + "ltsp-client", "glibc-doc-reference", "libpthread-dev", |
31 | + "cman", "mysql-server", "fuse-utils", |
32 | + "ltspfs", "gfs2-tools", "edubuntu-server", |
33 | + "gnbd-client", "gnbd-server", "mysql-server-5.0", |
34 | + "rgmanager", "clvm", "redhat-cluster-suite", |
35 | + # has a funny "can not be upgraded automatically" policy |
36 | + # see debian #368226 |
37 | + "quagga", |
38 | + "system-config-cluster", "gfs-tools"] |
39 | + for b in blacklist: |
40 | + if name.startswith(b): |
41 | + return True |
42 | + return False |
43 | + |
44 | + |
45 | +cache = apt.Cache() |
46 | +group = apt_pkg.ActionGroup(cache._depcache) |
47 | + |
48 | +arch = "i386" |
49 | +if platform.machine() == "x86_64": |
50 | + arch = "amd64" |
51 | + |
52 | +troublemaker = set() |
53 | +for pkg in cache: |
54 | + if not pkg.candidate and arch not in pkg.fullname: |
55 | + continue |
56 | + for c in pkg.candidate.origins: |
57 | + if c.component == "main": |
58 | + current = set([p.name for p in cache if p.marked_install]) |
59 | + if (not (pkg.is_installed or blacklisted(pkg.name)) and |
60 | + arch in pkg.fullname): |
61 | + pkg.mark_install() |
62 | + print("Install candidate: %s" % pkg.name) |
63 | + new = set([p.name for p in cache if p.marked_install]) |
64 | + if not (pkg.is_installed or pkg.marked_install): |
65 | + print("Can't install: %s" % pkg.name) |
66 | + if len(current - new) > 0: |
67 | + troublemaker.add(pkg.name) |
68 | + print("Installing '%s'\ |
69 | + caused removals_ %s" % (pkg.name, current - new)) |
70 | + |
71 | +for pkg in ["ubuntu-desktop", "ubuntu-minimal", "ubuntu-standard"]: |
72 | + cache[pkg].mark_install() |
73 | + |
74 | +# make sure we don't install blacklisted stuff |
75 | +for pkg in cache: |
76 | + if blacklisted(pkg.name): |
77 | + pkg.mark_keep() |
78 | + |
79 | +print("We can install:") |
80 | +print(len([pkg.name for pkg in cache if pkg.marked_install])) |
81 | +print("Download: ") |
82 | +pm = apt_pkg.PackageManager(cache._depcache) |
83 | +fetcher = apt_pkg.Acquire() |
84 | +pm.get_archives(fetcher, cache._list, cache._records) |
85 | +print(apt_pkg.size_to_str(fetcher.fetch_needed)) |
86 | +print("Total space: ", apt_pkg.size_to_str(cache._depcache.usr_size)) |
87 | + |
88 | +res = False |
89 | +current = 0 |
90 | +maxRetries = 3 |
91 | +while current < maxRetries: |
92 | + try: |
93 | + res = cache.commit(apt.progress.text.AcquireProgress(), |
94 | + apt.progress.base.InstallProgress()) |
95 | + except IOError as e: |
96 | + # fetch failed, will be retried |
97 | + current += 1 |
98 | + print("Retrying to fetch: ", current) |
99 | + continue |
100 | + except SystemError as e: |
101 | + print("Error installing packages! ") |
102 | + print(e) |
103 | + print("Install result: ", res) |
104 | + break |
105 | |
106 | === modified file 'main/install_main/tc_control' |
107 | --- main/install_main/tc_control 2013-05-31 19:55:55 +0000 |
108 | +++ main/install_main/tc_control 2013-08-12 10:37:39 +0000 |
109 | @@ -6,5 +6,6 @@ |
110 | 1. all packages from main are installed |
111 | type: userland |
112 | timeout: 3600 # 10 hours |
113 | -command: ./auto-upgrade-testing/share/scripts/install_all_main |
114 | -tc_setup: bzr branch lp:auto-upgrade-testing |
115 | +command: ./install_all_main.py |
116 | +run_as: root |
117 | + |
118 | |
119 | === added directory 'post-upgrade' |
120 | === added file 'post-upgrade/README' |
121 | --- post-upgrade/README 1970-01-01 00:00:00 +0000 |
122 | +++ post-upgrade/README 2013-08-12 10:37:39 +0000 |
123 | @@ -0,0 +1,8 @@ |
124 | +The scripts in this folder are run after the upgrade was performed |
125 | +and after a reboot. They can test various functionality like |
126 | +- is the latest kernel running |
127 | +- is the xserver running |
128 | +- is python still working |
129 | +- are my daemons still running |
130 | + |
131 | +etc |
132 | |
133 | === added directory 'post-upgrade/conffiles' |
134 | === added file 'post-upgrade/conffiles/tc_control' |
135 | --- post-upgrade/conffiles/tc_control 1970-01-01 00:00:00 +0000 |
136 | +++ post-upgrade/conffiles/tc_control 2013-08-12 10:37:39 +0000 |
137 | @@ -0,0 +1,9 @@ |
138 | +description: Check if there are obsolete conf files left over after upgrade |
139 | +dependencies: none |
140 | +action: | |
141 | + 1. Test if there are obsolete config files left after the upgrade |
142 | +expected_results: | |
143 | + 1. No obsolete conf files left afte the upgrade |
144 | +type: userland |
145 | +timeout: 60 # 1 minute |
146 | +command: ./test_conffiles.py |
147 | |
148 | === added file 'post-upgrade/conffiles/test_conffiles.py' |
149 | --- post-upgrade/conffiles/test_conffiles.py 1970-01-01 00:00:00 +0000 |
150 | +++ post-upgrade/conffiles/test_conffiles.py 2013-08-12 10:37:39 +0000 |
151 | @@ -0,0 +1,77 @@ |
152 | +#!/usr/bin/python |
153 | +# |
154 | +# This script checks status of configuration files after upgrade. |
155 | +# Current checks are: |
156 | +# - Obsolete config files |
157 | +# - Existence of *.dpkg-dist files. It means there was a prompt for an |
158 | +# unmodified configuration during upgrade |
159 | +# |
160 | +# (C) 2012 Canonical Ltd. |
161 | +# Author: Jean-Baptiste Lallement <jean-baptiste.lallement@canonical.com> |
162 | +# License: GPL v2 or higher |
163 | + |
164 | +import unittest |
165 | +import subprocess |
166 | +import glob |
167 | + |
168 | +class TestConfFiles(unittest.TestCase): |
169 | + def test_obsolete_configfile(self): |
170 | + '''Check for obsolete config files after upgrade''' |
171 | + cmd = ['dpkg-query' ,'-W', '-f=${Package}\n${Conffiles}\n\n'] |
172 | + output_file = '/tmp/obsolete_conffiles.log' |
173 | + test_output = '' |
174 | + |
175 | + dpkgquery = subprocess.check_output(cmd) |
176 | + current = set() |
177 | + obsolete = {} |
178 | + for pkg in dpkgquery.split('\n\n'): |
179 | + pkg = pkg.strip().split('\n') |
180 | + pkgname = pkg[0] |
181 | + cfgfiles = pkg[1:] |
182 | + for cfgfile in cfgfiles: |
183 | + cfgbits = cfgfile.strip().split() |
184 | + if len(cfgbits) < 3: |
185 | + # No status, not obsolete |
186 | + current.add(cfgbits[0]) |
187 | + else: |
188 | + file, md5, status = cfgbits[:3] |
189 | + if 'obsolete' in status: |
190 | + obsolete.setdefault(pkgname, []).append(file) |
191 | + else: |
192 | + current.add(file) |
193 | + |
194 | + for pkgname in sorted(obsolete.keys()): |
195 | + cfgfiles = [cfgfile for cfgfile in obsolete[pkgname] |
196 | + if cfgfile not in current] |
197 | + if cfgfiles: |
198 | + test_output += "%s\n %s\n" % (pkgname, "\n ".join(cfgfiles)) |
199 | + |
200 | + if test_output: |
201 | + with open(output_file, 'w') as f: |
202 | + print >>f, test_output |
203 | + |
204 | + def test_dpkgdist(self): |
205 | + '''Check for existence of *.dpkg-dist files''' |
206 | + whitelist_dpkg = [ |
207 | + '/tmp/sudoers.dpkg-dist', |
208 | + '/tmp/release-upgrades.dpkg-dist'] |
209 | + |
210 | + dpkgdist_files = subprocess.check_output(['find', '/etc', '-name', \ |
211 | + '*.dpkg-dist']).split('\n') |
212 | + for f in dpkgdist_files: |
213 | + if f.strip(): |
214 | + subprocess.check_call(['cp %s /tmp/' % f], shell=True) |
215 | + conffile = f.replace('.dpkg-dist', '') |
216 | + subprocess.check_call(['cp %s /tmp/' % conffile], shell=True) |
217 | + |
218 | + saved_dpkgdist_files = glob.glob('/tmp/*.dpkg-dist') |
219 | + saved_dpkgdist_files = [f for f in saved_dpkgdist_files \ |
220 | + if f not in whitelist_dpkg] |
221 | + |
222 | + self.assertEqual( |
223 | + len(saved_dpkgdist_files), 0, |
224 | + "*.dpkg-dist files found after upgrade:\n %s" % |
225 | + "\n ".join(saved_dpkgdist_files)) |
226 | + |
227 | +if __name__ == '__main__': |
228 | + unittest.main() |
229 | |
230 | === added directory 'post-upgrade/debconf' |
231 | === added file 'post-upgrade/debconf/debconf_test.py' |
232 | --- post-upgrade/debconf/debconf_test.py 1970-01-01 00:00:00 +0000 |
233 | +++ post-upgrade/debconf/debconf_test.py 2013-08-12 10:37:39 +0000 |
234 | @@ -0,0 +1,68 @@ |
235 | +#!/usr/bin/python |
236 | +""" |
237 | +Parse debconf log file and split in a file per prompt |
238 | +Exit with status 1 if there is a debconf prompt not in whitelist |
239 | +""" |
240 | +from __future__ import print_function |
241 | + |
242 | +import re, os, sys |
243 | + |
244 | +# Keep this path in sync with the corresponding setting in |
245 | +# profile/defaults.cfg.d/defaults.cfg |
246 | +DEBCONF_LOG_PATH = '/var/log/dist-upgrade/debconf.log' |
247 | +RESULT_DIR = '/tmp' |
248 | + |
249 | +# Prompts in this list won't generate a test failure |
250 | +# i.e WHITELIST = ['libraries/restart-without-asking'] |
251 | +WHITELIST = [ |
252 | + 'glibc/restart-services', |
253 | + 'libraries/restart-without-asking' ] |
254 | + |
255 | +def run_test(logfile, resultdir): |
256 | + """ Run the test and slice debconf log |
257 | + |
258 | + :param logfile: Path to debconf log |
259 | + :param resultdir: Output directory to write log file to |
260 | + """ |
261 | + global WHITELIST |
262 | + |
263 | + ret = 0 |
264 | + if not os.path.exists(logfile): |
265 | + print('Debconf logfile not present. Whitelist. Skipping!') |
266 | + return ret |
267 | + |
268 | + re_dsetting = re.compile('^\w') |
269 | + inprompt = False |
270 | + prompt = dsetting = "" |
271 | + |
272 | + with open(logfile, 'r') as f_in: |
273 | + for line in f_in.readlines(): |
274 | + # Only keep interesting bits of the prompt |
275 | + if line.startswith('#####'): |
276 | + inprompt = not inprompt |
277 | + |
278 | + # Reached the second separator, write content to result file |
279 | + # One per prompt |
280 | + if not inprompt: |
281 | + print("Got debconf prompt for '%s'" % dsetting) |
282 | + if dsetting in WHITELIST: |
283 | + print(' But it is in Whitelist. Skipping!') |
284 | + continue |
285 | + else: |
286 | + ret = 1 |
287 | + |
288 | + with open(os.path.join( |
289 | + resultdir, |
290 | + 'debconf_%s.log' % dsetting.replace('/', '_')), |
291 | + 'w') as f_out: |
292 | + f_out.write(prompt) |
293 | + |
294 | + if inprompt: |
295 | + prompt += line |
296 | + if re_dsetting.match(line) and '=' in line: |
297 | + dsetting = line.split('=')[0] |
298 | + |
299 | + return ret |
300 | + |
301 | +if __name__ == '__main__': |
302 | + sys.exit(run_test(DEBCONF_LOG_PATH, RESULT_DIR)) |
303 | |
304 | === added file 'post-upgrade/debconf/tc_control' |
305 | --- post-upgrade/debconf/tc_control 1970-01-01 00:00:00 +0000 |
306 | +++ post-upgrade/debconf/tc_control 2013-08-12 10:37:39 +0000 |
307 | @@ -0,0 +1,9 @@ |
308 | +description: Check if there is any unnecessary prompts during upgrade |
309 | +dependencies: none |
310 | +action: | |
311 | + 1. Test there is no unnecessary user prompts during the upgrade |
312 | +expected_results: | |
313 | + 1. There is no prompts unless user modified the files beforehand. |
314 | +type: userland |
315 | +timeout: 60 # 1 minute |
316 | +command: ./debconf_test.py |
317 | |
318 | === added directory 'post-upgrade/debsums' |
319 | === added file 'post-upgrade/debsums/debsums_lite.py' |
320 | --- post-upgrade/debsums/debsums_lite.py 1970-01-01 00:00:00 +0000 |
321 | +++ post-upgrade/debsums/debsums_lite.py 2013-08-12 10:37:39 +0000 |
322 | @@ -0,0 +1,21 @@ |
323 | +#!/usr/bin/python |
324 | + |
325 | +from __future__ import print_function |
326 | + |
327 | +import glob |
328 | +import os |
329 | +import subprocess |
330 | +import sys |
331 | + |
332 | +basepath = "/var/lib/dpkg/info/*.md5sums" |
333 | +ok = True |
334 | +for f in glob.glob(basepath): |
335 | + ret = subprocess.call(["md5sum", "--quiet", "-c", |
336 | + os.path.join(basepath, f)], |
337 | + cwd="/") |
338 | + if ret != 0: |
339 | + ok = False |
340 | + |
341 | +if not ok: |
342 | + print("WARNING: at least one md5sum mismatch") |
343 | + sys.exit(1) |
344 | |
345 | === added file 'post-upgrade/debsums/tc_control' |
346 | --- post-upgrade/debsums/tc_control 1970-01-01 00:00:00 +0000 |
347 | +++ post-upgrade/debsums/tc_control 2013-08-12 10:37:39 +0000 |
348 | @@ -0,0 +1,9 @@ |
349 | +description: Check for package debsum mismatches |
350 | +dependencies: none |
351 | +action: | |
352 | + 1. Check if the md5sums of the installed packages match their debsums |
353 | +expected_results: | |
354 | + 1. The debsums of the packages match |
355 | +type: userland |
356 | +timeout: 60 # 1 minute |
357 | +command: ./debsums_lite.py |
358 | |
359 | === added directory 'post-upgrade/kernel' |
360 | === added file 'post-upgrade/kernel/tc_control' |
361 | --- post-upgrade/kernel/tc_control 1970-01-01 00:00:00 +0000 |
362 | +++ post-upgrade/kernel/tc_control 2013-08-12 10:37:39 +0000 |
363 | @@ -0,0 +1,11 @@ |
364 | +description: Check if the kernel update was proper during the upgrade |
365 | +dependencies: none |
366 | +action: | |
367 | + 1. Test if the kernel being used after the ugprade and reboot is the latest |
368 | + 2. Test if there are at-least two kernels installed (old and new) |
369 | +expected_results: | |
370 | + 1. The kernel in use is the new kernel that was installed during the upgrade |
371 | + 2. At least two kernel versions are in the system |
372 | +type: userland |
373 | +timeout: 60 # 1 minute |
374 | +command: ./test_kernel.py |
375 | |
376 | === added file 'post-upgrade/kernel/test_kernel.py' |
377 | --- post-upgrade/kernel/test_kernel.py 1970-01-01 00:00:00 +0000 |
378 | +++ post-upgrade/kernel/test_kernel.py 2013-08-12 10:37:39 +0000 |
379 | @@ -0,0 +1,47 @@ |
380 | +#!/usr/bin/python |
381 | +# |
382 | +# This script checks for that at least 2 kernels are installed post-upgrade |
383 | +# and that the latest one is active |
384 | +# |
385 | +# (C) 2012 Canonical Ltd. |
386 | +# Author: Jean-Baptiste Lallement <jean-baptiste.lallement@canonical.com> |
387 | +# Based on the original version from Michael Vogt |
388 | +# License: GPL v2 or higher |
389 | + |
390 | +import unittest |
391 | +import apt_pkg |
392 | +import glob |
393 | +import os |
394 | + |
395 | +class TestKernel(unittest.TestCase): |
396 | + def setUp(self): |
397 | + apt_pkg.init() |
398 | + self.current_kernelversion = os.uname()[2] |
399 | + self.versions = set() |
400 | + for kernel in glob.glob('/boot/vmlinuz-*'): |
401 | + version = "-".join(kernel.split("-")[1:4]) |
402 | + self.versions.add(version) |
403 | + |
404 | + def test_kernel_in_use(self): |
405 | + '''Check latest kernel is in use''' |
406 | + if os.path.exists("/run/container_type"): |
407 | + with open("/run/container_type") as fd: |
408 | + container = fd.read().strip() |
409 | + print("Skipping test_kernel_in_use as in a '%s' container." % container) |
410 | + return |
411 | + |
412 | + for version in self.versions: |
413 | + self.assertFalse( |
414 | + apt_pkg.version_compare(self.current_kernelversion, version) < 0, |
415 | + "There is a kernel version '%s' installed higher than the running kernel '%s'" % |
416 | + (version, self.current_kernelversion)) |
417 | + |
418 | + def test_old_kernel_is_installed(self): |
419 | + '''Check that previous kernel is still there after install''' |
420 | + self.assertNotEqual( |
421 | + len(self.versions), 1, |
422 | + "Only one kernel found '%s', expected at least 2 (new + previous)" % |
423 | + self.versions) |
424 | + |
425 | +if __name__ == '__main__': |
426 | + unittest.main() |
427 | |
428 | === added directory 'post-upgrade/lts_upgrade_system' |
429 | === added file 'post-upgrade/lts_upgrade_system/tc_control' |
430 | --- post-upgrade/lts_upgrade_system/tc_control 1970-01-01 00:00:00 +0000 |
431 | +++ post-upgrade/lts_upgrade_system/tc_control 2013-08-12 10:37:39 +0000 |
432 | @@ -0,0 +1,11 @@ |
433 | +description: Check if system config settings are preserved |
434 | +dependencies: none |
435 | +action: | |
436 | + 1. Check if system wide configuration customisation is preserved |
437 | + for an lts->lts upgrade. Skipped for anything else |
438 | +expected_results: | |
439 | + 1. System wide configuration customisation is preserved for lts->lts |
440 | + upgrades |
441 | +type: userland |
442 | +timeout: 60 # 1 minute |
443 | +command: ./test_lts_upgrade_system.py |
444 | |
445 | === added file 'post-upgrade/lts_upgrade_system/test_lts_upgrade_system.py' |
446 | --- post-upgrade/lts_upgrade_system/test_lts_upgrade_system.py 1970-01-01 00:00:00 +0000 |
447 | +++ post-upgrade/lts_upgrade_system/test_lts_upgrade_system.py 2013-08-12 10:37:39 +0000 |
448 | @@ -0,0 +1,73 @@ |
449 | +#!/usr/bin/python |
450 | +# |
451 | +# This script checks system-wide configuration settings after an Ubuntu 10.04 |
452 | +# LTS to Ubuntu 12.04 LTS upgrade. Run this after upgrading to 12.04 or later. |
453 | +# It reads the old gdm settings and ensures that they were appropriately |
454 | +# migrated to lightdm and that lightdm is the default DM. |
455 | +# It does not need any particular privileges, it is fine to run this as any |
456 | +# user. |
457 | +# |
458 | +# (C) 2012 Canonical Ltd. |
459 | +# Author: Martin Pitt <martin.pitt@ubuntu.com> |
460 | +# License: GPL v2 or higher |
461 | + |
462 | +from __future__ import print_function |
463 | + |
464 | +import unittest |
465 | +import os, sys |
466 | +try: |
467 | + import configparser |
468 | + configparser # pyflakes |
469 | +except ImportError: |
470 | + import ConfigParser as configparser |
471 | + |
472 | +class T(unittest.TestCase): |
473 | + @classmethod |
474 | + def setUpClass(klass): |
475 | + # read gdm configuration |
476 | + klass.gdm_config = klass._read_conf('/etc/gdm/custom.conf', 'daemon') |
477 | + klass.lightdm_config = klass._read_conf('/etc/lightdm/lightdm.conf', 'SeatDefaults') |
478 | + |
479 | + def test_lightdm_default_dm(self): |
480 | + '''lightdm is the default display manager''' |
481 | + |
482 | + with open('/etc/X11/default-display-manager') as f: |
483 | + default_dm = f.read().strip() |
484 | + |
485 | + self.assertTrue(os.access(default_dm, os.X_OK)) |
486 | + self.assertEqual(os.path.basename(default_dm), 'lightdm') |
487 | + |
488 | + def test_autologin_migration(self): |
489 | + '''autologin migration from gdm to lightdm''' |
490 | + |
491 | + if self.gdm_config.get('automaticloginenable', 'false') == 'true': |
492 | + gdm_autologin = self.gdm_config.get('automaticlogin', '') |
493 | + else: |
494 | + gdm_autologin = '' |
495 | + |
496 | + self.assertEqual(gdm_autologin, self.lightdm_config.get('autologin-user', '')) |
497 | + |
498 | + @classmethod |
499 | + def _read_conf(klass, filename, section): |
500 | + '''Read section from an INI configuration file. |
501 | + |
502 | + Return a dictionary with the configuration of the given section. |
503 | + ''' |
504 | + p = configparser.ConfigParser() |
505 | + p.read(filename) |
506 | + config = {} |
507 | + try: |
508 | + for (key, value) in p.items(section): |
509 | + config[key] = value |
510 | + except configparser.NoSectionError: |
511 | + # just keep an empty config |
512 | + pass |
513 | + return config |
514 | + |
515 | +# Only run on lts-ubuntu testcases |
516 | +if not os.path.exists('/upgrade-tester/prepare_lts_desktop'): |
517 | + print("Not an Ubuntu Desktop LTS upgrade. Skipping!") |
518 | + sys.exit(0) |
519 | + |
520 | +if __name__ == '__main__': |
521 | + unittest.main() |
522 | |
523 | === added directory 'post-upgrade/lts_upgrade_user' |
524 | === added file 'post-upgrade/lts_upgrade_user/tc_control' |
525 | --- post-upgrade/lts_upgrade_user/tc_control 1970-01-01 00:00:00 +0000 |
526 | +++ post-upgrade/lts_upgrade_user/tc_control 2013-08-12 10:37:39 +0000 |
527 | @@ -0,0 +1,10 @@ |
528 | +description: Check if user config settings are preserved for lts upgrade |
529 | +dependencies: none |
530 | +action: | |
531 | + 1. Check if the user config settings are preserved |
532 | + after an lts->lts upgrade. Skipped for anything else |
533 | +expected_results: | |
534 | + 1. User config settings are preserved for an lts->lts upgrade |
535 | +type: userland |
536 | +timeout: 60 # 1 minute |
537 | +command: ./test_lts_upgrade_user.py |
538 | |
539 | === added file 'post-upgrade/lts_upgrade_user/test_lts_upgrade_user.py' |
540 | --- post-upgrade/lts_upgrade_user/test_lts_upgrade_user.py 1970-01-01 00:00:00 +0000 |
541 | +++ post-upgrade/lts_upgrade_user/test_lts_upgrade_user.py 2013-08-12 10:37:39 +0000 |
542 | @@ -0,0 +1,107 @@ |
543 | +#!/usr/bin/python |
544 | +# |
545 | +# This script checks user configuration settings after an Ubuntu 10.04 |
546 | +# LTS to Ubuntu 12.04 LTS upgrade. Run prepare_lts_upgrade_user.sh in 10.04 |
547 | +# LTS, then upgrade to 12.04 LTS (or later), and run this script to confirm |
548 | +# that settings were migrated properly. In particular this checks for gconf -> |
549 | +# gsettings migration (and sometimes changing the format of the values) for |
550 | +# popular settings, as well as custom panel/desktop launchers. |
551 | +# |
552 | +# You need to run both the prepare and this test script as the same user, |
553 | +# in a full desktop session. |
554 | +# |
555 | +# (C) 2012 Canonical Ltd. |
556 | +# Author: Martin Pitt <martin.pitt@ubuntu.com> |
557 | +# License: GPL v2 or higher |
558 | + |
559 | +from __future__ import print_function |
560 | + |
561 | +import unittest |
562 | +import os, sys |
563 | +import subprocess |
564 | +from time import sleep |
565 | + |
566 | +try: |
567 | + from gi.repository import Gio |
568 | +except: |
569 | + # Not a desktop |
570 | + print("Failed to import gi.repository. Not a LTS Desktop Upgrade. Skipping!") |
571 | + sys.exit(0) |
572 | + |
573 | +class T(unittest.TestCase): |
574 | + def test_background(self): |
575 | + '''background image''' |
576 | + |
577 | + bg_settings = Gio.Settings('org.gnome.desktop.background') |
578 | + # note: original gconf value does not have a file:// prefix, but GNOME |
579 | + # 3.x requires this prefix |
580 | + self.assertEqual(bg_settings.get_string('picture-uri'), |
581 | + 'file://%s/mybackground.jpg' % os.environ['HOME']) |
582 | + |
583 | +# Theme is not preserved on upgrade. LP: #969569 |
584 | +# Test disabled |
585 | +# def test_gtk_theme(self): |
586 | +# '''GTK theme''' |
587 | +# |
588 | +# iface_settings = Gio.Settings('org.gnome.desktop.interface') |
589 | +# self.assertEqual(iface_settings.get_string('gtk-theme'), 'Radiance') |
590 | + |
591 | + def test_custom_launchers(self): |
592 | + '''Custom panel/desktop launchers appear in Unity launcher''' |
593 | + |
594 | + launcher_settings = Gio.Settings('com.canonical.Unity.Launcher') |
595 | + favorites = launcher_settings['favorites'] |
596 | + |
597 | + # gedit was dragged from Application menu to panel, pointing to system |
598 | + # .desktop file |
599 | + self.assertTrue('gedit.desktop' in favorites) |
600 | + |
601 | + # custom "echo hello" panel starter uses its own .desktop file |
602 | + for starter in favorites: |
603 | + if 'echo' in starter: |
604 | + self.assertTrue(os.path.exists(starter)) |
605 | + break |
606 | + else: |
607 | + self.fail('custom hello starter not found') |
608 | + |
609 | + # gucharmap was dragged from Application menu to desktop, should be |
610 | + # converted to system .desktop file |
611 | + self.assertTrue('gucharmap.desktop' in favorites) |
612 | + |
613 | + # custom "bc -l" desktop starter uses its own .desktop file |
614 | + self.assertTrue('%s/Desktop/termcalc.desktop' % os.environ['HOME'] in favorites) |
615 | + |
616 | + def test_keyboard_layouts(self): |
617 | + '''Custom keyboard layouts are migrated and applied''' |
618 | + |
619 | + # verify gconf->gsettings migration |
620 | + kbd_settings = Gio.Settings('org.gnome.libgnomekbd.keyboard') |
621 | + self.assertEqual(kbd_settings['layouts'], |
622 | + ['us','de\tnodeadkeys','gb','gb\tdvorak']) |
623 | + |
624 | +# NO DISPLAY IN AUTOMATED TEST |
625 | +# # verify that they get applied to the X server correctly |
626 | +# xprop = subprocess.Popen(['xprop', '-root', '_XKB_RULES_NAMES'], |
627 | +# stdout=subprocess.PIPE, universal_newlines=True) |
628 | +# out = xprop.communicate()[0] |
629 | +# self.assertEqual(xprop.returncode, 0) |
630 | +# |
631 | +# # chop off key name |
632 | +# out = out.split('=', 1)[1].strip() |
633 | +# |
634 | +# self.assertEqual(out, '"evdev", "pc105", "us,de,gb,gb", ",nodeadkeys,,dvorak", "grp:alts_toggle"') |
635 | + |
636 | +# Only run on lts-ubuntu testcases |
637 | +if not os.path.exists('/upgrade-tester/prepare_lts_desktop'): |
638 | + print("Not an Ubuntu Desktop LTS upgrade. Skipping!") |
639 | + sys.exit(0) |
640 | + |
641 | +if os.getuid() == 0: |
642 | + # Root ? reexecute itself as user ubuntu |
643 | + ret = subprocess.call('sudo -H -u ubuntu dbus-launch %s' % |
644 | + os.path.abspath(__file__), shell=True) |
645 | + sys.exit(ret) |
646 | +else: |
647 | + # Give 1 minute for the session to start, convert, ... |
648 | + sleep(60) |
649 | + unittest.main() |
650 | |
651 | === added directory 'post-upgrade/python_import' |
652 | === added file 'post-upgrade/python_import/tc_control' |
653 | --- post-upgrade/python_import/tc_control 1970-01-01 00:00:00 +0000 |
654 | +++ post-upgrade/python_import/tc_control 2013-08-12 10:37:39 +0000 |
655 | @@ -0,0 +1,10 @@ |
656 | +description: Check if python modules are importable |
657 | +dependencies: none |
658 | +action: | |
659 | + 1. Attempt to import the py modules listed under dist-packages |
660 | + of the default version |
661 | +expected_results: | |
662 | + 1. The modules present in dist-packages are importable |
663 | +type: userland |
664 | +timeout: 60 # 1 minute |
665 | +command: ./test_python_import.py |
666 | |
667 | === added file 'post-upgrade/python_import/test_python_import.py' |
668 | --- post-upgrade/python_import/test_python_import.py 1970-01-01 00:00:00 +0000 |
669 | +++ post-upgrade/python_import/test_python_import.py 2013-08-12 10:37:39 +0000 |
670 | @@ -0,0 +1,131 @@ |
671 | +#!/usr/bin/python |
672 | +# |
673 | +# This script checks python. Current tests: |
674 | +# - import python modules available on the systen |
675 | +# |
676 | +# (C) 2012 Canonical Ltd. |
677 | +# Author: Jean-Baptiste Lallement <jean-baptiste.lallement@canonical.com> |
678 | +# Based on original version from Michael Vogt |
679 | +# License: GPL v2 or higher |
680 | + |
681 | +import unittest |
682 | +import ConfigParser |
683 | +import os |
684 | +import logging |
685 | +import subprocess |
686 | + |
687 | +logging.basicConfig( |
688 | + filename='/tmp/%s.log' % os.path.basename(__file__)[:-3], |
689 | + filemode='w', |
690 | + level=logging.DEBUG) |
691 | + |
692 | +# stuff that we know does not work when doing a simple "import" |
693 | +BLACKLIST = ["speechd_config", |
694 | + "PAMmodule.so", |
695 | + "aomodule.so", |
696 | + "plannerui.so", |
697 | + "desktopcouch", # needs a KeyringDaemon |
698 | + "ropemacs", # just hangs |
699 | + "keyring", # needs X |
700 | + "invest", |
701 | + "Onboard", |
702 | + "goocanvasmodule.so", |
703 | + ] |
704 | + |
705 | +# If you want to test modules that require a display you'll have to install |
706 | +# xvfb in the base image |
707 | +XVFB_BIN='/usr/bin/xvfb-run' |
708 | +XVFB_OPT=[] |
709 | + |
710 | +def py_module_filter(pymodule): |
711 | + return not ( |
712 | + pymodule.endswith(".egg-info") or |
713 | + pymodule.endswith(".pth") or |
714 | + pymodule.startswith("_") or |
715 | + pymodule.endswith(".pyc") or |
716 | + pymodule.endswith("_d.so") or |
717 | + pymodule in BLACKLIST |
718 | + ) |
719 | + |
720 | +def get_module_from_path(path): |
721 | + f = os.path.basename(path) |
722 | + if path and os.path.exists(os.path.join(path, "__init__.py")): |
723 | + return f |
724 | + elif f.endswith(".py"): |
725 | + return f.split(".")[0] |
726 | + # swig uses this, calls it "foomodule.so" but the import is "foo" |
727 | + # (eg xdelta3module.so, pqueuemodule.so) |
728 | + elif f.endswith("module.so"): |
729 | + return f.split("modules.so")[0] |
730 | + elif f.endswith(".so"): |
731 | + return f.split(".")[0] |
732 | + |
733 | +class TestPython(unittest.TestCase): |
734 | + # total imports |
735 | + total = 0 |
736 | + failed = [] |
737 | + |
738 | + def _try_import(self, path): |
739 | + '''Try to import a module from a path |
740 | + |
741 | + a simple __import__(module) does not work, the problem |
742 | + is that module import have funny side-effects (like |
743 | + "import uno; import pyatspi" will fail, but importing |
744 | + them individually is fine |
745 | + ''' |
746 | + logging.info('Importing %s', path) |
747 | + module = get_module_from_path(path) |
748 | + rc = True |
749 | + if not module: |
750 | + logging.warn("could not get module for '%s'" % path) |
751 | + return rc |
752 | + |
753 | + try: |
754 | + cmd = ["python", "-c","import %s" % module] |
755 | + self.total += 1 |
756 | + subprocess.check_call(cmd, stderr = self.stderr) |
757 | + except subprocess.CalledProcessError: |
758 | + try: |
759 | + pkg = subprocess.check_output(["dpkg", "-S", os.path.realpath(path)]) |
760 | + self.failed.append((module, pkg.strip())) |
761 | + logging.error('Import failed. Package providing this module: %s', pkg) |
762 | + except subprocess.CalledProcessError: |
763 | + logging.error("Import of %s failed, and no package ships this module.", path) |
764 | + rc = False |
765 | + return rc |
766 | + |
767 | + def setUp(self): |
768 | + # Read default python version installed on the system |
769 | + config = ConfigParser.SafeConfigParser() |
770 | + config.read('/usr/share/python/debian_defaults') |
771 | + self.default_version = config.get('DEFAULT', 'default-version') |
772 | + self.distpackages = '/usr/lib/%s/dist-packages/' % self.default_version |
773 | + self.stderr = open('/tmp/%s.stderr' % os.path.basename(__file__)[:-3],'w') |
774 | + |
775 | + def tearDown(self): |
776 | + self.stderr.close() |
777 | + |
778 | + def test_python_import(self): |
779 | + '''Import python modules from /usr/lib/PYTHONVER/dist-packages/''' |
780 | + res = True |
781 | + |
782 | + for module in filter(py_module_filter, os.listdir(self.distpackages)): |
783 | + res &= self._try_import(os.path.join(self.distpackages, module)) |
784 | + |
785 | + logging.info('Modules imported: %d', self.total) |
786 | + if res: |
787 | + logging.info('No failure') |
788 | + |
789 | + self.assertTrue(res, '%d module(s) failed to import' % len(self.failed)) |
790 | + |
791 | +if __name__ == '__main__': |
792 | + if 'DISPLAY' in os.environ: |
793 | + unittest.main() |
794 | + elif os.path.exists(XVFB_BIN): |
795 | + logging.info("'%s' found and DISPLAY not set. Re-executing myself with xvfb") |
796 | + cmd = [ XVFB_BIN ] + XVFB_OPT + [os.path.abspath(__file__)] |
797 | + logging.info(cmd) |
798 | + subprocess.call(cmd) |
799 | + else: |
800 | + logging.warning("'%s' not found and DISPLAY not set. Executing test without a display", XVFB_BIN) |
801 | + unittest.main() |
802 | |
803 | === added file 'post-upgrade/tslist.run' |
804 | --- post-upgrade/tslist.run 1970-01-01 00:00:00 +0000 |
805 | +++ post-upgrade/tslist.run 2013-08-12 10:37:39 +0000 |
806 | @@ -0,0 +1,7 @@ |
807 | +- test: conffiles |
808 | +- test: debconf |
809 | +- test: kernel |
810 | +- test: lts_upgrade_system |
811 | +- test: lts_upgrade_user |
812 | +- test: python_import |
813 | +- test: xserver |
814 | |
815 | === added directory 'post-upgrade/xserver' |
816 | === added file 'post-upgrade/xserver/tc_control' |
817 | --- post-upgrade/xserver/tc_control 1970-01-01 00:00:00 +0000 |
818 | +++ post-upgrade/xserver/tc_control 2013-08-12 10:37:39 +0000 |
819 | @@ -0,0 +1,9 @@ |
820 | +description: Checking for Xorg after upgrade |
821 | +dependencies: none |
822 | +action: | |
823 | + 1. Check if Xorg is running for desktop upgrades. Skip the test for others |
824 | +expected_results: | |
825 | + 1. For desktop upgrades Xorg is running |
826 | +type: userland |
827 | +timeout: 60 # 1 minute |
828 | +command: ./test_xserver.py |
829 | |
830 | === added file 'post-upgrade/xserver/test_xserver.py' |
831 | --- post-upgrade/xserver/test_xserver.py 1970-01-01 00:00:00 +0000 |
832 | +++ post-upgrade/xserver/test_xserver.py 2013-08-12 10:37:39 +0000 |
833 | @@ -0,0 +1,48 @@ |
834 | +#!/usr/bin/python |
835 | +# |
836 | +# This script checks that xserver is running |
837 | +# |
838 | +# (C) 2012 Canonical Ltd. |
839 | +# Author: Jean-Baptiste Lallement <jean-baptiste.lallement@canonical.com> |
840 | +# Based on the original version from Michael Vogt |
841 | +# License: GPL v2 or higher |
842 | + |
843 | +import unittest |
844 | +import subprocess |
845 | +from time import sleep |
846 | + |
847 | +def is_process_running(procname): |
848 | + '''Check if a process is running''' |
849 | + proclist = subprocess.Popen(["ps","-eo","comm"], stdout=subprocess.PIPE, |
850 | + universal_newlines=True).communicate()[0] |
851 | + for line in proclist.split("\n"): |
852 | + if line == procname: |
853 | + return True |
854 | + return False |
855 | + |
856 | +def is_desktop_install(): |
857 | + '''Check that at least an *ubuntu-desktop package is installed''' |
858 | + cmd = ['dpkg-query', '-Wf', '${Status}\n', '*ubuntu-desktop'] |
859 | + try: |
860 | + output = subprocess.check_output(cmd).split('\n') |
861 | + except: |
862 | + return False |
863 | + |
864 | + for line in output: |
865 | + if line.startswith('install'): |
866 | + return True |
867 | + return False |
868 | + |
869 | +class TestXserver(unittest.TestCase): |
870 | + @unittest.skipIf(not is_desktop_install(), 'Not a desktop installation.') |
871 | + def test_xserver_running(self): |
872 | + '''Checking for running Xorg''' |
873 | + count = 0 |
874 | + while not is_process_running('Xorg') and count<10: |
875 | + count += 1 |
876 | + sleep(10) |
877 | + |
878 | + self.assertTrue(is_process_running('Xorg'), 'X Server not running') |
879 | + |
880 | +if __name__ == '__main__': |
881 | + unittest.main() |
882 | |
883 | === modified file 'upgrade.run' |
884 | --- upgrade.run 2013-05-30 21:11:38 +0000 |
885 | +++ upgrade.run 2013-08-12 10:37:39 +0000 |
886 | @@ -3,3 +3,7 @@ |
887 | - name: upgrade |
888 | fetch_method: bzr-export |
889 | fetch_location: lp:~utah/utah/jenkins-upgradetest-setup/upgrade |
890 | + |
891 | + - name: post-upgrade |
892 | + fetch_method: bzr-export |
893 | + fetch_location: lp:~utah/utah/jenkins-upgradetest-setup/post-upgrade |
Are you cleaning up the disks when destroying the machine?