Merge lp:~canonical-platform-qa/ubuntu-ota-tests/check-for-running-service into lp:ubuntu-ota-tests

Proposed by Christopher Lee on 2015-03-06
Status: Merged
Approved by: Christopher Lee on 2015-03-10
Approved revision: 12
Merged at revision: 3
Proposed branch: lp:~canonical-platform-qa/ubuntu-ota-tests/check-for-running-service
Merge into: lp:ubuntu-ota-tests
Diff against target: 212 lines (+183/-2)
5 files modified
debian/tests/control (+4/-2)
debian/tests/ubuntu_ota_tests/__init__.py (+27/-0)
debian/tests/ubuntu_ota_tests/selftests/test_services.py (+32/-0)
debian/tests/ubuntu_ota_tests/services.py (+86/-0)
debian/tests/ubuntu_ota_tests/system.py (+34/-0)
To merge this branch: bzr merge lp:~canonical-platform-qa/ubuntu-ota-tests/check-for-running-service
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve on 2015-03-10
Christopher Lee (community) Approve on 2015-03-10
Leo Arias (community) 2015-03-06 Approve on 2015-03-10
Barry Warsaw (community) Needs Fixing on 2015-03-09
Review via email: mp+252057@code.launchpad.net

Commit Message

Add script for ensuring the system-image-dbus process is not running.

Description of the Change

Add script for ensuring the system-image-dbus process is not running.

Perhaps there is a better way to have the support scripts instead of in the d/tests/ dir. SHould they instead be packaged up in ubuntu-ota-tests so that they can be consumed outside of the dep8 tests?

Also, note that the is a simple workable case in revno 4 where it just catches the dbus exception, I added the use of checking for the running of the process (check with psutil) but that adds a Depends: python3-psutil meaning the test setup will take a little longer.

Also, also :-) I don't think the test that I have there will stay, it's purely there as a stand-in for now.

To post a comment you must log in.
Barry Warsaw (barry) wrote :

Comments inline.

I like the way you've created a package for utilities to live in. We should definitely do that. Also, I think it's perfectly fine to import things from the systemimage package. There's a lot of useful utilities there, such as systemimage.reactor.Reactor, and since this is the SUT, I think it's perfectly acceptable to use them when appropriate.

(Note, in the case where you locate the system-image-dbus process, si has a similar utility, but it's semantics are somewhat different, so it's not a perfect fit.)

review: Needs Fixing
Barry Warsaw (barry) wrote :

Oh also, re: packaging. Yes, they probably should live outside the debian/tests directory, i.e. get installed into the system Python 3's dist-packages like a normal Python 3 package. That's a little more work though, so I think we can refactor that in later.

6. By Christopher Lee on 2015-03-10

Tidy up use of list comprehension.

7. By Christopher Lee on 2015-03-10

Add timed check to ensure process has actually stopped, adds depends on autopilot though.

8. By Christopher Lee on 2015-03-10

Use global for process name

9. By Christopher Lee on 2015-03-10

Rename loop method

Christopher Lee (veebers) wrote :

Thanks Barry I've made the suggested changes.

I came across an issue today where the example test would fail due to the process not being exited right at that moment. As a fix I'm using some functionality from autopilot, but I'm concerned by this for som ereasons:
  1. This pulls in autopilot as a dep. Not sure if we want to do that for the core parts of the scripts.
  2. There may be a better way to resolve the issue I use ap for.

I agree re: the packaging, we can iterate over it this week. We need to get the base code down so we can continue.

I'll take a closer look at what systemimage provides. Are you suggesting that there is code there already I can use in this instance?

10. By Leo Arias on 2015-03-10

Reorg to bootstrap the selftests.

Leo Arias (elopio) wrote :

I moved the selftest to a directory, and made it a test case so we get nice results out of it.

11. By Leo Arias on 2015-03-10

Fixed the order of dependencies.

Leo Arias (elopio) wrote :

When using 3.0 from barry's branch, the test fails with:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/dbus/bus.py", line 175, in activate_name_owner
    return self.get_name_owner(bus_name)
  File "/usr/lib/python3/dist-packages/dbus/bus.py", line 361, in get_name_owner
    's', (bus_name,), **keywords)
  File "/usr/lib/python3/dist-packages/dbus/connection.py", line 651, in call_blocking
    message, timeout)
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NameHasNoOwner: Could not get owner of name 'com.canonical.SystemImage': no such name

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/tmp/adt-run.cQbK74/build.KLU/real-tree/debian/tests/ubuntu_ota_tests/selftests/test_services.py", line 28, in test_ensure_system_image_dbus_not_runnig_must_stop_process
    services.get_system_image_interface()
  File "/tmp/adt-run.cQbK74/build.KLU/real-tree/debian/tests/ubuntu_ota_tests/services.py", line 56, in get_system_image_interface
    service = system_bus.get_object('com.canonical.SystemImage', '/Service')
  File "/usr/lib/python3/dist-packages/dbus/bus.py", line 241, in get_object
    follow_name_owner_changes=follow_name_owner_changes)
  File "/usr/lib/python3/dist-packages/dbus/proxies.py", line 248, in __init__
    self._named_service = conn.activate_name_owner(bus_name)
  File "/usr/lib/python3/dist-packages/dbus/bus.py", line 180, in activate_name_owner
    self.start_service_by_name(bus_name)
  File "/usr/lib/python3/dist-packages/dbus/bus.py", line 278, in start_service_by_name
    'su', (bus_name, flags)))
  File "/usr/lib/python3/dist-packages/dbus/connection.py", line 651, in call_blocking
    message, timeout)
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NoMemory: Launcher could not run (out of memory)

----------------------------------------------------------------------

12. By Leo Arias on 2015-03-10

Use the test command.

Federico Gimenez (fgimenez) wrote :

One inline comment, I think also that we should describe a bit in the README the layout that we have decided for the project in order to make it more understandable: if we are not building any debian package, why is the source code under debian/tests? It seems that you must know about autopkgtest to understand where to find things, the layout seems to be conditioned by the tool used to run the tests.

Cheers!

Leo Arias (elopio) wrote :

Now the tests are passing for me. Weird because I didn't change anything, just reflashed. Maybe my phone was broken before.

Barry Warsaw (barry) wrote :

On Mar 10, 2015, at 03:42 AM, Christopher Lee wrote:

>I came across an issue today where the example test would fail due to the
>process not being exited right at that moment. As a fix I'm using some
>functionality from autopilot, but I'm concerned by this for som ereasons:

Yeah, D-Bus is notoriously unreliable for tests like this. It's a source of
constant sorrow for getting system-image built in a PPA. I'm now testing some
new techniques using the org.freedesktop.DBus interface. It seems to improve
things but it's not perfect. There are still opportunities for race
conditions, and I suspect they're just inherent in D-Bus.

>1. This pulls in autopilot as a dep. Not sure if we want to do that for the
>core parts of the scripts.

I say "whatever works" :)

>2. There may be a better way to resolve the issue I use ap for.

Here's what I'm using now:

    bus = dbus.SystemBus()
    service = dbus.SystemBus().get_object('org.freedesktop.DBus', '/')
    iface = dbus.Interface(service, 'org.freedesktop.DBus')
    reply = 0
    # 2015-03-09 BAW: This could potentially spin forever, but we'll assume
    # D-Bus eventually is successful in starting the service.
    while reply != 2:
        reply = iface.StartServiceByName('com.canonical.SystemImage', 0)
        time.sleep(0.1)

`reply` could be 1 or 2. 1 means it's started but 2 means it's already
running, which is why I wait for that.

Barry Warsaw (barry) wrote :

On Mar 10, 2015, at 09:18 AM, Federico Gimenez wrote:

>> +def ensure_loop_ready():
>> + global _loop_running
>
>This global variable and the need for the client code of this module to know
>how it works internally (it has to request first a interface and later pass
>that object to the module methods) makes me wonder if we should use better a
>class here, it seems that the design would be more suited to the task.

I have a somewhat different approach in my branch. We'll need to decide which
way we want to go.

Barry Warsaw (barry) wrote :

On Mar 10, 2015, at 06:37 AM, Leo Arias wrote:

>When using 3.0 from barry's branch, the test fails with:

I can't tell you what's causing the NoMember error. As best I've been able to
determine, the NameHasNoOwner error occurs when the process
(system-image-dbus) associated with the name (com.canonical.SystemImage)
hasn't yet started. See my previous comment for a new approach I'm trying to
take, which works locally, although the proof will be in the PPA pudding.

Leo Arias (elopio) wrote :

This is good for me, lets use it as a bootstrap and improve things as we find them.

review: Approve
Christopher Lee (veebers) wrote :

Me too.

review: Approve
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/tests/control'
2--- debian/tests/control 2015-03-05 00:36:08 +0000
3+++ debian/tests/control 2015-03-10 06:38:09 +0000
4@@ -1,2 +1,4 @@
5-Tests: ota_basic
6-Depends:
7+Test-Command: cd debian/tests; python3 -m unittest discover ubuntu_ota_tests.selftests
8+Restrictions: allow-stderr
9+Depends: python3-autopilot,
10+ python3-psutil,
11
12=== added directory 'debian/tests/ubuntu_ota_tests'
13=== added file 'debian/tests/ubuntu_ota_tests/__init__.py'
14--- debian/tests/ubuntu_ota_tests/__init__.py 1970-01-01 00:00:00 +0000
15+++ debian/tests/ubuntu_ota_tests/__init__.py 2015-03-10 06:38:09 +0000
16@@ -0,0 +1,27 @@
17+#
18+# Ubuntu OTA Tests
19+# Copyright (C) 2015 Canonical
20+#
21+# This program is free software: you can redistribute it and/or modify
22+# it under the terms of the GNU General Public License as published by
23+# the Free Software Foundation, either version 3 of the License, or
24+# (at your option) any later version.
25+#
26+# This program is distributed in the hope that it will be useful,
27+# but WITHOUT ANY WARRANTY; without even the implied warranty of
28+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29+# GNU General Public License for more details.
30+#
31+# You should have received a copy of the GNU General Public License
32+# along with this program. If not, see <http://www.gnu.org/licenses/>.
33+#
34+
35+from ubuntu_ota_tests import (
36+ services,
37+ system,
38+)
39+
40+__all__ = [
41+ 'services',
42+ 'system',
43+]
44
45=== added directory 'debian/tests/ubuntu_ota_tests/selftests'
46=== added file 'debian/tests/ubuntu_ota_tests/selftests/__init__.py'
47=== added file 'debian/tests/ubuntu_ota_tests/selftests/test_services.py'
48--- debian/tests/ubuntu_ota_tests/selftests/test_services.py 1970-01-01 00:00:00 +0000
49+++ debian/tests/ubuntu_ota_tests/selftests/test_services.py 2015-03-10 06:38:09 +0000
50@@ -0,0 +1,32 @@
51+#
52+# Ubuntu OTA Tests
53+# Copyright (C) 2015 Canonical
54+#
55+# This program is free software: you can redistribute it and/or modify
56+# it under the terms of the GNU General Public License as published by
57+# the Free Software Foundation, either version 3 of the License, or
58+# (at your option) any later version.
59+#
60+# This program is distributed in the hope that it will be useful,
61+# but WITHOUT ANY WARRANTY; without even the implied warranty of
62+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
63+# GNU General Public License for more details.
64+#
65+# You should have received a copy of the GNU General Public License
66+# along with this program. If not, see <http://www.gnu.org/licenses/>.
67+#
68+
69+import unittest
70+
71+from ubuntu_ota_tests import services
72+
73+
74+class ServicesTestCase(unittest.TestCase):
75+
76+ def test_ensure_system_image_dbus_not_runnig_must_stop_process(self):
77+ # start the dbus process if it isn't already
78+ services.get_system_image_interface()
79+ self.assertTrue(services._is_system_image_process_running())
80+
81+ services.ensure_system_image_dbus_not_running()
82+ self.assertFalse(services._is_system_image_process_running())
83
84=== added file 'debian/tests/ubuntu_ota_tests/services.py'
85--- debian/tests/ubuntu_ota_tests/services.py 1970-01-01 00:00:00 +0000
86+++ debian/tests/ubuntu_ota_tests/services.py 2015-03-10 06:38:09 +0000
87@@ -0,0 +1,86 @@
88+#
89+# Ubuntu OTA Tests
90+# Copyright (C) 2015 Canonical
91+#
92+# This program is free software: you can redistribute it and/or modify
93+# it under the terms of the GNU General Public License as published by
94+# the Free Software Foundation, either version 3 of the License, or
95+# (at your option) any later version.
96+#
97+# This program is distributed in the hope that it will be useful,
98+# but WITHOUT ANY WARRANTY; without even the implied warranty of
99+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
100+# GNU General Public License for more details.
101+#
102+# You should have received a copy of the GNU General Public License
103+# along with this program. If not, see <http://www.gnu.org/licenses/>.
104+#
105+
106+import dbus
107+import logging
108+
109+from autopilot.matchers import Eventually
110+from dbus.mainloop.glib import DBusGMainLoop
111+from testtools import matchers
112+
113+from ubuntu_ota_tests import system
114+
115+
116+logger = logging.getLogger(__name__)
117+
118+# For some reason the process name is 'system-image-db' on the device.
119+SYS_IMG_PROC_NAME = 'system-image-db'
120+
121+# Is there a better mechanism that we can use to ensure that DBusGMainLoop
122+# isn't called more than once?
123+_loop_running = False
124+
125+
126+def ensure_loop_ready():
127+ global _loop_running
128+ if not _loop_running:
129+ DBusGMainLoop(set_as_default=True)
130+ _loop_running = True
131+
132+
133+def get_system_image_interface():
134+ """Return a dbus Interface for SystemImage Service.
135+
136+ Note calling this method will cause system-image-dbus to start (if it's not
137+ already started).
138+
139+ """
140+ ensure_loop_ready()
141+
142+ system_bus = dbus.SystemBus()
143+ service = system_bus.get_object('com.canonical.SystemImage', '/Service')
144+ iface = dbus.Interface(service, 'com.canonical.SystemImage')
145+
146+ return iface
147+
148+
149+def ensure_system_image_dbus_not_running():
150+ sys_image_iface = get_system_image_interface()
151+ try:
152+ sys_image_iface.Exit()
153+ _ensure_system_image_process_not_running()
154+ except dbus.DBusException:
155+ logger.debug("Attempted to exit system dbus when not running.")
156+
157+
158+def _ensure_system_image_process_not_running():
159+ """Raise RuntimeError if process is still running after 10 seconds."""
160+ result = Eventually(
161+ matchers.Equals(False)
162+ ).match(_is_system_image_process_running)
163+ if result is not None:
164+ raise RuntimeError(
165+ 'system image dbus process still running after 10.0 seconds')
166+
167+
168+def _is_system_image_process_running():
169+ """Return True if system-image-dbus process is running False otherwise."""
170+ try:
171+ return system.get_process_by_name(SYS_IMG_PROC_NAME) is not None
172+ except OSError:
173+ return False
174
175=== added file 'debian/tests/ubuntu_ota_tests/system.py'
176--- debian/tests/ubuntu_ota_tests/system.py 1970-01-01 00:00:00 +0000
177+++ debian/tests/ubuntu_ota_tests/system.py 2015-03-10 06:38:09 +0000
178@@ -0,0 +1,34 @@
179+#
180+# Ubuntu OTA Tests
181+# Copyright (C) 2015 Canonical
182+#
183+# This program is free software: you can redistribute it and/or modify
184+# it under the terms of the GNU General Public License as published by
185+# the Free Software Foundation, either version 3 of the License, or
186+# (at your option) any later version.
187+#
188+# This program is distributed in the hope that it will be useful,
189+# but WITHOUT ANY WARRANTY; without even the implied warranty of
190+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
191+# GNU General Public License for more details.
192+#
193+# You should have received a copy of the GNU General Public License
194+# along with this program. If not, see <http://www.gnu.org/licenses/>.
195+#
196+
197+import psutil
198+
199+
200+def get_process_by_name(process_name):
201+ """Return a psutil.Process for the process with the given name.
202+
203+ :raises err something: if a process cannot be found with the given name.
204+
205+ """
206+ try:
207+ for process in psutil.process_iter():
208+ if process.name() == process_name:
209+ return process
210+ except IndexError:
211+ raise OSError(
212+ 'No process found with the name "{}"'.format(process_name))

Subscribers

People subscribed via source and target branches

to all changes: