]> git.parisson.com Git - django-social-auth.git/commitdiff
Initial testing suite. Only twitter so far, more to come soon. Refs gh-25
authorMatías Aguirre <matiasaguirre@gmail.com>
Sun, 27 Feb 2011 16:24:34 +0000 (14:24 -0200)
committerMatías Aguirre <matiasaguirre@gmail.com>
Sun, 27 Feb 2011 16:24:34 +0000 (14:24 -0200)
social_auth/tests/__init__.py [new file with mode: 0644]
social_auth/tests/base.py [new file with mode: 0644]
social_auth/tests/twitter.py [new file with mode: 0644]

diff --git a/social_auth/tests/__init__.py b/social_auth/tests/__init__.py
new file mode 100644 (file)
index 0000000..196a8ca
--- /dev/null
@@ -0,0 +1 @@
+from social_auth.tests.twitter import *
diff --git a/social_auth/tests/base.py b/social_auth/tests/base.py
new file mode 100644 (file)
index 0000000..3bd40a6
--- /dev/null
@@ -0,0 +1,83 @@
+import urllib
+import urlparse
+import unittest
+from sgmllib import SGMLParser
+
+from django.test.client import Client
+from django.core.urlresolvers import reverse
+
+
+class SocialAuthTestsCase(unittest.TestCase):
+    """Base class for social auth tests"""
+    def __init__(self, *args, **kwargs):
+        self.client = Client()
+        super(SocialAuthTestsCase, self).__init__(*args, **kwargs)
+
+    def get_content(self, url, data=None):
+        """Return content for given url, if data is not None, then a POST
+        request will be issued, otherwise GET will be used"""
+        data = data and urllib.urlencode(data) or data
+        return ''.join(urllib.urlopen(url, data=data).readlines())
+
+    def reverse(self, name, backend):
+        """Reverses backend URL by name"""
+        return reverse(name, args=(backend,))
+
+    def make_relative(self, value):
+        """Converst URL to relative, useful for server responses"""
+        parsed = urlparse.urlparse(value)
+        return urlparse.urlunparse(('', '', parsed.path, parsed.params,
+                                    parsed.query, parsed.fragment))
+
+
+class CustomParser(SGMLParser):
+    """Custom SGMLParser that closes the parser once it's fed"""
+    def feed(self, data):
+        SGMLParser.feed(self, data)
+        self.close()
+
+
+class FormParser(CustomParser):
+    """Form parser, load form data and action for given form identified
+    by its id"""
+    def __init__(self, form_id, *args, **kwargs):
+        CustomParser.__init__(self, *args, **kwargs)
+        self.form_id = form_id
+        self.inside_form = False
+        self.action = None
+        self.values = {}
+
+    def start_form(self, attributes):
+        """Start form parsing detecting if form is the one requested"""
+        attrs = dict(attributes)
+        if attrs.get('id') == self.form_id:
+            # flag that we are inside the form and save action
+            self.inside_form = True 
+            self.action = attrs.get('action')
+
+    def end_form(self):
+        """End form parsing, unset inside_form flag"""
+        self.inside_form = False
+
+    def start_input(self, attributes):
+        """Parse input fields, we only keep data for fields of type text,
+        hidden or password and that has a valid name."""
+        attrs = dict(attributes)
+        if self.inside_form:
+            type, name, value = attrs.get('type'), attrs.get('name'), \
+                                attrs.get('value')
+            if name and type in ('text', 'hidden', 'password'):
+                self.values[name] = value
+
+
+class RefreshParser(CustomParser):
+    """Refresh parser, will check refresh by meta tag and store refresh URL"""
+    def __init__(self, *args, **kwargs):
+        CustomParser.__init__(self, *args, **kwargs)
+        self.value = None
+
+    def start_meta(self, attributes):
+        """Start meta parsing checking by http-equiv attribute"""
+        attrs = dict(attributes)
+        if attrs.get('http-equiv') == 'refresh':
+            self.value = attrs.get('content').lstrip('0;url=')
diff --git a/social_auth/tests/twitter.py b/social_auth/tests/twitter.py
new file mode 100644 (file)
index 0000000..5e8986f
--- /dev/null
@@ -0,0 +1,131 @@
+import urllib
+import urlparse
+import unittest
+from sgmllib import SGMLParser
+
+from django.conf import settings
+from django.test.client import Client
+from django.core.urlresolvers import reverse
+
+from social_auth.backends.twitter import TwitterAuth
+
+
+SERVER_NAME = 'myapp.com'
+SERVER_PORT = '8000'
+USER   = 'social_auth'
+PASSWD = 'pass(twitter).7'
+
+
+class SocialAuthTestsCase(unittest.TestCase):
+    def __init__(self, *args, **kwargs):
+        self.client = Client()
+        super(SocialAuthTestsCase, self).__init__(*args, **kwargs)
+
+    def get_content(self, url, data=None):
+        """Open URL and return content"""
+        data = data and urllib.urlencode(data) or data
+        return ''.join(urllib.urlopen(url, data=data).readlines())
+
+    def reverse(self, name, backend):
+        return reverse(name, args=(backend,))
+
+    def make_relative(self, value):
+        parsed = urlparse.urlparse(value)
+        return urlparse.urlunparse(('', '', parsed.path, parsed.params,
+                                    parsed.query, parsed.fragment))
+
+
+class TwitterTestCase(SocialAuthTestsCase):
+    def testLogin(self):
+        response = self.client.get(self.reverse('begin', 'twitter'))
+        # social_auth must redirect to service page
+        self.assertEqual(response.status_code, 302)
+
+        # Open first redirect page, it contains user login form because
+        # we don't have cookie to send to twitter
+        login_content = self.get_content(response['Location'])
+        parser = FormParser('login_form')
+        parser.feed(login_content)
+        auth = {'session[username_or_email]': USER,
+                'session[password]': PASSWD}
+
+        # Check that action and values were loaded properly
+        self.assertTrue(parser.action)
+        self.assertTrue(parser.values)
+
+        # Post login form, will return authorization or redirect page
+        parser.values.update(auth)
+        content = self.get_content(parser.action, data=parser.values)
+
+        # If page contains a form#login_form, then we are in the app
+        # authorization page because the app is not authorized yet,
+        # otherwise the app already gained permission and twitter sends
+        # a page that redirects to redirect_url
+        if 'login_form' in content:
+            # authorization form post, returns redirect_page
+            parser = FormParser('login_form').feed(content)
+            self.assertTrue(parser.action)
+            self.assertTrue(parser.values)
+            parser.values.update(auth)
+            redirect_page = self.get_content(parser.action, data=parser.values)
+        else:
+            redirect_page = content
+
+        parser = RefreshParser()
+        parser.feed(redirect_page)
+        self.assertTrue(parser.value)
+
+        response = self.client.get(self.make_relative(parser.value))
+        self.assertEqual(response.status_code, 302)
+        location = self.make_relative(response['Location'])
+        login_redirect = getattr(settings, 'LOGIN_REDIRECT_URL', '')
+        self.assertTrue(location == login_redirect)
+
+    def runTest(self):
+        # don't run tests if it's not enabled
+        if TwitterAuth.enabled:
+            self.testLogin()
+
+
+class TwitterParser(SGMLParser):
+    def feed(self, data):
+        SGMLParser.feed(self, data)
+        self.close()
+        return self
+
+
+class FormParser(TwitterParser):
+    def __init__(self, form_id, *args, **kwargs):
+        TwitterParser.__init__(self, *args, **kwargs)
+        self.form_id = form_id
+        self.inside_form = False
+        self.action = None
+        self.values = {}
+
+    def start_form(self, attributes):
+        attrs = dict(attributes)
+        if attrs.get('id') == self.form_id:
+            self.inside_form = True
+            self.action = attrs.get('action')
+
+    def end_form(self):
+        self.inside_form = False
+
+    def start_input(self, attributes):
+        attrs = dict(attributes)
+        if self.inside_form:
+            type, name, value = attrs.get('type'), attrs.get('name'), \
+                                attrs.get('value')
+            if name and value and type in ('text', 'hidden', 'password'):
+                self.values[name] = value
+
+
+class RefreshParser(TwitterParser):
+    def __init__(self, *args, **kwargs):
+        TwitterParser.__init__(self, *args, **kwargs)
+        self.value = None
+
+    def start_meta(self, attributes):
+        attrs = dict(attributes)
+        if attrs.get('http-equiv') == 'refresh':
+            self.value = attrs.get('content').lstrip('0;url=')