Added tests

parent 650111dc
...@@ -3,3 +3,5 @@ syntax: glob ...@@ -3,3 +3,5 @@ syntax: glob
*.pyc *.pyc
*.db *.db
env env
.project
.pydevproject
# To install django-rest-framework...
#
# Requirements:
# python2.6
# virtualenv
hg clone https://tomchristie@bitbucket.org/tomchristie/django-rest-framework
cd django-rest-framework/
virtualenv --no-site-packages --distribute --python=python2.6 env
source ./env/bin/activate
pip install -r ./requirements.txt
python ./src/manage.py test
...@@ -4,6 +4,14 @@ from rest import emitters, parsers ...@@ -4,6 +4,14 @@ from rest import emitters, parsers
class Resource(object): class Resource(object):
class HTTPException(Exception):
def __init__(self, status, content, headers):
self.status = status
self.content = content
self.headers = headers
allowed_methods = ('GET',)
callmap = { 'GET': 'read', 'POST': 'create', callmap = { 'GET': 'read', 'POST': 'create',
'PUT': 'update', 'DELETE': 'delete' } 'PUT': 'update', 'DELETE': 'delete' }
...@@ -17,6 +25,7 @@ class Resource(object): ...@@ -17,6 +25,7 @@ class Resource(object):
'application/xml': parsers.XMLParser, 'application/xml': parsers.XMLParser,
'application/x-www-form-urlencoded': parsers.FormParser } 'application/x-www-form-urlencoded': parsers.FormParser }
def __new__(cls, request, *args, **kwargs): def __new__(cls, request, *args, **kwargs):
self = object.__new__(cls) self = object.__new__(cls)
self.__init__() self.__init__()
...@@ -28,7 +37,6 @@ class Resource(object): ...@@ -28,7 +37,6 @@ class Resource(object):
def _determine_parser(self, request): def _determine_parser(self, request):
"""Return the appropriate parser for the input, given the client's 'Content-Type' header, """Return the appropriate parser for the input, given the client's 'Content-Type' header,
and the content types that this Resource knows how to parse.""" and the content types that this Resource knows how to parse."""
print request.META
return self.parsers.values()[0] return self.parsers.values()[0]
# TODO: Raise 415 Unsupported media type # TODO: Raise 415 Unsupported media type
...@@ -79,25 +87,40 @@ class Resource(object): ...@@ -79,25 +87,40 @@ class Resource(object):
(accept_mimetype == mimetype)): (accept_mimetype == mimetype)):
return (mimetype, emitter) return (mimetype, emitter)
# TODO: Raise 406, Not Acceptable raise self.HTTPException(406, {'status': 'Not Acceptable',
'accepts': ','.join(item[0] for item in self.emitters)}, {})
def _handle_request(self, request, *args, **kwargs): def _handle_request(self, request, *args, **kwargs):
meth = request.method method = request.method
try:
if not method in self.allowed_methods:
raise self.HTTPException(405, {'status': 'Method Not Allowed'}, {})
# Parse the HTTP Request content # Parse the HTTP Request content
if meth in ('PUT', 'POST'): func = getattr(self, self.callmap.get(method, ''))
if method in ('PUT', 'POST'):
parser = self._determine_parser(request) parser = self._determine_parser(request)
data = parser(self, request).parse(request.raw_post_data) data = parser(self, request).parse(request.raw_post_data)
(status, ret, headers) = func(data, request.META, *args, **kwargs)
if meth == "POST":
(status, ret, headers) = self.handle_post(data, request.META, *args, **kwargs)
else: else:
(status, ret, headers) = self.handle_get(request.META, *args, **kwargs) (status, ret, headers) = func(request.META, *args, **kwargs)
except self.HTTPException, exc:
(status, ret, headers) = (exc.status, exc.content, exc.headers)
headers['Allow'] = ', '.join(self.allowed_methods)
# Serialize the HTTP Response content # Serialize the HTTP Response content
try:
mimetype, emitter = self._determine_emitter(request) mimetype, emitter = self._determine_emitter(request)
except self.HTTPException, exc:
(status, ret, headers) = (exc.status, exc.content, exc.headers)
mimetype, emitter = self.emitters[0]
content = emitter(self, status, headers).emit(ret) content = emitter(self, status, headers).emit(ret)
print mimetype, emitter, content
# Build the HTTP Response # Build the HTTP Response
resp = HttpResponse(content, mimetype=mimetype, status=status) resp = HttpResponse(content, mimetype=mimetype, status=status)
...@@ -106,8 +129,19 @@ class Resource(object): ...@@ -106,8 +129,19 @@ class Resource(object):
return resp return resp
def handle_get(self): def _not_implemented(self, operation):
raise NotImplementedError(self.handle_get) resource_name = self.__class__.__name__
return (500, {'status': 'Internal Server Error',
'detail': '%s %s operation is permitted but has not been implemented' % (resource_name, operation)}, {})
def read(self, headers={}, *args, **kwargs):
return self._not_implemented('read')
def create(self, data=None, headers={}, *args, **kwargs):
return self._not_implemented('create')
def update(self, data=None, headers={}, *args, **kwargs):
return self._not_implemented('update')
def handle_post(self): def delete(self, headers={}, *args, **kwargs):
raise NotImplementedError(self.handle_post) return self._not_implemented('delete')
\ No newline at end of file
...@@ -75,7 +75,7 @@ MIDDLEWARE_CLASSES = ( ...@@ -75,7 +75,7 @@ MIDDLEWARE_CLASSES = (
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
) )
ROOT_URLCONF = 'src.urls' ROOT_URLCONF = 'urls'
TEMPLATE_DIRS = ( TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
...@@ -93,5 +93,6 @@ INSTALLED_APPS = ( ...@@ -93,5 +93,6 @@ INSTALLED_APPS = (
'django.contrib.admin', 'django.contrib.admin',
# Uncomment the next line to enable admin documentation: # Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs', # 'django.contrib.admindocs',
'testarchive', 'testapp',
'rest',
) )
"""
This file demonstrates two different styles of tests (one doctest and one
unittest). These will both pass when you run "manage.py test".
Replace these with more appropriate tests for your application.
"""
from django.test import TestCase
from django.core.urlresolvers import reverse
from testapp.views import ReadOnlyResource, MirroringWriteResource
class AcceptHeaderTests(TestCase):
def assert_accept_mimetype(self, mimetype, expect=None, expect_match=True):
"""
Assert that a request with given mimetype in the accept header,
gives a response with the appropriate content-type.
"""
if expect is None:
expect = mimetype
resp = self.client.get(reverse(ReadOnlyResource), HTTP_ACCEPT=mimetype)
if expect_match:
self.assertEquals(resp['content-type'], expect)
else:
self.assertNotEquals(resp['content-type'], expect)
def test_accept_xml(self):
self.assert_accept_mimetype('application/xml')
def test_accept_json(self):
self.assert_accept_mimetype('application/json')
def test_accept_xml_prefered_to_json(self):
self.assert_accept_mimetype('application/xml,q=0.9;application/json,q=0.1', expect='application/xml')
def test_accept_json_prefered_to_xml(self):
self.assert_accept_mimetype('application/json,q=0.9;application/xml,q=0.1', expect='application/json')
def test_dont_accept_invalid(self):
self.assert_accept_mimetype('application/invalid', expect_match=False)
def test_invalid_accept_header_returns_406(self):
resp = self.client.get(reverse(ReadOnlyResource), HTTP_ACCEPT='invalid/invalid')
self.assertEquals(resp.status_code, 406)
class AllowedMethodsTests(TestCase):
def test_write_on_read_only_resource_returns_405(self):
resp = self.client.put(reverse(ReadOnlyResource), {})
self.assertEquals(resp.status_code, 405)
def test_read_on_write_only_resource_returns_405(self):
resp = self.client.get(reverse(MirroringWriteResource))
self.assertEquals(resp.status_code, 405)
from django.conf.urls.defaults import patterns from django.conf.urls.defaults import patterns
from testarchive.views import RootResource from testapp.views import ReadOnlyResource, MirroringWriteResource
urlpatterns = patterns('', urlpatterns = patterns('',
(r'^$', RootResource), (r'^read-only$', ReadOnlyResource),
(r'^mirroring-write$', MirroringWriteResource),
) )
from decimal import Decimal
from rest.resource import Resource
class ReadOnlyResource(Resource):
"""This is my docstring
"""
allowed_methods = ('GET',)
def read(self, headers={}, *args, **kwargs):
return (200, {'ExampleString': 'Example',
'ExampleInt': 1,
'ExampleDecimal': 1.0}, {})
class MirroringWriteResource(Resource):
"""This is my docstring
"""
allowed_methods = ('PUT',)
def create(self, data, headers={}, *args, **kwargs):
return (200, data, {})
"""
This file demonstrates two different styles of tests (one doctest and one
unittest). These will both pass when you run "manage.py test".
Replace these with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.failUnlessEqual(1 + 1, 3)
__test__ = {"doctest": """
Another way to test that 1 + 1 is equal to 2.
>>> 1 + 1 == 2
True
"""}
from rest.resource import Resource
class RootResource(Resource):
"""This is my docstring
"""
def handle_get(self, headers={}, *args, **kwargs):
return (200, {'Name': 'Test', 'Value': 1}, {'Location': 'BLAH'})
...@@ -5,7 +5,7 @@ admin.autodiscover() ...@@ -5,7 +5,7 @@ admin.autodiscover()
urlpatterns = patterns('', urlpatterns = patterns('',
# Example: # Example:
(r'^testarchive/', include('testarchive.urls')), (r'^testapp/', include('testapp.urls')),
# Uncomment the admin/doc line below to enable admin documentation: # Uncomment the admin/doc line below to enable admin documentation:
(r'^admin/doc/', include('django.contrib.admindocs.urls')), (r'^admin/doc/', include('django.contrib.admindocs.urls')),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment