/appengine/apps/tests.py
Python | 323 lines | 295 code | 12 blank | 16 comment | 0 complexity | bcafb3a5504d86720d12de38e46cc05a MD5 | raw file
- import re
- import logging
- import datetime
- from mock import Mock
- from django.conf import settings
- from django.test import TestCase, Client
- from django.utils import simplejson as json
- from auth.models import User
- from apps.models import App
- from docs.models import Doc
- from blobs.models import Blob
- from apps.middleware import app_id_from_trusted_domain
- from utils.middleware import RequestMiddleware
- TAG_REGEX = re.compile(r'<[/!\w][^>]*>')
- class MockDatetime(datetime.datetime):
- orig_datetime = datetime.datetime
- base_time = datetime.datetime(2010, 11, 12, 13, 14, 15)
- delta_secs = 0
- @classmethod
- def now(cls):
- return cls.base_time + datetime.timedelta(0, cls.delta_secs)
- @classmethod
- def advance_time(cls, secs):
- cls.delta_secs += secs
- @classmethod
- def reset_time(cls):
- cls.delta_secs = 0
- class AppTestCase(TestCase):
- """
- Reusable TestCase with automatic users, apps, documents.
- Users: peter, paul (not email verified)
- Apps: www, myapp
- Docs: myapp/mydoc (owned by peter)
- Blobs: apps/myapp/index.html/
- myapp/mydoc/ (Doc's Blob)
- myapp/mydoc/myblob (Child Blob)
- Clients: www, myapp, admin.myapp
- """
- def setUp(self):
- # Reset the RequestMiddleware.
- RequestMiddleware.thread_local = None
- # Mock the datetime object.
- datetime.datetime = MockDatetime
- MockDatetime.reset_time()
- # Create some users.
- self.peter = User(key_name='peter', username='Peter',
- email='peter@example.com',
- email_verified=datetime.datetime.now())
- self.peter.set_password('peter_secret')
- self.peter.put()
- self.paul = User(key_name='paul', username='Paul',
- email='paul@example.com')
- self.paul.set_password('paul_secret')
- self.paul.put()
- # Create a test application.
- self.www = App.lookup('www')
- self.app = App(
- key_name='myapp',
- title='My Test App',
- url='http://myapp.pageforest.com/',
- referers=['http://trusted.com'],
- owner='peter',
- readers=['public'],
- tags=['mytag', 'pf:featured'],
- secret="myapp_secret")
- self.app.put()
- # Create a test document.
- self.doc = Doc(
- key_name='myapp/mydoc',
- doc_id='MyDoc',
- title="My Document",
- tags='one two three'.split(),
- owner='peter',
- readers=['public'],
- )
- self.doc.put()
- self.private_doc = Doc(
- key_name='myapp/private',
- doc_id='private',
- title="My Secret Document",
- owner='peter',
- )
- self.private_doc.put()
- # Create some test blobs.
- Blob(key_name='apps/myapp/index.html/', value='<html>').put()
- Blob(key_name='myapp/mydoc/', value='{"int": 123}').put()
- self.blob = Blob(key_name='myapp/mydoc/myblob/', value='["json"]')
- self.blob.put()
- # Create test clients for www and app.
- self.www_client = Client(
- HTTP_HOST='www.pageforest.com',
- HTTP_REFERER='http://www.pageforest.com/')
- self.app_client = Client(
- HTTP_HOST='myapp.pageforest.com',
- HTTP_REFERER='http://myapp.pageforest.com/')
- self.admin_client = Client(
- HTTP_HOST='%s.myapp.pageforest.com' % settings.ADMIN_SUBDOMAIN,
- HTTP_REFERER='http://myapp.pageforest.com/')
- def tearDown(self):
- datetime.datetime = MockDatetime.orig_datetime
- def sign_in(self, user):
- """
- Generate sessionkey cookies for this user.
- """
- self.www_client.cookies[settings.SESSION_COOKIE_NAME] = \
- user.generate_session_key(self.www)
- self.app_client.cookies[settings.SESSION_COOKIE_NAME] = \
- user.generate_session_key(self.app)
- self.admin_client.cookies[settings.SESSION_COOKIE_NAME] = \
- user.generate_session_key(
- self.app, subdomain=settings.ADMIN_SUBDOMAIN)
- def sign_out(self):
- """
- Remove sessionkey cookies.
- """
- if settings.SESSION_COOKIE_NAME in self.www_client.cookies:
- del self.www_client.cookies[settings.SESSION_COOKIE_NAME]
- if settings.SESSION_COOKIE_NAME in self.app_client.cookies:
- del self.app_client.cookies[settings.SESSION_COOKIE_NAME]
- if settings.SESSION_COOKIE_NAME in self.admin_client.cookies:
- del self.admin_client.cookies[settings.SESSION_COOKIE_NAME]
- def extract_content(self, response):
- """Extract the most meaningful parts from the response."""
- text = TAG_REGEX.sub(' ', response.content)
- lines = [line.strip() for line in text.splitlines() if line.strip()]
- return '\n'.join(lines[:20])
- def assertContains(self, response, *args, **kwargs):
- """Show the response if the test fails."""
- try:
- super(AppTestCase, self).assertContains(response, *args, **kwargs)
- except:
- logging.error("assertContains:\n" + self.extract_content(response))
- raise
- def assertRedirects(self, response, *args, **kwargs):
- """Show the response if the test fails."""
- try:
- super(AppTestCase, self).assertRedirects(response, *args, **kwargs)
- except:
- logging.error("assertRedirects:\n" + self.extract_content(response))
- raise
- class AppJsonTest(AppTestCase):
- def test_app_json_update(self):
- """HTTP PUT app.json should update meta info."""
- url = '/app.json'
- self.sign_in(self.peter)
- response = self.admin_client.put(url, """\
- {
- "title": "My Application",
- "tags": ["test", "myapp"]
- }
- """, content_type='text/plain')
- self.assertContains(response, '"statusText": "Saved"')
- # Retrieve updated meta info.
- response = self.admin_client.get(url)
- decoded = json.loads(response.content)
- self.assertEqual(decoded['title'], "My Application")
- self.assertTrue('myapp' in decoded['tags'])
- self.assertTrue('test' in decoded['tags'])
- def test_http_method_not_allowed(self):
- """The /doc_id/ URL should report allowed methods."""
- self.sign_in(self.peter)
- response = self.admin_client.post('/app.json', {'key': 'value'})
- self.assertEqual(response.status_code, 405)
- self.assertEqual(response['Allow'], 'DELETE, GET, PUT')
- def test_delete(self):
- self.sign_in(self.peter)
- response = self.admin_client.delete('/app.json')
- self.assertEqual(response.status_code, 200)
- response = self.admin_client.get('/app.json')
- self.assertEqual(response.status_code, 404, "NOT FOUND")
- def test_app_json_get_auth(self):
- """The app_json_get view function should check read permissions."""
- url = '/app.json'
- self.app.readers = []
- self.app.put()
- # Application owner should have read permission.
- self.admin_client.cookies[settings.SESSION_COOKIE_NAME] = \
- self.peter.generate_session_key(
- self.app, subdomain=settings.ADMIN_SUBDOMAIN)
- response = self.admin_client.get(url)
- self.assertContains(response, '"url": "http://myapp.pageforest.com/"')
- # Session key for other subdomain should not have read permission.
- self.admin_client.cookies[settings.SESSION_COOKIE_NAME] = \
- self.peter.generate_session_key(self.app, subdomain='docs')
- response = self.admin_client.get(url)
- self.assertContains(response, "Different subdomain.", status_code=403)
- # Session key without subdomain should not have read permission.
- self.admin_client.cookies[settings.SESSION_COOKIE_NAME] = \
- self.peter.generate_session_key(self.app)
- response = self.admin_client.get(url)
- self.assertContains(response, "Missing subdomain.", status_code=403)
- # Other users should not have read permission.
- self.admin_client.cookies[settings.SESSION_COOKIE_NAME] = \
- self.paul.generate_session_key(
- self.app, subdomain=settings.ADMIN_SUBDOMAIN)
- response = self.admin_client.get(url)
- self.assertContains(response, "Read permission denied.",
- status_code=403)
- # Invalid session key should return a helpful error message.
- self.admin_client.cookies[settings.SESSION_COOKIE_NAME] = 'bogus'
- response = self.admin_client.get(url)
- self.assertContains(
- response, "Invalid sessionkey cookie: Expected 4 parts.",
- status_code=403)
- # Anonymous should not have read permission.
- del self.admin_client.cookies[settings.SESSION_COOKIE_NAME]
- response = self.admin_client.get(url)
- self.assertContains(response, "Read permission denied.",
- status_code=403)
- def test_app_json_put_auth(self):
- """The app_json_put view function should check write permissions."""
- url = '/app.json'
- # Application owner should have write permission.
- self.admin_client.cookies[settings.SESSION_COOKIE_NAME] = \
- self.peter.generate_session_key(
- self.app, subdomain=settings.ADMIN_SUBDOMAIN)
- response = self.admin_client.put(url, '{}', content_type='text/plain')
- self.assertContains(response, '"statusText": "Saved"')
- # Session key for other subdomain should not have write permission.
- self.admin_client.cookies[settings.SESSION_COOKIE_NAME] = \
- self.peter.generate_session_key(
- self.app, subdomain=settings.ADMIN_SUBDOMAIN + 's')
- response = self.admin_client.put(url, '{}', content_type='text/plain')
- self.assertContains(response, "Different subdomain.", status_code=403)
- # Session key without subdomain should not have write permission.
- self.admin_client.cookies[settings.SESSION_COOKIE_NAME] = \
- self.peter.generate_session_key(self.app)
- response = self.admin_client.put(url, '{}', content_type='text/plain')
- self.assertContains(response, "Missing subdomain.", status_code=403)
- # Other users should not have write permission.
- self.admin_client.cookies[settings.SESSION_COOKIE_NAME] = \
- self.paul.generate_session_key(
- self.app, subdomain=settings.ADMIN_SUBDOMAIN)
- response = self.admin_client.put(url, '{}', content_type='text/plain')
- self.assertContains(response, "Write permission denied.",
- status_code=403)
- # Invalid session key should return a helpful error message.
- self.admin_client.cookies[settings.SESSION_COOKIE_NAME] = 'bogus'
- response = self.admin_client.put(url, '{}', content_type='text/plain')
- self.assertContains(
- response, "Invalid sessionkey cookie: Expected 4 parts.",
- status_code=403)
- # Anonymous should not have write permission.
- del self.admin_client.cookies[settings.SESSION_COOKIE_NAME]
- response = self.admin_client.put(url, '{}', content_type='text/plain')
- self.assertContains(response, "Write permission denied.",
- status_code=403)
- def test_app_json_put_tags(self):
- """The app_json_put view function should update non-reserved tags."""
- self.sign_in(self.peter)
- self.assertEquals(
- App.get_by_key_name('myapp').tags, ['mytag', 'pf:featured'])
- self.admin_client.put(
- '/app.json', '{"tags": ["newtag", "pf:ignorethis"]}',
- content_type='application/json')
- self.assertEquals(
- App.get_by_key_name('myapp').tags, ['pf:featured', 'newtag'])
- class HostnameTest(TestCase):
- def test_trusted_domain(self):
- """The app_id_from_trusted_domain function should find myapp."""
- for hostname in [
- 'myapp.pageforest.com',
- 'myapp.pageforest.appspot.com',
- 'myapp.dev.latest.pageforest.appspot.com',
- 'myapp.2010-05-12.latest.pageforest.appspot.com',
- 'myapp.pgfr.st',
- 'myapp.pgfrst.com',
- 'myapp.pageforest',
- 'myapp.localhost',
- 'myapp.localhost:8080',
- ]:
- self.assertEqual(app_id_from_trusted_domain(hostname), 'myapp')
- def test_unknown_domain(self):
- """Untrusted domains should return None."""
- for hostname in [
- 'malicious.com',
- 'www.malicious.com',
- 'myapp.malicious.com',
- ]:
- self.assertEqual(app_id_from_trusted_domain(hostname), None)
- class AppErrorsTest(TestCase):
- def setUp(self):
- self.noapp_client = Client(HTTP_HOST="nosuch.pageforest.com")
- def test_missing_app(self):
- """A missing app should return 404 Not Found."""
- response = self.noapp_client.get('/')
- self.assertEqual(response.status_code, 404)