Merge lp:~mvo/software-center/get-installed-apps-instead-of-pkgs into lp:software-center

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
Reviewer Review Type Date Requested Status
Gary Lasker (community) Approve
Review via email: mp+93573@code.launchpad.net

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.
Revision history for this message
Gary Lasker (gary-lasker) wrote :

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!

review: Approve

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

Subscribers

People subscribed via source and target branches