Merge lp:~charlesk/python-dbusmock/add-upower-device-set-properties into lp:python-dbusmock

Proposed by Charles Kerr
Status: Merged
Merge reported by: Martin Pitt
Merged at revision: not available
Proposed branch: lp:~charlesk/python-dbusmock/add-upower-device-set-properties
Merge into: lp:python-dbusmock
Diff against target: 215 lines (+87/-29)
2 files modified
dbusmock/templates/upower.py (+48/-15)
tests/test_upower.py (+39/-14)
To merge this branch: bzr merge lp:~charlesk/python-dbusmock/add-upower-device-set-properties
Reviewer Review Type Date Requested Status
Martin Pitt Approve
Review via email: mp+246713@code.launchpad.net

Commit message

Add support for changing upower device properties.

Description of the change

Add support for changing upower device properties.

To post a comment you must log in.
Revision history for this message
Martin Pitt (pitti) wrote :

Looks good to me, with one little nitpick. Thanks!

review: Approve
Revision history for this message
Martin Pitt (pitti) wrote :

Hm, this causes a test failure:

======================================================================
FAIL: test_one_ac (test_upower.TestUPower)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/martin/upstream/python-dbusmock/tests/test_upower.py", line 107, in test_one_ac
    self.assertRegex(out, 'device changed:\s+' + path)
AssertionError: Regex didn't match: 'device changed:\\s+/org/freedesktop/UPower/devices/mock_AC' not found in 'Monitoring activity from the power daemon. Press Ctrl+C to cancel.\n'

----------------------------------------------------------------------
Ran 95 tests in 14.349s

Revision history for this message
Martin Pitt (pitti) wrote :

So this is genuinely broken for upower 0.99 and needs further investigation.

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

Okay so the issue is that the spawned template in the unit tests is always mocking the UPower 0 API, even when UPower 0.99 is installed, so there's a disconnect between the signals that the installed "dbus --monitor" is expecting and what the dbusmock is sending.

This worked before because the signal is emitted from the unit test code (which knows the installed upower version) instead of the template (which is mocking UPower 0).

When using "dbus --monitor" to sniff for events, we need to mock the installed version of upower. So I changed the test to pass the installed version as the 'DaemonVersion' parameter when spawning the template.

This caused a couple of side-effects, test_suspend() and test_no_display_device() both fail on 0.99 since Suspend was removed and DisplayDevice was added. :)

So, I've moved these (and the other test_09_properties()) methods out into a TestUPower0 class as a sibling to the existing TestUPower1 class for testing UPower 0-specific behavior.

223. By Charles Kerr

if a test relies on the installed version of upower, make sure to mock the installed version.

224. By Charles Kerr

fix upower.SetDeviceProperties' input argument signature

Revision history for this message
Charles Kerr (charlesk) :
225. By Charles Kerr

silence a flake8 'too many blank lines' warning

Revision history for this message
Martin Pitt (pitti) wrote :

Indeed, thanks for fixing this! I committed this to trunk: https://gitorious.org/python-dbusmock/python-dbusmock/commit/3f55ea9876fa

Closing MP manually as the LP branch is only a bzr mirror of the upstream git for PPA recipe purposes.

review: Approve
Revision history for this message
Martin Pitt (pitti) wrote :

I did an upstream 0.12 release with this. Will upload to Debian experimental and then sync into vivid.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'dbusmock/templates/upower.py'
2--- dbusmock/templates/upower.py 2014-09-22 08:23:08 +0000
3+++ dbusmock/templates/upower.py 2015-01-16 21:21:16 +0000
4@@ -24,11 +24,13 @@
5 import dbus
6
7 from dbusmock import MOCK_IFACE, mockobject
8+import dbusmock
9
10 BUS_NAME = 'org.freedesktop.UPower'
11 MAIN_OBJ = '/org/freedesktop/UPower'
12 MAIN_IFACE = 'org.freedesktop.UPower'
13 SYSTEM_BUS = True
14+DEVICE_IFACE = 'org.freedesktop.UPower.Device'
15
16
17 def load(mock, parameters):
18@@ -59,7 +61,7 @@
19 # add Display device; for defined properties, see
20 # http://cgit.freedesktop.org/upower/tree/src/org.freedesktop.UPower.xml
21 mock.AddObject(mock.p_display_dev,
22- 'org.freedesktop.UPower.Device',
23+ DEVICE_IFACE,
24 {
25 'Type': dbus.UInt32(0, variant_level=1),
26 'State': dbus.UInt32(0, variant_level=1),
27@@ -109,7 +111,7 @@
28 '''
29 path = '/org/freedesktop/UPower/devices/' + device_name
30 self.AddObject(path,
31- 'org.freedesktop.UPower.Device',
32+ DEVICE_IFACE,
33 {
34 'PowerSupply': dbus.Boolean(True, variant_level=1),
35 'Model': dbus.String(model_name, variant_level=1),
36@@ -136,7 +138,7 @@
37 '''
38 path = '/org/freedesktop/UPower/devices/' + device_name
39 self.AddObject(path,
40- 'org.freedesktop.UPower.Device',
41+ DEVICE_IFACE,
42 {
43 'PowerSupply': dbus.Boolean(True, variant_level=1),
44 'IsPresent': dbus.Boolean(True, variant_level=1),
45@@ -171,7 +173,7 @@
46 '''
47 path = '/org/freedesktop/UPower/devices/' + device_name
48 self.AddObject(path,
49- 'org.freedesktop.UPower.Device',
50+ DEVICE_IFACE,
51 {
52 'PowerSupply': dbus.Boolean(True, variant_level=1),
53 'IsPresent': dbus.Boolean(True, variant_level=1),
54@@ -209,24 +211,55 @@
55 'SetupDisplayDevice() can only be used with the 1.0 API')
56
57 display_props = mockobject.objects[self.p_display_dev]
58- display_props.Set('org.freedesktop.UPower.Device', 'Type',
59+ display_props.Set(DEVICE_IFACE, 'Type',
60 dbus.UInt32(type))
61- display_props.Set('org.freedesktop.UPower.Device', 'State',
62+ display_props.Set(DEVICE_IFACE, 'State',
63 dbus.UInt32(state))
64- display_props.Set('org.freedesktop.UPower.Device', 'Percentage',
65+ display_props.Set(DEVICE_IFACE, 'Percentage',
66 percentage)
67- display_props.Set('org.freedesktop.UPower.Device', 'Energy', energy)
68- display_props.Set('org.freedesktop.UPower.Device', 'EnergyFull',
69+ display_props.Set(DEVICE_IFACE, 'Energy', energy)
70+ display_props.Set(DEVICE_IFACE, 'EnergyFull',
71 energy_full)
72- display_props.Set('org.freedesktop.UPower.Device', 'EnergyRate',
73+ display_props.Set(DEVICE_IFACE, 'EnergyRate',
74 energy_rate)
75- display_props.Set('org.freedesktop.UPower.Device', 'TimeToEmpty',
76+ display_props.Set(DEVICE_IFACE, 'TimeToEmpty',
77 dbus.Int64(time_to_empty))
78- display_props.Set('org.freedesktop.UPower.Device', 'TimeToFull',
79+ display_props.Set(DEVICE_IFACE, 'TimeToFull',
80 dbus.Int64(time_to_full))
81- display_props.Set('org.freedesktop.UPower.Device', 'IsPresent',
82+ display_props.Set(DEVICE_IFACE, 'IsPresent',
83 is_present)
84- display_props.Set('org.freedesktop.UPower.Device', 'IconName',
85+ display_props.Set(DEVICE_IFACE, 'IconName',
86 icon_name)
87- display_props.Set('org.freedesktop.UPower.Device', 'WarningLevel',
88+ display_props.Set(DEVICE_IFACE, 'WarningLevel',
89 dbus.UInt32(warning_level))
90+
91+
92+@dbus.service.method(MOCK_IFACE, in_signature='oa{sv}', out_signature='')
93+def SetDeviceProperties(self, object_path, properties):
94+ '''Convenience method to Set a device's properties.
95+
96+ object_path: the device to update
97+ properties: dictionary of keys to dbus variants.
98+
99+ If the 1.0 API is being mocked, changing this property will trigger
100+ the device's PropertiesChanged signal; otherwise, the older
101+ org.freedesktop.UPower DeviceChanged signal will be emitted.
102+ '''
103+ device = dbusmock.get_object(object_path)
104+
105+ # set the properties
106+ for key, value in properties.items():
107+ device.Set(DEVICE_IFACE, key, value)
108+
109+ # notify the listeners
110+ if self.api1:
111+ device.EmitSignal(dbus.PROPERTIES_IFACE,
112+ 'PropertiesChanged',
113+ 'sa{sv}as',
114+ [
115+ DEVICE_IFACE,
116+ properties,
117+ []
118+ ])
119+ else:
120+ self.EmitSignal(MAIN_IFACE, 'DeviceChanged', 's', [object_path])
121
122=== modified file 'tests/test_upower.py'
123--- tests/test_upower.py 2014-09-22 08:23:08 +0000
124+++ tests/test_upower.py 2015-01-16 21:21:16 +0000
125@@ -55,7 +55,12 @@
126
127 def setUp(self):
128 (self.p_mock, self.obj_upower) = self.spawn_server_template(
129- 'upower', {'OnBattery': True, 'HibernateAllowed': False}, stdout=subprocess.PIPE)
130+ 'upower', {
131+ 'OnBattery': True,
132+ 'HibernateAllowed': False,
133+ 'DaemonVersion': upower_client_version
134+ },
135+ stdout=subprocess.PIPE)
136 # set log to nonblocking
137 flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL)
138 fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
139@@ -80,7 +85,6 @@
140 def test_one_ac(self):
141 path = self.dbusmock.AddAC('mock_AC', 'Mock AC')
142 self.assertEqual(path, '/org/freedesktop/UPower/devices/mock_AC')
143- ac_obj = self.dbus_con.get_object('org.freedesktop.UPower', path)
144
145 self.assertRegex(self.p_mock.stdout.read(),
146 b'emit org.freedesktop.UPower.DeviceAdded '
147@@ -100,16 +104,9 @@
148 universal_newlines=True)
149
150 time.sleep(0.3)
151- if upower_client_version < '0.99':
152- # for 0.9 API
153- self.dbusmock.EmitSignal('', 'DeviceChanged', 's', [path])
154- else:
155- # for 1.0 API
156- ac_obj.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as',
157- dbus.Array(['org.freedesktop.UPower.Device',
158- {'PowerSupply': dbus.Boolean(True, variant_level=1)},
159- dbus.Array([], signature='s')],
160- signature='v'))
161+ self.dbusmock.SetDeviceProperties(path, {
162+ 'PowerSupply': dbus.Boolean(True, variant_level=1)
163+ })
164 time.sleep(0.2)
165
166 mon.terminate()
167@@ -157,12 +154,39 @@
168 self.assertRegex(out, ' time to full:\s+20.0 min')
169 self.assertRegex(out, ' state:\s+charging')
170
171+
172+@unittest.skipUnless(have_upower, 'upower not installed')
173+@unittest.skipUnless(upower_client_version <= '0.99', 'pre-0.99 client API specific test')
174+class TestUPower0(dbusmock.DBusTestCase):
175+ '''Test mocking upowerd with 0.x API'''
176+
177+ @classmethod
178+ def setUpClass(klass):
179+ klass.start_system_bus()
180+ klass.dbus_con = klass.get_dbus(True)
181+
182+ def setUp(self):
183+ (self.p_mock, self.obj_upower) = self.spawn_server_template(
184+ 'upower', {
185+ 'OnBattery': True,
186+ 'HibernateAllowed': False,
187+ 'DaemonVersion': '0.9'
188+ },
189+ stdout=subprocess.PIPE)
190+ # set log to nonblocking
191+ flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL)
192+ fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
193+ self.dbusmock = dbus.Interface(self.obj_upower, dbusmock.MOCK_IFACE)
194+
195+ def tearDown(self):
196+ self.p_mock.terminate()
197+ self.p_mock.wait()
198+
199 def test_suspend(self):
200+ '''0.9 API specific Suspend signal'''
201 self.obj_upower.Suspend(dbus_interface='org.freedesktop.UPower')
202 self.assertRegex(self.p_mock.stdout.readline(), b'^[0-9.]+ Suspend$')
203
204- @unittest.skipUnless(upower_client_version < '0.99',
205- '0.9 client API specific test')
206 def test_09_properties(self):
207 '''0.9 API specific properties'''
208
209@@ -174,6 +198,7 @@
210 self.assertNotIn('critical-action:', out)
211
212 def test_no_display_device(self):
213+ '''0.9 API has no display device'''
214 self.assertRaises(dbus.exceptions.DBusException,
215 self.obj_upower.GetDisplayDevice)
216

Subscribers

People subscribed via source and target branches

to all changes: