Merge lp:~barry/ubuntu-system-image/citrain302 into lp:~ubuntu-managed-branches/ubuntu-system-image/system-image
- citrain302
- Merge into system-image
Proposed by
Barry Warsaw
Status: | Merged |
---|---|
Approved by: | Barry Warsaw |
Approved revision: | 245 |
Merged at revision: | 244 |
Proposed branch: | lp:~barry/ubuntu-system-image/citrain302 |
Merge into: | lp:~ubuntu-managed-branches/ubuntu-system-image/system-image |
Diff against target: |
395 lines (+147/-18) 14 files modified
NEWS.rst (+5/-0) PKG-INFO (+1/-1) debian/changelog (+11/-0) debian/rules (+3/-0) setup.cfg (+1/-1) system_image.egg-info/PKG-INFO (+1/-1) system_image.egg-info/SOURCES.txt (+1/-0) system_image.egg-info/pbr.json (+1/-0) systemimage/helpers.py (+12/-6) systemimage/logging.py (+10/-6) systemimage/testing/dbus.py (+28/-0) systemimage/tests/test_dbus.py (+26/-2) systemimage/tests/test_helpers.py (+46/-0) systemimage/version.txt (+1/-1) |
To merge this branch: | bzr merge lp:~barry/ubuntu-system-image/citrain302 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Barry Warsaw | Pending | ||
Review via email: mp+272481@code.launchpad.net |
Commit message
Don't crash when one of the .ini files is a dangling symlink. (LP: #1495688)
Description of the change
3.0.2 (2015-09-22)
==================
* Don't crash when one of the .ini files is a dangling symlink.
(LP: #1495688)
To post a comment you must log in.
- 245. By Barry Warsaw
-
d/rules: override_
dh_auto_ clean because otherwise, pybuild will
remove the .egg-info files and that causes the Jenkins job in the CI
train to fail.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'NEWS.rst' | |||
2 | --- NEWS.rst 2015-06-17 15:18:22 +0000 | |||
3 | +++ NEWS.rst 2015-09-28 21:36:51 +0000 | |||
4 | @@ -2,6 +2,11 @@ | |||
5 | 2 | NEWS for system-image updater | 2 | NEWS for system-image updater |
6 | 3 | ============================= | 3 | ============================= |
7 | 4 | 4 | ||
8 | 5 | 3.0.2 (2015-09-22) | ||
9 | 6 | ================== | ||
10 | 7 | * Don't crash when one of the .ini files is a dangling symlink. | ||
11 | 8 | (LP: #1495688) | ||
12 | 9 | |||
13 | 5 | 3.0.1 (2015-06-16) | 10 | 3.0.1 (2015-06-16) |
14 | 6 | ================== | 11 | ================== |
15 | 7 | * When `--progress=json` is used, print an error record to stdout if the | 12 | * When `--progress=json` is used, print an error record to stdout if the |
16 | 8 | 13 | ||
17 | === modified file 'PKG-INFO' | |||
18 | --- PKG-INFO 2015-06-17 15:18:22 +0000 | |||
19 | +++ PKG-INFO 2015-09-28 21:36:51 +0000 | |||
20 | @@ -1,6 +1,6 @@ | |||
21 | 1 | Metadata-Version: 1.0 | 1 | Metadata-Version: 1.0 |
22 | 2 | Name: system-image | 2 | Name: system-image |
24 | 3 | Version: 3.0.1 | 3 | Version: 3.0.2 |
25 | 4 | Summary: Ubuntu System Image Based Upgrades | 4 | Summary: Ubuntu System Image Based Upgrades |
26 | 5 | Home-page: UNKNOWN | 5 | Home-page: UNKNOWN |
27 | 6 | Author: Barry Warsaw | 6 | Author: Barry Warsaw |
28 | 7 | 7 | ||
29 | === modified file 'debian/changelog' | |||
30 | --- debian/changelog 2015-06-18 16:23:37 +0000 | |||
31 | +++ debian/changelog 2015-09-28 21:36:51 +0000 | |||
32 | @@ -1,3 +1,14 @@ | |||
33 | 1 | system-image (3.0.2-0ubuntu1) wily; urgency=medium | ||
34 | 2 | |||
35 | 3 | * New upstream release. | ||
36 | 4 | - LP: #1495688 - Don't crash when one of the .ini files is a dangling | ||
37 | 5 | symlink. | ||
38 | 6 | - d/rules: override_dh_auto_clean because otherwise, pybuild will | ||
39 | 7 | remove the .egg-info files and that causes the Jenkins job in the CI | ||
40 | 8 | train to fail. | ||
41 | 9 | |||
42 | 10 | -- Barry Warsaw <barry@ubuntu.com> Fri, 25 Sep 2015 15:28:37 -0400 | ||
43 | 11 | |||
44 | 1 | system-image (3.0.1-0ubuntu1) wily; urgency=medium | 12 | system-image (3.0.1-0ubuntu1) wily; urgency=medium |
45 | 2 | 13 | ||
46 | 3 | * New rebuild forced. | 14 | * New rebuild forced. |
47 | 4 | 15 | ||
48 | === modified file 'debian/rules' | |||
49 | --- debian/rules 2015-05-09 15:50:39 +0000 | |||
50 | +++ debian/rules 2015-09-28 21:36:51 +0000 | |||
51 | @@ -56,3 +56,6 @@ | |||
52 | 56 | rst2man dbus-manpage.rst > debian/tmp/system-image-dbus.man | 56 | rst2man dbus-manpage.rst > debian/tmp/system-image-dbus.man |
53 | 57 | rst2man ini-manpage.rst > debian/tmp/client-ini.man | 57 | rst2man ini-manpage.rst > debian/tmp/client-ini.man |
54 | 58 | dh_installman | 58 | dh_installman |
55 | 59 | |||
56 | 60 | # We don't want the buildds to remove the .egg-info files. | ||
57 | 61 | override_dh_auto_clean: | ||
58 | 59 | 62 | ||
59 | === modified file 'setup.cfg' | |||
60 | --- setup.cfg 2015-06-17 15:18:22 +0000 | |||
61 | +++ setup.cfg 2015-09-28 21:36:51 +0000 | |||
62 | @@ -4,7 +4,7 @@ | |||
63 | 4 | logging-filter = systemimage | 4 | logging-filter = systemimage |
64 | 5 | 5 | ||
65 | 6 | [egg_info] | 6 | [egg_info] |
66 | 7 | tag_date = 0 | ||
67 | 8 | tag_svn_revision = 0 | 7 | tag_svn_revision = 0 |
68 | 9 | tag_build = | 8 | tag_build = |
69 | 9 | tag_date = 0 | ||
70 | 10 | 10 | ||
71 | 11 | 11 | ||
72 | === modified file 'system_image.egg-info/PKG-INFO' | |||
73 | --- system_image.egg-info/PKG-INFO 2015-06-17 15:18:22 +0000 | |||
74 | +++ system_image.egg-info/PKG-INFO 2015-09-28 21:36:51 +0000 | |||
75 | @@ -1,6 +1,6 @@ | |||
76 | 1 | Metadata-Version: 1.0 | 1 | Metadata-Version: 1.0 |
77 | 2 | Name: system-image | 2 | Name: system-image |
79 | 3 | Version: 3.0.1 | 3 | Version: 3.0.2 |
80 | 4 | Summary: Ubuntu System Image Based Upgrades | 4 | Summary: Ubuntu System Image Based Upgrades |
81 | 5 | Home-page: UNKNOWN | 5 | Home-page: UNKNOWN |
82 | 6 | Author: Barry Warsaw | 6 | Author: Barry Warsaw |
83 | 7 | 7 | ||
84 | === modified file 'system_image.egg-info/SOURCES.txt' | |||
85 | --- system_image.egg-info/SOURCES.txt 2015-05-08 21:41:15 +0000 | |||
86 | +++ system_image.egg-info/SOURCES.txt 2015-09-28 21:36:51 +0000 | |||
87 | @@ -14,6 +14,7 @@ | |||
88 | 14 | system_image.egg-info/SOURCES.txt | 14 | system_image.egg-info/SOURCES.txt |
89 | 15 | system_image.egg-info/dependency_links.txt | 15 | system_image.egg-info/dependency_links.txt |
90 | 16 | system_image.egg-info/entry_points.txt | 16 | system_image.egg-info/entry_points.txt |
91 | 17 | system_image.egg-info/pbr.json | ||
92 | 17 | system_image.egg-info/requires.txt | 18 | system_image.egg-info/requires.txt |
93 | 18 | system_image.egg-info/top_level.txt | 19 | system_image.egg-info/top_level.txt |
94 | 19 | systemimage/__init__.py | 20 | systemimage/__init__.py |
95 | 20 | 21 | ||
96 | === added file 'system_image.egg-info/pbr.json' | |||
97 | --- system_image.egg-info/pbr.json 1970-01-01 00:00:00 +0000 | |||
98 | +++ system_image.egg-info/pbr.json 2015-09-28 21:36:51 +0000 | |||
99 | @@ -0,0 +1,1 @@ | |||
100 | 1 | {"is_release": true, "git_version": "4ecc87c"} | ||
101 | 0 | \ No newline at end of file | 2 | \ No newline at end of file |
102 | 1 | 3 | ||
103 | === modified file 'systemimage/helpers.py' | |||
104 | --- systemimage/helpers.py 2015-05-08 21:41:15 +0000 | |||
105 | +++ systemimage/helpers.py 2015-09-28 21:36:51 +0000 | |||
106 | @@ -41,7 +41,7 @@ | |||
107 | 41 | import logging | 41 | import logging |
108 | 42 | import tempfile | 42 | import tempfile |
109 | 43 | 43 | ||
111 | 44 | from contextlib import ExitStack, contextmanager | 44 | from contextlib import ExitStack, contextmanager, suppress |
112 | 45 | from datetime import datetime, timedelta | 45 | from datetime import datetime, timedelta |
113 | 46 | from hashlib import sha256 | 46 | from hashlib import sha256 |
114 | 47 | from importlib import import_module | 47 | from importlib import import_module |
115 | @@ -252,13 +252,19 @@ | |||
116 | 252 | try: | 252 | try: |
117 | 253 | timestamp = datetime.fromtimestamp(os.stat(LAST_UPDATE_FILE).st_mtime) | 253 | timestamp = datetime.fromtimestamp(os.stat(LAST_UPDATE_FILE).st_mtime) |
118 | 254 | except (FileNotFoundError, PermissionError): | 254 | except (FileNotFoundError, PermissionError): |
123 | 255 | # We fall back to the latest mtime of the config.d/*.ini files. | 255 | # We fall back to the latest mtime of the config.d/*.ini files. For |
124 | 256 | timestamps = sorted( | 256 | # robustness, watch out for two possibilities: the config file could |
125 | 257 | datetime.fromtimestamp(path.stat().st_mtime) | 257 | # have been deleted after the system started up (thus making |
126 | 258 | for path in config.ini_files) | 258 | # config.ini_files include nonexistent files), and the ini file could |
127 | 259 | # be a dangling symlink. For the latter, use lstat(). | ||
128 | 260 | timestamps = [] | ||
129 | 261 | for path in config.ini_files: | ||
130 | 262 | with suppress(FileNotFoundError): | ||
131 | 263 | timestamps.append( | ||
132 | 264 | datetime.fromtimestamp(path.lstat().st_mtime)) | ||
133 | 259 | if len(timestamps) == 0: | 265 | if len(timestamps) == 0: |
134 | 260 | return 'Unknown' | 266 | return 'Unknown' |
136 | 261 | timestamp = timestamps[-1] | 267 | timestamp = sorted(timestamps)[-1] |
137 | 262 | return str(timestamp.replace(microsecond=0)) | 268 | return str(timestamp.replace(microsecond=0)) |
138 | 263 | 269 | ||
139 | 264 | 270 | ||
140 | 265 | 271 | ||
141 | === modified file 'systemimage/logging.py' | |||
142 | --- systemimage/logging.py 2015-05-08 21:41:15 +0000 | |||
143 | +++ systemimage/logging.py 2015-09-28 21:36:51 +0000 | |||
144 | @@ -18,6 +18,7 @@ | |||
145 | 18 | __all__ = [ | 18 | __all__ = [ |
146 | 19 | 'debug_logging', | 19 | 'debug_logging', |
147 | 20 | 'initialize', | 20 | 'initialize', |
148 | 21 | 'make_handler', | ||
149 | 21 | ] | 22 | ] |
150 | 22 | 23 | ||
151 | 23 | 24 | ||
152 | @@ -68,13 +69,16 @@ | |||
153 | 68 | return super().getMessage() | 69 | return super().getMessage() |
154 | 69 | 70 | ||
155 | 70 | 71 | ||
157 | 71 | def _make_handler(path): | 72 | def make_handler(path): |
158 | 72 | # issue21539 - mkdir(..., exist_ok=True) | 73 | # issue21539 - mkdir(..., exist_ok=True) |
159 | 73 | with suppress(FileExistsError): | 74 | with suppress(FileExistsError): |
160 | 74 | path.parent.mkdir(DEFAULT_DIRMODE, parents=True) | 75 | path.parent.mkdir(DEFAULT_DIRMODE, parents=True) |
161 | 75 | path.touch(LOGFILE_PERMISSIONS) | 76 | path.touch(LOGFILE_PERMISSIONS) |
162 | 76 | # Our handler will output in UTF-8 using {} style logging. | 77 | # Our handler will output in UTF-8 using {} style logging. |
164 | 77 | return logging.FileHandler(bytes(path), encoding='utf-8') | 78 | formatter = logging.Formatter(style='{', fmt=MSG_FMT, datefmt=DATE_FMT) |
165 | 79 | handler = logging.FileHandler(bytes(path), encoding='utf-8') | ||
166 | 80 | handler.setFormatter(formatter) | ||
167 | 81 | return handler | ||
168 | 78 | 82 | ||
169 | 79 | 83 | ||
170 | 80 | def initialize(*, verbosity=0): | 84 | def initialize(*, verbosity=0): |
171 | @@ -95,13 +99,11 @@ | |||
172 | 95 | # Now configure the application level logger based on the ini file. | 99 | # Now configure the application level logger based on the ini file. |
173 | 96 | log = logging.getLogger(name) | 100 | log = logging.getLogger(name) |
174 | 97 | try: | 101 | try: |
176 | 98 | handler = _make_handler(Path(config.system.logfile)) | 102 | handler = make_handler(Path(config.system.logfile)) |
177 | 99 | except PermissionError: | 103 | except PermissionError: |
179 | 100 | handler = _make_handler( | 104 | handler = make_handler( |
180 | 101 | Path(xdg_cache_home) / 'system-image' / 'client.log') | 105 | Path(xdg_cache_home) / 'system-image' / 'client.log') |
181 | 102 | handler.setLevel(level) | 106 | handler.setLevel(level) |
182 | 103 | formatter = logging.Formatter(style='{', fmt=MSG_FMT, datefmt=DATE_FMT) | ||
183 | 104 | handler.setFormatter(formatter) | ||
184 | 105 | log.addHandler(handler) | 107 | log.addHandler(handler) |
185 | 106 | log.propagate = False | 108 | log.propagate = False |
186 | 107 | # If we want more verbosity, add a stream handler. | 109 | # If we want more verbosity, add a stream handler. |
187 | @@ -111,6 +113,8 @@ | |||
188 | 111 | else: # pragma: no cover | 113 | else: # pragma: no cover |
189 | 112 | handler = logging.StreamHandler(stream=sys.stderr) | 114 | handler = logging.StreamHandler(stream=sys.stderr) |
190 | 113 | handler.setLevel(level) | 115 | handler.setLevel(level) |
191 | 116 | formatter = logging.Formatter( | ||
192 | 117 | style='{', fmt=MSG_FMT, datefmt=DATE_FMT) | ||
193 | 114 | handler.setFormatter(formatter) | 118 | handler.setFormatter(formatter) |
194 | 115 | log.addHandler(handler) | 119 | log.addHandler(handler) |
195 | 116 | # Set the overall level on the log object to the minimum level. | 120 | # Set the overall level on the log object to the minimum level. |
196 | 117 | 121 | ||
197 | === modified file 'systemimage/testing/dbus.py' | |||
198 | --- systemimage/testing/dbus.py 2015-05-08 21:41:15 +0000 | |||
199 | +++ systemimage/testing/dbus.py 2015-09-28 21:36:51 +0000 | |||
200 | @@ -22,6 +22,7 @@ | |||
201 | 22 | 22 | ||
202 | 23 | 23 | ||
203 | 24 | import os | 24 | import os |
204 | 25 | import logging | ||
205 | 25 | 26 | ||
206 | 26 | try: | 27 | try: |
207 | 27 | import pycurl | 28 | import pycurl |
208 | @@ -30,10 +31,12 @@ | |||
209 | 30 | 31 | ||
210 | 31 | from dbus.service import method, signal | 32 | from dbus.service import method, signal |
211 | 32 | from gi.repository import GLib | 33 | from gi.repository import GLib |
212 | 34 | from pathlib import Path | ||
213 | 33 | from systemimage.api import Mediator | 35 | from systemimage.api import Mediator |
214 | 34 | from systemimage.config import config | 36 | from systemimage.config import config |
215 | 35 | from systemimage.dbus import Service, log_and_exit | 37 | from systemimage.dbus import Service, log_and_exit |
216 | 36 | from systemimage.helpers import MiB, makedirs, safe_remove, version_detail | 38 | from systemimage.helpers import MiB, makedirs, safe_remove, version_detail |
217 | 39 | from systemimage.logging import make_handler | ||
218 | 37 | from unittest.mock import patch | 40 | from unittest.mock import patch |
219 | 38 | 41 | ||
220 | 39 | 42 | ||
221 | @@ -74,6 +77,10 @@ | |||
222 | 74 | class _LiveTestableService(Service): | 77 | class _LiveTestableService(Service): |
223 | 75 | """For testing purposes only.""" | 78 | """For testing purposes only.""" |
224 | 76 | 79 | ||
225 | 80 | def __init__(self, bus, object_path, loop): | ||
226 | 81 | super().__init__(bus, object_path, loop) | ||
227 | 82 | self._debug_handler = None | ||
228 | 83 | |||
229 | 77 | @log_and_exit | 84 | @log_and_exit |
230 | 78 | @method('com.canonical.SystemImage') | 85 | @method('com.canonical.SystemImage') |
231 | 79 | def Reset(self): | 86 | def Reset(self): |
232 | @@ -103,6 +110,27 @@ | |||
233 | 103 | def TornDown(self): | 110 | def TornDown(self): |
234 | 104 | pass | 111 | pass |
235 | 105 | 112 | ||
236 | 113 | @log_and_exit | ||
237 | 114 | @method('com.canonical.SystemImage', | ||
238 | 115 | in_signature='ss', | ||
239 | 116 | out_signature='ss') | ||
240 | 117 | def DebugDBusTo(self, filename, level_name): | ||
241 | 118 | # Get the existing logging level and logging file name. | ||
242 | 119 | dbus_log = logging.getLogger('systemimage.dbus') | ||
243 | 120 | old_level = logging.getLevelName(dbus_log.getEffectiveLevel()) | ||
244 | 121 | old_filename = config.system.logfile | ||
245 | 122 | # Remove any previous D-Bus debugging handler. | ||
246 | 123 | if self._debug_handler is not None: | ||
247 | 124 | dbus_log.removeHandler(self._debug_handler) | ||
248 | 125 | self._debug_handler = None | ||
249 | 126 | new_level = getattr(logging, level_name.upper()) | ||
250 | 127 | dbus_log.setLevel(new_level) | ||
251 | 128 | if filename != '': | ||
252 | 129 | self._debug_handler = make_handler(Path(filename)) | ||
253 | 130 | self._debug_handler.setLevel(new_level) | ||
254 | 131 | dbus_log.addHandler(self._debug_handler) | ||
255 | 132 | return old_filename, old_level | ||
256 | 133 | |||
257 | 106 | 134 | ||
258 | 107 | class _UpdateAutoSuccess(Service): | 135 | class _UpdateAutoSuccess(Service): |
259 | 108 | """Normal update in auto-download mode.""" | 136 | """Normal update in auto-download mode.""" |
260 | 109 | 137 | ||
261 | === modified file 'systemimage/tests/test_dbus.py' | |||
262 | --- systemimage/tests/test_dbus.py 2015-05-08 21:41:15 +0000 | |||
263 | +++ systemimage/tests/test_dbus.py 2015-09-28 21:36:51 +0000 | |||
264 | @@ -44,10 +44,12 @@ | |||
265 | 44 | 44 | ||
266 | 45 | 45 | ||
267 | 46 | import os | 46 | import os |
268 | 47 | import sys | ||
269 | 47 | import dbus | 48 | import dbus |
270 | 48 | import json | 49 | import json |
271 | 49 | import time | 50 | import time |
272 | 50 | import shutil | 51 | import shutil |
273 | 52 | import tempfile | ||
274 | 51 | import unittest | 53 | import unittest |
275 | 52 | 54 | ||
276 | 53 | from contextlib import ExitStack, suppress | 55 | from contextlib import ExitStack, suppress |
277 | @@ -61,6 +63,7 @@ | |||
278 | 61 | from systemimage.helpers import MiB, safe_remove | 63 | from systemimage.helpers import MiB, safe_remove |
279 | 62 | from systemimage.reactor import Reactor | 64 | from systemimage.reactor import Reactor |
280 | 63 | from systemimage.settings import Settings | 65 | from systemimage.settings import Settings |
281 | 66 | from systemimage.testing.controller import USING_PYCURL | ||
282 | 64 | from systemimage.testing.helpers import ( | 67 | from systemimage.testing.helpers import ( |
283 | 65 | copy, data_path, find_dbus_process, make_http_server, setup_index, | 68 | copy, data_path, find_dbus_process, make_http_server, setup_index, |
284 | 66 | setup_keyring_txz, setup_keyrings, sign, terminate_service, touch_build, | 69 | setup_keyring_txz, setup_keyrings, sign, terminate_service, touch_build, |
285 | @@ -78,6 +81,27 @@ | |||
286 | 78 | 'last_update_date error_reason') | 81 | 'last_update_date error_reason') |
287 | 79 | 82 | ||
288 | 80 | 83 | ||
289 | 84 | def capture_dbus_calls(function): | ||
290 | 85 | def inner(self, *args, **kws): | ||
291 | 86 | with ExitStack() as resources: | ||
292 | 87 | fd, filename = tempfile.mkstemp('.log') | ||
293 | 88 | os.close(fd) | ||
294 | 89 | resources.callback(os.remove, filename) | ||
295 | 90 | old_filename, old_level = self.iface.DebugDBusTo(filename, 'debug') | ||
296 | 91 | try: | ||
297 | 92 | result = function(self, *args, **kws) | ||
298 | 93 | finally: | ||
299 | 94 | self.iface.DebugDBusTo('', old_level) | ||
300 | 95 | with open(filename, 'r', encoding='utf-8') as fp: | ||
301 | 96 | print('\nvvvvv', function.__name__, | ||
302 | 97 | 'dbus calls vvvvv', file=sys.stderr) | ||
303 | 98 | sys.stderr.write(fp.read()) | ||
304 | 99 | print('^^^^^', function.__name__, | ||
305 | 100 | 'dbus calls ^^^^^', file=sys.stderr) | ||
306 | 101 | return result | ||
307 | 102 | return inner | ||
308 | 103 | |||
309 | 104 | |||
310 | 81 | def tweak_checksums(checksum): | 105 | def tweak_checksums(checksum): |
311 | 82 | index_path = os.path.join( | 106 | index_path = os.path.join( |
312 | 83 | SystemImagePlugin.controller.serverdir, | 107 | SystemImagePlugin.controller.serverdir, |
313 | @@ -1717,7 +1741,9 @@ | |||
314 | 1717 | write_bytes(full_path, 750) | 1741 | write_bytes(full_path, 750) |
315 | 1718 | tweak_checksums('') | 1742 | tweak_checksums('') |
316 | 1719 | 1743 | ||
317 | 1744 | @capture_dbus_calls | ||
318 | 1720 | def test_pause(self): | 1745 | def test_pause(self): |
319 | 1746 | # Set up some extra D-Bus debugging. | ||
320 | 1721 | self.download_manually() | 1747 | self.download_manually() |
321 | 1722 | touch_build(0, use_config=self.config) | 1748 | touch_build(0, use_config=self.config) |
322 | 1723 | reactor = SignalCapturingReactor('UpdateAvailableStatus') | 1749 | reactor = SignalCapturingReactor('UpdateAvailableStatus') |
323 | @@ -1966,8 +1992,6 @@ | |||
324 | 1966 | self.assertEqual(reactor.uas_signals[0], reactor.uas_signals[1]) | 1992 | self.assertEqual(reactor.uas_signals[0], reactor.uas_signals[1]) |
325 | 1967 | 1993 | ||
326 | 1968 | 1994 | ||
327 | 1969 | from systemimage.testing.controller import USING_PYCURL | ||
328 | 1970 | |||
329 | 1971 | @unittest.skipIf(os.getuid() == 0, 'Test cannot succeed when run as root') | 1995 | @unittest.skipIf(os.getuid() == 0, 'Test cannot succeed when run as root') |
330 | 1972 | @unittest.skipUnless(USING_PYCURL, 'LP: #1411866') | 1996 | @unittest.skipUnless(USING_PYCURL, 'LP: #1411866') |
331 | 1973 | class TestDBusCheckForUpdateToUnwritablePartition(_LiveTesting): | 1997 | class TestDBusCheckForUpdateToUnwritablePartition(_LiveTesting): |
332 | 1974 | 1998 | ||
333 | === modified file 'systemimage/tests/test_helpers.py' | |||
334 | --- systemimage/tests/test_helpers.py 2015-05-08 21:41:15 +0000 | |||
335 | +++ systemimage/tests/test_helpers.py 2015-09-28 21:36:51 +0000 | |||
336 | @@ -255,6 +255,52 @@ | |||
337 | 255 | # The last update date will be the date of the 99_build.ini file. | 255 | # The last update date will be the date of the 99_build.ini file. |
338 | 256 | self.assertEqual(last_update_date(), '2022-01-02 03:04:05') | 256 | self.assertEqual(last_update_date(), '2022-01-02 03:04:05') |
339 | 257 | 257 | ||
340 | 258 | @configuration | ||
341 | 259 | def test_dangling_symlink(self, config): | ||
342 | 260 | # LP: #1495688 reports a problem where /userdata/.last_update doesn't | ||
343 | 261 | # exist, and the files in the config.d directory are dangling | ||
344 | 262 | # symlinks. In this case, there's really little that can be done to | ||
345 | 263 | # find a reliable last update date, but at least we don't crash. | ||
346 | 264 | # | ||
347 | 265 | # Start by deleting any existing .ini files in config.d. | ||
348 | 266 | for path in Path(config.config_d).iterdir(): | ||
349 | 267 | if path.suffix == '.ini': | ||
350 | 268 | path.unlink() | ||
351 | 269 | with ExitStack() as stack: | ||
352 | 270 | tmpdir = stack.enter_context(temporary_directory()) | ||
353 | 271 | userdata_path = Path(tmpdir) / '.last_update' | ||
354 | 272 | stack.enter_context(patch('systemimage.helpers.LAST_UPDATE_FILE', | ||
355 | 273 | str(userdata_path))) | ||
356 | 274 | # Do not create the .last_update file. | ||
357 | 275 | missing_ini = Path(tmpdir) / 'missing.ini' | ||
358 | 276 | config.ini_files = [missing_ini] | ||
359 | 277 | # Do not create the missing.ini file, but do create a symlink from | ||
360 | 278 | # a config.d file to this missing file. | ||
361 | 279 | default_ini = Path(config.config_d) / '00_default.ini' | ||
362 | 280 | default_ini.symlink_to(missing_ini) | ||
363 | 281 | last_update_date() | ||
364 | 282 | self.assertEqual(last_update_date(), 'Unknown') | ||
365 | 283 | |||
366 | 284 | @configuration | ||
367 | 285 | def test_post_startup_delete(self, config): | ||
368 | 286 | # Like test_dangling_symlink() except that an existing ini file gets | ||
369 | 287 | # deleted after system startup, so some of the files that | ||
370 | 288 | # last_update_date() looks at will throw an exception. | ||
371 | 289 | # | ||
372 | 290 | # Start by deleting any existing .ini files in config.d. This time | ||
373 | 291 | # however we don't update config.ini_files. | ||
374 | 292 | for path in Path(config.config_d).iterdir(): | ||
375 | 293 | if path.suffix == '.ini': | ||
376 | 294 | path.unlink() | ||
377 | 295 | with ExitStack() as stack: | ||
378 | 296 | tmpdir = stack.enter_context(temporary_directory()) | ||
379 | 297 | userdata_path = Path(tmpdir) / '.last_update' | ||
380 | 298 | stack.enter_context(patch('systemimage.helpers.LAST_UPDATE_FILE', | ||
381 | 299 | str(userdata_path))) | ||
382 | 300 | # Do not create the .last_update file. | ||
383 | 301 | last_update_date() | ||
384 | 302 | self.assertEqual(last_update_date(), 'Unknown') | ||
385 | 303 | |||
386 | 258 | 304 | ||
387 | 259 | class TestPhasedPercentage(unittest.TestCase): | 305 | class TestPhasedPercentage(unittest.TestCase): |
388 | 260 | def setUp(self): | 306 | def setUp(self): |
389 | 261 | 307 | ||
390 | === modified file 'systemimage/version.txt' | |||
391 | --- systemimage/version.txt 2015-06-17 15:18:22 +0000 | |||
392 | +++ systemimage/version.txt 2015-09-28 21:36:51 +0000 | |||
393 | @@ -1,1 +1,1 @@ | |||
395 | 1 | 3.0.1 | 1 | 3.0.2 |