Merge lp:~larryprice/libertine/always-progress into lp:libertine

Proposed by Larry Price
Status: Merged
Approved by: Christopher Townsend
Approved revision: 415
Merged at revision: 434
Proposed branch: lp:~larryprice/libertine/always-progress
Merge into: lp:libertine
Diff against target: 3094 lines (+1128/-705)
43 files modified
CMakeLists.txt (+6/-0)
debian/control (+1/-0)
liblibertine/libertined.cpp (+15/-10)
python/libertine/Client.py (+9/-8)
python/libertine/Libertine.py (+1/-1)
python/libertine/service/constants.py (+27/-0)
python/libertine/service/container.py (+10/-10)
python/libertine/service/container_control.py (+26/-6)
python/libertine/service/download.py (+35/-40)
python/libertine/service/operations.py (+18/-62)
python/libertine/service/operations_monitor.py (+92/-0)
python/libertine/service/task_dispatcher.py (+7/-5)
python/libertine/service/tasks/app_info_task.py (+5/-5)
python/libertine/service/tasks/base_task.py (+18/-14)
python/libertine/service/tasks/container_info_task.py (+4/-4)
python/libertine/service/tasks/create_task.py (+8/-8)
python/libertine/service/tasks/destroy_task.py (+5/-5)
python/libertine/service/tasks/install_task.py (+5/-5)
python/libertine/service/tasks/list_app_ids_task.py (+4/-4)
python/libertine/service/tasks/list_task.py (+3/-3)
python/libertine/service/tasks/remove_task.py (+5/-5)
python/libertine/service/tasks/search_task.py (+4/-4)
python/libertine/service/tasks/update_task.py (+7/-7)
tests/integration/CMakeLists.txt (+20/-0)
tests/integration/data/libertine/ContainersConfig.json (+19/-0)
tests/integration/test_libertine_service.py (+12/-12)
tests/integration/test_liblibertine.cpp (+145/-0)
tests/unit/CMakeLists.txt (+2/-1)
tests/unit/ContainerConfigListTests.cpp (+1/-0)
tests/unit/service/CMakeLists.txt (+2/-1)
tests/unit/service/tasks/test_app_info_task.py (+24/-26)
tests/unit/service/tasks/test_container_info_task.py (+26/-27)
tests/unit/service/tasks/test_create_task.py (+159/-176)
tests/unit/service/tasks/test_destroy_task.py (+43/-46)
tests/unit/service/tasks/test_install_task.py (+35/-39)
tests/unit/service/tasks/test_list_app_ids_task.py (+23/-25)
tests/unit/service/tasks/test_list_task.py (+15/-16)
tests/unit/service/tasks/test_remove_task.py (+35/-39)
tests/unit/service/tasks/test_search_task.py (+9/-9)
tests/unit/service/tasks/test_update_task.py (+45/-46)
tests/unit/service/test_container.py (+31/-31)
tests/unit/service/test_operations_monitor.py (+146/-0)
tools/libertined (+21/-5)
To merge this branch: bzr merge lp:~larryprice/libertine/always-progress
Reviewer Review Type Date Requested Status
Christopher Townsend Approve
Libertine CI Bot continuous-integration Approve
Review via email: mp+319255@code.launchpad.net

Commit message

Rearchitect libertine service python backend for simpler access to running tasks.

Description of the change

Rearchitect libertine service python backend for simpler access to running tasks.

This came about because of the intermittent jenkins failure we've been seeing. Hopefully this addresses our issues. If nothing else, it's done a nice job of abstracting away the (currently unused) Download interface, separated the container operations methods, and added some much-needed integration tests for liblibertine.

To post a comment you must log in.
412. By Larry Price

update control

413. By Larry Price

update copyright

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:412
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/446/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/829
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/683
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/683
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/683
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/683
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/839
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/831
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/831/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/831
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/831/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/831
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/831/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/831
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/831/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/446/rebuild

review: Approve (continuous-integration)
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:413
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/447/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/830
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/684
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/684
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/684
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/684
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/840
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/832
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/832/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/832
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/832/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/832
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/832/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/832
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/832/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/447/rebuild

review: Approve (continuous-integration)
414. By Larry Price

sort app ids

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:414
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/448/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/831
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/685
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/685
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/685
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/685
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/841
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/833
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/833/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/833
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/833/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/833
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/833/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/833
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/833/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/448/rebuild

review: Approve (continuous-integration)
415. By Larry Price

rm qdebug

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :

PASSED: Continuous integration, rev:415
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/449/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/832
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/686
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/686
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/686
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/686
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/842
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/834
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/834/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/834
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/834/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/834
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/834/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/834
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/834/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/449/rebuild

review: Approve (continuous-integration)
Revision history for this message
Christopher Townsend (townsend) wrote :

lgtm, +1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2017-02-08 19:55:41 +0000
3+++ CMakeLists.txt 2017-03-07 21:54:49 +0000
4@@ -30,6 +30,12 @@
5 pkg_check_modules(PYTHON3 REQUIRED python3)
6 include_directories(${PYTHON3_INCLUDE_DIRS})
7
8+pkg_check_modules(DBUSTEST REQUIRED dbustest-1>=14.04.0)
9+include_directories(${DBUSTEST_INCLUDE_DIRS})
10+
11+pkg_check_modules(GIO2 REQUIRED gio-2.0 gio-unix-2.0)
12+include_directories(${GIO2_INCLUDE_DIRS})
13+
14 set(CMAKE_AUTOMOC ON)
15
16 set(LIBERTINE_COMMON libertine-common)
17
18=== modified file 'debian/control'
19--- debian/control 2017-03-06 15:14:55 +0000
20+++ debian/control 2017-03-07 21:54:49 +0000
21@@ -9,6 +9,7 @@
22 gobject-introspection,
23 intltool,
24 libcontent-hub-dev (>= 0.2),
25+ libdbustest1-dev (>= 14.04.0),
26 libgirepository1.0-dev,
27 libglib2.0-dev,
28 libgtest-dev,
29
30=== modified file 'liblibertine/libertined.cpp'
31--- liblibertine/libertined.cpp 2017-02-23 21:08:28 +0000
32+++ liblibertine/libertined.cpp 2017-03-07 21:54:49 +0000
33@@ -25,12 +25,16 @@
34 #include <QJsonArray>
35 #include <QJsonObject>
36
37+
38 namespace
39 {
40-constexpr auto SERVICE_INTERFACE = "com.canonical.libertine.Service";
41-constexpr auto PROGRESS_INTERFACE = "com.canonical.libertine.Service.Progress";
42-constexpr auto SESSION_DBUS_ENV_VAR = "DBUS_SESSION_BUS_ADDRESS";
43-constexpr auto SERVICE_NAME = "libertined";
44+constexpr auto SERVICE_INTERFACE = "com.canonical.libertine.Service";
45+constexpr auto OPERATIONS_INTERFACE = "com.canonical.libertine.Service.Operations";
46+constexpr auto OPERATIONS_OBJECT = "/com/canonical/libertine/Service/Operations";
47+constexpr auto OPERATIONS_MONITOR_INTERFACE = "com.canonical.libertine.Service.OperationsMonitor";
48+constexpr auto OPERATIONS_MONITOR_OBJECT = "/com/canonical/libertine/Service/OperationsMonitor";
49+constexpr auto SESSION_DBUS_ENV_VAR = "DBUS_SESSION_BUS_ADDRESS";
50+constexpr auto SERVICE_NAME = "libertined";
51
52
53 class SessionBus
54@@ -69,7 +73,7 @@
55 static bool
56 isRunning(QDBusConnection const& bus, QString const& path)
57 {
58- auto args = dbusCall(bus, PROGRESS_INTERFACE, path, "running", QVariantList());
59+ auto args = dbusCall(bus, OPERATIONS_MONITOR_INTERFACE, OPERATIONS_MONITOR_OBJECT, "running", QVariantList{path});
60
61 if (args.isEmpty())
62 {
63@@ -83,12 +87,12 @@
64 static QString
65 result(QDBusConnection const& bus, QString const& path)
66 {
67- auto args = dbusCall(bus, PROGRESS_INTERFACE, path, "result");
68+ auto args = dbusCall(bus, OPERATIONS_MONITOR_INTERFACE, OPERATIONS_MONITOR_OBJECT, "result", QVariantList{path});
69
70 if (args.isEmpty())
71 {
72 qWarning() << "lastError - no arguments?";
73- return "";
74+ return QString();
75 }
76
77 return args.first().toString();
78@@ -97,12 +101,12 @@
79 static QString
80 lastError(QDBusConnection const& bus, QString const& path)
81 {
82- auto args = dbusCall(bus, PROGRESS_INTERFACE, path, "last_error");
83+ auto args = dbusCall(bus, OPERATIONS_MONITOR_INTERFACE, OPERATIONS_MONITOR_OBJECT, "last_error", QVariantList{path});
84
85 if (args.isEmpty())
86 {
87 qWarning() << "lastError - no arguments?";
88- return "";
89+ return QString();
90 }
91
92 return args.first().toString();
93@@ -111,7 +115,7 @@
94 static QString
95 call(QDBusConnection const& bus, QString const& method, QVariantList const& args)
96 {
97- auto results = dbusCall(bus, SERVICE_INTERFACE, "/Manager", method, args);
98+ auto results = dbusCall(bus, OPERATIONS_INTERFACE, OPERATIONS_OBJECT, method, args);
99
100 if (results.isEmpty())
101 {
102@@ -158,6 +162,7 @@
103 }
104 }
105
106+
107 QJsonArray
108 libertined_list()
109 {
110
111=== modified file 'python/libertine/Client.py'
112--- python/libertine/Client.py 2017-02-24 14:56:36 +0000
113+++ python/libertine/Client.py 2017-03-07 21:54:49 +0000
114@@ -24,14 +24,15 @@
115 self._get_manager()
116
117 def _get_manager(self):
118- self._manager = None
119+ self._control = None
120
121 try:
122- from .service.manager import LIBERTINE_MANAGER_NAME, LIBERTINE_MANAGER_OBJECT
123+ from .service import constants
124+
125 if utils.set_session_dbus_env_var():
126 bus = dbus.SessionBus()
127- self._manager = bus.get_object(LIBERTINE_MANAGER_NAME, LIBERTINE_MANAGER_OBJECT)
128- self._interface = LIBERTINE_MANAGER_NAME
129+ self._control = bus.get_object(constants.SERVICE_NAME, constants.CONTAINER_CONTROL_OBJECT)
130+ self._interface = constants.CONTAINER_CONTROL_INTERFACE
131 except ImportError as e:
132 utils.get_logger().warning("Libertine service libraries not installed.")
133 except dbus.exceptions.DBusException as e:
134@@ -51,11 +52,11 @@
135
136 @property
137 def valid(self):
138- return self._manager is not None
139+ return self._control is not None
140
141 def container_operation_start(self, id):
142 retries = 0
143- while not self._do_operation(lambda: self._manager.get_dbus_method('container_operation_start', self._interface)(id)):
144+ while not self._do_operation(lambda: self._control.get_dbus_method('start', self._interface)(id)):
145 retries += 1
146 if retries > 5:
147 return False
148@@ -64,7 +65,7 @@
149 return True
150
151 def container_operation_finished(self, id, app_name, pid):
152- return self._do_operation(lambda: self._manager.get_dbus_method("container_operation_finished", self._interface)(id, app_name, pid))
153+ return self._do_operation(lambda: self._control.get_dbus_method('finished', self._interface)(id, app_name, pid))
154
155 def container_stopped(self, id):
156- return self._do_operation(lambda: self._manager.get_dbus_method('container_stopped', self._interface)(id))
157+ return self._do_operation(lambda: self._control.get_dbus_method('stopped', self._interface)(id))
158
159=== modified file 'python/libertine/Libertine.py'
160--- python/libertine/Libertine.py 2017-03-03 15:34:16 +0000
161+++ python/libertine/Libertine.py 2017-03-07 21:54:49 +0000
162@@ -547,7 +547,7 @@
163 for root, dirs, files in os.walk(apps_dir):
164 app_ids.extend(["{}_{}_0.0".format(self.container_id, f[:-8]) for f in files if f.endswith(".desktop")])
165
166- return app_ids
167+ return sorted(app_ids)
168
169 def exec_command(self, exec_line):
170 """
171
172=== added file 'python/libertine/service/constants.py'
173--- python/libertine/service/constants.py 1970-01-01 00:00:00 +0000
174+++ python/libertine/service/constants.py 2017-03-07 21:54:49 +0000
175@@ -0,0 +1,27 @@
176+# Copyright 2017 Canonical Ltd.
177+#
178+# This program is free software: you can redistribute it and/or modify
179+# it under the terms of the GNU General Public License as published by
180+# the Free Software Foundation; version 3 of the License.
181+#
182+# This program is distributed in the hope that it will be useful,
183+# but WITHOUT ANY WARRANTY; without even the implied warranty of
184+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
185+# GNU General Public License for more details.
186+#
187+# You should have received a copy of the GNU General Public License
188+# along with this program. If not, see <http://www.gnu.org/licenses/>.
189+
190+SERVICE_NAME = "com.canonical.libertine.Service"
191+
192+OPERATIONS_INTERFACE = "com.canonical.libertine.Service.Operations"
193+OPERATIONS_OBJECT = "/com/canonical/libertine/Service/Operations"
194+
195+DOWNLOAD_INTERFACE = "com.canonical.applications.Service.Download"
196+DOWNLOAD_OBJECT = "/com/canonical/libertine/Service/Download/%s"
197+
198+OPERATIONS_MONITOR_INTERFACE = "com.canonical.libertine.Service.OperationsMonitor"
199+OPERATIONS_MONITOR_OBJECT = "/com/canonical/libertine/Service/OperationsMonitor"
200+
201+CONTAINER_CONTROL_INTERFACE = "com.canonical.libertine.Service.ContainerControl"
202+CONTAINER_CONTROL_OBJECT = "/com/canonical/libertine/Service/ContainerControl"
203
204=== modified file 'python/libertine/service/container.py'
205--- python/libertine/service/container.py 2017-02-07 12:35:48 +0000
206+++ python/libertine/service/container.py 2017-03-07 21:54:49 +0000
207@@ -22,9 +22,9 @@
208
209
210 class Container(object):
211- def __init__(self, container_id, config, connection, callback):
212+ def __init__(self, container_id, config, monitor, callback):
213 self._id = container_id
214- self._connection = connection
215+ self._monitor = monitor
216 self._callback = callback
217 self._config = config
218 self._lock = Lock()
219@@ -59,7 +59,7 @@
220 if utils.is_snap_environment():
221 raise Exception("This operation is not currently supported within the snap")
222
223- task = SearchTask(self.id, self._cache, query, self._connection, self._cleanup_task)
224+ task = SearchTask(self.id, self._cache, query, self._monitor, self._cleanup_task)
225 self._tasks.append(task)
226 task.start()
227
228@@ -72,7 +72,7 @@
229 raise Exception("This operation is not currently supported within the snap")
230
231 related_task_ids = [t.id for t in self._tasks if t.package == package_name and t.running]
232- task = AppInfoTask(self.id, self._cache, package_name, related_task_ids, self._config, self._connection, self._cleanup_task)
233+ task = AppInfoTask(self.id, self._cache, package_name, related_task_ids, self._config, self._monitor, self._cleanup_task)
234
235 self._tasks.append(task)
236 task.start()
237@@ -86,7 +86,7 @@
238 utils.get_logger().debug("Install already in progress for '%s':'%s'" % (package_name, self.id))
239 return tasks[0].id
240
241- task = InstallTask(package_name, self.id, self._config, self._lock, self._connection, self._cleanup_task)
242+ task = InstallTask(package_name, self.id, self._config, self._lock, self._monitor, self._cleanup_task)
243 self._tasks.append(task)
244 task.start()
245 return task.id
246@@ -99,7 +99,7 @@
247 utils.get_logger().debug("Remove already in progress for '%s':'%s'" % (package_name, self.id))
248 return tasks[0].id
249
250- task = RemoveTask(package_name, self.id, self._config, self._lock, self._connection, self._cleanup_task)
251+ task = RemoveTask(package_name, self.id, self._config, self._lock, self._monitor, self._cleanup_task)
252 self._tasks.append(task)
253 task.start()
254 return task.id
255@@ -113,7 +113,7 @@
256 return tasks[0].id
257
258 task = CreateTask(self.id, container_name, distro, container_type, enable_multiarch,
259- self._config, self._lock, self._connection, self._cleanup_task)
260+ self._config, self._lock, self._monitor, self._cleanup_task)
261 self._tasks.append(task)
262 task.start()
263 return task.id
264@@ -126,7 +126,7 @@
265 utils.get_logger().debug("Destroy already in progress for '%s'" % self.id)
266 return tasks[0].id
267
268- task = DestroyTask(self.id, self._config, self._lock, self._connection, self._cleanup_task)
269+ task = DestroyTask(self.id, self._config, self._lock, self._monitor, self._cleanup_task)
270 self._tasks.append(task)
271 task.start()
272 return task.id
273@@ -139,7 +139,7 @@
274 utils.get_logger().debug("Update already in progress for '%s'" % self.id)
275 return tasks[0].id
276
277- task = UpdateTask(self.id, self._config, self._lock, self._connection, self._cleanup_task)
278+ task = UpdateTask(self.id, self._config, self._lock, self._monitor, self._cleanup_task)
279 self._tasks.append(task)
280 task.start()
281 return task.id
282@@ -147,7 +147,7 @@
283 def list_app_ids(self):
284 utils.get_logger().debug("List all app ids in container '%s'" % self.id)
285
286- task = ListAppIdsTask(self.id, self._config, self._connection, self._cleanup_task)
287+ task = ListAppIdsTask(self.id, self._config, self._monitor, self._cleanup_task)
288
289 self._tasks.append(task)
290 task.start()
291
292=== renamed file 'python/libertine/service/operations_state.py' => 'python/libertine/service/container_control.py'
293--- python/libertine/service/operations_state.py 2017-02-23 15:25:17 +0000
294+++ python/libertine/service/container_control.py 2017-03-07 21:54:49 +0000
295@@ -12,17 +12,22 @@
296 # You should have received a copy of the GNU General Public License
297 # along with this program. If not, see <http://www.gnu.org/licenses/>.
298
299+
300+import dbus
301 import libertine.ContainersConfig
302 import psutil
303
304+from . import constants
305 from collections import Counter
306 from libertine import utils
307
308
309-class OperationsState(object):
310- def __init__(self):
311+class ContainerControl(dbus.service.Object):
312+ def __init__(self, connection):
313 self._get_running_apps_per_container()
314
315+ dbus.service.Object.__init__(self, conn=connection, object_path=constants.CONTAINER_CONTROL_OBJECT)
316+
317 def _get_running_apps_per_container(self):
318 self._invalid_apps = dict()
319 self._operations = Counter()
320@@ -47,7 +52,12 @@
321 config.delete_running_app(container, app)
322 continue
323
324- def operation_start(self, container):
325+
326+ @dbus.service.method(constants.CONTAINER_CONTROL_INTERFACE,
327+ in_signature='s',
328+ out_signature='b')
329+ def start(self, container):
330+ utils.get_logger().debug("start({})".format(container))
331 if self._operations[container] == -1:
332 return False
333
334@@ -55,7 +65,13 @@
335
336 return True
337
338- def operation_finished(self, container, app_name, pid):
339+
340+ @dbus.service.method(constants.CONTAINER_CONTROL_INTERFACE,
341+ in_signature='ssi',
342+ out_signature='b')
343+ def finished(self, container, app_name, pid):
344+ utils.get_logger().debug("finished({})".format(container))
345+
346 if container in self._invalid_apps and {app_name, pid} in self._invalid_apps[container]:
347 self._invalid_apps[container].remove({app_name, pid})
348 if not self._invalid_apps[container]:
349@@ -69,7 +85,11 @@
350
351 return False
352
353- def operation_stopped(self, container):
354+ @dbus.service.method(constants.CONTAINER_CONTROL_INTERFACE,
355+ in_signature='s',
356+ out_signature='b')
357+ def stopped(self, container):
358+ utils.get_logger().debug("stopped({})".format(container))
359+
360 del self._operations[container]
361-
362 return True
363
364=== renamed file 'python/libertine/service/progress.py' => 'python/libertine/service/download.py'
365--- python/libertine/service/progress.py 2017-01-24 18:00:57 +0000
366+++ python/libertine/service/download.py 2017-03-07 21:54:49 +0000
367@@ -1,4 +1,4 @@
368-# Copyright 2016-2017 Canonical Ltd.
369+# Copyright 2017 Canonical Ltd.
370 #
371 # This program is free software: you can redistribute it and/or modify
372 # it under the terms of the GNU General Public License as published by
373@@ -12,73 +12,68 @@
374 # You should have received a copy of the GNU General Public License
375 # along with this program. If not, see <http://www.gnu.org/licenses/>.
376
377+
378 import dbus.service
379 import threading
380+
381+from . import constants
382 from libertine import utils
383 from time import time
384
385-DOWNLOAD_INTERFACE = "com.canonical.applications.Download"
386-PROGRESS_INTERFACE = "com.canonical.libertine.Service.Progress"
387
388-class Progress(dbus.service.Object):
389- def __init__(self, connection):
390- utils.get_logger().debug("creating a Progress object")
391+class Download(dbus.service.Object):
392+ def __init__(self, connection, id):
393 self._finished = False
394- self._result = []
395+ self._result = ''
396 self._error = ''
397- dbus.service.Object.__init__(self, conn=connection, object_path=("/Progress/%s" % hex(int(time()*10000000))[2:]))
398-
399- # self.emit_processing() # Disabled until something requires the Download interface
400-
401- @property
402- def id(self):
403- return self._object_path
404-
405+ dbus.service.Object.__init__(self, conn=connection, object_path=(constants.DOWNLOAD_OBJECT % id))
406+
407+ # Disabled until something requires the Download interface
408+ # self.emit_processing()
409+
410+ # This is currently how services using the Ubuntu SDK to show progress
411+ # determine whether or not an operation is running.
412 def emit_processing(self):
413 if not self.done:
414 self.processing(self.id)
415 threading.Timer(0.5, self.emit_processing).start()
416
417 @property
418+ def id(self):
419+ return self._object_path
420+
421+ @property
422 def done(self):
423 return self._finished
424
425- @dbus.service.signal(DOWNLOAD_INTERFACE)
426+ @property
427+ def result(self):
428+ return self._result.strip()
429+
430+ @property
431+ def last_error(self):
432+ return self._error
433+
434+ def data(self, message):
435+ self._result += message + '\n'
436+
437+ # Signals to satisfy the download interface
438+
439+ @dbus.service.signal(constants.DOWNLOAD_INTERFACE, signature='o')
440 def processing(self, path):
441 utils.get_logger().debug("emit processing('%s')" % path)
442
443- @dbus.service.signal(DOWNLOAD_INTERFACE)
444+ @dbus.service.signal(constants.DOWNLOAD_INTERFACE, signature='o')
445 def finished(self, path):
446 utils.get_logger().debug("emit finished('%s')" % path)
447 self._finished = True
448
449- @dbus.service.signal(DOWNLOAD_INTERFACE)
450+ @dbus.service.signal(constants.DOWNLOAD_INTERFACE)
451 def progress(self, received, total):
452 utils.get_logger().debug("emit progress(%d, %d)" % (received, total))
453
454- @dbus.service.signal(DOWNLOAD_INTERFACE)
455+ @dbus.service.signal(constants.DOWNLOAD_INTERFACE, signature='s')
456 def error(self, message):
457 utils.get_logger().error("emit error(%s)" % message)
458 self._error = message
459 self._finished = True
460-
461- @dbus.service.signal(PROGRESS_INTERFACE)
462- def data(self, message):
463- utils.get_logger().debug("emit data(%s)" % message)
464- self._result.append(message)
465-
466- @dbus.service.method(PROGRESS_INTERFACE, out_signature='b')
467- def running(self):
468- utils.get_logger().debug(not self.done)
469- return not self.done
470-
471- @dbus.service.method(PROGRESS_INTERFACE, out_signature='s')
472- def result(self):
473- full_result = "\n".join(self._result)
474- utils.get_logger().debug(full_result)
475- return full_result
476-
477- @dbus.service.method(PROGRESS_INTERFACE, out_signature='s')
478- def last_error(self):
479- utils.get_logger().debug(self._error)
480- return self._error
481
482=== renamed file 'python/libertine/service/manager.py' => 'python/libertine/service/operations.py'
483--- python/libertine/service/manager.py 2017-02-21 18:20:21 +0000
484+++ python/libertine/service/operations.py 2017-03-07 21:54:49 +0000
485@@ -12,69 +12,51 @@
486 # You should have received a copy of the GNU General Public License
487 # along with this program. If not, see <http://www.gnu.org/licenses/>.
488
489+
490 import dbus
491 import dbus.service
492-import libertine.service.task_dispatcher
493-import libertine.service.operations_state
494-from dbus.mainloop.glib import DBusGMainLoop
495-from libertine.service import container
496+
497+from . import constants, operations_monitor, task_dispatcher
498 from libertine import utils
499
500
501-LIBERTINE_MANAGER_NAME = "com.canonical.libertine.Service"
502-LIBERTINE_MANAGER_INTERFACE = LIBERTINE_MANAGER_NAME
503-LIBERTINE_MANAGER_OBJECT = "/Manager"
504-
505-
506-class Manager(dbus.service.Object):
507- def __init__(self):
508- utils.get_logger().debug("creating service")
509- DBusGMainLoop(set_as_default=True)
510- self._operations_state = libertine.service.operations_state.OperationsState()
511-
512- try:
513- bus_name = dbus.service.BusName(LIBERTINE_MANAGER_NAME,
514- bus=dbus.SessionBus(),
515- do_not_queue=True)
516- except dbus.exceptions.NameExistsException:
517- utils.get_logger().warning("service is already running")
518- raise
519-
520- super().__init__(bus_name, LIBERTINE_MANAGER_OBJECT)
521-
522- self._dispatcher = libertine.service.task_dispatcher.TaskDispatcher(self.connection)
523+class Operations(dbus.service.Object):
524+ def __init__(self, bus_name):
525+ super().__init__(bus_name, constants.OPERATIONS_OBJECT)
526+
527+ self._dispatcher = task_dispatcher.TaskDispatcher(operations_monitor.OperationsMonitor(self.connection))
528
529 # Information
530
531- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
532+ @dbus.service.method(constants.OPERATIONS_INTERFACE,
533 in_signature='ss',
534 out_signature='o')
535 def search(self, container_id, search_string):
536 utils.get_logger().debug("search('{}', '{}') called".format(container_id, search_string))
537 return self._dispatcher.search(container_id, search_string)
538
539- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
540+ @dbus.service.method(constants.OPERATIONS_INTERFACE,
541 in_signature='ss',
542 out_signature='o')
543 def app_info(self, container_id, app_id):
544 utils.get_logger().debug("app_info('{}', '{}') called".format(container_id, app_id))
545 return self._dispatcher.app_info(container_id, app_id)
546
547- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
548+ @dbus.service.method(constants.OPERATIONS_INTERFACE,
549 in_signature='s',
550 out_signature='o')
551 def container_info(self, container_id):
552 utils.get_logger().debug("container_info('{}')".format(container_id))
553 return self._dispatcher.container_info(container_id)
554
555- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
556+ @dbus.service.method(constants.OPERATIONS_INTERFACE,
557 in_signature='s',
558 out_signature='o')
559 def list_app_ids(self, container_id):
560 utils.get_logger().debug("list_app_ids('{}')".format(container_id))
561 return self._dispatcher.list_app_ids(container_id)
562
563- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
564+ @dbus.service.method(constants.OPERATIONS_INTERFACE,
565 out_signature='o')
566 def list(self):
567 utils.get_logger().debug("list()")
568@@ -82,63 +64,37 @@
569
570 # Operations
571
572- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
573+ @dbus.service.method(constants.OPERATIONS_INTERFACE,
574 in_signature='ssssb',
575 out_signature='o')
576 def create(self, container_id, container_name='', distro='', container_type='', enable_multiarch=False):
577 utils.get_logger().debug("create('{}', '{}', '{}', '{}', '{}')".format(container_id, container_name, distro, container_type, enable_multiarch))
578 return self._dispatcher.create(container_id, container_name, distro, container_type, enable_multiarch)
579
580- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
581+ @dbus.service.method(constants.OPERATIONS_INTERFACE,
582 in_signature='s',
583 out_signature='o')
584 def destroy(self, container_id):
585 utils.get_logger().debug("destroy('{}')".format(container_id))
586 return self._dispatcher.destroy(container_id)
587
588- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
589+ @dbus.service.method(constants.OPERATIONS_INTERFACE,
590 in_signature='s',
591 out_signature='o')
592 def update(self, container_id):
593 utils.get_logger().debug("update('{}')".format(container_id))
594 return self._dispatcher.update(container_id)
595
596- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
597+ @dbus.service.method(constants.OPERATIONS_INTERFACE,
598 in_signature='ss',
599 out_signature='o')
600 def install(self, container_id, package_name):
601 utils.get_logger().debug("install('%s', '%s')" % (container_id, package_name))
602 return self._dispatcher.install(container_id, package_name)
603
604- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
605+ @dbus.service.method(constants.OPERATIONS_INTERFACE,
606 in_signature='ss',
607 out_signature='o')
608 def remove(self, container_id, package_name):
609 utils.get_logger().debug("remove('%s', '%s')" % (container_id, package_name))
610 return self._dispatcher.remove(container_id, package_name)
611-
612- # Container Lifecycle
613-
614- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
615- in_signature='s',
616- out_signature='b')
617- def container_operation_start(self, container):
618- utils.get_logger().debug("container_operation_start({})".format(container))
619-
620- return self._operations_state.operation_start(container)
621-
622- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
623- in_signature='ssi',
624- out_signature='b')
625- def container_operation_finished(self, container, app_name='', pid=0):
626- utils.get_logger().debug("container_operation_finished({})".format(container))
627-
628- return self._operations_state.operation_finished(container, app_name, pid)
629-
630- @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
631- in_signature='s',
632- out_signature='b')
633- def container_stopped(self, container):
634- utils.get_logger().debug("container_stopped({})".format(container))
635-
636- return self._operations_state.operation_stopped(container)
637
638=== added file 'python/libertine/service/operations_monitor.py'
639--- python/libertine/service/operations_monitor.py 1970-01-01 00:00:00 +0000
640+++ python/libertine/service/operations_monitor.py 2017-03-07 21:54:49 +0000
641@@ -0,0 +1,92 @@
642+# Copyright 2017 Canonical Ltd.
643+#
644+# This program is free software: you can redistribute it and/or modify
645+# it under the terms of the GNU General Public License as published by
646+# the Free Software Foundation; version 3 of the License.
647+#
648+# This program is distributed in the hope that it will be useful,
649+# but WITHOUT ANY WARRANTY; without even the implied warranty of
650+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
651+# GNU General Public License for more details.
652+#
653+# You should have received a copy of the GNU General Public License
654+# along with this program. If not, see <http://www.gnu.org/licenses/>.
655+
656+
657+import dbus.service
658+import threading
659+
660+from . import constants, download
661+from libertine import utils
662+from time import time
663+
664+
665+class OperationsMonitor(dbus.service.Object):
666+ def __init__(self, connection):
667+ self._operations = []
668+ dbus.service.Object.__init__(self, conn=connection, object_path=constants.OPERATIONS_MONITOR_OBJECT)
669+
670+ def new_operation(self):
671+ self._operations.append(download.Download(self.connection, hex(int(time()*10000000))[2:]))
672+ return self._operations[-1].id
673+
674+ def remove_from_connection(self, path):
675+ operation = self._operation(path)
676+ self._operations.remove(operation)
677+ operation.remove_from_connection()
678+
679+ def done(self, path):
680+ op = self._operation(path)
681+ if op:
682+ return op.done
683+ else:
684+ return False
685+
686+ def _operation(self, path):
687+ operations = [op for op in self._operations if op.id == path]
688+ if not operations:
689+ return None
690+
691+ return operations[0]
692+
693+ @dbus.service.signal(constants.OPERATIONS_MONITOR_INTERFACE, signature='o')
694+ def finished(self, path):
695+ op = self._operation(path)
696+ if op:
697+ op.finished(path)
698+
699+ @dbus.service.signal(constants.OPERATIONS_MONITOR_INTERFACE, signature='os')
700+ def error(self, path, message):
701+ op = self._operation(path)
702+ if op:
703+ op.error(message)
704+
705+ @dbus.service.signal(constants.OPERATIONS_MONITOR_INTERFACE, signature='os')
706+ def data(self, path, message):
707+ op = self._operation(path)
708+ if op:
709+ op.data(message)
710+
711+ @dbus.service.method(constants.OPERATIONS_MONITOR_INTERFACE, in_signature='o', out_signature='b')
712+ def running(self, path):
713+ op = self._operation(path)
714+ if op:
715+ return not op.done
716+ else:
717+ return False
718+
719+ @dbus.service.method(constants.OPERATIONS_MONITOR_INTERFACE, in_signature='o', out_signature='s')
720+ def result(self, path):
721+ op = self._operation(path)
722+ if op:
723+ return op.result
724+ else:
725+ return ''
726+
727+ @dbus.service.method(constants.OPERATIONS_MONITOR_INTERFACE, in_signature='o', out_signature='s')
728+ def last_error(self, path):
729+ op = self._operation(path)
730+ if op:
731+ return op.last_error
732+ else:
733+ return ''
734
735=== modified file 'python/libertine/service/task_dispatcher.py'
736--- python/libertine/service/task_dispatcher.py 2017-02-23 20:47:39 +0000
737+++ python/libertine/service/task_dispatcher.py 2017-03-07 21:54:49 +0000
738@@ -30,8 +30,8 @@
739
740
741 class TaskDispatcher(object):
742- def __init__(self, connection):
743- self._connection = connection
744+ def __init__(self, monitor):
745+ self._monitor = monitor
746 self._config = libertine.ContainersConfig.ContainersConfig()
747 self._containerless_tasks = []
748 self._tasks = []
749@@ -49,11 +49,13 @@
750
751 def _find_or_create_container(self, container_id):
752 utils.get_logger().debug("finding or creating container '%s'" % container_id)
753+
754 container = self._find_container(container_id)
755 if container is not None:
756 utils.get_logger().debug("using existing container '%s'" % container_id)
757 return container
758- container = Container(container_id, self._config, self._connection, self._cleanup_container)
759+
760+ container = Container(container_id, self._config, self._monitor, self._cleanup_container)
761 self._containers.append(container)
762
763 return container
764@@ -115,7 +117,7 @@
765 container = self._find_container(container_id)
766 if container is not None:
767 related_task_ids = container.tasks
768- task = ContainerInfoTask(container_id, related_task_ids, self._config, self._connection, self._cleanup_task)
769+ task = ContainerInfoTask(container_id, related_task_ids, self._config, self._monitor, self._cleanup_task)
770 self._tasks.append(task)
771 task.start()
772
773@@ -125,7 +127,7 @@
774 def list(self):
775 utils.get_logger().debug("dispatching list all containers")
776
777- task = ListTask(self._config, self._connection, self._cleanup_task)
778+ task = ListTask(self._config, self._monitor, self._cleanup_task)
779 self._tasks.append(task)
780 task.start()
781
782
783=== modified file 'python/libertine/service/tasks/app_info_task.py'
784--- python/libertine/service/tasks/app_info_task.py 2016-11-01 17:38:38 +0000
785+++ python/libertine/service/tasks/app_info_task.py 2017-03-07 21:54:49 +0000
786@@ -1,4 +1,4 @@
787-# Copyright 2016 Canonical Ltd.
788+# Copyright 2016-2017 Canonical Ltd.
789 #
790 # This program is free software: you can redistribute it and/or modify
791 # it under the terms of the GNU General Public License as published by
792@@ -18,8 +18,8 @@
793
794
795 class AppInfoTask(BaseTask):
796- def __init__(self, container_id, cache, app_id, tasks, config, connection, callback):
797- super().__init__(lock=None, container_id=container_id, config=config, connection=connection, callback=callback)
798+ def __init__(self, container_id, cache, app_id, tasks, config, monitor, callback):
799+ super().__init__(lock=None, container_id=container_id, config=config, monitor=monitor, callback=callback)
800 self._cache = cache
801 self._app_id = app_id
802 self._tasks = tasks
803@@ -27,9 +27,9 @@
804 def _run(self):
805 app = self._cache.app_info(self._app_id)
806 if app == {}:
807- self._progress.error("Could not find app info for '%s' in container '%s'" % (self._app_id, self._container))
808+ self._error("Could not find app info for '%s' in container '%s'" % (self._app_id, self._container))
809 return
810
811 app['status'] = self._config.get_package_install_status(self._container, app['package']) or ''
812 app['task_ids'] = self._tasks
813- self._progress.data(str(app))
814+ self._data(str(app))
815
816=== modified file 'python/libertine/service/tasks/base_task.py'
817--- python/libertine/service/tasks/base_task.py 2017-02-17 17:39:13 +0000
818+++ python/libertine/service/tasks/base_task.py 2017-03-07 21:54:49 +0000
819@@ -12,8 +12,9 @@
820 # You should have received a copy of the GNU General Public License
821 # along with this program. If not, see <http://www.gnu.org/licenses/>.
822
823-import libertine.service.progress
824+
825 import threading
826+
827 from abc import ABCMeta, abstractmethod
828
829
830@@ -24,24 +25,21 @@
831 in a separate thread. Override _before to implement pre-execution actions
832 without locking; if _before returns False, _run will not be executed.
833 """
834- def __init__(self, lock, container_id, config, connection, callback):
835+ def __init__(self, lock, container_id, config, monitor, callback):
836 self._lock = lock
837 self._container = container_id
838 self._config = config
839 self._callback = callback
840- self._connection = connection
841- self._progress = None
842- self._instant_callback = False
843+ self._monitor = monitor
844+ self._operation_id = None
845+ self._instant_callback = False # for testing
846
847 def matches(self, container, klass):
848 return self._container == container and self.__class__ == klass
849
850 @property
851 def id(self):
852- if self._progress is not None:
853- return self._progress.id
854- else:
855- return None
856+ return self._operation_id
857
858 @property
859 def container(self):
860@@ -53,23 +51,23 @@
861
862 @property
863 def running(self):
864- return not self._progress.done
865+ return not self._monitor.done(self._operation_id)
866
867 def _delayed_callback(self):
868 if self._instant_callback:
869 self._callback(self)
870 else:
871- threading.Timer(10, lambda: (self._progress.remove_from_connection(), self._callback(self))).start()
872+ threading.Timer(10, lambda: (self._monitor.remove_from_connection(self._operation_id), self._callback(self))).start()
873
874 def start(self):
875- self._progress = libertine.service.progress.Progress(self._connection)
876+ self._operation_id = self._monitor.new_operation()
877 thread = threading.Thread(target=self.run)
878 thread.start()
879 return thread
880
881 def run(self):
882 if not self._before():
883- self._progress.finished(self.container)
884+ self._monitor.finished(self._operation_id)
885 self._delayed_callback()
886 return
887
888@@ -80,7 +78,7 @@
889 self._run()
890
891 if self.running:
892- self._progress.finished(self.container)
893+ self._monitor.finished(self._operation_id)
894
895 self._delayed_callback()
896
897@@ -90,3 +88,9 @@
898
899 def _before(self):
900 return True
901+
902+ def _data(self, message):
903+ self._monitor.data(self._operation_id, message)
904+
905+ def _error(self, message):
906+ self._monitor.error(self._operation_id, message)
907
908=== modified file 'python/libertine/service/tasks/container_info_task.py'
909--- python/libertine/service/tasks/container_info_task.py 2017-01-18 20:08:47 +0000
910+++ python/libertine/service/tasks/container_info_task.py 2017-03-07 21:54:49 +0000
911@@ -20,8 +20,8 @@
912
913
914 class ContainerInfoTask(BaseTask):
915- def __init__(self, container_id, tasks, config, connection, callback):
916- super().__init__(lock=None, container_id=container_id, config=config, connection=connection, callback=callback)
917+ def __init__(self, container_id, tasks, config, monitor, callback):
918+ super().__init__(lock=None, container_id=container_id, config=config, monitor=monitor, callback=callback)
919 self._tasks = tasks
920
921 def _run(self):
922@@ -35,11 +35,11 @@
923 container['root'] = utils.get_libertine_container_rootfs_path(self._container)
924 container['home'] = utils.get_libertine_container_home_dir(self._container)
925
926- self._progress.data(json.dumps(container))
927+ self._data(json.dumps(container))
928
929 def _before(self):
930 if not self._config.container_exists(self._container):
931- self._progress.error("Container '%s' does not exist, ignoring info request" % self._container)
932+ self._error("Container '%s' does not exist, ignoring info request" % self._container)
933 return False
934
935 return True
936
937=== modified file 'python/libertine/service/tasks/create_task.py'
938--- python/libertine/service/tasks/create_task.py 2017-02-24 15:05:33 +0000
939+++ python/libertine/service/tasks/create_task.py 2017-03-07 21:54:49 +0000
940@@ -1,4 +1,4 @@
941-# Copyright 2016 Canonical Ltd.
942+# Copyright 2016-2017 Canonical Ltd.
943 #
944 # This program is free software: you can redistribute it and/or modify
945 # it under the terms of the GNU General Public License as published by
946@@ -19,8 +19,8 @@
947
948
949 class CreateTask(BaseTask):
950- def __init__(self, container_id, container_name, distro, container_type, enable_multiarch, config, lock, connection, callback):
951- super().__init__(lock=lock, container_id=container_id, config=config, connection=connection, callback=callback)
952+ def __init__(self, container_id, container_name, distro, container_type, enable_multiarch, config, lock, monitor, callback):
953+ super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, callback=callback)
954 self._name = container_name
955 self._distro = distro
956 self._type = container_type
957@@ -34,31 +34,31 @@
958
959 if not container.create_libertine_container(password='', multiarch=self._multiarch):
960 self._config.delete_container(self._container)
961- self._progress.error("Creating container '%s' failed" % self._container)
962+ self._error("Creating container '%s' failed" % self._container)
963 else:
964 self._config.update_container_install_status(self._container, "ready")
965 except RuntimeError as e:
966- self._progress.error(str(e))
967+ self._error(str(e))
968 self._config.delete_container(self._container)
969
970 def _before(self):
971 utils.get_logger().debug("CreateTask::_before")
972 if self._config.container_exists(self._container):
973- self._progress.error("Container '%s' already exists" % self._container)
974+ self._error("Container '%s' already exists" % self._container)
975 return False
976
977 info = HostInfo()
978 if not self._distro:
979 self._distro = info.get_host_distro_release()
980 elif not info.is_distro_valid(self._distro):
981- self._progress.error("Invalid distro '%s'." % self._distro)
982+ self._error("Invalid distro '%s'." % self._distro)
983 return False
984
985 if not self._type:
986 self._type = info.select_container_type_by_kernel()
987 elif (self._type == 'lxd' and not info.has_lxd_support()) or \
988 (self._type == 'lxc' and not info.has_lxc_support()):
989- self._progress.error("System kernel does not support %s type containers. "
990+ self._error("System kernel does not support %s type containers. "
991 "Please either use chroot or leave empty." % self._type)
992 return False
993
994
995=== modified file 'python/libertine/service/tasks/destroy_task.py'
996--- python/libertine/service/tasks/destroy_task.py 2016-11-01 17:38:38 +0000
997+++ python/libertine/service/tasks/destroy_task.py 2017-03-07 21:54:49 +0000
998@@ -1,4 +1,4 @@
999-# Copyright 2016 Canonical Ltd.
1000+# Copyright 2016-2017 Canonical Ltd.
1001 #
1002 # This program is free software: you can redistribute it and/or modify
1003 # it under the terms of the GNU General Public License as published by
1004@@ -18,15 +18,15 @@
1005
1006
1007 class DestroyTask(BaseTask):
1008- def __init__(self, container_id, config, lock, connection, callback):
1009- super().__init__(lock=lock, container_id=container_id, config=config, connection=connection, callback=callback)
1010+ def __init__(self, container_id, config, lock, monitor, callback):
1011+ super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, callback=callback)
1012
1013 def _run(self):
1014 utils.get_logger().debug("Destroying container '%s'" % self._container)
1015
1016 container = LibertineContainer(self._container, self._config)
1017 if not container.destroy_libertine_container():
1018- self._progress.error("Destroying container '%s' failed" % self._container)
1019+ self._error("Destroying container '%s' failed" % self._container)
1020 self._config.update_container_install_status(self._container, "ready")
1021 return
1022
1023@@ -35,7 +35,7 @@
1024 def _before(self):
1025 utils.get_logger().debug("CreateTask::_before")
1026 if self._config._get_value_by_key(self._container, 'installStatus') != 'ready':
1027- self._progress.error("Container '%s' does not exist" % self._container)
1028+ self._error("Container '%s' does not exist" % self._container)
1029 return False
1030
1031 self._config.update_container_install_status(self._container, 'removing')
1032
1033=== modified file 'python/libertine/service/tasks/install_task.py'
1034--- python/libertine/service/tasks/install_task.py 2016-11-08 15:45:54 +0000
1035+++ python/libertine/service/tasks/install_task.py 2017-03-07 21:54:49 +0000
1036@@ -1,4 +1,4 @@
1037-# Copyright 2016 Canonical Ltd.
1038+# Copyright 2016-2017 Canonical Ltd.
1039 #
1040 # This program is free software: you can redistribute it and/or modify
1041 # it under the terms of the GNU General Public License as published by
1042@@ -18,8 +18,8 @@
1043
1044
1045 class InstallTask(BaseTask):
1046- def __init__(self, package_name, container_id, config, lock, connection, callback):
1047- super().__init__(lock=lock, container_id=container_id, config=config, connection=connection, callback=callback)
1048+ def __init__(self, package_name, container_id, config, lock, monitor, callback):
1049+ super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, callback=callback)
1050 self._package = package_name
1051
1052 def matches(self, package, klass):
1053@@ -36,12 +36,12 @@
1054 self._config.update_package_install_status(self._container, self._package, "installed")
1055 else:
1056 self._config.delete_package(self._container, self._package)
1057- self._progress.error("Package installation failed for '%s'" % self._package)
1058+ self._error("Package installation failed for '%s'" % self._package)
1059
1060 def _before(self):
1061 utils.get_logger().debug("InstallTask::_before")
1062 if self._config.package_exists(self._container, self._package):
1063- self._progress.error("Package '%s' already exists, skipping install" % self._package)
1064+ self._error("Package '%s' already exists, skipping install" % self._package)
1065 return False
1066 else:
1067 self._config.add_new_package(self._container, self._package)
1068
1069=== modified file 'python/libertine/service/tasks/list_app_ids_task.py'
1070--- python/libertine/service/tasks/list_app_ids_task.py 2017-01-20 15:20:13 +0000
1071+++ python/libertine/service/tasks/list_app_ids_task.py 2017-03-07 21:54:49 +0000
1072@@ -20,16 +20,16 @@
1073
1074
1075 class ListAppIdsTask(BaseTask):
1076- def __init__(self, container_id, config, connection, callback):
1077- super().__init__(lock=None, container_id=container_id, config=config, connection=connection, callback=callback)
1078+ def __init__(self, container_id, config, monitor, callback):
1079+ super().__init__(lock=None, container_id=container_id, config=config, monitor=monitor, callback=callback)
1080
1081 def _run(self):
1082 utils.get_logger().debug("Listing app ids from container '%s'" % self._container)
1083- self._progress.data(json.dumps(LibertineContainer(self._container, self._config).list_app_ids()))
1084+ self._data(json.dumps(LibertineContainer(self._container, self._config).list_app_ids()))
1085
1086 def _before(self):
1087 if not self._config.container_exists(self._container):
1088- self._progress.error("Container '%s' does not exist, skipping list" % self._container)
1089+ self._error("Container '%s' does not exist, skipping list" % self._container)
1090 return False
1091
1092 return True
1093
1094=== modified file 'python/libertine/service/tasks/list_task.py'
1095--- python/libertine/service/tasks/list_task.py 2017-01-18 20:08:47 +0000
1096+++ python/libertine/service/tasks/list_task.py 2017-03-07 21:54:49 +0000
1097@@ -20,8 +20,8 @@
1098
1099
1100 class ListTask(BaseTask):
1101- def __init__(self, config, connection, callback):
1102- super().__init__(lock=None, container_id=None, config=config, connection=connection, callback=callback)
1103+ def __init__(self, config, monitor, callback):
1104+ super().__init__(lock=None, container_id=None, config=config, monitor=monitor, callback=callback)
1105
1106 def _run(self):
1107- self._progress.data(json.dumps(self._config.get_containers()))
1108+ self._data(json.dumps(self._config.get_containers()))
1109
1110=== modified file 'python/libertine/service/tasks/remove_task.py'
1111--- python/libertine/service/tasks/remove_task.py 2016-11-08 15:45:54 +0000
1112+++ python/libertine/service/tasks/remove_task.py 2017-03-07 21:54:49 +0000
1113@@ -1,4 +1,4 @@
1114-# Copyright 2016 Canonical Ltd.
1115+# Copyright 2016-2017 Canonical Ltd.
1116 #
1117 # This program is free software: you can redistribute it and/or modify
1118 # it under the terms of the GNU General Public License as published by
1119@@ -18,8 +18,8 @@
1120
1121
1122 class RemoveTask(BaseTask):
1123- def __init__(self, package_name, container_id, config, lock, connection, callback):
1124- super().__init__(lock=lock, container_id=container_id, config=config, connection=connection, callback=callback)
1125+ def __init__(self, package_name, container_id, config, lock, monitor, callback):
1126+ super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, callback=callback)
1127 self._package = package_name
1128
1129 def matches(self, package, klass):
1130@@ -36,7 +36,7 @@
1131 self._config.delete_package(self._container, self._package)
1132 else:
1133 self._config.update_package_install_status(self._container, self._package, 'installed')
1134- self._progress.error("Package removal failed for '%s'" % self._package)
1135+ self._error("Package removal failed for '%s'" % self._package)
1136
1137 def _before(self):
1138 utils.get_logger().debug("RemoveTask::_before")
1139@@ -44,5 +44,5 @@
1140 self._config.update_package_install_status(self._container, self._package, "removing")
1141 return True
1142 else:
1143- self._progress.error("Package '%s' not installed, skipping remove" % self._package)
1144+ self._error("Package '%s' not installed, skipping remove" % self._package)
1145 return False
1146
1147=== modified file 'python/libertine/service/tasks/search_task.py'
1148--- python/libertine/service/tasks/search_task.py 2016-11-01 19:49:32 +0000
1149+++ python/libertine/service/tasks/search_task.py 2017-03-07 21:54:49 +0000
1150@@ -1,4 +1,4 @@
1151-# Copyright 2016 Canonical Ltd.
1152+# Copyright 2016-2017 Canonical Ltd.
1153 #
1154 # This program is free software: you can redistribute it and/or modify
1155 # it under the terms of the GNU General Public License as published by
1156@@ -18,10 +18,10 @@
1157
1158
1159 class SearchTask(BaseTask):
1160- def __init__(self, container_id, cache, query, connection, callback):
1161- super().__init__(lock=None, container_id=container_id, config=None, connection=connection, callback=callback)
1162+ def __init__(self, container_id, cache, query, monitor, callback):
1163+ super().__init__(lock=None, container_id=container_id, config=None, monitor=monitor, callback=callback)
1164 self._cache = cache
1165 self._query = query
1166
1167 def _run(self):
1168- self._progress.data(str(self._cache.search(self._query)))
1169+ self._data(str(self._cache.search(self._query)))
1170
1171=== modified file 'python/libertine/service/tasks/update_task.py'
1172--- python/libertine/service/tasks/update_task.py 2016-11-08 15:37:58 +0000
1173+++ python/libertine/service/tasks/update_task.py 2017-03-07 21:54:49 +0000
1174@@ -1,4 +1,4 @@
1175-# Copyright 2016 Canonical Ltd.
1176+# Copyright 2016-2017 Canonical Ltd.
1177 #
1178 # This program is free software: you can redistribute it and/or modify
1179 # it under the terms of the GNU General Public License as published by
1180@@ -18,22 +18,22 @@
1181
1182
1183 class UpdateTask(BaseTask):
1184- def __init__(self, container_id, config, lock, connection, callback):
1185- super().__init__(lock=lock, container_id=container_id, config=config, connection=connection, callback=callback)
1186+ def __init__(self, container_id, config, lock, monitor, callback):
1187+ super().__init__(lock=lock, container_id=container_id, config=config, monitor=monitor, callback=callback)
1188
1189 def _run(self):
1190 utils.get_logger().debug("Updating container '%s'" % self._container)
1191 container = LibertineContainer(self._container, self._config)
1192 self._config.update_container_install_status(self._container, "updating")
1193 if not container.update_libertine_container():
1194- self._progress.error("Failed to update container '%s'" % self._container)
1195+ self._error("Failed to update container '%s'" % self._container)
1196
1197 self._config.update_container_install_status(self._container, "ready")
1198
1199 def _before(self):
1200 utils.get_logger().debug("UpdateTask::_before")
1201 if not self._config.container_exists(self._container):
1202- self._progress.error("Container '%s' does not exist, skipping update" % self._container)
1203+ self._error("Container '%s' does not exist, skipping update" % self._container)
1204 return False
1205- else:
1206- return True
1207+
1208+ return True
1209
1210=== modified file 'tests/integration/CMakeLists.txt'
1211--- tests/integration/CMakeLists.txt 2017-03-06 15:33:12 +0000
1212+++ tests/integration/CMakeLists.txt 2017-03-07 21:54:49 +0000
1213@@ -2,3 +2,23 @@
1214 set_tests_properties(test_libertine_service
1215 PROPERTIES ENVIRONMENT
1216 "PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_SOURCE_DIR}/python;LIBERTINE_DATA_DIR=${CMAKE_CURRENT_SOURCE_DIR};PATH=${CMAKE_SOURCE_DIR}/tools:$ENV{PATH};")
1217+
1218+add_executable(
1219+ test_liblibertine
1220+ test_liblibertine.cpp
1221+)
1222+
1223+target_link_libraries(
1224+ test_liblibertine
1225+ ${LIBERTINE_CORE}
1226+ gtest gtest_main
1227+ ${DBUSTEST_LIBRARIES}
1228+ ${GIO2_LIBRARIES}
1229+ Qt5::Core
1230+)
1231+
1232+add_test(test_liblibertine test_liblibertine)
1233+
1234+set_tests_properties(test_liblibertine
1235+ PROPERTIES ENVIRONMENT
1236+ "PYTHONPATH=${CMAKE_SOURCE_DIR}/python;PATH=${CMAKE_SOURCE_DIR}/tools:$ENV{PATH};XDG_DATA_HOME=${CMAKE_CURRENT_SOURCE_DIR}/data;XDG_CACHE_HOME=${CMAKE_CURRENT_SOURCE_DIR}/data")
1237
1238=== added directory 'tests/integration/data'
1239=== added directory 'tests/integration/data/libertine'
1240=== added directory 'tests/integration/data/libertine-container'
1241=== added directory 'tests/integration/data/libertine-container/padme'
1242=== added directory 'tests/integration/data/libertine-container/padme/rootfs'
1243=== added directory 'tests/integration/data/libertine-container/padme/rootfs/usr'
1244=== added directory 'tests/integration/data/libertine-container/padme/rootfs/usr/share'
1245=== added directory 'tests/integration/data/libertine-container/padme/rootfs/usr/share/applications'
1246=== added file 'tests/integration/data/libertine-container/padme/rootfs/usr/share/applications/dagobah.desktop'
1247=== added file 'tests/integration/data/libertine-container/padme/rootfs/usr/share/applications/tatooine.desktop'
1248=== added directory 'tests/integration/data/libertine-container/user-data'
1249=== added directory 'tests/integration/data/libertine-container/user-data/padme'
1250=== added file 'tests/integration/data/libertine/ContainersConfig.json'
1251--- tests/integration/data/libertine/ContainersConfig.json 1970-01-01 00:00:00 +0000
1252+++ tests/integration/data/libertine/ContainersConfig.json 2017-03-07 21:54:49 +0000
1253@@ -0,0 +1,19 @@
1254+{
1255+ "containerList": [
1256+ {
1257+ "id": "jarjar",
1258+ "name": "JarJar Binks",
1259+ "type": "mock"
1260+ },
1261+ {
1262+ "id": "padme",
1263+ "name": "Padme Amedala",
1264+ "type": "mock"
1265+ },
1266+ {
1267+ "id": "anakin",
1268+ "name": "Anakin Skywalker",
1269+ "type": "mock"
1270+ }
1271+ ]
1272+}
1273
1274=== modified file 'tests/integration/test_libertine_service.py'
1275--- tests/integration/test_libertine_service.py 2017-03-06 15:33:12 +0000
1276+++ tests/integration/test_libertine_service.py 2017-03-07 21:54:49 +0000
1277@@ -26,7 +26,7 @@
1278
1279 from gi.repository import GLib
1280 from libertine import utils
1281-from libertine.service import tasks, apt
1282+from libertine.service import tasks, apt, constants
1283 from libertine.ContainersConfig import ContainersConfig
1284 from subprocess import Popen, PIPE
1285 from unittest import TestCase
1286@@ -75,7 +75,7 @@
1287 for retries in range(1, 11):
1288 try:
1289 self._bus = dbus.SessionBus()
1290- self._libertined = self._bus.get_object('com.canonical.libertine.Service', '/Manager')
1291+ self._libertined = self._bus.get_object(constants.SERVICE_NAME, constants.OPERATIONS_OBJECT)
1292 break
1293 except dbus.DBusException as e:
1294 print("Service not available (attempt %i/10). Exception: %s" % (retries, str(e)))
1295@@ -101,20 +101,20 @@
1296
1297 obj_path = func()
1298 signals = []
1299- signals.append(self._bus.add_signal_receiver(path=obj_path, handler_function=self._finished_handler,
1300- dbus_interface='com.canonical.applications.Download', signal_name='finished'))
1301- signals.append(self._bus.add_signal_receiver(path=obj_path, handler_function=self._data_handler,
1302- dbus_interface='com.canonical.libertine.Service.Progress', signal_name='data'))
1303- signals.append(self._bus.add_signal_receiver(path=obj_path, handler_function=self._error_handler,
1304- dbus_interface='com.canonical.applications.Download', signal_name='error'))
1305+ signals.append(self._bus.add_signal_receiver(path=constants.OPERATIONS_MONITOR_OBJECT, handler_function=self._finished_handler,
1306+ dbus_interface=constants.OPERATIONS_MONITOR_INTERFACE, signal_name='finished'))
1307+ signals.append(self._bus.add_signal_receiver(path=constants.OPERATIONS_MONITOR_OBJECT, handler_function=self._data_handler,
1308+ dbus_interface=constants.OPERATIONS_MONITOR_INTERFACE, signal_name='data'))
1309+ signals.append(self._bus.add_signal_receiver(path=constants.OPERATIONS_MONITOR_OBJECT, handler_function=self._error_handler,
1310+ dbus_interface=constants.OPERATIONS_MONITOR_INTERFACE, signal_name='error'))
1311
1312- task = self._bus.get_object('com.canonical.libertine.Service', obj_path)
1313- if task.running():
1314+ monitor = self._bus.get_object(constants.SERVICE_NAME, constants.OPERATIONS_MONITOR_OBJECT)
1315+ if monitor.running(obj_path):
1316 self.event.wait(5)
1317 self.assertIsNone(self.error)
1318
1319- self.assertEqual('', task.get_dbus_method('last_error', 'com.canonical.libertine.Service.Progress')())
1320- self.result = task.get_dbus_method('result', 'com.canonical.libertine.Service.Progress')()
1321+ self.assertEqual('', monitor.last_error(obj_path))
1322+ self.result = monitor.result(obj_path)
1323
1324 for signal in signals:
1325 self._bus._clean_up_signal_match(signal)
1326
1327=== added file 'tests/integration/test_liblibertine.cpp'
1328--- tests/integration/test_liblibertine.cpp 1970-01-01 00:00:00 +0000
1329+++ tests/integration/test_liblibertine.cpp 2017-03-07 21:54:49 +0000
1330@@ -0,0 +1,145 @@
1331+/*
1332+ * Copyright 2017 Canonical Ltd.
1333+ *
1334+ * This program is free software: you can redistribute it and/or modify it under
1335+ * the terms of the GNU General Public License, version 3, as published by the
1336+ * Free Software Foundation.
1337+ *
1338+ * This program is distributed in the hope that it will be useful,
1339+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1340+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1341+ * GNU General Public License for more details.
1342+ *
1343+ * You should have received a copy of the GNU General Public License
1344+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1345+ */
1346+
1347+#include "liblibertine/libertine.h"
1348+#include <cstdlib>
1349+#include <gio/gio.h>
1350+#include <gtest/gtest.h>
1351+#include <libdbustest/dbus-test.h>
1352+#include <memory>
1353+#include <QtCore/QByteArray>
1354+#include <QtCore/QJsonDocument>
1355+#include <QtCore/QJsonParseError>
1356+
1357+class LiblibertineTest : public ::testing::Test
1358+{
1359+protected:
1360+ static void SetUpTestCase()
1361+ {
1362+ process = dbus_test_process_new("libertined");
1363+ dbus_test_process_append_param(process, "--debug");
1364+
1365+ dbus_test_task_set_bus(DBUS_TEST_TASK(process), DBUS_TEST_SERVICE_BUS_SESSION);
1366+ dbus_test_task_set_name(DBUS_TEST_TASK(process), "libertine");
1367+ dbus_test_task_set_return(DBUS_TEST_TASK(process), DBUS_TEST_TASK_RETURN_IGNORE);
1368+ dbus_test_task_set_wait_finished(DBUS_TEST_TASK(process), FALSE);
1369+
1370+ wait = dbus_test_task_new();
1371+ dbus_test_task_set_wait_for(wait, "com.canonical.libertine.Service");
1372+
1373+ service = dbus_test_service_new(nullptr);
1374+ dbus_test_service_add_task(service, DBUS_TEST_TASK(process));
1375+ dbus_test_service_add_task(service, wait);
1376+
1377+ dbus_test_service_start_tasks(service);
1378+
1379+ bus = g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, nullptr);
1380+ g_dbus_connection_set_exit_on_close(bus, FALSE);
1381+ g_object_add_weak_pointer(G_OBJECT(bus), (gpointer*)&bus);
1382+ }
1383+
1384+ static void TearDownTestCase()
1385+ {
1386+ g_clear_object(&process);
1387+ g_clear_object(&wait);
1388+
1389+ g_clear_object(&service);
1390+ g_object_unref(bus);
1391+ }
1392+
1393+private:
1394+ static DbusTestProcess* process;
1395+ static DbusTestTask* wait;
1396+ static DbusTestService* service;
1397+ static GDBusConnection* bus;
1398+};
1399+
1400+
1401+DbusTestProcess* LiblibertineTest::process = nullptr;
1402+DbusTestTask* LiblibertineTest::wait = nullptr;
1403+DbusTestService* LiblibertineTest::service = nullptr;
1404+GDBusConnection* LiblibertineTest::bus = nullptr;
1405+
1406+
1407+TEST_F(LiblibertineTest, libertine_list_containers)
1408+{
1409+ auto scontainers = std::shared_ptr<gchar*>(libertine_list_containers(), g_strfreev);
1410+ auto containers = scontainers.get();
1411+
1412+ ASSERT_NE(containers[0], nullptr);
1413+ EXPECT_STREQ(containers[0], "jarjar");
1414+
1415+ ASSERT_NE(containers[1], nullptr);
1416+ EXPECT_STREQ(containers[1], "padme");
1417+
1418+ ASSERT_NE(containers[2], nullptr);
1419+ EXPECT_STREQ(containers[2], "anakin");
1420+
1421+ ASSERT_EQ(containers[3], nullptr);
1422+}
1423+
1424+
1425+TEST_F(LiblibertineTest, libertine_list_app_ids)
1426+{
1427+ auto sapps = std::shared_ptr<gchar*>(libertine_list_apps_for_container("padme"), g_strfreev);
1428+ auto apps = sapps.get();
1429+
1430+ ASSERT_NE(apps[0], nullptr);
1431+ EXPECT_STREQ(apps[0], "padme_dagobah_0.0");
1432+
1433+ ASSERT_NE(apps[1], nullptr);
1434+ EXPECT_STREQ(apps[1], "padme_tatooine_0.0");
1435+
1436+ ASSERT_EQ(apps[2], nullptr);
1437+}
1438+
1439+
1440+TEST_F(LiblibertineTest, libertine_container_name)
1441+{
1442+ auto actual = libertine_container_name("padme");
1443+ EXPECT_STREQ("Padme Amedala", actual);
1444+ g_free(actual);
1445+}
1446+
1447+
1448+TEST_F(LiblibertineTest, libertine_container_path)
1449+{
1450+ auto actual = libertine_container_path("padme");
1451+ auto expected = QString(getenv("XDG_CACHE_HOME")) + "/libertine-container/padme/rootfs";
1452+ EXPECT_STREQ(expected.toUtf8(), actual);
1453+ g_free(actual);
1454+}
1455+
1456+
1457+TEST_F(LiblibertineTest, libertine_container_path_returns_empty)
1458+{
1459+ EXPECT_EQ(nullptr, libertine_container_path("jarjar"));
1460+}
1461+
1462+
1463+TEST_F(LiblibertineTest, libertine_container_home_path)
1464+{
1465+ auto actual = libertine_container_home_path("padme");
1466+ auto expected = QString(getenv("XDG_DATA_HOME")) + "/libertine-container/user-data/padme";
1467+ EXPECT_STREQ(expected.toUtf8(), actual);
1468+ g_free(actual);
1469+}
1470+
1471+
1472+TEST_F(LiblibertineTest, libertine_container_home_path_returns_empty)
1473+{
1474+ EXPECT_EQ(nullptr, libertine_container_home_path("jarjar"));
1475+}
1476
1477=== modified file 'tests/unit/CMakeLists.txt'
1478--- tests/unit/CMakeLists.txt 2017-02-13 21:41:36 +0000
1479+++ tests/unit/CMakeLists.txt 2017-03-07 21:54:49 +0000
1480@@ -8,9 +8,10 @@
1481 ContainerConfigListTests.cpp
1482 ContainersConfigTests.cpp
1483 )
1484+
1485 target_link_libraries(
1486 test_container_config
1487- libertine-common
1488+ ${LIBERTINE_COMMON}
1489 gtest gtest_main
1490 Qt5::Core
1491 )
1492
1493=== modified file 'tests/unit/ContainerConfigListTests.cpp'
1494--- tests/unit/ContainerConfigListTests.cpp 2017-02-08 14:57:34 +0000
1495+++ tests/unit/ContainerConfigListTests.cpp 2017-03-07 21:54:49 +0000
1496@@ -34,6 +34,7 @@
1497 EXPECT_EQ(container_configs.size(), 0);
1498 }
1499
1500+
1501 /** Verify constructing a ContainerConfig from JSON DTRT. */
1502 TEST(LibertineContainerConfigList, constructFromJson)
1503 {
1504
1505=== modified file 'tests/unit/service/CMakeLists.txt'
1506--- tests/unit/service/CMakeLists.txt 2016-11-04 13:49:40 +0000
1507+++ tests/unit/service/CMakeLists.txt 2017-03-07 21:54:49 +0000
1508@@ -1,5 +1,5 @@
1509 function(create_service_unit_test test_name)
1510- add_test(${test_name} /usr/bin/python3 -m testtools.run ${test_name})
1511+ add_test(${test_name} /usr/bin/python3 ${CMAKE_CURRENT_SOURCE_DIR}/${test_name}.py)
1512 set_tests_properties(${test_name}
1513 PROPERTIES ENVIRONMENT
1514 "GI_TYPELIB_PATH=${CMAKE_BINARY_DIR}/liblibertine;LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/liblibertine:${LD_LIBRARY_PATH};PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_SOURCE_DIR}/python;LIBERTINE_DATA_DIR=${CMAKE_CURRENT_SOURCE_DIR}")
1515@@ -8,5 +8,6 @@
1516 create_service_unit_test(test_container)
1517 create_service_unit_test(test_apt)
1518 create_service_unit_test(test_task_dispatcher)
1519+create_service_unit_test(test_operations_monitor)
1520
1521 add_subdirectory(tasks)
1522
1523=== modified file 'tests/unit/service/tasks/test_app_info_task.py'
1524--- tests/unit/service/tasks/test_app_info_task.py 2016-11-07 18:51:17 +0000
1525+++ tests/unit/service/tasks/test_app_info_task.py 2017-03-07 21:54:49 +0000
1526@@ -1,4 +1,4 @@
1527-# Copyright 2016 Canonical Ltd.
1528+# Copyright 2016-2017 Canonical Ltd.
1529 #
1530 # This program is free software: you can redistribute it and/or modify it
1531 # under the terms of the GNU General Public License version 3, as published
1532@@ -15,7 +15,7 @@
1533
1534 import unittest.mock
1535 from unittest import TestCase
1536-from libertine.service import tasks, apt
1537+from libertine.service import tasks, apt, operations_monitor
1538 from libertine.ContainersConfig import ContainersConfig
1539
1540
1541@@ -23,39 +23,37 @@
1542 def setUp(self):
1543 self.config = unittest.mock.create_autospec(ContainersConfig)
1544 self.cache = unittest.mock.create_autospec(apt.AptCache)
1545- self.connection = unittest.mock.Mock()
1546+ self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
1547+ self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
1548
1549 def test_app_not_found_causes_error(self):
1550 self.called_with = None
1551 def callback(t):
1552 self.called_with = t
1553
1554- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
1555- progress = MockProgress.return_value
1556- self.cache.app_info.return_value = {}
1557- task = tasks.AppInfoTask('palpatine', self.cache, 'lightside', [1, 2], self.config, self.connection, callback)
1558- task._instant_callback = True
1559- task.start().join()
1560-
1561- progress.error.assert_called_once_with('Could not find app info for \'lightside\' in container \'palpatine\'')
1562-
1563- self.assertEqual(task, self.called_with)
1564+ self.cache.app_info.return_value = {}
1565+ task = tasks.AppInfoTask('palpatine', self.cache, 'lightside', [1, 2], self.config, self.monitor, callback)
1566+ task._instant_callback = True
1567+ task.start().join()
1568+
1569+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Could not find app info for \'lightside\' in container \'palpatine\'')
1570+
1571+ self.assertEqual(task, self.called_with)
1572
1573 def test_success_sends_data(self):
1574 self.called_with = None
1575 def callback(t):
1576 self.called_with = t
1577
1578- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
1579- progress = MockProgress.return_value
1580- progress.done = False
1581-
1582- self.cache.app_info.return_value = {'package': 'darkside-common'}
1583- self.config.get_package_install_status.return_value = 'installed'
1584- task = tasks.AppInfoTask('palpatine', self.cache, 'darkside', [1, 2, 3], self.config, self.connection, callback)
1585- task._instant_callback = True
1586- task.start().join()
1587-
1588- progress.data.assert_called_once_with(str({'package': 'darkside-common', 'status': 'installed', 'task_ids': [1, 2, 3]}))
1589-
1590- self.assertEqual(task, self.called_with)
1591+ self.monitor.done.return_value = False
1592+
1593+ self.cache.app_info.return_value = {'package': 'darkside-common'}
1594+ self.config.get_package_install_status.return_value = 'installed'
1595+ task = tasks.AppInfoTask('palpatine', self.cache, 'darkside', [1, 2, 3], self.config, self.monitor, callback)
1596+ task._instant_callback = True
1597+ task.start().join()
1598+
1599+ self.monitor.data.assert_called_once_with(self.monitor.new_operation.return_value, str({'package': 'darkside-common', 'status': 'installed', 'task_ids': [1, 2, 3]}))
1600+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
1601+
1602+ self.assertEqual(task, self.called_with)
1603
1604=== modified file 'tests/unit/service/tasks/test_container_info_task.py'
1605--- tests/unit/service/tasks/test_container_info_task.py 2017-01-27 16:42:22 +0000
1606+++ tests/unit/service/tasks/test_container_info_task.py 2017-03-07 21:54:49 +0000
1607@@ -1,4 +1,4 @@
1608-# Copyright 2016 Canonical Ltd.
1609+# Copyright 2016-2017 Canonical Ltd.
1610 #
1611 # This program is free software: you can redistribute it and/or modify it
1612 # under the terms of the GNU General Public License version 3, as published
1613@@ -17,40 +17,39 @@
1614 import unittest.mock
1615 from unittest import TestCase
1616 from libertine import utils
1617-from libertine.service import tasks
1618+from libertine.service import tasks, operations_monitor
1619 from libertine.ContainersConfig import ContainersConfig
1620
1621
1622 class TestContainerInfoTask(TestCase):
1623 def setUp(self):
1624- self.config = unittest.mock.create_autospec(ContainersConfig)
1625- self.connection = unittest.mock.Mock()
1626+ self.config = unittest.mock.create_autospec(ContainersConfig)
1627+ self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
1628+ self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
1629
1630 def test_success_sends_data(self):
1631 self.called_with = None
1632 def callback(t):
1633 self.called_with = t
1634
1635- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
1636- progress = MockProgress.return_value
1637- progress.done = False
1638-
1639- self.config.get_container_install_status.return_value = 'ready'
1640- self.config.get_container_name.return_value = 'Palpatine'
1641- task = tasks.ContainerInfoTask('palpatine', [1, 2, 3], self.config, self.connection, callback)
1642- task._instant_callback = True
1643- task.start().join()
1644-
1645- progress.data.assert_called_once_with(unittest.mock.ANY)
1646- args, kwargs = progress.data.call_args
1647- self.assertEqual({'id': 'palpatine',
1648- 'status': 'ready',
1649- 'task_ids': [1, 2, 3],
1650- 'name': 'Palpatine',
1651- 'root': utils.get_libertine_container_rootfs_path('palpatine'),
1652- 'home': utils.get_libertine_container_home_dir('palpatine')},
1653- ast.literal_eval(args[0]))
1654-
1655- progress.finished.assert_called_once_with('palpatine')
1656-
1657- self.assertEqual(task, self.called_with)
1658+ self.monitor.done.return_value = False
1659+
1660+ self.config.get_container_install_status.return_value = 'ready'
1661+ self.config.get_container_name.return_value = 'Palpatine'
1662+ task = tasks.ContainerInfoTask('palpatine', [1, 2, 3], self.config, self.monitor, callback)
1663+ task._instant_callback = True
1664+ task.start().join()
1665+
1666+ self.monitor.data.assert_called_once_with(self.monitor.new_operation.return_value, unittest.mock.ANY)
1667+ args, kwargs = self.monitor.data.call_args
1668+ self.assertEqual({'id': 'palpatine',
1669+ 'status': 'ready',
1670+ 'task_ids': [1, 2, 3],
1671+ 'name': 'Palpatine',
1672+ 'root': utils.get_libertine_container_rootfs_path('palpatine'),
1673+ 'home': utils.get_libertine_container_home_dir('palpatine')},
1674+ ast.literal_eval(args[1]))
1675+
1676+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
1677+
1678+ self.assertEqual(task, self.called_with)
1679
1680=== modified file 'tests/unit/service/tasks/test_create_task.py'
1681--- tests/unit/service/tasks/test_create_task.py 2016-11-07 18:51:17 +0000
1682+++ tests/unit/service/tasks/test_create_task.py 2017-03-07 21:54:49 +0000
1683@@ -1,4 +1,4 @@
1684-# Copyright 2016 Canonical Ltd.
1685+# Copyright 2016-2017 Canonical Ltd.
1686 #
1687 # This program is free software: you can redistribute it and/or modify it
1688 # under the terms of the GNU General Public License version 3, as published
1689@@ -15,15 +15,17 @@
1690
1691 import unittest.mock
1692 from unittest import TestCase
1693-from libertine.service import tasks
1694+from libertine.service import tasks, operations_monitor
1695 from libertine.ContainersConfig import ContainersConfig
1696
1697
1698 class TestCreateTask(TestCase):
1699 def setUp(self):
1700- self.config = unittest.mock.create_autospec(ContainersConfig)
1701- self.connection = unittest.mock.Mock()
1702- self.lock = unittest.mock.MagicMock()
1703+ self.config = unittest.mock.create_autospec(ContainersConfig)
1704+ self.lock = unittest.mock.MagicMock()
1705+ self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
1706+
1707+ self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
1708 self.called_with = None
1709
1710 def callback(self, task):
1711@@ -31,204 +33,185 @@
1712
1713 def test_success_creates_lxc_container(self):
1714 self.config.container_exists.return_value = False
1715- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
1716- progress = MockProgress.return_value
1717- progress.done = False
1718- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.connection, self.callback)
1719- task._instant_callback = True
1720-
1721- with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1722- MockHostInfo.return_value.is_distro_valid.return_value = True
1723- MockHostInfo.return_value.has_lxc_support.return_value = True
1724-
1725- with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
1726- MockContainer.return_value.create_libertine_container.return_value = True
1727- task.start().join()
1728-
1729- progress.finished.assert_called_once_with('palpatine')
1730- self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'lxc', 'zesty')
1731- self.config.update_container_install_status.assert_has_calls([
1732- unittest.mock.call('palpatine', 'installing'),
1733- unittest.mock.call('palpatine', 'ready')
1734- ], any_order=True)
1735- self.assertEqual(task, self.called_with)
1736+ self.monitor.done.return_value = False
1737+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.monitor, self.callback)
1738+ task._instant_callback = True
1739+
1740+ with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1741+ MockHostInfo.return_value.is_distro_valid.return_value = True
1742+ MockHostInfo.return_value.has_lxc_support.return_value = True
1743+
1744+ with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
1745+ MockContainer.return_value.create_libertine_container.return_value = True
1746+ task.start().join()
1747+
1748+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
1749+ self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'lxc', 'zesty')
1750+ self.config.update_container_install_status.assert_has_calls([
1751+ unittest.mock.call('palpatine', 'installing'),
1752+ unittest.mock.call('palpatine', 'ready')
1753+ ], any_order=True)
1754+ self.assertEqual(task, self.called_with)
1755
1756 def test_success_creates_chroot_container(self):
1757 self.config.container_exists.return_value = False
1758- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
1759- progress = MockProgress.return_value
1760- progress.done = False
1761- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'chroot', False, self.config, self.lock, self.connection, self.callback)
1762- task._instant_callback = True
1763-
1764- with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1765- MockHostInfo.return_value.is_distro_valid.return_value = True
1766-
1767- with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
1768- MockContainer.return_value.create_libertine_container.return_value = True
1769- task.start().join()
1770-
1771- progress.finished.assert_called_once_with('palpatine')
1772- self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'chroot', 'zesty')
1773- self.config.update_container_install_status.assert_has_calls([
1774- unittest.mock.call('palpatine', 'installing'),
1775- unittest.mock.call('palpatine', 'ready')
1776- ], any_order=True)
1777- self.assertEqual(task, self.called_with)
1778+ self.monitor.done.return_value = False
1779+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'chroot', False, self.config, self.lock, self.monitor, self.callback)
1780+ task._instant_callback = True
1781+
1782+ with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1783+ MockHostInfo.return_value.is_distro_valid.return_value = True
1784+
1785+ with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
1786+ MockContainer.return_value.create_libertine_container.return_value = True
1787+ task.start().join()
1788+
1789+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
1790+ self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'chroot', 'zesty')
1791+ self.config.update_container_install_status.assert_has_calls([
1792+ unittest.mock.call('palpatine', 'installing'),
1793+ unittest.mock.call('palpatine', 'ready')
1794+ ], any_order=True)
1795+ self.assertEqual(task, self.called_with)
1796
1797 def test_container_runtime_error_sends_error(self):
1798 self.config.container_exists.return_value = False
1799- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
1800- progress = MockProgress.return_value
1801- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.connection, self.callback)
1802- task._instant_callback = True
1803-
1804- with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1805- MockHostInfo.return_value.is_distro_valid.return_value = True
1806- MockHostInfo.return_value.has_lxc_support.return_value = True
1807-
1808- with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
1809- MockContainer.return_value.create_libertine_container.side_effect = RuntimeError('a great disturbance')
1810- task.start().join()
1811-
1812- progress.error.assert_called_once_with('a great disturbance')
1813-
1814- self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'lxc', 'zesty')
1815- self.config.update_container_install_status.assert_called_once_with('palpatine', 'installing')
1816- self.config.delete_container.assert_called_once_with('palpatine')
1817-
1818- self.assertEqual(task, self.called_with)
1819+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.monitor, self.callback)
1820+ task._instant_callback = True
1821+
1822+ with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1823+ MockHostInfo.return_value.is_distro_valid.return_value = True
1824+ MockHostInfo.return_value.has_lxc_support.return_value = True
1825+
1826+ with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
1827+ MockContainer.return_value.create_libertine_container.side_effect = RuntimeError('a great disturbance')
1828+ task.start().join()
1829+
1830+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'a great disturbance')
1831+
1832+ self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'lxc', 'zesty')
1833+ self.config.update_container_install_status.assert_called_once_with('palpatine', 'installing')
1834+ self.config.delete_container.assert_called_once_with('palpatine')
1835+
1836+ self.assertEqual(task, self.called_with)
1837
1838 def test_failed_container_exists_sends_error(self):
1839 self.config.container_exists.return_value = True
1840- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
1841- progress = MockProgress.return_value
1842- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.connection, self.callback)
1843- task._instant_callback = True
1844- task.start().join()
1845+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.monitor, self.callback)
1846+ task._instant_callback = True
1847+ task.start().join()
1848
1849- progress.error.assert_called_once_with('Container \'palpatine\' already exists')
1850- self.assertEqual(task, self.called_with)
1851+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Container \'palpatine\' already exists')
1852+ self.assertEqual(task, self.called_with)
1853
1854 def test_container_invalid_distro_error_sends_error(self):
1855 self.config.container_exists.return_value = False
1856- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
1857- progress = MockProgress.return_value
1858- with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1859- MockHostInfo.return_value.is_distro_valid.return_value = False
1860- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'vesty', 'lxc', False, self.config, self.lock, self.connection, self.callback)
1861- task._instant_callback = True
1862- task.start().join()
1863+ with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1864+ MockHostInfo.return_value.is_distro_valid.return_value = False
1865+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'vesty', 'lxc', False, self.config, self.lock, self.monitor, self.callback)
1866+ task._instant_callback = True
1867+ task.start().join()
1868
1869- progress.error.assert_called_once_with('Invalid distro \'vesty\'.')
1870- self.assertEqual(task, self.called_with)
1871+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Invalid distro \'vesty\'.')
1872+ self.assertEqual(task, self.called_with)
1873
1874 def test_container_improper_lxc_error_sends_error(self):
1875 self.config.container_exists.return_value = False
1876- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
1877- progress = MockProgress.return_value
1878- with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1879- MockHostInfo.return_value.is_distro_valid.return_value = True
1880- MockHostInfo.return_value.has_lxc_support.return_value = False
1881- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.connection, self.callback)
1882- task._instant_callback = True
1883- task.start().join()
1884+ with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1885+ MockHostInfo.return_value.is_distro_valid.return_value = True
1886+ MockHostInfo.return_value.has_lxc_support.return_value = False
1887+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'lxc', False, self.config, self.lock, self.monitor, self.callback)
1888+ task._instant_callback = True
1889+ task.start().join()
1890
1891- progress.error.assert_called_once_with('System kernel does not support lxc type containers. Please either use chroot or leave empty.')
1892- self.assertEqual(task, self.called_with)
1893+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, \
1894+ 'System kernel does not support lxc type containers. Please either use chroot or leave empty.')
1895+ self.assertEqual(task, self.called_with)
1896
1897 def test_sets_generic_name_when_empty(self):
1898 self.config.container_exists.return_value = False
1899- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
1900- progress = MockProgress.return_value
1901- progress.done = False
1902- task = tasks.CreateTask('palpatine', None, 'zesty', 'chroot', False, self.config, self.lock, self.connection, self.callback)
1903- task._instant_callback = True
1904-
1905- with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1906- MockHostInfo.return_value.is_distro_valid.return_value = True
1907- MockHostInfo.return_value.get_distro_codename.return_value = 'Zesty Zapus 17.04'
1908-
1909- with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
1910- MockContainer.return_value.create_libertine_container.return_value = True
1911- task.start().join()
1912-
1913- progress.finished.assert_called_once_with('palpatine')
1914- self.config.add_new_container.assert_called_once_with('palpatine', 'Ubuntu \'Zesty Zapus 17.04\'', 'chroot', 'zesty')
1915- self.config.update_container_install_status.assert_has_calls([
1916- unittest.mock.call('palpatine', 'installing'),
1917- unittest.mock.call('palpatine', 'ready')
1918- ], any_order=True)
1919- self.assertEqual(task, self.called_with)
1920+ self.monitor.done.return_value = False
1921+ task = tasks.CreateTask('palpatine', None, 'zesty', 'chroot', False, self.config, self.lock, self.monitor, self.callback)
1922+ task._instant_callback = True
1923+
1924+ with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1925+ MockHostInfo.return_value.is_distro_valid.return_value = True
1926+ MockHostInfo.return_value.get_distro_codename.return_value = 'Zesty Zapus 17.04'
1927+
1928+ with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
1929+ MockContainer.return_value.create_libertine_container.return_value = True
1930+ task.start().join()
1931+
1932+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
1933+ self.config.add_new_container.assert_called_once_with('palpatine', 'Ubuntu \'Zesty Zapus 17.04\'', 'chroot', 'zesty')
1934+ self.config.update_container_install_status.assert_has_calls([
1935+ unittest.mock.call('palpatine', 'installing'),
1936+ unittest.mock.call('palpatine', 'ready')
1937+ ], any_order=True)
1938+ self.assertEqual(task, self.called_with)
1939
1940 def test_sets_multiarch(self):
1941 self.config.container_exists.return_value = False
1942- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
1943- progress = MockProgress.return_value
1944- progress.done = False
1945- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'chroot', True, self.config, self.lock, self.connection, self.callback)
1946- task._instant_callback = True
1947-
1948- with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1949- MockHostInfo.return_value.is_distro_valid.return_value = True
1950-
1951- with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
1952- MockContainer.return_value.create_libertine_container.return_value = True
1953- task.start().join()
1954-
1955- progress.finished.assert_called_once_with('palpatine')
1956- self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'chroot', 'zesty')
1957- self.config.update_container_multiarch_support.assert_called_once_with('palpatine', 'enabled')
1958- self.config.update_container_install_status.assert_has_calls([
1959- unittest.mock.call('palpatine', 'installing'),
1960- unittest.mock.call('palpatine', 'ready')
1961- ], any_order=True)
1962- self.assertEqual(task, self.called_with)
1963+ self.monitor.done.return_value = False
1964+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', 'chroot', True, self.config, self.lock, self.monitor, self.callback)
1965+ task._instant_callback = True
1966+
1967+ with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1968+ MockHostInfo.return_value.is_distro_valid.return_value = True
1969+
1970+ with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
1971+ MockContainer.return_value.create_libertine_container.return_value = True
1972+ task.start().join()
1973+
1974+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
1975+ self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'chroot', 'zesty')
1976+ self.config.update_container_multiarch_support.assert_called_once_with('palpatine', 'enabled')
1977+ self.config.update_container_install_status.assert_has_calls([
1978+ unittest.mock.call('palpatine', 'installing'),
1979+ unittest.mock.call('palpatine', 'ready')
1980+ ], any_order=True)
1981+ self.assertEqual(task, self.called_with)
1982
1983 def test_sets_default_type(self):
1984 self.config.container_exists.return_value = False
1985- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
1986- progress = MockProgress.return_value
1987- progress.done = False
1988- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', None, False, self.config, self.lock, self.connection, self.callback)
1989- task._instant_callback = True
1990-
1991- with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
1992- MockHostInfo.return_value.is_distro_valid.return_value = True
1993- MockHostInfo.return_value.select_container_type_by_kernel.return_value = 'lxc'
1994-
1995- with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
1996- MockContainer.return_value.create_libertine_container.return_value = True
1997- task.start().join()
1998-
1999- progress.finished.assert_called_once_with('palpatine')
2000- self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'lxc', 'zesty')
2001- self.config.update_container_install_status.assert_has_calls([
2002- unittest.mock.call('palpatine', 'installing'),
2003- unittest.mock.call('palpatine', 'ready')
2004- ], any_order=True)
2005- self.assertEqual(task, self.called_with)
2006+ self.monitor.done.return_value = False
2007+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', 'zesty', None, False, self.config, self.lock, self.monitor, self.callback)
2008+ task._instant_callback = True
2009+
2010+ with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
2011+ MockHostInfo.return_value.is_distro_valid.return_value = True
2012+ MockHostInfo.return_value.select_container_type_by_kernel.return_value = 'lxc'
2013+
2014+ with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
2015+ MockContainer.return_value.create_libertine_container.return_value = True
2016+ task.start().join()
2017+
2018+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
2019+ self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'lxc', 'zesty')
2020+ self.config.update_container_install_status.assert_has_calls([
2021+ unittest.mock.call('palpatine', 'installing'),
2022+ unittest.mock.call('palpatine', 'ready')
2023+ ], any_order=True)
2024+ self.assertEqual(task, self.called_with)
2025
2026 def test_sets_default_distro(self):
2027 self.config.container_exists.return_value = False
2028- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2029- progress = MockProgress.return_value
2030- progress.done = False
2031- task = tasks.CreateTask('palpatine', 'Emperor Palpatine', None, 'lxc', False, self.config, self.lock, self.connection, self.callback)
2032- task._instant_callback = True
2033-
2034- with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
2035- MockHostInfo.return_value.has_lxc_support.return_value = True
2036- MockHostInfo.return_value.get_host_distro_release.return_value = 'zesty'
2037-
2038- with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
2039- MockContainer.return_value.create_libertine_container.return_value = True
2040- task.start().join()
2041-
2042- progress.finished.assert_called_once_with('palpatine')
2043- self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'lxc', 'zesty')
2044- self.config.update_container_install_status.assert_has_calls([
2045- unittest.mock.call('palpatine', 'installing'),
2046- unittest.mock.call('palpatine', 'ready')
2047- ], any_order=True)
2048- self.assertEqual(task, self.called_with)
2049+ self.monitor.done.return_value = False
2050+ task = tasks.CreateTask('palpatine', 'Emperor Palpatine', None, 'lxc', False, self.config, self.lock, self.monitor, self.callback)
2051+ task._instant_callback = True
2052+
2053+ with unittest.mock.patch('libertine.service.tasks.create_task.HostInfo') as MockHostInfo:
2054+ MockHostInfo.return_value.has_lxc_support.return_value = True
2055+ MockHostInfo.return_value.get_host_distro_release.return_value = 'zesty'
2056+
2057+ with unittest.mock.patch('libertine.service.tasks.create_task.LibertineContainer') as MockContainer:
2058+ MockContainer.return_value.create_libertine_container.return_value = True
2059+ task.start().join()
2060+
2061+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
2062+ self.config.add_new_container.assert_called_once_with('palpatine', 'Emperor Palpatine', 'lxc', 'zesty')
2063+ self.config.update_container_install_status.assert_has_calls([
2064+ unittest.mock.call('palpatine', 'installing'),
2065+ unittest.mock.call('palpatine', 'ready')
2066+ ], any_order=True)
2067+ self.assertEqual(task, self.called_with)
2068
2069=== modified file 'tests/unit/service/tasks/test_destroy_task.py'
2070--- tests/unit/service/tasks/test_destroy_task.py 2016-11-07 18:51:17 +0000
2071+++ tests/unit/service/tasks/test_destroy_task.py 2017-03-07 21:54:49 +0000
2072@@ -1,4 +1,4 @@
2073-# Copyright 2016 Canonical Ltd.
2074+# Copyright 2016-2017 Canonical Ltd.
2075 #
2076 # This program is free software: you can redistribute it and/or modify it
2077 # under the terms of the GNU General Public License version 3, as published
2078@@ -15,15 +15,17 @@
2079
2080 import unittest.mock
2081 from unittest import TestCase
2082-from libertine.service import tasks
2083+from libertine.service import tasks, operations_monitor
2084 from libertine.ContainersConfig import ContainersConfig
2085
2086
2087 class TestDestroyTask(TestCase):
2088 def setUp(self):
2089- self.config = unittest.mock.create_autospec(ContainersConfig)
2090- self.connection = unittest.mock.Mock()
2091- self.lock = unittest.mock.MagicMock()
2092+ self.config = unittest.mock.create_autospec(ContainersConfig)
2093+ self.lock = unittest.mock.MagicMock()
2094+ self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
2095+
2096+ self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
2097 self.called_with = None
2098
2099 def callback(self, task):
2100@@ -31,50 +33,45 @@
2101
2102 def test_sends_error_on_non_ready_container(self):
2103 self.config._get_value_by_key.return_value = ''
2104- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2105- progress = MockProgress.return_value
2106- progress.done = False
2107- task = tasks.DestroyTask('palpatine', self.config, self.lock, self.connection, self.callback)
2108- task._instant_callback = True
2109-
2110- with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
2111- MockContainer.return_value.destroy_libertine_container.return_value = True
2112- task.start().join()
2113-
2114- progress.error.assert_called_once_with('Container \'palpatine\' does not exist')
2115- self.assertEqual(task, self.called_with)
2116+ self.monitor.done.return_value = False
2117+ task = tasks.DestroyTask('palpatine', self.config, self.lock, self.monitor, self.callback)
2118+ task._instant_callback = True
2119+
2120+ with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
2121+ MockContainer.return_value.destroy_libertine_container.return_value = True
2122+ task.start().join()
2123+
2124+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Container \'palpatine\' does not exist')
2125+ self.assertEqual(task, self.called_with)
2126
2127 def test_sends_error_on_failed_destroy(self):
2128 self.config._get_value_by_key.return_value = 'ready'
2129- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2130- progress = MockProgress.return_value
2131- task = tasks.DestroyTask('palpatine', self.config, self.lock, self.connection, self.callback)
2132- task._instant_callback = True
2133-
2134- with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
2135- MockContainer.return_value.destroy_libertine_container.return_value = False
2136- task.start().join()
2137-
2138- progress.error.assert_called_once_with('Destroying container \'palpatine\' failed')
2139- self.config.update_container_install_status.assert_has_calls([
2140- unittest.mock.call('palpatine', 'removing'),
2141- unittest.mock.call('palpatine', 'ready')
2142- ], any_order=True)
2143- self.assertEqual(task, self.called_with)
2144+ task = tasks.DestroyTask('palpatine', self.config, self.lock, self.monitor, self.callback)
2145+ task._instant_callback = True
2146+
2147+ with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
2148+ MockContainer.return_value.destroy_libertine_container.return_value = False
2149+ task.start().join()
2150+
2151+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Destroying container \'palpatine\' failed')
2152+ self.config.update_container_install_status.assert_has_calls([
2153+ unittest.mock.call('palpatine', 'removing'),
2154+ unittest.mock.call('palpatine', 'ready')
2155+ ], any_order=True)
2156+
2157+ self.assertEqual(task, self.called_with)
2158
2159 def test_successfully_destroys(self):
2160 self.config._get_value_by_key.return_value = 'ready'
2161- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2162- progress = MockProgress.return_value
2163- progress.done = False
2164- task = tasks.DestroyTask('palpatine', self.config, self.lock, self.connection, self.callback)
2165- task._instant_callback = True
2166-
2167- with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
2168- MockContainer.return_value.destroy_libertine_container.return_value = True
2169- task.start().join()
2170-
2171- progress.finished.assert_called_once_with('palpatine')
2172- self.config.update_container_install_status.assert_called_once_with('palpatine', 'removing')
2173- self.config.delete_container.assert_called_once_with('palpatine')
2174- self.assertEqual(task, self.called_with)
2175+ self.monitor.done.return_value = False
2176+ task = tasks.DestroyTask('palpatine', self.config, self.lock, self.monitor, self.callback)
2177+ task._instant_callback = True
2178+
2179+ with unittest.mock.patch('libertine.service.tasks.destroy_task.LibertineContainer') as MockContainer:
2180+ MockContainer.return_value.destroy_libertine_container.return_value = True
2181+ task.start().join()
2182+
2183+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
2184+ self.config.update_container_install_status.assert_called_once_with('palpatine', 'removing')
2185+ self.config.delete_container.assert_called_once_with('palpatine')
2186+ self.assertEqual(task, self.called_with)
2187
2188=== modified file 'tests/unit/service/tasks/test_install_task.py'
2189--- tests/unit/service/tasks/test_install_task.py 2016-11-08 15:20:20 +0000
2190+++ tests/unit/service/tasks/test_install_task.py 2017-03-07 21:54:49 +0000
2191@@ -1,4 +1,4 @@
2192-# Copyright 2016 Canonical Ltd.
2193+# Copyright 2016-2017 Canonical Ltd.
2194 #
2195 # This program is free software: you can redistribute it and/or modify it
2196 # under the terms of the GNU General Public License version 3, as published
2197@@ -15,15 +15,17 @@
2198
2199 import unittest.mock
2200 from unittest import TestCase
2201-from libertine.service import tasks
2202+from libertine.service import tasks, operations_monitor
2203 from libertine.ContainersConfig import ContainersConfig
2204
2205
2206 class TestInstallTask(TestCase):
2207 def setUp(self):
2208 self.config = unittest.mock.create_autospec(ContainersConfig)
2209- self.connection = unittest.mock.Mock()
2210 self.lock = unittest.mock.MagicMock()
2211+ self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
2212+
2213+ self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
2214 self.called_with = None
2215
2216 def callback(self, task):
2217@@ -31,46 +33,40 @@
2218
2219 def test_sends_error_on_existing_package(self):
2220 self.config.package_exists.return_value = True
2221- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2222- progress = MockProgress.return_value
2223- task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.connection, self.callback)
2224- task._instant_callback = True
2225- task.start().join()
2226+ task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.callback)
2227+ task._instant_callback = True
2228+ task.start().join()
2229
2230- progress.error.assert_called_once_with('Package \'darkside-common\' already exists, skipping install')
2231- self.assertEqual(task, self.called_with)
2232+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Package \'darkside-common\' already exists, skipping install')
2233+ self.assertEqual(task, self.called_with)
2234
2235 def test_sends_error_on_failed_install(self):
2236 self.config.package_exists.return_value = False
2237- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2238- progress = MockProgress.return_value
2239- task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.connection, self.callback)
2240- task._instant_callback = True
2241-
2242- with unittest.mock.patch('libertine.service.tasks.install_task.LibertineContainer') as MockContainer:
2243- MockContainer.return_value.install_package.return_value = False
2244- task.start().join()
2245-
2246- progress.error.assert_called_once_with("Package installation failed for 'darkside-common'")
2247- self.config.update_package_install_status.assert_called_once_with('palpatine', 'darkside-common', 'installing')
2248- self.config.delete_package.assert_called_once_with('palpatine', 'darkside-common')
2249- self.assertEqual(task, self.called_with)
2250+ task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.callback)
2251+ task._instant_callback = True
2252+
2253+ with unittest.mock.patch('libertine.service.tasks.install_task.LibertineContainer') as MockContainer:
2254+ MockContainer.return_value.install_package.return_value = False
2255+ task.start().join()
2256+
2257+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, "Package installation failed for 'darkside-common'")
2258+ self.config.update_package_install_status.assert_called_once_with('palpatine', 'darkside-common', 'installing')
2259+ self.config.delete_package.assert_called_once_with('palpatine', 'darkside-common')
2260+ self.assertEqual(task, self.called_with)
2261
2262 def test_successfully_install(self):
2263 self.config.package_exists.return_value = False
2264- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2265- progress = MockProgress.return_value
2266- progress.done = False
2267- task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.connection, self.callback)
2268- task._instant_callback = True
2269-
2270- with unittest.mock.patch('libertine.service.tasks.install_task.LibertineContainer') as MockContainer:
2271- MockContainer.return_value.install_package.return_value = True
2272- task.start().join()
2273-
2274- progress.finished.assert_called_once_with('palpatine')
2275- self.config.update_package_install_status.assert_has_calls([
2276- unittest.mock.call('palpatine', 'darkside-common', 'installing'),
2277- unittest.mock.call('palpatine', 'darkside-common', 'installed')
2278- ], any_order=True)
2279- self.assertEqual(task, self.called_with)
2280+ self.monitor.done.return_value = False
2281+ task = tasks.InstallTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.callback)
2282+ task._instant_callback = True
2283+
2284+ with unittest.mock.patch('libertine.service.tasks.install_task.LibertineContainer') as MockContainer:
2285+ MockContainer.return_value.install_package.return_value = True
2286+ task.start().join()
2287+
2288+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
2289+ self.config.update_package_install_status.assert_has_calls([
2290+ unittest.mock.call('palpatine', 'darkside-common', 'installing'),
2291+ unittest.mock.call('palpatine', 'darkside-common', 'installed')
2292+ ], any_order=True)
2293+ self.assertEqual(task, self.called_with)
2294
2295=== modified file 'tests/unit/service/tasks/test_list_app_ids_task.py'
2296--- tests/unit/service/tasks/test_list_app_ids_task.py 2017-02-07 12:35:48 +0000
2297+++ tests/unit/service/tasks/test_list_app_ids_task.py 2017-03-07 21:54:49 +0000
2298@@ -15,15 +15,17 @@
2299 import json
2300 import unittest.mock
2301 from unittest import TestCase
2302-from libertine.service import tasks
2303+from libertine.service import tasks, operations_monitor
2304 from libertine.ContainersConfig import ContainersConfig
2305
2306
2307 class TestListAppIdsTask(TestCase):
2308 def setUp(self):
2309 self.config = unittest.mock.create_autospec(ContainersConfig)
2310- self.connection = unittest.mock.Mock()
2311 self.lock = unittest.mock.MagicMock()
2312+ self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
2313+
2314+ self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
2315 self.called_with = None
2316
2317 def callback(self, task):
2318@@ -31,29 +33,25 @@
2319
2320 def test_sends_error_on_non_existent_container(self):
2321 self.config.container_exists.return_value = False
2322- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2323- progress = MockProgress.return_value
2324- task = tasks.ListAppIdsTask('palpatine', self.config, self.connection, self.callback)
2325- task._instant_callback = True
2326-
2327- with unittest.mock.patch('libertine.service.tasks.list_app_ids_task.LibertineContainer') as MockContainer:
2328- task.start().join()
2329-
2330- progress.error.assert_called_once_with('Container \'palpatine\' does not exist, skipping list')
2331- self.assertEqual(task, self.called_with)
2332+ task = tasks.ListAppIdsTask('palpatine', self.config, self.monitor, self.callback)
2333+ task._instant_callback = True
2334+
2335+ with unittest.mock.patch('libertine.service.tasks.list_app_ids_task.LibertineContainer') as MockContainer:
2336+ task.start().join()
2337+
2338+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Container \'palpatine\' does not exist, skipping list')
2339+ self.assertEqual(task, self.called_with)
2340
2341 def test_successfully_lists_apps(self):
2342 self.config.container_exists.return_value = True
2343- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2344- progress = MockProgress.return_value
2345- progress.done = False
2346- task = tasks.ListAppIdsTask('palpatine', self.config, self.connection, self.callback)
2347- task._instant_callback = True
2348-
2349- with unittest.mock.patch('libertine.service.tasks.list_app_ids_task.LibertineContainer') as MockContainer:
2350- MockContainer.return_value.list_app_ids.return_value = '["palpatine_gedit_0.0","palpatine_xterm_0.0"]'
2351- task.start().join()
2352-
2353- progress.finished.assert_called_once_with('palpatine')
2354- progress.data.assert_called_once_with(json.dumps('["palpatine_gedit_0.0","palpatine_xterm_0.0"]'))
2355- self.assertEqual(task, self.called_with)
2356+ self.monitor.done.return_value = False
2357+ task = tasks.ListAppIdsTask('palpatine', self.config, self.monitor, self.callback)
2358+ task._instant_callback = True
2359+
2360+ with unittest.mock.patch('libertine.service.tasks.list_app_ids_task.LibertineContainer') as MockContainer:
2361+ MockContainer.return_value.list_app_ids.return_value = '["palpatine_gedit_0.0","palpatine_xterm_0.0"]'
2362+ task.start().join()
2363+
2364+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
2365+ self.monitor.data.assert_called_once_with(self.monitor.new_operation.return_value, json.dumps('["palpatine_gedit_0.0","palpatine_xterm_0.0"]'))
2366+ self.assertEqual(task, self.called_with)
2367
2368=== modified file 'tests/unit/service/tasks/test_list_task.py'
2369--- tests/unit/service/tasks/test_list_task.py 2017-01-24 18:00:57 +0000
2370+++ tests/unit/service/tasks/test_list_task.py 2017-03-07 21:54:49 +0000
2371@@ -17,31 +17,30 @@
2372 import unittest.mock
2373
2374 from unittest import TestCase
2375-from libertine.service import tasks
2376+from libertine.service import tasks, operations_monitor
2377 from libertine.ContainersConfig import ContainersConfig
2378
2379
2380 class TestListTask(TestCase):
2381 def setUp(self):
2382 self.config = unittest.mock.create_autospec(ContainersConfig)
2383- self.connection = unittest.mock.Mock()
2384+ self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
2385+ self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
2386
2387 def test_success_sends_data(self):
2388 self.called_with = None
2389 def callback(t):
2390 self.called_with = t
2391
2392- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2393- progress = MockProgress.return_value
2394- progress.done = False
2395-
2396- task = tasks.ListTask(self.config, self.connection, callback)
2397- task._instant_callback = True
2398-
2399- self.config.get_containers.return_value = ['palatine', 'vader', 'maul']
2400- task.start().join()
2401-
2402- progress.data.assert_called_once_with(json.dumps(['palatine', 'vader', 'maul']))
2403- progress.finished.assert_called_once_with('')
2404-
2405- self.assertEqual(task, self.called_with)
2406+ self.monitor.done.return_value = False
2407+
2408+ task = tasks.ListTask(self.config, self.monitor, callback)
2409+ task._instant_callback = True
2410+
2411+ self.config.get_containers.return_value = ['palatine', 'vader', 'maul']
2412+ task.start().join()
2413+
2414+ self.monitor.data.assert_called_once_with(self.monitor.new_operation.return_value, json.dumps(['palatine', 'vader', 'maul']))
2415+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
2416+
2417+ self.assertEqual(task, self.called_with)
2418
2419=== modified file 'tests/unit/service/tasks/test_remove_task.py'
2420--- tests/unit/service/tasks/test_remove_task.py 2016-11-08 15:20:20 +0000
2421+++ tests/unit/service/tasks/test_remove_task.py 2017-03-07 21:54:49 +0000
2422@@ -1,4 +1,4 @@
2423-# Copyright 2016 Canonical Ltd.
2424+# Copyright 2016-2017 Canonical Ltd.
2425 #
2426 # This program is free software: you can redistribute it and/or modify it
2427 # under the terms of the GNU General Public License version 3, as published
2428@@ -15,15 +15,17 @@
2429
2430 import unittest.mock
2431 from unittest import TestCase
2432-from libertine.service import tasks
2433+from libertine.service import tasks, operations_monitor
2434 from libertine.ContainersConfig import ContainersConfig
2435
2436
2437 class TestRemoveTask(TestCase):
2438 def setUp(self):
2439 self.config = unittest.mock.create_autospec(ContainersConfig)
2440- self.connection = unittest.mock.Mock()
2441 self.lock = unittest.mock.MagicMock()
2442+ self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
2443+
2444+ self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
2445 self.called_with = None
2446
2447 def callback(self, task):
2448@@ -31,46 +33,40 @@
2449
2450 def test_sends_error_on_non_installed_package(self):
2451 self.config.get_package_install_status.return_value = 'installing'
2452- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2453- progress = MockProgress.return_value
2454- task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.connection, self.callback)
2455- task._instant_callback = True
2456- task.start().join()
2457+ task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.callback)
2458+ task._instant_callback = True
2459+ task.start().join()
2460
2461- progress.error.assert_called_once_with('Package \'darkside-common\' not installed, skipping remove')
2462- self.assertEqual(task, self.called_with)
2463+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Package \'darkside-common\' not installed, skipping remove')
2464+ self.assertEqual(task, self.called_with)
2465
2466 def test_sends_error_on_failed_install(self):
2467 self.config.get_package_install_status.return_value = 'installed'
2468- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2469- progress = MockProgress.return_value
2470- task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.connection, self.callback)
2471- task._instant_callback = True
2472-
2473- with unittest.mock.patch('libertine.service.tasks.remove_task.LibertineContainer') as MockContainer:
2474- MockContainer.return_value.remove_package.return_value = False
2475- task.start().join()
2476-
2477- progress.error.assert_called_once_with("Package removal failed for 'darkside-common'")
2478- self.config.update_package_install_status.assert_has_calls([
2479- unittest.mock.call('palpatine', 'darkside-common', 'removing'),
2480- unittest.mock.call('palpatine', 'darkside-common', 'installed')
2481- ], any_order=True)
2482- self.assertEqual(task, self.called_with)
2483+ task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.callback)
2484+ task._instant_callback = True
2485+
2486+ with unittest.mock.patch('libertine.service.tasks.remove_task.LibertineContainer') as MockContainer:
2487+ MockContainer.return_value.remove_package.return_value = False
2488+ task.start().join()
2489+
2490+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, "Package removal failed for 'darkside-common'")
2491+ self.config.update_package_install_status.assert_has_calls([
2492+ unittest.mock.call('palpatine', 'darkside-common', 'removing'),
2493+ unittest.mock.call('palpatine', 'darkside-common', 'installed')
2494+ ], any_order=True)
2495+ self.assertEqual(task, self.called_with)
2496
2497 def test_successfully_install(self):
2498 self.config.get_package_install_status.return_value = 'installed'
2499- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2500- progress = MockProgress.return_value
2501- progress.done = False
2502- task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.connection, self.callback)
2503- task._instant_callback = True
2504-
2505- with unittest.mock.patch('libertine.service.tasks.remove_task.LibertineContainer') as MockContainer:
2506- MockContainer.return_value.remove_package.return_value = True
2507- task.start().join()
2508-
2509- progress.finished.assert_called_once_with('palpatine')
2510- self.config.update_package_install_status.assert_called_once_with('palpatine', 'darkside-common', 'removing')
2511- self.config.delete_package.assert_called_once_with('palpatine', 'darkside-common')
2512- self.assertEqual(task, self.called_with)
2513+ self.monitor.done.return_value = False
2514+ task = tasks.RemoveTask('darkside-common', 'palpatine', self.config, self.lock, self.monitor, self.callback)
2515+ task._instant_callback = True
2516+
2517+ with unittest.mock.patch('libertine.service.tasks.remove_task.LibertineContainer') as MockContainer:
2518+ MockContainer.return_value.remove_package.return_value = True
2519+ task.start().join()
2520+
2521+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
2522+ self.config.update_package_install_status.assert_called_once_with('palpatine', 'darkside-common', 'removing')
2523+ self.config.delete_package.assert_called_once_with('palpatine', 'darkside-common')
2524+ self.assertEqual(task, self.called_with)
2525
2526=== modified file 'tests/unit/service/tasks/test_search_task.py'
2527--- tests/unit/service/tasks/test_search_task.py 2016-11-07 18:51:17 +0000
2528+++ tests/unit/service/tasks/test_search_task.py 2017-03-07 21:54:49 +0000
2529@@ -1,4 +1,4 @@
2530-# Copyright 2016 Canonical Ltd.
2531+# Copyright 2016-2017 Canonical Ltd.
2532 #
2533 # This program is free software: you can redistribute it and/or modify it
2534 # under the terms of the GNU General Public License version 3, as published
2535@@ -15,29 +15,29 @@
2536
2537 import unittest.mock
2538 from unittest import TestCase
2539-from libertine.service import tasks, apt
2540+from libertine.service import tasks, apt, operations_monitor
2541
2542
2543 class TestSearchTask(TestCase):
2544 def setUp(self):
2545- self.connection = unittest.mock.Mock()
2546 self.lock = unittest.mock.MagicMock()
2547 self.cache = unittest.mock.create_autospec(apt.AptCache)
2548+ self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
2549+
2550+ self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
2551 self.called_with = None
2552
2553 def callback(self, task):
2554 self.called_with = task
2555
2556 def test_successfully_lists_apps(self):
2557- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2558- progress = MockProgress.return_value
2559- progress.done = False
2560- task = tasks.SearchTask('palpatine', self.cache, 'jarjar', self.connection, self.callback)
2561+ self.monitor.done.return_value = False
2562+ task = tasks.SearchTask('palpatine', self.cache, 'jarjar', self.monitor, self.callback)
2563 task._instant_callback = True
2564
2565 self.cache.search.return_value = ['jarjar', 'sidius']
2566 task.start().join()
2567
2568- progress.finished.assert_called_once_with('palpatine')
2569- progress.data.assert_called_once_with(str(['jarjar', 'sidius']))
2570+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
2571+ self.monitor.data.assert_called_once_with(self.monitor.new_operation.return_value, str(['jarjar', 'sidius']))
2572 self.assertEqual(task, self.called_with)
2573
2574=== modified file 'tests/unit/service/tasks/test_update_task.py'
2575--- tests/unit/service/tasks/test_update_task.py 2016-11-08 15:20:20 +0000
2576+++ tests/unit/service/tasks/test_update_task.py 2017-03-07 21:54:49 +0000
2577@@ -1,4 +1,4 @@
2578-# Copyright 2016 Canonical Ltd.
2579+# Copyright 2016-2017 Canonical Ltd.
2580 #
2581 # This program is free software: you can redistribute it and/or modify it
2582 # under the terms of the GNU General Public License version 3, as published
2583@@ -15,15 +15,17 @@
2584
2585 import unittest.mock
2586 from unittest import TestCase
2587-from libertine.service import tasks
2588+from libertine.service import tasks, operations_monitor
2589 from libertine.ContainersConfig import ContainersConfig
2590
2591
2592 class TestUpdateTask(TestCase):
2593 def setUp(self):
2594- self.config = unittest.mock.create_autospec(ContainersConfig)
2595- self.connection = unittest.mock.Mock()
2596- self.lock = unittest.mock.MagicMock()
2597+ self.config = unittest.mock.create_autospec(ContainersConfig)
2598+ self.lock = unittest.mock.MagicMock()
2599+ self.monitor = unittest.mock.create_autospec(operations_monitor.OperationsMonitor)
2600+
2601+ self.monitor.new_operation.return_value = "/com/canonical/libertine/Service/Download/123456"
2602 self.called_with = None
2603
2604 def callback(self, task):
2605@@ -31,50 +33,47 @@
2606
2607 def test_sends_error_on_non_existent_container(self):
2608 self.config.container_exists.return_value = False
2609- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2610- progress = MockProgress.return_value
2611- task = tasks.UpdateTask('palpatine', self.config, self.lock, self.connection, self.callback)
2612- task._instant_callback = True
2613-
2614- with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
2615- task.start().join()
2616-
2617- progress.error.assert_called_once_with('Container \'palpatine\' does not exist, skipping update')
2618- self.assertEqual(task, self.called_with)
2619+ task = tasks.UpdateTask('palpatine', self.config, self.lock, self.monitor, self.callback)
2620+ task._instant_callback = True
2621+
2622+ with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
2623+ task.start().join()
2624+
2625+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Container \'palpatine\' does not exist, skipping update')
2626+
2627+ self.assertEqual(task, self.called_with)
2628
2629 def test_sends_error_on_failed_update(self):
2630 self.config.container_exists.return_value = True
2631- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2632- progress = MockProgress.return_value
2633- task = tasks.UpdateTask('palpatine', self.config, self.lock, self.connection, self.callback)
2634- task._instant_callback = True
2635-
2636- with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
2637- MockContainer.return_value.update_libertine_container.return_value = False
2638- task.start().join()
2639-
2640- progress.error.assert_called_once_with('Failed to update container \'palpatine\'')
2641- self.config.update_container_install_status.assert_has_calls([
2642- unittest.mock.call('palpatine', 'updating'),
2643- unittest.mock.call('palpatine', 'ready')
2644- ], any_order=True)
2645- self.assertEqual(task, self.called_with)
2646+ task = tasks.UpdateTask('palpatine', self.config, self.lock, self.monitor, self.callback)
2647+ task._instant_callback = True
2648+
2649+ with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
2650+ MockContainer.return_value.update_libertine_container.return_value = False
2651+ task.start().join()
2652+
2653+ self.monitor.error.assert_called_once_with(self.monitor.new_operation.return_value, 'Failed to update container \'palpatine\'')
2654+ self.config.update_container_install_status.assert_has_calls([
2655+ unittest.mock.call('palpatine', 'updating'),
2656+ unittest.mock.call('palpatine', 'ready')
2657+ ], any_order=True)
2658+
2659+ self.assertEqual(task, self.called_with)
2660
2661 def test_successfully_updates(self):
2662 self.config.container_exists.return_value = True
2663- with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
2664- progress = MockProgress.return_value
2665- progress.done = False
2666- task = tasks.UpdateTask('palpatine', self.config, self.lock, self.connection, self.callback)
2667- task._instant_callback = True
2668-
2669- with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
2670- MockContainer.return_value.update_libertine_container.return_value = True
2671- task.start().join()
2672-
2673- progress.finished.assert_called_once_with('palpatine')
2674- self.config.update_container_install_status.assert_has_calls([
2675- unittest.mock.call('palpatine', 'updating'),
2676- unittest.mock.call('palpatine', 'ready')
2677- ], any_order=True)
2678- self.assertEqual(task, self.called_with)
2679+ self.monitor.done.return_value = False
2680+ task = tasks.UpdateTask('palpatine', self.config, self.lock, self.monitor, self.callback)
2681+ task._instant_callback = True
2682+
2683+ with unittest.mock.patch('libertine.service.tasks.update_task.LibertineContainer') as MockContainer:
2684+ MockContainer.return_value.update_libertine_container.return_value = True
2685+ task.start().join()
2686+
2687+ self.monitor.finished.assert_called_once_with(self.monitor.new_operation.return_value)
2688+ self.config.update_container_install_status.assert_has_calls([
2689+ unittest.mock.call('palpatine', 'updating'),
2690+ unittest.mock.call('palpatine', 'ready')
2691+ ], any_order=True)
2692+
2693+ self.assertEqual(task, self.called_with)
2694
2695=== modified file 'tests/unit/service/test_container.py'
2696--- tests/unit/service/test_container.py 2017-02-07 12:35:48 +0000
2697+++ tests/unit/service/test_container.py 2017-03-07 21:54:49 +0000
2698@@ -20,31 +20,31 @@
2699
2700 class TestContainer(TestCase):
2701 def setUp(self):
2702- self._connection = unittest.mock.Mock()
2703+ self._monitor = unittest.mock.Mock()
2704 self._config = unittest.mock.Mock()
2705
2706 def test_search_creates_search_task(self):
2707 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2708 cache = MockCache.return_value
2709- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2710+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2711 with unittest.mock.patch('libertine.service.container.SearchTask') as MockSearchTask:
2712 c.search('darkseid')
2713- MockSearchTask.assert_called_once_with('palpatine', cache, 'darkseid', self._connection, unittest.mock.ANY)
2714+ MockSearchTask.assert_called_once_with('palpatine', cache, 'darkseid', self._monitor, unittest.mock.ANY)
2715 MockSearchTask.return_value.start.assert_called_once_with()
2716
2717 def test_app_info_creates_app_info_task(self):
2718 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2719 cache = MockCache.return_value
2720- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2721+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2722 with unittest.mock.patch('libertine.service.container.AppInfoTask') as MockAppInfoTask:
2723 c.app_info('force')
2724- MockAppInfoTask.assert_called_once_with('palpatine', cache, 'force', [], self._config, self._connection, unittest.mock.ANY)
2725+ MockAppInfoTask.assert_called_once_with('palpatine', cache, 'force', [], self._config, self._monitor, unittest.mock.ANY)
2726 MockAppInfoTask.return_value.start.assert_called_once_with()
2727
2728 def test_app_info_gets_related_task_info(self):
2729 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2730 cache = MockCache.return_value
2731- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2732+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2733 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
2734 MockInstallTask.return_value.package = 'darkside'
2735 MockInstallTask.return_value.matches.return_value = False
2736@@ -55,111 +55,111 @@
2737 with unittest.mock.patch('libertine.service.container.AppInfoTask') as MockAppInfoTask:
2738 c.app_info('darkside')
2739 MockAppInfoTask.assert_called_once_with('palpatine', cache, 'darkside', [install_task_id, remove_task_id],
2740- self._config, self._connection, unittest.mock.ANY)
2741+ self._config, self._monitor, unittest.mock.ANY)
2742
2743 def test_install_creates_install_task(self):
2744 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2745- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2746+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2747 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
2748 c.install('force')
2749- MockInstallTask.assert_called_once_with('force', 'palpatine', self._config, unittest.mock.ANY, self._connection, unittest.mock.ANY)
2750+ MockInstallTask.assert_called_once_with('force', 'palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
2751 MockInstallTask.return_value.start.assert_called_once_with()
2752
2753 def test_install_only_calls_once_when_unfinished(self):
2754 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2755- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2756+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2757 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
2758 c.install('darkside')
2759 c.install('darkside')
2760 c.install('darkside')
2761- MockInstallTask.assert_called_once_with('darkside', 'palpatine', self._config, unittest.mock.ANY, self._connection, unittest.mock.ANY)
2762+ MockInstallTask.assert_called_once_with('darkside', 'palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
2763 MockInstallTask.return_value.start.assert_called_once_with()
2764
2765 def test_remove_creates_remove_task(self):
2766 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2767- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2768+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2769 with unittest.mock.patch('libertine.service.container.RemoveTask') as MockRemoveTask:
2770 c.remove('force')
2771- MockRemoveTask.assert_called_once_with('force', 'palpatine', self._config, unittest.mock.ANY, self._connection, unittest.mock.ANY)
2772+ MockRemoveTask.assert_called_once_with('force', 'palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
2773 MockRemoveTask.return_value.start.assert_called_once_with()
2774
2775 def test_remove_only_calls_once_when_unfinished(self):
2776 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2777- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2778+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2779 with unittest.mock.patch('libertine.service.container.RemoveTask') as MockRemoveTask:
2780 c.remove('darkside')
2781 c.remove('darkside')
2782 c.remove('darkside')
2783- MockRemoveTask.assert_called_once_with('darkside', 'palpatine', self._config, unittest.mock.ANY, self._connection, unittest.mock.ANY)
2784+ MockRemoveTask.assert_called_once_with('darkside', 'palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
2785 MockRemoveTask.return_value.start.assert_called_once_with()
2786
2787 def test_create_creates_create_task(self):
2788 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2789- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2790+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2791 with unittest.mock.patch('libertine.service.container.CreateTask') as MockCreateTask:
2792 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
2793 MockCreateTask.assert_called_once_with('palpatine', 'Emperor Palpatine', 'zesty', 'lxd', False,
2794- self._config, unittest.mock.ANY, self._connection, unittest.mock.ANY)
2795+ self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
2796 MockCreateTask.return_value.start.assert_called_once_with()
2797
2798 def test_create_only_calls_once_when_unfinished(self):
2799 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2800- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2801+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2802 with unittest.mock.patch('libertine.service.container.CreateTask') as MockCreateTask:
2803 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
2804 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
2805 c.create('Emperor Palpatine', 'zesty', 'lxd', False)
2806 MockCreateTask.assert_called_once_with('palpatine', 'Emperor Palpatine', 'zesty', 'lxd', False,
2807- self._config, unittest.mock.ANY, self._connection, unittest.mock.ANY)
2808+ self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
2809 MockCreateTask.return_value.start.assert_called_once_with()
2810
2811 def test_destroy_creates_destroy_task(self):
2812 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2813- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2814+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2815 with unittest.mock.patch('libertine.service.container.DestroyTask') as MockDestroyTask:
2816 c.destroy()
2817- MockDestroyTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._connection, unittest.mock.ANY)
2818+ MockDestroyTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
2819 MockDestroyTask.return_value.start.assert_called_once_with()
2820
2821 def test_destroy_only_calls_once_when_unfinished(self):
2822 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2823- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2824+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2825 with unittest.mock.patch('libertine.service.container.DestroyTask') as MockDestroyTask:
2826 c.destroy()
2827 c.destroy()
2828 c.destroy()
2829- MockDestroyTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._connection, unittest.mock.ANY)
2830+ MockDestroyTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
2831 MockDestroyTask.return_value.start.assert_called_once_with()
2832
2833 def test_update_creates_update_task(self):
2834 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2835- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2836+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2837 with unittest.mock.patch('libertine.service.container.UpdateTask') as MockUpdateTask:
2838 c.update()
2839- MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._connection, unittest.mock.ANY)
2840+ MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
2841 MockUpdateTask.return_value.start.assert_called_once_with()
2842
2843 def test_update_only_calls_once_when_unfinished(self):
2844 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2845- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2846+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2847 with unittest.mock.patch('libertine.service.container.UpdateTask') as MockUpdateTask:
2848 c.update()
2849 c.update()
2850 c.update()
2851- MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._connection, unittest.mock.ANY)
2852+ MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._monitor, unittest.mock.ANY)
2853 MockUpdateTask.return_value.start.assert_called_once_with()
2854
2855 def test_list_app_ids_creates_list_app_ids_task(self):
2856 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2857- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2858+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2859 with unittest.mock.patch('libertine.service.container.ListAppIdsTask') as MockListAppIdsTask:
2860 c.list_app_ids()
2861- MockListAppIdsTask.assert_called_once_with('palpatine', self._config, self._connection, unittest.mock.ANY)
2862+ MockListAppIdsTask.assert_called_once_with('palpatine', self._config, self._monitor, unittest.mock.ANY)
2863 MockListAppIdsTask.return_value.start.assert_called_once_with()
2864
2865 def test_removes_task_during_callback(self):
2866 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
2867- c = container.Container('palpatine', self._config, self._connection, lambda task: task)
2868+ c = container.Container('palpatine', self._config, self._monitor, lambda task: task)
2869 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
2870 MockInstallTask.return_value.package = 'force'
2871 c.install('force')
2872@@ -176,7 +176,7 @@
2873 self._container_id = None
2874 def callback(container):
2875 self._container_id = container.id
2876- c = container.Container('palpatine', self._config, self._connection, callback)
2877+ c = container.Container('palpatine', self._config, self._monitor, callback)
2878 with unittest.mock.patch('libertine.service.container.InstallTask') as MockInstallTask:
2879 c.install('force')
2880 name, args, kwargs = MockInstallTask.mock_calls[0]
2881
2882=== added file 'tests/unit/service/test_operations_monitor.py'
2883--- tests/unit/service/test_operations_monitor.py 1970-01-01 00:00:00 +0000
2884+++ tests/unit/service/test_operations_monitor.py 2017-03-07 21:54:49 +0000
2885@@ -0,0 +1,146 @@
2886+# Copyright 2017 Canonical Ltd.
2887+#
2888+# This program is free software: you can redistribute it and/or modify it
2889+# under the terms of the GNU General Public License version 3, as published
2890+# by the Free Software Foundation.
2891+#
2892+# This program is distributed in the hope that it will be useful, but
2893+# WITHOUT ANY WARRANTY; without even the implied warranties of
2894+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2895+# PURPOSE. See the GNU General Public License for more details.
2896+#
2897+# You should have received a copy of the GNU General Public License along
2898+# with this program. If not, see <http://www.gnu.org/licenses/>.
2899+
2900+import unittest.mock
2901+from unittest import TestCase
2902+from libertine.service import operations_monitor, download
2903+
2904+
2905+class TestOperationsMonitor(TestCase):
2906+ def setUp(self):
2907+ self._connection = unittest.mock.Mock()
2908+
2909+ def test_new_operation_returns_some_id(self):
2910+ with unittest.mock.patch('dbus.service.Object'):
2911+ monitor = operations_monitor.OperationsMonitor(self._connection)
2912+ monitor._connection = self._connection
2913+
2914+ with unittest.mock.patch('libertine.service.operations_monitor.download.Download') as MockDownload:
2915+ self.assertIsNotNone(monitor.new_operation())
2916+
2917+ def test_remove_connection(self):
2918+ with unittest.mock.patch('dbus.service.Object'):
2919+ monitor = operations_monitor.OperationsMonitor(self._connection)
2920+ monitor._connection = self._connection
2921+
2922+ with unittest.mock.patch('libertine.service.operations_monitor.download.Download') as MockDownload:
2923+ monitor.remove_from_connection(monitor.new_operation())
2924+ MockDownload.return_value.remove_from_connection.assert_called_once_with()
2925+
2926+ def test_returns_done_for_operation(self):
2927+ with unittest.mock.patch('dbus.service.Object'):
2928+ monitor = operations_monitor.OperationsMonitor(self._connection)
2929+ monitor._connection = self._connection
2930+
2931+ with unittest.mock.patch('libertine.service.operations_monitor.download.Download') as MockDownload:
2932+ MockDownload.return_value.done = True
2933+ self.assertTrue(monitor.done(monitor.new_operation()))
2934+
2935+ MockDownload.return_value.done = False
2936+ self.assertFalse(monitor.done(monitor.new_operation()))
2937+
2938+ # non-existent operation
2939+ self.assertFalse(monitor.done("123456"))
2940+
2941+ def test_running_returns_download_state(self):
2942+ with unittest.mock.patch('dbus.service.Object'):
2943+ monitor = operations_monitor.OperationsMonitor(self._connection)
2944+ monitor._connection = self._connection
2945+
2946+ with unittest.mock.patch('libertine.service.operations_monitor.download.Download') as MockDownload:
2947+ MockDownload.return_value.done = True
2948+ self.assertFalse(monitor.running(monitor.new_operation()))
2949+
2950+ MockDownload.return_value.done = False
2951+ self.assertTrue(monitor.running(monitor.new_operation()))
2952+
2953+ # non-existent operation
2954+ self.assertFalse(monitor.running("123456"))
2955+
2956+ def test_result_returns_download_results(self):
2957+ with unittest.mock.patch('dbus.service.Object'):
2958+ monitor = operations_monitor.OperationsMonitor(self._connection)
2959+ monitor._connection = self._connection
2960+
2961+ with unittest.mock.patch('libertine.service.operations_monitor.download.Download') as MockDownload:
2962+ MockDownload.return_value.result = "pokemongus"
2963+ self.assertEqual("pokemongus", monitor.result(monitor.new_operation()))
2964+
2965+ # non-existent operation
2966+ self.assertEqual("", monitor.result("123456"))
2967+
2968+ def test_last_error_returns_download_last_errors(self):
2969+ with unittest.mock.patch('dbus.service.Object'):
2970+ monitor = operations_monitor.OperationsMonitor(self._connection)
2971+ monitor._connection = self._connection
2972+
2973+ with unittest.mock.patch('libertine.service.operations_monitor.download.Download') as MockDownload:
2974+ MockDownload.return_value.last_error = "pokemongus"
2975+ self.assertEqual("pokemongus", monitor.last_error(monitor.new_operation()))
2976+
2977+ # non-existent operation
2978+ self.assertEqual("", monitor.last_error("123456"))
2979+
2980+ def test_forwards_finished(self):
2981+ with unittest.mock.patch('dbus.service.Object'):
2982+ monitor = operations_monitor.OperationsMonitor(self._connection)
2983+ monitor._connection = self._connection
2984+ monitor._locations = []
2985+
2986+ with unittest.mock.patch('libertine.service.operations_monitor.download.Download') as MockDownload:
2987+ path = monitor.new_operation()
2988+ monitor.finished(path)
2989+ MockDownload.return_value.finished.assert_called_once_with(path)
2990+
2991+ # test does not crash on empty
2992+ MockDownload.reset_mock()
2993+ monitor.finished("some/junk")
2994+ MockDownload.return_value.finished.assert_not_called()
2995+
2996+ def test_forwards_error(self):
2997+ with unittest.mock.patch('dbus.service.Object'):
2998+ monitor = operations_monitor.OperationsMonitor(self._connection)
2999+ monitor._connection = self._connection
3000+ monitor._locations = []
3001+
3002+ with unittest.mock.patch('libertine.service.operations_monitor.download.Download') as MockDownload:
3003+ path = monitor.new_operation()
3004+ monitor.error(path, "something messed up")
3005+ MockDownload.return_value.error.assert_called_once_with("something messed up")
3006+
3007+ # test does not crash on empty
3008+ MockDownload.reset_mock()
3009+ monitor.error("some/junk", "something messed up")
3010+ MockDownload.return_value.error.assert_not_called()
3011+
3012+ def test_forwards_data(self):
3013+ with unittest.mock.patch('dbus.service.Object'):
3014+ monitor = operations_monitor.OperationsMonitor(self._connection)
3015+ monitor._connection = self._connection
3016+ monitor._locations = []
3017+
3018+ with unittest.mock.patch('libertine.service.operations_monitor.download.Download') as MockDownload:
3019+ path = monitor.new_operation()
3020+ monitor.data(path, "some of that gud data")
3021+ MockDownload.return_value.data.assert_called_once_with("some of that gud data")
3022+
3023+ # test does not crash on empty
3024+ MockDownload.reset_mock()
3025+ monitor.data("some/junk", "some of that gud data")
3026+ MockDownload.return_value.data.assert_not_called()
3027+
3028+
3029+
3030+if __name__ == '__main__':
3031+ unittest.main()
3032
3033=== modified file 'tools/libertined'
3034--- tools/libertined 2017-02-15 21:12:37 +0000
3035+++ tools/libertined 2017-03-07 21:54:49 +0000
3036@@ -1,7 +1,7 @@
3037 #!/usr/bin/python3
3038 # -*- coding: utf-8 -*-
3039
3040-# Copyright 2016 Canonical Ltd.
3041+# Copyright 2016-2017 Canonical Ltd.
3042 #
3043 # This program is free software: you can redistribute it and/or modify
3044 # it under the terms of the GNU General Public License as published by
3045@@ -15,13 +15,17 @@
3046 # You should have received a copy of the GNU General Public License
3047 # along with this program. If not, see <http://www.gnu.org/licenses/>.
3048
3049+
3050 import argparse
3051+import dbus
3052+import os
3053 import signal
3054 import sys
3055-import os
3056-from gi.repository import GLib, GObject
3057+
3058+from dbus.mainloop.glib import DBusGMainLoop
3059+from gi.repository import GLib
3060 from libertine import utils
3061-from libertine.service import manager
3062+from libertine.service import constants, operations, container_control
3063
3064
3065 class OutputRedirector(object):
3066@@ -116,6 +120,7 @@
3067 signal.SIGTERM,
3068 self.sigterm,
3069 None)
3070+ DBusGMainLoop(set_as_default=True)
3071 self.loop = GLib.MainLoop()
3072
3073 def sigterm(self, code):
3074@@ -136,8 +141,19 @@
3075
3076 with OutputRedirector(config):
3077 utils.get_logger().info("Starting libertine service")
3078- service = manager.Manager()
3079 loop = Loop()
3080+
3081+ try:
3082+ bus_name = dbus.service.BusName(constants.SERVICE_NAME,
3083+ bus=dbus.SessionBus(),
3084+ do_not_queue=True)
3085+ except dbus.exceptions.NameExistsException:
3086+ utils.get_logger().warning("service is already running")
3087+ raise
3088+
3089+ manager = operations.Operations(bus_name)
3090+ container_control.ContainerControl(manager.connection)
3091+
3092 try:
3093 loop.run()
3094 except KeyboardInterrupt:

Subscribers

People subscribed via source and target branches