Merge lp:~fgallina/rnr-server/click-reviews-return-useroid-as-username into lp:rnr-server

Proposed by Fabián Ezequiel Gallina
Status: Merged
Approved by: Fabián Ezequiel Gallina
Approved revision: 304
Merged at revision: 299
Proposed branch: lp:~fgallina/rnr-server/click-reviews-return-useroid-as-username
Merge into: lp:rnr-server
Diff against target: 348 lines (+126/-42)
7 files modified
src/clickreviews/api/handlers.py (+8/-0)
src/clickreviews/models.py (+6/-0)
src/clickreviews/tests/test_handlers.py (+12/-19)
src/clickreviews/tests/test_models.py (+19/-0)
src/core/tests/factory.py (+4/-2)
src/core/tests/helpers.py (+56/-0)
src/core/tests/test_utilities.py (+21/-21)
To merge this branch: bzr merge lp:~fgallina/rnr-server/click-reviews-return-useroid-as-username
Reviewer Review Type Date Requested Status
Natalia Bidart (community) Approve
Ricardo Kirkner (community) Approve
Review via email: mp+257106@code.launchpad.net

Commit message

Return the User openid as reviewer_username in clickreviews

To post a comment you must log in.
Revision history for this message
Ricardo Kirkner (ricardokirkner) :
Revision history for this message
Fabián Ezequiel Gallina (fgallina) :
Revision history for this message
Ricardo Kirkner (ricardokirkner) wrote :

LGTM

review: Approve
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Overall looks good, added a few comments for this implementation.

What I wonder it will not be a better approach to migrate usernames as we go, that means: we update the username value with the openid value, that we could have pre-stored in the instances.

What do you think?

Revision history for this message
Natalia Bidart (nataliabidart) :
review: Approve
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :
Download full text (9.1 KiB)

The attempt to merge lp:~fgallina/rnr-server/click-reviews-return-useroid-as-username into lp:rnr-server failed. Below is the output from the failed tests.

rm -rf ./virtualenv
sed -e '1,/# Dependencies/d;s/^rnr-server/./g;s/bazaar.isd/bazaar.launchpad.net/g' config-manager.txt > config-manager.txt.tmp
/usr/lib/config-manager/cm.py update config-manager.txt.tmp
Not deleting ./virtualenv/bin
New python executable in ./virtualenv/bin/python
Installing distribute.............................................................................................................................................................................................done.
Installing pip...............done.
./virtualenv/bin/pip install -r requirements.txt
Requirement already satisfied (use --upgrade to upgrade): coverage in /usr/lib/python2.7/dist-packages (from -r requirements.txt (line 4))
Downloading/unpacking django-factory==0.11 (from -r requirements.txt (line 5))
  Downloading django_factory-0.11.tar.gz
  Running setup.py egg_info for package django-factory

    warning: no previously-included files matching '*.pyc' found anywhere in distribution
Requirement already satisfied (use --upgrade to upgrade): mechanize in /usr/lib/python2.7/dist-packages (from -r requirements.txt (line 6))
Requirement already satisfied (use --upgrade to upgrade): mock in /usr/lib/python2.7/dist-packages (from -r requirements.txt (line 7))
Requirement already satisfied (use --upgrade to upgrade): paste==1.7.5.1 in /usr/lib/python2.7/dist-packages (from -r requirements.txt (line 8))
Requirement already satisfied (use --upgrade to upgrade): pep8 in /usr/lib/python2.7/dist-packages (from -r requirements.txt (line 9))
Requirement already satisfied (use --upgrade to upgrade): piston-mini-client in /usr/lib/python2.7/dist-packages (from -r requirements.txt (line 10))
Requirement already satisfied (use --upgrade to upgrade): testtools in /usr/lib/python2.7/dist-packages (from -r requirements.txt (line 11))
Downloading/unpacking wsgi-intercept==0.5.1 (from -r requirements.txt (line 12))
  Running setup.py egg_info for package wsgi-intercept

Requirement already satisfied (use --upgrade to upgrade): django>=1.1 in /usr/lib/python2.7/dist-packages (from django-factory==0.11->-r requirements.txt (line 5))
Installing collected packages: django-factory, wsgi-intercept
  Running setup.py install for django-factory

    warning: no previously-included files matching '*.pyc' found anywhere in distribution
  Running setup.py install for wsgi-intercept

Successfully installed django-factory wsgi-intercept
Cleaning up...
[localhost] local: virtualenv/bin/python django_project/manage.py test -v 2 --failfast src
Creating test database for alias 'default' (':memory:')...
Syncing...
Creating tables ...
Creating table django_admin_log
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table south_migrationhistory
Creating table piston_nonce
Creating t...

Read more...

304. By Fabián Ezequiel Gallina

Fix tests

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/clickreviews/api/handlers.py'
--- src/clickreviews/api/handlers.py 2015-03-10 14:56:42 +0000
+++ src/clickreviews/api/handlers.py 2015-04-22 19:38:49 +0000
@@ -58,6 +58,7 @@
58 package_name = form.cleaned_data['package_name']58 package_name = form.cleaned_data['package_name']
5959
60 return (ClickPackageReview.objects.published()60 return (ClickPackageReview.objects.published()
61 .prefetch_related('reviewer__useropenid_set')
61 .select_related('click_package', 'reviewer')62 .select_related('click_package', 'reviewer')
62 .filter(click_package__package_name=package_name)63 .filter(click_package__package_name=package_name)
63 # XXX: Order by date until usefulness is implemented.64 # XXX: Order by date until usefulness is implemented.
@@ -172,6 +173,9 @@
172 _model = None173 _model = None
173 _form = None174 _form = None
174175
176 def _prepare_queryset(self, queryset):
177 return queryset
178
175 def read(self, request, status=None, pk=None):179 def read(self, request, status=None, pk=None):
176 if status is None:180 if status is None:
177 queryset = self._model.objects.all()181 queryset = self._model.objects.all()
@@ -188,6 +192,7 @@
188 .order_by('-num_flags', 'date_created')192 .order_by('-num_flags', 'date_created')
189 .select_related()193 .select_related()
190 .prefetch_related('flag_set__user'))194 .prefetch_related('flag_set__user'))
195 queryset = self._prepare_queryset(queryset)
191196
192 if pk is not None:197 if pk is not None:
193 return get_object_or_404(queryset, pk=pk)198 return get_object_or_404(queryset, pk=pk)
@@ -288,3 +293,6 @@
288 'get_full_name',293 'get_full_name',
289 'last_name')))),294 'last_name')))),
290 'status')295 'status')
296
297 def _prepare_queryset(self, queryset):
298 return queryset.prefetch_related('review__reviewer__useropenid_set')
291299
=== modified file 'src/clickreviews/models.py'
--- src/clickreviews/models.py 2015-03-10 19:16:55 +0000
+++ src/clickreviews/models.py 2015-04-22 19:38:49 +0000
@@ -74,6 +74,12 @@
74 return self.click_package.package_name74 return self.click_package.package_name
7575
76 def reviewer_username(self):76 def reviewer_username(self):
77 # Use .all() so that `prefetch_related` have effect.
78 openid_objs = list(self.reviewer.useropenid_set.all())
79 if openid_objs:
80 openid_obj = openid_objs[-1]
81 return openid_obj.claimed_id.split('/')[-1]
82 # Production queries show this won't happen, use as safeguard.
77 return self.reviewer.username83 return self.reviewer.username
7884
79 def reviewer_displayname(self):85 def reviewer_displayname(self):
8086
=== modified file 'src/clickreviews/tests/test_handlers.py'
--- src/clickreviews/tests/test_handlers.py 2015-03-10 19:16:55 +0000
+++ src/clickreviews/tests/test_handlers.py 2015-04-22 19:38:49 +0000
@@ -23,7 +23,7 @@
23)23)
24from clickreviews.tests.factory import TestCaseWithFactory24from clickreviews.tests.factory import TestCaseWithFactory
25from core.models import BaseModeration25from core.models import BaseModeration
26from core.tests.helpers import SSOTestCaseMixin26from core.tests.helpers import SSOTestCaseMixin, assert_no_extra_queries_after
2727
2828
29class ClickReviewsHandlerTestCase(TestCaseWithFactory):29class ClickReviewsHandlerTestCase(TestCaseWithFactory):
@@ -91,7 +91,7 @@
91 'date_created': DateTimeAwareJSONEncoder().encode(91 'date_created': DateTimeAwareJSONEncoder().encode(
92 review.date_created).strip('"'),92 review.date_created).strip('"'),
93 'rating': 5,93 'rating': 5,
94 'reviewer_username': review.reviewer.username,94 'reviewer_username': review.reviewer_username(),
95 'reviewer_displayname': review.reviewer.get_full_name(),95 'reviewer_displayname': review.reviewer.get_full_name(),
96 'summary': 'Excellent',96 'summary': 'Excellent',
97 'review_text': 'Plain brilliant piece of software',97 'review_text': 'Plain brilliant piece of software',
@@ -253,10 +253,10 @@
253 package = self.factory.makeClickPackage()253 package = self.factory.makeClickPackage()
254 for _ in range(5):254 for _ in range(5):
255 self.factory.makeClickPackageReview(click_package=package)255 self.factory.makeClickPackageReview(click_package=package)
256256 assert_no_extra_queries_after(
257 self.assertNumQueries(1, self._get_reviews, data={257 lambda: self.factory.makeClickPackageReview(click_package=package),
258 'package_name': package.package_name,258 self._get_reviews, data={'package_name': package.package_name}
259 })259 )
260260
261 def _update_review(self, review, data, user=None):261 def _update_review(self, review, data, user=None):
262 # Post a review as an authenticated user.262 # Post a review as an authenticated user.
@@ -953,19 +953,12 @@
953 data['errors']['status'])953 data['errors']['status'])
954954
955 def test_read_query_count(self):955 def test_read_query_count(self):
956 # 1 query for counting the moderations956 for _ in range(5):
957 # 1 query for moderations themselves957 self.make_moderation_object()
958 # 1 query for prefetching flags958
959 expected_queries = 3959 assert_no_extra_queries_after(
960 url = reverse(self.url_name)960 lambda: self.make_moderation_object(),
961961 self.request_get, reverse(self.url_name))
962 for _ in range(10):
963 self.make_moderation_object()
964 self.assertNumQueries(expected_queries, lambda: self.request_get(url))
965
966 for _ in range(10):
967 self.make_moderation_object()
968 self.assertNumQueries(expected_queries, lambda: self.request_get(url))
969962
970 def test_ordering(self):963 def test_ordering(self):
971 # the following are sorted in reverse expected order.964 # the following are sorted in reverse expected order.
972965
=== modified file 'src/clickreviews/tests/test_models.py'
--- src/clickreviews/tests/test_models.py 2015-03-09 20:47:12 +0000
+++ src/clickreviews/tests/test_models.py 2015-04-22 19:38:49 +0000
@@ -157,6 +157,25 @@
157 # Stats should be updated.157 # Stats should be updated.
158 self.assertEqual(review.click_package.histogram, '[0, 0, 0, 0, 0]')158 self.assertEqual(review.click_package.histogram, '[0, 0, 0, 0, 0]')
159159
160 def test_reviewer_username_same_username_and_openid(self):
161 expected = 'theuoid'
162 user = self.factory.makeUser(username=expected, open_id=expected)
163 review = self.factory.makeClickPackageReview(reviewer=user)
164 self.assertEqual(review.reviewer_username(), expected)
165
166 def test_reviewer_username_returns_openid(self):
167 expected = 'theopenid'
168 user = self.factory.makeUser(
169 username='bogusfromlogin', open_id=expected)
170 review = self.factory.makeClickPackageReview(reviewer=user)
171 self.assertEqual(review.reviewer_username(), expected)
172
173 def test_reviewer_username_fallbacks_to_username(self):
174 expected = 'bogusfromlogin'
175 user = self.factory.makeUser(username=expected, open_id=False)
176 review = self.factory.makeClickPackageReview(reviewer=user)
177 self.assertEqual(review.reviewer_username(), expected)
178
160179
161class BaseClickPackageModerationTestCase(TestCaseWithFactory):180class BaseClickPackageModerationTestCase(TestCaseWithFactory):
162181
163182
=== modified file 'src/core/tests/factory.py'
--- src/core/tests/factory.py 2014-09-22 19:42:51 +0000
+++ src/core/tests/factory.py 2015-04-22 19:38:49 +0000
@@ -50,12 +50,14 @@
5050
51 # Create an openid record too.51 # Create an openid record too.
52 if open_id is None:52 if open_id is None:
53 open_id = full_claimed_id(self.getUniqueString(prefix='ident-'))53 open_id = self.getUniqueString(prefix='ident-')
54 elif open_id is False:54 elif open_id is False:
55 return user55 return user
5656
57 claimed_id = full_claimed_id(open_id)
58
57 UserOpenID.objects.create(59 UserOpenID.objects.create(
58 user=user, claimed_id=open_id, display_id=open_id)60 user=user, claimed_id=claimed_id, display_id=claimed_id)
5961
60 return user62 return user
6163
6264
=== modified file 'src/core/tests/helpers.py'
--- src/core/tests/helpers.py 2014-10-07 19:04:20 +0000
+++ src/core/tests/helpers.py 2015-04-22 19:38:49 +0000
@@ -1,3 +1,7 @@
1from operator import itemgetter
2
3from django.db import connection
4from django.test.utils import CaptureQueriesContext
1from mock import patch5from mock import patch
26
3from core.utilities import web_services7from core.utilities import web_services
@@ -27,3 +31,55 @@
27 }31 }
28 data.update(**kwargs)32 data.update(**kwargs)
29 return data33 return data
34
35
36def assert_no_extra_queries_after(modify_data, f, *args, **kwargs):
37 """Assert function performs equal query numbers after some change.
38
39 Many views perform terribly because they perform extra queries
40 for every item in some list. For example when looping over a
41 list of users to present them, if a value is accessed through
42 a foreign key then it may perform an extra query. If care
43 is not taken then the view may perform terribly when
44 operating on a large list. This is often worked around via
45 .prefetch_related() or .select_related().
46
47 This function helps in testing that this doesn't happen. The arguments
48 to this function are a callable to modify data, and a function
49 to call before and after (*args and **kwargs are passed
50 through to the latter function). Both calls to the function
51 should issue the same number of queries.
52
53 For instance
54
55 self.factory.makeUser()
56 assert_no_extra_queries_after(
57 self.factory.makeUser,
58 self.client.get, '/users'):
59
60 Will first request the view and record how many queries were
61 done. It will then run the modify function, creating another user
62 in this case, and then request the view again. If the second
63 request doesn't issue the same number of queries then an
64 AssertionError will be raised.
65 """
66 first = CaptureQueriesContext(connection)
67 with first:
68 f(*args, **kwargs)
69 modify_data()
70 second = CaptureQueriesContext(connection)
71 with second:
72 f(*args, **kwargs)
73 if len(first) != len(second):
74 message = ("Different number of queries for the "
75 "second execution. {} != {}".format(
76 len(first), len(second)))
77
78 def format_queries(qs):
79 return "\n\n".join(map(str, map(itemgetter('sql'), qs)))
80
81 message += "\nFirst queries:\n"
82 message += format_queries(first.captured_queries)
83 message += "\n\n\nSecond queries:\n"
84 message += format_queries(second.captured_queries)
85 raise AssertionError(message)
3086
=== modified file 'src/core/tests/test_utilities.py'
--- src/core/tests/test_utilities.py 2014-10-03 17:54:35 +0000
+++ src/core/tests/test_utilities.py 2015-04-22 19:38:49 +0000
@@ -376,22 +376,22 @@
376 sso_user_data = self.mock_data_for_account(376 sso_user_data = self.mock_data_for_account(
377 displayname='John Does', email='user@email.com')377 displayname='John Does', email='user@email.com')
378 self.mock_get_data.return_value = sso_user_data378 self.mock_get_data.return_value = sso_user_data
379 openid = full_claimed_id('existent')379 open_id = 'existent'
380 self.factory.makeUser(380 self.factory.makeUser(
381 first_name='John', last_name='Does', email='user@email.com',381 first_name='John', last_name='Does', email='user@email.com',
382 open_id=openid)382 open_id=open_id)
383 user, created = update_or_create_user_from_oauth('existent')383 user, created = update_or_create_user_from_oauth(open_id)
384 self.assertIsNotNone(user)384 self.assertIsNotNone(user)
385 self.assertFalse(created)385 self.assertFalse(created)
386 self.assert_user_data(user, sso_user_data)386 self.assert_user_data(user, sso_user_data)
387387
388 def test_missing_account_data_and_existing_user(self):388 def test_missing_account_data_and_existing_user(self):
389 self.mock_get_data.return_value = None389 self.mock_get_data.return_value = None
390 openid = full_claimed_id('existent')390 open_id = 'existent'
391 self.factory.makeUser(391 self.factory.makeUser(
392 first_name='John', last_name='Does', email='user@email.com',392 first_name='John', last_name='Does', email='user@email.com',
393 open_id=openid)393 open_id=open_id)
394 user, created = update_or_create_user_from_oauth('existent')394 user, created = update_or_create_user_from_oauth(open_id)
395 self.assertIsNotNone(user)395 self.assertIsNotNone(user)
396 self.assertFalse(created)396 self.assertFalse(created)
397397
@@ -399,12 +399,12 @@
399 sso_user_data = self.mock_data_for_account(399 sso_user_data = self.mock_data_for_account(
400 displayname='Juan Hace', email='juan@email.com')400 displayname='Juan Hace', email='juan@email.com')
401 self.mock_get_data.return_value = sso_user_data401 self.mock_get_data.return_value = sso_user_data
402 openid = full_claimed_id('existent')402 open_id = 'existent'
403 self.factory.makeUser(403 self.factory.makeUser(
404 first_name='John', last_name='Does', email='user@email.com',404 first_name='John', last_name='Does', email='user@email.com',
405 open_id=openid)405 open_id=open_id)
406 user, created = update_or_create_user_from_oauth(406 user, created = update_or_create_user_from_oauth(
407 'existent', update_window=None)407 open_id, update_window=None)
408 self.assertIsNotNone(user)408 self.assertIsNotNone(user)
409 self.assertFalse(created)409 self.assertFalse(created)
410 self.assert_user_data(user, sso_user_data)410 self.assert_user_data(user, sso_user_data)
@@ -413,12 +413,12 @@
413 sso_user_data = self.mock_data_for_account(413 sso_user_data = self.mock_data_for_account(
414 displayname='Juan Hace', email='juan@email.com')414 displayname='Juan Hace', email='juan@email.com')
415 self.mock_get_data.return_value = sso_user_data415 self.mock_get_data.return_value = sso_user_data
416 openid = full_claimed_id('existent')416 open_id = 'existent'
417 user = self.factory.makeUser(417 user = self.factory.makeUser(
418 first_name='John', last_name='Does', email='user@email.com',418 first_name='John', last_name='Does', email='user@email.com',
419 open_id=openid)419 open_id=open_id)
420 logged_user, created = update_or_create_user_from_oauth(420 logged_user, created = update_or_create_user_from_oauth(
421 'existent', update_window=60 * 60 * 24)421 open_id, update_window=60 * 60 * 24)
422 self.assertIsNotNone(logged_user)422 self.assertIsNotNone(logged_user)
423 self.assertFalse(created)423 self.assertFalse(created)
424 current_sso_user_data = self.mock_data_for_account(424 current_sso_user_data = self.mock_data_for_account(
@@ -429,12 +429,12 @@
429 sso_user_data = self.mock_data_for_account(429 sso_user_data = self.mock_data_for_account(
430 verified=False, displayname='Juan Hace', email='juan@email.com')430 verified=False, displayname='Juan Hace', email='juan@email.com')
431 self.mock_get_data.return_value = sso_user_data431 self.mock_get_data.return_value = sso_user_data
432 openid = full_claimed_id('existent')432 open_id = 'existent'
433 self.factory.makeUser(433 self.factory.makeUser(
434 first_name='John', last_name='Does', email='user@email.com',434 first_name='John', last_name='Does', email='user@email.com',
435 open_id=openid)435 open_id=open_id)
436 user, created = update_or_create_user_from_oauth(436 user, created = update_or_create_user_from_oauth(
437 'existent', update_window=None)437 open_id, update_window=None)
438 self.assertIsNotNone(user)438 self.assertIsNotNone(user)
439 self.assertFalse(created)439 self.assertFalse(created)
440 self.assertEqual(user.get_full_name(), 'John Does')440 self.assertEqual(user.get_full_name(), 'John Does')
@@ -444,12 +444,12 @@
444 sso_user_data = self.mock_data_for_account(444 sso_user_data = self.mock_data_for_account(
445 displayname='Juan Hace', email='')445 displayname='Juan Hace', email='')
446 self.mock_get_data.return_value = sso_user_data446 self.mock_get_data.return_value = sso_user_data
447 openid = full_claimed_id('existent')447 open_id = 'existent'
448 self.factory.makeUser(448 self.factory.makeUser(
449 first_name='John', last_name='Does', email='user@email.com',449 first_name='John', last_name='Does', email='user@email.com',
450 open_id=openid)450 open_id=open_id)
451 user, created = update_or_create_user_from_oauth(451 user, created = update_or_create_user_from_oauth(
452 'existent', update_window=None)452 open_id, update_window=None)
453 self.assertIsNotNone(user)453 self.assertIsNotNone(user)
454 self.assertFalse(created)454 self.assertFalse(created)
455 self.assertEqual(user.get_full_name(), 'John Does')455 self.assertEqual(user.get_full_name(), 'John Does')
@@ -459,12 +459,12 @@
459 sso_user_data = self.mock_data_for_account(459 sso_user_data = self.mock_data_for_account(
460 displayname=None, email='new@email.com')460 displayname=None, email='new@email.com')
461 self.mock_get_data.return_value = sso_user_data461 self.mock_get_data.return_value = sso_user_data
462 openid = full_claimed_id('existent')462 open_id = 'existent'
463 self.factory.makeUser(463 self.factory.makeUser(
464 first_name='John', last_name='Does', email='user@email.com',464 first_name='John', last_name='Does', email='user@email.com',
465 open_id=openid)465 open_id=open_id)
466 user, created = update_or_create_user_from_oauth(466 user, created = update_or_create_user_from_oauth(
467 'existent', update_window=None)467 open_id, update_window=None)
468 self.assertIsNotNone(user)468 self.assertIsNotNone(user)
469 self.assertFalse(created)469 self.assertFalse(created)
470 self.assertEqual(user.get_full_name(), 'John Does')470 self.assertEqual(user.get_full_name(), 'John Does')

Subscribers

People subscribed via source and target branches