Merge lp:~om26er/ubuntu-system-settings/system_upgrade_testing into lp:ubuntu-system-settings

Proposed by Omer Akram
Status: Work in progress
Proposed branch: lp:~om26er/ubuntu-system-settings/system_upgrade_testing
Merge into: lp:ubuntu-system-settings
Diff against target: 551 lines (+478/-0)
9 files modified
plugins/system-update/PageComponent.qml (+4/-0)
tests/autopilot/run_upgrade_tests.sh (+3/-0)
tests/autopilot/system_upgrade/__init__.py (+6/-0)
tests/autopilot/system_upgrade/helpers/__init__.py (+6/-0)
tests/autopilot/system_upgrade/helpers/system_image_flasher.py (+163/-0)
tests/autopilot/system_upgrade/helpers/unlock_screen.py (+55/-0)
tests/autopilot/system_upgrade/tests/test_system_updates.py (+106/-0)
tests/autopilot/system_upgrade/variables.py (+19/-0)
tests/autopilot/upgrade_test_runner.py (+116/-0)
To merge this branch: bzr merge lp:~om26er/ubuntu-system-settings/system_upgrade_testing
Reviewer Review Type Date Requested Status
Ubuntu Touch System Settings Pending
Review via email: mp+214025@code.launchpad.net
To post a comment you must log in.
675. By Omer Akram

merge trunk

676. By Omer Akram

fix

677. By Omer Akram

create separate deb for system upgrade tests

678. By Omer Akram

revert the packaging changes

679. By Omer Akram

setup network -- is temporarily there

680. By Omer Akram

cleanup some test code, also changed the unlocker script into a class

681. By Omer Akram

run the test runner with the argument of DUT serial number to prepare for CI

682. By Omer Akram

more work for CI, now takes ppa name and extra packages as arguments

683. By Omer Akram

pep8

684. By Omer Akram

add a parameter to specify if test is running in Canonical CI lab so that the connection to wifi network there is made

685. By Omer Akram

enable logging to help with debugging in future.

686. By Omer Akram

fix long strings

687. By Omer Akram

finally fix these damn strings

Unmerged revisions

687. By Omer Akram

finally fix these damn strings

686. By Omer Akram

fix long strings

685. By Omer Akram

enable logging to help with debugging in future.

684. By Omer Akram

add a parameter to specify if test is running in Canonical CI lab so that the connection to wifi network there is made

683. By Omer Akram

pep8

682. By Omer Akram

more work for CI, now takes ppa name and extra packages as arguments

681. By Omer Akram

run the test runner with the argument of DUT serial number to prepare for CI

680. By Omer Akram

cleanup some test code, also changed the unlocker script into a class

679. By Omer Akram

setup network -- is temporarily there

678. By Omer Akram

revert the packaging changes

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/system-update/PageComponent.qml'
2--- plugins/system-update/PageComponent.qml 2014-03-17 02:08:47 +0000
3+++ plugins/system-update/PageComponent.qml 2014-04-05 20:26:24 +0000
4@@ -35,6 +35,7 @@
5 title: i18n.tr("Updates")
6
7 property bool installAll: false
8+ property bool updatesDownloaded: false
9 property int updatesAvailable: 0
10
11 DeviceInfo {
12@@ -45,11 +46,13 @@
13 id: dialogInstallComponent
14 Dialog {
15 id: dialogueInstall
16+ objectName: "dialogInstall"
17 title: i18n.tr("Update System")
18 text: i18n.tr("The phone needs to restart to install the system update.")
19
20 Button {
21 text: i18n.tr("Install & Restart")
22+ objectName: "btnInstallUpdate"
23 color: UbuntuColors.orange
24 onClicked: {
25 installingImageUpdate.visible = true;
26@@ -157,6 +160,7 @@
27
28 onSystemUpdateDownloaded: {
29 root.updatesAvailable -= 1;
30+ root.updatesDownloaded = true;
31 PopupUtils.open(dialogInstallComponent);
32 }
33
34
35=== added file 'tests/autopilot/run_upgrade_tests.sh'
36--- tests/autopilot/run_upgrade_tests.sh 1970-01-01 00:00:00 +0000
37+++ tests/autopilot/run_upgrade_tests.sh 2014-04-05 20:26:24 +0000
38@@ -0,0 +1,3 @@
39+#!/bin/bash
40+
41+python3 upgrade_test_runner.py 04bf2c50e294d599
42
43=== added directory 'tests/autopilot/system_upgrade'
44=== added file 'tests/autopilot/system_upgrade/__init__.py'
45--- tests/autopilot/system_upgrade/__init__.py 1970-01-01 00:00:00 +0000
46+++ tests/autopilot/system_upgrade/__init__.py 2014-04-05 20:26:24 +0000
47@@ -0,0 +1,6 @@
48+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
49+# Copyright 2014 Canonical
50+#
51+# This program is free software: you can redistribute it and/or modify it
52+# under the terms of the GNU General Public License version 3, as published
53+# by the Free Software Foundation.
54
55=== added directory 'tests/autopilot/system_upgrade/helpers'
56=== added file 'tests/autopilot/system_upgrade/helpers/__init__.py'
57--- tests/autopilot/system_upgrade/helpers/__init__.py 1970-01-01 00:00:00 +0000
58+++ tests/autopilot/system_upgrade/helpers/__init__.py 2014-04-05 20:26:24 +0000
59@@ -0,0 +1,6 @@
60+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
61+# Copyright 2014 Canonical
62+#
63+# This program is free software: you can redistribute it and/or modify it
64+# under the terms of the GNU General Public License version 3, as published
65+# by the Free Software Foundation.
66
67=== added file 'tests/autopilot/system_upgrade/helpers/system_image_flasher.py'
68--- tests/autopilot/system_upgrade/helpers/system_image_flasher.py 1970-01-01 00:00:00 +0000
69+++ tests/autopilot/system_upgrade/helpers/system_image_flasher.py 2014-04-05 20:26:24 +0000
70@@ -0,0 +1,163 @@
71+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
72+# Copyright 2014 Canonical
73+#
74+# This program is free software: you can redistribute it and/or modify it
75+# under the terms of the GNU General Public License version 3, as published
76+# by the Free Software Foundation.
77+
78+import logging
79+import os
80+import subprocess
81+import time
82+
83+logger = logging.getLogger(__name__)
84+
85+
86+class DeviceImageFlash(object):
87+
88+ def setup_device(self, ppa=None, package_list=None, **kwargs):
89+ self.flash_device(**kwargs)
90+ self.wait_for_device()
91+ self.set_device_read_write()
92+ self.reboot_device()
93+ self.disable_intro_screen()
94+ self.reboot_device()
95+
96+ self.setup_network()
97+
98+ if ppa is not None:
99+ self.add_apt_repository(ppa)
100+
101+ self.apt_get_update()
102+
103+ if package_list is not None:
104+ self.apt_get_install(package_list)
105+
106+ if self.extra_packages is not None:
107+ self.apt_get_install(self.extra_packages)
108+
109+ def str_to_lst(self, string):
110+ result = []
111+ for char in string.split():
112+ result.append(char)
113+
114+ return result
115+
116+ def run_command_on_host(self, command, str_to_list=True, **kwargs):
117+ logger.info('Running command: {}'.format(command))
118+ if str_to_list is True:
119+ command = self.str_to_lst(command)
120+
121+ subprocess.call(command, **kwargs)
122+
123+ def run_autopilot_test_on_target(self, test_suite, user='phablet'):
124+ test_command = \
125+ "autopilot run -f text -o /tmp/upgrade.log -v {}".format(
126+ test_suite)
127+ command = 'adb -s {} shell sudo -iu {} bash -ic "{}"'.format(
128+ self.dut_serial, user, test_command)
129+
130+ subprocess.call(command, shell=True)
131+
132+ self.run_command_on_host('adb -s {} pull {} /tmp'.format(
133+ self.dut_serial, self.log_path)
134+ )
135+ self.addCleanup(os.remove, self.log_path)
136+
137+ def flash_device(
138+ self,
139+ channel='ubuntu-touch/trusty-proposed',
140+ revision_number=None,
141+ bootstrap=False
142+ ):
143+
144+ command = []
145+ command.append('phablet-flash')
146+ command.append('ubuntu-system')
147+ command.append('--serial')
148+ command.append(self.dut_serial)
149+ command.append('--channel')
150+ command.append(channel)
151+ if revision_number is not None:
152+ command.append('--revision')
153+ command.append(revision_number)
154+ if bootstrap is True:
155+ command.append('--bootstrap')
156+
157+ self.run_command_on_host(command, str_to_list=False)
158+
159+ def run_command_on_target(self, command, user=None, shell=False):
160+ if user == 'phablet':
161+ command = 'adb -s {} shell sudo -iu {} bash -ic "{}"'.format(
162+ self.dut_serial, user, command
163+ )
164+ self.run_command_on_host(command)
165+ elif user is None:
166+ command = 'adb -s {} shell {}'.format(self.dut_serial, command)
167+ self.run_command_on_host(command)
168+
169+ def wait_for_device(self, timeout=60):
170+ command = 'adb -s {} wait-for-device'.format(self.dut_serial)
171+ self.run_command_on_host(command)
172+ logger.info(
173+ 'Waiting {} seconds for the device to settle before '
174+ 'proceeding further.'.format(timeout)
175+ )
176+ time.sleep(timeout)
177+ logger.info('Just to be sure')
178+ self.run_command_on_host(command)
179+
180+ def set_device_read_write(self):
181+ command = 'touch /userdata/.writable_image'
182+ logger.info('Changing system to read/write.')
183+ self.run_command_on_target(command)
184+
185+ def reboot_device(self):
186+ wait = 10
187+ self.run_command_on_target('reboot')
188+ logger.info(
189+ 'Wating {} seconds to ensure target goes away from adb before '
190+ 'waiting for it to come back'.format(wait)
191+ )
192+ time.sleep(wait)
193+ self.wait_for_device()
194+
195+ def disable_intro_screen(self):
196+ self.run_command_on_target(
197+ 'dbus-send --system --print-reply '
198+ '--dest=org.freedesktop.Accounts '
199+ '/org/freedesktop/Accounts/User32011 '
200+ 'org.freedesktop.DBus.Properties.Set '
201+ 'string:com.canonical.unity.AccountsService '
202+ 'string:demo-edges variant:boolean:false')
203+ self.run_command_on_target('touch /.intro_off')
204+
205+ def setup_network(self):
206+ if self.running_in_ci:
207+ command = ('adb -s {} shell nmcli dev wifi '
208+ 'connect ubuntu-qa-g-wpa-d password '
209+ 'qalabwireless'.format(self.dut_serial) )
210+ logger.info('Setting up network on target.')
211+ self.run_command_on_host(command)
212+ else:
213+ command = 'phablet-network -s {}'.format(self.dut_serial)
214+ logger.warning(
215+ 'Setting up network on target. you may need to '
216+ 'enter your password for "{}" to complete.'
217+ )
218+ self.run_command_on_host(command)
219+
220+ def add_apt_repository(self, ppa):
221+ command = 'add-apt-repository -y {}'.format(ppa)
222+ logger.info('Adding ppa {} on target.'.format(ppa))
223+ self.run_command_on_target(command)
224+
225+ def apt_get_update(self):
226+ command = 'apt-get update'
227+ logger.info('Updating apt database.')
228+ self.run_command_on_target(command)
229+
230+ def apt_get_install(self, packages):
231+ command = 'apt-get -y -f --force-yes install {}'.format(packages)
232+ logger.info('Installing required packages on target.')
233+ self.run_command_on_target(command)
234
235=== added file 'tests/autopilot/system_upgrade/helpers/unlock_screen.py'
236--- tests/autopilot/system_upgrade/helpers/unlock_screen.py 1970-01-01 00:00:00 +0000
237+++ tests/autopilot/system_upgrade/helpers/unlock_screen.py 2014-04-05 20:26:24 +0000
238@@ -0,0 +1,55 @@
239+#!/usr/bin/env python
240+
241+import logging
242+import sys
243+
244+from unity8 import process_helpers as helpers
245+
246+import dbus
247+
248+logging.basicConfig(level=logging.INFO)
249+
250+
251+class UnlockScreen(object):
252+
253+ def __init__(self):
254+ self.powerd = self._get_powerd_interface()
255+
256+ def _get_powerd_interface(self):
257+ bus = dbus.SystemBus()
258+ return bus.get_object(
259+ 'com.canonical.powerd', '/com/canonical/powerd'
260+ )
261+
262+ def _powerd_request_state_active(self):
263+ logging.info('Setting system state "Active"')
264+ return self.powerd.requestSysState(
265+ 'autopilot-lock', 1, dbus_interface='com.canonical.powerd'
266+ )
267+
268+ def _powerd_release_state_active(self):
269+ logging.info('Releasing system state "Active"')
270+ self.powerd.clearSysState(
271+ self.active_cookie, dbus_interface='com.canonical.powerd'
272+ )
273+
274+ def restart_with_testability(self):
275+ self.active_cookie = self._powerd_request_state_active()
276+ helpers.restart_unity_with_testability()
277+ self._powerd_release_state_active()
278+
279+ def unlock_screen(self):
280+ self.restart_with_testability()
281+ helpers.unlock_unity()
282+
283+
284+def help():
285+ print("Usage:")
286+ print("Run the script without any argument to unlock with assertion.")
287+
288+
289+if len(sys.argv) >= 2 and sys.argv[1] == '-h':
290+ help()
291+else:
292+ unlocker = UnlockScreen()
293+ unlocker.unlock_screen()
294
295=== added directory 'tests/autopilot/system_upgrade/tests'
296=== added file 'tests/autopilot/system_upgrade/tests/__init__.py'
297=== added file 'tests/autopilot/system_upgrade/tests/test_system_updates.py'
298--- tests/autopilot/system_upgrade/tests/test_system_updates.py 1970-01-01 00:00:00 +0000
299+++ tests/autopilot/system_upgrade/tests/test_system_updates.py 2014-04-05 20:26:24 +0000
300@@ -0,0 +1,106 @@
301+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
302+# Copyright 2013 Canonical
303+#
304+# This program is free software: you can redistribute it and/or modify it
305+# under the terms of the GNU General Public License version 3, as published
306+# by the Free Software Foundation.
307+
308+import time
309+import logging
310+import os
311+
312+from autopilot.matchers import Eventually
313+from testtools.matchers import Equals
314+
315+parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
316+os.sys.path.insert(0, parentdir)
317+
318+from ubuntu_system_settings.tests import SystemUpdatesBaseTestCase
319+
320+logging.basicConfig(level=logging.INFO)
321+
322+
323+class SystemUpdatesTestCases(SystemUpdatesBaseTestCase):
324+
325+ """Tests for System Updates."""
326+
327+ def setUp(self):
328+ self.patch_environment('IGNORE_CREDENTIALS', 'True')
329+ super(SystemUpdatesTestCases, self).setUp()
330+
331+ def _get_updates_view(self):
332+ return self.app.select_single(
333+ 'PageComponent', objectName='systemUpdatesPage'
334+ )
335+
336+ def wait_for_updates_to_download(self, timeout=40):
337+ while timeout > 0:
338+ download_state = self._get_updates_view().updatesDownloaded
339+ if download_state:
340+ return
341+
342+ timeout = timeout - 1
343+ time.sleep(5)
344+ else:
345+ raise ValueError(
346+ "Download didn't complete in given time, check your "
347+ "internet and try again.")
348+
349+ def wait_for_state(self, state, timeout=60):
350+ """Wait for expected state
351+
352+ :returns: state
353+ :raises: SystemSettingsEmulatorException
354+ """
355+ for wait in range(timeout):
356+ status = self._get_updates_view().state
357+ logging.info(
358+ 'State: {} waiting for {}'.format(status, state)
359+ )
360+ if state == status:
361+ return state
362+ time.sleep(1)
363+
364+ raise ValueError(
365+ 'Error state {} not found before timeout'.format(state)
366+ )
367+
368+ def _get_install_dialog(self):
369+ return self.app.wait_select_single(
370+ 'Dialog', objectName='dialogInstall'
371+ )
372+
373+ def wait_for_dialog(self):
374+ dialog = self._get_install_dialog()
375+
376+ dialog.opacity.wait_for(1.0)
377+
378+ def click_install_and_restart_button(self):
379+ button = self.app.select_single(
380+ 'Button', objectName='btnInstallUpdate'
381+ )
382+
383+ self.pointer.click_object(button)
384+
385+ def _get_installing_update_screen(self):
386+ return self.app.wait_select_single(
387+ 'QQuickRectangle', objectName='installingImageUpdate'
388+ )
389+
390+ def test_image_update_from_ui_works(self):
391+ """Install latest system update available."""
392+ self.wait_for_state('UPDATE')
393+ logging.info('Waiting for update to download.')
394+ self.wait_for_updates_to_download()
395+ logging.info('finished waiting for update')
396+ self.wait_for_dialog()
397+ self.click_install_and_restart_button()
398+ installing_screen = self._get_installing_update_screen()
399+ self.assertThat(
400+ installing_screen.visible, Eventually(Equals(True))
401+ )
402+
403+ def test_state_noupdates(self):
404+ """Check if system is fully updated."""
405+ state = self.wait_for_state('NOUPDATES')
406+ self.assertThat(state, Equals('NOUPDATES'))
407
408=== added file 'tests/autopilot/system_upgrade/variables.py'
409--- tests/autopilot/system_upgrade/variables.py 1970-01-01 00:00:00 +0000
410+++ tests/autopilot/system_upgrade/variables.py 2014-04-05 20:26:24 +0000
411@@ -0,0 +1,19 @@
412+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
413+# Copyright 2014 Canonical
414+#
415+# This program is free software: you can redistribute it and/or modify it
416+# under the terms of the GNU General Public License version 3, as published
417+# by the Free Software Foundation.
418+
419+
420+PACKAGE_LIST = 'python-dbusmock unity8-autopilot ubuntu-download-manager \
421+ubuntu-ui-toolkit-autopilot ubuntu-download-manager system-image-dbus \
422+system-image-cli system-image-common ubuntu-system-settings-autopilot'
423+
424+
425+TEST1_PART1 = 'system_upgrade.tests.test_system_updates.SystemUpdatesTestCases\
426+.test_image_update_from_ui_works'
427+
428+
429+TEST1_PART2 = 'system_upgrade.tests.test_system_updates.SystemUpdatesTestCases\
430+.test_state_noupdates'
431
432=== added file 'tests/autopilot/upgrade_test_runner.py'
433--- tests/autopilot/upgrade_test_runner.py 1970-01-01 00:00:00 +0000
434+++ tests/autopilot/upgrade_test_runner.py 2014-04-05 20:26:24 +0000
435@@ -0,0 +1,116 @@
436+#!/usr/bin/python3
437+
438+import argparse
439+import logging
440+import sys
441+import unittest
442+
443+from system_upgrade.helpers.system_image_flasher import DeviceImageFlash
444+from system_upgrade.variables import (
445+ PACKAGE_LIST,
446+ TEST1_PART1,
447+ TEST1_PART2,
448+)
449+
450+
451+class SystemImageUpgrader(unittest.TestCase, DeviceImageFlash):
452+
453+ log_path = '/tmp/upgrade.log'
454+ source = 'system_upgrade'
455+ target_home = '/home/phablet/'
456+ test_suite = 'system_upgrade'
457+ device_test_path = '/home/phablet/{}'.format(test_suite)
458+ unlocker = 'unlock_screen.py'
459+ unlocker_abs_location = target_home + unlocker
460+ unlocker_location = 'system_upgrade/helpers/' + unlocker
461+
462+ def setUp(self):
463+ self.dut_serial = arguments.serial
464+ self.extra_packages = arguments.packages
465+ self.running_in_ci = arguments.ci
466+ self.setup_device(
467+ ppa=arguments.ppa,
468+ package_list=PACKAGE_LIST,
469+ bootstrap=True,
470+ revision_number='-1'
471+ )
472+
473+ def test_system_update(self):
474+ self._push_and_run_tests(test_suite=TEST1_PART1)
475+ log_file = self.open_log_file()
476+ self.assertTrue(log_file.endswith('OK\n'))
477+
478+ self.wait_for_device(timeout=150)
479+
480+ self._push_and_run_tests(test_suite=TEST1_PART2)
481+ log_file = self.open_log_file()
482+ self.assertTrue(log_file.endswith('OK\n'))
483+
484+ def open_log_file(self):
485+ log_file = open(self.log_path, 'r')
486+ self.addCleanup(log_file.close)
487+ return log_file.read()
488+
489+ def _push_and_run_tests(self, test_suite):
490+ self.push_files_to_device(self.source, self.device_test_path)
491+ self.push_files_to_device(
492+ 'ubuntu_system_settings', '/home/phablet/ubuntu_system_settings'
493+ )
494+ self.unlock_device_screen()
495+ self.run_autopilot_test_on_target(test_suite)
496+
497+ def push_files_to_device(self, source, location):
498+ self.addCleanup(self.delete_autopilot_test)
499+ command = 'adb -s {} push {} {}'.format(
500+ self.dut_serial, source, location
501+ )
502+
503+ logger.info('Pushing files to target with command:')
504+ logger.info(command)
505+ self.run_command_on_host(command)
506+
507+ def delete_autopilot_test(self):
508+ command = 'rm -rf {}'.format(self.device_test_path)
509+ self.run_command_on_target(command)
510+
511+ def unlock_device_screen(self):
512+ self.push_files_to_device(self.unlocker_location, self.target_home)
513+ self.run_command_on_target(
514+ 'chmod +x {}'.format(self.unlocker_abs_location)
515+ )
516+ self.run_command_on_target('./unlock_screen.py', user='phablet')
517+
518+
519+def _parse_command_line_arguments():
520+ parser = argparse.ArgumentParser(
521+ description='Ubuntu system update test runner'
522+ )
523+ parser.add_argument(
524+ 'serial', metavar='SERIAL_NUMBER', type=str,
525+ help='Serial numer of the device to run tests on.'
526+ )
527+ parser.add_argument(
528+ '--ppa', type=str,
529+ help='Launchpad ppa to add to the device before installing '
530+ 'test packages. example: ppa:test/ppa'
531+ )
532+ parser.add_argument(
533+ '--packages', type=str,
534+ help='Names of extra packages to be installed on the test device '
535+ 'before running the tests.'
536+ )
537+ parser.add_argument(
538+ '--ci', metavar='BOOLEAN', default=False,
539+ help='Specify whether the test suite is running in the Canonical '
540+ 'CI lab so that the network connection could be established '
541+ 'with the appropriate Wi-Fi network.'
542+ )
543+
544+ return parser.parse_args()
545+
546+
547+if __name__ == '__main__':
548+ arguments = _parse_command_line_arguments()
549+ logging.basicConfig(level=logging.INFO)
550+ logger = logging.getLogger(__name__)
551+ unittest.main(argv=[sys.argv[0]])

Subscribers

People subscribed via source and target branches