Merge lp:~zematynnad/rnr-server/api_check_856808 into lp:rnr-server

Proposed by Danny Tamez
Status: Merged
Approved by: Anthony Lenton
Approved revision: 220
Merged at revision: 218
Proposed branch: lp:~zematynnad/rnr-server/api_check_856808
Merge into: lp:rnr-server
Diff against target: 203 lines (+57/-61)
4 files modified
.bzrignore (+2/-1)
fabtasks/bootstrap.py (+8/-1)
src/reviewsapp/tests/test_utilities.py (+32/-24)
src/reviewsapp/utilities.py (+15/-35)
To merge this branch: bzr merge lp:~zematynnad/rnr-server/api_check_856808
Reviewer Review Type Date Requested Status
Michael Nelson (community) Approve
Review via email: mp+100028@code.launchpad.net

Commit message

Now calling sca's piston API for published apps.

Description of the change

Overview
=========
This branch switches to using SCA's piston api for retrieving applications.

Details
========
Now that SCA has this API available there is no need to call the view we were calling before. get_sca_publishings_for now calls api/2.0/applications/en/ubuntu/<distro>/<arch>/

To Test
========
$fab bootstrap test

To post a comment you must log in.
Revision history for this message
Michael Nelson (michael.nelson) wrote :

Looks fine Danny. I'm assuming you looked at whether it was worth using the actual piston mini-client and decided against it for this one call?

Sheesh - I just checked the scaclient, and it's also using the old view-based available apps:

http://bazaar.launchpad.net/~canonical-ca-hackers/software-center/scaclient/view/head:/scaclient.py

for all api calls :/

In which case, it might be best to (1) update the scaclient to use the 2.0 api for all calls (it's tested in test_scaclient.py in sca), and then (2) update rnr to use the sca client? I think (1) is necessary, (2) is just a matter of us dogfooding our own tools - feel free to ignore (2) and land this branch as is, but given that scaclient is what where giving others to use (such as USC) I think we should update it asap. What do you think?

Revision history for this message
Michael Nelson (michael.nelson) wrote :

Hi Danny!

Thanks for updating to use the sca client. I'm not sure how I missed above that the scaclient *is* using the /2.0/ api already - I must have missed the 'default_service_root' property.

Two things that might be worth considering with this branch - see what you think.

1) In utilities.py, you don't need to go through the whole _sca_service, _set_sca_service() before providing your sca property. It's used for lazr.restful clients which actually ping for wadl when they're instantiated. But in the case of the sca client, it's cheap to instantiate, so you can just have the sca property doing it directly without any cached service.

2) You wouldn't need your DictToObj conversion if you instead patched SoftwareCenterAgentAPI._get (or whatever it's underlying code is calling) with self.factory.get_test_file('software_center_apps.json') and let the piston-mini-client do the conversion for you.

See what you think. Happy to +1 the MP if you've got reasons against the above 2 points.

Revision history for this message
Danny Tamez (zematynnad) wrote :

As per our conversation on mumble - 1) no need to cache the service just use it directly as it's cheap. 2) instead of patching available_apps, patch httplib2.Http.request with a return value of ({'status': '200', <value of serialized json from file>) instead.

Revision history for this message
Michael Nelson (michael.nelson) wrote :

Thanks Danny - looks great. I can see why we'd no longer need the test_retrieved_url (as we'd be testing the sca client implementation), but I'm not sure why we'd remove test_get_sca_publishings_cached. If we did want to keep it, we could switch the @patch('httplib2.Http.request') into the setUp(), with:

{{{
def setUp(self):
   self.patcher = patch('httplib2.Http.request')
   self.mock_http_request = self.patcher.start()
   self.addCleanup(self.patcher.stop)
}}}

that way we could keep test_get_sca_publishings_cached, asserting that self.mock_http_request.call_count == 0... if we wanted to, but maybe there's a reason for removing the test. Anyway, I'm adding a +1 and you can see what you think.

review: Approve
Revision history for this message
Danny Tamez (zematynnad) wrote :

Combined the branch and the dependent branch into this one as there was much overlap in the comments on the two.

Revision history for this message
Michael Nelson (michael.nelson) wrote :

Two small things - see if you think they're worth changes, but +1 :)

1:

16:04 <noodles> Hey there! Should the assertion on line 121 alse be on line 117 (it looks like the
                previous code had a typo, which you've fixed, but we're only checking after the
                second call)
16:04 * zematynnad takes a look

2: I don't *think* you should need to make assumptions about the caching backend being used to mock it, we've got similar tests elsewhere that patch out the cache.get, but no biggie.

review: Approve
Revision history for this message
ISD Branch Mangler (isd-branches-mangler) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.bzrignore'
--- .bzrignore 2011-10-06 13:08:27 +0000
+++ .bzrignore 2012-04-11 16:37:30 +0000
@@ -18,4 +18,5 @@
18.virtualenvs18.virtualenvs
19branches/*19branches/*
20virtualenv/*20virtualenv/*
21sourcecode/*
22\ No newline at end of file21\ No newline at end of file
22sourcecode/*
23django_project/scaclient.py
2324
=== modified file 'fabtasks/bootstrap.py'
--- fabtasks/bootstrap.py 2012-01-27 12:39:58 +0000
+++ fabtasks/bootstrap.py 2012-04-11 16:37:30 +0000
@@ -17,7 +17,7 @@
17import os17import os
18import os.path18import os.path
1919
20from fabric.api import local, cd20from fabric.api import local
2121
2222
23def _get_or_pull_bzr_branch(repo, name):23def _get_or_pull_bzr_branch(repo, name):
@@ -67,6 +67,13 @@
67 "branches/wsgi-oops/canonical",67 "branches/wsgi-oops/canonical",
68 "django_project/canonical")68 "django_project/canonical")
6969
70 _get_or_pull_bzr_branch(
71 "lp:~canonical-ca-hackers/software-center/scaclient",
72 "scaclient")
73 _symlink(
74 "branches/scaclient/scaclient.py",
75 "django_project/scaclient.py")
76
7077
71def download_multi_mechanize():78def download_multi_mechanize():
72 multi_mechanize = "multi-mechanize_1.010.zip"79 multi_mechanize = "multi-mechanize_1.010.zip"
7380
=== modified file 'src/reviewsapp/tests/test_utilities.py'
--- src/reviewsapp/tests/test_utilities.py 2012-01-25 16:18:35 +0000
+++ src/reviewsapp/tests/test_utilities.py 2012-04-11 16:37:30 +0000
@@ -45,8 +45,8 @@
45from reviewsapp.utilities import (45from reviewsapp.utilities import (
46 cache_key_for_url,46 cache_key_for_url,
47 invalidate_paginated_reviews_for,47 invalidate_paginated_reviews_for,
48 WebServices,
48 WebServiceError,49 WebServiceError,
49 WebServices,
50 full_claimed_id,50 full_claimed_id,
51)51)
5252
@@ -238,24 +238,28 @@
238238
239class SCATestCase(TestCaseWithFactory):239class SCATestCase(TestCaseWithFactory):
240240
241 @patch('httplib2.Http.request')
241 def _request_sca_pubs_for(self, distroseries, arch_tag,242 def _request_sca_pubs_for(self, distroseries, arch_tag,
242 disable_cache=True):243 disable_cache, mock_request):
243 with patch('urllib.urlretrieve') as mock_urlretrieve:244 data_file = self.factory.get_test_file('software_center_apps.json')
244 mock_urlretrieve.return_value = (245 with open(data_file) as test_data:
245 self.factory.get_test_file('software_center_apps.json'), None)246 data = test_data.read()
246 if disable_cache:247 mock_request.return_value = ({'status': '200'}, data)
247 with patch('django.core.cache') as mock_cache:248
248 mock_cache.get.return_value = False249 if disable_cache:
249 published_apps = WebServices().get_sca_publishings_for(250 func = 'django.core.cache.cache.get'
250 distroseries, arch_tag)251 with patch(func) as mock_get:
251 else:252 mock_get.return_value = False
252 published_apps = WebServices().get_sca_publishings_for(253 published_apps = WebServices().get_sca_publishings_for(
253 distroseries, arch_tag)254 distroseries, arch_tag)
254 return published_apps, mock_urlretrieve255 else:
256 published_apps = WebServices().get_sca_publishings_for(
257 distroseries, arch_tag)
258 return published_apps, mock_request
255259
256 def test_get_sca_publishings(self):260 def test_get_sca_publishings(self):
257 published_apps, ignored = self._request_sca_pubs_for(261 published_apps, _ = self._request_sca_pubs_for(
258 'maverick', 'i386')262 'maverick', 'i386', True)
259263
260 self.assertEqual({264 self.assertEqual({
261 'lp-ppa-commercial-ppa-uploaders-brukkon': 'brukkon',265 'lp-ppa-commercial-ppa-uploaders-brukkon': 'brukkon',
@@ -272,19 +276,23 @@
272276
273 def test_retrieved_url(self):277 def test_retrieved_url(self):
274 with patch_settings(SCA_HOST_URL='http://example.com/'):278 with patch_settings(SCA_HOST_URL='http://example.com/'):
275 ignored, mock_urlretrieve = self._request_sca_pubs_for(279 ignored, mock_request = self._request_sca_pubs_for(
276 'natty', 'amd64')280 'natty', 'amd64', True)
277281
278 mock_urlretrieve.assert_called_with(282 mock_request.assert_called_with(
279 'http://example.com/apps/en/ubuntu/natty/amd64/')283 'http://example.com/api/2.0/applications/any/ubuntu/any/any/',
284 body='', headers={}, method='GET')
280285
281 def test_get_sca_publishings_cached(self):286 def test_get_sca_publishings_cached(self):
282 published_apps, mock_url_retrieve = self._request_sca_pubs_for(287 cache.clear()
283 'maverick', 'i386', disable_cache=False)288 published_apps, mock_request = self._request_sca_pubs_for(
284 published_apps, mock_urlretrieve = self._request_sca_pubs_for(289 'maverick', 'i386', False)
285 'maverick', 'i386', disable_cache=False)290 self.assertEqual(1, mock_request.call_count)
286291
287 self.assertEqual(0, mock_urlretrieve.call_count)292 published_apps, mock_request = self._request_sca_pubs_for(
293 'natty', 'i386', False)
294
295 self.assertEqual(0, mock_request.call_count)
288296
289 def _request_sca_verify(self, pkgname, origin, distroseries, arch_tag):297 def _request_sca_verify(self, pkgname, origin, distroseries, arch_tag):
290 with patch('urllib.urlretrieve') as mock_urlretrieve:298 with patch('urllib.urlretrieve') as mock_urlretrieve:
291299
=== modified file 'src/reviewsapp/utilities.py'
--- src/reviewsapp/utilities.py 2012-01-27 12:50:26 +0000
+++ src/reviewsapp/utilities.py 2012-04-11 16:37:30 +0000
@@ -37,7 +37,6 @@
37from django.http import HttpRequest37from django.http import HttpRequest
38from django.utils.cache import get_cache_key38from django.utils.cache import get_cache_key
39from django.utils.http import urlquote_plus39from django.utils.http import urlquote_plus
40from django.utils import simplejson
4140
42from launchpadlib.launchpad import Launchpad41from launchpadlib.launchpad import Launchpad
43from launchpadlib.uris import lookup_service_root42from launchpadlib.uris import lookup_service_root
@@ -46,6 +45,7 @@
46from lazr.restfulclient.errors import HTTPError45from lazr.restfulclient.errors import HTTPError
47from lazr.restfulclient.resource import ServiceRoot46from lazr.restfulclient.resource import ServiceRoot
48from oauth.oauth import OAuthToken47from oauth.oauth import OAuthToken
48from scaclient import SoftwareCenterAgentAPI
4949
5050
51class WebServiceError(Exception):51class WebServiceError(Exception):
@@ -222,40 +222,20 @@
222 return False222 return False
223223
224 def get_sca_publishings_for(self, distroseries, arch_tag):224 def get_sca_publishings_for(self, distroseries, arch_tag):
225 """A helper that builds a dict of publishings for sca-sold apps.225 cache_key = 'sca_all_available'
226226 apps = cache.get(cache_key)
227 XXX michaeln 2011-03-14 bug=734747 Optional parms for available_apps.227
228 It would be great if we could just pull /apps/en/ubuntu/ and use228 if not apps:
229 each items 'series' dict to populate this, rather than pulling each229 api = SoftwareCenterAgentAPI(service_root="{0}api/2.0/"
230 distroserie/arch separately. If we can assume that an app sold via230 .format(settings.SCA_HOST_URL))
231 softwarecenter will always be available for maverick i386, then we231 apps = api.available_apps(lang='any', series='any', arch='any')
232 could do just the one call too.232 cache.set(cache_key, apps, settings.SCA_APPS_CACHE_TIMEOUT)
233 """233
234 cache_key = 'sca_{0}_{1}'.format(distroseries, arch_tag)234 return dict([(
235 result = cache.get(cache_key)235 'lp-ppa-' + app.archive_id.replace('/', '-'),
236 if result is not None:236 app.package_name,
237 return result237 ) for app in apps if distroseries in app.series and
238238 arch_tag in app.series[distroseries]])
239 # XXX michaeln 2011-03-14 Update to use sca piston client.
240 # Once production SCA includes the piston client version we can
241 # use that instead. At time of writing the following url works
242 # on staging but not production sca:
243 # api/2.0/applications/en/ubuntu/maverick/i386/
244 filename, headers = urllib.urlretrieve(
245 settings.SCA_HOST_URL +
246 'apps/en/ubuntu/{0}/{1}/'.format(distroseries, arch_tag))
247
248 with open(filename, 'r') as sca_apps_file:
249 sca_apps = simplejson.load(sca_apps_file)
250
251 # We ensure the keys match Launchpad's current (ambiguous)
252 # origin identifiers - Launchpad bug 733170.
253 app_names = dict([(
254 'lp-ppa-' + app['archive_id'].replace('/', '-'),
255 app['package_name'],
256 ) for app in sca_apps])
257 cache.set(cache_key, app_names, settings.SCA_APPS_CACHE_TIMEOUT)
258 return app_names
259239
260240
261def cache_key_for_url(url):241def cache_key_for_url(url):

Subscribers

People subscribed via source and target branches