Merge lp:~indicator-applet-developers/unity8/indicator-power-autopilot-test into lp:unity8

Proposed by Allan LeSage
Status: Work in progress
Proposed branch: lp:~indicator-applet-developers/unity8/indicator-power-autopilot-test
Merge into: lp:unity8
Diff against target: 302 lines (+196/-9)
5 files modified
debian/control (+2/-0)
tests/autopilot/unity8/indicators/__init__.py (+20/-0)
tests/autopilot/unity8/indicators/tests/__init__.py (+20/-5)
tests/autopilot/unity8/indicators/tests/test_indicator_power.py (+145/-0)
tests/autopilot/unity8/indicators/tests/test_indicators.py (+9/-4)
To merge this branch: bzr merge lp:~indicator-applet-developers/unity8/indicator-power-autopilot-test
Reviewer Review Type Date Requested Status
Albert Astals Cid (community) Needs Fixing
PS Jenkins bot (community) continuous-integration Needs Fixing
Leo Arias (community) Approve
Thomi Richards (community) Approve
Christopher Lee (community) Needs Fixing
Review via email: mp+247079@code.launchpad.net

Commit message

Add discharging battery autopilot test.

Description of the change

This test simulates a discharging battery using a fake upower via python-dbusmock.

Offering for commentary with the UEQA team, charles wanting to absorb best practices for writing these autopilot tests.

Note that this requires a couple of related branches:

For a upower template tweak to enable signalling,
https://code.launchpad.net/~charlesk/python-dbusmock/add-upower-device-set-properties/+merge/246713

For an indicator-power which will listen on a special private bus for the fake upower:
https://code.launchpad.net/~charlesk/indicator-power/custom-bus-for-upower/+merge/246234

NOTE that we're chasing an intermittent failure, may need some pitti advice about, hence WIP.

To post a comment you must log in.
Revision history for this message
Charles Kerr (charlesk) :
Revision history for this message
Christopher Lee (veebers) wrote :

Looking good so far. Some questions and things that need fixing up.

review: Needs Fixing
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) :
review: Needs Fixing
Revision history for this message
Leo Arias (elopio) wrote :

I added some more comments.

review: Needs Fixing
Revision history for this message
Charles Kerr (charlesk) wrote :

I've nibbled around the edges of these NFs and have fixed most of the little pieces, but it's past my bedtime so Allan or I will need to finish the revisions tomorrow.

Remaining TODO:

 * device_emulation_scenarios + multiply_scenarios()

 * FakeUPower as a Fixture

 * moving the Indicator helper class to tests/autopilot/unity8/indicators/helpers/indicator_power.py -- not much payoff for this today, but scales if/when we add more indicator helpers

 * GRID_UNIT_PX: is it needed? if so, why?

Revision history for this message
Allan LeSage (allanlesage) wrote :

Filed lp:1413390 for the GRID_UNIT_PX issue, will tag in source, also here's a relevant IRC snippet with elopio: http://pastebin.ubuntu.com/9808551/ . Don't think we need to solve here.

Revision history for this message
Allan LeSage (allanlesage) wrote :

Corrected _get_device_emulation_scenarios() resolved GRID_UNIT_PX issue.

I see elopio's and veebers' questions about using a CPO for Indicator object--this isn't strictly CPO-able as it represents not the appearance of the Indicator but its D-Bus state. Please bring questions on this, resolved?

Revision history for this message
Leo Arias (elopio) wrote :

Some comments inline.

And one item for discussion:

<elopio> veebers: thomi: alesage: why are we putting the custom proxy object in a module named helpers, intead of putting them in the module named indicators?
<veebers> alesage, elopio: sounds good to me. I would imagine the apps have a similar layout for precedent?
<elopio> veebers: it's a mess with apps. But that's what I am aiming for. We will have the browser CPO in webbrowser.WebbrowserApp
<elopio> instead of webbrowser.helpers.WebbrowserApp
<veebers> ack, for the CPO no need to have it in helpers
<alesage> sounds decided, I'll make that change veebers, elopio

Thank you! I specially like the idea of starting the service with a different dbus address.

review: Needs Fixing
Revision history for this message
Leo Arias (elopio) :
Revision history for this message
Allan LeSage (allanlesage) wrote :

Question in comments. . . .

Revision history for this message
Charles Kerr (charlesk) wrote :

Responses to Leo inline

Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

Much better, but a few issues still.

review: Needs Fixing
Revision history for this message
Leo Arias (elopio) wrote :

I replied to some replies. Will look again at the new version.

Revision history for this message
Leo Arias (elopio) :
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

LGTM

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Charles, Allan, you good with this?

1569. By Allan LeSage

Add python3-dbusmock dependency.

Revision history for this message
Leo Arias (elopio) wrote :

Please remove the unused

56 + def icon_matches(self, icon_name):

These must be reverted to work with python2. We are currently installing unity8-autopilot also on the py2 path:

78 + super().setUp()
149 + super().setUp()
199 + super().setUp()

1570. By Allan LeSage

Move PowerIndicator, flake8 correction, restore py2 supers, broken test fix.

1571. By Allan LeSage

Remove icon_matches.

Revision history for this message
Leo Arias (elopio) wrote :

Looks good. Thanks for the changes.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1572. By Allan LeSage

Correct python-dbusmock build-deps.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1573. By Allan LeSage

Relocate python*-dbusmock dependencies.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in tests/autopilot/unity8/indicators/__init__.py
Text conflict in tests/autopilot/unity8/indicators/tests/__init__.py
Text conflict in tests/autopilot/unity8/indicators/tests/test_indicators.py
3 conflicts encountered.

1574. By Allan LeSage

Merge trunk, resolving conflicts.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Hi guys, can you please add the "MP Submission Checklist Template" from https://wiki.ubuntu.com/Process/Merges/Checklists/Unity8 as part of the "description Of the Change"?

review: Needs Fixing
Revision history for this message
Allan LeSage (allanlesage) wrote :

This might sit for a bit, need to investigate a persistent Jenkins failure, will ping you Albert.

Revision history for this message
Albert Astals Cid (aacid) wrote :

I'll put it as Work In Progress to remove it from my dashboard of things to review.

Unmerged revisions

1574. By Allan LeSage

Merge trunk, resolving conflicts.

1573. By Allan LeSage

Relocate python*-dbusmock dependencies.

1572. By Allan LeSage

Correct python-dbusmock build-deps.

1571. By Allan LeSage

Remove icon_matches.

1570. By Allan LeSage

Move PowerIndicator, flake8 correction, restore py2 supers, broken test fix.

1569. By Allan LeSage

Add python3-dbusmock dependency.

1568. By Charles Kerr

in __init__, make multiline import follow pep 328

1567. By Charles Kerr

in IndicatorPowerTestCase.setUp(), remove the self.main_window.wait_select_single(), since it's also encapsulated in the Indicator helper class

1566. By Charles Kerr

in IndicatorPowerTestCase.setUp(), don't create a temporary list for service_test_args.

1565. By Charles Kerr

in MockUPower.setUp(), clean up the OSError exception's message

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2015-01-22 10:09:11 +0000
+++ debian/control 2015-01-27 16:20:28 +0000
@@ -144,10 +144,12 @@
144 libqt5widgets5,144 libqt5widgets5,
145 python-autopilot,145 python-autopilot,
146 python-evdev,146 python-evdev,
147 python-dbusmock,
147 python-fixtures,148 python-fixtures,
148 python-gi,149 python-gi,
149 python-mock,150 python-mock,
150 python3-autopilot,151 python3-autopilot,
152 python3-dbusmock,
151 python3-evdev,153 python3-evdev,
152 python3-fixtures,154 python3-fixtures,
153 python3-gi,155 python3-gi,
154156
=== modified file 'tests/autopilot/unity8/indicators/__init__.py'
--- tests/autopilot/unity8/indicators/__init__.py 2015-01-21 04:15:31 +0000
+++ tests/autopilot/unity8/indicators/__init__.py 2015-01-27 16:20:28 +0000
@@ -12,6 +12,7 @@
12# but WITHOUT ANY WARRANTY; without even the implied warranty of12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.14# GNU General Public License for more details.
15#
15# You should have received a copy of the GNU General Public License16# You should have received a copy of the GNU General Public License
16# 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/>.
1718
@@ -21,6 +22,25 @@
21from unity8.shell import emulators22from unity8.shell import emulators
2223
2324
25class PowerIndicator(object):
26
27 def __init__(self, main_window):
28 self.main_window = main_window
29
30 def get_icon_name(self):
31 """Returns the icon name.
32
33 Can be a list of options, eg
34 'image://theme/battery-040,battery-good-symbolic,battery-good'
35
36 """
37 widget = self.main_window.wait_select_single(
38 objectName='indicator-power-widget'
39 )
40 # convert it from a dbus.string to a normal string
41 return str(widget.icons[0])
42
43
24class IndicatorPage(emulators.UnityEmulatorBase):44class IndicatorPage(emulators.UnityEmulatorBase):
2545
26 """Autopilot helper for the IndicatorPage component."""46 """Autopilot helper for the IndicatorPage component."""
2747
=== modified file 'tests/autopilot/unity8/indicators/tests/__init__.py'
--- tests/autopilot/unity8/indicators/tests/__init__.py 2015-01-20 17:56:49 +0000
+++ tests/autopilot/unity8/indicators/tests/__init__.py 2015-01-27 16:20:28 +0000
@@ -16,19 +16,34 @@
16# You should have received a copy of the GNU General Public License16# You should have received a copy of the GNU General Public License
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/>.
1818
19from autopilot import platform
20
21from unity8 import process_helpers19from unity8 import process_helpers
22from unity8.shell import tests20from unity8.shell import tests
2321
2422
25class IndicatorTestCase(tests.UnityTestCase):23class IndicatorTestCase(tests.UnityTestCase):
2624
27 device_emulation_scenarios = tests._get_device_emulation_scenarios()25 scenarios = tests._get_device_emulation_scenarios()
2826
29 def setUp(self):27 def setUp(self):
30 if platform.model() == 'Desktop':
31 self.skipTest('Test cannot be run on the desktop.')
32 super(IndicatorTestCase, self).setUp()28 super(IndicatorTestCase, self).setUp()
29 self._dirty_services = set()
33 self.unity_proxy = self.launch_unity()30 self.unity_proxy = self.launch_unity()
34 process_helpers.unlock_unity(self.unity_proxy)31 process_helpers.unlock_unity(self.unity_proxy)
32
33 def start_test_service(self, service_name, *args):
34 """Restart a service (e.g. 'indicator-power-service') with test args.
35
36 Adds a no-arguments restart to addCleanup() so that the system
37 can reset to a nontest version of the service when the tests finish.
38 """
39 self._start_service(service_name, *args)
40 if service_name not in self._dirty_services:
41 self._dirty_services.add(service_name)
42 self.addCleanup(self._start_service, service_name)
43
44 @staticmethod
45 def _start_service(service_name, *args):
46 """Restart an upstart service; e.g. indicator-power-service"""
47 if process_helpers.is_job_running(service_name):
48 process_helpers.stop_job(service_name)
49 process_helpers.start_job(service_name, *args)
3550
=== added file 'tests/autopilot/unity8/indicators/tests/test_indicator_power.py'
--- tests/autopilot/unity8/indicators/tests/test_indicator_power.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/unity8/indicators/tests/test_indicator_power.py 2015-01-27 16:20:28 +0000
@@ -0,0 +1,145 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Unity - Indicators Autopilot Test Suite
4# Copyright (C) 2015 Canonical
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19import os
20import subprocess
21
22from autopilot.matchers import Eventually
23import dbusmock
24from fixtures import Fixture
25from testtools.matchers import Contains
26
27from unity8.indicators import PowerIndicator
28from unity8.indicators.tests import IndicatorTestCase
29
30
31class MockBattery(object):
32
33 def __init__(self, proxy, object_path):
34 self.proxy = proxy
35 self.object_path = object_path
36
37 def set_properties(self, properties):
38 self.proxy.SetDeviceProperties(self.object_path, properties)
39
40
41class MockUPower(Fixture):
42
43 def setUp(self):
44
45 super(MockUPower, self).setUp()
46
47 self._battery_count = 0
48
49 key = 'DBUS_SYSTEM_BUS_ADDRESS'
50 if key in os.environ:
51 raise OSError("environment variable {} already set".format(key))
52
53 # start a dbusmock system bus and get its address, which looks like
54 # "unix:abstract=/tmp/dbus-LQo4Do4ldY,guid=3f7f39089f00884fa96533f354935995"
55 dbusmock.DBusTestCase.start_system_bus()
56 self.bus_address = os.environ[key].split(',')[0]
57
58 # start a mock upower service
59 self.proxy = dbusmock.DBusTestCase.spawn_server_template(
60 'upower',
61 {'OnBattery': True, 'HibernateAllowed': False},
62 stdout=subprocess.PIPE
63 )[1]
64
65 self.addCleanup(self._cleanUp)
66
67 def _cleanUp(self):
68 self.proxy = None
69 self.bus_address = None
70 dbusmock.DBusTestCase.tearDownClass()
71
72 def add_discharging_battery(
73 self,
74 model_name='Mock Battery',
75 percentage=30.0,
76 seconds_until_empty=1200):
77
78 # uniqueness required; this becomes part of the device's object_path
79 device_name = 'mock_BAT{}'.format(self._battery_count)
80 self._battery_count += 1
81
82 object_path = self.proxy.AddDischargingBattery(
83 device_name,
84 model_name,
85 percentage,
86 seconds_until_empty
87 )
88
89 return MockBattery(self.proxy, object_path)
90
91
92class IndicatorPowerTestCase(IndicatorTestCase):
93
94 def setUp(self):
95 super(IndicatorPowerTestCase, self).setUp()
96
97 # start a mock UPower service
98 self.upower = self.useFixture(MockUPower())
99
100 # restart indicator-power with the mock env variables
101 self.start_test_service(
102 'indicator-power',
103 'INDICATOR_POWER_BUS_ADDRESS_UPOWER={}'.format(
104 self.upower.bus_address
105 )
106 )
107
108 def test_discharging_battery(self):
109 """Test the icon as the battery drains."""
110
111 # tuples of battery states + expected outcomes for those states
112 steps = [
113 ({'Percentage': 100.0}, {'icon_name': 'battery-100'}),
114 ({'Percentage': 95.0}, {'icon_name': 'battery-100'}),
115 ({'Percentage': 90.0}, {'icon_name': 'battery-100'}),
116 ({'Percentage': 85.0}, {'icon_name': 'battery-080'}),
117 ({'Percentage': 80.0}, {'icon_name': 'battery-080'}),
118 ({'Percentage': 75.0}, {'icon_name': 'battery-080'}),
119 ({'Percentage': 70.0}, {'icon_name': 'battery-080'}),
120 ({'Percentage': 65.0}, {'icon_name': 'battery-060'}),
121 ({'Percentage': 60.0}, {'icon_name': 'battery-060'}),
122 ({'Percentage': 55.0}, {'icon_name': 'battery-060'}),
123 ({'Percentage': 50.0}, {'icon_name': 'battery-060'}),
124 ({'Percentage': 45.0}, {'icon_name': 'battery-040'}),
125 ({'Percentage': 40.0}, {'icon_name': 'battery-040'}),
126 ({'Percentage': 35.0}, {'icon_name': 'battery-040'}),
127 ({'Percentage': 30.0}, {'icon_name': 'battery-040'}),
128 ({'Percentage': 25.0}, {'icon_name': 'battery-020'}),
129 ({'Percentage': 20.0}, {'icon_name': 'battery-020'}),
130 ({'Percentage': 15.0}, {'icon_name': 'battery-020'}),
131 ({'Percentage': 10.0}, {'icon_name': 'battery-020'}),
132 ({'Percentage': 5.0}, {'icon_name': 'battery-000'}),
133 ({'Percentage': 0.0}, {'icon_name': 'battery-000'})
134 ]
135
136 battery = self.upower.add_discharging_battery()
137
138 indicator = PowerIndicator(self.main_window)
139
140 for properties, expected in steps:
141 battery.set_properties(properties)
142 self.assertTrue(
143 indicator.get_icon_name,
144 Eventually(Contains(expected['icon_name']))
145 )
0146
=== modified file 'tests/autopilot/unity8/indicators/tests/test_indicators.py'
--- tests/autopilot/unity8/indicators/tests/test_indicators.py 2015-01-20 17:56:49 +0000
+++ tests/autopilot/unity8/indicators/tests/test_indicators.py 2015-01-27 16:20:28 +0000
@@ -18,10 +18,9 @@
1818
19from __future__ import absolute_import19from __future__ import absolute_import
2020
21from autopilot import platform
21from testscenarios import multiply_scenarios22from testscenarios import multiply_scenarios
2223
23from autopilot import platform
24
25from unity8.indicators import tests24from unity8.indicators import tests
2625
2726
@@ -38,7 +37,7 @@
38 ]37 ]
39 scenarios = multiply_scenarios(38 scenarios = multiply_scenarios(
40 indicator_scenarios,39 indicator_scenarios,
41 tests.IndicatorTestCase.device_emulation_scenarios40 tests.IndicatorTestCase.scenarios
42 )41 )
4342
44 def setUp(self):43 def setUp(self):
@@ -46,6 +45,9 @@
46 if (platform.model() == 'Nexus 10' and45 if (platform.model() == 'Nexus 10' and
47 self.indicator_name == 'indicator-bluetooth'):46 self.indicator_name == 'indicator-bluetooth'):
48 self.skipTest('Nexus 10 does not have bluetooth at the moment.')47 self.skipTest('Nexus 10 does not have bluetooth at the moment.')
48 if platform.model() == 'Desktop':
49 # names exported differently in unity7
50 self.skipTest('Test cannot be run on the desktop.')
4951
50 def test_indicator_exists(self):52 def test_indicator_exists(self):
51 self.main_window._get_indicator_panel_item(53 self.main_window._get_indicator_panel_item(
@@ -73,7 +75,7 @@
73 ]75 ]
74 scenarios = multiply_scenarios(76 scenarios = multiply_scenarios(
75 indicator_scenarios,77 indicator_scenarios,
76 tests.IndicatorTestCase.device_emulation_scenarios78 tests.IndicatorTestCase.scenarios
77 )79 )
7880
79 def setUp(self):81 def setUp(self):
@@ -81,6 +83,9 @@
81 if (platform.model() == 'Nexus 10' and83 if (platform.model() == 'Nexus 10' and
82 self.indicator_name == 'indicator-bluetooth'):84 self.indicator_name == 'indicator-bluetooth'):
83 self.skipTest('Nexus 10 does not have bluetooth at the moment.')85 self.skipTest('Nexus 10 does not have bluetooth at the moment.')
86 if platform.model() == 'Desktop':
87 # names exported differently in unity7
88 self.skipTest('Test cannot be run on the desktop.')
8489
85 def test_indicator_page_title_matches_widget(self):90 def test_indicator_page_title_matches_widget(self):
86 """Swiping open an indicator must show its correct title.91 """Swiping open an indicator must show its correct title.

Subscribers

People subscribed via source and target branches