Status: | Merged |
---|---|
Approved by: | Santiago Baldassin |
Approved revision: | 592 |
Merged at revision: | 584 |
Proposed branch: | lp:autopilot |
Merge into: | lp:autopilot/1.6 |
Diff against target: |
745 lines (+125/-263) 17 files modified
README (+6/-0) autopilot/application/_launcher.py (+20/-14) autopilot/display/__init__.py (+6/-45) autopilot/display/_upa.py (+45/-27) autopilot/input/__init__.py (+7/-13) autopilot/introspection/types.py (+1/-0) autopilot/introspection/utilities.py (+1/-0) autopilot/platform.py (+2/-21) autopilot/process/__init__.py (+0/-4) autopilot/run.py (+1/-0) autopilot/testcase.py (+8/-7) autopilot/tests/unit/introspection_base.py (+1/-0) autopilot/tests/unit/test_application_launcher.py (+18/-21) autopilot/tests/unit/test_platform.py (+0/-22) autopilot/tests/unit/test_query_resolution.py (+0/-82) autopilot/utilities.py (+2/-0) debian/control (+7/-7) |
To merge this branch: | bzr merge lp:autopilot |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Autopilot Hackers | Pending | ||
Review via email: mp+318824@code.launchpad.net |
Commit message
New upstream release.
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'README' | |||
2 | --- README 2016-08-04 05:32:39 +0000 | |||
3 | +++ README 2017-03-02 18:46:50 +0000 | |||
4 | @@ -72,6 +72,12 @@ | |||
5 | 72 | If you are in the root of the autopilot source tree this will run/list the tests from | 72 | If you are in the root of the autopilot source tree this will run/list the tests from |
6 | 73 | within that local module. Otherwise autopilot will look in the system python path. | 73 | within that local module. Otherwise autopilot will look in the system python path. |
7 | 74 | 74 | ||
8 | 75 | Release Autopilot | ||
9 | 76 | ================= | ||
10 | 77 | 1. Open a new request on bileto: https://bileto.ubuntu.com/ with the lp:autopilot -> lp:autopilot/1.5 merge proposal | ||
11 | 78 | 2. Add the relevant details (i.e. bug fix details in the landing description and a link to the testplan: https://wiki.ubuntu.com/Process/Merges/TestPlan/autopilot) | ||
12 | 79 | 3. Build the silo and run the tests | ||
13 | 80 | 4. Once happy with all tests approve and publish the result | ||
14 | 75 | 81 | ||
15 | 76 | Release Manual Tests | 82 | Release Manual Tests |
16 | 77 | ==================== | 83 | ==================== |
17 | 78 | 84 | ||
18 | === modified file 'autopilot/application/_launcher.py' | |||
19 | --- autopilot/application/_launcher.py 2015-12-08 21:42:14 +0000 | |||
20 | +++ autopilot/application/_launcher.py 2017-03-02 18:46:50 +0000 | |||
21 | @@ -1,7 +1,7 @@ | |||
22 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
23 | 2 | # | 2 | # |
24 | 3 | # Autopilot Functional Test Tool | 3 | # Autopilot Functional Test Tool |
26 | 4 | # Copyright (C) 2013 Canonical | 4 | # Copyright (C) 2013,2017 Canonical |
27 | 5 | # | 5 | # |
28 | 6 | # This program is free software: you can redistribute it and/or modify | 6 | # This program is free software: you can redistribute it and/or modify |
29 | 7 | # it under the terms of the GNU General Public License as published by | 7 | # it under the terms of the GNU General Public License as published by |
30 | @@ -20,21 +20,20 @@ | |||
31 | 20 | """Base module for application launchers.""" | 20 | """Base module for application launchers.""" |
32 | 21 | 21 | ||
33 | 22 | import fixtures | 22 | import fixtures |
35 | 23 | from gi.repository import GLib | 23 | from gi import require_version |
36 | 24 | try: | 24 | try: |
38 | 25 | from gi import require_version | 25 | require_version('UbuntuAppLaunch', '3') |
39 | 26 | except ValueError: | ||
40 | 26 | require_version('UbuntuAppLaunch', '2') | 27 | require_version('UbuntuAppLaunch', '2') |
45 | 27 | from gi.repository import UbuntuAppLaunch | 28 | from gi.repository import GLib, UbuntuAppLaunch |
46 | 28 | except ImportError: | 29 | |
43 | 29 | # Note: the renamed package is not in Trusty. | ||
44 | 30 | from gi.repository import UpstartAppLaunch as UbuntuAppLaunch | ||
47 | 31 | import json | 30 | import json |
48 | 32 | import logging | 31 | import logging |
49 | 33 | import os | 32 | import os |
50 | 34 | import psutil | 33 | import psutil |
51 | 35 | import subprocess | 34 | import subprocess |
52 | 36 | import signal | 35 | import signal |
54 | 37 | from testtools.content import content_from_file | 36 | from systemd import journal |
55 | 38 | from autopilot.utilities import safe_text_content | 37 | from autopilot.utilities import safe_text_content |
56 | 39 | 38 | ||
57 | 40 | from autopilot._timeout import Timeout | 39 | from autopilot._timeout import Timeout |
58 | @@ -186,13 +185,20 @@ | |||
59 | 186 | self.addCleanup(self._stop_application, app_id) | 185 | self.addCleanup(self._stop_application, app_id) |
60 | 187 | self.addCleanup(self._attach_application_log, app_id) | 186 | self.addCleanup(self._attach_application_log, app_id) |
61 | 188 | 187 | ||
62 | 188 | @staticmethod | ||
63 | 189 | def _get_user_unit_match(app_id): | ||
64 | 190 | return 'ubuntu-app-launch-*-%s-*.service' % app_id | ||
65 | 191 | |||
66 | 189 | def _attach_application_log(self, app_id): | 192 | def _attach_application_log(self, app_id): |
73 | 190 | log_path = UbuntuAppLaunch.application_log_path(app_id) | 193 | j = journal.Reader() |
74 | 191 | if log_path and os.path.exists(log_path): | 194 | j.log_level(journal.LOG_INFO) |
75 | 192 | self.caseAddDetail( | 195 | j.add_match(_SYSTEMD_USER_UNIT=self._get_user_unit_match(app_id)) |
76 | 193 | "Application Log (%s)" % app_id, | 196 | log_data = '' |
77 | 194 | content_from_file(log_path) | 197 | for i in j: |
78 | 195 | ) | 198 | log_data += str(i) + '\n' |
79 | 199 | if len(log_data) > 0: | ||
80 | 200 | self.caseAddDetail('Application Log (%s)' % app_id, | ||
81 | 201 | safe_text_content(log_data)) | ||
82 | 196 | 202 | ||
83 | 197 | def _stop_application(self, app_id): | 203 | def _stop_application(self, app_id): |
84 | 198 | state = {} | 204 | state = {} |
85 | 199 | 205 | ||
86 | === modified file 'autopilot/display/__init__.py' | |||
87 | --- autopilot/display/__init__.py 2014-07-09 00:21:04 +0000 | |||
88 | +++ autopilot/display/__init__.py 2017-03-02 18:46:50 +0000 | |||
89 | @@ -40,9 +40,9 @@ | |||
90 | 40 | def is_rect_on_screen(screen_number, rect): | 40 | def is_rect_on_screen(screen_number, rect): |
91 | 41 | """Return True if *rect* is **entirely** on the specified screen, with no | 41 | """Return True if *rect* is **entirely** on the specified screen, with no |
92 | 42 | overlap.""" | 42 | overlap.""" |
96 | 43 | (x, y, w, h) = rect | 43 | x, y, w, h = rect |
97 | 44 | (mx, my, mw, mh) = Display.create().get_screen_geometry(screen_number) | 44 | mx, my, mw, mh = Display.create().get_screen_geometry(screen_number) |
98 | 45 | return (x >= mx and x + w <= mx + mw and y >= my and y + h <= my + mh) | 45 | return x >= mx and x + w <= mx + mw and y >= my and y + h <= my + mh |
99 | 46 | 46 | ||
100 | 47 | 47 | ||
101 | 48 | def is_point_on_screen(screen_number, point): | 48 | def is_point_on_screen(screen_number, point): |
102 | @@ -52,8 +52,8 @@ | |||
103 | 52 | 52 | ||
104 | 53 | """ | 53 | """ |
105 | 54 | x, y = point | 54 | x, y = point |
108 | 55 | (mx, my, mw, mh) = Display.create().get_screen_geometry(screen_number) | 55 | mx, my, mw, mh = Display.create().get_screen_geometry(screen_number) |
109 | 56 | return (x >= mx and x < mx + mw and y >= my and y < my + mh) | 56 | return mx <= x < mx + mw and my <= y < my + mh |
110 | 57 | 57 | ||
111 | 58 | 58 | ||
112 | 59 | def is_point_on_any_screen(point): | 59 | def is_point_on_any_screen(point): |
113 | @@ -71,45 +71,6 @@ | |||
114 | 71 | Mouse.create().move(x, y, False) | 71 | Mouse.create().move(x, y, False) |
115 | 72 | 72 | ||
116 | 73 | 73 | ||
117 | 74 | # veebers TODO: Write this so it's usable. | ||
118 | 75 | # def drag_window_to_screen(self, window, screen): | ||
119 | 76 | # """Drags *window* to *screen* | ||
120 | 77 | |||
121 | 78 | # :param BamfWindow window: The window to drag | ||
122 | 79 | # :param integer screen: The screen to drag the *window* to | ||
123 | 80 | # :raises: **TypeError** if *window* is not a BamfWindow | ||
124 | 81 | |||
125 | 82 | # """ | ||
126 | 83 | # if not isinstance(window, BamfWindow): | ||
127 | 84 | # raise TypeError("Window must be a BamfWindow") | ||
128 | 85 | |||
129 | 86 | # if window.monitor == screen: | ||
130 | 87 | # logger.debug( | ||
131 | 88 | # "Window %r is already on screen %d." % (window.x_id, screen)) | ||
132 | 89 | # return | ||
133 | 90 | |||
134 | 91 | # assert(not window.is_maximized) | ||
135 | 92 | # (win_x, win_y, win_w, win_h) = window.geometry | ||
136 | 93 | # (mx, my, mw, mh) = self.get_screen_geometry(screen) | ||
137 | 94 | |||
138 | 95 | # logger.debug("Dragging window %r to screen %d." % (window.x_id, screen)) | ||
139 | 96 | |||
140 | 97 | # mouse = Mouse() | ||
141 | 98 | # keyboard = Keyboard() | ||
142 | 99 | # mouse.move(win_x + win_w/2, win_y + win_h/2) | ||
143 | 100 | # keyboard.press("Alt") | ||
144 | 101 | # mouse.press() | ||
145 | 102 | # keyboard.release("Alt") | ||
146 | 103 | |||
147 | 104 | # # We do the movements in two steps, to reduce the risk of being | ||
148 | 105 | # # blocked by the pointer barrier | ||
149 | 106 | # target_x = mx + mw/2 | ||
150 | 107 | # target_y = my + mh/2 | ||
151 | 108 | # mouse.move(win_x, target_y, rate=20, time_between_events=0.005) | ||
152 | 109 | # mouse.move(target_x, target_y, rate=20, time_between_events=0.005) | ||
153 | 110 | # mouse.release() | ||
154 | 111 | |||
155 | 112 | |||
156 | 113 | class Display(object): | 74 | class Display(object): |
157 | 114 | 75 | ||
158 | 115 | """The base class/inteface for the display devices.""" | 76 | """The base class/inteface for the display devices.""" |
159 | @@ -146,8 +107,8 @@ | |||
160 | 146 | return Display() | 107 | return Display() |
161 | 147 | 108 | ||
162 | 148 | backends = OrderedDict() | 109 | backends = OrderedDict() |
163 | 110 | backends['UPA'] = get_upa_display | ||
164 | 149 | backends['X11'] = get_x11_display | 111 | backends['X11'] = get_x11_display |
165 | 150 | backends['UPA'] = get_upa_display | ||
166 | 151 | return _pick_backend(backends, preferred_backend) | 112 | return _pick_backend(backends, preferred_backend) |
167 | 152 | 113 | ||
168 | 153 | class BlacklistedDriverError(RuntimeError): | 114 | class BlacklistedDriverError(RuntimeError): |
169 | 154 | 115 | ||
170 | === modified file 'autopilot/display/_upa.py' | |||
171 | --- autopilot/display/_upa.py 2014-03-25 14:42:25 +0000 | |||
172 | +++ autopilot/display/_upa.py 2017-03-02 18:46:50 +0000 | |||
173 | @@ -17,44 +17,33 @@ | |||
174 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
175 | 18 | # | 18 | # |
176 | 19 | 19 | ||
177 | 20 | import os | ||
178 | 21 | import subprocess | ||
179 | 20 | 22 | ||
180 | 21 | from autopilot.display import Display as DisplayBase | 23 | from autopilot.display import Display as DisplayBase |
183 | 22 | from autopilot.platform import image_codename | 24 | from autopilot.platform import get_display_server, image_codename |
184 | 23 | import subprocess | 25 | |
185 | 26 | DISPLAY_SERVER_X11 = 'X11' | ||
186 | 27 | DISPLAY_SERVER_MIR = 'MIR' | ||
187 | 28 | ENV_MIR_SOCKET = 'MIR_SERVER_HOST_SOCKET' | ||
188 | 24 | 29 | ||
189 | 25 | 30 | ||
190 | 26 | def query_resolution(): | 31 | def query_resolution(): |
194 | 27 | try: | 32 | display_server = get_display_server() |
195 | 28 | return _get_fbset_resolution() | 33 | if display_server == DISPLAY_SERVER_X11: |
196 | 29 | except Exception: | 34 | return _get_resolution_from_xrandr() |
197 | 35 | elif display_server == DISPLAY_SERVER_MIR: | ||
198 | 36 | return _get_resolution_from_mirout() | ||
199 | 37 | else: | ||
200 | 30 | return _get_hardcoded_resolution() | 38 | return _get_hardcoded_resolution() |
201 | 31 | 39 | ||
202 | 32 | 40 | ||
203 | 33 | def _get_fbset_resolution(): | ||
204 | 34 | """Return the resolution, as determined by fbset, or None.""" | ||
205 | 35 | fbset_output = _get_fbset_output() | ||
206 | 36 | for line in fbset_output.split('\n'): | ||
207 | 37 | line = line.strip() | ||
208 | 38 | if line.startswith('Mode'): | ||
209 | 39 | quoted_resolution = line.split()[1] | ||
210 | 40 | resolution_string = quoted_resolution.strip('"') | ||
211 | 41 | return tuple(int(piece) for piece in resolution_string.split('x')) | ||
212 | 42 | raise RuntimeError("No modes found from fbset output") | ||
213 | 43 | |||
214 | 44 | |||
215 | 45 | def _get_fbset_output(): | ||
216 | 46 | return subprocess.check_output(["fbset", "-s", "-x"]).decode().strip() | ||
217 | 47 | |||
218 | 48 | |||
219 | 49 | def _get_hardcoded_resolution(): | 41 | def _get_hardcoded_resolution(): |
220 | 50 | name = image_codename() | 42 | name = image_codename() |
221 | 51 | 43 | ||
222 | 52 | resolutions = { | 44 | resolutions = { |
228 | 53 | "generic": (480, 800), | 45 | "Aquaris_M10_HD": (800, 1280), |
229 | 54 | "mako": (768, 1280), | 46 | "Desktop": (1920, 1080) |
225 | 55 | "maguro": (720, 1280), | ||
226 | 56 | "manta": (2560, 1600), | ||
227 | 57 | "grouper": (800, 1280), | ||
230 | 58 | } | 47 | } |
231 | 59 | 48 | ||
232 | 60 | if name not in resolutions: | 49 | if name not in resolutions: |
233 | @@ -64,6 +53,35 @@ | |||
234 | 64 | return resolutions[name] | 53 | return resolutions[name] |
235 | 65 | 54 | ||
236 | 66 | 55 | ||
237 | 56 | def _get_stdout_for_command(command, *args): | ||
238 | 57 | full_command = [command] | ||
239 | 58 | full_command.extend(args) | ||
240 | 59 | return subprocess.check_output( | ||
241 | 60 | full_command, | ||
242 | 61 | universal_newlines=True, | ||
243 | 62 | stderr=subprocess.DEVNULL, | ||
244 | 63 | ).split('\n') | ||
245 | 64 | |||
246 | 65 | |||
247 | 66 | def _get_resolution(server_output): | ||
248 | 67 | relevant_line = list(filter(lambda line: '*' in line, server_output))[0] | ||
249 | 68 | if relevant_line: | ||
250 | 69 | return tuple([int(i) for i in relevant_line.split()[0].split('x')]) | ||
251 | 70 | raise ValueError( | ||
252 | 71 | 'Failed to get display resolution, is a display connected?' | ||
253 | 72 | ) | ||
254 | 73 | |||
255 | 74 | |||
256 | 75 | def _get_resolution_from_xrandr(): | ||
257 | 76 | return _get_resolution(_get_stdout_for_command('xrandr', '--current')) | ||
258 | 77 | |||
259 | 78 | |||
260 | 79 | def _get_resolution_from_mirout(): | ||
261 | 80 | return _get_resolution( | ||
262 | 81 | _get_stdout_for_command('mirout', os.environ.get(ENV_MIR_SOCKET)) | ||
263 | 82 | ) | ||
264 | 83 | |||
265 | 84 | |||
266 | 67 | class Display(DisplayBase): | 85 | class Display(DisplayBase): |
267 | 68 | """The base class/inteface for the display devices""" | 86 | """The base class/inteface for the display devices""" |
268 | 69 | 87 | ||
269 | @@ -91,4 +109,4 @@ | |||
270 | 91 | :return: Tuple containing (x, y, width, height). | 109 | :return: Tuple containing (x, y, width, height). |
271 | 92 | 110 | ||
272 | 93 | """ | 111 | """ |
274 | 94 | return (0, 0, self._X, self._Y) | 112 | return 0, 0, self._X, self._Y |
275 | 95 | 113 | ||
276 | === modified file 'autopilot/input/__init__.py' | |||
277 | --- autopilot/input/__init__.py 2016-01-08 09:35:07 +0000 | |||
278 | +++ autopilot/input/__init__.py 2017-03-02 18:46:50 +0000 | |||
279 | @@ -126,9 +126,9 @@ | |||
280 | 126 | raise | 126 | raise |
281 | 127 | 127 | ||
282 | 128 | backends = OrderedDict() | 128 | backends = OrderedDict() |
283 | 129 | backends['X11'] = get_x11_kb | ||
284 | 130 | backends['UInput'] = get_uinput_kb | 129 | backends['UInput'] = get_uinput_kb |
285 | 131 | backends['OSK'] = get_osk_kb | 130 | backends['OSK'] = get_osk_kb |
286 | 131 | backends['X11'] = get_x11_kb | ||
287 | 132 | return _pick_backend(backends, preferred_backend) | 132 | return _pick_backend(backends, preferred_backend) |
288 | 133 | 133 | ||
289 | 134 | @contextmanager | 134 | @contextmanager |
290 | @@ -283,21 +283,15 @@ | |||
291 | 283 | from autopilot.input._X11 import Mouse | 283 | from autopilot.input._X11 import Mouse |
292 | 284 | return Mouse() | 284 | return Mouse() |
293 | 285 | 285 | ||
306 | 286 | from autopilot.platform import model | 286 | def get_uinput_mouse(): |
307 | 287 | if model() != 'Desktop': | 287 | # Return the Touch device for now as Mouse under a Mir desktop |
308 | 288 | _logger.info( | 288 | # is a challenge for now. |
309 | 289 | "You cannot create a Mouse on the devices where X11 is not " | 289 | from autopilot.input._uinput import Touch |
310 | 290 | "available. consider using a Touch or Pointer device. " | 290 | return Touch() |
299 | 291 | "For more information, see: " | ||
300 | 292 | "http://unity.ubuntu.com/autopilot/api/input.html" | ||
301 | 293 | "#autopilot-unified-input-system" | ||
302 | 294 | ) | ||
303 | 295 | raise RuntimeError( | ||
304 | 296 | "Cannot create a Mouse on devices where X11 is not available." | ||
305 | 297 | ) | ||
311 | 298 | 291 | ||
312 | 299 | backends = OrderedDict() | 292 | backends = OrderedDict() |
313 | 300 | backends['X11'] = get_x11_mouse | 293 | backends['X11'] = get_x11_mouse |
314 | 294 | backends['UInput'] = get_uinput_mouse | ||
315 | 301 | return _pick_backend(backends, preferred_backend) | 295 | return _pick_backend(backends, preferred_backend) |
316 | 302 | 296 | ||
317 | 303 | @property | 297 | @property |
318 | 304 | 298 | ||
319 | === modified file 'autopilot/introspection/types.py' | |||
320 | --- autopilot/introspection/types.py 2015-12-08 01:07:10 +0000 | |||
321 | +++ autopilot/introspection/types.py 2017-03-02 18:46:50 +0000 | |||
322 | @@ -255,6 +255,7 @@ | |||
323 | 255 | def _create_generic_repr(target_type): | 255 | def _create_generic_repr(target_type): |
324 | 256 | return compatible_repr(lambda self: repr(target_type(self))) | 256 | return compatible_repr(lambda self: repr(target_type(self))) |
325 | 257 | 257 | ||
326 | 258 | |||
327 | 258 | _bytes_repr = _create_generic_repr(bytes) | 259 | _bytes_repr = _create_generic_repr(bytes) |
328 | 259 | _text_repr = _create_generic_repr(str) | 260 | _text_repr = _create_generic_repr(str) |
329 | 260 | _dict_repr = _create_generic_repr(dict) | 261 | _dict_repr = _create_generic_repr(dict) |
330 | 261 | 262 | ||
331 | === modified file 'autopilot/introspection/utilities.py' | |||
332 | --- autopilot/introspection/utilities.py 2016-07-14 08:18:20 +0000 | |||
333 | +++ autopilot/introspection/utilities.py 2017-03-02 18:46:50 +0000 | |||
334 | @@ -138,4 +138,5 @@ | |||
335 | 138 | """ | 138 | """ |
336 | 139 | return self._query_pids_for_process(process_name) | 139 | return self._query_pids_for_process(process_name) |
337 | 140 | 140 | ||
338 | 141 | |||
339 | 141 | process_util = ProcessUtil() | 142 | process_util = ProcessUtil() |
340 | 142 | 143 | ||
341 | === modified file 'autopilot/platform.py' | |||
342 | --- autopilot/platform.py 2014-07-23 01:59:47 +0000 | |||
343 | +++ autopilot/platform.py 2017-03-02 18:46:50 +0000 | |||
344 | @@ -19,8 +19,6 @@ | |||
345 | 19 | 19 | ||
346 | 20 | 20 | ||
347 | 21 | import os | 21 | import os |
348 | 22 | import psutil | ||
349 | 23 | from functools import lru_cache | ||
350 | 24 | 22 | ||
351 | 25 | """ | 23 | """ |
352 | 26 | Platform identification utilities for Autopilot. | 24 | Platform identification utilities for Autopilot. |
353 | @@ -143,27 +141,10 @@ | |||
354 | 143 | def get_display_server(): | 141 | def get_display_server(): |
355 | 144 | """Returns display server type. | 142 | """Returns display server type. |
356 | 145 | 143 | ||
359 | 146 | :returns: string indicating display server type. Either "X11", "MIR" or | 144 | :returns: string indicating display server type. |
358 | 147 | "UNKNOWN" | ||
360 | 148 | 145 | ||
361 | 149 | """ | 146 | """ |
379 | 150 | if _display_is_x11(): | 147 | return os.environ.get('XDG_SESSION_TYPE', 'UNKNOWN').upper() |
363 | 151 | return "X11" | ||
364 | 152 | elif _display_is_mir(): | ||
365 | 153 | return "MIR" | ||
366 | 154 | else: | ||
367 | 155 | return "UNKNOWN" | ||
368 | 156 | |||
369 | 157 | |||
370 | 158 | def _display_is_x11(): | ||
371 | 159 | return 'DISPLAY' in os.environ | ||
372 | 160 | |||
373 | 161 | |||
374 | 162 | @lru_cache() | ||
375 | 163 | def _display_is_mir(): | ||
376 | 164 | return "unity-system-compositor" in [ | ||
377 | 165 | _get_process_name(p.name) for p in psutil.process_iter() | ||
378 | 166 | ] | ||
380 | 167 | 148 | ||
381 | 168 | 149 | ||
382 | 169 | # Different vers. of psutil across Trusty and Utopic have name as either a | 150 | # Different vers. of psutil across Trusty and Utopic have name as either a |
383 | 170 | 151 | ||
384 | === modified file 'autopilot/process/__init__.py' | |||
385 | --- autopilot/process/__init__.py 2015-05-04 06:28:37 +0000 | |||
386 | +++ autopilot/process/__init__.py 2017-03-02 18:46:50 +0000 | |||
387 | @@ -89,10 +89,6 @@ | |||
388 | 89 | from autopilot.process._bamf import ProcessManager | 89 | from autopilot.process._bamf import ProcessManager |
389 | 90 | return ProcessManager() | 90 | return ProcessManager() |
390 | 91 | 91 | ||
391 | 92 | def get_upa_pm(): | ||
392 | 93 | from autopilot.process._upa import ProcessManager | ||
393 | 94 | return ProcessManager() | ||
394 | 95 | |||
395 | 96 | backends = OrderedDict() | 92 | backends = OrderedDict() |
396 | 97 | backends['BAMF'] = get_bamf_pm | 93 | backends['BAMF'] = get_bamf_pm |
397 | 98 | return _pick_backend(backends, preferred_backend) | 94 | return _pick_backend(backends, preferred_backend) |
398 | 99 | 95 | ||
399 | === modified file 'autopilot/run.py' | |||
400 | --- autopilot/run.py 2015-08-19 00:25:00 +0000 | |||
401 | +++ autopilot/run.py 2017-03-02 18:46:50 +0000 | |||
402 | @@ -749,5 +749,6 @@ | |||
403 | 749 | print(e) | 749 | print(e) |
404 | 750 | exit(1) | 750 | exit(1) |
405 | 751 | 751 | ||
406 | 752 | |||
407 | 752 | if __name__ == "__main__": | 753 | if __name__ == "__main__": |
408 | 753 | main() | 754 | main() |
409 | 754 | 755 | ||
410 | === modified file 'autopilot/testcase.py' | |||
411 | --- autopilot/testcase.py 2015-09-02 03:25:43 +0000 | |||
412 | +++ autopilot/testcase.py 2017-03-02 18:46:50 +0000 | |||
413 | @@ -173,13 +173,14 @@ | |||
414 | 173 | # Work around for bug lp:1297592. | 173 | # Work around for bug lp:1297592. |
415 | 174 | _ensure_uinput_device_created() | 174 | _ensure_uinput_device_created() |
416 | 175 | 175 | ||
424 | 176 | try: | 176 | if get_display_server() == 'X11': |
425 | 177 | self._app_snapshot = _get_process_snapshot() | 177 | try: |
426 | 178 | self.addCleanup(self._compare_system_with_app_snapshot) | 178 | self._app_snapshot = _get_process_snapshot() |
427 | 179 | except RuntimeError: | 179 | self.addCleanup(self._compare_system_with_app_snapshot) |
428 | 180 | _logger.warning( | 180 | except RuntimeError: |
429 | 181 | "Process manager backend unavailable, application snapshot " | 181 | _logger.warning( |
430 | 182 | "support disabled.") | 182 | "Process manager backend unavailable, application " |
431 | 183 | "snapshot support disabled.") | ||
432 | 183 | 184 | ||
433 | 184 | self.addOnException(self._take_screenshot_on_failure) | 185 | self.addOnException(self._take_screenshot_on_failure) |
434 | 185 | 186 | ||
435 | 186 | 187 | ||
436 | === modified file 'autopilot/tests/unit/introspection_base.py' | |||
437 | --- autopilot/tests/unit/introspection_base.py 2016-07-19 14:24:10 +0000 | |||
438 | +++ autopilot/tests/unit/introspection_base.py 2017-03-02 18:46:50 +0000 | |||
439 | @@ -38,6 +38,7 @@ | |||
440 | 38 | def get_properties(self): | 38 | def get_properties(self): |
441 | 39 | return self.__dict__ | 39 | return self.__dict__ |
442 | 40 | 40 | ||
443 | 41 | |||
444 | 41 | get_mock_object = MockObject | 42 | get_mock_object = MockObject |
445 | 42 | 43 | ||
446 | 43 | 44 | ||
447 | 44 | 45 | ||
448 | === modified file 'autopilot/tests/unit/test_application_launcher.py' | |||
449 | --- autopilot/tests/unit/test_application_launcher.py 2014-07-22 02:30:19 +0000 | |||
450 | +++ autopilot/tests/unit/test_application_launcher.py 2017-03-02 18:46:50 +0000 | |||
451 | @@ -1,7 +1,7 @@ | |||
452 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
453 | 2 | # | 2 | # |
454 | 3 | # Autopilot Functional Test Tool | 3 | # Autopilot Functional Test Tool |
456 | 4 | # Copyright (C) 2013 Canonical | 4 | # Copyright (C) 2013,2017 Canonical |
457 | 5 | # | 5 | # |
458 | 6 | # This program is free software: you can redistribute it and/or modify | 6 | # This program is free software: you can redistribute it and/or modify |
459 | 7 | # it under the terms of the GNU General Public License as published by | 7 | # it under the terms of the GNU General Public License as published by |
460 | @@ -33,8 +33,7 @@ | |||
461 | 33 | raises, | 33 | raises, |
462 | 34 | ) | 34 | ) |
463 | 35 | from testtools.content import text_content | 35 | from testtools.content import text_content |
466 | 36 | import tempfile | 36 | from unittest.mock import MagicMock, Mock, patch |
465 | 37 | from unittest.mock import Mock, patch | ||
467 | 38 | 37 | ||
468 | 39 | from autopilot.application import ( | 38 | from autopilot.application import ( |
469 | 40 | ClickApplicationLauncher, | 39 | ClickApplicationLauncher, |
470 | @@ -782,32 +781,30 @@ | |||
471 | 782 | app_id = self.getUniqueString() | 781 | app_id = self.getUniqueString() |
472 | 783 | case_addDetail = Mock() | 782 | case_addDetail = Mock() |
473 | 784 | launcher = UpstartApplicationLauncher(case_addDetail) | 783 | launcher = UpstartApplicationLauncher(case_addDetail) |
476 | 785 | with patch.object(_l.UbuntuAppLaunch, 'application_log_path') as p: | 784 | j = MagicMock(spec=_l.journal.Reader) |
477 | 786 | p.return_value = None | 785 | with patch.object(_l.journal, 'Reader', return_value=j): |
478 | 787 | launcher._attach_application_log(app_id) | 786 | launcher._attach_application_log(app_id) |
481 | 788 | 787 | expected = launcher._get_user_unit_match(app_id) | |
482 | 789 | p.assert_called_once_with(app_id) | 788 | j.add_match.assert_called_once_with(_SYSTEMD_USER_UNIT=expected) |
483 | 790 | self.assertEqual(0, case_addDetail.call_count) | 789 | self.assertEqual(0, case_addDetail.call_count) |
484 | 791 | 790 | ||
486 | 792 | def test_attach_application_log_attaches_log_file(self): | 791 | def test_attach_application_log_attaches_log(self): |
487 | 793 | token = self.getUniqueString() | 792 | token = self.getUniqueString() |
488 | 794 | case_addDetail = Mock() | 793 | case_addDetail = Mock() |
489 | 795 | launcher = UpstartApplicationLauncher(case_addDetail) | 794 | launcher = UpstartApplicationLauncher(case_addDetail) |
490 | 796 | app_id = self.getUniqueString() | 795 | app_id = self.getUniqueString() |
497 | 797 | with tempfile.NamedTemporaryFile(mode='w') as f: | 796 | j = MagicMock(spec=_l.journal.Reader) |
498 | 798 | f.write(token) | 797 | j.__iter__ = lambda x: iter([token]) |
499 | 799 | f.flush() | 798 | with patch.object(_l.journal, 'Reader', return_value=j): |
500 | 800 | with patch.object(_l.UbuntuAppLaunch, 'application_log_path', | 799 | launcher._attach_application_log(app_id) |
495 | 801 | return_value=f.name): | ||
496 | 802 | launcher._attach_application_log(app_id) | ||
501 | 803 | 800 | ||
509 | 804 | self.assertEqual(1, case_addDetail.call_count) | 801 | self.assertEqual(1, case_addDetail.call_count) |
510 | 805 | content_name, content_obj = case_addDetail.call_args[0] | 802 | content_name, content_obj = case_addDetail.call_args[0] |
511 | 806 | self.assertEqual( | 803 | self.assertEqual( |
512 | 807 | "Application Log (%s)" % app_id, | 804 | "Application Log (%s)" % app_id, |
513 | 808 | content_name | 805 | content_name |
514 | 809 | ) | 806 | ) |
515 | 810 | self.assertThat(content_obj.as_text(), Contains(token)) | 807 | self.assertThat(content_obj.as_text(), Contains(token)) |
516 | 811 | 808 | ||
517 | 812 | def test_stop_adds_app_stopped_observer(self): | 809 | def test_stop_adds_app_stopped_observer(self): |
518 | 813 | mock_add_detail = Mock() | 810 | mock_add_detail = Mock() |
519 | 814 | 811 | ||
520 | === modified file 'autopilot/tests/unit/test_platform.py' | |||
521 | --- autopilot/tests/unit/test_platform.py 2015-12-08 00:48:04 +0000 | |||
522 | +++ autopilot/tests/unit/test_platform.py 2017-03-02 18:46:50 +0000 | |||
523 | @@ -20,7 +20,6 @@ | |||
524 | 20 | """Tests for the autopilot platform code.""" | 20 | """Tests for the autopilot platform code.""" |
525 | 21 | 21 | ||
526 | 22 | 22 | ||
527 | 23 | from contextlib import contextmanager | ||
528 | 24 | from io import StringIO | 23 | from io import StringIO |
529 | 25 | from testtools import TestCase | 24 | from testtools import TestCase |
530 | 26 | from testtools.matchers import Equals | 25 | from testtools.matchers import Equals |
531 | @@ -34,7 +33,6 @@ | |||
532 | 34 | 33 | ||
533 | 35 | def setUp(self): | 34 | def setUp(self): |
534 | 36 | super().setUp() | 35 | super().setUp() |
535 | 37 | platform._display_is_mir.cache_clear() | ||
536 | 38 | 36 | ||
537 | 39 | @patch('autopilot.platform._PlatformDetector') | 37 | @patch('autopilot.platform._PlatformDetector') |
538 | 40 | def test_model_creates_platform_detector(self, mock_detector): | 38 | def test_model_creates_platform_detector(self, mock_detector): |
539 | @@ -56,14 +54,6 @@ | |||
540 | 56 | mock_detector.image_codename = "test123" | 54 | mock_detector.image_codename = "test123" |
541 | 57 | self.assertThat(platform.image_codename(), Equals('test123')) | 55 | self.assertThat(platform.image_codename(), Equals('test123')) |
542 | 58 | 56 | ||
543 | 59 | def test_is_x11_returns_False_on_failure(self): | ||
544 | 60 | with _simulate_not_X11(): | ||
545 | 61 | self.assertFalse(platform._display_is_x11()) | ||
546 | 62 | |||
547 | 63 | def test_is_x11_returns_True_on_success(self): | ||
548 | 64 | with _simulate_X11(): | ||
549 | 65 | self.assertTrue(platform._display_is_x11()) | ||
550 | 66 | |||
551 | 67 | 57 | ||
552 | 68 | class PlatformGetProcessNameTests(TestCase): | 58 | class PlatformGetProcessNameTests(TestCase): |
553 | 69 | 59 | ||
554 | @@ -247,15 +237,3 @@ | |||
555 | 247 | prop_file = StringIO("ro.product.model=maguro") | 237 | prop_file = StringIO("ro.product.model=maguro") |
556 | 248 | properties = platform._parse_build_properties_file(prop_file) | 238 | properties = platform._parse_build_properties_file(prop_file) |
557 | 249 | self.assertThat(properties, Equals({'ro.product.model': 'maguro'})) | 239 | self.assertThat(properties, Equals({'ro.product.model': 'maguro'})) |
558 | 250 | |||
559 | 251 | |||
560 | 252 | @contextmanager | ||
561 | 253 | def _simulate_not_X11(): | ||
562 | 254 | with patch.dict(platform.os.environ, dict(), clear=True): | ||
563 | 255 | yield | ||
564 | 256 | |||
565 | 257 | |||
566 | 258 | @contextmanager | ||
567 | 259 | def _simulate_X11(): | ||
568 | 260 | with patch.dict(platform.os.environ, dict(DISPLAY=':0'), clear=True): | ||
569 | 261 | yield | ||
570 | 262 | 240 | ||
571 | === modified file 'autopilot/tests/unit/test_query_resolution.py' | |||
572 | --- autopilot/tests/unit/test_query_resolution.py 2014-05-20 08:53:21 +0000 | |||
573 | +++ autopilot/tests/unit/test_query_resolution.py 2017-03-02 18:46:50 +0000 | |||
574 | @@ -16,85 +16,3 @@ | |||
575 | 16 | # You should have received a copy of the GNU General Public License | 16 | # You should have received a copy of the GNU General Public License |
576 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
577 | 18 | # | 18 | # |
578 | 19 | |||
579 | 20 | from testtools import TestCase | ||
580 | 21 | from testtools.matchers import raises | ||
581 | 22 | from testscenarios import WithScenarios | ||
582 | 23 | from textwrap import dedent | ||
583 | 24 | from unittest.mock import patch | ||
584 | 25 | |||
585 | 26 | from autopilot.display import _upa as upa | ||
586 | 27 | |||
587 | 28 | |||
588 | 29 | class QueryResolutionFunctionTests(TestCase): | ||
589 | 30 | |||
590 | 31 | @patch('subprocess.check_output', return_value=b'') | ||
591 | 32 | def test_fbset_output_calls_subprocess(self, patched_check_output): | ||
592 | 33 | upa._get_fbset_output() | ||
593 | 34 | patched_check_output.assert_called_once_with( | ||
594 | 35 | ["fbset", "-s", "-x"] | ||
595 | 36 | ) | ||
596 | 37 | |||
597 | 38 | def test_get_fbset_resolution(self): | ||
598 | 39 | patched_fbset_resolution = dedent( | ||
599 | 40 | ''' | ||
600 | 41 | Mode "768x1280" | ||
601 | 42 | # D: 0.002 MHz, H: 0.002 kHz, V: 0.002 Hz | ||
602 | 43 | DotClock 0.003 | ||
603 | 44 | HTimings 768 776 780 960 | ||
604 | 45 | VTimings 1280 1288 1290 1312 | ||
605 | 46 | Flags "-HSync" "-VSync" | ||
606 | 47 | EndMode | ||
607 | 48 | ''' | ||
608 | 49 | ) | ||
609 | 50 | with patch.object(upa, '_get_fbset_output') as patched_gfo: | ||
610 | 51 | patched_gfo.return_value = patched_fbset_resolution | ||
611 | 52 | observed = upa._get_fbset_resolution() | ||
612 | 53 | self.assertEqual((768, 1280), observed) | ||
613 | 54 | |||
614 | 55 | def test_get_fbset_resolution_raises_runtimeError(self): | ||
615 | 56 | patched_fbset_resolution = 'something went wrong!' | ||
616 | 57 | with patch.object(upa, '_get_fbset_output') as patched_gfo: | ||
617 | 58 | patched_gfo.return_value = patched_fbset_resolution | ||
618 | 59 | self.assertThat( | ||
619 | 60 | upa._get_fbset_resolution, | ||
620 | 61 | raises(RuntimeError), | ||
621 | 62 | ) | ||
622 | 63 | |||
623 | 64 | def test_hardcoded_raises_error_on_unknown_model(self): | ||
624 | 65 | with patch.object(upa, 'image_codename', return_value="unknown"): | ||
625 | 66 | self.assertThat( | ||
626 | 67 | upa._get_hardcoded_resolution, | ||
627 | 68 | raises( | ||
628 | 69 | NotImplementedError( | ||
629 | 70 | 'Device "unknown" is not supported by Autopilot.' | ||
630 | 71 | ) | ||
631 | 72 | ) | ||
632 | 73 | ) | ||
633 | 74 | |||
634 | 75 | def test_query_resolution_uses_fbset_first(self): | ||
635 | 76 | with patch.object(upa, '_get_fbset_resolution', return_value=(1, 2)): | ||
636 | 77 | self.assertEqual((1, 2), upa.query_resolution()) | ||
637 | 78 | |||
638 | 79 | def test_query_resolution_uses_hardcoded_second(self): | ||
639 | 80 | with patch.object(upa, '_get_fbset_resolution', side_effect=Exception): | ||
640 | 81 | with patch.object( | ||
641 | 82 | upa, '_get_hardcoded_resolution', return_value=(2, 3) | ||
642 | 83 | ): | ||
643 | 84 | self.assertEqual((2, 3), upa.query_resolution()) | ||
644 | 85 | |||
645 | 86 | |||
646 | 87 | class HardCodedResolutionTests(WithScenarios, TestCase): | ||
647 | 88 | |||
648 | 89 | scenarios = [ | ||
649 | 90 | ("generic", dict(name="generic", expected=(480, 800))), | ||
650 | 91 | ("mako", dict(name="mako", expected=(768, 1280))), | ||
651 | 92 | ("maguro", dict(name="maguro", expected=(720, 1280))), | ||
652 | 93 | ("manta", dict(name="manta", expected=(2560, 1600))), | ||
653 | 94 | ("grouper", dict(name="grouper", expected=(800, 1280))), | ||
654 | 95 | ] | ||
655 | 96 | |||
656 | 97 | def test_hardcoded_resolutions_works_for_known_codenames(self): | ||
657 | 98 | with patch.object(upa, 'image_codename', return_value=self.name): | ||
658 | 99 | observed = upa._get_hardcoded_resolution() | ||
659 | 100 | self.assertEqual(self.expected, observed) | ||
660 | 101 | 19 | ||
661 | === modified file 'autopilot/utilities.py' | |||
662 | --- autopilot/utilities.py 2016-05-18 07:06:16 +0000 | |||
663 | +++ autopilot/utilities.py 2017-03-02 18:46:50 +0000 | |||
664 | @@ -430,6 +430,7 @@ | |||
665 | 430 | def total_time_slept(self): | 430 | def total_time_slept(self): |
666 | 431 | return self._mock_count | 431 | return self._mock_count |
667 | 432 | 432 | ||
668 | 433 | |||
669 | 433 | sleep = MockableSleep() | 434 | sleep = MockableSleep() |
670 | 434 | 435 | ||
671 | 435 | 436 | ||
672 | @@ -665,4 +666,5 @@ | |||
673 | 665 | process.get('pid') | 666 | process.get('pid') |
674 | 666 | ) | 667 | ) |
675 | 667 | 668 | ||
676 | 669 | |||
677 | 668 | process_iter = MockableProcessIter() | 670 | process_iter = MockableProcessIter() |
678 | 669 | 671 | ||
679 | === modified file 'debian/control' | |||
680 | --- debian/control 2016-08-10 16:36:11 +0000 | |||
681 | +++ debian/control 2017-03-02 18:46:50 +0000 | |||
682 | @@ -6,10 +6,9 @@ | |||
683 | 6 | Build-Depends: debhelper (>= 9.0.0), | 6 | Build-Depends: debhelper (>= 9.0.0), |
684 | 7 | dh-python, | 7 | dh-python, |
685 | 8 | dvipng, | 8 | dvipng, |
686 | 9 | gir1.2-gconf-2.0, | ||
687 | 10 | gir1.2-gtk-3.0, | 9 | gir1.2-gtk-3.0, |
688 | 11 | gir1.2-ibus-1.0, | 10 | gir1.2-ibus-1.0, |
690 | 12 | gir1.2-ubuntu-app-launch-2 | gir1.2-upstart-app-launch-2, | 11 | gir1.2-ubuntu-app-launch-3 | gir1.2-ubuntu-app-launch-2, |
691 | 13 | graphviz, | 12 | graphviz, |
692 | 14 | libjs-jquery, | 13 | libjs-jquery, |
693 | 15 | libjs-underscore, | 14 | libjs-underscore, |
694 | @@ -28,6 +27,7 @@ | |||
695 | 28 | python3-setuptools, | 27 | python3-setuptools, |
696 | 29 | python3-sphinx, | 28 | python3-sphinx, |
697 | 30 | python3-subunit, | 29 | python3-subunit, |
698 | 30 | python3-systemd, | ||
699 | 31 | python3-testscenarios, | 31 | python3-testscenarios, |
700 | 32 | python3-testtools, | 32 | python3-testtools, |
701 | 33 | python3-tz, | 33 | python3-tz, |
702 | @@ -38,15 +38,16 @@ | |||
703 | 38 | upstart, | 38 | upstart, |
704 | 39 | Standards-Version: 3.9.5 | 39 | Standards-Version: 3.9.5 |
705 | 40 | Homepage: https://launchpad.net/autopilot | 40 | Homepage: https://launchpad.net/autopilot |
707 | 41 | Vcs-bzr: https://code.launchpad.net/+branch/ubuntu/autopilot | 41 | Vcs-Bzr: https://code.launchpad.net/~autopilot/autopilot/trunk |
708 | 42 | X-Python-Version: >= 2.7 | 42 | X-Python-Version: >= 2.7 |
709 | 43 | X-Python3-Version: >= 3.3 | 43 | X-Python3-Version: >= 3.3 |
710 | 44 | 44 | ||
711 | 45 | Package: python3-autopilot | 45 | Package: python3-autopilot |
712 | 46 | Architecture: all | 46 | Architecture: all |
714 | 47 | Depends: gir1.2-ubuntu-app-launch-2 | gir1.2-upstart-app-launch-2, | 47 | Depends: gir1.2-ubuntu-app-launch-3 | gir1.2-ubuntu-app-launch-2, |
715 | 48 | libjs-jquery, | 48 | libjs-jquery, |
716 | 49 | libjs-underscore, | 49 | libjs-underscore, |
717 | 50 | mir-utils, | ||
718 | 50 | python3-dateutil, | 51 | python3-dateutil, |
719 | 51 | python3-dbus, | 52 | python3-dbus, |
720 | 52 | python3-decorator, | 53 | python3-decorator, |
721 | @@ -57,14 +58,14 @@ | |||
722 | 57 | python3-pil, | 58 | python3-pil, |
723 | 58 | python3-psutil, | 59 | python3-psutil, |
724 | 59 | python3-subunit, | 60 | python3-subunit, |
725 | 61 | python3-systemd, | ||
726 | 60 | python3-testscenarios, | 62 | python3-testscenarios, |
727 | 61 | python3-testtools, | 63 | python3-testtools, |
728 | 62 | python3-tz, | 64 | python3-tz, |
729 | 63 | udev, | 65 | udev, |
730 | 64 | ${misc:Depends}, | 66 | ${misc:Depends}, |
731 | 65 | ${python3:Depends}, | 67 | ${python3:Depends}, |
734 | 66 | Recommends: gir1.2-gconf-2.0, | 68 | Recommends: gir1.2-glib-2.0, |
733 | 67 | gir1.2-glib-2.0, | ||
735 | 68 | gir1.2-gtk-3.0, | 69 | gir1.2-gtk-3.0, |
736 | 69 | gir1.2-ibus-1.0, | 70 | gir1.2-ibus-1.0, |
737 | 70 | libautopilot-gtk (>= 1.4), | 71 | libautopilot-gtk (>= 1.4), |
738 | @@ -109,7 +110,6 @@ | |||
739 | 109 | Section: metapackages | 110 | Section: metapackages |
740 | 110 | Depends: at-spi2-core, | 111 | Depends: at-spi2-core, |
741 | 111 | bamfdaemon, | 112 | bamfdaemon, |
742 | 112 | gir1.2-gconf-2.0, | ||
743 | 113 | gir1.2-glib-2.0, | 113 | gir1.2-glib-2.0, |
744 | 114 | gir1.2-gtk-3.0, | 114 | gir1.2-gtk-3.0, |
745 | 115 | python3-autopilot, | 115 | python3-autopilot, |