Merge lp:~nskaggs/ubuntu-terminal-app/ap-restruct into lp:ubuntu-terminal-app
- ap-restruct
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Nicholas Skaggs | ||||
Approved revision: | 137 | ||||
Merged at revision: | 133 | ||||
Proposed branch: | lp:~nskaggs/ubuntu-terminal-app/ap-restruct | ||||
Merge into: | lp:ubuntu-terminal-app | ||||
Diff against target: |
763 lines (+299/-348) 5 files modified
src/app/qml/Terminal.qml (+0/-62) tests/autopilot/ubuntu_terminal_app/__init__.py (+173/-7) tests/autopilot/ubuntu_terminal_app/emulators.py (+0/-81) tests/autopilot/ubuntu_terminal_app/tests/__init__.py (+35/-104) tests/autopilot/ubuntu_terminal_app/tests/test_terminal.py (+91/-94) |
||||
To merge this branch: | bzr merge lp:~nskaggs/ubuntu-terminal-app/ap-restruct | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Ubuntu Terminal Developers | Pending | ||
Review via email: mp+232748@code.launchpad.net |
Commit message
Restructure test launching, fix 1341681
Description of the change
Restructure test launching, fix 1341681
remove hud actions
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:131
http://
Executed test runs:
FAILURE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 132. By Nicholas Skaggs
-
animation fixes, split tests
- 133. By Nicholas Skaggs
-
flake8 happiness
- 134. By Nicholas Skaggs
-
tweak test_header
- 135. By Nicholas Skaggs
-
flake8
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:132
http://
Executed test runs:
FAILURE: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:135
http://
Executed test runs:
FAILURE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 136. By Nicholas Skaggs
-
move circle menu helper
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:136
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Alan Pope 🍺🐧🐱 🦄 (popey) wrote : | # |
Looks like pyflakes issues:-
+ pyflakes .
./tests/
./debian/
./debian/
- 137. By Nicholas Skaggs
-
flake8 happiness
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:137
http://
Executed test runs:
FAILURE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) : | # |
Preview Diff
1 | === modified file 'src/app/qml/Terminal.qml' | |||
2 | --- src/app/qml/Terminal.qml 2014-08-26 13:31:30 +0000 | |||
3 | +++ src/app/qml/Terminal.qml 2014-09-02 16:53:27 +0000 | |||
4 | @@ -1,7 +1,6 @@ | |||
5 | 1 | import QtQuick 2.0 | 1 | import QtQuick 2.0 |
6 | 2 | import Ubuntu.Components 0.1 | 2 | import Ubuntu.Components 0.1 |
7 | 3 | import org.kde.konsole 0.1 | 3 | import org.kde.konsole 0.1 |
8 | 4 | import Ubuntu.Unity.Action 1.0 as UnityActions | ||
9 | 5 | import "config" | 4 | import "config" |
10 | 6 | import "extraPanel" | 5 | import "extraPanel" |
11 | 7 | 6 | ||
12 | @@ -368,65 +367,4 @@ | |||
13 | 368 | } | 367 | } |
14 | 369 | 368 | ||
15 | 370 | } | 369 | } |
16 | 371 | |||
17 | 372 | UnityActions.ActionContext { | ||
18 | 373 | id: actionContext | ||
19 | 374 | active: mparent.visible | ||
20 | 375 | actions: [ | ||
21 | 376 | UnityActions.Action { | ||
22 | 377 | text: i18n.tr("Upload Crash Reports") | ||
23 | 378 | keywords: i18n.tr("Whoopsie;Apport;Debugging;Bugs") | ||
24 | 379 | onTriggered: ksession.sendText("\x03\n/usr/share/apport/whoopsie-upload-all\n") | ||
25 | 380 | }, | ||
26 | 381 | UnityActions.Action { | ||
27 | 382 | text: i18n.tr("Make Image Writable") | ||
28 | 383 | keywords: i18n.tr("System Image;Install Deb") | ||
29 | 384 | onTriggered: ksession.sendText("\x03\nsudo touch /userdata/.writable_image\n") | ||
30 | 385 | }, | ||
31 | 386 | UnityActions.Action { | ||
32 | 387 | text: i18n.tr("List Running Applications") | ||
33 | 388 | keywords: i18n.tr("Apps") | ||
34 | 389 | onTriggered: ksession.sendText("\x03\nupstart-app-list\n") | ||
35 | 390 | }, | ||
36 | 391 | UnityActions.Action { | ||
37 | 392 | text: i18n.tr("Installed Click Packages") | ||
38 | 393 | keywords: i18n.tr("Packages;Applications;Utilities") | ||
39 | 394 | onTriggered: ksession.sendText("\x03\nclick list\n") | ||
40 | 395 | }, | ||
41 | 396 | UnityActions.Action { | ||
42 | 397 | text: i18n.tr("System Image Information") | ||
43 | 398 | keywords: i18n.tr("Image;Version;Channel") | ||
44 | 399 | onTriggered: ksession.sendText("\x03\nsudo system-image-cli -i\n") | ||
45 | 400 | }, | ||
46 | 401 | UnityActions.Action { | ||
47 | 402 | text: i18n.tr("System Kernel Version") | ||
48 | 403 | onTriggered: ksession.sendText("\x03\nuname -a\n") | ||
49 | 404 | }, | ||
50 | 405 | UnityActions.Action { | ||
51 | 406 | text: i18n.tr("Upstart Job Status") | ||
52 | 407 | keywords: i18n.tr("Init;Session;User Job") | ||
53 | 408 | onTriggered: ksession.sendText("\x03\ninitctl list | sort\n") | ||
54 | 409 | }, | ||
55 | 410 | UnityActions.Action { | ||
56 | 411 | text: i18n.tr("Hack into the NSA") | ||
57 | 412 | keywords: i18n.tr("Government;Secret;Cracking") | ||
58 | 413 | onTriggered: ksession.sendText("\x03\nclear;echo -n \"That's not very nice, now tracing your location .\";sleep 1;echo -n \" .\";sleep 1;echo -n \" .\";sleep 1;echo -n \" .\";sleep 1;echo -n \" .\";sleep 1;echo -n \" .\";sleep 1;echo -n \" .\";sleep 1;echo -n \" .\";sleep 1;echo -n \" .\";sleep 1;echo -n \" .\";sleep 1;echo -n \" .\";sleep 1;echo -n \" .\";echo \"Trace failed\";echo \"You get away this time, but don't try again.\"\n") | ||
59 | 414 | }, | ||
60 | 415 | UnityActions.Action { | ||
61 | 416 | text: i18n.tr("Watch Running Processes") | ||
62 | 417 | keywords: i18n.tr("Top;Memory;Usage") | ||
63 | 418 | onTriggered: ksession.sendText("\x03\ntop\n") | ||
64 | 419 | }, | ||
65 | 420 | UnityActions.Action { | ||
66 | 421 | text: i18n.tr("Networking Status") | ||
67 | 422 | keywords: i18n.tr("Wireless;Ethernet;Access Points") | ||
68 | 423 | onTriggered: ksession.sendText("\x03\nnm-tool\n") | ||
69 | 424 | }, | ||
70 | 425 | UnityActions.Action { | ||
71 | 426 | text: i18n.tr("Watch Star Wars Episode IV") | ||
72 | 427 | keywords: i18n.tr("Death Star;Skywalker;Leia;Darth Vader") | ||
73 | 428 | onTriggered: ksession.sendText("\x03\nnetcat -v towel.blinkenlights.nl 23\n") | ||
74 | 429 | } | ||
75 | 430 | ] | ||
76 | 431 | } | ||
77 | 432 | } | 370 | } |
78 | 433 | 371 | ||
79 | === modified file 'tests/autopilot/ubuntu_terminal_app/__init__.py' | |||
80 | --- tests/autopilot/ubuntu_terminal_app/__init__.py 2013-05-31 13:10:55 +0000 | |||
81 | +++ tests/autopilot/ubuntu_terminal_app/__init__.py 2014-09-02 16:53:27 +0000 | |||
82 | @@ -1,8 +1,174 @@ | |||
83 | 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 -*- |
91 | 2 | # Copyright 2013 Canonical | 2 | # |
92 | 3 | # | 3 | # Copyright (C) 2013 Canonical Ltd. |
93 | 4 | # This program is free software: you can redistribute it and/or modify it | 4 | # |
94 | 5 | # under the terms of the GNU General Public License version 3, as published | 5 | # This program is free software; you can redistribute it and/or modify |
95 | 6 | # by the Free Software Foundation. | 6 | # it under the terms of the GNU Lesser General Public License as published by |
96 | 7 | 7 | # the Free Software Foundation; version 3. | |
97 | 8 | """terminal-app tests and emulators - top level package.""" | 8 | # |
98 | 9 | # This program is distributed in the hope that it will be useful, | ||
99 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
100 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
101 | 12 | # GNU Lesser General Public License for more details. | ||
102 | 13 | # | ||
103 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
104 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
105 | 16 | |||
106 | 17 | """Terminal app autopilot helpers.""" | ||
107 | 18 | |||
108 | 19 | from time import sleep | ||
109 | 20 | import sqlite3 | ||
110 | 21 | import os.path | ||
111 | 22 | import ubuntuuitoolkit | ||
112 | 23 | |||
113 | 24 | |||
114 | 25 | class TerminalApp(object): | ||
115 | 26 | |||
116 | 27 | """Autopilot helper object for the terminal application.""" | ||
117 | 28 | |||
118 | 29 | def __init__(self, app_proxy): | ||
119 | 30 | self.app = app_proxy | ||
120 | 31 | self.main_view = self.app.select_single(MainView) | ||
121 | 32 | |||
122 | 33 | @property | ||
123 | 34 | def pointing_device(self): | ||
124 | 35 | return self.app.pointing_device | ||
125 | 36 | |||
126 | 37 | |||
127 | 38 | class MainView(ubuntuuitoolkit.MainView): | ||
128 | 39 | |||
129 | 40 | """Autopilot custom proxy object for the MainView.""" | ||
130 | 41 | |||
131 | 42 | def __init__(self, *args): | ||
132 | 43 | super(MainView, self).__init__(*args) | ||
133 | 44 | self.visible.wait_for(True) | ||
134 | 45 | |||
135 | 46 | def get_slider_item(self, slider): | ||
136 | 47 | return self.wait_select_single("Slider", objectName=slider) | ||
137 | 48 | |||
138 | 49 | def get_control_panel(self): | ||
139 | 50 | return self.wait_select_single("CtrlKeys", objectName="kbCtrl") | ||
140 | 51 | |||
141 | 52 | def get_function_panel(self): | ||
142 | 53 | return self.wait_select_single("FnKeys", objectName="kbFn") | ||
143 | 54 | |||
144 | 55 | def get_text_panel(self): | ||
145 | 56 | return self.wait_select_single("ScrlKeys", objectName="kbScrl") | ||
146 | 57 | |||
147 | 58 | def get_terminal_page(self): | ||
148 | 59 | return self.wait_select_single("Terminal", objectName="pgTerm") | ||
149 | 60 | |||
150 | 61 | def get_circle_menu(self): | ||
151 | 62 | return self.wait_select_single("CircleMenu", objectName="cmenu") | ||
152 | 63 | |||
153 | 64 | def long_tap_terminal_center(self): | ||
154 | 65 | x, y, w, h = self.globalRect | ||
155 | 66 | tap_x = (x + w) / 2 | ||
156 | 67 | tap_y = (y + h) / 3 | ||
157 | 68 | |||
158 | 69 | # tap in the top third of the screen, to avoid OSK | ||
159 | 70 | self.pointing_device.move(tap_x, tap_y) | ||
160 | 71 | self.pointing_device.press() | ||
161 | 72 | # we can hold the press for a long time without issue | ||
162 | 73 | # so we'll ensure the app recieves our signal when under load | ||
163 | 74 | sleep(4) | ||
164 | 75 | self.pointing_device.release() | ||
165 | 76 | |||
166 | 77 | def drag_horizontal_slider(self, slider, pos): | ||
167 | 78 | """Drag slider until value is set""" | ||
168 | 79 | slItem = self.get_slider_item(slider) | ||
169 | 80 | |||
170 | 81 | slRect = slItem.select_single("SliderStyle") | ||
171 | 82 | |||
172 | 83 | slideMin = int(slItem.minimumValue) | ||
173 | 84 | slideMax = int(slItem.maximumValue) | ||
174 | 85 | |||
175 | 86 | if pos > slideMax: | ||
176 | 87 | raise ValueError("Pos cannot be greater than" + str(slideMax)) | ||
177 | 88 | |||
178 | 89 | if pos < slideMin: | ||
179 | 90 | raise ValueError("Pos cannot be less than" + str(slideMin)) | ||
180 | 91 | |||
181 | 92 | x, y, w, h = slRect.globalRect | ||
182 | 93 | # calculate the approximate slide step width | ||
183 | 94 | # we take half of the theoretical step value just to make | ||
184 | 95 | # sure we don't miss any values | ||
185 | 96 | step = w / ((slideMax - slideMin) * 2) | ||
186 | 97 | sx = x + step | ||
187 | 98 | sy = y + h / 2 | ||
188 | 99 | loop = 1 | ||
189 | 100 | |||
190 | 101 | # set the slider to minimum value and loop | ||
191 | 102 | self.pointing_device.move(sx, sy) | ||
192 | 103 | self.pointing_device.click() | ||
193 | 104 | |||
194 | 105 | # drag through the slider until the pos matches our desired value | ||
195 | 106 | # in case of bad sliding, loop will also timeout | ||
196 | 107 | while round(slItem.value) != pos and slItem.value < slideMax \ | ||
197 | 108 | and loop <= (slideMax * 2): | ||
198 | 109 | valuePos = int(sx + step) | ||
199 | 110 | self.pointing_device.drag(sx, sy, valuePos, sy) | ||
200 | 111 | sx = valuePos | ||
201 | 112 | sleep(1) | ||
202 | 113 | loop = loop + 1 | ||
203 | 114 | |||
204 | 115 | |||
205 | 116 | class DbMan(object): | ||
206 | 117 | |||
207 | 118 | """ | ||
208 | 119 | Helper functions for dealing with sqlite databases | ||
209 | 120 | """ | ||
210 | 121 | |||
211 | 122 | def get_db(self): | ||
212 | 123 | dbs_path = os.path.expanduser( | ||
213 | 124 | "~/.local/share/com.ubuntu.terminal/Databases") | ||
214 | 125 | if not os.path.exists(dbs_path): | ||
215 | 126 | return None | ||
216 | 127 | |||
217 | 128 | files = [f for f in os.listdir(dbs_path) | ||
218 | 129 | if os.path.splitext(f)[1] == ".ini"] | ||
219 | 130 | for f in files: | ||
220 | 131 | ini_path = os.path.join(dbs_path, f) | ||
221 | 132 | with open(ini_path) as ini: | ||
222 | 133 | for line in ini: | ||
223 | 134 | if "=" in line: | ||
224 | 135 | key, val = line.strip().split("=") | ||
225 | 136 | if key == "Name" and val == "UbuntuTerminalDB": | ||
226 | 137 | try: | ||
227 | 138 | return ini_path.replace(".ini", ".sqlite") | ||
228 | 139 | except OSError: | ||
229 | 140 | pass | ||
230 | 141 | return None | ||
231 | 142 | |||
232 | 143 | def clean_db(self): | ||
233 | 144 | path = self.get_db() | ||
234 | 145 | if path is None: | ||
235 | 146 | self.assertNotEquals(path, None) | ||
236 | 147 | try: | ||
237 | 148 | os.remove(path) | ||
238 | 149 | except OSError: | ||
239 | 150 | pass | ||
240 | 151 | |||
241 | 152 | def get_font_size_from_storage(self): | ||
242 | 153 | db = self.get_db() | ||
243 | 154 | conn = sqlite3.connect(db) | ||
244 | 155 | |||
245 | 156 | with conn: | ||
246 | 157 | cur = conn.cursor() | ||
247 | 158 | cur.execute("SELECT value FROM config WHERE item='fontSize'") | ||
248 | 159 | row = cur.fetchone() | ||
249 | 160 | if row is None: | ||
250 | 161 | self.assertNotEquals(row, None) | ||
251 | 162 | return int(row[0]) | ||
252 | 163 | |||
253 | 164 | def get_color_scheme_from_storage(self): | ||
254 | 165 | db = self.get_db() | ||
255 | 166 | conn = sqlite3.connect(db) | ||
256 | 167 | |||
257 | 168 | with conn: | ||
258 | 169 | cur = conn.cursor() | ||
259 | 170 | cur.execute("SELECT value FROM config WHERE item='colorScheme'") | ||
260 | 171 | row = cur.fetchone() | ||
261 | 172 | if row is None: | ||
262 | 173 | self.assertNotEquals(row, None) | ||
263 | 174 | return row[0] | ||
264 | 9 | 175 | ||
265 | === removed file 'tests/autopilot/ubuntu_terminal_app/emulators.py' | |||
266 | --- tests/autopilot/ubuntu_terminal_app/emulators.py 2014-08-28 16:47:48 +0000 | |||
267 | +++ tests/autopilot/ubuntu_terminal_app/emulators.py 1970-01-01 00:00:00 +0000 | |||
268 | @@ -1,81 +0,0 @@ | |||
269 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
270 | 2 | # | ||
271 | 3 | # Copyright (C) 2013 Canonical Ltd. | ||
272 | 4 | # | ||
273 | 5 | # This program is free software; you can redistribute it and/or modify | ||
274 | 6 | # it under the terms of the GNU Lesser General Public License as published by | ||
275 | 7 | # the Free Software Foundation; version 3. | ||
276 | 8 | # | ||
277 | 9 | # This program is distributed in the hope that it will be useful, | ||
278 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
279 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
280 | 12 | # GNU Lesser General Public License for more details. | ||
281 | 13 | # | ||
282 | 14 | # You should have received a copy of the GNU Lesser General Public License | ||
283 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
284 | 16 | |||
285 | 17 | """Terminal app autopilot emulators.""" | ||
286 | 18 | |||
287 | 19 | from time import sleep | ||
288 | 20 | from ubuntuuitoolkit import emulators as toolkit_emulators | ||
289 | 21 | |||
290 | 22 | |||
291 | 23 | class MainView(toolkit_emulators.MainView): | ||
292 | 24 | |||
293 | 25 | """Terminal MainView Autopilot emulator.""" | ||
294 | 26 | |||
295 | 27 | def get_slider_item(self, slider): | ||
296 | 28 | return self.wait_select_single("Slider", objectName=slider) | ||
297 | 29 | |||
298 | 30 | def get_control_panel(self): | ||
299 | 31 | return self.wait_select_single("CtrlKeys", objectName="kbCtrl") | ||
300 | 32 | |||
301 | 33 | def get_function_panel(self): | ||
302 | 34 | return self.wait_select_single("FnKeys", objectName="kbFn") | ||
303 | 35 | |||
304 | 36 | def get_scroll_panel(self): | ||
305 | 37 | return self.wait_select_single("ScrlKeys", objectName="kbScrl") | ||
306 | 38 | |||
307 | 39 | def get_terminal_page(self): | ||
308 | 40 | return self.wait_select_single("Terminal", objectName="pgTerm") | ||
309 | 41 | |||
310 | 42 | def get_circle_menu(self): | ||
311 | 43 | return self.wait_select_single("CircleMenu", objectName="cmenu") | ||
312 | 44 | |||
313 | 45 | def drag_horizontal_slider(self, slider, pos): | ||
314 | 46 | """Drag slider until value is set""" | ||
315 | 47 | slItem = self.get_slider_item(slider) | ||
316 | 48 | |||
317 | 49 | slRect = slItem.select_single("SliderStyle") | ||
318 | 50 | |||
319 | 51 | slideMin = int(slItem.minimumValue) | ||
320 | 52 | slideMax = int(slItem.maximumValue) | ||
321 | 53 | |||
322 | 54 | if pos > slideMax: | ||
323 | 55 | raise ValueError("Pos cannot be greater than" + str(slideMax)) | ||
324 | 56 | |||
325 | 57 | if pos < slideMin: | ||
326 | 58 | raise ValueError("Pos cannot be less than" + str(slideMin)) | ||
327 | 59 | |||
328 | 60 | x, y, w, h = slRect.globalRect | ||
329 | 61 | # calculate the approximate slide step width | ||
330 | 62 | # we take half of the theoretical step value just to make | ||
331 | 63 | # sure we don't miss any values | ||
332 | 64 | step = w / ((slideMax - slideMin) * 2) | ||
333 | 65 | sx = x + step | ||
334 | 66 | sy = y + h / 2 | ||
335 | 67 | loop = 1 | ||
336 | 68 | |||
337 | 69 | # set the slider to minimum value and loop | ||
338 | 70 | self.pointing_device.move(sx, sy) | ||
339 | 71 | self.pointing_device.click() | ||
340 | 72 | |||
341 | 73 | # drag through the slider until the pos matches our desired value | ||
342 | 74 | # in case of bad sliding, loop will also timeout | ||
343 | 75 | while round(slItem.value) != pos and slItem.value < slideMax \ | ||
344 | 76 | and loop <= (slideMax * 2): | ||
345 | 77 | valuePos = int(sx + step) | ||
346 | 78 | self.pointing_device.drag(sx, sy, valuePos, sy) | ||
347 | 79 | sx = valuePos | ||
348 | 80 | sleep(0.3) | ||
349 | 81 | loop = loop + 1 | ||
350 | 82 | 0 | ||
351 | === modified file 'tests/autopilot/ubuntu_terminal_app/tests/__init__.py' | |||
352 | --- tests/autopilot/ubuntu_terminal_app/tests/__init__.py 2014-06-27 15:14:32 +0000 | |||
353 | +++ tests/autopilot/ubuntu_terminal_app/tests/__init__.py 2014-09-02 16:53:27 +0000 | |||
354 | @@ -7,16 +7,16 @@ | |||
355 | 7 | 7 | ||
356 | 8 | """Terminal app autopilot tests.""" | 8 | """Terminal app autopilot tests.""" |
357 | 9 | 9 | ||
358 | 10 | import sqlite3 | ||
359 | 11 | import os.path | 10 | import os.path |
360 | 12 | |||
361 | 13 | import fixtures | 11 | import fixtures |
364 | 14 | from autopilot.input import Mouse, Touch, Pointer | 12 | import logging |
365 | 15 | from autopilot.platform import model | 13 | from autopilot import logging as autopilot_logging |
366 | 16 | from autopilot.testcase import AutopilotTestCase | 14 | from autopilot.testcase import AutopilotTestCase |
370 | 17 | from ubuntuuitoolkit import emulators as toolkit_emulators | 15 | import ubuntuuitoolkit |
371 | 18 | 16 | ||
372 | 19 | from ubuntu_terminal_app import emulators | 17 | import ubuntu_terminal_app |
373 | 18 | |||
374 | 19 | logger = logging.getLogger(__name__) | ||
375 | 20 | 20 | ||
376 | 21 | 21 | ||
377 | 22 | class TerminalTestCase(AutopilotTestCase): | 22 | class TerminalTestCase(AutopilotTestCase): |
378 | @@ -25,120 +25,51 @@ | |||
379 | 25 | app. | 25 | app. |
380 | 26 | 26 | ||
381 | 27 | """ | 27 | """ |
386 | 28 | if model() == 'Desktop': | 28 | |
387 | 29 | scenarios = [('with mouse', dict(input_device_class=Mouse))] | 29 | binary = 'terminal' |
388 | 30 | else: | 30 | source_dir = os.path.dirname(os.path.dirname(os.path.abspath('.'))) |
389 | 31 | scenarios = [('with touch', dict(input_device_class=Touch))] | 31 | local_location_binary = os.path.join(source_dir, 'src', 'app', binary) |
390 | 32 | installed_location_binary = os.path.join('/usr/bin/', binary) | ||
391 | 33 | installed_location_qml = '/usr/share/terminal/qml/ubuntu-terminal-app.qml' | ||
392 | 32 | 34 | ||
393 | 33 | def setUp(self): | 35 | def setUp(self): |
394 | 34 | self.pointing_device = Pointer(self.input_device_class.create()) | ||
395 | 35 | super(TerminalTestCase, self).setUp() | 36 | super(TerminalTestCase, self).setUp() |
407 | 36 | 37 | launcher_method, _ = self.get_launcher_method_and_type() | |
408 | 37 | self.EXEC = 'terminal' | 38 | self.app = ubuntu_terminal_app.TerminalApp(launcher_method()) |
409 | 38 | self.source_dir = os.path.dirname( | 39 | |
410 | 39 | os.path.dirname(os.path.abspath('.'))) | 40 | def get_launcher_method_and_type(self): |
400 | 40 | self.build_dir = self._get_build_dir() | ||
401 | 41 | self.local_location_binary = os.path.join(self.build_dir, | ||
402 | 42 | 'src', 'app', self.EXEC) | ||
403 | 43 | self.installed_location_binary = os.path.join('/usr/bin/', self.EXEC) | ||
404 | 44 | self.installed_location_qml = \ | ||
405 | 45 | '/usr/share/terminal/qml/ubuntu-terminal-app.qml' | ||
406 | 46 | |||
411 | 47 | if os.path.exists(self.local_location_binary): | 41 | if os.path.exists(self.local_location_binary): |
413 | 48 | self.launch_test_local() | 42 | launcher = self.launch_test_local |
414 | 43 | test_type = 'local' | ||
415 | 49 | elif os.path.exists(self.installed_location_binary): | 44 | elif os.path.exists(self.installed_location_binary): |
417 | 50 | self.launch_test_installed() | 45 | launcher = self.launch_test_installed |
418 | 46 | test_type = 'deb' | ||
419 | 51 | else: | 47 | else: |
427 | 52 | self.launch_test_click() | 48 | launcher = self.launch_test_click |
428 | 53 | 49 | test_type = 'click' | |
429 | 54 | def _get_build_dir(self): | 50 | return launcher, test_type |
430 | 55 | build_dir = self.source_dir | 51 | |
431 | 56 | 52 | @autopilot_logging.log_action(logger.info) | |
425 | 57 | return build_dir | ||
426 | 58 | |||
432 | 59 | def launch_test_local(self): | 53 | def launch_test_local(self): |
433 | 60 | self.useFixture(fixtures.EnvironmentVariable( | 54 | self.useFixture(fixtures.EnvironmentVariable( |
435 | 61 | 'QML2_IMPORT_PATH', newvalue=os.path.join(self.build_dir, | 55 | 'QML2_IMPORT_PATH', newvalue=os.path.join(self.source_dir, |
436 | 62 | 'src', 'plugin'))) | 56 | 'src', 'plugin'))) |
437 | 63 | 57 | ||
439 | 64 | self.app = self.launch_test_application( | 58 | return self.launch_test_application( |
440 | 65 | self.local_location_binary, | 59 | self.local_location_binary, |
441 | 66 | app_type='qt', | 60 | app_type='qt', |
443 | 67 | emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase) | 61 | emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase) |
444 | 68 | 62 | ||
445 | 63 | @autopilot_logging.log_action(logger.info) | ||
446 | 69 | def launch_test_installed(self): | 64 | def launch_test_installed(self): |
448 | 70 | self.app = self.launch_test_application( | 65 | return self.launch_test_application( |
449 | 71 | self.installed_location_binary, | 66 | self.installed_location_binary, |
450 | 72 | '-q', self.installed_location_qml, | 67 | '-q', self.installed_location_qml, |
451 | 73 | app_type='qt', | 68 | app_type='qt', |
453 | 74 | emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase) | 69 | emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase) |
454 | 75 | 70 | ||
455 | 71 | @autopilot_logging.log_action(logger.info) | ||
456 | 76 | def launch_test_click(self): | 72 | def launch_test_click(self): |
458 | 77 | self.app = self.launch_click_package( | 73 | return self.launch_click_package( |
459 | 78 | "com.ubuntu.terminal", | 74 | "com.ubuntu.terminal", |
526 | 79 | emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase) | 75 | emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase) |
461 | 80 | |||
462 | 81 | @property | ||
463 | 82 | def main_view(self): | ||
464 | 83 | return self.app.select_single(emulators.MainView) | ||
465 | 84 | |||
466 | 85 | |||
467 | 86 | class DbMan(object): | ||
468 | 87 | |||
469 | 88 | """ | ||
470 | 89 | Helper functions for dealing with sqlite databases | ||
471 | 90 | """ | ||
472 | 91 | |||
473 | 92 | def get_db(self): | ||
474 | 93 | dbs_path = os.path.expanduser( | ||
475 | 94 | "~/.local/share/com.ubuntu.terminal/Databases") | ||
476 | 95 | if not os.path.exists(dbs_path): | ||
477 | 96 | return None | ||
478 | 97 | |||
479 | 98 | files = [f for f in os.listdir(dbs_path) | ||
480 | 99 | if os.path.splitext(f)[1] == ".ini"] | ||
481 | 100 | for f in files: | ||
482 | 101 | ini_path = os.path.join(dbs_path, f) | ||
483 | 102 | with open(ini_path) as ini: | ||
484 | 103 | for line in ini: | ||
485 | 104 | if "=" in line: | ||
486 | 105 | key, val = line.strip().split("=") | ||
487 | 106 | if key == "Name" and val == "UbuntuTerminalDB": | ||
488 | 107 | try: | ||
489 | 108 | return ini_path.replace(".ini", ".sqlite") | ||
490 | 109 | except OSError: | ||
491 | 110 | pass | ||
492 | 111 | return None | ||
493 | 112 | |||
494 | 113 | def clean_db(self): | ||
495 | 114 | path = self.get_db() | ||
496 | 115 | if path is None: | ||
497 | 116 | self.assertNotEquals(path, None) | ||
498 | 117 | try: | ||
499 | 118 | os.remove(path) | ||
500 | 119 | except OSError: | ||
501 | 120 | pass | ||
502 | 121 | |||
503 | 122 | def get_font_size_from_storage(self): | ||
504 | 123 | db = self.get_db() | ||
505 | 124 | conn = sqlite3.connect(db) | ||
506 | 125 | |||
507 | 126 | with conn: | ||
508 | 127 | cur = conn.cursor() | ||
509 | 128 | cur.execute("SELECT value FROM config WHERE item='fontSize'") | ||
510 | 129 | row = cur.fetchone() | ||
511 | 130 | if row is None: | ||
512 | 131 | self.assertNotEquals(row, None) | ||
513 | 132 | return int(row[0]) | ||
514 | 133 | |||
515 | 134 | def get_color_scheme_from_storage(self): | ||
516 | 135 | db = self.get_db() | ||
517 | 136 | conn = sqlite3.connect(db) | ||
518 | 137 | |||
519 | 138 | with conn: | ||
520 | 139 | cur = conn.cursor() | ||
521 | 140 | cur.execute("SELECT value FROM config WHERE item='colorScheme'") | ||
522 | 141 | row = cur.fetchone() | ||
523 | 142 | if row is None: | ||
524 | 143 | self.assertNotEquals(row, None) | ||
525 | 144 | return row[0] | ||
527 | 145 | 76 | ||
528 | === modified file 'tests/autopilot/ubuntu_terminal_app/tests/test_terminal.py' | |||
529 | --- tests/autopilot/ubuntu_terminal_app/tests/test_terminal.py 2014-08-28 16:18:16 +0000 | |||
530 | +++ tests/autopilot/ubuntu_terminal_app/tests/test_terminal.py 2014-09-02 16:53:27 +0000 | |||
531 | @@ -11,112 +11,108 @@ | |||
532 | 11 | 11 | ||
533 | 12 | from autopilot.matchers import Eventually | 12 | from autopilot.matchers import Eventually |
534 | 13 | from testtools.matchers import Equals | 13 | from testtools.matchers import Equals |
535 | 14 | from autopilot.platform import model | ||
536 | 15 | 14 | ||
539 | 16 | from ubuntu_terminal_app.tests import TerminalTestCase, DbMan | 15 | from ubuntu_terminal_app.tests import TerminalTestCase |
540 | 17 | from ubuntuuitoolkit import ToolkitException as ToolkitException | 16 | from ubuntu_terminal_app import DbMan |
541 | 17 | from ubuntuuitoolkit import ToolkitException | ||
542 | 18 | from testscenarios import TestWithScenarios | ||
543 | 18 | 19 | ||
544 | 19 | from time import sleep | 20 | from time import sleep |
545 | 20 | import random | 21 | import random |
546 | 21 | 22 | ||
547 | 22 | 23 | ||
564 | 23 | class TestMainWindow(TerminalTestCase, DbMan): | 24 | class TestMainWindow(TerminalTestCase): |
565 | 24 | 25 | ||
566 | 25 | def setUp(self): | 26 | def test_circle_menu_shows(self): |
567 | 26 | super(TestMainWindow, self).setUp() | 27 | """Make sure that Circle Menu is visible |
568 | 27 | self.assertThat( | 28 | on long tap""" |
569 | 28 | self.main_view.visible, Eventually(Equals(True))) | 29 | self.app.main_view.long_tap_terminal_center() |
570 | 29 | 30 | menu = self.app.main_view.get_circle_menu() | |
571 | 30 | def hide_panels(self): | 31 | self.assertThat(menu.visible, Eventually(Equals(True))) |
572 | 31 | """Click hide panels button""" | 32 | |
573 | 32 | header = self.main_view.get_header() | 33 | def test_header(self): |
574 | 33 | header.click_action_button('hidepanelaction') | 34 | """Make sure that Header is visible |
575 | 34 | # Click on the button a second time in case that the | 35 | in Portrait Mode and not visible in landscape mode""" |
576 | 35 | # actions list was open and the first click just closed it | 36 | kterm = self.app.main_view.get_terminal_page() |
577 | 36 | # without further effect. If that was not the case, then | 37 | header = self.app.main_view.get_header() |
578 | 37 | # be prepared to catch the exception, as once clicked on, | 38 | if kterm.width > kterm.height: |
579 | 38 | # the action to hide panels makes the button no longer visible | 39 | self.assertThat(header.visible, Equals(False)) |
580 | 40 | else: | ||
581 | 41 | self.assertThat(header.visible, Equals(True)) | ||
582 | 42 | |||
583 | 43 | |||
584 | 44 | class TestPanel(TerminalTestCase, TestWithScenarios): | ||
585 | 45 | |||
586 | 46 | scenarios = [ | ||
587 | 47 | ('controlpanel', | ||
588 | 48 | {'button': 'controlkeysaction', | ||
589 | 49 | 'helper_method': 'get_control_panel' | ||
590 | 50 | }), | ||
591 | 51 | |||
592 | 52 | ('functionpanel', | ||
593 | 53 | {'button': 'functionkeysaction', | ||
594 | 54 | 'helper_method': 'get_function_panel' | ||
595 | 55 | }), | ||
596 | 56 | |||
597 | 57 | ('textpanel', | ||
598 | 58 | {'button': 'textkeysaction', | ||
599 | 59 | 'helper_method': 'get_text_panel' | ||
600 | 60 | }) | ||
601 | 61 | ] | ||
602 | 62 | |||
603 | 63 | def open_panel(self, button, helper_method): | ||
604 | 64 | """Open named panel""" | ||
605 | 65 | header = self.app.main_view.get_header() | ||
606 | 66 | header.click_action_button(button) | ||
607 | 67 | get_panel = getattr(self.app.main_view, helper_method) | ||
608 | 68 | return get_panel() | ||
609 | 69 | |||
610 | 70 | def hide_panel(self): | ||
611 | 71 | """Close any open panel""" | ||
612 | 72 | header = self.app.main_view.get_header() | ||
613 | 73 | |||
614 | 74 | # the overflow panel can be left open, so we need to try again | ||
615 | 75 | # https://bugs.launchpad.net/ubuntu-terminal-app/+bug/1363233 | ||
616 | 39 | try: | 76 | try: |
617 | 40 | header.click_action_button('hidepanelaction') | 77 | header.click_action_button('hidepanelaction') |
618 | 78 | try: | ||
619 | 79 | sleep(2) | ||
620 | 80 | header.click_action_button('hidepanelaction') | ||
621 | 81 | except ToolkitException: | ||
622 | 82 | pass | ||
623 | 41 | except ToolkitException: | 83 | except ToolkitException: |
624 | 42 | pass | 84 | pass |
625 | 43 | 85 | ||
626 | 86 | def test_panels(self): | ||
627 | 87 | """Make sure that Panel is visible | ||
628 | 88 | when clicking the toolbar popup items and hides properly.""" | ||
629 | 89 | panel = self.open_panel(self.button, self.helper_method) | ||
630 | 90 | self.assertThat(panel.visible, Eventually(Equals(True))) | ||
631 | 91 | self.hide_panel() | ||
632 | 92 | self.assertThat(panel.visible, Eventually(Equals(False))) | ||
633 | 93 | |||
634 | 94 | |||
635 | 95 | class TestSettings(TerminalTestCase, DbMan): | ||
636 | 96 | |||
637 | 44 | def click_item_selector_item(self, selector, value): | 97 | def click_item_selector_item(self, selector, value): |
638 | 45 | """Clicks item from item selector""" | 98 | """Clicks item from item selector""" |
639 | 46 | # This needs a toolkit helper | 99 | # This needs a toolkit helper |
640 | 47 | # https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1272345 | 100 | # https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1272345 |
647 | 48 | item_selector = self.main_view.wait_select_single('ItemSelector', | 101 | select = self.app.main_view.wait_select_single('ItemSelector', |
648 | 49 | objectName=selector) | 102 | objectName=selector) |
649 | 50 | selector = item_selector.wait_select_single('Standard', | 103 | container = select.wait_select_single('Standard', |
650 | 51 | objectName='listContainer') | 104 | objectName='listContainer') |
651 | 52 | self.pointing_device.click_object(selector) | 105 | self.app.pointing_device.click_object(container) |
652 | 53 | item_selector.currentlyExpanded.wait_for(True) | 106 | select.currentlyExpanded.wait_for(True) |
653 | 54 | # waiting for currentlyExpanded is not enough | 107 | # waiting for currentlyExpanded is not enough |
654 | 55 | # some animation is not accounted for and thus we sleep | 108 | # some animation is not accounted for and thus we sleep |
655 | 56 | sleep(2) | 109 | sleep(2) |
719 | 57 | item = selector.wait_select_single('Label', text=value) | 110 | item = container.wait_select_single('Label', text=value) |
720 | 58 | self.pointing_device.click_object(item) | 111 | self.app.pointing_device.click_object(item) |
721 | 59 | 112 | select.currentlyExpanded.wait_for(False) | |
722 | 60 | def test_control_panel(self): | 113 | # waiting for currentlyExpanded is not enough |
723 | 61 | """Make sure that Control Keys Panel is visible | 114 | # some animation is not accounted for and thus we sleep |
724 | 62 | when clicking the toolbar popup items and hides properly.""" | 115 | sleep(1) |
662 | 63 | header = self.main_view.get_header() | ||
663 | 64 | header.click_action_button('controlkeysaction') | ||
664 | 65 | |||
665 | 66 | panelCtrl = lambda: self.main_view.get_control_panel().visible | ||
666 | 67 | self.assertThat(panelCtrl, Eventually(Equals(True))) | ||
667 | 68 | self.hide_panels() | ||
668 | 69 | self.assertThat(panelCtrl, Eventually(Equals(False))) | ||
669 | 70 | |||
670 | 71 | def test_function_panel(self): | ||
671 | 72 | """Make sure that function Keys Panel is visible | ||
672 | 73 | when clicking the toolbar popup items and hides properly.""" | ||
673 | 74 | header = self.main_view.get_header() | ||
674 | 75 | header.click_action_button('functionkeysaction') | ||
675 | 76 | |||
676 | 77 | panelFunc = lambda: self.main_view.get_function_panel().visible | ||
677 | 78 | self.assertThat(panelFunc, Eventually(Equals(True))) | ||
678 | 79 | self.hide_panels() | ||
679 | 80 | self.assertThat(panelFunc, Eventually(Equals(False))) | ||
680 | 81 | |||
681 | 82 | def test_textctrl_panel(self): | ||
682 | 83 | """Make sure that Text Control Keys Panel is visible | ||
683 | 84 | when clicking the toolbar popup items and hides properly.""" | ||
684 | 85 | header = self.main_view.get_header() | ||
685 | 86 | header.click_action_button('textkeysaction') | ||
686 | 87 | |||
687 | 88 | panelScrl = lambda: self.main_view.get_scroll_panel().visible | ||
688 | 89 | self.assertThat(panelScrl, Eventually(Equals(True))) | ||
689 | 90 | self.hide_panels() | ||
690 | 91 | self.assertThat(panelScrl, Eventually(Equals(False))) | ||
691 | 92 | |||
692 | 93 | def test_circle_menu_shows(self): | ||
693 | 94 | """Make sure that Circle Menu is visible | ||
694 | 95 | on long tap""" | ||
695 | 96 | kterm = self.main_view.get_terminal_page() | ||
696 | 97 | x, y, w, h = kterm.globalRect | ||
697 | 98 | tap_x = (x + w) / 2 | ||
698 | 99 | tap_y = (y + h) / 3 | ||
699 | 100 | |||
700 | 101 | # tap in the top third of the screen, to avoid OSK | ||
701 | 102 | self.pointing_device.move(tap_x, tap_y) | ||
702 | 103 | self.pointing_device.press() | ||
703 | 104 | # we can hold the press for a long time without issue | ||
704 | 105 | # so we'll ensure the app recieves our signal when under load | ||
705 | 106 | sleep(4) | ||
706 | 107 | self.pointing_device.release() | ||
707 | 108 | |||
708 | 109 | menu = self.main_view.get_circle_menu() | ||
709 | 110 | self.assertThat(menu.visible, Eventually(Equals(True))) | ||
710 | 111 | |||
711 | 112 | def test_header(self): | ||
712 | 113 | """Make sure that Header is visible | ||
713 | 114 | in Portrait Mode and not visible in landscape mode""" | ||
714 | 115 | header = lambda: self.main_view.get_header().visible | ||
715 | 116 | if model() == "Nexus 10" or model() == "Nexus 7": | ||
716 | 117 | self.assertThat(header, Eventually(Equals(False))) | ||
717 | 118 | else: | ||
718 | 119 | self.assertThat(header, Eventually(Equals(True))) | ||
725 | 120 | 116 | ||
726 | 121 | def test_color_scheme_changes(self): | 117 | def test_color_scheme_changes(self): |
727 | 122 | """Make sure that color scheme is set correctly""" | 118 | """Make sure that color scheme is set correctly""" |
728 | @@ -133,28 +129,29 @@ | |||
729 | 133 | 129 | ||
730 | 134 | colorScheme = self.get_color_scheme_from_storage | 130 | colorScheme = self.get_color_scheme_from_storage |
731 | 135 | for scheme in schemeList: | 131 | for scheme in schemeList: |
733 | 136 | self.main_view.get_header().click_action_button('SettingsButton') | 132 | header = self.app.main_view.get_header() |
734 | 133 | header.click_action_button('SettingsButton') | ||
735 | 137 | self.click_item_selector_item("liSchemes", scheme) | 134 | self.click_item_selector_item("liSchemes", scheme) |
737 | 138 | self.main_view.go_back() | 135 | self.app.main_view.go_back() |
738 | 139 | self.assertThat(colorScheme, Eventually(Equals(scheme))) | 136 | self.assertThat(colorScheme, Eventually(Equals(scheme))) |
739 | 140 | 137 | ||
740 | 141 | def test_font_size_changes(self): | 138 | def test_font_size_changes(self): |
741 | 142 | """Make sure that font size is set correctly""" | 139 | """Make sure that font size is set correctly""" |
743 | 143 | header = self.main_view.get_header() | 140 | header = self.app.main_view.get_header() |
744 | 144 | header.click_action_button('SettingsButton') | 141 | header.click_action_button('SettingsButton') |
745 | 145 | 142 | ||
746 | 146 | font_size = self.get_font_size_from_storage | 143 | font_size = self.get_font_size_from_storage |
747 | 147 | 144 | ||
748 | 148 | # change font size to min | 145 | # change font size to min |
750 | 149 | self.main_view.drag_horizontal_slider("slFont", 8) | 146 | self.app.main_view.drag_horizontal_slider("slFont", 8) |
751 | 150 | self.assertThat(font_size, Eventually(Equals(8))) | 147 | self.assertThat(font_size, Eventually(Equals(8))) |
752 | 151 | 148 | ||
753 | 152 | # change font size to max | 149 | # change font size to max |
755 | 153 | self.main_view.drag_horizontal_slider("slFont", 32) | 150 | self.app.main_view.drag_horizontal_slider("slFont", 32) |
756 | 154 | self.assertThat(font_size, Eventually(Equals(32))) | 151 | self.assertThat(font_size, Eventually(Equals(32))) |
757 | 155 | 152 | ||
758 | 156 | # change font size to random sizes | 153 | # change font size to random sizes |
759 | 157 | for loop in range(1, 3): | 154 | for loop in range(1, 3): |
760 | 158 | randSize = random.randrange(9, 31, 1) | 155 | randSize = random.randrange(9, 31, 1) |
762 | 159 | self.main_view.drag_horizontal_slider("slFont", randSize) | 156 | self.app.main_view.drag_horizontal_slider("slFont", randSize) |
763 | 160 | self.assertThat(font_size, Eventually(Equals(randSize))) | 157 | self.assertThat(font_size, Eventually(Equals(randSize))) |
FAILED: Continuous integration, rev:129 91.189. 93.70:8080/ job/ubuntu- terminal- app-ci/ 85/ 91.189. 93.70:8080/ job/generic- mediumtests- utopic/ 1744/console 91.189. 93.70:8080/ job/generic- mediumtests- utopic/ 1744/artifact/ work/output/ *zip*/output. zip 91.189. 93.70:8080/ job/ubuntu- terminal- app-utopic- amd64-ci/ 29
http://
Executed test runs:
FAILURE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/ubuntu- terminal- app-ci/ 85/rebuild
http://