Merge lp:~mvo/software-center/get-installed-apps-instead-of-pkgs into lp:software-center
- get-installed-apps-instead-of-pkgs
- Merge into trunk
Proposed by
Michael Vogt
Status: | Merged |
---|---|
Merged at revision: | 2783 |
Proposed branch: | lp:~mvo/software-center/get-installed-apps-instead-of-pkgs |
Merge into: | lp:software-center |
Diff against target: |
326 lines (+118/-43) 6 files modified
softwarecenter/backend/recagent.py (+46/-7) softwarecenter/db/database.py (+7/-0) softwarecenter/db/utils.py (+11/-0) softwarecenter/ui/gtk3/widgets/recommendations.py (+8/-29) test/test_database.py (+13/-0) test/test_recagent.py (+33/-7) |
To merge this branch: | bzr merge lp:~mvo/software-center/get-installed-apps-instead-of-pkgs |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gary Lasker (community) | Approve | ||
Review via email: mp+93573@code.launchpad.net |
Commit message
Description of the change
This branch adds a mock test and moves the logic into the backend.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'softwarecenter/backend/recagent.py' |
2 | --- softwarecenter/backend/recagent.py 2012-02-13 01:27:59 +0000 |
3 | +++ softwarecenter/backend/recagent.py 2012-02-17 14:27:17 +0000 |
4 | @@ -25,6 +25,10 @@ |
5 | import softwarecenter.paths |
6 | from spawn_helper import SpawnHelper |
7 | |
8 | +from softwarecenter.config import get_config |
9 | +from softwarecenter.db.utils import get_installed_apps_list |
10 | +from softwarecenter.utils import get_uuid |
11 | + |
12 | LOG = logging.getLogger(__name__) |
13 | |
14 | class RecommenderAgent(GObject.GObject): |
15 | @@ -38,11 +42,11 @@ |
16 | GObject.TYPE_NONE, |
17 | (GObject.TYPE_PYOBJECT,), |
18 | ), |
19 | - "submit-profile" : (GObject.SIGNAL_RUN_LAST, |
20 | + "submit-profile-finished" : (GObject.SIGNAL_RUN_LAST, |
21 | GObject.TYPE_NONE, |
22 | - (GObject.TYPE_PYOBJECT,), |
23 | + (GObject.TYPE_PYOBJECT, str), |
24 | ), |
25 | - "submit-anon-profile" : (GObject.SIGNAL_RUN_LAST, |
26 | + "submit-anon-profile-finished" : (GObject.SIGNAL_RUN_LAST, |
27 | GObject.TYPE_NONE, |
28 | (GObject.TYPE_PYOBJECT,), |
29 | ), |
30 | @@ -68,9 +72,30 @@ |
31 | ), |
32 | } |
33 | |
34 | - def __init__(self, xid=None): |
35 | + def __init__(self, db, xid=None): |
36 | GObject.GObject.__init__(self) |
37 | self.xid = xid |
38 | + self.db = db |
39 | + self.recommender_uuid = "" |
40 | + |
41 | + def _get_recommender_uuid(self): |
42 | + # FIXME: probs should just pass this on in instead of reading config |
43 | + config = get_config() |
44 | + if config.has_option("general", "recommender_uuid"): |
45 | + self.recommender_uuid = config.get("general", |
46 | + "recommender_uuid") |
47 | + else: |
48 | + self.recommender_uuid = get_uuid() |
49 | + return self.recommender_uuid |
50 | + |
51 | + def _generate_submit_profile_data(self, recommender_uuid, package_list): |
52 | + submit_profile_data = [ |
53 | + { |
54 | + 'uuid': recommender_uuid, |
55 | + 'package_list': package_list |
56 | + } |
57 | + ] |
58 | + return submit_profile_data |
59 | |
60 | def query_server_status(self): |
61 | # build the command |
62 | @@ -82,7 +107,17 @@ |
63 | spawner.run_generic_piston_helper( |
64 | "SoftwareCenterRecommenderAPI", "server_status") |
65 | |
66 | - def query_submit_profile(self, data): |
67 | + def post_submit_profile(self): |
68 | + """ This will post the users profile to the recommender server |
69 | + and also generate the UUID for the user if that is not |
70 | + there yet |
71 | + """ |
72 | + # garther the data |
73 | + recommender_uuid = self._get_recommender_uuid() |
74 | + installed_pkglist = [app.pkgname |
75 | + for app in get_installed_apps_list(self.db)] |
76 | + data = self._generate_submit_profile_data( |
77 | + recommender_uuid, installed_pkglist) |
78 | # build the command |
79 | spawner = SpawnHelper() |
80 | spawner.parent_xid = self.xid |
81 | @@ -94,7 +129,7 @@ |
82 | "submit_profile", |
83 | data=data) |
84 | |
85 | - def query_submit_anon_profile(self, uuid, installed_packages, extra): |
86 | + def post_submit_anon_profile(self, uuid, installed_packages, extra): |
87 | # build the command |
88 | spawner = SpawnHelper() |
89 | spawner.parent_xid = self.xid |
90 | @@ -166,7 +201,11 @@ |
91 | self.emit("profile", piston_profile) |
92 | |
93 | def _on_submit_profile_data(self, spawner, piston_submit_profile): |
94 | - self.emit("submit-profile", piston_submit_profile) |
95 | + self.emit("submit-profile-finished", |
96 | + piston_submit_profile, |
97 | + # FIXME: do we need this or is this part of the |
98 | + # piston_submit_profile response? |
99 | + self.recommender_uuid) |
100 | |
101 | def _on_submit_anon_profile_data(self, spawner, piston_submit_anon_profile): |
102 | self.emit("submit-anon_profile", piston_submit_anon_profile) |
103 | |
104 | === modified file 'softwarecenter/db/database.py' |
105 | --- softwarecenter/db/database.py 2012-01-03 11:27:15 +0000 |
106 | +++ softwarecenter/db/database.py 2012-02-17 14:27:17 +0000 |
107 | @@ -374,6 +374,13 @@ |
108 | pass |
109 | return summary |
110 | |
111 | + def get_application(self, doc): |
112 | + """ Return a application from a xapian document """ |
113 | + appname = self.get_appname(doc) |
114 | + pkgname = self.get_pkgname(doc) |
115 | + iconname = self.get_iconname(doc) |
116 | + return Application(appname, pkgname, iconname) |
117 | + |
118 | def get_pkgname(self, doc): |
119 | """ Return a packagename from a xapian document """ |
120 | pkgname = doc.get_value(XapianValues.PKGNAME) |
121 | |
122 | === modified file 'softwarecenter/db/utils.py' |
123 | --- softwarecenter/db/utils.py 2012-02-15 09:06:51 +0000 |
124 | +++ softwarecenter/db/utils.py 2012-02-17 14:27:17 +0000 |
125 | @@ -30,6 +30,17 @@ |
126 | xapian.Query("AP"+pkgname)) |
127 | return query |
128 | |
129 | +def get_installed_apps_list(db): |
130 | + """ return a list of installed applications """ |
131 | + apps = set() |
132 | + for doc in db: |
133 | + if db.get_appname(doc): |
134 | + pkgname = db.get_pkgname(doc) |
135 | + if (pkgname in db._aptcache and |
136 | + db._aptcache[pkgname].is_installed): |
137 | + apps.add(db.get_application(doc)) |
138 | + return apps |
139 | + |
140 | def get_installed_package_list(): |
141 | """ return a set of all of the currently installed packages """ |
142 | from softwarecenter.db.pkginfo import get_pkg_info |
143 | |
144 | === modified file 'softwarecenter/ui/gtk3/widgets/recommendations.py' |
145 | --- softwarecenter/ui/gtk3/widgets/recommendations.py 2012-02-15 15:40:41 +0000 |
146 | +++ softwarecenter/ui/gtk3/widgets/recommendations.py 2012-02-17 14:27:17 +0000 |
147 | @@ -28,9 +28,7 @@ |
148 | from softwarecenter.db.categories import (RecommendedForYouCategory, |
149 | AppRecommendationsCategory) |
150 | from softwarecenter.backend.recagent import RecommenderAgent |
151 | -from softwarecenter.db.utils import get_installed_package_list |
152 | -from softwarecenter.utils import get_uuid |
153 | -from softwarecenter.config import get_config |
154 | + |
155 | |
156 | LOG = logging.getLogger(__name__) |
157 | |
158 | @@ -80,17 +78,12 @@ |
159 | RecommendationsPanel.__init__(self, catview) |
160 | self.set_header_label(_(u"Recommended for You")) |
161 | |
162 | - self.recommender_uuid = "" |
163 | - # FIXME: probs should just pass this on in instead of reading config |
164 | config = get_config() |
165 | if config.has_option("general", "recommender_uuid"): |
166 | - self.recommender_uuid = config.get("general", |
167 | - "recommender_uuid") |
168 | - |
169 | - if not self.recommender_uuid: |
170 | + self.recommender_uuid = config.get("general", "recommender_uuid") |
171 | + self._update_recommended_for_you_content() |
172 | + else: |
173 | self._show_opt_in_view() |
174 | - else: |
175 | - self._update_recommended_for_you_content() |
176 | |
177 | self.add(self.recommended_for_you_content) |
178 | self.header_implements_more_button() |
179 | @@ -132,22 +125,18 @@ |
180 | def _upload_user_profile(self): |
181 | self.spinner.set_text(_("Submitting inventory…")) |
182 | self.show_spinner() |
183 | - self.recommender_uuid = get_uuid() |
184 | - installed_pkglist = list(get_installed_package_list()) |
185 | - self.recommender_agent.connect("submit-profile", |
186 | + self.recommender_agent.connect("submit-profile-finished", |
187 | self._on_profile_submitted) |
188 | self.recommender_agent.connect("error", |
189 | self._on_profile_submitted_error) |
190 | - self.recommender_agent.query_submit_profile( |
191 | - self._generate_submit_profile_data(self.recommender_uuid, |
192 | - installed_pkglist)) |
193 | + self.recommender_agent.do_submit_profile() |
194 | |
195 | - def _on_profile_submitted(self): |
196 | + def _on_profile_submitted(self, agent, profile, recommender_uuid): |
197 | # after the user profile data has been uploaded, make the request |
198 | # and load the the recommended_for_you content |
199 | LOG.debug("The recommendations profile has been successfully " |
200 | "submitted to the recommender agent") |
201 | - self.emit("recommendations-opt-in", self.recommender_uuid) |
202 | + self.emit("recommendations-opt-in", recommender_uuid) |
203 | self._update_recommended_for_you_content() |
204 | |
205 | def _on_profile_submitted_error(self, agent, msg): |
206 | @@ -195,16 +184,6 @@ |
207 | # and hide the pane |
208 | self.hide() |
209 | |
210 | - def _generate_submit_profile_data(self, |
211 | - recommender_uuid, |
212 | - package_list): |
213 | - submit_profile_data = [ |
214 | - { |
215 | - 'uuid': recommender_uuid, |
216 | - 'package_list': package_list |
217 | - } |
218 | - ] |
219 | - return submit_profile_data |
220 | |
221 | class RecommendationsPanelDetails(RecommendationsPanel): |
222 | """ |
223 | |
224 | === modified file 'test/test_database.py' |
225 | --- test/test_database.py 2012-02-15 16:55:32 +0000 |
226 | +++ test/test_database.py 2012-02-17 14:27:17 +0000 |
227 | @@ -458,11 +458,24 @@ |
228 | self.assertTrue(len(enquirer.get_docids()) > 0) |
229 | # FIXME: test more of the interface |
230 | |
231 | +class UtilsTestCase(unittest.TestCase): |
232 | + |
233 | def test_utils_get_installed_package_list(self): |
234 | from softwarecenter.db.utils import get_installed_package_list |
235 | installed_pkgs = get_installed_package_list() |
236 | self.assertTrue(len(installed_pkgs) > 0) |
237 | |
238 | + def test_utils_get_installed_apps_list(self): |
239 | + from softwarecenter.db.utils import ( |
240 | + get_installed_package_list,get_installed_apps_list) |
241 | + db = get_test_db() |
242 | + # installed pkgs |
243 | + installed_pkgs = get_installed_package_list() |
244 | + # the installed apps |
245 | + installed_apps = get_installed_apps_list(db) |
246 | + self.assertTrue(len(installed_apps) > 0) |
247 | + self.assertTrue(len(installed_pkgs) > len(installed_apps)) |
248 | + |
249 | |
250 | def make_purchased_app_details(db=None, supported_series=None): |
251 | """Return an AppDetail instance with the required attributes.""" |
252 | |
253 | === modified file 'test/test_recagent.py' |
254 | --- test/test_recagent.py 2012-02-15 17:06:32 +0000 |
255 | +++ test/test_recagent.py 2012-02-17 14:27:17 +0000 |
256 | @@ -3,13 +3,19 @@ |
257 | from gi.repository import GObject |
258 | import unittest |
259 | import os |
260 | +import uuid |
261 | + |
262 | +from mock import patch |
263 | |
264 | from testutils import setup_test_env |
265 | setup_test_env() |
266 | |
267 | from softwarecenter.backend.recagent import RecommenderAgent |
268 | |
269 | -from softwarecenter.testutils import make_recommender_profile_upload_data |
270 | +from softwarecenter.testutils import ( |
271 | + make_recommender_profile_upload_data, |
272 | + get_test_db, |
273 | +) |
274 | |
275 | class TestRecommenderAgent(unittest.TestCase): |
276 | """ tests the recommender agent """ |
277 | @@ -27,7 +33,26 @@ |
278 | else: |
279 | os.environ["SOFTWARE_CENTER_RECOMMENDER_HOST"] = self.orig_host |
280 | |
281 | - def on_query_done(self, recagent, data): |
282 | + @patch('softwarecenter.backend.recagent.SpawnHelper' |
283 | + '.run_generic_piston_helper') |
284 | + def test_mocked_recagent_post_submit_profile(self, mock_spawn_helper_run): |
285 | + def _patched_on_submit_profile_data(*args, **kwargs): |
286 | + piston_submit_profile = {} |
287 | + recommender_agent.emit("submit-profile-finished", |
288 | + piston_submit_profile, |
289 | + uuid.uuid1()) |
290 | + mock_spawn_helper_run.side_effect = _patched_on_submit_profile_data |
291 | + db = get_test_db() |
292 | + recommender_agent = RecommenderAgent(db) |
293 | + recommender_agent.connect("submit-profile-finished", self.on_query_done) |
294 | + recommender_agent.connect("error", self.on_query_error) |
295 | + recommender_agent.post_submit_profile() |
296 | + self.assertFalse(self.error) |
297 | + args, kwargs = mock_spawn_helper_run.call_args |
298 | + self.assertNotEqual(kwargs['data'][0]['uuid'], None) |
299 | + self.assertNotEqual(kwargs['data'][0]['package_list'], []) |
300 | + |
301 | + def on_query_done(self, recagent, data, uuid=""): |
302 | print "query done, data: '%s'" % data |
303 | self.loop.quit() |
304 | |
305 | @@ -45,15 +70,16 @@ |
306 | self.loop.run() |
307 | self.assertFalse(self.error) |
308 | |
309 | - # FIXME: disabled for now as the server is not quite working |
310 | - def disabled_test_recagent_query_submit_profile(self): |
311 | + def disabled_test_recagent_post_submit_profile(self, mock_request): |
312 | # NOTE: This requires a working recommender host that is reachable |
313 | - recommender_agent = RecommenderAgent() |
314 | - recommender_agent.connect("submit-profile", self.on_query_done) |
315 | + db = get_test_db() |
316 | + recommender_agent = RecommenderAgent(db) |
317 | + recommender_agent.connect("submit-profile-finished", self.on_query_done) |
318 | recommender_agent.connect("error", self.on_query_error) |
319 | - recommender_agent.query_submit_profile(data=make_recommender_profile_upload_data()) |
320 | + recommender_agent.post_submit_profile() |
321 | self.loop.run() |
322 | self.assertFalse(self.error) |
323 | + #print mock_request._post |
324 | |
325 | # def disabled_test_recagent_query_submit_anon_profile(self): |
326 | # # NOTE: This requires a working recommender host that is reachable |
Hi mvo!! Thanks for this! I found some test failures and so made a few updates to fix these and also made other small needed fixes. I took the opportunity to do a bit of additional refactoring/ simplifying as well to fully move the recommender UUID into the backend code.
You can see the updates that I made in my branch lp:~gary-lasker/software-center/get-installed-apps-instead-of-pkgs-tweaks.
The new test is really cool, and this is a nice bit of refactoring, thank you again!