Merge lp:~mvo/software-center/support-multiple-exhibit-images into lp:software-center
- support-multiple-exhibit-images
- Merge into trunk
Proposed by
Michael Vogt
Status: | Merged |
---|---|
Merged at revision: | 3201 |
Proposed branch: | lp:~mvo/software-center/support-multiple-exhibit-images |
Merge into: | lp:software-center |
Diff against target: |
516 lines (+244/-182) 4 files modified
softwarecenter/ui/gtk3/views/lobbyview.py (+3/-0) softwarecenter/ui/gtk3/widgets/exhibits.py (+56/-37) tests/gtk3/test_catview.py (+3/-145) tests/gtk3/test_exhibits.py (+182/-0) |
To merge this branch: | bzr merge lp:~mvo/software-center/support-multiple-exhibit-images |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gary Lasker (community) | Approve | ||
Review via email: mp+125959@code.launchpad.net |
Commit message
Description of the change
This branch adds support for multiple images in the exhibit banners.
This is to fix #920542. It also does a bit of drive-by cleanup in the
testscases by extracting the exhibits testcase into its own file.
To post a comment you must log in.
- 3203. By Michael Vogt
-
add some debug code
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'softwarecenter/ui/gtk3/views/lobbyview.py' | |||
2 | --- softwarecenter/ui/gtk3/views/lobbyview.py 2012-09-20 01:09:57 +0000 | |||
3 | +++ softwarecenter/ui/gtk3/views/lobbyview.py 2012-09-24 15:24:22 +0000 | |||
4 | @@ -150,6 +150,9 @@ | |||
5 | 150 | exhibit.package_names.split(',')) | 150 | exhibit.package_names.split(',')) |
6 | 151 | if available: | 151 | if available: |
7 | 152 | result.append(exhibit) | 152 | result.append(exhibit) |
8 | 153 | else: | ||
9 | 154 | LOG.warn("skipping exhibit for: '%r' not available" % ( | ||
10 | 155 | exhibit.package_names)) | ||
11 | 153 | 156 | ||
12 | 154 | # its ok if result is empty, since set_exhibits() will ignore | 157 | # its ok if result is empty, since set_exhibits() will ignore |
13 | 155 | # empty lists | 158 | # empty lists |
14 | 156 | 159 | ||
15 | === modified file 'softwarecenter/ui/gtk3/widgets/exhibits.py' | |||
16 | --- softwarecenter/ui/gtk3/widgets/exhibits.py 2012-09-12 14:08:18 +0000 | |||
17 | +++ softwarecenter/ui/gtk3/widgets/exhibits.py 2012-09-24 15:24:22 +0000 | |||
18 | @@ -86,10 +86,10 @@ | |||
19 | 86 | "webservice-office-zoho") | 86 | "webservice-office-zoho") |
20 | 87 | self.title_translated = _("Our star apps") | 87 | self.title_translated = _("Our star apps") |
21 | 88 | self.published = True | 88 | self.published = True |
24 | 89 | self.banner_url = "file:%s" % (os.path.abspath(os.path.join( | 89 | self.banner_urls = ["file:%s" % (os.path.abspath(os.path.join( |
25 | 90 | softwarecenter.paths.datadir, "default_banner/fallback.png"))) | 90 | softwarecenter.paths.datadir, "default_banner/fallback.png")))] |
26 | 91 | self.html = EXHIBIT_HTML % { | 91 | self.html = EXHIBIT_HTML % { |
28 | 92 | 'banner_url': self.banner_url, | 92 | 'banner_url': self.banner_urls[0], |
29 | 93 | 'title': _("Our star apps"), | 93 | 'title': _("Our star apps"), |
30 | 94 | 'subtitle': _("Come and explore our favourites"), | 94 | 'subtitle': _("Come and explore our favourites"), |
31 | 95 | } | 95 | } |
32 | @@ -121,47 +121,66 @@ | |||
33 | 121 | self.show_all() | 121 | self.show_all() |
34 | 122 | self.loader = SimpleFileDownloader() | 122 | self.loader = SimpleFileDownloader() |
35 | 123 | self.loader.connect("file-download-complete", | 123 | self.loader.connect("file-download-complete", |
37 | 124 | self.on_download_complete) | 124 | self._on_one_download_complete) |
38 | 125 | self.loader.connect("error", | 125 | self.loader.connect("error", |
40 | 126 | self.on_download_error) | 126 | self._on_download_error) |
41 | 127 | self.exhibit = None | 127 | self.exhibit = None |
45 | 128 | self.view.connect("notify::load-status", self._on_load_status) | 128 | self._downloaded_banner_images = [] |
46 | 129 | 129 | self.view.connect( | |
47 | 130 | def _on_load_status(self, view, prop): | 130 | "notify::load-status", self._on_internal_renderer_load_status) |
48 | 131 | |||
49 | 132 | def set_exhibit(self, exhibit): | ||
50 | 133 | LOG.debug("set_exhibit: '%s'" % exhibit) | ||
51 | 134 | self._downloaded_banner_images = [] | ||
52 | 135 | self.exhibit = exhibit | ||
53 | 136 | self._download_next_banner_image() | ||
54 | 137 | |||
55 | 138 | def _on_download_error(self, loader, exception, error): | ||
56 | 139 | LOG.warn("download failed: '%s', '%s'" % (exception, error)) | ||
57 | 140 | |||
58 | 141 | def _on_one_download_complete(self, loader, path): | ||
59 | 142 | LOG.debug("downloading of '%s' finished" % path) | ||
60 | 143 | self._downloaded_banner_images.append(path) | ||
61 | 144 | if len(self._downloaded_banner_images) < len(self.exhibit.banner_urls): | ||
62 | 145 | self._download_next_banner_image() | ||
63 | 146 | self._on_all_banner_images_downloaded() | ||
64 | 147 | |||
65 | 148 | def _on_all_banner_images_downloaded(self): | ||
66 | 149 | LOG.debug("downloading of all banner images finished") | ||
67 | 150 | html = self.exhibit.html | ||
68 | 151 | cache_dir = os.path.join( | ||
69 | 152 | softwarecenter.paths.SOFTWARE_CENTER_CACHE_DIR, | ||
70 | 153 | "download-cache") | ||
71 | 154 | for url, local_file in zip(self.exhibit.banner_urls, | ||
72 | 155 | self._downloaded_banner_images): | ||
73 | 156 | # no need to mangle local urls | ||
74 | 157 | if url.startswith("file"): | ||
75 | 158 | continue | ||
76 | 159 | scheme, netloc, server_path, para, query, frag = urlparse(url) | ||
77 | 160 | image_name = os.path.basename(local_file) | ||
78 | 161 | # replace the server side path with the local image name, this | ||
79 | 162 | # assumes that the image always comes from the same server as | ||
80 | 163 | # the html | ||
81 | 164 | html = html.replace(server_path, image_name) | ||
82 | 165 | self.exhibit.html = html | ||
83 | 166 | LOG.debug("mangled html: '%s'" % html) | ||
84 | 167 | self.view.load_string(html, "text/html", "UTF-8", | ||
85 | 168 | "file:%s/" % cache_dir) | ||
86 | 169 | |||
87 | 170 | def _download_next_banner_image(self): | ||
88 | 171 | LOG.debug("_download_next_banner_image") | ||
89 | 172 | self.loader.download_file( | ||
90 | 173 | self.exhibit.banner_urls[len(self._downloaded_banner_images)], | ||
91 | 174 | use_cache=True, | ||
92 | 175 | simple_quoting_for_webkit=True) | ||
93 | 176 | |||
94 | 177 | def _on_internal_renderer_load_status(self, view, prop): | ||
95 | 178 | """Called when the rendering of the html banner is done""" | ||
96 | 131 | if view.get_property("load-status") == WebKit.LoadStatus.FINISHED: | 179 | if view.get_property("load-status") == WebKit.LoadStatus.FINISHED: |
97 | 132 | # this needs to run with a timeout because otherwise the | 180 | # this needs to run with a timeout because otherwise the |
98 | 133 | # status is emited before the offscreen image is finihsed | 181 | # status is emited before the offscreen image is finihsed |
99 | 134 | GObject.timeout_add(100, lambda: self.emit("render-finished")) | 182 | GObject.timeout_add(100, lambda: self.emit("render-finished")) |
100 | 135 | 183 | ||
101 | 136 | def on_download_error(self, loader, exception, error): | ||
102 | 137 | LOG.warn("download failed: '%s', '%s'" % (exception, error)) | ||
103 | 138 | |||
104 | 139 | def on_download_complete(self, loader, path): | ||
105 | 140 | image_name = os.path.basename(path) | ||
106 | 141 | cache_dir = os.path.dirname(path) | ||
107 | 142 | if hasattr(self.exhibit, "html") and self.exhibit.html: | ||
108 | 143 | html = self.exhibit.html | ||
109 | 144 | else: | ||
110 | 145 | html = EXHIBIT_HTML % { | ||
111 | 146 | 'banner_url': self.exhibit.banner_url, | ||
112 | 147 | 'title': self.exhibit.title_translated, | ||
113 | 148 | 'subtitle': "", | ||
114 | 149 | } | ||
115 | 150 | # replace the server side path with the local image name, this | ||
116 | 151 | # assumes that the image always comes from the same server as | ||
117 | 152 | # the html | ||
118 | 153 | scheme, netloc, server_path, para, query, frag = urlparse( | ||
119 | 154 | self.exhibit.banner_url) | ||
120 | 155 | html = html.replace(server_path, image_name) | ||
121 | 156 | self.view.load_string(html, "text/html", "UTF-8", | ||
122 | 157 | "file:%s/" % cache_dir) | ||
123 | 158 | |||
124 | 159 | def set_exhibit(self, exhibit): | ||
125 | 160 | self.exhibit = exhibit | ||
126 | 161 | self.loader.download_file(exhibit.banner_url, | ||
127 | 162 | use_cache=True, | ||
128 | 163 | simple_quoting_for_webkit=True) | ||
129 | 164 | |||
130 | 165 | 184 | ||
131 | 166 | class ExhibitButton(Gtk.Button): | 185 | class ExhibitButton(Gtk.Button): |
132 | 167 | 186 | ||
133 | 168 | 187 | ||
134 | === modified file 'tests/gtk3/test_catview.py' | |||
135 | --- tests/gtk3/test_catview.py 2012-09-18 06:38:40 +0000 | |||
136 | +++ tests/gtk3/test_catview.py 2012-09-24 15:24:22 +0000 | |||
137 | @@ -6,11 +6,9 @@ | |||
138 | 6 | from tests.utils import ( | 6 | from tests.utils import ( |
139 | 7 | do_events, | 7 | do_events, |
140 | 8 | do_events_with_sleep, | 8 | do_events_with_sleep, |
141 | 9 | FakedCache, | ||
142 | 10 | get_test_db, | 9 | get_test_db, |
143 | 11 | get_test_gtk3_icon_cache, | 10 | get_test_gtk3_icon_cache, |
144 | 12 | make_recommender_agent_recommend_me_dict, | 11 | make_recommender_agent_recommend_me_dict, |
145 | 13 | ObjectWithSignals, | ||
146 | 14 | setup_test_env, | 12 | setup_test_env, |
147 | 15 | ) | 13 | ) |
148 | 16 | setup_test_env() | 14 | setup_test_env() |
149 | @@ -19,7 +17,6 @@ | |||
150 | 19 | import softwarecenter.paths | 17 | import softwarecenter.paths |
151 | 20 | 18 | ||
152 | 21 | from softwarecenter.db.appfilter import AppFilter | 19 | from softwarecenter.db.appfilter import AppFilter |
153 | 22 | from softwarecenter.db.database import StoreDatabase | ||
154 | 23 | from softwarecenter.enums import (SortMethods, | 20 | from softwarecenter.enums import (SortMethods, |
155 | 24 | TransactionTypes, | 21 | TransactionTypes, |
156 | 25 | RecommenderFeedbackActions) | 22 | RecommenderFeedbackActions) |
157 | @@ -35,10 +32,10 @@ | |||
158 | 35 | def setUpClass(cls): | 32 | def setUpClass(cls): |
159 | 36 | cls.db = get_test_db() | 33 | cls.db = get_test_db() |
160 | 37 | 34 | ||
162 | 38 | def setUp(self): | 35 | def setUp(self, selected_category=None): |
163 | 39 | self._cat = None | 36 | self._cat = None |
164 | 40 | self._app = None | 37 | self._app = None |
166 | 41 | self.win = get_test_window_catview(self.db) | 38 | self.win = get_test_window_catview(self.db, selected_category) |
167 | 42 | self.addCleanup(self.win.destroy) | 39 | self.addCleanup(self.win.destroy) |
168 | 43 | self.notebook = self.win.get_child() | 40 | self.notebook = self.win.get_child() |
169 | 44 | self.lobby = self.win.get_data("lobby") | 41 | self.lobby = self.win.get_data("lobby") |
170 | @@ -122,19 +119,12 @@ | |||
171 | 122 | @patch('softwarecenter.ui.gtk3.widgets.recommendations.RecommenderAgent' | 119 | @patch('softwarecenter.ui.gtk3.widgets.recommendations.RecommenderAgent' |
172 | 123 | '.post_submit_profile') | 120 | '.post_submit_profile') |
173 | 124 | def setUp(self, mock_query, mock_recommender_is_opted_in, mock_sso): | 121 | def setUp(self, mock_query, mock_recommender_is_opted_in, mock_sso): |
174 | 125 | self._cat = None | ||
175 | 126 | self._app = None | ||
176 | 127 | # patch the recommender to specify that we are not opted-in at | 122 | # patch the recommender to specify that we are not opted-in at |
177 | 128 | # the start of each test | 123 | # the start of each test |
178 | 129 | mock_recommender_is_opted_in.return_value = False | 124 | mock_recommender_is_opted_in.return_value = False |
179 | 130 | # we specify the "Internet" category because we do specific checks | 125 | # we specify the "Internet" category because we do specific checks |
180 | 131 | # in the following tests that depend on this being the category choice | 126 | # in the following tests that depend on this being the category choice |
187 | 132 | self.win = get_test_window_catview(self.db, | 127 | super(RecommendationsTestCase, self).setUp(selected_category="Internet") |
182 | 133 | selected_category="Internet") | ||
183 | 134 | self.addCleanup(self.win.destroy) | ||
184 | 135 | self.notebook = self.win.get_child() | ||
185 | 136 | self.lobby = self.win.get_data("lobby") | ||
186 | 137 | self.subcat_view = self.win.get_data("subcat") | ||
188 | 138 | self.rec_panel = self.lobby.recommended_for_you_panel | 128 | self.rec_panel = self.lobby.recommended_for_you_panel |
189 | 139 | 129 | ||
190 | 140 | def test_recommended_for_you_opt_in_display(self): | 130 | def test_recommended_for_you_opt_in_display(self): |
191 | @@ -371,138 +361,6 @@ | |||
192 | 371 | mock_result) | 361 | mock_result) |
193 | 372 | do_events() | 362 | do_events() |
194 | 373 | 363 | ||
195 | 374 | |||
196 | 375 | class ExhibitsTestCase(unittest.TestCase): | ||
197 | 376 | """The test suite for the exhibits carousel.""" | ||
198 | 377 | |||
199 | 378 | def setUp(self): | ||
200 | 379 | self.cache = FakedCache() | ||
201 | 380 | self.db = StoreDatabase(cache=self.cache) | ||
202 | 381 | self.lobby = lobbyview.LobbyView(cache=self.cache, db=self.db, | ||
203 | 382 | icons=None, apps_filter=None) | ||
204 | 383 | self.addCleanup(self.lobby.destroy) | ||
205 | 384 | |||
206 | 385 | def _get_banner_from_lobby(self): | ||
207 | 386 | return self.lobby.vbox.get_children()[-1].get_child() | ||
208 | 387 | |||
209 | 388 | def test_featured_exhibit_by_default(self): | ||
210 | 389 | """Show the featured exhibit before querying the remote service.""" | ||
211 | 390 | self.lobby._append_banner_ads() | ||
212 | 391 | |||
213 | 392 | banner = self._get_banner_from_lobby() | ||
214 | 393 | self.assertEqual(1, len(banner.exhibits)) | ||
215 | 394 | self.assertIsInstance(banner.exhibits[0], lobbyview.FeaturedExhibit) | ||
216 | 395 | |||
217 | 396 | def test_no_exhibit_if_not_available(self): | ||
218 | 397 | """The exhibit should not be shown if the package is not available.""" | ||
219 | 398 | exhibit = Mock() | ||
220 | 399 | exhibit.package_names = u'foobarbaz' | ||
221 | 400 | |||
222 | 401 | sca = ObjectWithSignals() | ||
223 | 402 | sca.query_exhibits = lambda: sca.emit('exhibits', sca, [exhibit]) | ||
224 | 403 | |||
225 | 404 | with patch.object(lobbyview, 'SoftwareCenterAgent', lambda: sca): | ||
226 | 405 | self.lobby._append_banner_ads() | ||
227 | 406 | |||
228 | 407 | banner = self._get_banner_from_lobby() | ||
229 | 408 | self.assertEqual(1, len(banner.exhibits)) | ||
230 | 409 | self.assertIsInstance(banner.exhibits[0], lobbyview.FeaturedExhibit) | ||
231 | 410 | |||
232 | 411 | def test_exhibit_if_available(self): | ||
233 | 412 | """The exhibit should be shown if the package is available.""" | ||
234 | 413 | exhibit = Mock() | ||
235 | 414 | exhibit.package_names = u'foobarbaz' | ||
236 | 415 | exhibit.banner_url = 'banner' | ||
237 | 416 | exhibit.title_translated = '' | ||
238 | 417 | |||
239 | 418 | self.cache[u'foobarbaz'] = Mock() | ||
240 | 419 | |||
241 | 420 | sca = ObjectWithSignals() | ||
242 | 421 | sca.query_exhibits = lambda: sca.emit('exhibits', sca, [exhibit]) | ||
243 | 422 | |||
244 | 423 | with patch.object(lobbyview, 'SoftwareCenterAgent', lambda: sca): | ||
245 | 424 | self.lobby._append_banner_ads() | ||
246 | 425 | |||
247 | 426 | banner = self._get_banner_from_lobby() | ||
248 | 427 | self.assertEqual(1, len(banner.exhibits)) | ||
249 | 428 | self.assertIs(banner.exhibits[0], exhibit) | ||
250 | 429 | |||
251 | 430 | def test_exhibit_if_mixed_availability(self): | ||
252 | 431 | """The exhibit should be shown even if some are not available.""" | ||
253 | 432 | # available exhibit | ||
254 | 433 | exhibit = Mock() | ||
255 | 434 | exhibit.package_names = u'foobarbaz' | ||
256 | 435 | exhibit.banner_url = 'banner' | ||
257 | 436 | exhibit.title_translated = '' | ||
258 | 437 | |||
259 | 438 | self.cache[u'foobarbaz'] = Mock() | ||
260 | 439 | |||
261 | 440 | # not available exhibit | ||
262 | 441 | other = Mock() | ||
263 | 442 | other.package_names = u'not-there' | ||
264 | 443 | |||
265 | 444 | sca = ObjectWithSignals() | ||
266 | 445 | sca.query_exhibits = lambda: sca.emit('exhibits', sca, | ||
267 | 446 | [exhibit, other]) | ||
268 | 447 | |||
269 | 448 | with patch.object(lobbyview, 'SoftwareCenterAgent', lambda: sca): | ||
270 | 449 | self.lobby._append_banner_ads() | ||
271 | 450 | |||
272 | 451 | banner = self._get_banner_from_lobby() | ||
273 | 452 | self.assertEqual(1, len(banner.exhibits)) | ||
274 | 453 | self.assertIs(banner.exhibits[0], exhibit) | ||
275 | 454 | |||
276 | 455 | def test_exhibit_with_url(self): | ||
277 | 456 | # available exhibit | ||
278 | 457 | exhibit = Mock() | ||
279 | 458 | exhibit.package_names = '' | ||
280 | 459 | exhibit.click_url = 'http://example.com' | ||
281 | 460 | exhibit.banner_url = 'banner' | ||
282 | 461 | exhibit.title_translated = '' | ||
283 | 462 | |||
284 | 463 | sca = ObjectWithSignals() | ||
285 | 464 | sca.query_exhibits = lambda: sca.emit('exhibits', sca, | ||
286 | 465 | [exhibit]) | ||
287 | 466 | |||
288 | 467 | with patch.object(lobbyview, 'SoftwareCenterAgent', lambda: sca): | ||
289 | 468 | # add the banners | ||
290 | 469 | self.lobby._append_banner_ads() | ||
291 | 470 | # fake click | ||
292 | 471 | alloc = self.lobby.exhibit_banner.get_allocation() | ||
293 | 472 | mock_event = Mock() | ||
294 | 473 | mock_event.x = alloc.x | ||
295 | 474 | mock_event.y = alloc.y | ||
296 | 475 | with patch.object(self.lobby.exhibit_banner, 'emit') as mock_emit: | ||
297 | 476 | self.lobby.exhibit_banner.on_button_press(None, mock_event) | ||
298 | 477 | self.lobby.exhibit_banner.on_button_release(None, mock_event) | ||
299 | 478 | mock_emit.assert_called() | ||
300 | 479 | signal_name = mock_emit.call_args[0][0] | ||
301 | 480 | call_exhibit = mock_emit.call_args[0][1] | ||
302 | 481 | self.assertEqual(signal_name, "show-exhibits-clicked") | ||
303 | 482 | self.assertEqual(call_exhibit.click_url, "http://example.com") | ||
304 | 483 | |||
305 | 484 | def test_exhibit_with_featured_exhibit(self): | ||
306 | 485 | """ regression test for bug #1023777 """ | ||
307 | 486 | sca = ObjectWithSignals() | ||
308 | 487 | sca.query_exhibits = lambda: sca.emit('exhibits', sca, | ||
309 | 488 | [lobbyview.FeaturedExhibit()]) | ||
310 | 489 | |||
311 | 490 | with patch.object(lobbyview, 'SoftwareCenterAgent', lambda: sca): | ||
312 | 491 | # add the banners | ||
313 | 492 | self.lobby._append_banner_ads() | ||
314 | 493 | # fake click | ||
315 | 494 | alloc = self.lobby.exhibit_banner.get_allocation() | ||
316 | 495 | mock_event = Mock() | ||
317 | 496 | mock_event.x = alloc.x | ||
318 | 497 | mock_event.y = alloc.y | ||
319 | 498 | with patch.object(self.lobby, 'emit') as mock_emit: | ||
320 | 499 | self.lobby.exhibit_banner.on_button_press(None, mock_event) | ||
321 | 500 | self.lobby.exhibit_banner.on_button_release(None, mock_event) | ||
322 | 501 | mock_emit.assert_called() | ||
323 | 502 | signal_name = mock_emit.call_args[0][0] | ||
324 | 503 | call_category = mock_emit.call_args[0][1] | ||
325 | 504 | self.assertEqual(signal_name, "category-selected") | ||
326 | 505 | self.assertEqual(call_category.name, "Our star apps") | ||
327 | 506 | 364 | ||
328 | 507 | if __name__ == "__main__": | 365 | if __name__ == "__main__": |
329 | 508 | unittest.main() | 366 | unittest.main() |
330 | 509 | 367 | ||
331 | === added file 'tests/gtk3/test_exhibits.py' | |||
332 | --- tests/gtk3/test_exhibits.py 1970-01-01 00:00:00 +0000 | |||
333 | +++ tests/gtk3/test_exhibits.py 2012-09-24 15:24:22 +0000 | |||
334 | @@ -0,0 +1,182 @@ | |||
335 | 1 | import os | ||
336 | 2 | import unittest | ||
337 | 3 | |||
338 | 4 | from mock import patch, Mock | ||
339 | 5 | |||
340 | 6 | from tests.utils import ( | ||
341 | 7 | FakedCache, | ||
342 | 8 | ObjectWithSignals, | ||
343 | 9 | setup_test_env, | ||
344 | 10 | ) | ||
345 | 11 | setup_test_env() | ||
346 | 12 | |||
347 | 13 | |||
348 | 14 | from softwarecenter.db.database import StoreDatabase | ||
349 | 15 | from softwarecenter.ui.gtk3.views import lobbyview | ||
350 | 16 | from softwarecenter.ui.gtk3.widgets.exhibits import ( | ||
351 | 17 | _HtmlRenderer, | ||
352 | 18 | ) | ||
353 | 19 | |||
354 | 20 | |||
355 | 21 | class ExhibitsTestCase(unittest.TestCase): | ||
356 | 22 | """The test suite for the exhibits carousel.""" | ||
357 | 23 | |||
358 | 24 | def setUp(self): | ||
359 | 25 | self.cache = FakedCache() | ||
360 | 26 | self.db = StoreDatabase(cache=self.cache) | ||
361 | 27 | self.lobby = lobbyview.LobbyView(cache=self.cache, db=self.db, | ||
362 | 28 | icons=None, apps_filter=None) | ||
363 | 29 | self.addCleanup(self.lobby.destroy) | ||
364 | 30 | |||
365 | 31 | def _get_banner_from_lobby(self): | ||
366 | 32 | return self.lobby.vbox.get_children()[-1].get_child() | ||
367 | 33 | |||
368 | 34 | def test_featured_exhibit_by_default(self): | ||
369 | 35 | """Show the featured exhibit before querying the remote service.""" | ||
370 | 36 | self.lobby._append_banner_ads() | ||
371 | 37 | |||
372 | 38 | banner = self._get_banner_from_lobby() | ||
373 | 39 | self.assertEqual(1, len(banner.exhibits)) | ||
374 | 40 | self.assertIsInstance(banner.exhibits[0], lobbyview.FeaturedExhibit) | ||
375 | 41 | |||
376 | 42 | def test_no_exhibit_if_not_available(self): | ||
377 | 43 | """The exhibit should not be shown if the package is not available.""" | ||
378 | 44 | exhibit = Mock() | ||
379 | 45 | exhibit.package_names = u'foobarbaz' | ||
380 | 46 | |||
381 | 47 | sca = ObjectWithSignals() | ||
382 | 48 | sca.query_exhibits = lambda: sca.emit('exhibits', sca, [exhibit]) | ||
383 | 49 | |||
384 | 50 | with patch.object(lobbyview, 'SoftwareCenterAgent', lambda: sca): | ||
385 | 51 | self.lobby._append_banner_ads() | ||
386 | 52 | |||
387 | 53 | banner = self._get_banner_from_lobby() | ||
388 | 54 | self.assertEqual(1, len(banner.exhibits)) | ||
389 | 55 | self.assertIsInstance(banner.exhibits[0], lobbyview.FeaturedExhibit) | ||
390 | 56 | |||
391 | 57 | def test_exhibit_if_available(self): | ||
392 | 58 | """The exhibit should be shown if the package is available.""" | ||
393 | 59 | exhibit = Mock() | ||
394 | 60 | exhibit.package_names = u'foobarbaz' | ||
395 | 61 | exhibit.banner_urls = ['banner'] | ||
396 | 62 | exhibit.title_translated = '' | ||
397 | 63 | |||
398 | 64 | self.cache[u'foobarbaz'] = Mock() | ||
399 | 65 | |||
400 | 66 | sca = ObjectWithSignals() | ||
401 | 67 | sca.query_exhibits = lambda: sca.emit('exhibits', sca, [exhibit]) | ||
402 | 68 | |||
403 | 69 | with patch.object(lobbyview, 'SoftwareCenterAgent', lambda: sca): | ||
404 | 70 | self.lobby._append_banner_ads() | ||
405 | 71 | |||
406 | 72 | banner = self._get_banner_from_lobby() | ||
407 | 73 | self.assertEqual(1, len(banner.exhibits)) | ||
408 | 74 | self.assertIs(banner.exhibits[0], exhibit) | ||
409 | 75 | |||
410 | 76 | def test_exhibit_if_mixed_availability(self): | ||
411 | 77 | """The exhibit should be shown even if some are not available.""" | ||
412 | 78 | # available exhibit | ||
413 | 79 | exhibit = Mock() | ||
414 | 80 | exhibit.package_names = u'foobarbaz' | ||
415 | 81 | exhibit.banner_urls = ['banner'] | ||
416 | 82 | exhibit.title_translated = '' | ||
417 | 83 | |||
418 | 84 | self.cache[u'foobarbaz'] = Mock() | ||
419 | 85 | |||
420 | 86 | # not available exhibit | ||
421 | 87 | other = Mock() | ||
422 | 88 | other.package_names = u'not-there' | ||
423 | 89 | |||
424 | 90 | sca = ObjectWithSignals() | ||
425 | 91 | sca.query_exhibits = lambda: sca.emit('exhibits', sca, | ||
426 | 92 | [exhibit, other]) | ||
427 | 93 | |||
428 | 94 | with patch.object(lobbyview, 'SoftwareCenterAgent', lambda: sca): | ||
429 | 95 | self.lobby._append_banner_ads() | ||
430 | 96 | |||
431 | 97 | banner = self._get_banner_from_lobby() | ||
432 | 98 | self.assertEqual(1, len(banner.exhibits)) | ||
433 | 99 | self.assertIs(banner.exhibits[0], exhibit) | ||
434 | 100 | |||
435 | 101 | def test_exhibit_with_url(self): | ||
436 | 102 | # available exhibit | ||
437 | 103 | exhibit = Mock() | ||
438 | 104 | exhibit.package_names = '' | ||
439 | 105 | exhibit.click_url = 'http://example.com' | ||
440 | 106 | exhibit.banner_urls = ['banner'] | ||
441 | 107 | exhibit.title_translated = '' | ||
442 | 108 | |||
443 | 109 | sca = ObjectWithSignals() | ||
444 | 110 | sca.query_exhibits = lambda: sca.emit('exhibits', sca, | ||
445 | 111 | [exhibit]) | ||
446 | 112 | |||
447 | 113 | with patch.object(lobbyview, 'SoftwareCenterAgent', lambda: sca): | ||
448 | 114 | # add the banners | ||
449 | 115 | self.lobby._append_banner_ads() | ||
450 | 116 | # fake click | ||
451 | 117 | alloc = self.lobby.exhibit_banner.get_allocation() | ||
452 | 118 | mock_event = Mock() | ||
453 | 119 | mock_event.x = alloc.x | ||
454 | 120 | mock_event.y = alloc.y | ||
455 | 121 | with patch.object(self.lobby.exhibit_banner, 'emit') as mock_emit: | ||
456 | 122 | self.lobby.exhibit_banner.on_button_press(None, mock_event) | ||
457 | 123 | self.lobby.exhibit_banner.on_button_release(None, mock_event) | ||
458 | 124 | mock_emit.assert_called() | ||
459 | 125 | signal_name = mock_emit.call_args[0][0] | ||
460 | 126 | call_exhibit = mock_emit.call_args[0][1] | ||
461 | 127 | self.assertEqual(signal_name, "show-exhibits-clicked") | ||
462 | 128 | self.assertEqual(call_exhibit.click_url, "http://example.com") | ||
463 | 129 | |||
464 | 130 | def test_exhibit_with_featured_exhibit(self): | ||
465 | 131 | """ regression test for bug #1023777 """ | ||
466 | 132 | sca = ObjectWithSignals() | ||
467 | 133 | sca.query_exhibits = lambda: sca.emit('exhibits', sca, | ||
468 | 134 | [lobbyview.FeaturedExhibit()]) | ||
469 | 135 | |||
470 | 136 | with patch.object(lobbyview, 'SoftwareCenterAgent', lambda: sca): | ||
471 | 137 | # add the banners | ||
472 | 138 | self.lobby._append_banner_ads() | ||
473 | 139 | # fake click | ||
474 | 140 | alloc = self.lobby.exhibit_banner.get_allocation() | ||
475 | 141 | mock_event = Mock() | ||
476 | 142 | mock_event.x = alloc.x | ||
477 | 143 | mock_event.y = alloc.y | ||
478 | 144 | with patch.object(self.lobby, 'emit') as mock_emit: | ||
479 | 145 | self.lobby.exhibit_banner.on_button_press(None, mock_event) | ||
480 | 146 | self.lobby.exhibit_banner.on_button_release(None, mock_event) | ||
481 | 147 | mock_emit.assert_called() | ||
482 | 148 | signal_name = mock_emit.call_args[0][0] | ||
483 | 149 | call_category = mock_emit.call_args[0][1] | ||
484 | 150 | self.assertEqual(signal_name, "category-selected") | ||
485 | 151 | self.assertEqual(call_category.name, "Our star apps") | ||
486 | 152 | |||
487 | 153 | |||
488 | 154 | class HtmlRendererTestCase(unittest.TestCase): | ||
489 | 155 | |||
490 | 156 | def test_multiple_images(self): | ||
491 | 157 | downloader = ObjectWithSignals() | ||
492 | 158 | downloader.download_file = lambda *args, **kwargs: downloader.emit( | ||
493 | 159 | "file-download-complete", downloader, os.path.basename(args[0])) | ||
494 | 160 | |||
495 | 161 | with patch("softwarecenter.ui.gtk3.widgets.exhibits." | ||
496 | 162 | "SimpleFileDownloader", lambda: downloader): | ||
497 | 163 | renderer = _HtmlRenderer() | ||
498 | 164 | mock_exhibit = Mock() | ||
499 | 165 | mock_exhibit.banner_urls = [ | ||
500 | 166 | "http://example.com/path1/banner1.png", | ||
501 | 167 | "http://example.com/path2/banner2.png", | ||
502 | 168 | ] | ||
503 | 169 | mock_exhibit.html = "url('/path1/banner1.png')#"\ | ||
504 | 170 | "url('/path2/banner2.png')" | ||
505 | 171 | |||
506 | 172 | renderer.set_exhibit(mock_exhibit) | ||
507 | 173 | # assert the stuff we expected to get downloaded got downloaded | ||
508 | 174 | self.assertEqual( | ||
509 | 175 | renderer._downloaded_banner_images, | ||
510 | 176 | ["banner1.png", "banner2.png"]) | ||
511 | 177 | # test that the path mangling worked | ||
512 | 178 | self.assertEqual( | ||
513 | 179 | mock_exhibit.html, "url('banner1.png')#url('banner2.png')") | ||
514 | 180 | |||
515 | 181 | if __name__ == "__main__": | ||
516 | 182 | unittest.main() |
Thanks, Michael!