| Status: | Merged |
|---|---|
| Approved by: | Selene ToyKeeper |
| Approved revision: | 572 |
| Merged at revision: | 524 |
| Proposed branch: | lp:autopilot |
| Merge into: | lp:autopilot/1.5 |
| Diff against target: |
328 lines (+74/-49) 10 files modified
autopilot/_logging.py (+5/-4) autopilot/_video.py (+2/-2) autopilot/application/_launcher.py (+7/-4) autopilot/content.py (+11/-2) autopilot/introspection/types.py (+7/-30) autopilot/tests/unit/test_platform.py (+2/-2) autopilot/tests/unit/test_utilities.py (+16/-0) autopilot/utilities.py (+20/-0) debian/control (+2/-0) docs/otto.py (+2/-5) |
| To merge this branch: | bzr merge lp:autopilot |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Martin Pitt (community) | packaging | Approve | |
| Selene ToyKeeper (community) | Approve | ||
| Max Brustkern (community) | Approve | ||
| PS Jenkins bot | continuous-integration | Approve | |
|
Review via email:
|
|||
Commit message
Stops attempts to access NoneType instead of bytes''. Considered a workaround, fixed in newer testtools.
Description of the change
Provide a workaround due to older versions of testtools on vivid. Stops attempts to access NoneType instead of bytes''
| PS Jenkins bot (ps-jenkins) wrote : | # |
| Max Brustkern (nuclearbob) wrote : | # |
This looks good to me, but I haven't run tests yet.
| Selene ToyKeeper (toykeeper) wrote : | # |
Approving since it's the same as the other already-approved MP.
| Max Brustkern (nuclearbob) wrote : | # |
There are sphinx build problems in xenial with docs/api/
I'll look into a resolution for that.
| Max Brustkern (nuclearbob) wrote : | # |
The ".. otto::" lines are creating problems. I suspect maybe something we're using there work differently in the current version of sphinx, so I'll look for API changes.
| Max Brustkern (nuclearbob) wrote : | # |
This line in otto.py is the problem:
image_container
| Max Brustkern (nuclearbob) wrote : | # |
If I remove that line, sphinx builds fine, but I get 8 test failures around datetime stuff that don't appear on wily. I'll look into that more.
| Max Brustkern (nuclearbob) wrote : | # |
I get these failures running tests under python3.5 on xenial, while they pass if run under 3.4:
/usr/lib/
tests = list(self.
** (process:27668): WARNING **: Unable to connect to Upstart bus: Error spawning command line 'dbus-launch --autolaunch=
** (process:27668): WARNING **: Unable to connect to Upstart bus: Error spawning command line 'dbus-launch --autolaunch=
** (process:27668): WARNING **: Unable to connect to Upstart bus: Error spawning command line 'dbus-launch --autolaunch=
** (process:27668): WARNING **: Unable to connect to Upstart bus: Error spawning command line 'dbus-launch --autolaunch=
** (process:27668): WARNING **: Unable to connect to Upstart bus: Error spawning command line 'dbus-launch --autolaunch=
** (process:27668): WARNING **: Unable to connect to Upstart bus: Error spawning command line 'dbus-launch --autolaunch=
** (process:27668): WARNING **: Unable to connect to Upstart bus: Error spawning command line 'dbus-launch --autolaunch=
Followed stream is empty.
Could not add content object 'autopilot.
Could not add content object 'autopilot.
Followed stream is empty.
Followed stream is empty.
INFO:root:
INFO:root:Starting test Test.id
INFO:autopilot.
INFO:root:Autopilot Source Version: 1.5.0
INFO:root:Autopilot Source Version: 1.5.0
INFO:root:Autopilot Source Version: 1.5.0
INFO:root:Autopilot Source Version: 1.5.0
INFO:root:Autopilot Source Version: 1.5.0
INFO:root:Autopilot Source Version: 1.5.0
INFO:root:Autopilot Source Version: 1.5.0
INFO:root:Autopilot Source Version: 1.5.0
INFO:root:Autopilot Source Version: 1.5.0
INFO:root:Autopilot Source Version: 1.5.0
INFO:root:Autopilot Source Version: 1.5.0
INFO:root:Autopilot Source Version: 1.5.0
INFO:root:Autopilot Source Version: 1.5.0
WARNING:autopil...
| Max Brustkern (nuclearbob) wrote : | # |
The same problems (sphinx and test failures) appear when building lp:autopilot/1.5 under xenial. I think this is an issue with the transition to python3.5
| Max Brustkern (nuclearbob) wrote : | # |
Changing debian/rules to force python3.4 for the testing portion allows that to work, but I can't get sphinx to finish building yet.
- 573. By Christopher Lee
-
Fix build issues on Xenial. Incl. simplifying DateTime. Fixes: https:/
/bugs.launchpad .net/bugs/ 1524000. Approved by Max Brustkern, PS Jenkins bot.
- 574. By Christopher Lee
-
Fix missing dep packaging.
Approved by PS Jenkins bot.
| Martin Pitt (pitti) wrote : | # |
(Trivial) packaging change ack, python3-tz is in main and no other changes in the packaging. Thanks!
Preview Diff
| 1 | === modified file 'autopilot/_logging.py' |
| 2 | --- autopilot/_logging.py 2014-07-14 04:07:05 +0000 |
| 3 | +++ autopilot/_logging.py 2015-12-09 05:28:20 +0000 |
| 4 | @@ -22,10 +22,11 @@ |
| 5 | import logging |
| 6 | from io import StringIO |
| 7 | |
| 8 | -from testtools.content import text_content |
| 9 | - |
| 10 | from autopilot._fixtures import FixtureWithDirectAddDetail |
| 11 | -from autopilot.utilities import LogFormatter |
| 12 | +from autopilot.utilities import ( |
| 13 | + LogFormatter, |
| 14 | + safe_text_content, |
| 15 | +) |
| 16 | |
| 17 | |
| 18 | class TestCaseLoggingFixture(FixtureWithDirectAddDetail): |
| 19 | @@ -54,7 +55,7 @@ |
| 20 | self._log_buffer.seek(0) |
| 21 | self.caseAddDetail( |
| 22 | 'test-log', |
| 23 | - text_content(self._log_buffer.getvalue()) |
| 24 | + safe_text_content(self._log_buffer.getvalue()) |
| 25 | ) |
| 26 | root_logger.removeHandler(self._log_handler) |
| 27 | self._log_buffer = None |
| 28 | |
| 29 | === modified file 'autopilot/_video.py' |
| 30 | --- autopilot/_video.py 2014-09-05 04:03:57 +0000 |
| 31 | +++ autopilot/_video.py 2015-12-09 05:28:20 +0000 |
| 32 | @@ -26,10 +26,10 @@ |
| 33 | import signal |
| 34 | import subprocess |
| 35 | |
| 36 | -from testtools.content import text_content |
| 37 | from testtools.matchers import NotEquals |
| 38 | |
| 39 | from autopilot.matchers import Eventually |
| 40 | +from autopilot.utilities import safe_text_content |
| 41 | |
| 42 | |
| 43 | logger = logging.getLogger(__name__) |
| 44 | @@ -103,7 +103,7 @@ |
| 45 | if self._capture_process.returncode != 0: |
| 46 | test_instance.addDetail( |
| 47 | 'video capture log', |
| 48 | - text_content(self._capture_process.stdout.read())) |
| 49 | + safe_text_content(self._capture_process.stdout.read())) |
| 50 | self._capture_process = None |
| 51 | self._currently_recording_description = None |
| 52 | |
| 53 | |
| 54 | === modified file 'autopilot/application/_launcher.py' |
| 55 | --- autopilot/application/_launcher.py 2015-09-07 21:59:05 +0000 |
| 56 | +++ autopilot/application/_launcher.py 2015-12-09 05:28:20 +0000 |
| 57 | @@ -22,6 +22,8 @@ |
| 58 | import fixtures |
| 59 | from gi.repository import GLib |
| 60 | try: |
| 61 | + from gi import require_version |
| 62 | + require_version('UbuntuAppLaunch', '2') |
| 63 | from gi.repository import UbuntuAppLaunch |
| 64 | except ImportError: |
| 65 | # Note: the renamed package is not in Trusty. |
| 66 | @@ -32,7 +34,8 @@ |
| 67 | import psutil |
| 68 | import subprocess |
| 69 | import signal |
| 70 | -from testtools.content import content_from_file, text_content |
| 71 | +from testtools.content import content_from_file |
| 72 | +from autopilot.utilities import safe_text_content |
| 73 | |
| 74 | from autopilot._timeout import Timeout |
| 75 | from autopilot._fixtures import FixtureWithDirectAddDetail |
| 76 | @@ -428,15 +431,15 @@ |
| 77 | stdout, stderr, return_code = _kill_process(process) |
| 78 | self.caseAddDetail( |
| 79 | 'process-return-code (%s)' % app_path, |
| 80 | - text_content(str(return_code)) |
| 81 | + safe_text_content(str(return_code)) |
| 82 | ) |
| 83 | self.caseAddDetail( |
| 84 | 'process-stdout (%s)' % app_path, |
| 85 | - text_content(stdout) |
| 86 | + safe_text_content(stdout) |
| 87 | ) |
| 88 | self.caseAddDetail( |
| 89 | 'process-stderr (%s)' % app_path, |
| 90 | - text_content(stderr) |
| 91 | + safe_text_content(stderr) |
| 92 | ) |
| 93 | |
| 94 | |
| 95 | |
| 96 | === modified file 'autopilot/content.py' |
| 97 | --- autopilot/content.py 2014-05-23 13:22:56 +0000 |
| 98 | +++ autopilot/content.py 2015-12-09 05:28:20 +0000 |
| 99 | @@ -22,7 +22,8 @@ |
| 100 | import io |
| 101 | |
| 102 | import logging |
| 103 | -from testtools.content import ContentType, content_from_stream, text_content |
| 104 | +from testtools.content import ContentType, content_from_stream |
| 105 | +from autopilot.utilities import safe_text_content |
| 106 | |
| 107 | _logger = logging.getLogger(__name__) |
| 108 | |
| 109 | @@ -46,7 +47,7 @@ |
| 110 | content_name, |
| 111 | str(e) |
| 112 | ) |
| 113 | - return text_content('') |
| 114 | + return safe_text_content('') |
| 115 | else: |
| 116 | file_obj.seek(0, io.SEEK_END) |
| 117 | return follow_stream( |
| 118 | @@ -74,5 +75,13 @@ |
| 119 | ContentType('text', 'plain', {'charset': 'iso8859-1'}), |
| 120 | buffer_now=True |
| 121 | ) |
| 122 | + |
| 123 | + # Work around a bug in older testtools where an empty file would result |
| 124 | + # in None being decoded and exploding. |
| 125 | + # See: https://bugs.launchpad.net/autopilot/+bug/1517289 |
| 126 | + if list(content_obj.iter_text()) == []: |
| 127 | + _logger.warning('Followed stream is empty.') |
| 128 | + content_obj = safe_text_content('Unable to read file data.') |
| 129 | + |
| 130 | test_case.addDetail(content_name, content_obj) |
| 131 | test_case.addCleanup(make_content) |
| 132 | |
| 133 | === modified file 'autopilot/introspection/types.py' |
| 134 | --- autopilot/introspection/types.py 2014-10-22 20:43:01 +0000 |
| 135 | +++ autopilot/introspection/types.py 2015-12-09 05:28:20 +0000 |
| 136 | @@ -37,8 +37,9 @@ |
| 137 | |
| 138 | """ |
| 139 | |
| 140 | +import pytz |
| 141 | from datetime import datetime, time, timedelta |
| 142 | -from dateutil.tz import gettz, tzutc |
| 143 | +from dateutil.tz import gettz |
| 144 | |
| 145 | import dbus |
| 146 | import logging |
| 147 | @@ -650,39 +651,15 @@ |
| 148 | super(DateTime, self).__init__(*args, **kwargs) |
| 149 | # Using timedelta in this manner is a workaround so that we can support |
| 150 | # timestamps larger than the 32bit time_t limit on 32bit hardware. |
| 151 | - # We then apply another workaround where timedelta doesn't apply |
| 152 | - # daylight savings, so we need to work out the offsets for the |
| 153 | - # localtime manually and apply them to give us the correct local time. |
| 154 | + # We then apply the timezone information to this to get the correct |
| 155 | + # datetime. |
| 156 | # |
| 157 | # Note. self[0] is a UTC timestamp |
| 158 | - EPOCH = datetime(1970, 1, 1, tzinfo=tzutc()) |
| 159 | + utc = pytz.timezone('UTC') |
| 160 | + EPOCH = datetime(1970, 1, 1, tzinfo=utc) |
| 161 | utc_dt = EPOCH + timedelta(seconds=self[0]) |
| 162 | |
| 163 | - local_tzinfo = gettz() |
| 164 | - |
| 165 | - # Get the localtimes timezone offset (known as standard offset) by |
| 166 | - # subtracting its dst offset (if any) from its utc offset. |
| 167 | - # We apply this to the utc datetime object to get datetime object in |
| 168 | - # localtime. |
| 169 | - # (We will check (once we have a local datetime) if the time is in dst |
| 170 | - # and make that adjustment then.) |
| 171 | - utc_offset = local_tzinfo.utcoffset(utc_dt) |
| 172 | - dst_offset = local_tzinfo.dst(utc_dt) |
| 173 | - standard_offset = utc_offset - dst_offset |
| 174 | - |
| 175 | - # Create a local timezone aware datetime object from the utc_dt |
| 176 | - # (i.e. attaching a timezone to it) and apply the standard offset to |
| 177 | - # give us the local time. |
| 178 | - local_dt = utc_dt.replace(tzinfo=local_tzinfo) + standard_offset |
| 179 | - |
| 180 | - # If the new local time is firmly in std time then the standard offset |
| 181 | - # will be 0 (i.e. timedelta(0)). |
| 182 | - # If the delta isn't 0 then we need to use the timezone information to |
| 183 | - # apply the dst delta to the local time. |
| 184 | - if standard_offset != timedelta(0): |
| 185 | - local_dt = local_dt + local_tzinfo.dst(local_dt) |
| 186 | - |
| 187 | - self._cached_dt = local_dt |
| 188 | + self._cached_dt = utc_dt.astimezone(gettz()) |
| 189 | |
| 190 | @property |
| 191 | def year(self): |
| 192 | |
| 193 | === modified file 'autopilot/tests/unit/test_platform.py' |
| 194 | --- autopilot/tests/unit/test_platform.py 2014-07-23 03:37:24 +0000 |
| 195 | +++ autopilot/tests/unit/test_platform.py 2015-12-09 05:28:20 +0000 |
| 196 | @@ -39,7 +39,7 @@ |
| 197 | @patch('autopilot.platform._PlatformDetector') |
| 198 | def test_model_creates_platform_detector(self, mock_detector): |
| 199 | platform.model() |
| 200 | - mock_detector.create.assert_called_once() |
| 201 | + mock_detector.create.assert_called_once_with() |
| 202 | |
| 203 | @patch('autopilot.platform._PlatformDetector._cached_detector') |
| 204 | def test_model_returns_correct_value(self, mock_detector): |
| 205 | @@ -49,7 +49,7 @@ |
| 206 | @patch('autopilot.platform._PlatformDetector') |
| 207 | def test_image_codename_creates_platform_detector(self, mock_detector): |
| 208 | platform.image_codename() |
| 209 | - mock_detector.create.assert_called_once() |
| 210 | + mock_detector.create.assert_called_once_with() |
| 211 | |
| 212 | @patch('autopilot.platform._PlatformDetector._cached_detector') |
| 213 | def test_image_codename_returns_correct_value(self, mock_detector): |
| 214 | |
| 215 | === modified file 'autopilot/tests/unit/test_utilities.py' |
| 216 | --- autopilot/tests/unit/test_utilities.py 2014-11-10 11:00:21 +0000 |
| 217 | +++ autopilot/tests/unit/test_utilities.py 2015-12-09 05:28:20 +0000 |
| 218 | @@ -20,6 +20,7 @@ |
| 219 | from unittest.mock import Mock, patch |
| 220 | import re |
| 221 | from testtools import TestCase |
| 222 | +from testtools.content import Content |
| 223 | from testtools.matchers import ( |
| 224 | Equals, |
| 225 | IsInstance, |
| 226 | @@ -39,6 +40,7 @@ |
| 227 | compatible_repr, |
| 228 | deprecated, |
| 229 | EventDelay, |
| 230 | + safe_text_content, |
| 231 | sleep, |
| 232 | ) |
| 233 | |
| 234 | @@ -357,3 +359,17 @@ |
| 235 | wrapped.reset_cache() |
| 236 | wrapped() |
| 237 | self.assertThat(inner.call_count, Equals(2)) |
| 238 | + |
| 239 | + |
| 240 | +class SafeTextContentTests(TestCase): |
| 241 | + |
| 242 | + def test_raises_TypeError_on_non_texttype(self): |
| 243 | + self.assertThat( |
| 244 | + lambda: safe_text_content(None), |
| 245 | + raises(TypeError) |
| 246 | + ) |
| 247 | + |
| 248 | + def test_returns_text_content_object(self): |
| 249 | + example_string = self.getUniqueString() |
| 250 | + content_obj = safe_text_content(example_string) |
| 251 | + self.assertTrue(isinstance(content_obj, Content)) |
| 252 | |
| 253 | === modified file 'autopilot/utilities.py' |
| 254 | --- autopilot/utilities.py 2014-11-10 11:00:21 +0000 |
| 255 | +++ autopilot/utilities.py 2015-12-09 05:28:20 +0000 |
| 256 | @@ -29,6 +29,7 @@ |
| 257 | import os |
| 258 | import time |
| 259 | import timeit |
| 260 | +from testtools.content import text_content |
| 261 | from functools import wraps |
| 262 | |
| 263 | from autopilot.exceptions import BackendException |
| 264 | @@ -37,6 +38,25 @@ |
| 265 | logger = logging.getLogger(__name__) |
| 266 | |
| 267 | |
| 268 | +def safe_text_content(text): |
| 269 | + """Return testtools.content.Content object. |
| 270 | + |
| 271 | + Safe in the sense that it will catch any attempt to attach NoneType |
| 272 | + objects. |
| 273 | + |
| 274 | + :raises ValueError: If `text` is not a text-type object. |
| 275 | + |
| 276 | + """ |
| 277 | + if not isinstance(text, str): |
| 278 | + raise TypeError( |
| 279 | + 'text argument must be string not {}'.format( |
| 280 | + type(text).__name__ |
| 281 | + ) |
| 282 | + ) |
| 283 | + |
| 284 | + return text_content(text) |
| 285 | + |
| 286 | + |
| 287 | def _pick_backend(backends, preferred_backend): |
| 288 | """Pick a backend and return an instance of it.""" |
| 289 | possible_backends = list(backends.keys()) |
| 290 | |
| 291 | === modified file 'debian/control' |
| 292 | --- debian/control 2015-07-22 23:29:11 +0000 |
| 293 | +++ debian/control 2015-12-09 05:28:20 +0000 |
| 294 | @@ -30,6 +30,7 @@ |
| 295 | python3-subunit, |
| 296 | python3-testscenarios, |
| 297 | python3-testtools, |
| 298 | + python3-tz, |
| 299 | python3-xlib (>=0.14+20091101-1ubuntu3), |
| 300 | sphinx-common, |
| 301 | texlive-latex-extra, |
| 302 | @@ -55,6 +56,7 @@ |
| 303 | python3-subunit, |
| 304 | python3-testscenarios, |
| 305 | python3-testtools, |
| 306 | + python3-tz, |
| 307 | udev, |
| 308 | ${misc:Depends}, |
| 309 | ${python3:Depends}, |
| 310 | |
| 311 | === modified file 'docs/otto.py' |
| 312 | --- docs/otto.py 2013-07-25 05:47:36 +0000 |
| 313 | +++ docs/otto.py 2015-12-09 05:28:20 +0000 |
| 314 | @@ -56,12 +56,9 @@ |
| 315 | self.content, self.lineno, self.content_offset, |
| 316 | self.block_text, self.state, self.state_machine) |
| 317 | image_container = nodes.container() |
| 318 | - image_container.children.append(nodes.image(uri='/images/otto-64.png')) |
| 319 | + image_container.append(nodes.image(uri='/images/otto-64.png')) |
| 320 | image_container['classes'] = ['otto-image-container'] |
| 321 | outer_container = nodes.container() |
| 322 | - outer_container.children.extend( |
| 323 | - [image_container] |
| 324 | - + ad |
| 325 | - ) |
| 326 | + outer_container.extend([image_container] + ad) |
| 327 | outer_container['classes'] = ['otto-says-container'] |
| 328 | return [outer_container] |
PASSED: Continuous integration, rev:572 jenkins. qa.ubuntu. com/job/ autopilot- 1.5-ci/ 42/ jenkins. qa.ubuntu. com/job/ autopilot- 1.5-wily- amd64-ci/ 16 jenkins. qa.ubuntu. com/job/ autopilot- 1.5-wily- amd64-ci/ 16/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ autopilot- 1.5-wily- armhf-ci/ 16 jenkins. qa.ubuntu. com/job/ autopilot- 1.5-wily- armhf-ci/ 16/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ autopilot- 1.5-wily- i386-ci/ 16 jenkins. qa.ubuntu. com/job/ autopilot- 1.5-wily- i386-ci/ 16/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- wily-touch/ 977 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- wily-touch/ 544 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- wily-armhf/ 977 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- wily-armhf/ 977/artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 25693
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/autopilot- 1.5-ci/ 42/rebuild
http://