Merge lp:~gary-lasker/software-center/recommended-installed-feedback into lp:software-center
- recommended-installed-feedback
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~gary-lasker/software-center/recommended-installed-feedback |
Merge into: | lp:software-center |
Prerequisite: | lp:~gary-lasker/software-center/update-to-latest-recommender-client |
Diff against target: |
321 lines (+145/-23) 6 files modified
softwarecenter/backend/piston/sreclient_pristine.py (+1/-1) softwarecenter/backend/recagent.py (+24/-1) softwarecenter/enums.py (+4/-0) softwarecenter/ui/gtk3/widgets/recommendations.py (+33/-0) tests/gtk3/test_catview.py (+73/-21) tests/test_recagent.py (+10/-0) |
To merge this branch: | bzr merge lp:~gary-lasker/software-center/recommended-installed-feedback |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
software-store-developers | Pending | ||
Review via email: mp+121539@code.launchpad.net |
This proposal has been superseded by a proposal from 2012-08-30.
Commit message
* lp:~gary-lasker/software-center/recommended-installed-feedback:
- signal the recommender service when a recommended item has been
successfully installed (LP: #944060)
Description of the change
This branch implements the "implicit" recommender feedback feature. It detects the case where the user successfully installs a recommended item and fires a "submit_
This is the client-side implementation for bug 944060.
Note that this branch depends on the lp:~gary-lasker/software-center/update-to-latest-recommender-client branch as that branch adds the new recommender client code from lp:~canonical-ca-hackers/ubuntu-recommender/ubuntu-recommender-client. Also note that I made one small change to sreclient to fix the validate decorator for the pkgname argument to implicit_feedback so that it matches the validator for the other calls that use pkgname as an argument.
Finally, I added a unit test for the new call in test_recagent.py, however like a few of the other tests there, the test is not currently working with the server. Therefore, it remains disabled as the other tests are. I'll look at this tomorrow to try to see what the issue is with these tests.
Meanwhile, everything here should be working. To test, just select any recommended item in the lobby or category views and install it. Once the installation is complete, the corresponding implicit_feedback call will be fired.
Many thanks for your review!
Michael Vogt (mvo) wrote : | # |
- 3088. By Gary Lasker
-
merge latest lp:~gary-lasker/software-center/update-to-latest-recommender-client for changes there after review
Gary Lasker (gary-lasker) wrote : | # |
Just a note that I have a branch for review with the recommender-client changes that I mentioned above (and that have been made to sreclient_
- 3089. By Gary Lasker
-
use a class for RecommenderFeed
backActions - 3090. By Gary Lasker
-
pep8 fixes
- 3091. By Gary Lasker
-
merge trunk and resolve conflicts
- 3092. By Gary Lasker
-
use a set rather than a list for self.recommende
d_apps_ viewed - 3093. By Gary Lasker
-
consolidate some duplicated code, other cleanup, add a new unit test for the recommender implicit feedback functionality
Gary Lasker (gary-lasker) wrote : | # |
> On Tue, Aug 28, 2012 at 05:46:23AM -0000, Gary Lasker wrote:
> > Gary Lasker has proposed merging lp:~gary-lasker/software-center
> /recommended-
> /software-
>
> Thanks for working on this branch. I'm very happy to see this feature
> coming.
>
> [..]
> > Note that this branch depends on the lp:~gary-lasker/software-center/update-
> to-latest-
> client code from lp:~canonical-ca-hackers/ubuntu-recommender/ubuntu-
> recommender-client. Also note that I made one small change to sreclient to fix
> the validate decorator for the pkgname argument to implicit_feedback so that
> it matches the validator for the other calls that use pkgname as an argument.
>
> Thanks for this, if you fixed the sreclient_
> send the diff to the server team (if you haven't done already) so that
> they add it to their
> lp:~canonical-ca-hackers/ubuntu-recommender/ubuntu-recommender-client
> branch.
Yep, I proposed a branch for this and it has been merged by Lukasz.
>
> > Finally, I added a unit test for the new call in test_recagent.py, however
> like a few of the other tests there, the test is not currently working with
> the server. Therefore, it remains disabled as the other tests are. I'll look
> at this tomorrow to try to see what the issue is with these tests.
> [..]
>
> Maybe the staging server had problems. I just tested enabling them and
> its working, but that may well be that its now fixed. While looking at
> the test code I noticed that there is a bit of duplication in
> there, I pushed a branch at
> lp:~mvo/software-center/recagent-test-cleanup that removes most of
> that.
>
> I also noticed that the branch is missing a test for the new
> functionality, it would be nice to add one to
> tests/gtk3/
> app, trigger a install transaction and verify that on finish the
> self.recommende
>
I added a thorough test for this functionality in test_catview.py (this is where the other recommendations panel tests are, and imo it's consistent because the tests for the other lobby panels (What's New and Top Rated) are also located here. While in test_catview.py I did some cleanup and consolidation of duplicated code as well.
> > @@ -244,7 +262,7 @@
> >
> > def _on_submit_
> > piston_
> > - self.emit(
> > + self.emit(
> piston_
>
> Nice that this is more consistent now (plus that it will actually work).
>
> > === modified file 'softwarecenter
> > --- softwarecenter/
> > +++ softwarecenter/
> > @@ -299,6 +299,9 @@
> > LOBBY_RECOMMEND
> > DETAILS_
> >
> > +# action values for recommendations implicit f...
Gary Lasker (gary-lasker) wrote : | # |
Oops, I noticed a typo in my last comment:
"...when a person clicks on a recommended item, we remember that they did that for that item for as long as the current USC session is active (it is now, however, persisted between sessions, I think would be a mistake)."
Should be (see the "*not*"):
"...when a person clicks on a recommended item, we remember that they did that for that item for as long as the current USC session is active (it is *not*, however, persisted between sessions, I think would be a mistake)."
Though maybe this was obvious, but I wanted to make sure that I'm clear.
Thanks again!
- 3094. By Gary Lasker
-
add a test to insure that no recommender feedback call occurs in the case where the user is *not* opted in to the recommender service
- 3095. By Gary Lasker
-
merge with trunk
Michael Vogt (mvo) wrote : | # |
On Thu, Aug 30, 2012 at 09:25:21PM -0000, Gary Lasker wrote:
> > On Tue, Aug 28, 2012 at 05:46:23AM -0000, Gary Lasker wrote:
> > > Gary Lasker has proposed merging lp:~gary-lasker/software-center
> > /recommended-
> > /software-
> >
> > Thanks for working on this branch. I'm very happy to see this feature
> > coming.
> >
> > [..]
> > > Note that this branch depends on the lp:~gary-lasker/software-center/update-
> > to-latest-
> > client code from lp:~canonical-ca-hackers/ubuntu-recommender/ubuntu-
> > recommender-client. Also note that I made one small change to sreclient to fix
> > the validate decorator for the pkgname argument to implicit_feedback so that
> > it matches the validator for the other calls that use pkgname as an argument.
> >
> > Thanks for this, if you fixed the sreclient_
> > send the diff to the server team (if you haven't done already) so that
> > they add it to their
> > lp:~canonical-ca-hackers/ubuntu-recommender/ubuntu-recommender-client
> > branch.
>
> Yep, I proposed a branch for this and it has been merged by Lukasz.
Great, thanks for this.
> > > Finally, I added a unit test for the new call in test_recagent.py, however
> > like a few of the other tests there, the test is not currently working with
> > the server. Therefore, it remains disabled as the other tests are. I'll look
> > at this tomorrow to try to see what the issue is with these tests.
> > [..]
> >
> > Maybe the staging server had problems. I just tested enabling them and
> > its working, but that may well be that its now fixed. While looking at
> > the test code I noticed that there is a bit of duplication in
> > there, I pushed a branch at
> > lp:~mvo/software-center/recagent-test-cleanup that removes most of
> > that.
> >
> > I also noticed that the branch is missing a test for the new
> > functionality, it would be nice to add one to
> > tests/gtk3/
> > app, trigger a install transaction and verify that on finish the
> > self.recommende
> >
>
> I added a thorough test for this functionality in test_catview.py (this is where the other recommendations panel tests are, and imo it's consistent because the tests for the other lobby panels (What's New and Top Rated) are also located here. While in test_catview.py I did some cleanup and consolidation of duplicated code as well.
Thanks for adding the test and for the cleanup there, that looks very
good!
[..]
> > Should self.recommende
> > e.g on _on_app_
> > function for the categories). Or should this be persistent? I'm don't
> > know the details of the spec well enough :) I guess it comes down to
> > if we should consider it a recommendation that are reached
> > "indirectly", e.g. click on it "app A", move back to main view search
> > for something else and then reach "app A" again late...
- 3096. By Gary Lasker
-
RED: add a failing test to show that the implicit recommender call is incorrectly being made from the top rated panel
- 3097. By Gary Lasker
-
the fix for the failing test case is to do the refactoring that we know is needed in CategoriesViewGtk to move the add_tiles_
to_flowgrid and corresponding on_application_ selected methods to where they belong, specifically, to the FlowableGrid class itself, this commit contains the brunt of this refactor, but there are some additional pieces needed to finish it up - 3098. By Gary Lasker
-
GREEN: essential refactor complete and signals wired up, all test cases now working; removed the unused (with FIXME) 'application-
selected' signal from catview as it is not used there (we only 'activate' apps from this widget), fix single-line cut-and-paste error in the test case - 3099. By Gary Lasker
-
REFACTOR: make a new TileGrid subclass of FlowableGrid so that FlowableGrid remains generic, wire up the TileGrid for the various panels that it is used
- 3100. By Gary Lasker
-
REFACTOR: remove all need for the catview in the recommendations code
- 3101. By Gary Lasker
-
don't use hasattr in the FramedHeaderBox so that we can attach listeners to the more button when we need to, connect listeners for this, add a signal to the RecommenderPane
lCategory (and subclass RecommenderPane lLobby) so that we can get their correct categories when clicking 'More' in those - 3102. By Gary Lasker
-
pep8 fixes
- 3103. By Gary Lasker
-
merge with trunk
- 3104. By Gary Lasker
-
clean up get_test_
window_ recommendations in windows.py per the new factoring - 3105. By Gary Lasker
-
move the application-
activated signal into the TileGrid subclass where it belongs - 3106. By Gary Lasker
-
make a docstring more better per review comment
- 3107. By Gary Lasker
-
merge with trunk, don't wanna cruft
Unmerged revisions
Preview Diff
1 | === modified file 'softwarecenter/backend/piston/sreclient_pristine.py' | |||
2 | --- softwarecenter/backend/piston/sreclient_pristine.py 2012-08-28 18:16:47 +0000 | |||
3 | +++ softwarecenter/backend/piston/sreclient_pristine.py 2012-08-30 20:56:21 +0000 | |||
4 | @@ -84,7 +84,7 @@ | |||
5 | 84 | scheme=AUTHENTICATED_API_SCHEME) | 84 | scheme=AUTHENTICATED_API_SCHEME) |
6 | 85 | 85 | ||
7 | 86 | @oauth_protected | 86 | @oauth_protected |
9 | 87 | @validate('pkgname', str) | 87 | @validate_pattern('pkgname', '[^/]+') |
10 | 88 | @validate_pattern('action', '\w{3,20}') | 88 | @validate_pattern('action', '\w{3,20}') |
11 | 89 | @returns_json | 89 | @returns_json |
12 | 90 | def implicit_feedback(self, pkgname, action): | 90 | def implicit_feedback(self, pkgname, action): |
13 | 91 | 91 | ||
14 | === modified file 'softwarecenter/backend/recagent.py' | |||
15 | --- softwarecenter/backend/recagent.py 2012-08-29 18:05:52 +0000 | |||
16 | +++ softwarecenter/backend/recagent.py 2012-08-30 20:56:21 +0000 | |||
17 | @@ -68,6 +68,10 @@ | |||
18 | 68 | GObject.TYPE_NONE, | 68 | GObject.TYPE_NONE, |
19 | 69 | (GObject.TYPE_PYOBJECT,), | 69 | (GObject.TYPE_PYOBJECT,), |
20 | 70 | ), | 70 | ), |
21 | 71 | "submit-implicit-feedback-finished": (GObject.SIGNAL_RUN_LAST, | ||
22 | 72 | GObject.TYPE_NONE, | ||
23 | 73 | (GObject.TYPE_PYOBJECT,), | ||
24 | 74 | ), | ||
25 | 71 | "error": (GObject.SIGNAL_RUN_LAST, | 75 | "error": (GObject.SIGNAL_RUN_LAST, |
26 | 72 | GObject.TYPE_NONE, | 76 | GObject.TYPE_NONE, |
27 | 73 | (str,), | 77 | (str,), |
28 | @@ -215,6 +219,20 @@ | |||
29 | 215 | spawner.run_generic_piston_helper( | 219 | spawner.run_generic_piston_helper( |
30 | 216 | "SoftwareCenterRecommenderAPI", "recommend_top") | 220 | "SoftwareCenterRecommenderAPI", "recommend_top") |
31 | 217 | 221 | ||
32 | 222 | def post_implicit_feedback(self, pkgname, action): | ||
33 | 223 | # build the command | ||
34 | 224 | spawner = SpawnHelper() | ||
35 | 225 | spawner.parent_xid = self.xid | ||
36 | 226 | spawner.needs_auth = True | ||
37 | 227 | spawner.connect("data-available", | ||
38 | 228 | self._on_submit_implicit_feedback_data) | ||
39 | 229 | spawner.connect("error", lambda spawner, err: self.emit("error", err)) | ||
40 | 230 | spawner.run_generic_piston_helper( | ||
41 | 231 | "SoftwareCenterRecommenderAPI", | ||
42 | 232 | "implicit_feedback", | ||
43 | 233 | pkgname=pkgname, | ||
44 | 234 | action=action) | ||
45 | 235 | |||
46 | 218 | def is_opted_in(self): | 236 | def is_opted_in(self): |
47 | 219 | """ | 237 | """ |
48 | 220 | Return True is the user is currently opted-in to the recommender | 238 | Return True is the user is currently opted-in to the recommender |
49 | @@ -244,7 +262,7 @@ | |||
50 | 244 | 262 | ||
51 | 245 | def _on_submit_anon_profile_data(self, spawner, | 263 | def _on_submit_anon_profile_data(self, spawner, |
52 | 246 | piston_submit_anon_profile): | 264 | piston_submit_anon_profile): |
54 | 247 | self.emit("submit-anon_profile", piston_submit_anon_profile) | 265 | self.emit("submit-anon-profile-finished", piston_submit_anon_profile) |
55 | 248 | 266 | ||
56 | 249 | def _on_recommend_me_data(self, spawner, piston_me_apps): | 267 | def _on_recommend_me_data(self, spawner, piston_me_apps): |
57 | 250 | self.emit("recommend-me", piston_me_apps) | 268 | self.emit("recommend-me", piston_me_apps) |
58 | @@ -258,6 +276,11 @@ | |||
59 | 258 | def _on_recommend_top_data(self, spawner, piston_top_apps): | 276 | def _on_recommend_top_data(self, spawner, piston_top_apps): |
60 | 259 | self.emit("recommend-top", piston_top_apps) | 277 | self.emit("recommend-top", piston_top_apps) |
61 | 260 | 278 | ||
62 | 279 | def _on_submit_implicit_feedback_data(self, spawner, | ||
63 | 280 | piston_submit_implicit_feedback): | ||
64 | 281 | self.emit("submit-implicit-feedback-finished", | ||
65 | 282 | piston_submit_implicit_feedback) | ||
66 | 283 | |||
67 | 261 | def _generate_submit_profile_data(self, recommender_uuid, package_list): | 284 | def _generate_submit_profile_data(self, recommender_uuid, package_list): |
68 | 262 | submit_profile_data = [{ | 285 | submit_profile_data = [{ |
69 | 263 | 'uuid': recommender_uuid, | 286 | 'uuid': recommender_uuid, |
70 | 264 | 287 | ||
71 | === modified file 'softwarecenter/enums.py' | |||
72 | --- softwarecenter/enums.py 2012-08-23 14:37:28 +0000 | |||
73 | +++ softwarecenter/enums.py 2012-08-30 20:56:21 +0000 | |||
74 | @@ -282,6 +282,10 @@ | |||
75 | 282 | PACKAGE = "," | 282 | PACKAGE = "," |
76 | 283 | 283 | ||
77 | 284 | 284 | ||
78 | 285 | # action values for recommendations feedback | ||
79 | 286 | class RecommenderFeedbackActions: | ||
80 | 287 | INSTALLED = "installed" | ||
81 | 288 | |||
82 | 285 | # mouse event codes for back/forward buttons | 289 | # mouse event codes for back/forward buttons |
83 | 286 | # TODO: consider whether we ought to get these values from gconf so that we | 290 | # TODO: consider whether we ought to get these values from gconf so that we |
84 | 287 | # can be sure to use the corresponding values used by Nautilus: | 291 | # can be sure to use the corresponding values used by Nautilus: |
85 | 288 | 292 | ||
86 | === modified file 'softwarecenter/ui/gtk3/widgets/recommendations.py' | |||
87 | --- softwarecenter/ui/gtk3/widgets/recommendations.py 2012-08-22 08:16:30 +0000 | |||
88 | +++ softwarecenter/ui/gtk3/widgets/recommendations.py 2012-08-30 20:56:21 +0000 | |||
89 | @@ -28,6 +28,7 @@ | |||
90 | 28 | from softwarecenter.ui.gtk3.utils import get_parent_xid | 28 | from softwarecenter.ui.gtk3.utils import get_parent_xid |
91 | 29 | from softwarecenter.db.categories import (RecommendedForYouCategory, | 29 | from softwarecenter.db.categories import (RecommendedForYouCategory, |
92 | 30 | AppRecommendationsCategory) | 30 | AppRecommendationsCategory) |
93 | 31 | from softwarecenter.backend import get_install_backend | ||
94 | 31 | from softwarecenter.backend.recagent import RecommenderAgent | 32 | from softwarecenter.backend.recagent import RecommenderAgent |
95 | 32 | from softwarecenter.backend.login_sso import get_sso_backend | 33 | from softwarecenter.backend.login_sso import get_sso_backend |
96 | 33 | from softwarecenter.backend.ubuntusso import get_ubuntu_sso_backend | 34 | from softwarecenter.backend.ubuntusso import get_ubuntu_sso_backend |
97 | @@ -35,6 +36,8 @@ | |||
98 | 35 | LOBBY_RECOMMENDATIONS_CAROUSEL_LIMIT, | 36 | LOBBY_RECOMMENDATIONS_CAROUSEL_LIMIT, |
99 | 36 | DETAILS_RECOMMENDATIONS_CAROUSEL_LIMIT, | 37 | DETAILS_RECOMMENDATIONS_CAROUSEL_LIMIT, |
100 | 37 | SOFTWARE_CENTER_NAME_KEYRING, | 38 | SOFTWARE_CENTER_NAME_KEYRING, |
101 | 39 | RecommenderFeedbackActions, | ||
102 | 40 | TransactionTypes, | ||
103 | 38 | ) | 41 | ) |
104 | 39 | from softwarecenter.utils import utf8 | 42 | from softwarecenter.utils import utf8 |
105 | 40 | from softwarecenter.netstatus import network_state_is_connected | 43 | from softwarecenter.netstatus import network_state_is_connected |
106 | @@ -63,9 +66,39 @@ | |||
107 | 63 | self.catview.connect( | 66 | self.catview.connect( |
108 | 64 | "application-activated", self._on_application_activated) | 67 | "application-activated", self._on_application_activated) |
109 | 65 | self.recommender_agent = RecommenderAgent() | 68 | self.recommender_agent = RecommenderAgent() |
110 | 69 | # keep track of applications that have been viewed via a | ||
111 | 70 | # recommendation so that we can detect when a recommended app | ||
112 | 71 | # has been installed | ||
113 | 72 | self.recommended_apps_viewed = set() | ||
114 | 73 | self.backend = get_install_backend() | ||
115 | 74 | self.backend.connect("transaction-started", | ||
116 | 75 | self._on_transaction_started) | ||
117 | 76 | self.backend.connect("transaction-finished", | ||
118 | 77 | self._on_transaction_finished) | ||
119 | 66 | 78 | ||
120 | 67 | def _on_application_activated(self, catview, app): | 79 | def _on_application_activated(self, catview, app): |
121 | 68 | self.emit("application-activated", app) | 80 | self.emit("application-activated", app) |
122 | 81 | # we only track installed items if the user has opted-in to the | ||
123 | 82 | # recommendations service | ||
124 | 83 | if self.recommender_agent.is_opted_in(): | ||
125 | 84 | self.recommended_apps_viewed.add(app.pkgname) | ||
126 | 85 | |||
127 | 86 | def _on_transaction_started(self, backend, pkgname, appname, trans_id, | ||
128 | 87 | trans_type): | ||
129 | 88 | if (trans_type != TransactionTypes.INSTALL and | ||
130 | 89 | pkgname in self.recommended_apps_viewed): | ||
131 | 90 | # if the transaction is not an installation we don't want to | ||
132 | 91 | # track it as a recommended item | ||
133 | 92 | self.recommended_apps_viewed.remove(pkgname) | ||
134 | 93 | |||
135 | 94 | def _on_transaction_finished(self, backend, result): | ||
136 | 95 | if result.pkgname in self.recommended_apps_viewed: | ||
137 | 96 | self.recommended_apps_viewed.remove(result.pkgname) | ||
138 | 97 | if network_state_is_connected(): | ||
139 | 98 | # no need to monitor for an error, etc., for this | ||
140 | 99 | self.recommender_agent.post_implicit_feedback( | ||
141 | 100 | result.pkgname, | ||
142 | 101 | RecommenderFeedbackActions.INSTALLED) | ||
143 | 69 | 102 | ||
144 | 70 | def _on_recommender_agent_error(self, agent, msg): | 103 | def _on_recommender_agent_error(self, agent, msg): |
145 | 71 | LOG.warn("Error while accessing the recommender agent: %s" % msg) | 104 | LOG.warn("Error while accessing the recommender agent: %s" % msg) |
146 | 72 | 105 | ||
147 | === modified file 'tests/gtk3/test_catview.py' | |||
148 | --- tests/gtk3/test_catview.py 2012-08-28 21:20:40 +0000 | |||
149 | +++ tests/gtk3/test_catview.py 2012-08-30 20:56:21 +0000 | |||
150 | @@ -20,7 +20,9 @@ | |||
151 | 20 | 20 | ||
152 | 21 | from softwarecenter.db.appfilter import AppFilter | 21 | from softwarecenter.db.appfilter import AppFilter |
153 | 22 | from softwarecenter.db.database import StoreDatabase | 22 | from softwarecenter.db.database import StoreDatabase |
155 | 23 | from softwarecenter.enums import SortMethods | 23 | from softwarecenter.enums import (SortMethods, |
156 | 24 | TransactionTypes, | ||
157 | 25 | RecommenderFeedbackActions) | ||
158 | 24 | from softwarecenter.ui.gtk3.views import catview_gtk | 26 | from softwarecenter.ui.gtk3.views import catview_gtk |
159 | 25 | from softwarecenter.ui.gtk3.widgets.containers import FramedHeaderBox | 27 | from softwarecenter.ui.gtk3.widgets.containers import FramedHeaderBox |
160 | 26 | from softwarecenter.ui.gtk3.widgets.spinner import SpinnerNotebook | 28 | from softwarecenter.ui.gtk3.widgets.spinner import SpinnerNotebook |
161 | @@ -35,6 +37,7 @@ | |||
162 | 35 | 37 | ||
163 | 36 | def setUp(self): | 38 | def setUp(self): |
164 | 37 | self._cat = None | 39 | self._cat = None |
165 | 40 | self._app = None | ||
166 | 38 | self.win = get_test_window_catview(self.db) | 41 | self.win = get_test_window_catview(self.db) |
167 | 39 | self.addCleanup(self.win.destroy) | 42 | self.addCleanup(self.win.destroy) |
168 | 40 | self.notebook = self.win.get_child() | 43 | self.notebook = self.win.get_child() |
169 | @@ -121,6 +124,7 @@ | |||
170 | 121 | '.post_submit_profile') | 124 | '.post_submit_profile') |
171 | 122 | def setUp(self, mock_query, mock_recommender_is_opted_in, mock_sso): | 125 | def setUp(self, mock_query, mock_recommender_is_opted_in, mock_sso): |
172 | 123 | self._cat = None | 126 | self._cat = None |
173 | 127 | self._app = None | ||
174 | 124 | # patch the recommender to specify that we are not opted-in at | 128 | # patch the recommender to specify that we are not opted-in at |
175 | 125 | # the start of each test | 129 | # the start of each test |
176 | 126 | mock_recommender_is_opted_in.return_value = False | 130 | mock_recommender_is_opted_in.return_value = False |
177 | @@ -162,11 +166,7 @@ | |||
178 | 162 | mock_network_state_is_connected): | 166 | mock_network_state_is_connected): |
179 | 163 | # simulate no network available | 167 | # simulate no network available |
180 | 164 | mock_network_state_is_connected.return_value = False | 168 | mock_network_state_is_connected.return_value = False |
186 | 165 | # click the opt-in button to initiate the process | 169 | self._populate_recommended_for_you_panel() |
182 | 166 | self.rec_panel.opt_in_button.clicked() | ||
183 | 167 | do_events() | ||
184 | 168 | self.rec_panel._update_recommended_for_you_content() | ||
185 | 169 | do_events() | ||
187 | 170 | self.assertEqual(self.rec_panel.spinner_notebook.get_current_page(), | 170 | self.assertEqual(self.rec_panel.spinner_notebook.get_current_page(), |
188 | 171 | FramedHeaderBox.CONTENT) | 171 | FramedHeaderBox.CONTENT) |
189 | 172 | # ensure that we are showing the network not available view | 172 | # ensure that we are showing the network not available view |
190 | @@ -176,14 +176,9 @@ | |||
191 | 176 | self.rec_panel.NO_NETWORK_RECOMMENDATIONS_TEXT) | 176 | self.rec_panel.NO_NETWORK_RECOMMENDATIONS_TEXT) |
192 | 177 | 177 | ||
193 | 178 | def test_recommended_for_you_display_recommendations(self): | 178 | def test_recommended_for_you_display_recommendations(self): |
200 | 179 | # click the opt-in button to initiate the process, | 179 | self._populate_recommended_for_you_panel() |
195 | 180 | # this will show the spinner | ||
196 | 181 | self.rec_panel.opt_in_button.clicked() | ||
197 | 182 | do_events() | ||
198 | 183 | self.rec_panel._update_recommended_for_you_content() | ||
199 | 184 | do_events() | ||
201 | 185 | # we fake the callback from the agent here | 180 | # we fake the callback from the agent here |
203 | 186 | for_you = self.lobby.recommended_for_you_panel.recommended_for_you_cat | 181 | for_you = self.rec_panel.recommended_for_you_cat |
204 | 187 | for_you._recommend_me_result(None, | 182 | for_you._recommend_me_result(None, |
205 | 188 | make_recommender_agent_recommend_me_dict()) | 183 | make_recommender_agent_recommend_me_dict()) |
206 | 189 | self.assertNotEqual(for_you.get_documents(self.db), []) | 184 | self.assertNotEqual(for_you.get_documents(self.db), []) |
207 | @@ -192,7 +187,7 @@ | |||
208 | 192 | do_events() | 187 | do_events() |
209 | 193 | # test clicking recommended_for_you More button | 188 | # test clicking recommended_for_you More button |
210 | 194 | self.lobby.connect("category-selected", self._on_category_selected) | 189 | self.lobby.connect("category-selected", self._on_category_selected) |
212 | 195 | self.lobby.recommended_for_you_panel.more.clicked() | 190 | self.rec_panel.more.clicked() |
213 | 196 | # this is delayed for some reason so we need to sleep here | 191 | # this is delayed for some reason so we need to sleep here |
214 | 197 | do_events_with_sleep() | 192 | do_events_with_sleep() |
215 | 198 | self.assertNotEqual(self._cat, None) | 193 | self.assertNotEqual(self._cat, None) |
216 | @@ -208,13 +203,8 @@ | |||
217 | 208 | self.assertFalse(visible) | 203 | self.assertFalse(visible) |
218 | 209 | 204 | ||
219 | 210 | def test_recommended_for_you_display_recommendations_opted_in(self): | 205 | def test_recommended_for_you_display_recommendations_opted_in(self): |
227 | 211 | # click the opt-in button to initiate the process, | 206 | self._populate_recommended_for_you_panel() |
228 | 212 | # this will show the spinner | 207 | |
222 | 213 | self.rec_panel.opt_in_button.clicked() | ||
223 | 214 | do_events() | ||
224 | 215 | self.rec_panel._update_recommended_for_you_content() | ||
225 | 216 | do_events() | ||
226 | 217 | |||
229 | 218 | # we want to work in the "subcat" view | 208 | # we want to work in the "subcat" view |
230 | 219 | self.notebook.next_page() | 209 | self.notebook.next_page() |
231 | 220 | 210 | ||
232 | @@ -248,6 +238,68 @@ | |||
233 | 248 | do_events_with_sleep() | 238 | do_events_with_sleep() |
234 | 249 | self.assertNotEqual(self._cat, None) | 239 | self.assertNotEqual(self._cat, None) |
235 | 250 | self.assertEqual(self._cat.name, "Recommended For You in Internet") | 240 | self.assertEqual(self._cat.name, "Recommended For You in Internet") |
236 | 241 | |||
237 | 242 | def test_implicit_recommender_feedback(self): | ||
238 | 243 | self._populate_recommended_for_you_panel() | ||
239 | 244 | # we fake the callback from the agent here | ||
240 | 245 | for_you = self.rec_panel.recommended_for_you_cat | ||
241 | 246 | for_you._recommend_me_result(None, | ||
242 | 247 | make_recommender_agent_recommend_me_dict()) | ||
243 | 248 | do_events() | ||
244 | 249 | |||
245 | 250 | post_implicit_feedback_fn = ('softwarecenter.ui.gtk3.widgets' | ||
246 | 251 | '.recommendations.RecommenderAgent' | ||
247 | 252 | '.post_implicit_feedback') | ||
248 | 253 | with patch(post_implicit_feedback_fn) as mock_post_implicit_feedback: | ||
249 | 254 | # we want to grab the recommended app that is activated | ||
250 | 255 | self.lobby.connect("application-activated", | ||
251 | 256 | self._on_application_activated) | ||
252 | 257 | # click a recommendation in the lobby | ||
253 | 258 | self._click_first_recommended_tile() | ||
254 | 259 | # simulate installing the application | ||
255 | 260 | self._simulate_install_events(self._app) | ||
256 | 261 | # and verify that after the install has completed we have fired | ||
257 | 262 | # the implicit feedback call to the recommender with the correct | ||
258 | 263 | # arguments | ||
259 | 264 | mock_post_implicit_feedback.assert_called_with( | ||
260 | 265 | self._app.pkgname, | ||
261 | 266 | RecommenderFeedbackActions.INSTALLED) | ||
262 | 267 | # finally, make sure that we have cleared the application | ||
263 | 268 | # from the recommended_apps_viewed set | ||
264 | 269 | self.assertFalse(self._app.pkgname in | ||
265 | 270 | self.rec_panel.recommended_apps_viewed) | ||
266 | 271 | |||
267 | 272 | def _populate_recommended_for_you_panel(self): | ||
268 | 273 | # click the opt-in button to initiate the process | ||
269 | 274 | self.rec_panel.opt_in_button.clicked() | ||
270 | 275 | do_events() | ||
271 | 276 | # and update the recommended for you panel to load it up | ||
272 | 277 | self.rec_panel._update_recommended_for_you_content() | ||
273 | 278 | do_events() | ||
274 | 279 | |||
275 | 280 | def _on_application_activated(self, catview, app): | ||
276 | 281 | self._app = app | ||
277 | 282 | |||
278 | 283 | def _click_first_recommended_tile(self): | ||
279 | 284 | rec_item_tile = (self.rec_panel.content_box. | ||
280 | 285 | get_children()[0].get_children()[0]) | ||
281 | 286 | rec_item_tile.on_press(None, None) | ||
282 | 287 | rec_item_tile.on_release(None, None) | ||
283 | 288 | do_events_with_sleep() | ||
284 | 289 | |||
285 | 290 | def _simulate_install_events(self, app): | ||
286 | 291 | # pretend we started an install | ||
287 | 292 | self.rec_panel.backend.emit("transaction-started", | ||
288 | 293 | app.pkgname, app.appname, | ||
289 | 294 | "testid101", | ||
290 | 295 | TransactionTypes.INSTALL) | ||
291 | 296 | do_events_with_sleep() | ||
292 | 297 | # send the signal to complete the install | ||
293 | 298 | mock_result = Mock() | ||
294 | 299 | mock_result.pkgname = app.pkgname | ||
295 | 300 | self.rec_panel.backend.emit("transaction-finished", | ||
296 | 301 | mock_result) | ||
297 | 302 | do_events() | ||
298 | 251 | 303 | ||
299 | 252 | 304 | ||
300 | 253 | class ExhibitsTestCase(unittest.TestCase): | 305 | class ExhibitsTestCase(unittest.TestCase): |
301 | 254 | 306 | ||
302 | === modified file 'tests/test_recagent.py' | |||
303 | --- tests/test_recagent.py 2012-08-29 14:46:51 +0000 | |||
304 | +++ tests/test_recagent.py 2012-08-30 20:56:21 +0000 | |||
305 | @@ -129,6 +129,16 @@ | |||
306 | 129 | self.loop.run() | 129 | self.loop.run() |
307 | 130 | self.assertTrue(self.error) | 130 | self.assertTrue(self.error) |
308 | 131 | 131 | ||
309 | 132 | @unittest.skip("server returns 401") | ||
310 | 133 | def test_recagent_post_implicit_feedback(self): | ||
311 | 134 | self.recommender_agent.connect("submit-implicit-feedback-finished", | ||
312 | 135 | self.on_query_done) | ||
313 | 136 | from softwarecenter.enums import RecommenderFeedbackActions | ||
314 | 137 | self.recommender_agent.post_implicit_feedback( | ||
315 | 138 | "bluefish", | ||
316 | 139 | RecommenderFeedbackActions.INSTALLED) | ||
317 | 140 | self.assertServerReturnsWithNoError() | ||
318 | 141 | |||
319 | 132 | 142 | ||
320 | 133 | if __name__ == "__main__": | 143 | if __name__ == "__main__": |
321 | 134 | #import logging | 144 | #import logging |
On Tue, Aug 28, 2012 at 05:46:23AM -0000, Gary Lasker wrote:
> Gary Lasker has proposed merging lp:~gary-lasker/software-center/recommended-installed-feedback into lp:software-center with lp:~gary-lasker/software-center/update-to-latest-recommender-client as a prerequisite.
Thanks for working on this branch. I'm very happy to see this feature
coming.
[..]
> Note that this branch depends on the lp:~gary-lasker/software-center/update-to-latest-recommender-client branch as that branch adds the new recommender client code from lp:~canonical-ca-hackers/ubuntu-recommender/ubuntu-recommender-client. Also note that I made one small change to sreclient to fix the validate decorator for the pkgname argument to implicit_feedback so that it matches the validator for the other calls that use pkgname as an argument.
Thanks for this, if you fixed the sreclient_ pristine. py, please also
send the diff to the server team (if you haven't done already) so that
they add it to their
lp:~canonical-ca-hackers/ubuntu-recommender/ubuntu-recommender-client
branch.
> Finally, I added a unit test for the new call in test_recagent.py, however like a few of the other tests there, the test is not currently working with the server. Therefore, it remains disabled as the other tests are. I'll look at this tomorrow to try to see what the issue is with these tests.
[..]
Maybe the staging server had problems. I just tested enabling them and
its working, but that may well be that its now fixed. While looking at
the test code I noticed that there is a bit of duplication in
there, I pushed a branch at
lp:~mvo/software-center/recagent-test-cleanup that removes most of
that.
I also noticed that the branch is missing a test for the new test_recommenda tions_widget. py. Something like activate a r_agent. post_implicit_ feedback( ) call was done.
functionality, it would be nice to add one to
tests/gtk3/
app, trigger a install transaction and verify that on finish the
self.recommende
> @@ -244,7 +262,7 @@ anon_profile_ data(self, spawner, submit_ anon_profile) : "submit- anon_profile" , piston_ submit_ anon_profile) "submit- anon-profile- finished" , piston_ submit_ anon_profile)
>
> def _on_submit_
> piston_
> - self.emit(
> + self.emit(
Nice that this is more consistent now (plus that it will actually work).
> === modified file 'softwarecenter /enums. py' enums.py 2012-08-23 14:37:28 +0000 enums.py 2012-08-28 05:45:23 +0000 ATIONS_ CAROUSEL_ LIMIT = 9 RECOMMENDATIONS _CAROUSEL_ LIMIT = 4 S_FEEDBACK_ INSTALLED = "installed"
> --- softwarecenter/
> +++ softwarecenter/
> @@ -299,6 +299,9 @@
> LOBBY_RECOMMEND
> DETAILS_
>
> +# action values for recommendations implicit feedback
> +RECOMMENDATION
> +
That looks like we could use:
class RecommenderFeed back:
INSTALLED = "installed"
(so that later "REMOVED" can be added there as well and its more
consitent with the rest of enums.py).
[..] _activated( self, catview, app): "application- activated" , app) r_agent. i...
> def _on_application
> self.emit(
> + # we only track installed items of the user has opted-in to the
> + # recommendations service
> + if self.recommende