Merge lp:~michael.nelson/rnr-server/731736-other-origins into lp:rnr-server

Proposed by Michael Nelson
Status: Merged
Approved by: Michael Nelson
Approved revision: 154
Merged at revision: 151
Proposed branch: lp:~michael.nelson/rnr-server/731736-other-origins
Merge into: lp:rnr-server
Diff against target: 571 lines (+277/-103)
9 files modified
django_project/config_dev/config/main.cfg (+8/-0)
django_project/config_dev/schema.py (+1/-0)
src/reviewsapp/api/handlers.py (+3/-1)
src/reviewsapp/forms.py (+45/-38)
src/reviewsapp/models/reviews.py (+6/-0)
src/reviewsapp/tests/test_handlers.py (+42/-3)
src/reviewsapp/tests/test_rnrclient.py (+8/-3)
src/reviewsapp/tests/test_utilities.py (+120/-43)
src/reviewsapp/utilities.py (+44/-15)
To merge this branch: bzr merge lp:~michael.nelson/rnr-server/731736-other-origins
Reviewer Review Type Date Requested Status
Danny Tamez (community) Approve
Review via email: mp+53007@code.launchpad.net

Commit message

[r=zematynnad][bug=731376] Enable reviews of packages in partner and extras.

Description of the change

Overview
========

This branch is fixing bug 731376 by enabling reviews for origins other than 'ubuntu'.

To test: follow the README and then `make test`

This branch will not land until the next one, dealing with the issue identified below, is ready.

Details for the next branch
===========================
The main issue is verifying the origin for a new review when we don't yet have a record of that origin.

For 'ubuntu' and 'canonical' it is simple enough - we can use the LP API to verify that a binary with the given package name is published in the repository for the distroseries and arch. For extras it's also possible to verify (differently) using the API.

But we cannot generalise the origin for public PPAs currently, as the published origin is ambiguous (I created bug 733170). So I've just left that for the moment.

For the commercial PPAs, we cannot verify that the specified origin is correct, as LP doesn't let us query private PPAs for binaries :). So currently (in this branch) submitting a review for 'linux' in the fluendo-dvd origin would work, as would submitting a review for 'vendetta-online' in the fluendo-dvd origin, as would 'fluendo-dvd' in the correct origin, but with 'hoary' as the distroseries etc.

Sooo, we need a solution. The solutions I can think of are:
 1) Pull and cache the staging/production sca available apps to get the data (currently this will also pull the icons, but we could later add a separate url on sca for just the data we need, if necessary)
 2) (Temporary solution): Encode the binary publishings (ie. ppa-name, arch, distroseries) for each of the commercial apps in the settings (and update settings each time a new app is added).
...
So I'll probably go ahead with 1 (Update: checked with achuni and he agrees).

To post a comment you must log in.
Revision history for this message
Danny Tamez (zematynnad) wrote :

Michael - great works as always. Approved but what would you think of adding a test that is the negative test for "test_create_repository_and_software_item"? As it would be good to also test that when lp returns False that the item and repo are not created.

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

On Mon, Mar 14, 2011 at 6:46 PM, Danny Tamez <email address hidden>wrote:

> Review: Approve
> Michael - great works as always. Approved but what would you think of
> adding a test that is the negative test for
> "test_create_repository_and_software_item"? As it would be good to also
> test that when lp returns False that the item and repo are not created.
>

Yeah - good find... I'll add the test.

Thanks again!
M

154. By Michael Nelson

Added test ensuring new repositories are not created when lp_verify returns false.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'django_project/config_dev/config/main.cfg'
--- django_project/config_dev/config/main.cfg 2011-03-11 21:09:10 +0000
+++ django_project/config_dev/config/main.cfg 2011-03-15 09:36:33 +0000
@@ -98,6 +98,14 @@
98cache_review_stats_seconds = 1440098cache_review_stats_seconds = 14400
99token_cache_expiry_hours = 499token_cache_expiry_hours = 4
100reviewsapp_media_root = src/reviewsapp/media100reviewsapp_media_root = src/reviewsapp/media
101commercial_origins = lp-ppa-commercial-ppa-uploaders-fluendo-dvd
102 lp-ppa-commercial-ppa-uploaders-fluendo-plugins
103 lp-ppa-commercial-ppa-uploaders-fluendo-wmv-plugins
104 lp-ppa-commercial-ppa-uploaders-brukkon
105 lp-ppa-commercial-ppa-uploaders-vendetta-online
106 lp-ppa-commercial-ppa-uploaders-world-of-goo
107 lp-ppa-commercial-ppa-uploaders-illumination
108
101109
102[sso_api]110[sso_api]
103sso_api_service_root = https://login.staging.ubuntu.com/api/1.0111sso_api_service_root = https://login.staging.ubuntu.com/api/1.0
104112
=== modified file 'django_project/config_dev/schema.py'
--- django_project/config_dev/schema.py 2011-03-10 22:56:54 +0000
+++ django_project/config_dev/schema.py 2011-03-15 09:36:33 +0000
@@ -56,6 +56,7 @@
56 rnr.token_cache_expiry_hours = IntConfigOption(default=4)56 rnr.token_cache_expiry_hours = IntConfigOption(default=4)
57 rnr.reviewsapp_media_root = StringConfigOption()57 rnr.reviewsapp_media_root = StringConfigOption()
58 rnr.allow_multiple_reviews_for_testing = BoolConfigOption(default=False)58 rnr.allow_multiple_reviews_for_testing = BoolConfigOption(default=False)
59 rnr.commercial_origins = LinesConfigOption(item=StringConfigOption())
5960
60 # Launchpad61 # Launchpad
61 launchpad = ConfigSection()62 launchpad = ConfigSection()
6263
=== modified file 'src/reviewsapp/api/handlers.py'
--- src/reviewsapp/api/handlers.py 2011-03-01 12:24:51 +0000
+++ src/reviewsapp/api/handlers.py 2011-03-15 09:36:33 +0000
@@ -80,7 +80,7 @@
8080
81class RetrieveReviewHandler(BaseHandler):81class RetrieveReviewHandler(BaseHandler):
82 allowed_methods = ('GET',)82 allowed_methods = ('GET',)
83 83
84 def read(self, request, review_id):84 def read(self, request, review_id):
85 try:85 try:
86 review = Review.objects.get(id=review_id)86 review = Review.objects.get(id=review_id)
@@ -95,6 +95,8 @@
95 'id',95 'id',
96 'package_name',96 'package_name',
97 'app_name',97 'app_name',
98 'origin',
99 'distroseries',
98 'language',100 'language',
99 'date_created',101 'date_created',
100 'rating',102 'rating',
101103
=== modified file 'src/reviewsapp/forms.py'
--- src/reviewsapp/forms.py 2011-03-09 11:45:47 +0000
+++ src/reviewsapp/forms.py 2011-03-15 09:36:33 +0000
@@ -88,8 +88,7 @@
88 if not self.is_valid():88 if not self.is_valid():
89 return self.cleaned_data89 return self.cleaned_data
9090
91 self._validate_and_populate_software_item()91 self._validate_software_item_and_repository()
92 self._validate_and_populate_repository()
9392
94 if not settings.ALLOW_MULTIPLE_REVIEWS_FOR_TESTING:93 if not settings.ALLOW_MULTIPLE_REVIEWS_FOR_TESTING:
95 # Ensure a user cannot submit a second review for the same app94 # Ensure a user cannot submit a second review for the same app
@@ -117,52 +116,60 @@
117 self.cleaned_data['architecture'] = architecture116 self.cleaned_data['architecture'] = architecture
118 return arch_tag117 return arch_tag
119118
120 def _validate_and_populate_software_item(self):119 def _validate_software_item_and_repository(self):
121 """Add the software item to the cleaned data, creating if necessary.120 """Add the software item and repository to the cleaned data.
121
122 If they do not exist in the db, we check the validity and
123 create them if they are valid.
122 """124 """
123 package_name = self.cleaned_data['package_name']125 package_name = self.cleaned_data['package_name']
124 app_name = self.cleaned_data['app_name']126 app_name = self.cleaned_data['app_name']
127 origin = self.cleaned_data['origin']
125 distroseries = self.cleaned_data['distroseries']128 distroseries = self.cleaned_data['distroseries']
126 arch_tag=self.cleaned_data['arch_tag']129 arch_tag=self.cleaned_data['arch_tag']
127 review_count = Review.objects.filter(130
128 softwareitem__package_name=package_name,131 require_lp_check = False
129 softwareitem__app_name=app_name,132 repository = None
130 repository__distroseries=distroseries,133 # First we grab the repository - if it exists.
131 architecture__tag=arch_tag).count()134 try:
132 if review_count == 0:135 repository = Repository.objects.get(
133 # This is the first review for this software_item and distroseries136 origin=origin, distroseries=distroseries)
134 if not WebServices().lp_verify_packagename_in_distro(137 except Repository.DoesNotExist:
135 package_name, distroseries, arch_tag=arch_tag):138 require_lp_check = True
139
140 if repository is not None:
141 # Check whether there are any existing reviews for this
142 # software in the repository with the given arch.
143 review_count = Review.objects.filter(
144 softwareitem__package_name=package_name,
145 softwareitem__app_name=app_name,
146 repository=repository,
147 architecture__tag=arch_tag).count()
148 if review_count == 0:
149 # This is the first review for this software_item in the
150 # repository with the given arch.
151 require_lp_check = True
152
153 if require_lp_check:
154 valid_in_lp = WebServices().lp_verify_packagename_in_repository(
155 package_name, origin, distroseries, arch_tag=arch_tag)
156
157 if not valid_in_lp:
136 raise forms.ValidationError(158 raise forms.ValidationError(
137 ': package {0} not in {1} for {2}'.format(159 ': package {0} not in {1} {2} for {2}'.format(
138 package_name, distroseries, arch_tag))160 package_name, origin, distroseries, arch_tag))
161
162 # Now we know the given data corresponds to a published binary
163 # on launchpad, so we can populate the cleaned data, creating
164 # the repository and software_item records if necessary.
165 repository = repository or Repository.objects.create(
166 origin=origin, distroseries=distroseries)
167 self.cleaned_data['repository'] = repository
168
139 software_item, created = SoftwareItem.objects.get_or_create(169 software_item, created = SoftwareItem.objects.get_or_create(
140 package_name=package_name, app_name=app_name)170 package_name=package_name, app_name=app_name)
141
142 self.cleaned_data['software_item'] = software_item171 self.cleaned_data['software_item'] = software_item
143172
144 def _validate_and_populate_repository(self):
145 """Add the repository to the cleaned data, creating if necessary."""
146 # Find the origin/distroseries for the software item.
147 origin = self.cleaned_data['origin']
148 distroseries = self.cleaned_data['distroseries']
149 try:
150 repository = Repository.objects.get(
151 origin=origin,
152 distroseries=distroseries)
153 except Repository.DoesNotExist:
154 # The software repository does not yet exist, probably because
155 # this is the first review for this origin/distroseries. That's
156 # okay, create a record for it in our database.
157 #
158 # XXX 2010-03-03 bug=688043 Verify with Launchpad first.
159 repository = Repository(
160 origin=origin,
161 distroseries=distroseries)
162 repository.save()
163
164 self.cleaned_data['repository'] = repository
165
166173
167class ReviewModerationFilterForm(forms.Form):174class ReviewModerationFilterForm(forms.Form):
168 """Filtering options for review moderation list."""175 """Filtering options for review moderation list."""
169176
=== modified file 'src/reviewsapp/models/reviews.py'
--- src/reviewsapp/models/reviews.py 2011-03-09 08:27:34 +0000
+++ src/reviewsapp/models/reviews.py 2011-03-15 09:36:33 +0000
@@ -270,6 +270,12 @@
270 def app_name(self):270 def app_name(self):
271 return self.softwareitem.app_name271 return self.softwareitem.app_name
272272
273 def origin(self):
274 return self.repository.origin
275
276 def distroseries(self):
277 return self.repository.distroseries
278
273 def package_app_name(self):279 def package_app_name(self):
274 app_name = self.app_name()280 app_name = self.app_name()
275 if app_name:281 if app_name:
276282
=== modified file 'src/reviewsapp/tests/test_handlers.py'
--- src/reviewsapp/tests/test_handlers.py 2011-03-09 11:49:10 +0000
+++ src/reviewsapp/tests/test_handlers.py 2011-03-15 09:36:33 +0000
@@ -51,6 +51,7 @@
51 SubmitUsefulnessHandler,51 SubmitUsefulnessHandler,
52)52)
53from reviewsapp.models import (53from reviewsapp.models import (
54 Repository,
54 Review,55 Review,
55 ReviewModerationFlag,56 ReviewModerationFlag,
56 SoftwareItem,57 SoftwareItem,
@@ -475,7 +476,7 @@
475 }476 }
476 super(SubmitReviewHandlerTestCase, self).setUp()477 super(SubmitReviewHandlerTestCase, self).setUp()
477478
478 def _post_new_review(self, data, user=None):479 def _post_new_review(self, data, user=None, lp_verify_result=True):
479 # Post a review as an authenticated user.480 # Post a review as an authenticated user.
480 url = reverse('rnr-api-reviews')481 url = reverse('rnr-api-reviews')
481482
@@ -485,11 +486,11 @@
485486
486 is_authed_fn = 'reviewsapp.auth.SSOOAuthAuthentication.is_authenticated'487 is_authed_fn = 'reviewsapp.auth.SSOOAuthAuthentication.is_authenticated'
487 lp_verify_fn = ('reviewsapp.utilities.WebServices.'488 lp_verify_fn = ('reviewsapp.utilities.WebServices.'
488 'lp_verify_packagename_in_distro')489 'lp_verify_packagename_in_repository')
489 with patch(is_authed_fn) as mock_is_authenticated:490 with patch(is_authed_fn) as mock_is_authenticated:
490 mock_is_authenticated.return_value = True491 mock_is_authenticated.return_value = True
491 with patch(lp_verify_fn) as mock_lp_verify_method:492 with patch(lp_verify_fn) as mock_lp_verify_method:
492 mock_lp_verify_method.return_value = True493 mock_lp_verify_method.return_value = lp_verify_result
493 response = self.client.post(494 response = self.client.post(
494 url, data=data, content_type='application/json')495 url, data=data, content_type='application/json')
495 return response496 return response
@@ -520,6 +521,44 @@
520 response_dict = simplejson.loads(response.content)521 response_dict = simplejson.loads(response.content)
521 self.assertEqual('inkscape', response_dict['package_name'])522 self.assertEqual('inkscape', response_dict['package_name'])
522523
524 def test_creates_repository_and_software_item(self):
525 # Submitting a review for a software item or repository of which
526 # we don't yet have a record will create those records (after
527 # validating that the corresponding binary exists on Launchpad).
528 required_data = self.required_data
529 required_data['distroseries'] = 'doesntexist'
530 self.assertEqual(0, Repository.objects.filter(
531 origin='ubuntu', distroseries='doesntexist').count())
532 self.assertEqual(0, SoftwareItem.objects.filter(
533 package_name='inkscape').count())
534
535 response = self._post_new_review(simplejson.dumps(self.required_data))
536
537 self.assertEqual(1, Repository.objects.filter(
538 origin='ubuntu', distroseries='doesntexist').count())
539 self.assertEqual(1, SoftwareItem.objects.filter(
540 package_name='inkscape').count())
541
542 def test_bad_repository(self):
543 # If lp_verify returns false a bad request status is returned,
544 # and no new repositories are created.
545 required_data = self.required_data
546 required_data['distroseries'] = 'doesntexist'
547 self.assertEqual(0, Repository.objects.filter(
548 origin='ubuntu', distroseries='doesntexist').count())
549 self.assertEqual(0, SoftwareItem.objects.filter(
550 package_name='inkscape').count())
551
552 response = self._post_new_review(
553 simplejson.dumps(self.required_data), lp_verify_result=False)
554
555 self.assertEqual(httplib.BAD_REQUEST, response.status_code)
556 self.assertEqual(0, Repository.objects.filter(
557 origin='ubuntu', distroseries='doesntexist').count())
558 self.assertEqual(0, SoftwareItem.objects.filter(
559 package_name='inkscape').count())
560
561
523 def test_max_length_summary(self):562 def test_max_length_summary(self):
524 # Posting with a summary > 80 chars results in a bad request.563 # Posting with a summary > 80 chars results in a bad request.
525 data = self.required_data564 data = self.required_data
526565
=== modified file 'src/reviewsapp/tests/test_rnrclient.py'
--- src/reviewsapp/tests/test_rnrclient.py 2011-03-09 08:27:34 +0000
+++ src/reviewsapp/tests/test_rnrclient.py 2011-03-15 09:36:33 +0000
@@ -154,6 +154,8 @@
154 reviews[0].reviewer_username)154 reviews[0].reviewer_username)
155 self.assertEqual(review.reviewer_displayname(),155 self.assertEqual(review.reviewer_displayname(),
156 reviews[0].reviewer_displayname)156 reviews[0].reviewer_displayname)
157 self.assertEqual(review.origin(), reviews[0].origin)
158 self.assertEqual(review.distroseries(), reviews[0].distroseries)
157159
158 def test_get_reviews_for_app(self):160 def test_get_reviews_for_app(self):
159 software_item = self.factory.makeSoftwareItem(app_name='something')161 software_item = self.factory.makeSoftwareItem(app_name='something')
@@ -202,9 +204,11 @@
202 review = self.factory.makeReview()204 review = self.factory.makeReview()
203205
204 api = RatingsAndReviewsAPI()206 api = RatingsAndReviewsAPI()
205 review_request = api.get_review(review_id=review.id)207 review_detail = api.get_review(review_id=review.id)
206208
207 self.assertEqual(review_request.id, review.id)209 self.assertEqual(review_detail.id, review.id)
210 self.assertEqual(review_detail.origin, review.origin())
211 self.assertEqual(review_detail.distroseries, review.distroseries())
208 invalidate_paginated_reviews_for(review)212 invalidate_paginated_reviews_for(review)
209213
210214
@@ -222,7 +226,8 @@
222 auth = OAuthAuthorizer(token.token, token.token_secret, consumer.key,226 auth = OAuthAuthorizer(token.token, token.token_secret, consumer.key,
223 consumer.secret)227 consumer.secret)
224 lp_verify_packagename_method = (228 lp_verify_packagename_method = (
225 'reviewsapp.utilities.WebServices.lp_verify_packagename_in_distro')229 'reviewsapp.utilities.WebServices.'
230 'lp_verify_packagename_in_repository')
226231
227 if mock_verify_package is None:232 if mock_verify_package is None:
228 mock_verify_package = Mock()233 mock_verify_package = Mock()
229234
=== modified file 'src/reviewsapp/tests/test_utilities.py'
--- src/reviewsapp/tests/test_utilities.py 2011-03-10 22:56:54 +0000
+++ src/reviewsapp/tests/test_utilities.py 2011-03-15 09:36:33 +0000
@@ -100,58 +100,135 @@
100class LaunchpadTestCase(TestCaseWithFactory):100class LaunchpadTestCase(TestCaseWithFactory):
101 def setUp(self):101 def setUp(self):
102 super(LaunchpadTestCase, self).setUp()102 super(LaunchpadTestCase, self).setUp()
103 self._request = HttpRequest()
104 self._request.user = self.factory.makeUser()
105 self.binary = Mock()
106 self.mock_lp = Mock()
107 archive = self.mock_lp.load.return_value
108 archive.getPublishedBinaries.return_value = [self.binary]
109 self.client.login(username=self._request.user.username, password='test')
110 # Force web_services to recreate the the Launchpad service root103 # Force web_services to recreate the the Launchpad service root
111 WebServices._launchpad_service = None104 WebServices._launchpad_service = None
112105
113 @patch('reviewsapp.utilities.Launchpad')106 def _make_mock_launchpad(self, binary_name='mypkg'):
114 def test_valid_package(self, mock_launchpad):107 mock_ubuntu = Mock()
115 # A valid package in a distroseries can be found.108 mock_ubuntu.self_link = 'http://lpapi/ubuntu'
116 mock_launchpad.login_anonymously.return_value = self.mock_lp109
117 self.binary.binary_package_name = 'apt'110 mock_launchpad = Mock()
118 ws = WebServices()111 mock_launchpad.distributions = dict(ubuntu=mock_ubuntu)
119112 app_review_board = Mock()
120 self.assertTrue(ws.lp_verify_packagename_in_distro("apt", "lucid",113 mock_launchpad.people = {'app-review-board': app_review_board}
121 'i386'))114
122115 mock_archive = Mock()
123 @patch('reviewsapp.utilities.Launchpad')116 mock_ubuntu.getArchive.return_value = mock_archive
124 def test_invalid_distro(self, mock_launchpad):117 app_review_board.getPPAByName.return_value = mock_archive
125 # Invalid distroseries (assuming we never call a release 'xxx') cannot118
126 # be found.119 mock_binary = Mock()
127 mock_launchpad.login_anonymously.return_value = self.mock_lp120 mock_binary.binary_package_name = binary_name
121 mock_archive.getPublishedBinaries.return_value = [mock_binary]
122 return (mock_launchpad, mock_ubuntu, mock_archive)
123
124 def _verify_package(self, mock_lp_api, package_name,
125 distro, series, arch_tag):
126 with patch('reviewsapp.utilities.Launchpad') as mock_launchpad:
127 mock_launchpad.login_anonymously.return_value = mock_lp_api
128 return WebServices().lp_verify_packagename_in_repository(
129 package_name, distro, series, arch_tag)
130
131 def test_package_in_ubuntu(self):
132 lp_api, ubuntu, archive = self._make_mock_launchpad()
133
134 result = self._verify_package(lp_api, 'mypkg', 'ubuntu', 'lucid',
135 'i386')
136
137 ubuntu.getArchive.assert_called_with(name='primary')
138 archive.getPublishedBinaries.assert_called_with(
139 binary_name='mypkg',
140 distro_arch_series='http://lpapi/ubuntu/lucid/i386',
141 status='Published', exact_match=True)
142 self.assertTrue(result)
143
144 def test_package_not_in_ubuntu(self):
145 lp_api, ubuntu, archive = self._make_mock_launchpad(
146 binary_name='other_pkg')
147
148 result = self._verify_package(lp_api, 'mypkg', 'ubuntu', 'lucid',
149 'i386')
150
151 ubuntu.getArchive.assert_called_with(name='primary')
152 archive.getPublishedBinaries.assert_called_with(
153 binary_name='mypkg',
154 distro_arch_series='http://lpapi/ubuntu/lucid/i386',
155 status='Published', exact_match=True)
156 self.assertFalse(result)
157
158 def test_package_in_partner(self):
159 lp_api, ubuntu, archive = self._make_mock_launchpad()
160
161 result = self._verify_package(lp_api, 'mypkg', 'canonical', 'lucid',
162 'i386')
163
164 ubuntu.getArchive.assert_called_with(name='partner')
165 archive.getPublishedBinaries.assert_called_with(
166 binary_name='mypkg',
167 distro_arch_series='http://lpapi/ubuntu/lucid/i386',
168 status='Published', exact_match=True)
169 self.assertTrue(result)
170
171 def test_package_in_extras(self):
172 lp_api, ubuntu, archive = self._make_mock_launchpad()
173
174 result = self._verify_package(lp_api, 'mypkg',
175 'lp-ppa-app-review-board', 'lucid', 'i386')
176
177 app_review_board = lp_api.people['app-review-board']
178 app_review_board.getPPAByName.assert_called_with(name='ppa')
179 archive.getPublishedBinaries.assert_called_with(
180 binary_name='mypkg',
181 distro_arch_series='http://lpapi/ubuntu/lucid/i386',
182 status='Published', exact_match=True)
183 self.assertTrue(result)
184
185 def test_commercial_package(self):
186 lp_api, ubuntu, archive = self._make_mock_launchpad()
187
188 with patch_settings(COMMERCIAL_ORIGINS=['lp-ppa-commercial-one']):
189 result = self._verify_package(lp_api, 'anything',
190 'lp-ppa-commercial-one', 'anything', 'anything')
191
192 # XXX The result should not always be true... we need a way to
193 # know the content of commercial ppas.
194 self.assertTrue(result)
195
196 def test_unknown_origin(self):
197 lp_api, ubuntu, archive = self._make_mock_launchpad()
198
199 result = self._verify_package(lp_api, 'mypkg',
200 'lp-ppa-unknown', 'lucid', 'i386')
201
202 # Currently we only support primary, partner, extras and the
203 # specified commercial origins.
204 self.assertEqual(0, archive.getPublishedBinaries.call_count)
205 self.assertFalse(result)
206
207 def test_invalid_series_or_arch(self):
208 # An invalid series or arch raises a 400 Bad Request.
209 lp_api, ubuntu, archive = self._make_mock_launchpad()
128 response = Mock()210 response = Mock()
129 response.status = 404211 response.status = 400
130 mock_launchpad.load.side_effect = HTTPError(response, 'content')212 archive.getPublishedBinaries.side_effect = HTTPError(
131 ws = WebServices()213 response, 'content')
132214
133 self.assertFalse(ws.lp_verify_packagename_in_distro("apt", "xxx",215 result = self._verify_package(lp_api, 'mypkg', 'ubuntu', 'lucid',
134 'i386'))216 'i386')
135217
136 @patch('reviewsapp.utilities.Launchpad')218 self.assertFalse(result)
137 def test_invalid_package(self, mock_launchpad):
138 # Invalid package (assuming no one creates such a package) in a valid
139 # distroseries cannot be found.
140 mock_launchpad.login_anonymously.return_value = self.mock_lp
141 ws = WebServices()
142
143 self.assertFalse(ws.lp_verify_packagename_in_distro(
144 "***xxx***", "lucid", 'i386'))
145219
146 @patch('reviewsapp.utilities.Launchpad')220 @patch('reviewsapp.utilities.Launchpad')
147 def test_doesnt_sign_in_each_time(self, mock_launchpad):221 def test_doesnt_sign_in_each_time(self, mock_launchpad):
148 mock_launchpad.login_anonymously.return_value = self.mock_lp222 lp_api, ubuntu, archive = self._make_mock_launchpad()
223 mock_launchpad.login_anonymously.return_value = lp_api
149 ws = WebServices()224 ws = WebServices()
150 ws.lp_verify_packagename_in_distro("foobar", "lucid", 'i386')225 ws.lp_verify_packagename_in_repository("foobar", 'ubuntu',
226 "lucid", 'i386')
151 self.assertTrue(mock_launchpad.login_anonymously.called)227 self.assertTrue(mock_launchpad.login_anonymously.called)
152 mock_launchpad.login_anonymously.reset_mock()228 mock_launchpad.login_anonymously.reset_mock()
153229
154 ws.lp_verify_packagename_in_distro("foobar", "lucid", 'i386')230 ws.lp_verify_packagename_in_repository("foobar", 'ubuntu',
231 "lucid", 'i386')
155232
156 self.assertFalse(mock_launchpad.login_anonymously.called)233 self.assertFalse(mock_launchpad.login_anonymously.called)
157234
@@ -163,8 +240,8 @@
163 del os.environ['HOME']240 del os.environ['HOME']
164 ws = WebServices()241 ws = WebServices()
165 # SyntaxError is raised when we fail to parse our dummy wadl242 # SyntaxError is raised when we fail to parse our dummy wadl
166 self.assertRaises(SyntaxError, ws.lp_verify_packagename_in_distro,243 self.assertRaises(SyntaxError, ws.lp_verify_packagename_in_repository,
167 "foobar", "lucid", 'i386')244 "foobar", "ubuntu", "lucid", 'i386')
168245
169246
170class InvalidatePaginatedReviewsTestCase(TestCaseWithFactory):247class InvalidatePaginatedReviewsTestCase(TestCaseWithFactory):
171248
=== modified file 'src/reviewsapp/utilities.py'
--- src/reviewsapp/utilities.py 2011-03-10 11:02:01 +0000
+++ src/reviewsapp/utilities.py 2011-03-15 09:36:33 +0000
@@ -157,33 +157,62 @@
157 result.update(api.accounts.me())157 result.update(api.accounts.me())
158 return result158 return result
159159
160 def lp_verify_packagename_in_distro(self, pkgname, distroseries,160 def lp_verify_packagename_in_repository(self, pkgname, origin, distroseries,
161 arch_tag):161 arch_tag):
162 """Verify that a given package exists in a distroseries.162 """Verify that a given package exists in a distroseries.
163163
164 :param pkgname: The name of the package to check.164 :param pkgname: The name of the package to check.
165 :param origin: The repository origin identifier.
165 :param distroseries: The name of distribution series.166 :param distroseries: The name of distribution series.
166 :param arch_tag: The machine architecture (i386, amd64...)167 :param arch_tag: The machine architecture (i386, amd64...)
167 :return: Whether the package was found or not.168 :return: Whether the package was found or not.
168 :rtype: bool169 :rtype: bool
169 """170 """
170 # FIXME: is there a better way to get the root_uri from LP?171 ubuntu = self.launchpad_service.distributions['ubuntu']
171 ubuntu_uri = str(self.launchpad_service._root_uri) + "ubuntu/"172 if origin == 'ubuntu':
173 archive = ubuntu.getArchive(name='primary')
174 elif origin == 'canonical':
175 archive = ubuntu.getArchive(name='partner')
176 elif origin =='lp-ppa-app-review-board':
177 app_review_board = self.launchpad_service.people[
178 'app-review-board']
179 archive = app_review_board.getPPAByName(name='ppa')
180 elif origin in settings.COMMERCIAL_ORIGINS:
181 # XXX 2011-03-11 michaeln bug=733170 PPA origins are
182 # currently ambiguous.
183 # We should check this in a way that doesn't require
184 # settings, either pulling the data from SCA, or request
185 # that LP updates IArchive to allow public access to
186 # getPublishedBinaries() for commercial PPAs (but not
187 # private-only).
188 # XXX - chat with achuni about options - dict in settings?
189 # Perhaps for now just a non-configglue setting with a
190 # complex dict:
191 # 'lp-ppa-commercial-ppa-uploaders-fluendo-dvd': {
192 # 'package_name': 'fluendo-dvd',
193 # 'releases': {
194 # 'natty': ['i386', 'amd64'],
195 # ...
196 # And then we can make this available on SCA as json/api.
197 return True
198 else:
199 return False
200
201 # We now have the archive, check for the distroseries and the
202 # package.
203 distro_arch_series = ubuntu.self_link + '/{0}/{1}'.format(
204 distroseries, arch_tag)
172 try:205 try:
173 release = self.launchpad_service.load(ubuntu_uri + distroseries)206 binaries = archive.getPublishedBinaries(
174 distro_arch = self.launchpad_service.load(207 binary_name=pkgname, distro_arch_series=distro_arch_series,
175 ubuntu_uri + '{0}/{1}'.format(distroseries, arch_tag))208 status='Published', exact_match=True)
176 except HTTPError as error:209 except HTTPError as error:
177 if error.response.status == 404:210 if error.response.status == 400:
178 # Either the release or distro_arch does not exist.211 # A bad request is raised if the distro arch series we
179 # Obviously, this does not verify! Any other status is212 # indicate does not exist. Obviously, this does not
180 # unexpected.213 # verify! Any other status is unexpected.
181 return False214 return False
182 raise215 raise
183 archive = self.launchpad_service.load(ubuntu_uri + '+archive/primary')
184 binaries = archive.getPublishedBinaries(
185 binary_name=pkgname, distro_arch_series=distro_arch,
186 exact_match=True)
187 for binary in binaries:216 for binary in binaries:
188 if binary.binary_package_name == pkgname:217 if binary.binary_package_name == pkgname:
189 return True218 return True

Subscribers

People subscribed via source and target branches