Merge lp:~mvo/software-center/test-catview-cleanup into lp:software-center

Proposed by Michael Vogt on 2012-05-22
Status: Superseded
Proposed branch: lp:~mvo/software-center/test-catview-cleanup
Merge into: lp:software-center
Diff against target: 879 lines (+350/-246)
7 files modified
softwarecenter/backend/channel.py (+4/-4)
softwarecenter/db/application.py (+5/-4)
softwarecenter/testutils.py (+62/-0)
softwarecenter/ui/gtk3/models/appstore2.py (+11/-5)
softwarecenter/ui/gtk3/views/catview_gtk.py (+48/-21)
test/gtk3/test_app.py (+2/-36)
test/gtk3/test_catview.py (+218/-176)
To merge this branch: bzr merge lp:~mvo/software-center/test-catview-cleanup
Reviewer Review Type Date Requested Status
software-store-developers 2012-05-22 Pending
Review via email: mp+106766@code.launchpad.net

This proposal has been superseded by a proposal from 2012-05-22.

Description of the change

This branch refactors the test_catview.py code:
- split the TestCases for the Recommender and the Top Rated/Whats New
- remove duplicated code in the tests by using setUp()/tearDown() more efficiently
- use the patch decorator more
- avoid re-creating the DB in each test via setUpClass, this could be optimized further by just having one global instance for the entire test

To post a comment you must log in.
3034. By Michael Vogt on 2012-05-22

test/gtk3/test_catview.py: use addCleanup() instead of tearDown() as suggested by Natalia

3035. By Michael Vogt on 2012-05-22

merge 5.2 and resolve conflicts

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'softwarecenter/backend/channel.py'
2--- softwarecenter/backend/channel.py 2012-03-19 14:20:55 +0000
3+++ softwarecenter/backend/channel.py 2012-05-22 12:42:24 +0000
4@@ -22,7 +22,7 @@
5
6 from gettext import gettext as _
7
8-from softwarecenter.distro import get_distro
9+import softwarecenter.distro
10
11 from softwarecenter.enums import (SortMethods,
12 Icons,
13@@ -34,7 +34,7 @@
14
15 class ChannelsManager(object):
16 def __init__(self, db, **kwargs):
17- self.distro = get_distro()
18+ self.distro = softwarecenter.distro.get_distro()
19 self.db = db
20
21 # public
22@@ -154,7 +154,7 @@
23 self.installed_only = installed_only
24 self._channel_sort_mode = channel_sort_mode
25 # distro specific stuff
26- self.distro = get_distro()
27+ self.distro = softwarecenter.distro.get_distro()
28 # configure the channel
29 self._channel_display_name = self._get_display_name_for_channel(
30 channel_name, channel_origin, channel_component)
31@@ -351,7 +351,7 @@
32 return AptChannelsManager.channel_available(channelname)
33
34 if __name__ == "__main__":
35- distro = get_distro()
36+ distro = softwarecenter.distro.get_distro()
37 channel = SoftwareChannel(distro.get_distro_channel_name(),
38 None, None)
39 print(channel)
40
41=== modified file 'softwarecenter/db/application.py'
42--- softwarecenter/db/application.py 2012-05-11 13:48:04 +0000
43+++ softwarecenter/db/application.py 2012-05-22 12:42:24 +0000
44@@ -24,9 +24,10 @@
45 import os
46 import re
47
48+import softwarecenter.distro
49+
50 from gettext import gettext as _
51 from softwarecenter.backend.channel import is_channel_available
52-from softwarecenter.distro import get_distro
53 from softwarecenter.enums import PkgStates, XapianValues, Icons
54
55 from softwarecenter.paths import (APP_INSTALL_CHANNELS_PATH,
56@@ -177,7 +178,7 @@
57 self._db = db
58 self._db.connect("reopen", self._on_db_reopen)
59 self._cache = self._db._aptcache
60- self._distro = get_distro()
61+ self._distro = softwarecenter.distro.get_distro()
62 self._history = None
63 # import here (intead of global) to avoid dbus dependency
64 # in update-software-center (that imports application, but
65@@ -298,7 +299,7 @@
66 # try apt first
67 if self._pkg:
68 for origin in self._pkg.candidate.origins:
69- if (origin.origin == get_distro().get_distro_channel_name() and
70+ if (origin.origin == self._distro.get_distro_channel_name() and
71 origin.trusted and origin.component):
72 return origin.component
73 # then xapian
74@@ -639,7 +640,7 @@
75 self.emit("screenshots-available", self._screenshot_list)
76 return
77 # download it
78- distro = get_distro()
79+ distro = self._distro
80 url = distro.SCREENSHOT_JSON_URL % self._app.pkgname
81 try:
82 f = Gio.File.new_for_uri(url)
83
84=== modified file 'softwarecenter/testutils.py'
85--- softwarecenter/testutils.py 2012-04-16 16:41:29 +0000
86+++ softwarecenter/testutils.py 2012-05-22 12:42:24 +0000
87@@ -22,6 +22,8 @@
88 import tempfile
89 import time
90
91+from collections import defaultdict
92+
93 from mock import Mock
94
95 m_dbus = m_polkit = m_aptd = None
96@@ -142,6 +144,12 @@
97 main_loop.iteration()
98
99
100+def do_events_with_sleep(iterations=5, sleep=0.1):
101+ for i in range(iterations):
102+ do_events()
103+ time.sleep(sleep)
104+
105+
106 def get_mock_app_from_real_app(real_app):
107 """ take a application and return a app where the details are a mock
108 of the real details so they can easily be modified
109@@ -314,3 +322,57 @@
110 {u'rating': 1.5, u'package_name': u'tucan'}],
111 u'app': u'pitivi'}
112 return recommend_app_data
113+
114+
115+class ObjectWithSignals(object):
116+ """A faked object that you can connect to and emit signals."""
117+
118+ def __init__(self, *a, **kw):
119+ super(ObjectWithSignals, self).__init__()
120+ self._callbacks = defaultdict(list)
121+
122+ def connect(self, signal, callback):
123+ """Connect a signal with a callback."""
124+ self._callbacks[signal].append(callback)
125+
126+ def disconnect(self, signal, callback):
127+ """Connect a signal with a callback."""
128+ self._callbacks[signal].remove(callback)
129+ if len(self._callbacks[signal]) == 0:
130+ self._callbacks.pop(signal)
131+
132+ def disconnect_by_func(self, callback):
133+ """Disconnect 'callback' from every signal."""
134+ # do not use iteritems since we may change the dict inside the for
135+ for signal, callbacks in self._callbacks.items():
136+ if callback in callbacks:
137+ self.disconnect(signal, callback)
138+
139+ def emit(self, signal, *args, **kwargs):
140+ """Emit 'signal' passing *args, **kwargs to every callback."""
141+ for callback in self._callbacks[signal]:
142+ callback(*args, **kwargs)
143+
144+
145+class FakedCache(ObjectWithSignals, dict):
146+ """A faked cache."""
147+
148+ def __init__(self, *a, **kw):
149+ super(FakedCache, self).__init__()
150+ self.ready = False
151+
152+ def open(self):
153+ """Open this cache."""
154+ self.ready = True
155+
156+ def component_available(self, distro_codename, component):
157+ """Return whether 'component' is available in 'distro_codename'."""
158+
159+ def get_addons(self, pkgname):
160+ """Return (recommended, suggested) addons for 'pkgname'."""
161+ return ([], [])
162+
163+ def get_total_size_on_install(self, pkgname, addons_to_install,
164+ addons_to_remove, archive_suite):
165+ """Return a fake (total_download_size, total_install_size) result."""
166+ return (0, 0)
167
168=== modified file 'softwarecenter/ui/gtk3/models/appstore2.py'
169--- softwarecenter/ui/gtk3/models/appstore2.py 2012-05-18 18:42:27 +0000
170+++ softwarecenter/ui/gtk3/models/appstore2.py 2012-05-22 12:42:24 +0000
171@@ -115,9 +115,7 @@
172 self.icons = icons
173 self.icon_size = icon_size
174
175- # cache the 'missing icon' used in the treeview for apps without an
176- # icon
177- self._missing_icon = icons.load_icon(Icons.MISSING_APP, icon_size, 0)
178+ self._missing_icon = None # delay this until actually needed
179 if global_icon_cache:
180 self.icon_cache = _app_icon_cache
181 else:
182@@ -146,6 +144,14 @@
183 on_image_download_complete, pkgname)
184 image_downloader.download_file(url, icon_file_path)
185
186+ @property
187+ def missing_icon(self):
188+ # cache the 'missing icon' used in treeviews for apps without an icon
189+ if self._missing_icon is None:
190+ self._missing_icon = self.icons.load_icon(Icons.MISSING_APP,
191+ self.icon_size, 0)
192+ return self._missing_icon
193+
194 def update_availability(self, doc):
195 doc.available = None
196 doc.installed = None
197@@ -228,10 +234,10 @@
198 self.get_pkgname(doc),
199 full_icon_file_name)
200 # display the missing icon while the real one downloads
201- self.icon_cache[icon_name] = self._missing_icon
202+ self.icon_cache[icon_name] = self.missing_icon
203 except GObject.GError as e:
204 LOG.debug("get_icon returned '%s'" % e)
205- return self._missing_icon
206+ return self.missing_icon
207
208 def get_review_stats(self, doc):
209 return self.review_loader.get_review_stats(self.get_application(doc))
210
211=== modified file 'softwarecenter/ui/gtk3/views/catview_gtk.py'
212--- softwarecenter/ui/gtk3/views/catview_gtk.py 2012-03-16 16:52:54 +0000
213+++ softwarecenter/ui/gtk3/views/catview_gtk.py 2012-05-22 12:42:24 +0000
214@@ -28,9 +28,12 @@
215
216 import softwarecenter.paths
217 from softwarecenter.db.application import Application
218-from softwarecenter.enums import (NonAppVisibility,
219- SortMethods,
220- TOP_RATED_CAROUSEL_LIMIT)
221+from softwarecenter.enums import (
222+ NonAppVisibility,
223+ PkgStates,
224+ SortMethods,
225+ TOP_RATED_CAROUSEL_LIMIT,
226+)
227 from softwarecenter.utils import wait_for_apt_cache_ready
228 from softwarecenter.ui.gtk3.models.appstore2 import AppPropertiesHelper
229 from softwarecenter.ui.gtk3.widgets.viewport import Viewport
230@@ -224,6 +227,8 @@
231 apps_filter, apps_limit=0):
232 CategoriesViewGtk.__init__(self, datadir, desktopdir, cache, db, icons,
233 apps_filter, apps_limit=0)
234+ self.top_rated = None
235+ self.exhibit_banner = None
236
237 # sections
238 self.departments = None
239@@ -337,24 +342,41 @@
240 flags=['nonapps-visible'])
241 self.emit("category-selected", cat)
242
243+ def _pkg_available(self, pkgname):
244+ try:
245+ state = Application("", pkgname).get_details(self.db).pkg_state
246+ except:
247+ available = False
248+ else:
249+ available = state not in (PkgStates.NOT_FOUND, PkgStates.ERROR)
250+ return available
251+
252+ def _filter_and_set_exhibits(self, sca_client, exhibit_list):
253+ result = []
254+ # filter out those exhibits that are not available in this run
255+ for exhibit in exhibit_list:
256+ available = all(self._pkg_available(p) for p in
257+ exhibit.package_names.split(','))
258+ if available:
259+ result.append(exhibit)
260+
261+ self.exhibit_banner.set_exhibits(result)
262+
263 def _append_banner_ads(self):
264- exhibit_banner = ExhibitBanner()
265- exhibit_banner.set_exhibits([FeaturedExhibit(),
266- ])
267- exhibit_banner.connect("show-exhibits-clicked", self._on_show_exhibits)
268+ self.exhibit_banner = ExhibitBanner()
269+ self.exhibit_banner.set_exhibits([FeaturedExhibit()])
270+ self.exhibit_banner.connect(
271+ "show-exhibits-clicked", self._on_show_exhibits)
272
273 # query using the agent
274 scagent = SoftwareCenterAgent()
275- scagent.connect(
276- "exhibits", lambda sca, l: exhibit_banner.set_exhibits(l))
277+ scagent.connect("exhibits", self._filter_and_set_exhibits)
278 scagent.query_exhibits()
279
280 a = Gtk.Alignment()
281 a.set_padding(0, StockEms.SMALL, 0, 0)
282- a.add(exhibit_banner)
283-
284+ a.add(self.exhibit_banner)
285 self.vbox.pack_start(a, False, False, 0)
286- return
287
288 def _append_departments(self):
289 # set the departments section to use the label markup we have just
290@@ -382,6 +404,8 @@
291 # FIXME: _update_{top_rated,whats_new,recommended_for_you}_content()
292 # duplicates a lot of code
293 def _update_top_rated_content(self):
294+ if self.top_rated is None:
295+ return
296 # remove any existing children from the grid widget
297 self.top_rated.remove_all()
298 # get top_rated category and docs
299@@ -715,21 +739,24 @@
300 #return
301
302
303-def get_test_window_catview():
304+def get_test_window_catview(db=None):
305
306 def on_category_selected(view, cat):
307 print "on_category_selected view: ", view
308 print "on_category_selected cat: ", cat
309
310- from softwarecenter.db.pkginfo import get_pkg_info
311- cache = get_pkg_info()
312- cache.open()
313+ if db is None:
314+ from softwarecenter.db.pkginfo import get_pkg_info
315+ cache = get_pkg_info()
316+ cache.open()
317
318- from softwarecenter.db.database import StoreDatabase
319- xapian_base_path = "/var/cache/software-center"
320- pathname = os.path.join(xapian_base_path, "xapian")
321- db = StoreDatabase(pathname, cache)
322- db.open()
323+ from softwarecenter.db.database import StoreDatabase
324+ xapian_base_path = "/var/cache/software-center"
325+ pathname = os.path.join(xapian_base_path, "xapian")
326+ db = StoreDatabase(pathname, cache)
327+ db.open()
328+ else:
329+ cache = db._aptcache
330
331 import softwarecenter.paths
332 datadir = softwarecenter.paths.datadir
333
334=== modified file 'test/gtk3/test_app.py'
335--- test/gtk3/test_app.py 2012-05-16 15:52:07 +0000
336+++ test/gtk3/test_app.py 2012-05-22 12:42:24 +0000
337@@ -8,7 +8,7 @@
338
339 from mock import Mock
340
341-from testutils import get_mock_options, setup_test_env
342+from testutils import FakedCache, get_mock_options, setup_test_env
343 setup_test_env()
344
345 import softwarecenter.paths
346@@ -17,40 +17,6 @@
347 from softwarecenter.ui.gtk3 import app
348
349
350-class FakedCache(dict):
351- """A faked cache."""
352-
353- def __init__(self, *a, **kw):
354- super(FakedCache, self).__init__()
355- self._callbacks = defaultdict(list)
356- self.ready = False
357-
358- def open(self):
359- """Open this cache."""
360- self.ready = True
361-
362- def connect(self, signal, callback):
363- """Connect a signal with a callback."""
364- self._callbacks[signal].append(callback)
365-
366- def disconnect_by_func(self, callback):
367- """Disconnect 'callback' from every signal."""
368- for signal, cb in self._callbacks.iteritems():
369- if cb == callback:
370- self._callbacks[signal].remove(callback)
371- if len(self._callbacks[signal]) == 0:
372- self._callbacks.pop(signal)
373-
374- def get_addons(self, pkgname):
375- """Return (recommended, suggested) addons for 'pkgname'."""
376- return ([],[])
377-
378- def get_total_size_on_install(self,pkgname, addons_to_install,
379- addons_to_remove, archive_suite):
380- """Return a fake (total_download_size, total_install_size) result."""
381- return (0, 0)
382-
383-
384 class ParsePackagesArgsTestCase(unittest.TestCase):
385 """Test suite for the parse_packages_args helper."""
386
387@@ -109,7 +75,7 @@
388 fname = __file__
389 assert os.path.exists(fname)
390 self.assertRaises(DebFileOpenError, app.parse_packages_args, fname)
391-
392+
393
394 class ParsePackagesWithAptPrefixTestCase(ParsePackagesArgsTestCase):
395
396
397=== modified file 'test/gtk3/test_catview.py'
398--- test/gtk3/test_catview.py 2012-03-15 22:23:21 +0000
399+++ test/gtk3/test_catview.py 2012-05-22 12:42:24 +0000
400@@ -1,66 +1,81 @@
401+import unittest
402+
403 from gi.repository import Gtk
404-import time
405-import unittest
406 from mock import patch, Mock
407
408 from testutils import setup_test_env
409 setup_test_env()
410
411+import softwarecenter.distro
412+import softwarecenter.paths
413+
414+from softwarecenter.db.database import StoreDatabase
415 from softwarecenter.enums import SortMethods
416-from softwarecenter.testutils import (get_test_db,
417- make_recommender_agent_recommend_me_dict)
418-
419-class TestCatView(unittest.TestCase):
420+from softwarecenter.testutils import (
421+ do_events_with_sleep,
422+ do_events,
423+ FakedCache,
424+ get_test_db,
425+ make_recommender_agent_recommend_me_dict,
426+ ObjectWithSignals,
427+)
428+from softwarecenter.ui.gtk3.views import catview_gtk
429+from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
430+from softwarecenter.ui.gtk3.widgets.containers import FramedHeaderBox
431+from softwarecenter.ui.gtk3.widgets.spinner import SpinnerNotebook
432+
433+
434+class CatViewBaseTestCase(unittest.TestCase):
435+
436+ @classmethod
437+ def setUpClass(cls):
438+ cls.db = get_test_db()
439
440 def setUp(self):
441- self.db = get_test_db()
442+ self._cat = None
443+ self.win = get_test_window_catview(self.db)
444+ self.addCleanup(self.win.destroy)
445+ self.notebook = self.win.get_child()
446+ self.lobby = self.win.get_data("lobby")
447+ self.subcat_view = self.win.get_data("subcat")
448+ self.rec_panel = self.lobby.recommended_for_you_panel
449
450 def _on_category_selected(self, subcatview, category):
451- #print "**************", subcatview, category
452 self._cat = category
453-
454- def test_subcatview_top_rated(self):
455- from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
456- # get the widgets we need
457- win = get_test_window_catview()
458- lobby = win.get_data("lobby")
459-
460+
461+
462+class TopAndWhatsNewTestCase(CatViewBaseTestCase):
463+
464+ def test_top_rated(self):
465 # simulate review-stats refresh
466- lobby._update_top_rated_content = Mock()
467- lobby.reviews_loader.emit("refresh-review-stats-finished", [])
468- self.assertTrue(lobby._update_top_rated_content.called)
469+ self.lobby._update_top_rated_content = Mock()
470+ self.lobby.reviews_loader.emit("refresh-review-stats-finished", [])
471+ self.assertTrue(self.lobby._update_top_rated_content.called)
472
473 # test clicking top_rated
474- lobby.connect("category-selected", self._on_category_selected)
475- lobby.top_rated_frame.more.clicked()
476- self._p()
477+ self.lobby.connect("category-selected", self._on_category_selected)
478+ self.lobby.top_rated_frame.more.clicked()
479+ do_events()
480 self.assertNotEqual(self._cat, None)
481 self.assertEqual(self._cat.name, "Top Rated")
482 self.assertEqual(self._cat.sortmode, SortMethods.BY_TOP_RATED)
483- win.destroy()
484-
485- def test_subcatview_new(self):
486- from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
487- # get the widgets we need
488- win = get_test_window_catview()
489- lobby = win.get_data("lobby")
490-
491+
492+ def test_new(self):
493 # test db reopen triggers whats-new update
494- lobby._update_whats_new_content = Mock()
495- lobby.db.emit("reopen")
496- self.assertTrue(lobby._update_whats_new_content.called)
497+ self.lobby._update_whats_new_content = Mock()
498+ self.lobby.db.emit("reopen")
499+ self.assertTrue(self.lobby._update_whats_new_content.called)
500
501 # test clicking new
502- lobby.connect("category-selected", self._on_category_selected)
503- lobby.whats_new_frame.more.clicked()
504- self._p()
505+ self.lobby.connect("category-selected", self._on_category_selected)
506+ self.lobby.whats_new_frame.more.clicked()
507+ do_events()
508 self.assertNotEqual(self._cat, None)
509 # encoding is utf-8 (since r2218, see category.py)
510 self.assertEqual(self._cat.name, 'What\xe2\x80\x99s New')
511 self.assertEqual(self._cat.sortmode, SortMethods.BY_CATALOGED_TIME)
512- win.destroy()
513
514- def test_subcatview_new_no_sort_info_yet(self):
515+ def test_new_no_sort_info_yet(self):
516 # ensure that we don't show a empty "whats new" category
517 # see LP: #865985
518 from softwarecenter.testutils import get_test_db
519@@ -68,7 +83,7 @@
520 cache = db._aptcache
521 # simulate a fresh install with no catalogedtime info
522 del db._axi_values["catalogedtime"]
523-
524+
525 from softwarecenter.testutils import get_test_gtk3_icon_cache
526 icons = get_test_gtk3_icon_cache()
527
528@@ -76,7 +91,6 @@
529 apps_filter = AppFilter(db, cache)
530
531 from softwarecenter.distro import get_distro
532- import softwarecenter.paths
533 from softwarecenter.paths import APP_INSTALL_PATH
534 from softwarecenter.ui.gtk3.views.catview_gtk import LobbyViewGtk
535 view = LobbyViewGtk(softwarecenter.paths.datadir, APP_INSTALL_PATH,
536@@ -85,6 +99,7 @@
537
538 # gui
539 win = Gtk.Window()
540+ self.addCleanup(win.destroy)
541 win.set_size_request(800, 400)
542
543 scroll = Gtk.ScrolledWindow()
544@@ -93,171 +108,198 @@
545 win.add(scroll)
546 win.show()
547 # test visibility
548- self._p()
549+ do_events()
550 self.assertFalse(view.whats_new_frame.get_property("visible"))
551- self._p()
552- win.destroy()
553-
554- def test_subcatview_recommended_for_you_opt_in_display(self):
555-
556- # patch the recommender UUID value to insure that we are not opted-in for this test
557- get_recommender_opted_in_patcher = patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
558- self.addCleanup(get_recommender_opted_in_patcher.stop)
559- mock_get_recommender_opted_in = get_recommender_opted_in_patcher.start()
560- mock_get_recommender_opted_in.return_value = False
561-
562- from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
563- # get the widgets we need
564- win = get_test_window_catview()
565- lobby = win.get_data("lobby")
566- rec_panel = lobby.recommended_for_you_panel
567- self._p()
568- from softwarecenter.ui.gtk3.widgets.containers import FramedHeaderBox
569- self.assertTrue(rec_panel.spinner_notebook.get_current_page() == FramedHeaderBox.CONTENT)
570- self.assertTrue(rec_panel.opt_in_vbox.get_property("visible"))
571- win.destroy()
572-
573- # patch out the agent query method to avoid making the actual server call
574- @patch('softwarecenter.backend.recagent.RecommenderAgent'
575- '.post_submit_profile')
576- def test_subcatview_recommended_for_you_spinner_display(self, mock_query):
577-
578- # patch the recommender UUID value to insure that we are not opted-in for this test
579- get_recommender_opted_in_patcher = patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
580- self.addCleanup(get_recommender_opted_in_patcher.stop)
581- mock_get_recommender_opted_in = get_recommender_opted_in_patcher.start()
582- mock_get_recommender_opted_in.return_value = False
583-
584- from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
585- # get the widgets we need
586- win = get_test_window_catview()
587- lobby = win.get_data("lobby")
588- rec_panel = lobby.recommended_for_you_panel
589- self._p()
590- # click the opt-in button to initiate the process, this will show the spinner
591- rec_panel.opt_in_button.emit('clicked')
592- self._p()
593- from softwarecenter.ui.gtk3.widgets.spinner import SpinnerNotebook
594- self.assertTrue(rec_panel.spinner_notebook.get_current_page() == SpinnerNotebook.SPINNER_PAGE)
595- self.assertTrue(rec_panel.opt_in_vbox.get_property("visible"))
596- win.destroy()
597-
598- # patch out the agent query method to avoid making the actual server call
599- @patch('softwarecenter.backend.recagent.RecommenderAgent'
600- '.post_submit_profile')
601- def test_subcatview_recommended_for_you_display_recommendations(self, mock_query):
602-
603- # patch the recommender UUID value to insure that we are not opted-in for this test
604- get_recommender_opted_in_patcher = patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
605- self.addCleanup(get_recommender_opted_in_patcher.stop)
606- mock_get_recommender_opted_in = get_recommender_opted_in_patcher.start()
607- mock_get_recommender_opted_in.return_value = False
608-
609- from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
610- # get the widgets we need
611- win = get_test_window_catview()
612- lobby = win.get_data("lobby")
613- rec_panel = lobby.recommended_for_you_panel
614- self._p()
615- # click the opt-in button to initiate the process, this will show the spinner
616- rec_panel.opt_in_button.emit('clicked')
617- self._p()
618- rec_panel._update_recommended_for_you_content()
619- self._p()
620+
621+
622+class RecommendationsTestCase(CatViewBaseTestCase):
623+ """The test suite for the recommendations ."""
624+
625+ @patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
626+ def test_recommended_for_you_opt_in_display(
627+ self, mock_get_recommender_opted_in):
628+ # patch the recommender UUID value to ensure that we are not opted-in
629+ # for this test
630+ mock_get_recommender_opted_in.return_value = False
631+
632+ do_events()
633+ self.assertEqual(self.rec_panel.spinner_notebook.get_current_page(),
634+ FramedHeaderBox.CONTENT)
635+ self.assertTrue(self.rec_panel.opt_in_vbox.get_property("visible"))
636+
637+ # patch out the agent query method to avoid making the actual server call
638+ @patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
639+ @patch('softwarecenter.backend.recagent.RecommenderAgent'
640+ '.post_submit_profile')
641+ def test_recommended_for_you_spinner_display(
642+ self, mock_query, mock_get_recommender_opted_in):
643+ # patch the recommender UUID value to insure that we are not opted-in
644+ # for this test
645+ mock_get_recommender_opted_in.return_value = False
646+
647+ # click the opt-in button to initiate the process,
648+ # this will show the spinner
649+ self.rec_panel.opt_in_button.emit('clicked')
650+ do_events()
651+ self.assertEqual(self.rec_panel.spinner_notebook.get_current_page(),
652+ SpinnerNotebook.SPINNER_PAGE)
653+ self.assertTrue(self.rec_panel.opt_in_vbox.get_property("visible"))
654+
655+ # patch out the agent query method to avoid making the actual server call
656+ @patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
657+ @patch('softwarecenter.backend.recagent.RecommenderAgent'
658+ '.post_submit_profile')
659+ def test_recommended_for_you_display_recommendations(self,
660+ mock_query, mock_get_recommender_opted_in):
661+ # patch the recommender UUID value to insure that we are not opted-in
662+ # for this test
663+ mock_get_recommender_opted_in.return_value = False
664+
665+ # click the opt-in button to initiate the process,
666+ # this will show the spinner
667+ self.rec_panel.opt_in_button.emit('clicked')
668+ do_events()
669+ self.rec_panel._update_recommended_for_you_content()
670+ do_events()
671 # we fake the callback from the agent here
672- lobby.recommended_for_you_panel.recommended_for_you_cat._recommend_me_result(
673- None,
674- make_recommender_agent_recommend_me_dict())
675- self.assertNotEqual(
676- lobby.recommended_for_you_panel.recommended_for_you_cat.get_documents(self.db), [])
677- from softwarecenter.ui.gtk3.widgets.spinner import SpinnerNotebook
678- self.assertTrue(rec_panel.spinner_notebook.get_current_page() == SpinnerNotebook.CONTENT_PAGE)
679- self._p()
680+ for_you = self.lobby.recommended_for_you_panel.recommended_for_you_cat
681+ for_you._recommend_me_result(None,
682+ make_recommender_agent_recommend_me_dict())
683+ self.assertNotEqual(for_you.get_documents(self.db), [])
684+ self.assertEqual(self.rec_panel.spinner_notebook.get_current_page(),
685+ SpinnerNotebook.CONTENT_PAGE)
686+ do_events()
687 # test clicking recommended_for_you More button
688- lobby.connect("category-selected", self._on_category_selected)
689- lobby.recommended_for_you_panel.more.clicked()
690- self._p()
691+ self.lobby.connect("category-selected", self._on_category_selected)
692+ self.lobby.recommended_for_you_panel.more.clicked()
693+ # this is delayed for some reason so we need to sleep here
694+ do_events_with_sleep()
695 self.assertNotEqual(self._cat, None)
696 self.assertEqual(self._cat.name, "Recommended For You")
697- win.destroy()
698-
699+
700 # patch out the agent query method to avoid making the actual server call
701+ @patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
702 @patch('softwarecenter.backend.recagent.RecommenderAgent'
703 '.query_recommend_me')
704- def test_subcatview_recommended_for_you_display_recommendations_not_opted_in(self, mock_query):
705-
706- # patch the recommender UUID value to insure that we are not opted-in for this test
707- get_recommender_opted_in_patcher = patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
708- self.addCleanup(get_recommender_opted_in_patcher.stop)
709- mock_get_recommender_opted_in = get_recommender_opted_in_patcher.start()
710+ def test_recommended_for_you_display_recommendations_not_opted_in(self,
711+ mock_query, mock_get_recommender_opted_in):
712+ # patch the recommender UUID value to insure that we are not opted-in
713+ # for this test
714 mock_get_recommender_opted_in.return_value = False
715-
716- from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
717- # get the widgets we need
718- win = get_test_window_catview()
719+
720 # we want to work in the "subcat" view
721- notebook = win.get_child()
722- notebook.next_page()
723-
724- subcat_view = win.get_data("subcat")
725- self._p()
726- self.assertFalse(subcat_view.recommended_for_you_in_cat.get_property("visible"))
727- win.destroy()
728-
729+ self.notebook.next_page()
730+
731+ do_events()
732+ visible = self.subcat_view.recommended_for_you_in_cat.get_property(
733+ "visible")
734+ self.assertFalse(visible)
735+
736 # patch out the agent query method to avoid making the actual server call
737+ @patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
738 @patch('softwarecenter.backend.recagent.RecommenderAgent'
739 '.query_recommend_me')
740- def test_subcatview_recommended_for_you_display_recommendations_opted_in(self, mock_query):
741-
742- # patch the recommender UUID value to insure that we are not opted-in for this test
743- get_recommender_opted_in_patcher = patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
744- self.addCleanup(get_recommender_opted_in_patcher.stop)
745- mock_get_recommender_opted_in = get_recommender_opted_in_patcher.start()
746+ def test_recommended_for_you_display_recommendations_opted_in(
747+ self, mock_query, mock_get_recommender_opted_in):
748+ # patch the recommender UUID value to insure that we are not opted-in
749+ # for this test
750 mock_get_recommender_opted_in.return_value = True
751-
752- from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
753- # get the widgets we need
754- win = get_test_window_catview()
755+
756 # we want to work in the "subcat" view
757- notebook = win.get_child()
758- notebook.next_page()
759-
760- subcat_view = win.get_data("subcat")
761- rec_cat_panel = subcat_view.recommended_for_you_in_cat
762- self._p()
763+ self.notebook.next_page()
764+
765+ rec_cat_panel = self.subcat_view.recommended_for_you_in_cat
766 rec_cat_panel._update_recommended_for_you_content()
767- self._p()
768+ do_events()
769 # we fake the callback from the agent here
770 rec_cat_panel.recommended_for_you_cat._recommend_me_result(
771 None,
772 make_recommender_agent_recommend_me_dict())
773- result_docs = rec_cat_panel.recommended_for_you_cat.get_documents(self.db)
774+ result_docs = rec_cat_panel.recommended_for_you_cat.get_documents(
775+ self.db)
776 self.assertNotEqual(result_docs, [])
777- # check that we are getting the correct number of results, corresponding
778- # to the following Internet items:
779+ # check that we are getting the correct number of results,
780+ # corresponding to the following Internet items:
781 # Mangler, Midori, Midori Private Browsing, Psi
782 self.assertTrue(len(result_docs) == 4)
783- from softwarecenter.ui.gtk3.widgets.spinner import SpinnerNotebook
784- self.assertTrue(rec_cat_panel.spinner_notebook.get_current_page() == SpinnerNotebook.CONTENT_PAGE)
785+ self.assertEqual(rec_cat_panel.spinner_notebook.get_current_page(),
786+ SpinnerNotebook.CONTENT_PAGE)
787 # check that the tiles themselves are visible
788- self._p()
789- self.assertTrue(rec_cat_panel.recommended_for_you_content.get_property("visible"))
790- self.assertTrue(rec_cat_panel.recommended_for_you_content.get_children()[0].title.get_property("visible"))
791- self._p()
792+ do_events()
793+ self.assertTrue(rec_cat_panel.recommended_for_you_content.get_property(
794+ "visible"))
795+ self.assertTrue(rec_cat_panel.recommended_for_you_content.get_children(
796+ )[0].title.get_property("visible"))
797+ do_events()
798 # test clicking recommended_for_you More button
799- subcat_view.connect("category-selected", self._on_category_selected)
800+ self.subcat_view.connect(
801+ "category-selected", self._on_category_selected)
802 rec_cat_panel.more.clicked()
803- self._p()
804+ # this is delayed for some reason so we need to sleep here
805+ do_events_with_sleep()
806 self.assertNotEqual(self._cat, None)
807 self.assertEqual(self._cat.name, "Recommended For You in Internet")
808- win.destroy()
809-
810- def _p(self):
811- for i in range(5):
812- time.sleep(0.1)
813- while Gtk.events_pending():
814- Gtk.main_iteration()
815-
816+
817+
818+class ExhibitsTestCase(unittest.TestCase):
819+ """The test suite for the exhibits carousel."""
820+
821+ def setUp(self):
822+ self.datadir = softwarecenter.paths.datadir
823+ self.desktopdir = softwarecenter.paths.APP_INSTALL_PATH
824+ self.cache = FakedCache()
825+ self.db = StoreDatabase(cache=self.cache)
826+ self.lobby = catview_gtk.LobbyViewGtk(datadir=self.datadir,
827+ desktopdir=self.desktopdir, cache=self.cache, db=self.db,
828+ icons=None, apps_filter=None)
829+ self.addCleanup(self.lobby.destroy)
830+
831+ def _get_banner_from_lobby(self):
832+ return self.lobby.vbox.get_children()[-1].get_child()
833+
834+ def test_featured_exhibit_by_default(self):
835+ """Show the featured exhibit before querying the remote service."""
836+ self.lobby._append_banner_ads()
837+
838+ banner = self._get_banner_from_lobby()
839+ self.assertEqual(1, len(banner.exhibits))
840+ self.assertIsInstance(banner.exhibits[0], catview_gtk.FeaturedExhibit)
841+
842+ def test_no_exhibit_if_not_available(self):
843+ """The exhibit should not be shown if the package is not available."""
844+ exhibit = Mock()
845+ exhibit.package_names = u'foobarbaz'
846+
847+ sca = ObjectWithSignals()
848+ sca.query_exhibits = lambda: sca.emit('exhibits', sca, [exhibit])
849+
850+ with patch.object(catview_gtk, 'SoftwareCenterAgent', lambda: sca):
851+ self.lobby._append_banner_ads()
852+
853+ banner = self._get_banner_from_lobby()
854+ self.assertEqual(1, len(banner.exhibits))
855+ self.assertIsInstance(banner.exhibits[0], catview_gtk.FeaturedExhibit)
856+
857+ def test_exhibit_if_available(self):
858+ """The exhibit should be shown if the package is not available."""
859+ exhibit = Mock()
860+ exhibit.package_names = u'foobarbaz'
861+ exhibit.banner_url = 'banner'
862+
863+ pkg = Mock()
864+ pkg.banner_url = ''
865+ pkg.title_translated = ''
866+ self.cache[u'foobarbaz'] = pkg
867+
868+ sca = ObjectWithSignals()
869+ sca.query_exhibits = lambda: sca.emit('exhibits', sca, [exhibit])
870+
871+ with patch.object(catview_gtk, 'SoftwareCenterAgent', lambda: sca):
872+ self.lobby._append_banner_ads()
873+
874+ banner = self._get_banner_from_lobby()
875+ self.assertEqual(1, len(banner.exhibits))
876+ self.assertIs(banner.exhibits[0], exhibit)
877
878
879 if __name__ == "__main__":

Subscribers

People subscribed via source and target branches