Merge lp:~nataliabidart/software-center/fix-977931 into lp:software-center/5.2

Proposed by Natalia Bidart
Status: Merged
Merged at revision: 3027
Proposed branch: lp:~nataliabidart/software-center/fix-977931
Merge into: lp:software-center/5.2
Diff against target: 1180 lines (+627/-146)
19 files modified
README (+1/-0)
softwarecenter/backend/spawn_helper.py (+3/-0)
softwarecenter/db/__init__.py (+7/-2)
softwarecenter/db/database.py (+4/-0)
softwarecenter/db/debfile.py (+38/-21)
softwarecenter/enums.py (+6/-0)
softwarecenter/testutils.py (+11/-1)
softwarecenter/ui/gtk3/SimpleGtkbuilderApp.py (+2/-1)
softwarecenter/ui/gtk3/app.py (+151/-89)
softwarecenter/ui/gtk3/models/appstore2.py (+1/-0)
softwarecenter/ui/gtk3/session/appmanager.py (+5/-0)
softwarecenter/ui/gtk3/session/viewmanager.py (+5/-0)
softwarecenter/ui/gtk3/views/appdetailsview.py (+2/-2)
softwarecenter/ui/gtk3/widgets/videoplayer.py (+5/-1)
test/gtk3/test_app.py (+357/-0)
test/gtk3/test_debfile_view.py (+3/-8)
test/gtk3/test_purchase.py (+8/-12)
test/test_database.py (+8/-3)
test/test_debfileapplication.py (+10/-6)
To merge this branch: bzr merge lp:~nataliabidart/software-center/fix-977931
Reviewer Review Type Date Requested Status
Michael Vogt Approve
Review via email: mp+106011@code.launchpad.net

This proposal supersedes a proposal from 2012-04-17.

Commit message

- Unified package string parsing into a single method that will be used from either the command line arguments, or from the dbus method 'bringToFront'. This way, search will be consistent between all entry points.
- Also added proper test suites for the above.

To post a comment you must log in.
Revision history for this message
Michael Vogt (mvo) wrote : Posted in a previous version of this proposal

Thanks Natalia for this branch and sorry for my slow reply.

First let me say thanks for the work and the refactor and the excellent test, we shall use that
as a example.

This looks fine, there have been some changes in the 5.2 branch so I merged it and resolved
conflicts and tweaked it a bit more, please remerge lp:~mvo/software-center/fix-977931/ with this branch
and let me know what you think.

I was curious how to reproduce/understand the changes in appview.py, reviews.py that cause the model to
be "None". I revert that change but for me its not crashing so I wonder if that is still needed? Or is it
a random issue? Except for this (which I just would like to understand better how it happens) the branch
is +10 approve ;)

Additional thanks for unifying get_mock_options() and the with open() fix (and the cleanup) in test_database.py.

Revision history for this message
Natalia Bidart (nataliabidart) wrote : Posted in a previous version of this proposal

Merged the branch suggested by mvo adding a minor tweaks about detetcting .deb files.

2993. By Natalia Bidart

Merged 5.2 in.

2994. By Natalia Bidart

Merged 5.2 in.

Revision history for this message
Michael Vogt (mvo) wrote :

This looks great, I will merge it now into 5.2 (and it will be merged into trunk via 5.2 too).

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'README'
--- README 2012-03-08 18:08:49 +0000
+++ README 2012-05-21 15:37:20 +0000
@@ -53,6 +53,7 @@
53SOFTWARE_CENTER_DISTRO_CODENAME - overwrite "lsb_release -c -s" output53SOFTWARE_CENTER_DISTRO_CODENAME - overwrite "lsb_release -c -s" output
54SOFTWARE_CENTER_ARCHITECTURE - overwrite the current architecture54SOFTWARE_CENTER_ARCHITECTURE - overwrite the current architecture
55SOFTWARE_CENTER_NO_SC_AGENT - disable the software-center-agent55SOFTWARE_CENTER_NO_SC_AGENT - disable the software-center-agent
56SOFTWARE_CENTER_DISABLE_SPAWN_HELPER - disable everything that is run via the "SpawnHelper", i.e. recommender-agent, software-center-agent, reviews
56SOFTWARE_CENTER_DEBUG_TABS - show notebook tabs for debugging57SOFTWARE_CENTER_DEBUG_TABS - show notebook tabs for debugging
57SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK - disables certificates checking in webkit views (for use in test environments)58SOFTWARE_CENTER_FORCE_DISABLE_CERTS_CHECK - disables certificates checking in webkit views (for use in test environments)
58SOFTWARE_CENTER_FORCE_NON_SSL - disable SSL (for use in test environments)59SOFTWARE_CENTER_FORCE_NON_SSL - disable SSL (for use in test environments)
5960
=== modified file 'softwarecenter/backend/spawn_helper.py'
--- softwarecenter/backend/spawn_helper.py 2012-03-19 13:35:47 +0000
+++ softwarecenter/backend/spawn_helper.py 2012-05-21 15:37:20 +0000
@@ -86,6 +86,9 @@
86 self.run(cmd)86 self.run(cmd)
8787
88 def run(self, cmd):88 def run(self, cmd):
89 # only useful for debugging
90 if "SOFTWARE_CENTER_DISABLE_SPAWN_HELPER" in os.environ:
91 return
89 self._cmd = cmd92 self._cmd = cmd
90 (pid, stdin, stdout, stderr) = GObject.spawn_async(93 (pid, stdin, stdout, stderr) = GObject.spawn_async(
91 cmd, flags=GObject.SPAWN_DO_NOT_REAP_CHILD,94 cmd, flags=GObject.SPAWN_DO_NOT_REAP_CHILD,
9295
=== modified file 'softwarecenter/db/__init__.py'
--- softwarecenter/db/__init__.py 2012-03-15 04:30:04 +0000
+++ softwarecenter/db/__init__.py 2012-05-21 15:37:20 +0000
@@ -1,9 +1,14 @@
1import logging1import logging
2
2try:3try:
3 from debfile import DebFileApplication4 from debfile import DebFileApplication, DebFileOpenError
4 DebFileApplication # pyflakes5 DebFileApplication # pyflakes
6 DebFileOpenError # pyflakes
5except:7except:
6 logging.exception("DebFileApplication import")8 logging.exception("DebFileApplication import")
79
8 class DebFileApplication():10 class DebFileApplication(object):
11 pass
12
13 class DebFileOpenError(Exception):
9 pass14 pass
1015
=== modified file 'softwarecenter/db/database.py'
--- softwarecenter/db/database.py 2012-04-12 10:15:36 +0000
+++ softwarecenter/db/database.py 2012-05-21 15:37:20 +0000
@@ -139,6 +139,10 @@
139139
140 def __init__(self, pathname=None, cache=None):140 def __init__(self, pathname=None, cache=None):
141 GObject.GObject.__init__(self)141 GObject.GObject.__init__(self)
142 # initialize at creation time to avoid spurious AttributeError
143 self._use_agent = False
144 self._use_axi = False
145
142 if pathname is None:146 if pathname is None:
143 pathname = softwarecenter.paths.XAPIAN_PATH147 pathname = softwarecenter.paths.XAPIAN_PATH
144 self._db_pathname = pathname148 self._db_pathname = pathname
145149
=== modified file 'softwarecenter/db/debfile.py'
--- softwarecenter/db/debfile.py 2012-03-29 00:18:23 +0000
+++ softwarecenter/db/debfile.py 2012-05-21 15:37:20 +0000
@@ -27,12 +27,28 @@
27from softwarecenter.utils import ExecutionTime, utf827from softwarecenter.utils import ExecutionTime, utf8
2828
2929
30DEB_MIME_TYPE = 'application/x-debian-package'
31
32
33def is_deb_file(debfile):
34 mtype = guess_type(debfile)
35 return mtype is not None and DEB_MIME_TYPE in mtype
36
37
38class DebFileOpenError(Exception):
39 """ Raised if a DebFile fails to open """
40
41 def __init__(self, msg, path):
42 super(DebFileOpenError, self).__init__(msg)
43 self.path = path
44
45
30class DebFileApplication(Application):46class DebFileApplication(Application):
3147
32 def __init__(self, debfile):48 def __init__(self, debfile):
33 # sanity check49 if not is_deb_file(debfile):
34 if not debfile.endswith(".deb"):50 raise DebFileOpenError("Could not open %r." % debfile, debfile)
35 raise ValueError("Need a deb file, got '%s'" % debfile)51
36 # work out debname/appname52 # work out debname/appname
37 debname = os.path.splitext(os.path.basename(debfile))[0]53 debname = os.path.splitext(os.path.basename(debfile))[0]
38 pkgname = debname.split('_')[0].lower()54 pkgname = debname.split('_')[0].lower()
@@ -50,7 +66,21 @@
50 def __init__(self, db, doc=None, application=None):66 def __init__(self, db, doc=None, application=None):
51 super(AppDetailsDebFile, self).__init__(db, doc, application)67 super(AppDetailsDebFile, self).__init__(db, doc, application)
52 if doc:68 if doc:
53 raise ValueError("doc must be None for deb files")69 raise DebFileOpenError("AppDetailsDebFile: doc must be None.")
70
71 self._error = None
72 # check errors before creating the DebPackage
73 if not os.path.exists(self._app.request):
74 self._error = _("Not found")
75 self._error_not_found = utf8(_(u"The file \u201c%s\u201d "
76 "does not exist.")) % utf8(self._app.request)
77 elif not is_deb_file(self._app.request):
78 self._error = _("Not found")
79 self._error_not_found = utf8(_(u"The file \u201c%s\u201d "
80 "is not a software package.")) % utf8(self._app.request)
81
82 if self._error is not None:
83 return
5484
55 try:85 try:
56 with ExecutionTime("create DebPackage"):86 with ExecutionTime("create DebPackage"):
@@ -59,23 +89,10 @@
59 self._deb = DebPackage(self._app.request, self._cache._cache)89 self._deb = DebPackage(self._app.request, self._cache._cache)
60 except:90 except:
61 self._deb = None91 self._deb = None
62 self._pkg = None92 # deb files which are corrupt
63 if not os.path.exists(self._app.request):93 self._error = _("Internal Error")
64 self._error = _("Not found")94 self._error_not_found = utf8(_(u"The file \u201c%s\u201d "
65 self._error_not_found = utf8(_(u"The file \u201c%s\u201d "95 "could not be opened.")) % utf8(self._app.request)
66 "does not exist.")) % utf8(self._app.request)
67 else:
68 mimetype = guess_type(self._app.request)
69 if mimetype[0] != "application/x-debian-package":
70 self._error = _("Not found")
71 self._error_not_found = utf8(_(u"The file \u201c%s\u201d "
72 "is not a software package.")) % utf8(
73 self._app.request)
74 else:
75 # deb files which are corrupt
76 self._error = _("Internal Error")
77 self._error_not_found = utf8(_(u"The file \u201c%s\u201d "
78 "could not be opened.")) % utf8(self._app.request)
79 return96 return
8097
81 if self.pkgname and self.pkgname != self._app.pkgname:98 if self.pkgname and self.pkgname != self._app.pkgname:
8299
=== modified file 'softwarecenter/enums.py'
--- softwarecenter/enums.py 2012-03-21 20:54:46 +0000
+++ softwarecenter/enums.py 2012-05-21 15:37:20 +0000
@@ -237,6 +237,12 @@
237 REPAIR = "repair_dependencies"237 REPAIR = "repair_dependencies"
238238
239239
240# Search separators
241class SearchSeparators:
242 REGULAR = " "
243 PACKAGE = ","
244
245
240# mouse event codes for back/forward buttons246# mouse event codes for back/forward buttons
241# TODO: consider whether we ought to get these values from gconf so that we247# TODO: consider whether we ought to get these values from gconf so that we
242# can be sure to use the corresponding values used by Nautilus:248# can be sure to use the corresponding values used by Nautilus:
243249
=== modified file 'softwarecenter/testutils.py'
--- softwarecenter/testutils.py 2012-03-19 14:23:52 +0000
+++ softwarecenter/testutils.py 2012-05-21 15:37:20 +0000
@@ -22,6 +22,7 @@
22import tempfile22import tempfile
23import time23import time
2424
25from mock import Mock
2526
26m_dbus = m_polkit = m_aptd = None27m_dbus = m_polkit = m_aptd = None
2728
@@ -145,7 +146,6 @@
145 """ take a application and return a app where the details are a mock146 """ take a application and return a app where the details are a mock
146 of the real details so they can easily be modified147 of the real details so they can easily be modified
147 """148 """
148 from mock import Mock
149 import copy149 import copy
150 app = copy.copy(real_app)150 app = copy.copy(real_app)
151 db = get_test_db()151 db = get_test_db()
@@ -160,6 +160,16 @@
160 return app160 return app
161161
162162
163def get_mock_options():
164 """Return a mock suitable to act as SoftwareCenterAppGtk3's options."""
165 mock_options = Mock()
166 mock_options.display_navlog = False
167 mock_options.disable_apt_xapian_index = False
168 mock_options.disable_buy = False
169
170 return mock_options
171
172
163def setup_test_env():173def setup_test_env():
164 """ Setup environment suitable for running the test/* code in a checkout.174 """ Setup environment suitable for running the test/* code in a checkout.
165 This includes PYTHONPATH, sys.path and softwarecenter.paths.datadir.175 This includes PYTHONPATH, sys.path and softwarecenter.paths.datadir.
166176
=== modified file 'softwarecenter/ui/gtk3/SimpleGtkbuilderApp.py'
--- softwarecenter/ui/gtk3/SimpleGtkbuilderApp.py 2012-03-15 09:32:18 +0000
+++ softwarecenter/ui/gtk3/SimpleGtkbuilderApp.py 2012-05-21 15:37:20 +0000
@@ -23,9 +23,10 @@
2323
2424
25# based on SimpleGladeApp25# based on SimpleGladeApp
26class SimpleGtkbuilderApp:26class SimpleGtkbuilderApp(object):
2727
28 def __init__(self, path, domain):28 def __init__(self, path, domain):
29 super(SimpleGtkbuilderApp, self).__init__()
29 self.builder = Gtk.Builder()30 self.builder = Gtk.Builder()
30 self.builder.set_translation_domain(domain)31 self.builder.set_translation_domain(domain)
31 self.builder.add_from_file(path)32 self.builder.add_from_file(path)
3233
=== modified file 'softwarecenter/ui/gtk3/app.py'
--- softwarecenter/ui/gtk3/app.py 2012-05-15 18:37:27 +0000
+++ softwarecenter/ui/gtk3/app.py 2012-05-21 15:37:20 +0000
@@ -31,6 +31,7 @@
31import gettext31import gettext
32import logging32import logging
33import os33import os
34import re
34import subprocess35import subprocess
35import sys36import sys
36import xapian37import xapian
@@ -47,28 +48,35 @@
4748
48# db imports49# db imports
49from softwarecenter.db.application import Application50from softwarecenter.db.application import Application
50from softwarecenter.db import DebFileApplication51from softwarecenter.db import DebFileApplication, DebFileOpenError
51from softwarecenter.i18n import init_locale52from softwarecenter.i18n import init_locale
5253
53# misc imports54# misc imports
54from softwarecenter.plugin import PluginManager55from softwarecenter.plugin import PluginManager
55from softwarecenter.paths import SOFTWARE_CENTER_PLUGIN_DIRS56from softwarecenter.paths import SOFTWARE_CENTER_PLUGIN_DIRS
56from softwarecenter.enums import (Icons,57from softwarecenter.enums import (
57 PkgStates,58 AppActions,
58 ViewPages,59 DB_SCHEMA_VERSION,
59 AppActions,60 Icons,
60 DB_SCHEMA_VERSION,61 MOUSE_EVENT_FORWARD_BUTTON,
61 MOUSE_EVENT_FORWARD_BUTTON,62 MOUSE_EVENT_BACK_BUTTON,
62 MOUSE_EVENT_BACK_BUTTON,63 PkgStates,
63 SOFTWARE_CENTER_TOS_LINK,64 SearchSeparators,
64 SOFTWARE_CENTER_NAME_KEYRING)65 SOFTWARE_CENTER_TOS_LINK,
65from softwarecenter.utils import (clear_token_from_ubuntu_sso_sync,66 SOFTWARE_CENTER_NAME_KEYRING,
66 get_http_proxy_string_from_gsettings,67 ViewPages,
67 wait_for_apt_cache_ready,68)
68 ExecutionTime,69from softwarecenter.utils import (
69 is_unity_running)70 clear_token_from_ubuntu_sso_sync,
70from softwarecenter.ui.gtk3.utils import (get_sc_icon_theme,71 get_http_proxy_string_from_gsettings,
71 init_sc_css_provider)72 wait_for_apt_cache_ready,
73 ExecutionTime,
74 is_unity_running,
75)
76from softwarecenter.ui.gtk3.utils import (
77 get_sc_icon_theme,
78 init_sc_css_provider,
79)
72from softwarecenter.version import VERSION80from softwarecenter.version import VERSION
73from softwarecenter.db.database import StoreDatabase81from softwarecenter.db.database import StoreDatabase
74try:82try:
@@ -87,10 +95,14 @@
87from softwarecenter.ui.gtk3.panes.historypane import HistoryPane95from softwarecenter.ui.gtk3.panes.historypane import HistoryPane
88from softwarecenter.ui.gtk3.panes.globalpane import GlobalPane96from softwarecenter.ui.gtk3.panes.globalpane import GlobalPane
89from softwarecenter.ui.gtk3.panes.pendingpane import PendingPane97from softwarecenter.ui.gtk3.panes.pendingpane import PendingPane
90from softwarecenter.ui.gtk3.session.appmanager import (ApplicationManager,98from softwarecenter.ui.gtk3.session.appmanager import (
91 get_appmanager)99 ApplicationManager,
100 get_appmanager,
101 )
92from softwarecenter.ui.gtk3.session.viewmanager import (102from softwarecenter.ui.gtk3.session.viewmanager import (
93 ViewManager, get_viewmanager)103 ViewManager,
104 get_viewmanager,
105 )
94from softwarecenter.ui.gtk3.widgets.recommendations import (106from softwarecenter.ui.gtk3.widgets.recommendations import (
95 RecommendationsOptInDialog)107 RecommendationsOptInDialog)
96108
@@ -112,6 +124,10 @@
112from gi.repository import Gdk124from gi.repository import Gdk
113125
114LOG = logging.getLogger(__name__)126LOG = logging.getLogger(__name__)
127PACKAGE_PREFIX = 'apt:'
128# "apt:///" is a valid prefix for 'apt:pkgname' in alt+F2 in gnome
129PACKAGE_PREFIX_REGEX = re.compile('^%s(?:/{2,3})*' % PACKAGE_PREFIX)
130SEARCH_PREFIX = 'search:'
115131
116132
117# py3 compat133# py3 compat
@@ -119,6 +135,64 @@
119 return isinstance(func, collections.Callable)135 return isinstance(func, collections.Callable)
120136
121137
138def parse_packages_args(packages):
139 search_text = ''
140 app = None
141
142 # avoid treating strings as sequences ('foo' should not be 'f', 'o', 'o')
143 if isinstance(packages, basestring):
144 packages = (packages,)
145
146 if not isinstance(packages, collections.Iterable):
147 LOG.warning('show_available_packages: argument is not an iterable %r',
148 packages)
149 return search_text, app
150
151 items = [] # make a copy of the given sequence
152 for arg in packages:
153 # support both "pkg1 pkg" and "pkg1,pkg2" (and "pkg1,pkg2 pkg3")
154 if "," in arg:
155 items.extend(arg.split(SearchSeparators.PACKAGE))
156 else:
157 items.append(arg)
158
159 if len(items) > 0:
160 # allow s-c to be called with a search term
161 if items[0].startswith(SEARCH_PREFIX):
162 # remove the initial search prefix
163 items[0] = items[0].replace(SEARCH_PREFIX, '', 1)
164 search_text = SearchSeparators.REGULAR.join(items)
165 else:
166 # strip away the initial apt: prefix, if present
167 items[0] = re.sub(PACKAGE_PREFIX_REGEX, '', items[0])
168 if len(items) > 1:
169 # turn multiple packages into a search with "," as separator
170 search_text = SearchSeparators.PACKAGE.join(items)
171
172 if not search_text and len(items) == 1:
173 request = items[0]
174 # are we dealing with a path?
175 if os.path.exists(request) and not os.path.isdir(request):
176 if not request.startswith('/'):
177 # we may have been given a relative path
178 request = os.path.abspath(request)
179 # will raise DebOpenFileError if request is invalid
180 app = DebFileApplication(request)
181 else:
182 # package from archive
183 # if there is a "/" in the string consider it as tuple
184 # of (pkgname, appname) for exact matching (used by
185 # e.g. unity
186 (pkgname, sep, appname) = request.partition("/")
187 if pkgname or appname:
188 app = Application(appname, pkgname)
189 else:
190 LOG.warning('show_available_packages: received %r but '
191 'can not build an Application from it.', request)
192
193 return search_text, app
194
195
122class SoftwarecenterDbusController(dbus.service.Object):196class SoftwarecenterDbusController(dbus.service.Object):
123 """197 """
124 This is a helper to provide the SoftwarecenterIFace198 This is a helper to provide the SoftwarecenterIFace
@@ -158,13 +232,16 @@
158 # the size of the icon for dialogs232 # the size of the icon for dialogs
159 APP_ICON_SIZE = Gtk.IconSize.DIALOG233 APP_ICON_SIZE = Gtk.IconSize.DIALOG
160234
235 START_DBUS = True
236
161 def __init__(self, datadir, xapian_base_path, options, args=None):237 def __init__(self, datadir, xapian_base_path, options, args=None):
162 # setup dbus and exit if there is another instance already238 self.dbusControler = None
163 # running239 if self.START_DBUS:
164 self.setup_dbus_or_bring_other_instance_to_front(args)240 # setup dbus and exit if there is another instance already running
241 self.setup_dbus_or_bring_other_instance_to_front(args)
165242
166 self.datadir = datadir243 self.datadir = datadir
167 SimpleGtkbuilderApp.__init__(self,244 super(SoftwareCenterAppGtk3, self).__init__(
168 datadir + "/ui/gtk3/SoftwareCenter.ui",245 datadir + "/ui/gtk3/SoftwareCenter.ui",
169 "software-center")246 "software-center")
170 gettext.bindtextdomain("software-center", "/usr/share/locale")247 gettext.bindtextdomain("software-center", "/usr/share/locale")
@@ -525,6 +602,18 @@
525 def on_review_stats_loaded(self, reviews):602 def on_review_stats_loaded(self, reviews):
526 LOG.debug("on_review_stats_loaded: '%s'" % len(reviews))603 LOG.debug("on_review_stats_loaded: '%s'" % len(reviews))
527604
605 def destroy(self):
606 """Destroy this instance and every used resource."""
607 self.window_main.destroy()
608
609 # remove global instances of Managers
610 self.app_manager.destroy()
611 self.view_manager.destroy()
612
613 if self.dbusControler is not None:
614 # ensure that the dbus controller is really gone
615 self.dbusControler.stop()
616
528 def close_app(self):617 def close_app(self):
529 """ perform tasks like save-state etc when the application is618 """ perform tasks like save-state etc when the application is
530 exited619 exited
@@ -539,15 +628,14 @@
539 if hasattr(self, "glaunchpad"):628 if hasattr(self, "glaunchpad"):
540 self.glaunchpad.shutdown()629 self.glaunchpad.shutdown()
541 self.save_state()630 self.save_state()
631 self.destroy()
632
542 # this will not throw exceptions in pygi but "only" log via g_critical633 # this will not throw exceptions in pygi but "only" log via g_critical
543 # to the terminal but it might in the future so we add a handler here634 # to the terminal but it might in the future so we add a handler here
544 try:635 try:
545 Gtk.main_quit()636 Gtk.main_quit()
546 except:637 except:
547 LOG.exception("Gtk.main_quit failed")638 LOG.exception("Gtk.main_quit failed")
548 # ensure that the dbus controller is really gone, just for good
549 # measure
550 self.dbusControler.stop()
551 # exit here explictely to ensure that no further gtk event loops or639 # exit here explictely to ensure that no further gtk event loops or
552 # threads run and cause havoc on exit (LP: #914393)640 # threads run and cause havoc on exit (LP: #914393)
553 sys.exit(0)641 sys.exit(0)
@@ -1217,75 +1305,49 @@
1217 bus_name = dbus.service.BusName('com.ubuntu.Softwarecenter', bus)1305 bus_name = dbus.service.BusName('com.ubuntu.Softwarecenter', bus)
1218 self.dbusControler = SoftwarecenterDbusController(self, bus_name)1306 self.dbusControler = SoftwarecenterDbusController(self, bus_name)
12191307
1308 @wait_for_apt_cache_ready
1309 def show_app(self, app):
1310 """Show 'app' in the installed pane if is installed.
1311
1312 If 'app' is not installed, show it in the available pane.
1313
1314 """
1315 if (app.pkgname in self.cache and self.cache[app.pkgname].installed):
1316 with ExecutionTime("installed_pane.init_view()"):
1317 self.installed_pane.init_view()
1318 with ExecutionTime("installed_pane.show_app()"):
1319 self.installed_pane.show_app(app)
1320 else:
1321 self.available_pane.init_view()
1322 self.available_pane.show_app(app)
1323
1220 def show_available_packages(self, packages):1324 def show_available_packages(self, packages):
1221 """ Show packages given as arguments in the available_pane1325 """ Show packages given as arguments in the available_pane
1222 If the list of packages is only one element long show that,1326 If the list of packages is only one element long show that,
1223 otherwise turn it into a comma seperated search1327 otherwise turn it into a comma seperated search
1224 """1328 """
1225 # strip away the apt: prefix1329 try:
1226 if packages and packages[0].startswith("apt:///"):1330 search_text, app = parse_packages_args(packages)
1227 # this is for 'apt:pkgname' in alt+F2 in gnome1331 except DebFileOpenError as e:
1228 packages[0] = packages[0].partition("apt:///")[2]1332 LOG.exception("show_available_packages: can not open %r, error:",
1229 elif packages and packages[0].startswith("apt://"):1333 packages)
1230 packages[0] = packages[0].partition("apt://")[2]1334 dialogs.error(None,
1231 elif packages and packages[0].startswith("apt:"):
1232 packages[0] = packages[0].partition("apt:")[2]
1233
1234 # allow s-c to be called with a search term
1235 if packages and packages[0].startswith("search:"):
1236 packages[0] = packages[0].partition("search:")[2]
1237 self.available_pane.init_view()
1238 self.available_pane.searchentry.set_text(" ".join(packages))
1239 return
1240
1241 if len(packages) == 1:
1242 request = packages[0]
1243
1244 # are we dealing with a path?
1245 if os.path.exists(request) and not os.path.isdir(request):
1246 if not request.startswith('/'):
1247 # we may have been given a relative path
1248 request = os.path.join(os.getcwd(), request)
1249 try:
1250 app = DebFileApplication(request)
1251 except ValueError as e:
1252 LOG.error("can not open %s: %s" % (request, e))
1253 from softwarecenter.ui.gtk3.dialogs import error
1254 error(None,
1255 _("Error"),1335 _("Error"),
1256 _("The file “%s” could not be opened.") % request)1336 _("The file “%s” could not be opened.") % e.path)
1257 app = None1337 search_text = app = None
1258 else:1338
1259 # package from archive1339 LOG.info('show_available_packages: search_text is %r, app is %r.',
1260 # if there is a "/" in the string consider it as tuple1340 search_text, app)
1261 # of (pkgname, appname) for exact matching (used by1341
1262 # e.g. unity1342 if search_text:
1263 (pkgname, sep, appname) = packages[0].partition("/")
1264 app = Application(appname, pkgname)
1265
1266 @wait_for_apt_cache_ready
1267 def show_app(self, app):
1268 # if the pkg is installed, show it in the installed pane
1269 if (app.pkgname in self.cache and
1270 self.cache[app.pkgname].installed):
1271 with ExecutionTime("installed_pane.init_view()"):
1272 self.installed_pane.init_view()
1273 with ExecutionTime("installed_pane.show_app()"):
1274 self.installed_pane.show_app(app)
1275 else:
1276 self.available_pane.init_view()
1277 self.available_pane.show_app(app)
1278 if app:
1279 show_app(self, app)
1280 return
1281 elif len(packages) > 1:
1282 # turn multiple packages into a search with ","
1283 self.available_pane.init_view()1343 self.available_pane.init_view()
1284 self.available_pane.searchentry.set_text(",".join(packages))1344 self.available_pane.searchentry.set_text(search_text)
1285 return1345 elif app is not None:
1286 # normal startup, show the lobby (it will have a spinner when1346 self.show_app(app)
1287 # its not ready yet) - it will also initialize the view1347 else:
1288 self.view_manager.set_active_view(ViewPages.AVAILABLE)1348 # normal startup, show the lobby (it will have a spinner when
1349 # its not ready yet) - it will also initialize the view
1350 self.view_manager.set_active_view(ViewPages.AVAILABLE)
12891351
1290 def restore_state(self):1352 def restore_state(self):
1291 if self.config.has_option("general", "size"):1353 if self.config.has_option("general", "size"):
12921354
=== modified file 'softwarecenter/ui/gtk3/models/appstore2.py'
--- softwarecenter/ui/gtk3/models/appstore2.py 2012-05-18 05:47:10 +0000
+++ softwarecenter/ui/gtk3/models/appstore2.py 2012-05-21 15:37:20 +0000
@@ -164,6 +164,7 @@
164 if doc.installed is None:164 if doc.installed is None:
165 pkgname = self.get_pkgname(doc)165 pkgname = self.get_pkgname(doc)
166 doc.installed = (self.is_available(doc) and166 doc.installed = (self.is_available(doc) and
167 pkgname in self.cache and
167 self.cache[pkgname].is_installed)168 self.cache[pkgname].is_installed)
168 return doc.installed169 return doc.installed
169170
170171
=== modified file 'softwarecenter/ui/gtk3/session/appmanager.py'
--- softwarecenter/ui/gtk3/session/appmanager.py 2012-03-15 00:16:03 +0000
+++ softwarecenter/ui/gtk3/session/appmanager.py 2012-05-21 15:37:20 +0000
@@ -71,6 +71,11 @@
71 else:71 else:
72 _appmanager = self72 _appmanager = self
7373
74 def destroy(self):
75 """Destroy the global instance."""
76 global _appmanager
77 _appmanager = None
78
74 def request_action(self, app, addons_install, addons_remove, action):79 def request_action(self, app, addons_install, addons_remove, action):
75 """callback when an app action is requested from the appview,80 """callback when an app action is requested from the appview,
76 if action is "remove", must check if other dependencies have to be81 if action is "remove", must check if other dependencies have to be
7782
=== modified file 'softwarecenter/ui/gtk3/session/viewmanager.py'
--- softwarecenter/ui/gtk3/session/viewmanager.py 2012-03-15 00:16:03 +0000
+++ softwarecenter/ui/gtk3/session/viewmanager.py 2012-05-21 15:37:20 +0000
@@ -69,6 +69,11 @@
69 else:69 else:
70 _viewmanager = self70 _viewmanager = self
7171
72 def destroy(self):
73 """Destroy the global instance."""
74 global _viewmanager
75 _viewmanager = None
76
72 def on_search_terms_changed(self, widget, new_text):77 def on_search_terms_changed(self, widget, new_text):
73 pane = self.get_current_view_widget()78 pane = self.get_current_view_widget()
74 if hasattr(pane, "on_search_terms_changed"):79 if hasattr(pane, "on_search_terms_changed"):
7580
=== modified file 'softwarecenter/ui/gtk3/views/appdetailsview.py'
--- softwarecenter/ui/gtk3/views/appdetailsview.py 2012-05-14 03:16:07 +0000
+++ softwarecenter/ui/gtk3/views/appdetailsview.py 2012-05-21 15:37:20 +0000
@@ -1738,7 +1738,7 @@
1738 # update all (but skip the addons calculation if this is a1738 # update all (but skip the addons calculation if this is a
1739 # DebFileApplication as this is not useful for this case and it1739 # DebFileApplication as this is not useful for this case and it
1740 # increases the view load time dramatically)1740 # increases the view load time dramatically)
1741 skip_update_addons = type(self.app) == DebFileApplication1741 skip_update_addons = isinstance(self.app, DebFileApplication)
1742 self._update_all(self.app_details,1742 self._update_all(self.app_details,
1743 skip_update_addons=skip_update_addons)1743 skip_update_addons=skip_update_addons)
17441744
@@ -2013,7 +2013,7 @@
2013 self.addons_manager.addons_to_remove,2013 self.addons_manager.addons_to_remove,
2014 self.app.archive_suite)2014 self.app.archive_suite)
2015 total_download_size, total_install_size = res2015 total_download_size, total_install_size = res
2016 if res == (0, 0) and type(self.app) == DebFileApplication:2016 if res == (0, 0) and isinstance(self.app, DebFileApplication):
2017 total_install_size = self.app_details.installed_size2017 total_install_size = self.app_details.installed_size
2018 if total_download_size > 0:2018 if total_download_size > 0:
2019 download_size = GLib.format_size(total_download_size)2019 download_size = GLib.format_size(total_download_size)
20202020
=== modified file 'softwarecenter/ui/gtk3/widgets/videoplayer.py'
--- softwarecenter/ui/gtk3/widgets/videoplayer.py 2012-03-08 17:42:36 +0000
+++ softwarecenter/ui/gtk3/widgets/videoplayer.py 2012-05-21 15:37:20 +0000
@@ -72,7 +72,11 @@
72 # uri property72 # uri property
73 def _set_uri(self, v):73 def _set_uri(self, v):
74 self._uri = v or ""74 self._uri = v or ""
75 self.webkit.load_uri(self._uri)75 if self._uri:
76 # only load the uri if it's defined, otherwise we may get:
77 # Program received signal SIGSEGV, Segmentation fault.
78 # webkit_web_frame_load_uri () from /usr/lib/libwebkitgtk-3.0.so.0
79 self.webkit.load_uri(self._uri)
7680
77 def _get_uri(self):81 def _get_uri(self):
78 return self._uri82 return self._uri
7983
=== added file 'test/gtk3/__init__.py'
=== added file 'test/gtk3/test_app.py'
--- test/gtk3/test_app.py 1970-01-01 00:00:00 +0000
+++ test/gtk3/test_app.py 2012-05-21 15:37:20 +0000
@@ -0,0 +1,357 @@
1#!/usr/bin/python
2
3import os
4import unittest
5
6from collections import defaultdict
7from functools import partial
8
9from mock import Mock
10
11from testutils import get_mock_options, setup_test_env
12setup_test_env()
13
14import softwarecenter.paths
15from softwarecenter.db import DebFileApplication, DebFileOpenError
16from softwarecenter.enums import PkgStates, SearchSeparators
17from softwarecenter.ui.gtk3 import app
18
19
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):
55 """Test suite for the parse_packages_args helper."""
56
57 pkg_name = 'foo'
58
59 def transform_for_test(self, items):
60 """Transform a sequence into a comma separated string."""
61 return app.SEARCH_PREFIX + SearchSeparators.REGULAR.join(items)
62
63 def do_check(self, apps, items=None):
64 """Check that the available_pane was shown."""
65 if items is None:
66 items = self.transform_for_test(apps)
67
68 search_text, result_app = app.parse_packages_args(items)
69
70 self.assertEqual(SearchSeparators.REGULAR.join(apps), search_text)
71 self.assertIsNone(result_app)
72
73 def test_empty(self):
74 """Pass an empty argument, show the 'available' view."""
75 self.do_check(apps=())
76
77 def test_single_empty_item(self):
78 """Pass a single empty item, show the 'available' view."""
79 self.do_check(apps=('',))
80
81 def test_single_item(self):
82 """Pass a single item, show the 'available' view."""
83 self.do_check(apps=(self.pkg_name,))
84
85 def test_two_items(self):
86 """Pass two items, show the 'available' view."""
87 self.do_check(apps=(self.pkg_name, 'bar'))
88
89 def test_several_items(self):
90 """Pass several items, show the 'available' view."""
91 self.do_check(apps=(self.pkg_name, 'firefox', 'software-center'))
92
93
94class ParsePackageArgsAsFileTestCase(unittest.TestCase):
95
96 def test_item_is_a_file(self):
97 """Pass an item that is an existing file."""
98 # pass a real deb here
99 fname = os.path.join(os.path.dirname(os.path.abspath(__file__)),
100 "..", "data", "test_debs", "gdebi-test1.deb")
101 assert os.path.exists(fname)
102 # test once as string and as list
103 for items in ( fname, [fname] ):
104 search_text, result_app = app.parse_packages_args(fname)
105 self.assertIsInstance(result_app, DebFileApplication)
106
107 def test_item_is_invalid_file(self):
108 """ Pass an invalid file item """
109 fname = __file__
110 assert os.path.exists(fname)
111 self.assertRaises(DebFileOpenError, app.parse_packages_args, fname)
112
113
114class ParsePackagesWithAptPrefixTestCase(ParsePackagesArgsTestCase):
115
116 installed = None
117
118 def setUp(self):
119 super(ParsePackagesWithAptPrefixTestCase, self).setUp()
120
121 self.cache = FakedCache()
122 self.db = app.StoreDatabase(cache=self.cache)
123
124 assert self.pkg_name not in self.cache
125 if self.installed is not None:
126 mock_cache_entry = Mock()
127 mock_cache_entry.website = None
128 mock_cache_entry.license = None
129 mock_cache_entry.installed_files = []
130 mock_cache_entry.candidate = Mock()
131 mock_cache_entry.candidate.version = '1.0'
132 mock_cache_entry.candidate.description = 'A nonsense app.'
133 mock_cache_entry.candidate.origins = ()
134 mock_cache_entry.versions = (Mock(),)
135 mock_cache_entry.versions[0].version = '0.99'
136 mock_cache_entry.versions[0].origins = (Mock(),)
137 mock_cache_entry.versions[0].origins[0].archive = 'test'
138 mock_cache_entry.is_installed = self.installed
139 if self.installed:
140 mock_cache_entry.installed = Mock()
141 mock_cache_entry.installed.version = '0.90'
142 mock_cache_entry.installed.installed_size = 0
143 else:
144 mock_cache_entry.installed = None
145
146 self.cache[self.pkg_name] = mock_cache_entry
147 self.addCleanup(self.cache.pop, self.pkg_name)
148
149
150 def transform_for_test(self, items):
151 """Do nothing."""
152 return items
153
154 def check_package_availability(self, name):
155 """Check whether the package 'name' is available."""
156 if name not in self.cache:
157 state = PkgStates.NOT_FOUND
158 elif self.cache[name].installed:
159 state = PkgStates.INSTALLED
160 else:
161 state = PkgStates.UNINSTALLED
162 return state
163
164 def do_check(self, apps, items=None):
165 """Check that the available_pane was shown."""
166 if items is None:
167 items = self.transform_for_test(apps)
168
169 search_text, result_app = app.parse_packages_args(items)
170
171 if apps and len(apps) == 1 and apps[0] and not os.path.isfile(apps[0]):
172 self.assertIsNotNone(result_app)
173 app_details = result_app.get_details(self.db)
174
175 self.assertEqual(apps[0], app_details.name)
176 state = self.check_package_availability(app_details.name)
177 self.assertEqual(state, app_details.pkg_state)
178 else:
179 self.assertIsNone(result_app)
180
181 if apps and (len(apps) > 1 or os.path.isfile(apps[0])):
182 self.assertEqual(SearchSeparators.PACKAGE.join(apps), search_text)
183 else:
184 self.assertEqual('', search_text)
185
186 def test_item_with_prefix(self):
187 """Pass a item with the item prefix."""
188 for prefix in ('apt:', 'apt://', 'apt:///'):
189 for case in (self.pkg_name, app.PACKAGE_PREFIX + self.pkg_name):
190 self.do_check(apps=(case,), items=(prefix + case,))
191
192
193class ParsePackagesNotInstalledTestCase(ParsePackagesWithAptPrefixTestCase):
194 """Test suite for parsing/searching/loading package lists."""
195
196 installed = False
197
198
199class ParsePackagesInstalledTestCase(ParsePackagesWithAptPrefixTestCase):
200 """Test suite for parsing/searching/loading package lists."""
201
202 installed = True
203
204
205class ParsePackagesArgsStringTestCase(ParsePackagesWithAptPrefixTestCase):
206 """Test suite for parsing/loading package lists from strings."""
207
208 def transform_for_test(self, items):
209 """Transform a sequence into a comma separated string."""
210 return SearchSeparators.PACKAGE.join(items)
211
212
213class AppTestCase(unittest.TestCase):
214 """Test suite for the app module."""
215
216 def setUp(self):
217 super(AppTestCase, self).setUp()
218 self.called = defaultdict(list)
219 self.addCleanup(self.called.clear)
220
221 orig = app.SoftwareCenterAppGtk3.START_DBUS
222 self.addCleanup(setattr, app.SoftwareCenterAppGtk3, 'START_DBUS', orig)
223 app.SoftwareCenterAppGtk3.START_DBUS = False
224
225 orig = app.get_pkg_info
226 self.addCleanup(setattr, app, 'get_pkg_info', orig)
227 app.get_pkg_info = lambda: FakedCache()
228
229 datadir = softwarecenter.paths.datadir
230 xapianpath = softwarecenter.paths.XAPIAN_BASE_PATH
231 options = get_mock_options()
232 self.app = app.SoftwareCenterAppGtk3(datadir, xapianpath, options)
233 self.addCleanup(self.app.destroy)
234
235 self.app.cache.open()
236
237 # connect some signals of interest
238 cid = self.app.installed_pane.connect('installed-pane-created',
239 partial(self.track_calls, 'pane-created'))
240 self.addCleanup(self.app.installed_pane.disconnect, cid)
241
242 cid = self.app.available_pane.connect('available-pane-created',
243 partial(self.track_calls, 'pane-created'))
244 self.addCleanup(self.app.available_pane.disconnect, cid)
245
246 def track_calls(self, name, *a, **kw):
247 """Record the callback for 'name' using 'args' and 'kwargs'."""
248 self.called[name].append((a, kw))
249
250
251class ShowPackagesTestCase(AppTestCase):
252 """Test suite for parsing/searching/loading package lists."""
253
254 def do_check(self, packages, search_text):
255 """Check that the available_pane was shown."""
256 self.app.show_available_packages(packages=packages)
257
258 self.assertEqual(self.called,
259 {'pane-created': [((self.app.available_pane,), {})]})
260
261 actual = self.app.available_pane.searchentry.get_text()
262 self.assertEqual(search_text, actual,
263 'Expected search text %r (got %r instead) for packages %r.' %
264 (search_text, actual, packages))
265
266 self.assertIsNone(self.app.available_pane.app_details_view.app_details)
267
268 def test_show_available_packages_search_prefix(self):
269 """Check that the available_pane was shown."""
270 self.do_check(packages='search:foo,bar baz', search_text='foo bar baz')
271
272 def test_show_available_packages_apt_prefix(self):
273 """Check that the available_pane was shown."""
274 for prefix in ('apt:', 'apt://', 'apt:///'):
275 self.do_check(packages=prefix + 'foo,bar,baz',
276 search_text='foo,bar,baz')
277
278
279class ShowPackagesOnePackageTestCase(AppTestCase):
280 """Test suite for parsing/searching/loading package lists."""
281
282 pkg_name = 'foo'
283 installed = None
284
285 def setUp(self):
286 super(ShowPackagesOnePackageTestCase, self).setUp()
287 assert self.pkg_name not in self.app.cache
288 if self.installed is not None:
289 mock_cache_entry = Mock()
290 mock_cache_entry.website = None
291 mock_cache_entry.license = None
292 mock_cache_entry.installed_files = []
293 mock_cache_entry.candidate = Mock()
294 mock_cache_entry.candidate.version = '1.0'
295 mock_cache_entry.candidate.description = 'A nonsense app.'
296 mock_cache_entry.candidate.origins = ()
297 mock_cache_entry.versions = (Mock(),)
298 mock_cache_entry.versions[0].version = '0.99'
299 mock_cache_entry.versions[0].origins = (Mock(),)
300 mock_cache_entry.versions[0].origins[0].archive = 'test'
301 mock_cache_entry.is_installed = self.installed
302 if self.installed:
303 mock_cache_entry.installed = Mock()
304 mock_cache_entry.installed.version = '0.90'
305 mock_cache_entry.installed.installed_size = 0
306 else:
307 mock_cache_entry.installed = None
308
309 self.app.cache[self.pkg_name] = mock_cache_entry
310 self.addCleanup(self.app.cache.pop, self.pkg_name)
311
312 def check_package_availability(self, name):
313 """Check whether the package 'name' is available."""
314 pane = self.app.available_pane
315 if name not in self.app.cache:
316 state = PkgStates.NOT_FOUND
317 elif self.app.cache[name].installed:
318 state = PkgStates.INSTALLED
319 pane = self.app.installed_pane
320 else:
321 state = PkgStates.UNINSTALLED
322
323 self.assertEqual(state, pane.app_details_view.app_details.pkg_state)
324
325 return pane
326
327 def test_show_available_packages(self):
328 """Check that the available_pane was shown."""
329 self.app.show_available_packages(packages=self.pkg_name)
330
331 expected_pane = self.check_package_availability(self.pkg_name)
332 name = expected_pane.app_details_view.app_details.name
333 self.assertEqual(self.pkg_name, name)
334
335 self.assertEqual('', self.app.available_pane.searchentry.get_text())
336
337 self.assertEqual(self.called,
338 {'pane-created': [((expected_pane,), {})]})
339
340
341class ShowPackagesNotInstalledTestCase(ShowPackagesOnePackageTestCase):
342 """Test suite for parsing/searching/loading package lists."""
343
344 installed = False
345
346
347class ShowPackagesInstalledTestCase(ShowPackagesOnePackageTestCase):
348 """Test suite for parsing/searching/loading package lists."""
349
350 installed = True
351
352
353if __name__ == "__main__":
354 # avoid spawning recommender-agent, reviews, software-center-agent etc,
355 # cuts ~5s or so
356 os.environ["SOFTWARE_CENTER_DISABLE_SPAWN_HELPER"] = "1"
357 unittest.main()
0358
=== modified file 'test/gtk3/test_debfile_view.py'
--- test/gtk3/test_debfile_view.py 2012-02-23 16:40:27 +0000
+++ test/gtk3/test_debfile_view.py 2012-05-21 15:37:20 +0000
@@ -3,22 +3,18 @@
3import time3import time
4import unittest4import unittest
55
6from mock import Mock6from testutils import do_events, get_mock_options, setup_test_env
7
8from testutils import setup_test_env, do_events
9setup_test_env()7setup_test_env()
108
11import softwarecenter.paths9import softwarecenter.paths
12from softwarecenter.ui.gtk3.app import SoftwareCenterAppGtk310from softwarecenter.ui.gtk3.app import SoftwareCenterAppGtk3
13from softwarecenter.ui.gtk3.panes.availablepane import AvailablePane11from softwarecenter.ui.gtk3.panes.availablepane import AvailablePane
1412
13
15class DebFileOpenTestCase(unittest.TestCase):14class DebFileOpenTestCase(unittest.TestCase):
1615
17 def test_deb_file_view_error(self):16 def test_deb_file_view_error(self):
18 mock_options = Mock()17 mock_options = get_mock_options()
19 mock_options.display_navlog = False
20 mock_options.disable_apt_xapian_index = False
21 mock_options.disable_buy = False
22 xapianpath = softwarecenter.paths.XAPIAN_BASE_PATH18 xapianpath = softwarecenter.paths.XAPIAN_BASE_PATH
23 app = SoftwareCenterAppGtk3(19 app = SoftwareCenterAppGtk3(
24 softwarecenter.paths.datadir, xapianpath, mock_options)20 softwarecenter.paths.datadir, xapianpath, mock_options)
@@ -37,7 +33,6 @@
37 # this is deb that is not installable33 # this is deb that is not installable
38 action_button = app.available_pane.app_details_view.pkg_statusbar.button34 action_button = app.available_pane.app_details_view.pkg_statusbar.button
39 self.assertFalse(action_button.get_property("visible"))35 self.assertFalse(action_button.get_property("visible"))
40
4136
4237
43if __name__ == "__main__":38if __name__ == "__main__":
4439
=== modified file 'test/gtk3/test_purchase.py'
--- test/gtk3/test_purchase.py 2012-03-19 14:38:10 +0000
+++ test/gtk3/test_purchase.py 2012-05-21 15:37:20 +0000
@@ -3,12 +3,12 @@
3import time3import time
4import unittest4import unittest
55
6from mock import Mock,patch6from mock import Mock, patch
77
8from testutils import setup_test_env8from testutils import setup_test_env
9setup_test_env()9setup_test_env()
1010
11from softwarecenter.testutils import do_events11from softwarecenter.testutils import do_events, get_mock_options
12from softwarecenter.ui.gtk3.app import SoftwareCenterAppGtk312from softwarecenter.ui.gtk3.app import SoftwareCenterAppGtk3
13from softwarecenter.ui.gtk3.panes.availablepane import AvailablePane13from softwarecenter.ui.gtk3.panes.availablepane import AvailablePane
14import softwarecenter.paths14import softwarecenter.paths
@@ -35,7 +35,7 @@
35 self.assertTrue("skipping" in mock.debug.call_args[0][0])35 self.assertTrue("skipping" in mock.debug.call_args[0][0])
36 self.assertFalse("consumer_secret" in mock.debug.call_args[0][0])36 self.assertFalse("consumer_secret" in mock.debug.call_args[0][0])
37 mock.reset_mock()37 mock.reset_mock()
38 38
39 # run another one39 # run another one
40 win.destroy()40 win.destroy()
4141
@@ -71,25 +71,21 @@
71 # run another one71 # run another one
72 win.destroy()72 win.destroy()
7373
74
75 def test_reinstall_previous_purchase_display(self):74 def test_reinstall_previous_purchase_display(self):
76 mock_options = Mock()75 mock_options = get_mock_options()
77 mock_options.display_navlog = False
78 mock_options.disable_apt_xapian_index = False
79 mock_options.disable_buy = False
80 xapiandb = "/var/cache/software-center/"76 xapiandb = "/var/cache/software-center/"
81 app = SoftwareCenterAppGtk3(77 app = SoftwareCenterAppGtk3(
82 softwarecenter.paths.datadir, xapiandb, mock_options)78 softwarecenter.paths.datadir, xapiandb, mock_options)
83 # real app opens cache async79 # real app opens cache async
84 app.cache.open()80 app.cache.open()
85 # show it81 # show it
86 app.window_main.show_all()82 app.window_main.show_all()
87 app.available_pane.init_view()83 app.available_pane.init_view()
88 self._p()84 self._p()
89 app.on_menuitem_reinstall_purchases_activate(None)85 app.on_menuitem_reinstall_purchases_activate(None)
90 # it can take a bit until the sso client is ready86 # it can take a bit until the sso client is ready
91 for i in range(100):87 for i in range(100):
92 if (app.available_pane.get_current_page() == 88 if (app.available_pane.get_current_page() ==
93 AvailablePane.Pages.LIST):89 AvailablePane.Pages.LIST):
94 break90 break
95 self._p()91 self._p()
9692
=== modified file 'test/test_database.py'
--- test/test_database.py 2012-04-13 16:32:26 +0000
+++ test/test_database.py 2012-05-21 15:37:20 +0000
@@ -406,9 +406,13 @@
406packagesize 3 # package size406packagesize 3 # package size
407app-popcon 4 # app-install .desktop popcon rank407app-popcon 4 # app-install .desktop popcon rank
408"""408"""
409 open("axi-test-values","w").write(s)409 fname = "axi-test-values"
410 with open(fname, "w") as f:
411 f.write(s)
412 self.addCleanup(os.remove, fname)
413
410 #db = StoreDatabase("/var/cache/software-center/xapian", self.cache)414 #db = StoreDatabase("/var/cache/software-center/xapian", self.cache)
411 axi_values = parse_axi_values_file("axi-test-values")415 axi_values = parse_axi_values_file(fname)
412 self.assertNotEqual(axi_values, {})416 self.assertNotEqual(axi_values, {})
413 print axi_values417 print axi_values
414418
@@ -428,7 +432,8 @@
428 nonblocking_load=False)432 nonblocking_load=False)
429 self.assertTrue(len(enquirer.get_docids()) > 0)433 self.assertTrue(len(enquirer.get_docids()) > 0)
430 # FIXME: test more of the interface434 # FIXME: test more of the interface
431 435
436
432class UtilsTestCase(unittest.TestCase):437class UtilsTestCase(unittest.TestCase):
433438
434 def test_utils_get_installed_package_list(self):439 def test_utils_get_installed_package_list(self):
435440
=== modified file 'test/test_debfileapplication.py'
--- test/test_debfileapplication.py 2012-02-23 16:40:27 +0000
+++ test/test_debfileapplication.py 2012-05-21 15:37:20 +0000
@@ -7,7 +7,7 @@
7setup_test_env()7setup_test_env()
88
9from softwarecenter.enums import PkgStates9from softwarecenter.enums import PkgStates
10from softwarecenter.db.debfile import DebFileApplication10from softwarecenter.db.debfile import DebFileApplication, DebFileOpenError
11from softwarecenter.testutils import get_test_db11from softwarecenter.testutils import get_test_db
1212
13DEBFILE_PATH = './data/test_debs/gdebi-test9.deb'13DEBFILE_PATH = './data/test_debs/gdebi-test9.deb'
@@ -22,6 +22,7 @@
22DEBFILE_PATH_CORRUPT = './data/test_debs/corrupt.deb'22DEBFILE_PATH_CORRUPT = './data/test_debs/corrupt.deb'
23DEBFILE_NOT_INSTALLABLE = './data/test_debs/gdebi-test1.deb'23DEBFILE_NOT_INSTALLABLE = './data/test_debs/gdebi-test1.deb'
2424
25
25class TestDebFileApplication(unittest.TestCase):26class TestDebFileApplication(unittest.TestCase):
26 """ Test the class DebFileApplication """27 """ Test the class DebFileApplication """
2728
@@ -31,7 +32,7 @@
31 def test_get_name(self):32 def test_get_name(self):
32 debfileapplication = DebFileApplication(DEBFILE_PATH)33 debfileapplication = DebFileApplication(DEBFILE_PATH)
33 debfiledetails = debfileapplication.get_details(self.db)34 debfiledetails = debfileapplication.get_details(self.db)
34 35
35 self.assertEquals(debfiledetails.name, DEBFILE_NAME)36 self.assertEquals(debfiledetails.name, DEBFILE_NAME)
3637
37 def test_get_description(self):38 def test_get_description(self):
@@ -64,9 +65,10 @@
64 debfileapplication = DebFileApplication(DEBFILE_PATH_NOTFOUND)65 debfileapplication = DebFileApplication(DEBFILE_PATH_NOTFOUND)
65 debfiledetails = debfileapplication.get_details(self.db)66 debfiledetails = debfileapplication.get_details(self.db)
66 self.assertEquals(debfiledetails.pkg_state, PkgStates.NOT_FOUND)67 self.assertEquals(debfiledetails.pkg_state, PkgStates.NOT_FOUND)
67 68
68 def test_get_pkg_state_not_a_deb(self):69 def test_get_pkg_state_not_a_deb(self):
69 self.assertRaises(ValueError, DebFileApplication, DEBFILE_PATH_NOTADEB)70 self.assertRaises(DebFileOpenError,
71 DebFileApplication, DEBFILE_PATH_NOTADEB)
7072
71 def test_get_pkg_state_corrupt(self):73 def test_get_pkg_state_corrupt(self):
72 debfileapplication = DebFileApplication(DEBFILE_PATH_CORRUPT)74 debfileapplication = DebFileApplication(DEBFILE_PATH_CORRUPT)
@@ -87,12 +89,14 @@
87 debfileapplication = DebFileApplication(DEBFILE_PATH)89 debfileapplication = DebFileApplication(DEBFILE_PATH)
88 debfiledetails = debfileapplication.get_details(self.db)90 debfiledetails = debfileapplication.get_details(self.db)
89 self.assertEquals(debfiledetails.installed_size, 0)91 self.assertEquals(debfiledetails.installed_size, 0)
90 92
91 def test_get_warning(self):93 def test_get_warning(self):
92 debfileapplication = DebFileApplication(DEBFILE_PATH)94 debfileapplication = DebFileApplication(DEBFILE_PATH)
93 debfiledetails = debfileapplication.get_details(self.db)95 debfiledetails = debfileapplication.get_details(self.db)
94 self.assertEquals(debfiledetails.warning, DEBFILE_WARNING)96 self.assertEquals(debfiledetails.warning, DEBFILE_WARNING)
95 97
98
96if __name__ == "__main__":99if __name__ == "__main__":
97 logging.basicConfig(level=logging.DEBUG)100 logging.basicConfig(level=logging.DEBUG)
98 unittest.main()101 unittest.main()
102

Subscribers

People subscribed via source and target branches