Rev 5136: Put several tests behind a Feature object. in http://bazaar.launchpad.net/~jameinel/bzr/2.2-is-up-to-date

John Arbash Meinel john at arbash-meinel.com
Wed Jul 13 12:22:59 UTC 2011


At http://bazaar.launchpad.net/~jameinel/bzr/2.2-is-up-to-date

------------------------------------------------------------
revno: 5136
revision-id: john at arbash-meinel.com-20110713122227-0nb381xfj9bi965c
parent: john at arbash-meinel.com-20110713121021-aeuvnkjp5c627lxd
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: 2.2-is-up-to-date
timestamp: Wed 2011-07-13 14:22:27 +0200
message:
  Put several tests behind a Feature object.
  Add some edge-case tests that even when we don't get the
  response we are expecting, we don't explode.
-------------- next part --------------
=== modified file 'bzrlib/plugins/launchpad/lp_api_lite.py'
--- a/bzrlib/plugins/launchpad/lp_api_lite.py	2011-07-13 12:10:21 +0000
+++ b/bzrlib/plugins/launchpad/lp_api_lite.py	2011-07-13 12:22:27 +0000
@@ -129,7 +129,12 @@
         """Parse the json response from Launchpad into objects."""
         if json is None:
             return None
-        return json.loads(json_info)
+        try:
+            return json.loads(json_info)
+        except Exception:
+            trace.mutter('Failed to parse json info: %r' % (json_info,))
+            trace.log_exception_quietly()
+            return None
 
     def get_latest_version(self):
         """Get the latest published version for the given package."""
@@ -137,10 +142,16 @@
         if json_info is None:
             return None
         info = self._parse_json_info(json_info)
-        entries = info['entries']
-        if len(entries) == 0:
-            return None
-        return entries[0]['source_package_version']
+        if info is None:
+            return None
+        try:
+            entries = info['entries']
+            if len(entries) == 0:
+                return None
+            return entries[0]['source_package_version']
+        except KeyError:
+            trace.log_exception_quietly()
+            return None
 
 
 def get_latest_publication(archive, series, project):
@@ -153,70 +164,5 @@
     :return: A version string indicating the most-recent version published in
         Launchpad. Might return None if there is an error.
     """
-    if json is None:
-        return None
-    archive_url = '%s/%s/+archive/primary?' % (LatestPublication.LP_API_ROOT, archive)
-    pocket = None
-    # TODO: If series is None, we probably need to hard-code it. I don't have
-    #       proof yet, but otherwise we just get the most-recent version in any
-    #       series, rather than getting the one for eg 'oneiric'. The problem I
-    #       envision is that natty-proposed might have a newer version than
-    #       'oneiric'. Is this a useful distinction in practice?
-    if series is not None and '-' in series:
-        # The lp: URL 'lp:ubuntu/natty-proposed/...' is translated into series
-        # 'natty' pocket 'proposed'
-        try:
-            series, pocket = series.split('-')
-        except ValueError, e:
-            trace.mutter('failed to find series,pocket from %s' % (series,))
-            return None
-        # pocket must be in 'Title' case, so Proposed, not 'proposed'.
-        pocket = pocket.title()
-    params = {'ws.op': 'getPublishedSources',
-              'exact_match': 'true',
-              # If we need to use "" shouldn't we quote the project somehow?
-              'source_name': '"%s"' % (project,),
-              'status': 'Published',
-              # We only need the latest one, the results seem to be properly
-              # most-recent-debian-version sorted
-              'ws.size': '1',
-    }
-    if series is not None:
-        params['distro_series'] = '/%s/%s' % (archive, series)
-    if pocket is not None:
-        params['pocket'] = pocket
-    query_url = archive_url + urllib.urlencode(params)
-    try:
-        req = urllib2.Request(query_url)
-        response = urllib2.urlopen(req)
-        json_txt = response.read()
-    except urllib2.HTTPError, e:
-        trace.mutter('failed to place query to %r' % (query_url,))
-        trace.log_exception_quietly()
-        return None
-    try:
-        o = json.loads(json_txt)
-    except Exception:
-        # simplejson raises simplejson.decoder.JSONDecodeError,
-        # but json raises ValueError, so we just catch a generic error and move
-        # on
-        trace.log_exception_quietly()
-        return None
-    try:
-        for e in o['entries']:
-            this_name = e['source_package_name']
-            this_ver = e['source_package_version']
-            # this_comp seems to always be 'main', are we supposed to do
-            # something with it?
-            # this_comp = e['component_name']
-            # pocket = e['pocket'].lower()
-            # series = e['distro_series_link'].split('/')[-1]
-            # if pocket != 'release':
-            #     series += '-' + pocket
-            return this_ver
-    except KeyError:
-        # Some expected attribute was missing
-        trace.log_exception_quietly()
-        return None
-    trace.mutter('No versions found for: %r', query_url)
-    return None
+    lp = LatestPublication(archive, series, project)
+    return lp.get_latest_version()

=== modified file 'bzrlib/plugins/launchpad/test_lp_api_lite.py'
--- a/bzrlib/plugins/launchpad/test_lp_api_lite.py	2011-07-13 12:10:21 +0000
+++ b/bzrlib/plugins/launchpad/test_lp_api_lite.py	2011-07-13 12:22:27 +0000
@@ -22,6 +22,16 @@
 from bzrlib import tests
 from bzrlib.plugins.launchpad import lp_api_lite
 
+class _JSONParserFeature(tests.Feature):
+
+    def _probe(self):
+        return lp_api_lite.json is not None
+
+    def feature_name(self):
+        return 'simplejson or json'
+
+JSONParserFeature = _JSONParserFeature()
+
 _example_response = r"""
 {
     "total_size": 2,
@@ -185,8 +195,7 @@
         self.assertIs(None, latest_pub._parse_json_info(_example_response))
 
     def test__parse_json_example_response(self):
-        if lp_api_lite.json is None:
-            raise tests.UnavailableFeature('json or simplejson module')
+        self.requireFeature(JSONParserFeature)
         latest_pub = self.make_latest_publication()
         content = latest_pub._parse_json_info(_example_response)
         self.assertIsNot(None, content)
@@ -197,6 +206,11 @@
         self.assertEqual('bzr', entry['source_package_name'])
         self.assertEqual("2.1.4-0ubuntu1", entry["source_package_version"])
 
+    def test__parse_json_not_json(self):
+        self.requireFeature(JSONParserFeature)
+        latest_pub = self.make_latest_publication()
+        self.assertIs(None, latest_pub._parse_json_info('Not_valid_json'))
+
     def test_get_latest_version_no_response(self):
         latest_pub = self.make_latest_publication()
         latest_pub._get_lp_info = lambda: None
@@ -207,16 +221,40 @@
         latest_pub = self.make_latest_publication()
         self.assertEqual(None, latest_pub.get_latest_version())
 
+    def test_get_latest_version_invalid_json(self):
+        self.requireFeature(JSONParserFeature)
+        latest_pub = self.make_latest_publication()
+        latest_pub._get_lp_info = lambda: "not json"
+        self.assertEqual(None, latest_pub.get_latest_version())
+
     def test_get_latest_version_no_versions(self):
+        self.requireFeature(JSONParserFeature)
         latest_pub = self.make_latest_publication()
         latest_pub._get_lp_info = lambda: _no_versions_response
         self.assertEqual(None, latest_pub.get_latest_version())
 
+    def test_get_latest_version_missing_entries(self):
+        # Launchpad's no-entries response does have an empty entries value.
+        # However, lets test that we handle other failures without tracebacks
+        self.requireFeature(JSONParserFeature)
+        latest_pub = self.make_latest_publication()
+        latest_pub._get_lp_info = lambda: '{}'
+        self.assertEqual(None, latest_pub.get_latest_version())
+
+    def test_get_latest_version_invalid_entries(self):
+        # Make sure we sanely handle a json response we don't understand
+        self.requireFeature(JSONParserFeature)
+        latest_pub = self.make_latest_publication()
+        latest_pub._get_lp_info = lambda: '{"entries": {"a": 1}}'
+        self.assertEqual(None, latest_pub.get_latest_version())
+
     def test_get_latest_version_example(self):
+        self.requireFeature(JSONParserFeature)
         latest_pub = self.make_latest_publication()
         latest_pub._get_lp_info = lambda: _example_response
         self.assertEqual("2.1.4-0ubuntu1", latest_pub.get_latest_version())
 
     def DONT_test_get_latest_version_from_launchpad(self):
+        self.requireFeature(JSONParserFeature)
         latest_pub = self.make_latest_publication()
         self.assertIsNot(None, latest_pub.get_latest_version())



More information about the bazaar-commits mailing list