Skip to content

Commit c5e0382

Browse files
authored
Increased test coverage (#229)
* Added twitter login test * pep8 * Fixes missing backend attr issue * Refactored login process * pep8 * Added more tests for twitter social login
1 parent 976b3bb commit c5e0382

File tree

7 files changed

+208
-13
lines changed

7 files changed

+208
-13
lines changed

rest_auth/registration/views.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from rest_framework.generics import CreateAPIView
88
from rest_framework import status
99

10+
from allauth.account.adapter import get_adapter
1011
from allauth.account.views import ConfirmEmailView
1112
from allauth.account.utils import complete_signup
1213
from allauth.account import app_settings as allauth_settings
@@ -101,3 +102,6 @@ class FacebookLogin(SocialLoginView):
101102
"""
102103

103104
serializer_class = SocialLoginSerializer
105+
106+
def process_login(self):
107+
get_adapter(self.request).login(self.request, self.user)

rest_auth/social_serializers.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,11 @@ def validate(self, attrs):
4646
if not adapter_class:
4747
raise serializers.ValidationError('Define adapter_class in view')
4848

49-
adapter = adapter_class()
49+
adapter = adapter_class(request)
5050
app = adapter.get_provider().get_app(request)
5151

52-
if('access_token' in attrs) and ('token_secret' in attrs):
53-
access_token = attrs.get('access_token')
54-
token_secret = attrs.get('token_secret')
55-
else:
56-
raise serializers.ValidationError('Incorrect input. access_token and token_secret are required.')
52+
access_token = attrs.get('access_token')
53+
token_secret = attrs.get('token_secret')
5754

5855
request.session['oauth_api.twitter.com_access_token'] = {
5956
'oauth_token': access_token,

rest_auth/tests/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
'allauth.account',
8181
'allauth.socialaccount',
8282
'allauth.socialaccount.providers.facebook',
83+
'allauth.socialaccount.providers.twitter',
8384

8485
'rest_framework',
8586
'rest_framework.authtoken',

rest_auth/tests/test_base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ def init(self):
9999
self.user_url = reverse('rest_user_details')
100100
self.veirfy_email_url = reverse('rest_verify_email')
101101
self.fb_login_url = reverse('fb_login')
102+
self.tw_login_url = reverse('tw_login')
103+
self.tw_login_no_view_url = reverse('tw_login_no_view')
104+
self.tw_login_no_adapter_url = reverse('tw_login_no_adapter')
102105

103106
def _login(self):
104107
payload = {

rest_auth/tests/test_social.py

Lines changed: 156 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import json
2+
13
from django.test import TestCase
24
from django.contrib.auth import get_user_model
35
from django.test.utils import override_settings
@@ -34,9 +36,19 @@ def setUp(self):
3436
client_id='123123123',
3537
secret='321321321',
3638
)
39+
40+
twitter_social_app = SocialApp.objects.create(
41+
provider='twitter',
42+
name='Twitter',
43+
client_id='11223344',
44+
secret='55667788',
45+
)
46+
3747
site = Site.objects.get_current()
3848
social_app.sites.add(site)
49+
twitter_social_app.sites.add(site)
3950
self.graph_api_url = GRAPH_API_URL + '/me'
51+
self.twitter_url = 'http://twitter.com/foobarme'
4052

4153
@responses.activate
4254
def test_failed_social_auth(self):
@@ -57,11 +69,24 @@ def test_failed_social_auth(self):
5769
@responses.activate
5870
def test_social_auth(self):
5971
# fake response for facebook call
60-
resp_body = '{"id":"123123123123","first_name":"John","gender":"male","last_name":"Smith","link":"https:\\/\\/www.facebook.com\\/john.smith","locale":"en_US","name":"John Smith","timezone":2,"updated_time":"2014-08-13T10:14:38+0000","username":"john.smith","verified":true}' # noqa
72+
resp_body = {
73+
"id": "123123123123",
74+
"first_name": "John",
75+
"gender": "male",
76+
"last_name": "Smith",
77+
"link": "https://www.facebook.com/john.smith",
78+
"locale": "en_US",
79+
"name": "John Smith",
80+
"timezone": 2,
81+
"updated_time": "2014-08-13T10:14:38+0000",
82+
"username": "john.smith",
83+
"verified": True
84+
}
85+
6186
responses.add(
6287
responses.GET,
6388
self.graph_api_url,
64-
body=resp_body,
89+
body=json.dumps(resp_body),
6590
status=200,
6691
content_type='application/json'
6792
)
@@ -80,18 +105,145 @@ def test_social_auth(self):
80105
self.assertIn('key', self.response.json.keys())
81106
self.assertEqual(get_user_model().objects.all().count(), users_count + 1)
82107

108+
def _twitter_social_auth(self):
109+
# fake response for twitter call
110+
resp_body = {
111+
"id": "123123123123",
112+
}
113+
114+
responses.add(
115+
responses.GET,
116+
'https://api.twitter.com/1.1/account/verify_credentials.json',
117+
body=json.dumps(resp_body),
118+
status=200,
119+
content_type='application/json'
120+
)
121+
122+
users_count = get_user_model().objects.all().count()
123+
payload = {
124+
'access_token': 'abc123',
125+
'token_secret': '1111222233334444'
126+
}
127+
128+
self.post(self.tw_login_url, data=payload)
129+
130+
self.assertIn('key', self.response.json.keys())
131+
self.assertEqual(get_user_model().objects.all().count(), users_count + 1)
132+
133+
# make sure that second request will not create a new user
134+
self.post(self.tw_login_url, data=payload, status_code=200)
135+
self.assertIn('key', self.response.json.keys())
136+
self.assertEqual(get_user_model().objects.all().count(), users_count + 1)
137+
138+
@responses.activate
139+
@override_settings(SOCIALACCOUNT_AUTO_SIGNUP=True)
140+
def test_twitter_social_auth(self):
141+
self._twitter_social_auth()
142+
143+
@responses.activate
144+
@override_settings(SOCIALACCOUNT_AUTO_SIGNUP=False)
145+
def test_twitter_social_auth_without_auto_singup(self):
146+
self._twitter_social_auth()
147+
148+
@responses.activate
149+
def test_twitter_social_auth_request_error(self):
150+
# fake response for twitter call
151+
resp_body = {
152+
"id": "123123123123",
153+
}
154+
155+
responses.add(
156+
responses.GET,
157+
'https://api.twitter.com/1.1/account/verify_credentials.json',
158+
body=json.dumps(resp_body),
159+
status=400,
160+
content_type='application/json'
161+
)
162+
163+
users_count = get_user_model().objects.all().count()
164+
payload = {
165+
'access_token': 'abc123',
166+
'token_secret': '1111222233334444'
167+
}
168+
169+
self.post(self.tw_login_url, data=payload, status_code=400)
170+
self.assertNotIn('key', self.response.json.keys())
171+
self.assertEqual(get_user_model().objects.all().count(), users_count)
172+
173+
@responses.activate
174+
def test_twitter_social_auth_no_view_in_context(self):
175+
# fake response for twitter call
176+
resp_body = {
177+
"id": "123123123123",
178+
}
179+
180+
responses.add(
181+
responses.GET,
182+
'https://api.twitter.com/1.1/account/verify_credentials.json',
183+
body=json.dumps(resp_body),
184+
status=400,
185+
content_type='application/json'
186+
)
187+
188+
users_count = get_user_model().objects.all().count()
189+
payload = {
190+
'access_token': 'abc123',
191+
'token_secret': '1111222233334444'
192+
}
193+
194+
self.post(self.tw_login_no_view_url, data=payload, status_code=400)
195+
self.assertEqual(get_user_model().objects.all().count(), users_count)
196+
197+
@responses.activate
198+
def test_twitter_social_auth_no_adapter(self):
199+
# fake response for twitter call
200+
resp_body = {
201+
"id": "123123123123",
202+
}
203+
204+
responses.add(
205+
responses.GET,
206+
'https://api.twitter.com/1.1/account/verify_credentials.json',
207+
body=json.dumps(resp_body),
208+
status=400,
209+
content_type='application/json'
210+
)
211+
212+
users_count = get_user_model().objects.all().count()
213+
payload = {
214+
'access_token': 'abc123',
215+
'token_secret': '1111222233334444'
216+
}
217+
218+
self.post(self.tw_login_no_adapter_url, data=payload, status_code=400)
219+
self.assertEqual(get_user_model().objects.all().count(), users_count)
220+
83221
@responses.activate
84222
@override_settings(
85223
ACCOUNT_EMAIL_VERIFICATION='mandatory',
86224
ACCOUNT_EMAIL_REQUIRED=True,
87225
REST_SESSION_LOGIN=False
88226
)
89227
def test_edge_case(self):
90-
resp_body = '{"id":"123123123123","first_name":"John","gender":"male","last_name":"Smith","link":"https:\\/\\/www.facebook.com\\/john.smith","locale":"en_US","name":"John Smith","timezone":2,"updated_time":"2014-08-13T10:14:38+0000","username":"john.smith","verified":true,"email":"%s"}' # noqa
228+
resp_body = {
229+
"id": "123123123123",
230+
"first_name": "John",
231+
"gender": "male",
232+
"last_name": "Smith",
233+
"link": "https://www.facebook.com/john.smith",
234+
"locale": "en_US",
235+
"name": "John Smith",
236+
"timezone": 2,
237+
"updated_time": "2014-08-13T10:14:38+0000",
238+
"username": "john.smith",
239+
"verified": True,
240+
"email": self.EMAIL
241+
}
242+
91243
responses.add(
92244
responses.GET,
93245
self.graph_api_url,
94-
body=resp_body % self.EMAIL,
246+
body=json.dumps(resp_body),
95247
status=200,
96248
content_type='application/json'
97249
)

rest_auth/tests/urls.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,41 @@
33
from . import django_urls
44

55
from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter
6+
from allauth.socialaccount.providers.twitter.views import TwitterOAuthAdapter
7+
8+
from rest_framework.decorators import api_view
69

710
from rest_auth.urls import urlpatterns
811
from rest_auth.registration.views import SocialLoginView
12+
from rest_auth.social_serializers import TwitterLoginSerializer
913

1014

1115
class FacebookLogin(SocialLoginView):
1216
adapter_class = FacebookOAuth2Adapter
1317

18+
19+
class TwitterLogin(SocialLoginView):
20+
adapter_class = TwitterOAuthAdapter
21+
serializer_class = TwitterLoginSerializer
22+
23+
24+
class TwitterLoginSerializerFoo(TwitterLoginSerializer):
25+
pass
26+
27+
28+
@api_view(['POST'])
29+
def twitter_login_view(request):
30+
serializer = TwitterLoginSerializerFoo(
31+
data={'access_token': '11223344', 'token_secret': '55667788'},
32+
context={'request': request}
33+
)
34+
serializer.is_valid(raise_exception=True)
35+
36+
37+
class TwitterLoginNoAdapter(SocialLoginView):
38+
serializer_class = TwitterLoginSerializer
39+
40+
1441
urlpatterns += [
1542
url(r'^rest-registration/', include('rest_auth.registration.urls')),
1643
url(r'^test-admin/', include(django_urls)),
@@ -19,5 +46,8 @@ class FacebookLogin(SocialLoginView):
1946
url(r'^account-confirm-email/(?P<key>\w+)/$', TemplateView.as_view(),
2047
name='account_confirm_email'),
2148
url(r'^social-login/facebook/$', FacebookLogin.as_view(), name='fb_login'),
49+
url(r'^social-login/twitter/$', TwitterLogin.as_view(), name='tw_login'),
50+
url(r'^social-login/twitter-no-view/$', twitter_login_view, name='tw_login_no_view'),
51+
url(r'^social-login/twitter-no-adapter/$', TwitterLoginNoAdapter.as_view(), name='tw_login_no_adapter'),
2252
url(r'^accounts/', include('allauth.socialaccount.urls'))
2353
]

rest_auth/views.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
from django.contrib.auth import login, logout
1+
from django.contrib.auth import (
2+
login as django_login,
3+
logout as django_logout
4+
)
25
from django.conf import settings
36
from django.core.exceptions import ObjectDoesNotExist
47
from django.utils.translation import ugettext_lazy as _
@@ -37,6 +40,9 @@ class LoginView(GenericAPIView):
3740
serializer_class = LoginSerializer
3841
token_model = TokenModel
3942

43+
def process_login(self):
44+
django_login(self.request, self.user)
45+
4046
def get_response_serializer(self):
4147
if getattr(settings, 'REST_USE_JWT', False):
4248
response_serializer = JWTSerializer
@@ -53,7 +59,7 @@ def login(self):
5359
self.token = create_token(self.token_model, self.user, self.serializer)
5460

5561
if getattr(settings, 'REST_SESSION_LOGIN', True):
56-
login(self.request, self.user)
62+
self.process_login()
5763

5864
def get_response(self):
5965
serializer_class = self.get_response_serializer()
@@ -70,8 +76,10 @@ def get_response(self):
7076
return Response(serializer.data, status=status.HTTP_200_OK)
7177

7278
def post(self, request, *args, **kwargs):
79+
self.request = request
7380
self.serializer = self.get_serializer(data=self.request.data)
7481
self.serializer.is_valid(raise_exception=True)
82+
7583
self.login()
7684
return self.get_response()
7785

@@ -106,7 +114,7 @@ def logout(self, request):
106114
except (AttributeError, ObjectDoesNotExist):
107115
pass
108116

109-
logout(request)
117+
django_logout(request)
110118

111119
return Response({"success": _("Successfully logged out.")},
112120
status=status.HTTP_200_OK)

0 commit comments

Comments
 (0)