diff --git a/.travis.yml b/.travis.yml index c7628a2..5152e3c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ env: install: - pip install -q Django==$DJANGO --use-mirrors - pip install coveralls - - pip install -r test_requirements.pip + - pip install -r rest_auth/tests/requirements.pip script: - coverage run --source=rest_auth setup.py test after_success: diff --git a/rest_auth/tests/__init__.py b/rest_auth/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rest_auth/django_test_urls.py b/rest_auth/tests/django_urls.py similarity index 100% rename from rest_auth/django_test_urls.py rename to rest_auth/tests/django_urls.py diff --git a/test_requirements.pip b/rest_auth/tests/requirements.pip similarity index 100% rename from test_requirements.pip rename to rest_auth/tests/requirements.pip diff --git a/test_settings.py b/rest_auth/tests/settings.py similarity index 99% rename from test_settings.py rename to rest_auth/tests/settings.py index d90d71c..5c7a940 100644 --- a/test_settings.py +++ b/rest_auth/tests/settings.py @@ -2,6 +2,7 @@ import os import sys PROJECT_ROOT = os.path.abspath(os.path.split(os.path.split(__file__)[0])[0]) + ROOT_URLCONF = 'urls' STATIC_URL = '/static/' STATIC_ROOT = '%s/staticserve' % PROJECT_ROOT diff --git a/rest_auth/tests.py b/rest_auth/tests/test_api.py similarity index 56% rename from rest_auth/tests.py rename to rest_auth/tests/test_api.py index 4e5a1c2..7adcf71 100644 --- a/rest_auth/tests.py +++ b/rest_auth/tests/test_api.py @@ -1,123 +1,13 @@ -import json - -from django.conf import settings from django.core.urlresolvers import reverse -from django.test.client import Client, MULTIPART_CONTENT from django.test import TestCase from django.contrib.auth import get_user_model from django.core import mail from django.test.utils import override_settings -from django.contrib.sites.models import Site from django.utils.encoding import force_text -from allauth.socialaccount.models import SocialApp -from allauth.socialaccount.providers.facebook.provider import GRAPH_API_URL -import responses - from rest_framework import status - -class APIClient(Client): - - def patch(self, path, data='', content_type=MULTIPART_CONTENT, follow=False, **extra): - return self.generic('PATCH', path, data, content_type, **extra) - - def options(self, path, data='', content_type=MULTIPART_CONTENT, follow=False, **extra): - return self.generic('OPTIONS', path, data, content_type, **extra) - - -class BaseAPITestCase(object): - - """ - base for API tests: - * easy request calls, f.e.: self.post(url, data), self.get(url) - * easy status check, f.e.: self.post(url, data, status_code=200) - """ - def send_request(self, request_method, *args, **kwargs): - request_func = getattr(self.client, request_method) - status_code = None - if 'content_type' not in kwargs and request_method != 'get': - kwargs['content_type'] = 'application/json' - if 'data' in kwargs and request_method != 'get' and kwargs['content_type'] == 'application/json': - data = kwargs.get('data', '') - kwargs['data'] = json.dumps(data) # , cls=CustomJSONEncoder - if 'status_code' in kwargs: - status_code = kwargs.pop('status_code') - - # check_headers = kwargs.pop('check_headers', True) - if hasattr(self, 'token'): - kwargs['HTTP_AUTHORIZATION'] = 'Token %s' % self.token - - self.response = request_func(*args, **kwargs) - is_json = bool( - [x for x in self.response._headers['content-type'] if 'json' in x]) - if is_json and self.response.content: - self.response.json = json.loads(force_text(self.response.content)) - else: - self.response.json = {} - if status_code: - self.assertEqual(self.response.status_code, status_code) - return self.response - - def post(self, *args, **kwargs): - return self.send_request('post', *args, **kwargs) - - def get(self, *args, **kwargs): - return self.send_request('get', *args, **kwargs) - - def patch(self, *args, **kwargs): - return self.send_request('patch', *args, **kwargs) - - # def put(self, *args, **kwargs): - # return self.send_request('put', *args, **kwargs) - - # def delete(self, *args, **kwargs): - # return self.send_request('delete', *args, **kwargs) - - # def options(self, *args, **kwargs): - # return self.send_request('options', *args, **kwargs) - - # def post_file(self, *args, **kwargs): - # kwargs['content_type'] = MULTIPART_CONTENT - # return self.send_request('post', *args, **kwargs) - - # def get_file(self, *args, **kwargs): - # content_type = None - # if 'content_type' in kwargs: - # content_type = kwargs.pop('content_type') - # response = self.send_request('get', *args, **kwargs) - # if content_type: - # self.assertEqual( - # bool(filter(lambda x: content_type in x, response._headers['content-type'])), True) - # return response - - def init(self): - settings.DEBUG = True - self.client = APIClient() - - self.login_url = reverse('rest_login') - self.logout_url = reverse('rest_logout') - self.password_change_url = reverse('rest_password_change') - self.register_url = reverse('rest_register') - self.password_reset_url = reverse('rest_password_reset') - self.user_url = reverse('rest_user_details') - self.veirfy_email_url = reverse('rest_verify_email') - self.fb_login_url = reverse('fb_login') - - def _login(self): - payload = { - "username": self.USERNAME, - "password": self.PASS - } - self.post(self.login_url, data=payload, status_code=status.HTTP_200_OK) - - def _logout(self): - self.post(self.logout_url, status=status.HTTP_200_OK) - - -# ----------------------- -# T E S T H E R E -# ----------------------- +from .test_base import BaseAPITestCase class APITestCase1(TestCase, BaseAPITestCase): @@ -127,7 +17,7 @@ class APITestCase1(TestCase, BaseAPITestCase): - custom registration: backend defined """ - urls = 'rest_auth.test_urls' + urls = 'tests.urls' USERNAME = 'person' PASS = 'person' @@ -421,119 +311,3 @@ class APITestCase1(TestCase, BaseAPITestCase): # try to login again self._login() self._logout() - - -class TestSocialAuth(TestCase, BaseAPITestCase): - - urls = 'rest_auth.test_urls' - - USERNAME = 'person' - PASS = 'person' - EMAIL = "person1@world.com" - REGISTRATION_DATA = { - "username": USERNAME, - "password1": PASS, - "password2": PASS, - "email": EMAIL - } - - def setUp(self): - self.init() - - social_app = SocialApp.objects.create( - provider='facebook', - name='Facebook', - client_id='123123123', - secret='321321321', - ) - site = Site.objects.get_current() - social_app.sites.add(site) - self.graph_api_url = GRAPH_API_URL + '/me' - - @responses.activate - def test_failed_social_auth(self): - # fake response - responses.add( - responses.GET, - self.graph_api_url, - body='', - status=400, - content_type='application/json' - ) - - payload = { - 'access_token': 'abc123' - } - self.post(self.fb_login_url, data=payload, status_code=400) - - @responses.activate - def test_social_auth(self): - # fake response for facebook call - 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 - responses.add( - responses.GET, - self.graph_api_url, - body=resp_body, - status=200, - content_type='application/json' - ) - - users_count = get_user_model().objects.all().count() - payload = { - 'access_token': 'abc123' - } - - self.post(self.fb_login_url, data=payload, status_code=200) - self.assertIn('key', self.response.json.keys()) - self.assertEqual(get_user_model().objects.all().count(), users_count + 1) - - # make sure that second request will not create a new user - self.post(self.fb_login_url, data=payload, status_code=200) - self.assertIn('key', self.response.json.keys()) - self.assertEqual(get_user_model().objects.all().count(), users_count + 1) - - @responses.activate - @override_settings( - ACCOUNT_EMAIL_VERIFICATION='mandatory', - ACCOUNT_EMAIL_REQUIRED=True, - REST_SESSION_LOGIN=False - ) - def test_edge_case(self): - 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 - responses.add( - responses.GET, - self.graph_api_url, - body=resp_body % self.EMAIL, - status=200, - content_type='application/json' - ) - - # test empty payload - self.post(self.register_url, data={}, status_code=400) - - self.post( - self.register_url, - data=self.REGISTRATION_DATA, - status_code=201 - ) - new_user = get_user_model().objects.latest('id') - self.assertEqual(new_user.username, self.REGISTRATION_DATA['username']) - - # verify email - email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL)\ - .emailconfirmation_set.order_by('-created')[0] - self.post( - self.veirfy_email_url, - data={"key": email_confirmation.key}, - status_code=status.HTTP_200_OK - ) - - self._login() - self._logout() - - payload = { - 'access_token': 'abc123' - } - - self.post(self.fb_login_url, data=payload, status_code=200) - self.assertIn('key', self.response.json.keys()) diff --git a/rest_auth/tests/test_base.py b/rest_auth/tests/test_base.py new file mode 100644 index 0000000..ed8ffeb --- /dev/null +++ b/rest_auth/tests/test_base.py @@ -0,0 +1,106 @@ +import json + +from django.conf import settings +from django.core.urlresolvers import reverse +from django.test.client import Client, MULTIPART_CONTENT +from django.utils.encoding import force_text + +from rest_framework import status + + +class APIClient(Client): + + def patch(self, path, data='', content_type=MULTIPART_CONTENT, follow=False, **extra): + return self.generic('PATCH', path, data, content_type, **extra) + + def options(self, path, data='', content_type=MULTIPART_CONTENT, follow=False, **extra): + return self.generic('OPTIONS', path, data, content_type, **extra) + + +class BaseAPITestCase(object): + + """ + base for API tests: + * easy request calls, f.e.: self.post(url, data), self.get(url) + * easy status check, f.e.: self.post(url, data, status_code=200) + """ + def send_request(self, request_method, *args, **kwargs): + request_func = getattr(self.client, request_method) + status_code = None + if 'content_type' not in kwargs and request_method != 'get': + kwargs['content_type'] = 'application/json' + if 'data' in kwargs and request_method != 'get' and kwargs['content_type'] == 'application/json': + data = kwargs.get('data', '') + kwargs['data'] = json.dumps(data) # , cls=CustomJSONEncoder + if 'status_code' in kwargs: + status_code = kwargs.pop('status_code') + + # check_headers = kwargs.pop('check_headers', True) + if hasattr(self, 'token'): + kwargs['HTTP_AUTHORIZATION'] = 'Token %s' % self.token + + self.response = request_func(*args, **kwargs) + is_json = bool( + [x for x in self.response._headers['content-type'] if 'json' in x]) + if is_json and self.response.content: + self.response.json = json.loads(force_text(self.response.content)) + else: + self.response.json = {} + if status_code: + self.assertEqual(self.response.status_code, status_code) + return self.response + + def post(self, *args, **kwargs): + return self.send_request('post', *args, **kwargs) + + def get(self, *args, **kwargs): + return self.send_request('get', *args, **kwargs) + + def patch(self, *args, **kwargs): + return self.send_request('patch', *args, **kwargs) + + # def put(self, *args, **kwargs): + # return self.send_request('put', *args, **kwargs) + + # def delete(self, *args, **kwargs): + # return self.send_request('delete', *args, **kwargs) + + # def options(self, *args, **kwargs): + # return self.send_request('options', *args, **kwargs) + + # def post_file(self, *args, **kwargs): + # kwargs['content_type'] = MULTIPART_CONTENT + # return self.send_request('post', *args, **kwargs) + + # def get_file(self, *args, **kwargs): + # content_type = None + # if 'content_type' in kwargs: + # content_type = kwargs.pop('content_type') + # response = self.send_request('get', *args, **kwargs) + # if content_type: + # self.assertEqual( + # bool(filter(lambda x: content_type in x, response._headers['content-type'])), True) + # return response + + def init(self): + settings.DEBUG = True + self.client = APIClient() + + self.login_url = reverse('rest_login') + self.logout_url = reverse('rest_logout') + self.password_change_url = reverse('rest_password_change') + self.register_url = reverse('rest_register') + self.password_reset_url = reverse('rest_password_reset') + self.user_url = reverse('rest_user_details') + self.veirfy_email_url = reverse('rest_verify_email') + self.fb_login_url = reverse('fb_login') + + def _login(self): + payload = { + "username": self.USERNAME, + "password": self.PASS + } + self.post(self.login_url, data=payload, status_code=status.HTTP_200_OK) + + def _logout(self): + self.post(self.logout_url, status=status.HTTP_200_OK) diff --git a/rest_auth/tests/test_social.py b/rest_auth/tests/test_social.py new file mode 100644 index 0000000..0bb10f5 --- /dev/null +++ b/rest_auth/tests/test_social.py @@ -0,0 +1,128 @@ +from django.test import TestCase +from django.contrib.auth import get_user_model +from django.test.utils import override_settings +from django.contrib.sites.models import Site + +from allauth.socialaccount.models import SocialApp +from allauth.socialaccount.providers.facebook.provider import GRAPH_API_URL +import responses + +from rest_framework import status + +from .test_base import BaseAPITestCase + + +class TestSocialAuth(TestCase, BaseAPITestCase): + + urls = 'tests.urls' + + USERNAME = 'person' + PASS = 'person' + EMAIL = "person1@world.com" + REGISTRATION_DATA = { + "username": USERNAME, + "password1": PASS, + "password2": PASS, + "email": EMAIL + } + + def setUp(self): + self.init() + + social_app = SocialApp.objects.create( + provider='facebook', + name='Facebook', + client_id='123123123', + secret='321321321', + ) + site = Site.objects.get_current() + social_app.sites.add(site) + self.graph_api_url = GRAPH_API_URL + '/me' + + @responses.activate + def test_failed_social_auth(self): + # fake response + responses.add( + responses.GET, + self.graph_api_url, + body='', + status=400, + content_type='application/json' + ) + + payload = { + 'access_token': 'abc123' + } + self.post(self.fb_login_url, data=payload, status_code=400) + + @responses.activate + def test_social_auth(self): + # fake response for facebook call + 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 + responses.add( + responses.GET, + self.graph_api_url, + body=resp_body, + status=200, + content_type='application/json' + ) + + users_count = get_user_model().objects.all().count() + payload = { + 'access_token': 'abc123' + } + + self.post(self.fb_login_url, data=payload, status_code=200) + self.assertIn('key', self.response.json.keys()) + self.assertEqual(get_user_model().objects.all().count(), users_count + 1) + + # make sure that second request will not create a new user + self.post(self.fb_login_url, data=payload, status_code=200) + self.assertIn('key', self.response.json.keys()) + self.assertEqual(get_user_model().objects.all().count(), users_count + 1) + + @responses.activate + @override_settings( + ACCOUNT_EMAIL_VERIFICATION='mandatory', + ACCOUNT_EMAIL_REQUIRED=True, + REST_SESSION_LOGIN=False + ) + def test_edge_case(self): + 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 + responses.add( + responses.GET, + self.graph_api_url, + body=resp_body % self.EMAIL, + status=200, + content_type='application/json' + ) + + # test empty payload + self.post(self.register_url, data={}, status_code=400) + + self.post( + self.register_url, + data=self.REGISTRATION_DATA, + status_code=201 + ) + new_user = get_user_model().objects.latest('id') + self.assertEqual(new_user.username, self.REGISTRATION_DATA['username']) + + # verify email + email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL)\ + .emailconfirmation_set.order_by('-created')[0] + self.post( + self.veirfy_email_url, + data={"key": email_confirmation.key}, + status_code=status.HTTP_200_OK + ) + + self._login() + self._logout() + + payload = { + 'access_token': 'abc123' + } + + self.post(self.fb_login_url, data=payload, status_code=200) + self.assertIn('key', self.response.json.keys()) diff --git a/rest_auth/test_urls.py b/rest_auth/tests/urls.py similarity index 89% rename from rest_auth/test_urls.py rename to rest_auth/tests/urls.py index ae5ef1d..b80541c 100644 --- a/rest_auth/test_urls.py +++ b/rest_auth/tests/urls.py @@ -1,6 +1,6 @@ from django.conf.urls import patterns, url, include from django.views.generic import TemplateView -import rest_auth.django_test_urls +from . import django_urls from allauth.socialaccount.providers.facebook.views import FacebookOAuth2Adapter @@ -14,7 +14,7 @@ class FacebookLogin(SocialLoginView): urlpatterns += patterns( '', url(r'^rest-registration/', include('rest_auth.registration.urls')), - url(r'^test-admin/', include(rest_auth.django_test_urls)), + url(r'^test-admin/', include(django_urls)), url(r'^account-email-verification-sent/$', TemplateView.as_view(), name='account_email_verification_sent'), url(r'^account-confirm-email/(?P\w+)/$', TemplateView.as_view(), diff --git a/runtests.py b/runtests.py index a59b2bb..8b7ede2 100644 --- a/runtests.py +++ b/runtests.py @@ -3,8 +3,8 @@ import os import sys -os.environ['DJANGO_SETTINGS_MODULE'] = 'test_settings' -test_dir = os.path.dirname(__file__) +os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings' +test_dir = os.path.join(os.path.dirname(__file__), 'rest_auth') sys.path.insert(0, test_dir) import django