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

Proposed by Michael Vogt
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 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

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

3035. By Michael Vogt

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
=== modified file 'softwarecenter/backend/channel.py'
--- softwarecenter/backend/channel.py 2012-03-19 14:20:55 +0000
+++ softwarecenter/backend/channel.py 2012-05-22 12:42:24 +0000
@@ -22,7 +22,7 @@
2222
23from gettext import gettext as _23from gettext import gettext as _
2424
25from softwarecenter.distro import get_distro25import softwarecenter.distro
2626
27from softwarecenter.enums import (SortMethods,27from softwarecenter.enums import (SortMethods,
28 Icons,28 Icons,
@@ -34,7 +34,7 @@
3434
35class ChannelsManager(object):35class ChannelsManager(object):
36 def __init__(self, db, **kwargs):36 def __init__(self, db, **kwargs):
37 self.distro = get_distro()37 self.distro = softwarecenter.distro.get_distro()
38 self.db = db38 self.db = db
3939
40 # public40 # public
@@ -154,7 +154,7 @@
154 self.installed_only = installed_only154 self.installed_only = installed_only
155 self._channel_sort_mode = channel_sort_mode155 self._channel_sort_mode = channel_sort_mode
156 # distro specific stuff156 # distro specific stuff
157 self.distro = get_distro()157 self.distro = softwarecenter.distro.get_distro()
158 # configure the channel158 # configure the channel
159 self._channel_display_name = self._get_display_name_for_channel(159 self._channel_display_name = self._get_display_name_for_channel(
160 channel_name, channel_origin, channel_component)160 channel_name, channel_origin, channel_component)
@@ -351,7 +351,7 @@
351 return AptChannelsManager.channel_available(channelname)351 return AptChannelsManager.channel_available(channelname)
352352
353if __name__ == "__main__":353if __name__ == "__main__":
354 distro = get_distro()354 distro = softwarecenter.distro.get_distro()
355 channel = SoftwareChannel(distro.get_distro_channel_name(),355 channel = SoftwareChannel(distro.get_distro_channel_name(),
356 None, None)356 None, None)
357 print(channel)357 print(channel)
358358
=== modified file 'softwarecenter/db/application.py'
--- softwarecenter/db/application.py 2012-05-11 13:48:04 +0000
+++ softwarecenter/db/application.py 2012-05-22 12:42:24 +0000
@@ -24,9 +24,10 @@
24import os24import os
25import re25import re
2626
27import softwarecenter.distro
28
27from gettext import gettext as _29from gettext import gettext as _
28from softwarecenter.backend.channel import is_channel_available30from softwarecenter.backend.channel import is_channel_available
29from softwarecenter.distro import get_distro
30from softwarecenter.enums import PkgStates, XapianValues, Icons31from softwarecenter.enums import PkgStates, XapianValues, Icons
3132
32from softwarecenter.paths import (APP_INSTALL_CHANNELS_PATH,33from softwarecenter.paths import (APP_INSTALL_CHANNELS_PATH,
@@ -177,7 +178,7 @@
177 self._db = db178 self._db = db
178 self._db.connect("reopen", self._on_db_reopen)179 self._db.connect("reopen", self._on_db_reopen)
179 self._cache = self._db._aptcache180 self._cache = self._db._aptcache
180 self._distro = get_distro()181 self._distro = softwarecenter.distro.get_distro()
181 self._history = None182 self._history = None
182 # import here (intead of global) to avoid dbus dependency183 # import here (intead of global) to avoid dbus dependency
183 # in update-software-center (that imports application, but184 # in update-software-center (that imports application, but
@@ -298,7 +299,7 @@
298 # try apt first299 # try apt first
299 if self._pkg:300 if self._pkg:
300 for origin in self._pkg.candidate.origins:301 for origin in self._pkg.candidate.origins:
301 if (origin.origin == get_distro().get_distro_channel_name() and302 if (origin.origin == self._distro.get_distro_channel_name() and
302 origin.trusted and origin.component):303 origin.trusted and origin.component):
303 return origin.component304 return origin.component
304 # then xapian305 # then xapian
@@ -639,7 +640,7 @@
639 self.emit("screenshots-available", self._screenshot_list)640 self.emit("screenshots-available", self._screenshot_list)
640 return641 return
641 # download it642 # download it
642 distro = get_distro()643 distro = self._distro
643 url = distro.SCREENSHOT_JSON_URL % self._app.pkgname644 url = distro.SCREENSHOT_JSON_URL % self._app.pkgname
644 try:645 try:
645 f = Gio.File.new_for_uri(url)646 f = Gio.File.new_for_uri(url)
646647
=== modified file 'softwarecenter/testutils.py'
--- softwarecenter/testutils.py 2012-04-16 16:41:29 +0000
+++ softwarecenter/testutils.py 2012-05-22 12:42:24 +0000
@@ -22,6 +22,8 @@
22import tempfile22import tempfile
23import time23import time
2424
25from collections import defaultdict
26
25from mock import Mock27from mock import Mock
2628
27m_dbus = m_polkit = m_aptd = None29m_dbus = m_polkit = m_aptd = None
@@ -142,6 +144,12 @@
142 main_loop.iteration()144 main_loop.iteration()
143145
144146
147def do_events_with_sleep(iterations=5, sleep=0.1):
148 for i in range(iterations):
149 do_events()
150 time.sleep(sleep)
151
152
145def get_mock_app_from_real_app(real_app):153def get_mock_app_from_real_app(real_app):
146 """ take a application and return a app where the details are a mock154 """ take a application and return a app where the details are a mock
147 of the real details so they can easily be modified155 of the real details so they can easily be modified
@@ -314,3 +322,57 @@
314 {u'rating': 1.5, u'package_name': u'tucan'}],322 {u'rating': 1.5, u'package_name': u'tucan'}],
315 u'app': u'pitivi'}323 u'app': u'pitivi'}
316 return recommend_app_data324 return recommend_app_data
325
326
327class ObjectWithSignals(object):
328 """A faked object that you can connect to and emit signals."""
329
330 def __init__(self, *a, **kw):
331 super(ObjectWithSignals, self).__init__()
332 self._callbacks = defaultdict(list)
333
334 def connect(self, signal, callback):
335 """Connect a signal with a callback."""
336 self._callbacks[signal].append(callback)
337
338 def disconnect(self, signal, callback):
339 """Connect a signal with a callback."""
340 self._callbacks[signal].remove(callback)
341 if len(self._callbacks[signal]) == 0:
342 self._callbacks.pop(signal)
343
344 def disconnect_by_func(self, callback):
345 """Disconnect 'callback' from every signal."""
346 # do not use iteritems since we may change the dict inside the for
347 for signal, callbacks in self._callbacks.items():
348 if callback in callbacks:
349 self.disconnect(signal, callback)
350
351 def emit(self, signal, *args, **kwargs):
352 """Emit 'signal' passing *args, **kwargs to every callback."""
353 for callback in self._callbacks[signal]:
354 callback(*args, **kwargs)
355
356
357class FakedCache(ObjectWithSignals, dict):
358 """A faked cache."""
359
360 def __init__(self, *a, **kw):
361 super(FakedCache, self).__init__()
362 self.ready = False
363
364 def open(self):
365 """Open this cache."""
366 self.ready = True
367
368 def component_available(self, distro_codename, component):
369 """Return whether 'component' is available in 'distro_codename'."""
370
371 def get_addons(self, pkgname):
372 """Return (recommended, suggested) addons for 'pkgname'."""
373 return ([], [])
374
375 def get_total_size_on_install(self, pkgname, addons_to_install,
376 addons_to_remove, archive_suite):
377 """Return a fake (total_download_size, total_install_size) result."""
378 return (0, 0)
317379
=== modified file 'softwarecenter/ui/gtk3/models/appstore2.py'
--- softwarecenter/ui/gtk3/models/appstore2.py 2012-05-18 18:42:27 +0000
+++ softwarecenter/ui/gtk3/models/appstore2.py 2012-05-22 12:42:24 +0000
@@ -115,9 +115,7 @@
115 self.icons = icons115 self.icons = icons
116 self.icon_size = icon_size116 self.icon_size = icon_size
117117
118 # cache the 'missing icon' used in the treeview for apps without an118 self._missing_icon = None # delay this until actually needed
119 # icon
120 self._missing_icon = icons.load_icon(Icons.MISSING_APP, icon_size, 0)
121 if global_icon_cache:119 if global_icon_cache:
122 self.icon_cache = _app_icon_cache120 self.icon_cache = _app_icon_cache
123 else:121 else:
@@ -146,6 +144,14 @@
146 on_image_download_complete, pkgname)144 on_image_download_complete, pkgname)
147 image_downloader.download_file(url, icon_file_path)145 image_downloader.download_file(url, icon_file_path)
148146
147 @property
148 def missing_icon(self):
149 # cache the 'missing icon' used in treeviews for apps without an icon
150 if self._missing_icon is None:
151 self._missing_icon = self.icons.load_icon(Icons.MISSING_APP,
152 self.icon_size, 0)
153 return self._missing_icon
154
149 def update_availability(self, doc):155 def update_availability(self, doc):
150 doc.available = None156 doc.available = None
151 doc.installed = None157 doc.installed = None
@@ -228,10 +234,10 @@
228 self.get_pkgname(doc),234 self.get_pkgname(doc),
229 full_icon_file_name)235 full_icon_file_name)
230 # display the missing icon while the real one downloads236 # display the missing icon while the real one downloads
231 self.icon_cache[icon_name] = self._missing_icon237 self.icon_cache[icon_name] = self.missing_icon
232 except GObject.GError as e:238 except GObject.GError as e:
233 LOG.debug("get_icon returned '%s'" % e)239 LOG.debug("get_icon returned '%s'" % e)
234 return self._missing_icon240 return self.missing_icon
235241
236 def get_review_stats(self, doc):242 def get_review_stats(self, doc):
237 return self.review_loader.get_review_stats(self.get_application(doc))243 return self.review_loader.get_review_stats(self.get_application(doc))
238244
=== modified file 'softwarecenter/ui/gtk3/views/catview_gtk.py'
--- softwarecenter/ui/gtk3/views/catview_gtk.py 2012-03-16 16:52:54 +0000
+++ softwarecenter/ui/gtk3/views/catview_gtk.py 2012-05-22 12:42:24 +0000
@@ -28,9 +28,12 @@
2828
29import softwarecenter.paths29import softwarecenter.paths
30from softwarecenter.db.application import Application30from softwarecenter.db.application import Application
31from softwarecenter.enums import (NonAppVisibility,31from softwarecenter.enums import (
32 SortMethods,32 NonAppVisibility,
33 TOP_RATED_CAROUSEL_LIMIT)33 PkgStates,
34 SortMethods,
35 TOP_RATED_CAROUSEL_LIMIT,
36)
34from softwarecenter.utils import wait_for_apt_cache_ready37from softwarecenter.utils import wait_for_apt_cache_ready
35from softwarecenter.ui.gtk3.models.appstore2 import AppPropertiesHelper38from softwarecenter.ui.gtk3.models.appstore2 import AppPropertiesHelper
36from softwarecenter.ui.gtk3.widgets.viewport import Viewport39from softwarecenter.ui.gtk3.widgets.viewport import Viewport
@@ -224,6 +227,8 @@
224 apps_filter, apps_limit=0):227 apps_filter, apps_limit=0):
225 CategoriesViewGtk.__init__(self, datadir, desktopdir, cache, db, icons,228 CategoriesViewGtk.__init__(self, datadir, desktopdir, cache, db, icons,
226 apps_filter, apps_limit=0)229 apps_filter, apps_limit=0)
230 self.top_rated = None
231 self.exhibit_banner = None
227232
228 # sections233 # sections
229 self.departments = None234 self.departments = None
@@ -337,24 +342,41 @@
337 flags=['nonapps-visible'])342 flags=['nonapps-visible'])
338 self.emit("category-selected", cat)343 self.emit("category-selected", cat)
339344
345 def _pkg_available(self, pkgname):
346 try:
347 state = Application("", pkgname).get_details(self.db).pkg_state
348 except:
349 available = False
350 else:
351 available = state not in (PkgStates.NOT_FOUND, PkgStates.ERROR)
352 return available
353
354 def _filter_and_set_exhibits(self, sca_client, exhibit_list):
355 result = []
356 # filter out those exhibits that are not available in this run
357 for exhibit in exhibit_list:
358 available = all(self._pkg_available(p) for p in
359 exhibit.package_names.split(','))
360 if available:
361 result.append(exhibit)
362
363 self.exhibit_banner.set_exhibits(result)
364
340 def _append_banner_ads(self):365 def _append_banner_ads(self):
341 exhibit_banner = ExhibitBanner()366 self.exhibit_banner = ExhibitBanner()
342 exhibit_banner.set_exhibits([FeaturedExhibit(),367 self.exhibit_banner.set_exhibits([FeaturedExhibit()])
343 ])368 self.exhibit_banner.connect(
344 exhibit_banner.connect("show-exhibits-clicked", self._on_show_exhibits)369 "show-exhibits-clicked", self._on_show_exhibits)
345370
346 # query using the agent371 # query using the agent
347 scagent = SoftwareCenterAgent()372 scagent = SoftwareCenterAgent()
348 scagent.connect(373 scagent.connect("exhibits", self._filter_and_set_exhibits)
349 "exhibits", lambda sca, l: exhibit_banner.set_exhibits(l))
350 scagent.query_exhibits()374 scagent.query_exhibits()
351375
352 a = Gtk.Alignment()376 a = Gtk.Alignment()
353 a.set_padding(0, StockEms.SMALL, 0, 0)377 a.set_padding(0, StockEms.SMALL, 0, 0)
354 a.add(exhibit_banner)378 a.add(self.exhibit_banner)
355
356 self.vbox.pack_start(a, False, False, 0)379 self.vbox.pack_start(a, False, False, 0)
357 return
358380
359 def _append_departments(self):381 def _append_departments(self):
360 # set the departments section to use the label markup we have just382 # set the departments section to use the label markup we have just
@@ -382,6 +404,8 @@
382 # FIXME: _update_{top_rated,whats_new,recommended_for_you}_content()404 # FIXME: _update_{top_rated,whats_new,recommended_for_you}_content()
383 # duplicates a lot of code405 # duplicates a lot of code
384 def _update_top_rated_content(self):406 def _update_top_rated_content(self):
407 if self.top_rated is None:
408 return
385 # remove any existing children from the grid widget409 # remove any existing children from the grid widget
386 self.top_rated.remove_all()410 self.top_rated.remove_all()
387 # get top_rated category and docs411 # get top_rated category and docs
@@ -715,21 +739,24 @@
715 #return739 #return
716740
717741
718def get_test_window_catview():742def get_test_window_catview(db=None):
719743
720 def on_category_selected(view, cat):744 def on_category_selected(view, cat):
721 print "on_category_selected view: ", view745 print "on_category_selected view: ", view
722 print "on_category_selected cat: ", cat746 print "on_category_selected cat: ", cat
723747
724 from softwarecenter.db.pkginfo import get_pkg_info748 if db is None:
725 cache = get_pkg_info()749 from softwarecenter.db.pkginfo import get_pkg_info
726 cache.open()750 cache = get_pkg_info()
751 cache.open()
727752
728 from softwarecenter.db.database import StoreDatabase753 from softwarecenter.db.database import StoreDatabase
729 xapian_base_path = "/var/cache/software-center"754 xapian_base_path = "/var/cache/software-center"
730 pathname = os.path.join(xapian_base_path, "xapian")755 pathname = os.path.join(xapian_base_path, "xapian")
731 db = StoreDatabase(pathname, cache)756 db = StoreDatabase(pathname, cache)
732 db.open()757 db.open()
758 else:
759 cache = db._aptcache
733760
734 import softwarecenter.paths761 import softwarecenter.paths
735 datadir = softwarecenter.paths.datadir762 datadir = softwarecenter.paths.datadir
736763
=== modified file 'test/gtk3/test_app.py'
--- test/gtk3/test_app.py 2012-05-16 15:52:07 +0000
+++ test/gtk3/test_app.py 2012-05-22 12:42:24 +0000
@@ -8,7 +8,7 @@
88
9from mock import Mock9from mock import Mock
1010
11from testutils import get_mock_options, setup_test_env11from testutils import FakedCache, get_mock_options, setup_test_env
12setup_test_env()12setup_test_env()
1313
14import softwarecenter.paths14import softwarecenter.paths
@@ -17,40 +17,6 @@
17from softwarecenter.ui.gtk3 import app17from softwarecenter.ui.gtk3 import app
1818
1919
20class FakedCache(dict):
21 """A faked cache."""
22
23 def __init__(self, *a, **kw):
24 super(FakedCache, self).__init__()
25 self._callbacks = defaultdict(list)
26 self.ready = False
27
28 def open(self):
29 """Open this cache."""
30 self.ready = True
31
32 def connect(self, signal, callback):
33 """Connect a signal with a callback."""
34 self._callbacks[signal].append(callback)
35
36 def disconnect_by_func(self, callback):
37 """Disconnect 'callback' from every signal."""
38 for signal, cb in self._callbacks.iteritems():
39 if cb == callback:
40 self._callbacks[signal].remove(callback)
41 if len(self._callbacks[signal]) == 0:
42 self._callbacks.pop(signal)
43
44 def get_addons(self, pkgname):
45 """Return (recommended, suggested) addons for 'pkgname'."""
46 return ([],[])
47
48 def get_total_size_on_install(self,pkgname, addons_to_install,
49 addons_to_remove, archive_suite):
50 """Return a fake (total_download_size, total_install_size) result."""
51 return (0, 0)
52
53
54class ParsePackagesArgsTestCase(unittest.TestCase):20class ParsePackagesArgsTestCase(unittest.TestCase):
55 """Test suite for the parse_packages_args helper."""21 """Test suite for the parse_packages_args helper."""
5622
@@ -109,7 +75,7 @@
109 fname = __file__75 fname = __file__
110 assert os.path.exists(fname)76 assert os.path.exists(fname)
111 self.assertRaises(DebFileOpenError, app.parse_packages_args, fname)77 self.assertRaises(DebFileOpenError, app.parse_packages_args, fname)
112 78
11379
114class ParsePackagesWithAptPrefixTestCase(ParsePackagesArgsTestCase):80class ParsePackagesWithAptPrefixTestCase(ParsePackagesArgsTestCase):
11581
11682
=== modified file 'test/gtk3/test_catview.py'
--- test/gtk3/test_catview.py 2012-03-15 22:23:21 +0000
+++ test/gtk3/test_catview.py 2012-05-22 12:42:24 +0000
@@ -1,66 +1,81 @@
1import unittest
2
1from gi.repository import Gtk3from gi.repository import Gtk
2import time
3import unittest
4from mock import patch, Mock4from mock import patch, Mock
55
6from testutils import setup_test_env6from testutils import setup_test_env
7setup_test_env()7setup_test_env()
88
9import softwarecenter.distro
10import softwarecenter.paths
11
12from softwarecenter.db.database import StoreDatabase
9from softwarecenter.enums import SortMethods13from softwarecenter.enums import SortMethods
10from softwarecenter.testutils import (get_test_db,14from softwarecenter.testutils import (
11 make_recommender_agent_recommend_me_dict)15 do_events_with_sleep,
1216 do_events,
13class TestCatView(unittest.TestCase):17 FakedCache,
18 get_test_db,
19 make_recommender_agent_recommend_me_dict,
20 ObjectWithSignals,
21)
22from softwarecenter.ui.gtk3.views import catview_gtk
23from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
24from softwarecenter.ui.gtk3.widgets.containers import FramedHeaderBox
25from softwarecenter.ui.gtk3.widgets.spinner import SpinnerNotebook
26
27
28class CatViewBaseTestCase(unittest.TestCase):
29
30 @classmethod
31 def setUpClass(cls):
32 cls.db = get_test_db()
1433
15 def setUp(self):34 def setUp(self):
16 self.db = get_test_db()35 self._cat = None
36 self.win = get_test_window_catview(self.db)
37 self.addCleanup(self.win.destroy)
38 self.notebook = self.win.get_child()
39 self.lobby = self.win.get_data("lobby")
40 self.subcat_view = self.win.get_data("subcat")
41 self.rec_panel = self.lobby.recommended_for_you_panel
1742
18 def _on_category_selected(self, subcatview, category):43 def _on_category_selected(self, subcatview, category):
19 #print "**************", subcatview, category
20 self._cat = category44 self._cat = category
21 45
22 def test_subcatview_top_rated(self):46
23 from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview47class TopAndWhatsNewTestCase(CatViewBaseTestCase):
24 # get the widgets we need48
25 win = get_test_window_catview()49 def test_top_rated(self):
26 lobby = win.get_data("lobby")
27
28 # simulate review-stats refresh50 # simulate review-stats refresh
29 lobby._update_top_rated_content = Mock()51 self.lobby._update_top_rated_content = Mock()
30 lobby.reviews_loader.emit("refresh-review-stats-finished", [])52 self.lobby.reviews_loader.emit("refresh-review-stats-finished", [])
31 self.assertTrue(lobby._update_top_rated_content.called)53 self.assertTrue(self.lobby._update_top_rated_content.called)
3254
33 # test clicking top_rated55 # test clicking top_rated
34 lobby.connect("category-selected", self._on_category_selected)56 self.lobby.connect("category-selected", self._on_category_selected)
35 lobby.top_rated_frame.more.clicked()57 self.lobby.top_rated_frame.more.clicked()
36 self._p()58 do_events()
37 self.assertNotEqual(self._cat, None)59 self.assertNotEqual(self._cat, None)
38 self.assertEqual(self._cat.name, "Top Rated")60 self.assertEqual(self._cat.name, "Top Rated")
39 self.assertEqual(self._cat.sortmode, SortMethods.BY_TOP_RATED)61 self.assertEqual(self._cat.sortmode, SortMethods.BY_TOP_RATED)
40 win.destroy()62
4163 def test_new(self):
42 def test_subcatview_new(self):
43 from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
44 # get the widgets we need
45 win = get_test_window_catview()
46 lobby = win.get_data("lobby")
47
48 # test db reopen triggers whats-new update64 # test db reopen triggers whats-new update
49 lobby._update_whats_new_content = Mock()65 self.lobby._update_whats_new_content = Mock()
50 lobby.db.emit("reopen")66 self.lobby.db.emit("reopen")
51 self.assertTrue(lobby._update_whats_new_content.called)67 self.assertTrue(self.lobby._update_whats_new_content.called)
5268
53 # test clicking new69 # test clicking new
54 lobby.connect("category-selected", self._on_category_selected)70 self.lobby.connect("category-selected", self._on_category_selected)
55 lobby.whats_new_frame.more.clicked()71 self.lobby.whats_new_frame.more.clicked()
56 self._p()72 do_events()
57 self.assertNotEqual(self._cat, None)73 self.assertNotEqual(self._cat, None)
58 # encoding is utf-8 (since r2218, see category.py)74 # encoding is utf-8 (since r2218, see category.py)
59 self.assertEqual(self._cat.name, 'What\xe2\x80\x99s New')75 self.assertEqual(self._cat.name, 'What\xe2\x80\x99s New')
60 self.assertEqual(self._cat.sortmode, SortMethods.BY_CATALOGED_TIME)76 self.assertEqual(self._cat.sortmode, SortMethods.BY_CATALOGED_TIME)
61 win.destroy()
6277
63 def test_subcatview_new_no_sort_info_yet(self):78 def test_new_no_sort_info_yet(self):
64 # ensure that we don't show a empty "whats new" category79 # ensure that we don't show a empty "whats new" category
65 # see LP: #86598580 # see LP: #865985
66 from softwarecenter.testutils import get_test_db81 from softwarecenter.testutils import get_test_db
@@ -68,7 +83,7 @@
68 cache = db._aptcache83 cache = db._aptcache
69 # simulate a fresh install with no catalogedtime info84 # simulate a fresh install with no catalogedtime info
70 del db._axi_values["catalogedtime"]85 del db._axi_values["catalogedtime"]
71 86
72 from softwarecenter.testutils import get_test_gtk3_icon_cache87 from softwarecenter.testutils import get_test_gtk3_icon_cache
73 icons = get_test_gtk3_icon_cache()88 icons = get_test_gtk3_icon_cache()
7489
@@ -76,7 +91,6 @@
76 apps_filter = AppFilter(db, cache)91 apps_filter = AppFilter(db, cache)
7792
78 from softwarecenter.distro import get_distro93 from softwarecenter.distro import get_distro
79 import softwarecenter.paths
80 from softwarecenter.paths import APP_INSTALL_PATH94 from softwarecenter.paths import APP_INSTALL_PATH
81 from softwarecenter.ui.gtk3.views.catview_gtk import LobbyViewGtk95 from softwarecenter.ui.gtk3.views.catview_gtk import LobbyViewGtk
82 view = LobbyViewGtk(softwarecenter.paths.datadir, APP_INSTALL_PATH,96 view = LobbyViewGtk(softwarecenter.paths.datadir, APP_INSTALL_PATH,
@@ -85,6 +99,7 @@
8599
86 # gui100 # gui
87 win = Gtk.Window()101 win = Gtk.Window()
102 self.addCleanup(win.destroy)
88 win.set_size_request(800, 400)103 win.set_size_request(800, 400)
89104
90 scroll = Gtk.ScrolledWindow()105 scroll = Gtk.ScrolledWindow()
@@ -93,171 +108,198 @@
93 win.add(scroll)108 win.add(scroll)
94 win.show()109 win.show()
95 # test visibility110 # test visibility
96 self._p()111 do_events()
97 self.assertFalse(view.whats_new_frame.get_property("visible"))112 self.assertFalse(view.whats_new_frame.get_property("visible"))
98 self._p()113
99 win.destroy()114
100115class RecommendationsTestCase(CatViewBaseTestCase):
101 def test_subcatview_recommended_for_you_opt_in_display(self):116 """The test suite for the recommendations ."""
102 117
103 # patch the recommender UUID value to insure that we are not opted-in for this test118 @patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
104 get_recommender_opted_in_patcher = patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')119 def test_recommended_for_you_opt_in_display(
105 self.addCleanup(get_recommender_opted_in_patcher.stop)120 self, mock_get_recommender_opted_in):
106 mock_get_recommender_opted_in = get_recommender_opted_in_patcher.start()121 # patch the recommender UUID value to ensure that we are not opted-in
107 mock_get_recommender_opted_in.return_value = False122 # for this test
108 123 mock_get_recommender_opted_in.return_value = False
109 from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview124
110 # get the widgets we need125 do_events()
111 win = get_test_window_catview()126 self.assertEqual(self.rec_panel.spinner_notebook.get_current_page(),
112 lobby = win.get_data("lobby")127 FramedHeaderBox.CONTENT)
113 rec_panel = lobby.recommended_for_you_panel128 self.assertTrue(self.rec_panel.opt_in_vbox.get_property("visible"))
114 self._p()129
115 from softwarecenter.ui.gtk3.widgets.containers import FramedHeaderBox130 # patch out the agent query method to avoid making the actual server call
116 self.assertTrue(rec_panel.spinner_notebook.get_current_page() == FramedHeaderBox.CONTENT)131 @patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
117 self.assertTrue(rec_panel.opt_in_vbox.get_property("visible"))132 @patch('softwarecenter.backend.recagent.RecommenderAgent'
118 win.destroy()133 '.post_submit_profile')
119 134 def test_recommended_for_you_spinner_display(
120 # patch out the agent query method to avoid making the actual server call135 self, mock_query, mock_get_recommender_opted_in):
121 @patch('softwarecenter.backend.recagent.RecommenderAgent'136 # patch the recommender UUID value to insure that we are not opted-in
122 '.post_submit_profile')137 # for this test
123 def test_subcatview_recommended_for_you_spinner_display(self, mock_query):138 mock_get_recommender_opted_in.return_value = False
124 139
125 # patch the recommender UUID value to insure that we are not opted-in for this test140 # click the opt-in button to initiate the process,
126 get_recommender_opted_in_patcher = patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')141 # this will show the spinner
127 self.addCleanup(get_recommender_opted_in_patcher.stop)142 self.rec_panel.opt_in_button.emit('clicked')
128 mock_get_recommender_opted_in = get_recommender_opted_in_patcher.start()143 do_events()
129 mock_get_recommender_opted_in.return_value = False144 self.assertEqual(self.rec_panel.spinner_notebook.get_current_page(),
130 145 SpinnerNotebook.SPINNER_PAGE)
131 from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview146 self.assertTrue(self.rec_panel.opt_in_vbox.get_property("visible"))
132 # get the widgets we need147
133 win = get_test_window_catview()148 # patch out the agent query method to avoid making the actual server call
134 lobby = win.get_data("lobby")149 @patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
135 rec_panel = lobby.recommended_for_you_panel150 @patch('softwarecenter.backend.recagent.RecommenderAgent'
136 self._p()151 '.post_submit_profile')
137 # click the opt-in button to initiate the process, this will show the spinner152 def test_recommended_for_you_display_recommendations(self,
138 rec_panel.opt_in_button.emit('clicked')153 mock_query, mock_get_recommender_opted_in):
139 self._p()154 # patch the recommender UUID value to insure that we are not opted-in
140 from softwarecenter.ui.gtk3.widgets.spinner import SpinnerNotebook155 # for this test
141 self.assertTrue(rec_panel.spinner_notebook.get_current_page() == SpinnerNotebook.SPINNER_PAGE)156 mock_get_recommender_opted_in.return_value = False
142 self.assertTrue(rec_panel.opt_in_vbox.get_property("visible"))157
143 win.destroy()158 # click the opt-in button to initiate the process,
144159 # this will show the spinner
145 # patch out the agent query method to avoid making the actual server call160 self.rec_panel.opt_in_button.emit('clicked')
146 @patch('softwarecenter.backend.recagent.RecommenderAgent'161 do_events()
147 '.post_submit_profile')162 self.rec_panel._update_recommended_for_you_content()
148 def test_subcatview_recommended_for_you_display_recommendations(self, mock_query):163 do_events()
149
150 # patch the recommender UUID value to insure that we are not opted-in for this test
151 get_recommender_opted_in_patcher = patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
152 self.addCleanup(get_recommender_opted_in_patcher.stop)
153 mock_get_recommender_opted_in = get_recommender_opted_in_patcher.start()
154 mock_get_recommender_opted_in.return_value = False
155
156 from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
157 # get the widgets we need
158 win = get_test_window_catview()
159 lobby = win.get_data("lobby")
160 rec_panel = lobby.recommended_for_you_panel
161 self._p()
162 # click the opt-in button to initiate the process, this will show the spinner
163 rec_panel.opt_in_button.emit('clicked')
164 self._p()
165 rec_panel._update_recommended_for_you_content()
166 self._p()
167 # we fake the callback from the agent here164 # we fake the callback from the agent here
168 lobby.recommended_for_you_panel.recommended_for_you_cat._recommend_me_result(165 for_you = self.lobby.recommended_for_you_panel.recommended_for_you_cat
169 None,166 for_you._recommend_me_result(None,
170 make_recommender_agent_recommend_me_dict())167 make_recommender_agent_recommend_me_dict())
171 self.assertNotEqual(168 self.assertNotEqual(for_you.get_documents(self.db), [])
172 lobby.recommended_for_you_panel.recommended_for_you_cat.get_documents(self.db), [])169 self.assertEqual(self.rec_panel.spinner_notebook.get_current_page(),
173 from softwarecenter.ui.gtk3.widgets.spinner import SpinnerNotebook170 SpinnerNotebook.CONTENT_PAGE)
174 self.assertTrue(rec_panel.spinner_notebook.get_current_page() == SpinnerNotebook.CONTENT_PAGE)171 do_events()
175 self._p()
176 # test clicking recommended_for_you More button172 # test clicking recommended_for_you More button
177 lobby.connect("category-selected", self._on_category_selected)173 self.lobby.connect("category-selected", self._on_category_selected)
178 lobby.recommended_for_you_panel.more.clicked()174 self.lobby.recommended_for_you_panel.more.clicked()
179 self._p()175 # this is delayed for some reason so we need to sleep here
176 do_events_with_sleep()
180 self.assertNotEqual(self._cat, None)177 self.assertNotEqual(self._cat, None)
181 self.assertEqual(self._cat.name, "Recommended For You")178 self.assertEqual(self._cat.name, "Recommended For You")
182 win.destroy()179
183
184 # patch out the agent query method to avoid making the actual server call180 # patch out the agent query method to avoid making the actual server call
181 @patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
185 @patch('softwarecenter.backend.recagent.RecommenderAgent'182 @patch('softwarecenter.backend.recagent.RecommenderAgent'
186 '.query_recommend_me')183 '.query_recommend_me')
187 def test_subcatview_recommended_for_you_display_recommendations_not_opted_in(self, mock_query):184 def test_recommended_for_you_display_recommendations_not_opted_in(self,
188 185 mock_query, mock_get_recommender_opted_in):
189 # patch the recommender UUID value to insure that we are not opted-in for this test186 # patch the recommender UUID value to insure that we are not opted-in
190 get_recommender_opted_in_patcher = patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')187 # for this test
191 self.addCleanup(get_recommender_opted_in_patcher.stop)
192 mock_get_recommender_opted_in = get_recommender_opted_in_patcher.start()
193 mock_get_recommender_opted_in.return_value = False188 mock_get_recommender_opted_in.return_value = False
194 189
195 from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
196 # get the widgets we need
197 win = get_test_window_catview()
198 # we want to work in the "subcat" view190 # we want to work in the "subcat" view
199 notebook = win.get_child()191 self.notebook.next_page()
200 notebook.next_page()192
201 193 do_events()
202 subcat_view = win.get_data("subcat")194 visible = self.subcat_view.recommended_for_you_in_cat.get_property(
203 self._p()195 "visible")
204 self.assertFalse(subcat_view.recommended_for_you_in_cat.get_property("visible"))196 self.assertFalse(visible)
205 win.destroy()197
206
207 # patch out the agent query method to avoid making the actual server call198 # patch out the agent query method to avoid making the actual server call
199 @patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')
208 @patch('softwarecenter.backend.recagent.RecommenderAgent'200 @patch('softwarecenter.backend.recagent.RecommenderAgent'
209 '.query_recommend_me')201 '.query_recommend_me')
210 def test_subcatview_recommended_for_you_display_recommendations_opted_in(self, mock_query):202 def test_recommended_for_you_display_recommendations_opted_in(
211 203 self, mock_query, mock_get_recommender_opted_in):
212 # patch the recommender UUID value to insure that we are not opted-in for this test204 # patch the recommender UUID value to insure that we are not opted-in
213 get_recommender_opted_in_patcher = patch('softwarecenter.backend.recagent.RecommenderAgent.is_opted_in')205 # for this test
214 self.addCleanup(get_recommender_opted_in_patcher.stop)
215 mock_get_recommender_opted_in = get_recommender_opted_in_patcher.start()
216 mock_get_recommender_opted_in.return_value = True206 mock_get_recommender_opted_in.return_value = True
217 207
218 from softwarecenter.ui.gtk3.views.catview_gtk import get_test_window_catview
219 # get the widgets we need
220 win = get_test_window_catview()
221 # we want to work in the "subcat" view208 # we want to work in the "subcat" view
222 notebook = win.get_child()209 self.notebook.next_page()
223 notebook.next_page()210
224 211 rec_cat_panel = self.subcat_view.recommended_for_you_in_cat
225 subcat_view = win.get_data("subcat")
226 rec_cat_panel = subcat_view.recommended_for_you_in_cat
227 self._p()
228 rec_cat_panel._update_recommended_for_you_content()212 rec_cat_panel._update_recommended_for_you_content()
229 self._p()213 do_events()
230 # we fake the callback from the agent here214 # we fake the callback from the agent here
231 rec_cat_panel.recommended_for_you_cat._recommend_me_result(215 rec_cat_panel.recommended_for_you_cat._recommend_me_result(
232 None,216 None,
233 make_recommender_agent_recommend_me_dict())217 make_recommender_agent_recommend_me_dict())
234 result_docs = rec_cat_panel.recommended_for_you_cat.get_documents(self.db)218 result_docs = rec_cat_panel.recommended_for_you_cat.get_documents(
219 self.db)
235 self.assertNotEqual(result_docs, [])220 self.assertNotEqual(result_docs, [])
236 # check that we are getting the correct number of results, corresponding221 # check that we are getting the correct number of results,
237 # to the following Internet items:222 # corresponding to the following Internet items:
238 # Mangler, Midori, Midori Private Browsing, Psi223 # Mangler, Midori, Midori Private Browsing, Psi
239 self.assertTrue(len(result_docs) == 4)224 self.assertTrue(len(result_docs) == 4)
240 from softwarecenter.ui.gtk3.widgets.spinner import SpinnerNotebook225 self.assertEqual(rec_cat_panel.spinner_notebook.get_current_page(),
241 self.assertTrue(rec_cat_panel.spinner_notebook.get_current_page() == SpinnerNotebook.CONTENT_PAGE)226 SpinnerNotebook.CONTENT_PAGE)
242 # check that the tiles themselves are visible227 # check that the tiles themselves are visible
243 self._p()228 do_events()
244 self.assertTrue(rec_cat_panel.recommended_for_you_content.get_property("visible"))229 self.assertTrue(rec_cat_panel.recommended_for_you_content.get_property(
245 self.assertTrue(rec_cat_panel.recommended_for_you_content.get_children()[0].title.get_property("visible"))230 "visible"))
246 self._p()231 self.assertTrue(rec_cat_panel.recommended_for_you_content.get_children(
232 )[0].title.get_property("visible"))
233 do_events()
247 # test clicking recommended_for_you More button234 # test clicking recommended_for_you More button
248 subcat_view.connect("category-selected", self._on_category_selected)235 self.subcat_view.connect(
236 "category-selected", self._on_category_selected)
249 rec_cat_panel.more.clicked()237 rec_cat_panel.more.clicked()
250 self._p()238 # this is delayed for some reason so we need to sleep here
239 do_events_with_sleep()
251 self.assertNotEqual(self._cat, None)240 self.assertNotEqual(self._cat, None)
252 self.assertEqual(self._cat.name, "Recommended For You in Internet")241 self.assertEqual(self._cat.name, "Recommended For You in Internet")
253 win.destroy()242
254243
255 def _p(self):244class ExhibitsTestCase(unittest.TestCase):
256 for i in range(5):245 """The test suite for the exhibits carousel."""
257 time.sleep(0.1)246
258 while Gtk.events_pending():247 def setUp(self):
259 Gtk.main_iteration()248 self.datadir = softwarecenter.paths.datadir
260249 self.desktopdir = softwarecenter.paths.APP_INSTALL_PATH
250 self.cache = FakedCache()
251 self.db = StoreDatabase(cache=self.cache)
252 self.lobby = catview_gtk.LobbyViewGtk(datadir=self.datadir,
253 desktopdir=self.desktopdir, cache=self.cache, db=self.db,
254 icons=None, apps_filter=None)
255 self.addCleanup(self.lobby.destroy)
256
257 def _get_banner_from_lobby(self):
258 return self.lobby.vbox.get_children()[-1].get_child()
259
260 def test_featured_exhibit_by_default(self):
261 """Show the featured exhibit before querying the remote service."""
262 self.lobby._append_banner_ads()
263
264 banner = self._get_banner_from_lobby()
265 self.assertEqual(1, len(banner.exhibits))
266 self.assertIsInstance(banner.exhibits[0], catview_gtk.FeaturedExhibit)
267
268 def test_no_exhibit_if_not_available(self):
269 """The exhibit should not be shown if the package is not available."""
270 exhibit = Mock()
271 exhibit.package_names = u'foobarbaz'
272
273 sca = ObjectWithSignals()
274 sca.query_exhibits = lambda: sca.emit('exhibits', sca, [exhibit])
275
276 with patch.object(catview_gtk, 'SoftwareCenterAgent', lambda: sca):
277 self.lobby._append_banner_ads()
278
279 banner = self._get_banner_from_lobby()
280 self.assertEqual(1, len(banner.exhibits))
281 self.assertIsInstance(banner.exhibits[0], catview_gtk.FeaturedExhibit)
282
283 def test_exhibit_if_available(self):
284 """The exhibit should be shown if the package is not available."""
285 exhibit = Mock()
286 exhibit.package_names = u'foobarbaz'
287 exhibit.banner_url = 'banner'
288
289 pkg = Mock()
290 pkg.banner_url = ''
291 pkg.title_translated = ''
292 self.cache[u'foobarbaz'] = pkg
293
294 sca = ObjectWithSignals()
295 sca.query_exhibits = lambda: sca.emit('exhibits', sca, [exhibit])
296
297 with patch.object(catview_gtk, 'SoftwareCenterAgent', lambda: sca):
298 self.lobby._append_banner_ads()
299
300 banner = self._get_banner_from_lobby()
301 self.assertEqual(1, len(banner.exhibits))
302 self.assertIs(banner.exhibits[0], exhibit)
261303
262304
263if __name__ == "__main__":305if __name__ == "__main__":

Subscribers

People subscribed via source and target branches