Merge lp:~larryprice/libertine/new-list-apps into lp:libertine

Proposed by Larry Price
Status: Merged
Approved by: Christopher Townsend
Approved revision: 393
Merged at revision: 392
Proposed branch: lp:~larryprice/libertine/new-list-apps
Merge into: lp:libertine
Diff against target: 654 lines (+20/-438)
16 files modified
debian/python3-libertine.install (+0/-1)
python/libertine/AppDiscovery.py (+0/-220)
python/libertine/Libertine.py (+0/-18)
python/libertine/service/container.py (+0/-9)
python/libertine/service/manager.py (+0/-7)
python/libertine/service/task_dispatcher.py (+0/-4)
python/libertine/service/tasks/__init__.py (+0/-2)
python/libertine/service/tasks/list_apps_task.py (+0/-34)
tests/integration/test_libertine_service.py (+1/-2)
tests/unit/service/tasks/CMakeLists.txt (+0/-1)
tests/unit/service/tasks/test_list_app_ids_task.py (+1/-1)
tests/unit/service/tasks/test_list_apps_task.py (+0/-59)
tests/unit/service/test_container.py (+3/-11)
tests/unit/service/test_task_dispatcher.py (+7/-14)
tests/unit/test_app_discovery.py (+0/-52)
tools/libertine-container-manager (+8/-3)
To merge this branch: bzr merge lp:~larryprice/libertine/new-list-apps
Reviewer Review Type Date Requested Status
Christopher Townsend Approve
Libertine CI Bot continuous-integration Approve
Review via email: mp+316556@code.launchpad.net

Commit message

Migrate the list-apps subcommand to list application ids.

Description of the change

Migrate the list-apps subcommand to list application ids.

To post a comment you must log in.
Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
392. By Larry Price

missed a spot

Revision history for this message
Libertine CI Bot (libertine-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
393. By Larry Price

test method was using wrong dbus service giving false positive

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

PASSED: Continuous integration, rev:393
https://jenkins.canonical.com/libertine/job/lp-libertine-ci/371/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/libertine/job/build/710
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=default/581
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=amd64,release=zesty,testname=default/581
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=xenial+overlay,testname=default/581
    SUCCESS: https://jenkins.canonical.com/libertine/job/test-0-autopkgtest/label=i386,release=zesty,testname=default/581
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-0-fetch/720
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/701
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=xenial+overlay/701/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/701
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=amd64,release=zesty/701/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/701
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=xenial+overlay/701/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/701
        deb: https://jenkins.canonical.com/libertine/job/build-2-binpkg/arch=i386,release=zesty/701/artifact/output/*zip*/output.zip

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

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

lgtm

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/python3-libertine.install'
--- debian/python3-libertine.install 2017-01-31 18:21:43 +0000
+++ debian/python3-libertine.install 2017-02-07 13:30:52 +0000
@@ -1,4 +1,3 @@
1usr/lib/python*/*/libertine/AppDiscovery.py
2usr/lib/python*/*/libertine/ContainersConfig.py1usr/lib/python*/*/libertine/ContainersConfig.py
3usr/lib/python*/*/libertine/HostInfo.py2usr/lib/python*/*/libertine/HostInfo.py
4usr/lib/python*/*/libertine/Libertine.py3usr/lib/python*/*/libertine/Libertine.py
54
=== removed file 'python/libertine/AppDiscovery.py'
--- python/libertine/AppDiscovery.py 2017-01-17 21:46:43 +0000
+++ python/libertine/AppDiscovery.py 1970-01-01 00:00:00 +0000
@@ -1,220 +0,0 @@
1# Copyright 2015 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15from . import utils
16from xdg.BaseDirectory import xdg_data_dirs
17import configparser
18import glob
19import io
20import json
21import os
22import re
23import sys
24
25
26class IconCache(object):
27 """
28 Caches the names of all icon files available in the standard places (possibly
29 in a container) and provides a search function to deliver icon file names
30 matching a given icon name.
31
32 See the `Freedesktop.org icon theme specification
33 <http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html>`_
34 for the detailed specification.
35 """
36
37 def __init__(self, root_path, file_loader=None):
38 """
39 :param root_path: Where to start the file scan.
40 :type root_path: A valid filesystem path string.
41 :param file_loader: A function that builds a cache of filenames.
42 :type file_loader: Function returning a list of filenames.
43 """
44 if file_loader:
45 self._icon_cache = file_loader(root_path)
46 else:
47 self._icon_cache = self._file_loader(root_path)
48
49 def _get_icon_search_paths(self, root_path):
50 """
51 Gets a list of paths on which to search for icons.
52
53 :param root_path: Where to start the file scan.
54 :type root_path: A valid filesystem path string.
55 :rtype: A list of filesystem patch to serarch for qualifying icon files.
56 """
57 icon_search_paths = []
58 icon_search_paths.append(os.path.join(root_path, os.environ['HOME'], ".icons"))
59 for d in reversed(xdg_data_dirs):
60 icon_search_paths.append(os.path.join(root_path, d.lstrip('/'), "icons"))
61 icon_search_paths.append(os.path.join(root_path, "usr/share/pixmaps"))
62 return icon_search_paths
63
64 def _file_loader(self, root_path):
65 """
66 Loads a cache of file names by scanning the filesystem rooted at
67 ``root_path``.
68
69 :param root_path: Where to start the file scan.
70 :type root_path: A valid filesystem path.
71 :rtype: A list of fully-qualified file paths.
72 """
73 file_names = []
74 pattern = re.compile(r".*\.(png|svg|xpm)")
75 for path in self._get_icon_search_paths(root_path):
76 for base, dirs, files in os.walk(path):
77 for file in files:
78 if pattern.match(file):
79 file_names.append(os.path.join(base, file))
80 return file_names
81
82 def _find_icon_files(self, icon_name):
83 """
84 Finds a list of file name strings matching the given icon name.
85
86 :param icon_name: An icon name, pobably from a .desktop file.
87 :rtype: A list of filename strings matching the icon name.
88 """
89 icon_file_names = []
90 match_string = r"/" + os.path.splitext(icon_name)[0] + r"\....$"
91 pattern = re.compile(match_string)
92 for icon_file in self._icon_cache:
93 if pattern.search(icon_file):
94 icon_file_names.append(icon_file)
95 return icon_file_names
96
97 def expand_icons(self, desktop_icon_list):
98 """
99 Expands a string containing a list of icon names into a list of matching
100 file names.
101
102 :param desktop_icon_list: A string containing a list of icon names
103 separated by semicolons.
104 :rtype: A list of filename stings matching the icon names passed in.
105
106 See `the Freedesktop.org desktop file specification
107 <http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#recognized-keys>`_
108 for more information.
109 """
110 if desktop_icon_list:
111 icon_list = desktop_icon_list.split(';')
112 if icon_list[0][0] == '/':
113 return icon_list
114 icon_files = []
115 for i in icon_list:
116 icon_files += self._find_icon_files(i)
117 return icon_files
118 return []
119
120
121def expand_mime_types(desktop_mime_types):
122 if desktop_mime_types:
123 return desktop_mime_types.split(';')
124 return []
125
126
127class AppInfo(object):
128
129 def __init__(self, desktop_file_name, config_entry, icon_cache):
130 self.desktop_file_name = desktop_file_name
131 self.name = config_entry.get('Name')
132 if not self.name:
133 raise RuntimeError("required Name attribute is missing")
134 d = config_entry.get('NoDisplay')
135 self.no_display = (d != None and d == 'true')
136 self.exec_line = config_entry.get('Exec')
137 if not self.exec_line:
138 raise RuntimeError("required Exec attribute is missing")
139 self.icons = icon_cache.expand_icons(config_entry.get('Icon'))
140 self.mime_types = expand_mime_types(config_entry.get('MimeType'))
141
142 def __str__(self):
143 with io.StringIO() as ostr:
144 print(self.name, file=ostr)
145 print(" desktop_file={}".format(self.desktop_file_name), file=ostr)
146 print(" no-display={}".format(self.no_display), file=ostr)
147 print(" exec='{}'".format(self.exec_line), file=ostr)
148 for icon in self.icons:
149 print(" icon: {}".format(icon), file=ostr)
150 for mime in self.mime_types:
151 print(" mime: {}".format(mime), file=ostr)
152 return ostr.getvalue()
153
154 def to_json(self):
155 return json.dumps(self.__dict__)
156
157
158def desktop_file_is_showable(desktop_entry):
159 """
160 Determines if a particular application entry should be reported: the entry
161 can not be hidden and must be showable in Unity.
162 """
163 t = desktop_entry.get('Type')
164 if t != 'Application':
165 return False
166 n = desktop_entry.get('Hidden')
167 if n and n == 'true':
168 return False
169 n = desktop_entry.get('NoShowIn')
170 if n:
171 targets = n.split(';')
172 if 'Unity' in targets:
173 return False
174 n = desktop_entry.get('OnlyShowIn')
175 if n:
176 targets = n.split(';')
177 if 'Unity' not in targets:
178 return False
179 return True
180
181
182def get_app_info(desktop_path, icon_cache):
183 for desktop_file_name in glob.glob(desktop_path):
184 desktop_file = configparser.ConfigParser(strict=False, interpolation=None)
185 try:
186 desktop_file.read(desktop_file_name)
187 desktop_entry = desktop_file['Desktop Entry']
188 if desktop_file_is_showable(desktop_entry):
189 yield AppInfo(desktop_file_name, desktop_entry, icon_cache)
190 except Exception as ex:
191 utils.get_logger().error("error processing {}: {}".format(desktop_file_name, ex))
192
193
194class AppLauncherCache(object):
195 """
196 Caches a list of application launcher information (derived from .desktop
197 files installed in a container.
198 """
199
200 def __init__(self, name, root_path):
201 self.name = name
202 self.app_launchers = []
203 icon_cache = IconCache(root_path)
204 for dir in reversed(xdg_data_dirs):
205 path = os.path.join(root_path, dir.lstrip('/'), "applications")
206 for app_info in get_app_info(os.path.join(path, "*.desktop"), icon_cache):
207 self.app_launchers.append(app_info)
208
209 def __str__(self):
210 with io.StringIO() as ostr:
211 print("{}\n".format(self.name), file=ostr)
212 for app_info in self.app_launchers:
213 print(" {}".format(app_info), file=ostr)
214 return ostr.getvalue()
215
216 def to_json(self):
217 return json.dumps(self,
218 default=lambda o: o.__dict__,
219 sort_keys=True,
220 indent=4)
2210
=== modified file 'python/libertine/Libertine.py'
--- python/libertine/Libertine.py 2017-02-01 21:13:14 +0000
+++ python/libertine/Libertine.py 2017-02-07 13:30:52 +0000
@@ -12,7 +12,6 @@
12# You should have received a copy of the GNU General Public License along12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.13# with this program. If not, see <http://www.gnu.org/licenses/>.
1414
15from .AppDiscovery import AppLauncherCache
16import abc15import abc
17import contextlib16import contextlib
18import os17import os
@@ -525,23 +524,6 @@
525 """524 """
526 self.container.finish_application(app)525 self.container.finish_application(app)
527526
528 def list_app_launchers(self, use_json=False):
529 """
530 Enumerates all application launchers (based on .desktop files) available
531 in the container.
532
533 :param use_json: Indicates the returned string should be in JSON format.
534 The default format is some human-readble format.
535 :rtype: A printable string containing a list of application launchers
536 available in the container.
537 """
538 if use_json:
539 return AppLauncherCache(self.container.name,
540 self.container.root_path).to_json()
541 else:
542 return str(AppLauncherCache(self.container.name,
543 self.container.root_path))
544
545 def list_app_ids(self):527 def list_app_ids(self):
546 """528 """
547 Finds application ids (based on .desktop files) available in the529 Finds application ids (based on .desktop files) available in the
548530
=== modified file 'python/libertine/service/container.py'
--- python/libertine/service/container.py 2017-01-24 16:03:25 +0000
+++ python/libertine/service/container.py 2017-02-07 13:30:52 +0000
@@ -144,15 +144,6 @@
144 task.start()144 task.start()
145 return task.id145 return task.id
146146
147 def list_apps(self):
148 utils.get_logger().debug("List all apps in container '%s'" % self.id)
149
150 task = ListAppsTask(self.id, self._config, self._connection, self._cleanup_task)
151
152 self._tasks.append(task)
153 task.start()
154 return task.id
155
156 def list_app_ids(self):147 def list_app_ids(self):
157 utils.get_logger().debug("List all app ids in container '%s'" % self.id)148 utils.get_logger().debug("List all app ids in container '%s'" % self.id)
158149
159150
=== modified file 'python/libertine/service/manager.py'
--- python/libertine/service/manager.py 2017-01-31 19:24:32 +0000
+++ python/libertine/service/manager.py 2017-02-07 13:30:52 +0000
@@ -69,13 +69,6 @@
69 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,69 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
70 in_signature='s',70 in_signature='s',
71 out_signature='o')71 out_signature='o')
72 def list_apps(self, container_id):
73 utils.get_logger().debug("list_apps('{}')".format(container_id))
74 return self._dispatcher.list_apps(container_id)
75
76 @dbus.service.method(LIBERTINE_MANAGER_INTERFACE,
77 in_signature='s',
78 out_signature='o')
79 def list_app_ids(self, container_id):72 def list_app_ids(self, container_id):
80 utils.get_logger().debug("list_app_ids('{}')".format(container_id))73 utils.get_logger().debug("list_app_ids('{}')".format(container_id))
81 return self._dispatcher.list_app_ids(container_id)74 return self._dispatcher.list_app_ids(container_id)
8275
=== modified file 'python/libertine/service/task_dispatcher.py'
--- python/libertine/service/task_dispatcher.py 2017-01-24 18:00:57 +0000
+++ python/libertine/service/task_dispatcher.py 2017-02-07 13:30:52 +0000
@@ -84,10 +84,6 @@
84 utils.get_logger().debug("dispatching update container '%s'" % container_id)84 utils.get_logger().debug("dispatching update container '%s'" % container_id)
85 return self._find_or_create_container(container_id).update()85 return self._find_or_create_container(container_id).update()
8686
87 def list_apps(self, container_id):
88 utils.get_logger().debug("dispatching list all apps in container '%s'" % container_id)
89 return self._find_or_create_container(container_id).list_apps()
90
91 def list_app_ids(self, container_id):87 def list_app_ids(self, container_id):
92 utils.get_logger().debug("dispatching list apps ids in container '%s'" % container_id)88 utils.get_logger().debug("dispatching list apps ids in container '%s'" % container_id)
93 return self._find_or_create_container(container_id).list_app_ids()89 return self._find_or_create_container(container_id).list_app_ids()
9490
=== modified file 'python/libertine/service/tasks/__init__.py'
--- python/libertine/service/tasks/__init__.py 2017-01-24 18:00:57 +0000
+++ python/libertine/service/tasks/__init__.py 2017-02-07 13:30:52 +0000
@@ -22,7 +22,6 @@
22from .search_task import SearchTask22from .search_task import SearchTask
23from .update_task import UpdateTask23from .update_task import UpdateTask
24from .list_task import ListTask24from .list_task import ListTask
25from .list_apps_task import ListAppsTask
26from .list_app_ids_task import ListAppIdsTask25from .list_app_ids_task import ListAppIdsTask
2726
28__all__ = [27__all__ = [
@@ -36,6 +35,5 @@
36 'SearchTask',35 'SearchTask',
37 'UpdateTask',36 'UpdateTask',
38 'ListTask',37 'ListTask',
39 'ListAppsTask',
40 'ListAppIdsTask'38 'ListAppIdsTask'
41 ]39 ]
4240
=== removed file 'python/libertine/service/tasks/list_apps_task.py'
--- python/libertine/service/tasks/list_apps_task.py 2017-01-11 17:28:54 +0000
+++ python/libertine/service/tasks/list_apps_task.py 1970-01-01 00:00:00 +0000
@@ -1,34 +0,0 @@
1# Copyright 2016-2017 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; version 3 of the License.
6#
7# This program is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16from .base_task import BaseTask
17from libertine import LibertineContainer, utils
18
19
20class ListAppsTask(BaseTask):
21 def __init__(self, container_id, config, connection, callback):
22 super().__init__(lock=None, container_id=container_id, config=config, connection=connection, callback=callback)
23
24 def _run(self):
25 utils.get_logger().debug("Listing apps in container '%s'" % self._container)
26 container = LibertineContainer(self._container, self._config)
27 self._progress.data(str(container.list_app_launchers(use_json=True)))
28
29 def _before(self):
30 if not self._config.container_exists(self._container):
31 self._progress.error("Container '%s' does not exist, skipping list" % self._container)
32 return False
33
34 return True
350
=== modified file 'tests/integration/test_libertine_service.py'
--- tests/integration/test_libertine_service.py 2017-01-24 18:00:57 +0000
+++ tests/integration/test_libertine_service.py 2017-02-07 13:30:52 +0000
@@ -147,8 +147,7 @@
147 config = ContainersConfig()147 config = ContainersConfig()
148148
149 self._send(lambda: self._libertined.create('jarjar', 'JarJar Binks', 'xenial', 'mock'))149 self._send(lambda: self._libertined.create('jarjar', 'JarJar Binks', 'xenial', 'mock'))
150 self.assertEqual({'name': 'JarJar Binks', 'app_launchers': []},150 self.assertEqual([], ast.literal_eval(self._send(lambda: self._libertined.list_app_ids('jarjar'))))
151 ast.literal_eval(self._send(lambda: self._libertined.list_apps('jarjar'))))
152151
153 self._send(lambda: self._libertined.install('jarjar', 'the-force'))152 self._send(lambda: self._libertined.install('jarjar', 'the-force'))
154 config.refresh_database()153 config.refresh_database()
155154
=== modified file 'tests/unit/service/tasks/CMakeLists.txt'
--- tests/unit/service/tasks/CMakeLists.txt 2017-01-20 18:30:21 +0000
+++ tests/unit/service/tasks/CMakeLists.txt 2017-02-07 13:30:52 +0000
@@ -4,7 +4,6 @@
4create_service_unit_test(test_destroy_task)4create_service_unit_test(test_destroy_task)
5create_service_unit_test(test_install_task)5create_service_unit_test(test_install_task)
6create_service_unit_test(test_list_task)6create_service_unit_test(test_list_task)
7create_service_unit_test(test_list_apps_task)
8create_service_unit_test(test_list_app_ids_task)7create_service_unit_test(test_list_app_ids_task)
9create_service_unit_test(test_remove_task)8create_service_unit_test(test_remove_task)
10create_service_unit_test(test_search_task)9create_service_unit_test(test_search_task)
1110
=== modified file 'tests/unit/service/tasks/test_list_app_ids_task.py'
--- tests/unit/service/tasks/test_list_app_ids_task.py 2017-01-20 18:30:21 +0000
+++ tests/unit/service/tasks/test_list_app_ids_task.py 2017-02-07 13:30:52 +0000
@@ -36,7 +36,7 @@
36 task = tasks.ListAppIdsTask('palpatine', self.config, self.connection, self.callback)36 task = tasks.ListAppIdsTask('palpatine', self.config, self.connection, self.callback)
37 task._instant_callback = True37 task._instant_callback = True
3838
39 with unittest.mock.patch('libertine.service.tasks.list_apps_task.LibertineContainer') as MockContainer:39 with unittest.mock.patch('libertine.service.tasks.list_app_ids_task.LibertineContainer') as MockContainer:
40 task.start().join()40 task.start().join()
4141
42 progress.error.assert_called_once_with('Container \'palpatine\' does not exist, skipping list')42 progress.error.assert_called_once_with('Container \'palpatine\' does not exist, skipping list')
4343
=== removed file 'tests/unit/service/tasks/test_list_apps_task.py'
--- tests/unit/service/tasks/test_list_apps_task.py 2016-11-07 18:51:17 +0000
+++ tests/unit/service/tasks/test_list_apps_task.py 1970-01-01 00:00:00 +0000
@@ -1,59 +0,0 @@
1# Copyright 2016 Canonical Ltd.
2#
3# This program is free software: you can redistribute it and/or modify it
4# under the terms of the GNU General Public License version 3, as published
5# by the Free Software Foundation.
6#
7# This program is distributed in the hope that it will be useful, but
8# WITHOUT ANY WARRANTY; without even the implied warranties of
9# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
10# PURPOSE. See the GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License along
13# with this program. If not, see <http://www.gnu.org/licenses/>.
14
15
16import unittest.mock
17from unittest import TestCase
18from libertine.service import tasks
19from libertine.ContainersConfig import ContainersConfig
20
21
22class TestListAppsTask(TestCase):
23 def setUp(self):
24 self.config = unittest.mock.create_autospec(ContainersConfig)
25 self.connection = unittest.mock.Mock()
26 self.lock = unittest.mock.MagicMock()
27 self.called_with = None
28
29 def callback(self, task):
30 self.called_with = task
31
32 def test_sends_error_on_non_existent_container(self):
33 self.config.container_exists.return_value = False
34 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
35 progress = MockProgress.return_value
36 task = tasks.ListAppsTask('palpatine', self.config, self.connection, self.callback)
37 task._instant_callback = True
38
39 with unittest.mock.patch('libertine.service.tasks.list_apps_task.LibertineContainer') as MockContainer:
40 task.start().join()
41
42 progress.error.assert_called_once_with('Container \'palpatine\' does not exist, skipping list')
43 self.assertEqual(task, self.called_with)
44
45 def test_successfully_lists_apps(self):
46 self.config.container_exists.return_value = True
47 with unittest.mock.patch('libertine.service.tasks.base_task.libertine.service.progress.Progress') as MockProgress:
48 progress = MockProgress.return_value
49 progress.done = False
50 task = tasks.ListAppsTask('palpatine', self.config, self.connection, self.callback)
51 task._instant_callback = True
52
53 with unittest.mock.patch('libertine.service.tasks.list_apps_task.LibertineContainer') as MockContainer:
54 MockContainer.return_value.list_app_launchers.return_value = 'jarjar\nsidius'
55 task.start().join()
56
57 progress.finished.assert_called_once_with('palpatine')
58 progress.data.assert_called_once_with('jarjar\nsidius')
59 self.assertEqual(task, self.called_with)
600
=== modified file 'tests/unit/service/test_container.py'
--- tests/unit/service/test_container.py 2017-01-20 20:51:27 +0000
+++ tests/unit/service/test_container.py 2017-02-07 13:30:52 +0000
@@ -149,21 +149,13 @@
149 MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._connection, unittest.mock.ANY)149 MockUpdateTask.assert_called_once_with('palpatine', self._config, unittest.mock.ANY, self._connection, unittest.mock.ANY)
150 MockUpdateTask.return_value.start.assert_called_once_with()150 MockUpdateTask.return_value.start.assert_called_once_with()
151151
152 def test_list_apps_creates_list_apps_task(self):
153 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
154 c = container.Container('palpatine', self._config, self._connection, lambda task: task)
155 with unittest.mock.patch('libertine.service.container.ListAppsTask') as MockListAppsTask:
156 c.list_apps()
157 MockListAppsTask.assert_called_once_with('palpatine', self._config, self._connection, unittest.mock.ANY)
158 MockListAppsTask.return_value.start.assert_called_once_with()
159
160 def test_list_app_ids_creates_list_app_ids_task(self):152 def test_list_app_ids_creates_list_app_ids_task(self):
161 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:153 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
162 c = container.Container('palpatine', self._config, self._connection, lambda task: task)154 c = container.Container('palpatine', self._config, self._connection, lambda task: task)
163 with unittest.mock.patch('libertine.service.container.ListAppIdsTask') as MockListAppsTask:155 with unittest.mock.patch('libertine.service.container.ListAppIdsTask') as MockListAppIdsTask:
164 c.list_app_ids()156 c.list_app_ids()
165 MockListAppsTask.assert_called_once_with('palpatine', self._config, self._connection, unittest.mock.ANY)157 MockListAppIdsTask.assert_called_once_with('palpatine', self._config, self._connection, unittest.mock.ANY)
166 MockListAppsTask.return_value.start.assert_called_once_with()158 MockListAppIdsTask.return_value.start.assert_called_once_with()
167159
168 def test_removes_task_during_callback(self):160 def test_removes_task_during_callback(self):
169 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:161 with unittest.mock.patch('libertine.service.container.apt.AptCache') as MockCache:
170162
=== modified file 'tests/unit/service/test_task_dispatcher.py'
--- tests/unit/service/test_task_dispatcher.py 2017-01-20 20:51:27 +0000
+++ tests/unit/service/test_task_dispatcher.py 2017-02-07 13:30:52 +0000
@@ -76,14 +76,7 @@
76 self.assertEqual(123, self._dispatcher.update('palpatine'))76 self.assertEqual(123, self._dispatcher.update('palpatine'))
77 c.update.assert_called_once_with()77 c.update.assert_called_once_with()
7878
79 def test_list_apps_calls_list_apps_on_container(self):79 def test_list_app_ids_calls_list_app_ids_on_container(self):
80 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
81 c = MockContainer.return_value
82 c.list_apps.return_value = 123
83 self.assertEqual(123, self._dispatcher.list_apps('palpatine'))
84 c.list_apps.assert_called_once_with()
85
86 def test_list_apps_calls_list_apps_on_container(self):
87 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:80 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
88 c = MockContainer.return_value81 c = MockContainer.return_value
89 c.list_app_ids.return_value = 12382 c.list_app_ids.return_value = 123
@@ -94,20 +87,20 @@
94 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:87 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
95 c = MockContainer.return_value88 c = MockContainer.return_value
96 c.id = 'palpatine'89 c.id = 'palpatine'
97 self._dispatcher.list_apps('palpatine')90 self._dispatcher.list_app_ids('palpatine')
98 self._dispatcher.list_apps('palpatine')91 self._dispatcher.list_app_ids('palpatine')
99 self._dispatcher.list_apps('palpatine')92 self._dispatcher.list_app_ids('palpatine')
100 MockContainer.assert_called_once_with('palpatine', unittest.mock.ANY, self._connection, unittest.mock.ANY)93 MockContainer.assert_called_once_with('palpatine', unittest.mock.ANY, self._connection, unittest.mock.ANY)
10194
102 def test_container_callback_removes_container(self):95 def test_container_callback_removes_container(self):
103 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:96 with unittest.mock.patch('libertine.service.task_dispatcher.Container') as MockContainer:
104 c = MockContainer.return_value97 c = MockContainer.return_value
105 c.id = 'palpatine'98 c.id = 'palpatine'
106 self._dispatcher.list_apps('palpatine')99 self._dispatcher.list_app_ids('palpatine')
107 MockContainer.assert_called_once_with('palpatine', unittest.mock.ANY, self._connection, unittest.mock.ANY)100 MockContainer.assert_called_once_with('palpatine', unittest.mock.ANY, self._connection, unittest.mock.ANY)
108 name, args, kwargs = MockContainer.mock_calls[0]101 name, args, kwargs = MockContainer.mock_calls[0]
109 args[len(args)-1](MockContainer.return_value)102 args[len(args)-1](MockContainer.return_value)
110 self._dispatcher.list_apps('palpatine')103 self._dispatcher.list_app_ids('palpatine')
111 MockContainer.assert_has_calls([ # verify container constructed twice104 MockContainer.assert_has_calls([ # verify container constructed twice
112 unittest.mock.call('palpatine', unittest.mock.ANY, self._connection, unittest.mock.ANY),105 unittest.mock.call('palpatine', unittest.mock.ANY, self._connection, unittest.mock.ANY),
113 unittest.mock.call('palpatine', unittest.mock.ANY, self._connection, unittest.mock.ANY)106 unittest.mock.call('palpatine', unittest.mock.ANY, self._connection, unittest.mock.ANY)
@@ -128,7 +121,7 @@
128 c = MockContainer.return_value121 c = MockContainer.return_value
129 c.tasks = [1, 2, 3]122 c.tasks = [1, 2, 3]
130 c.id = 'palpatine'123 c.id = 'palpatine'
131 self._dispatcher.list_apps('palpatine') # creates container124 self._dispatcher.list_app_ids('palpatine') # creates container
132 self._dispatcher.container_info('palpatine')125 self._dispatcher.container_info('palpatine')
133 MockContainerInfoTask.assert_called_once_with('palpatine', [1, 2, 3], unittest.mock.ANY, self._connection, unittest.mock.ANY)126 MockContainerInfoTask.assert_called_once_with('palpatine', [1, 2, 3], unittest.mock.ANY, self._connection, unittest.mock.ANY)
134 task.start.assert_called_once_with()127 task.start.assert_called_once_with()
135128
=== removed file 'tests/unit/test_app_discovery.py'
--- tests/unit/test_app_discovery.py 2015-12-22 17:28:10 +0000
+++ tests/unit/test_app_discovery.py 1970-01-01 00:00:00 +0000
@@ -1,52 +0,0 @@
1"""Unit tests for the AppLauncher module."""
2# Copyright 2015 Canonical Ltd.
3#
4# This program is free software: you can redistribute it and/or modify it
5# under the terms of the GNU General Public License version 3, as published
6# by the Free Software Foundation.
7#
8# This program is distributed in the hope that it will be useful, but
9# WITHOUT ANY WARRANTY; without even the implied warranties of
10# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11# PURPOSE. See the GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.
15
16from libertine.AppDiscovery import IconCache
17from testtools import TestCase
18from testtools.matchers import Equals
19
20
21class TestIconSearching(TestCase):
22
23 def mock_file_loader(self, root_path):
24 return [
25 "/some/path/128x128/icon.png",
26 "/somepath/icon.png",
27 "/somepath/testme.png"
28 ];
29
30 def test_full_path(self):
31 some_root = "/some_root"
32 icon_cache = IconCache(some_root, file_loader=self.mock_file_loader)
33
34 some_full_path = "/this/is/a/full/path"
35 self.assertThat(icon_cache.expand_icons(some_full_path)[0],
36 Equals(some_full_path))
37
38 def test_icon_name(self):
39 some_root = "/some_root"
40 icon_cache = IconCache(some_root, file_loader=self.mock_file_loader)
41
42 some_icon_list = "testme"
43 self.assertThat(icon_cache.expand_icons(some_icon_list)[0],
44 Equals("/somepath/testme.png"))
45
46 def test_edge_case_relative_file_name(self):
47 some_root = "/some_root"
48 icon_cache = IconCache(some_root, file_loader=self.mock_file_loader)
49
50 some_icon_list = "testme.png"
51 self.assertThat(icon_cache.expand_icons(some_icon_list)[0],
52 Equals("/somepath/testme.png"))
530
=== modified file 'tools/libertine-container-manager'
--- tools/libertine-container-manager 2017-02-01 21:13:14 +0000
+++ tools/libertine-container-manager 2017-02-07 13:30:52 +0000
@@ -17,8 +17,9 @@
17# along with this program. If not, see <http://www.gnu.org/licenses/>.17# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
19import argparse19import argparse
20import getpass
21import json
20import libertine.utils22import libertine.utils
21import getpass
22import os23import os
23import sys24import sys
24import re25import re
@@ -224,8 +225,12 @@
224 def list_apps(self, args):225 def list_apps(self, args):
225 container_id = self.containers_config.check_container_id(args.id)226 container_id = self.containers_config.check_container_id(args.id)
226227
227 container = LibertineContainer(container_id)228 app_ids = LibertineContainer(container_id).list_app_ids()
228 print(container.list_app_launchers(use_json=args.json))229 if args.json:
230 print(json.dumps(app_ids))
231 else:
232 for app in app_ids:
233 print(app)
229234
230 def exec(self, args):235 def exec(self, args):
231 container_id = self.containers_config.check_container_id(args.id)236 container_id = self.containers_config.check_container_id(args.id)

Subscribers

People subscribed via source and target branches