Skip to content

Commit

Permalink
Fixed #20864 -- Made the test client use common method for performing…
Browse files Browse the repository at this point in the history
… requests.
  • Loading branch information
KrzysiekJ authored and timgraham committed Aug 13, 2013
1 parent 4e50e40 commit 4eeb8ec
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 37 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -317,6 +317,7 @@ answer newbie questions, and generally made Django that much better:
Michael Josephson <http://www.sdjournal.com/> Michael Josephson <http://www.sdjournal.com/>
jpellerin@gmail.com jpellerin@gmail.com
junzhang.jn@gmail.com junzhang.jn@gmail.com
Krzysztof Jurewicz <krzysztof.jurewicz@gmail.com>
Xia Kai <http://blog.xiaket.org/> Xia Kai <http://blog.xiaket.org/>
Antti Kaihola <http://djangopeople.net/akaihola/> Antti Kaihola <http://djangopeople.net/akaihola/>
Peter van Kampen Peter van Kampen
Expand Down
63 changes: 26 additions & 37 deletions django/test/client.py
Expand Up @@ -37,6 +37,7 @@
MULTIPART_CONTENT = 'multipart/form-data; boundary=%s' % BOUNDARY MULTIPART_CONTENT = 'multipart/form-data; boundary=%s' % BOUNDARY
CONTENT_TYPE_RE = re.compile('.*; charset=([\w\d-]+);?') CONTENT_TYPE_RE = re.compile('.*; charset=([\w\d-]+);?')



class FakePayload(object): class FakePayload(object):
""" """
A wrapper around BytesIO that restricts what can be read since data from A wrapper around BytesIO that restricts what can be read since data from
Expand Down Expand Up @@ -123,6 +124,7 @@ def __call__(self, environ):


return response return response



def store_rendered_templates(store, signal, sender, template, context, **kwargs): def store_rendered_templates(store, signal, sender, template, context, **kwargs):
""" """
Stores templates and contexts that are rendered. Stores templates and contexts that are rendered.
Expand All @@ -133,6 +135,7 @@ def store_rendered_templates(store, signal, sender, template, context, **kwargs)
store.setdefault('templates', []).append(template) store.setdefault('templates', []).append(template)
store.setdefault('context', ContextList()).append(copy(context)) store.setdefault('context', ContextList()).append(copy(context))



def encode_multipart(boundary, data): def encode_multipart(boundary, data):
""" """
Encodes multipart POST data from a dictionary of form values. Encodes multipart POST data from a dictionary of form values.
Expand Down Expand Up @@ -178,6 +181,7 @@ def encode_multipart(boundary, data):
]) ])
return b'\r\n'.join(lines) return b'\r\n'.join(lines)



def encode_file(boundary, key, file): def encode_file(boundary, key, file):
to_bytes = lambda s: force_bytes(s, settings.DEFAULT_CHARSET) to_bytes = lambda s: force_bytes(s, settings.DEFAULT_CHARSET)
if hasattr(file, 'content_type'): if hasattr(file, 'content_type'):
Expand All @@ -189,8 +193,8 @@ def encode_file(boundary, key, file):
content_type = 'application/octet-stream' content_type = 'application/octet-stream'
return [ return [
to_bytes('--%s' % boundary), to_bytes('--%s' % boundary),
to_bytes('Content-Disposition: form-data; name="%s"; filename="%s"' \ to_bytes('Content-Disposition: form-data; name="%s"; filename="%s"'
% (key, os.path.basename(file.name))), % (key, os.path.basename(file.name))),
to_bytes('Content-Type: %s' % content_type), to_bytes('Content-Type: %s' % content_type),
b'', b'',
file.read() file.read()
Expand Down Expand Up @@ -274,47 +278,31 @@ def _get_path(self, parsed):
def get(self, path, data={}, **extra): def get(self, path, data={}, **extra):
"Construct a GET request." "Construct a GET request."


parsed = urlparse(path)
r = { r = {
'PATH_INFO': self._get_path(parsed), 'QUERY_STRING': urlencode(data, doseq=True),
'QUERY_STRING': urlencode(data, doseq=True) or force_str(parsed[4]),
'REQUEST_METHOD': str('GET'),
} }
r.update(extra) r.update(extra)
return self.request(**r) return self.generic('GET', path, **r)


def post(self, path, data={}, content_type=MULTIPART_CONTENT, def post(self, path, data={}, content_type=MULTIPART_CONTENT,
**extra): **extra):
"Construct a POST request." "Construct a POST request."


post_data = self._encode_data(data, content_type) post_data = self._encode_data(data, content_type)


parsed = urlparse(path) return self.generic('POST', path, post_data, content_type, **extra)
r = {
'CONTENT_LENGTH': len(post_data),
'CONTENT_TYPE': content_type,
'PATH_INFO': self._get_path(parsed),
'QUERY_STRING': force_str(parsed[4]),
'REQUEST_METHOD': str('POST'),
'wsgi.input': FakePayload(post_data),
}
r.update(extra)
return self.request(**r)


def head(self, path, data={}, **extra): def head(self, path, data={}, **extra):
"Construct a HEAD request." "Construct a HEAD request."


parsed = urlparse(path)
r = { r = {
'PATH_INFO': self._get_path(parsed), 'QUERY_STRING': urlencode(data, doseq=True),
'QUERY_STRING': urlencode(data, doseq=True) or force_str(parsed[4]),
'REQUEST_METHOD': str('HEAD'),
} }
r.update(extra) r.update(extra)
return self.request(**r) return self.generic('HEAD', path, **r)


def options(self, path, data='', content_type='application/octet-stream', def options(self, path, data='', content_type='application/octet-stream',
**extra): **extra):
"Construct an OPTIONS request." "Construct an OPTIONS request."
return self.generic('OPTIONS', path, data, content_type, **extra) return self.generic('OPTIONS', path, data, content_type, **extra)


Expand All @@ -324,22 +312,22 @@ def put(self, path, data='', content_type='application/octet-stream',
return self.generic('PUT', path, data, content_type, **extra) return self.generic('PUT', path, data, content_type, **extra)


def patch(self, path, data='', content_type='application/octet-stream', def patch(self, path, data='', content_type='application/octet-stream',
**extra): **extra):
"Construct a PATCH request." "Construct a PATCH request."
return self.generic('PATCH', path, data, content_type, **extra) return self.generic('PATCH', path, data, content_type, **extra)


def delete(self, path, data='', content_type='application/octet-stream', def delete(self, path, data='', content_type='application/octet-stream',
**extra): **extra):
"Construct a DELETE request." "Construct a DELETE request."
return self.generic('DELETE', path, data, content_type, **extra) return self.generic('DELETE', path, data, content_type, **extra)


def generic(self, method, path, def generic(self, method, path,
data='', content_type='application/octet-stream', **extra): data='', content_type='application/octet-stream', **extra):
"""Constructs an arbitrary HTTP request."""
parsed = urlparse(path) parsed = urlparse(path)
data = force_bytes(data, settings.DEFAULT_CHARSET) data = force_bytes(data, settings.DEFAULT_CHARSET)
r = { r = {
'PATH_INFO': self._get_path(parsed), 'PATH_INFO': self._get_path(parsed),
'QUERY_STRING': force_str(parsed[4]),
'REQUEST_METHOD': str(method), 'REQUEST_METHOD': str(method),
} }
if data: if data:
Expand All @@ -349,8 +337,12 @@ def generic(self, method, path,
'wsgi.input': FakePayload(data), 'wsgi.input': FakePayload(data),
}) })
r.update(extra) r.update(extra)
# If QUERY_STRING is absent or empty, we want to extract it from the URL.
if not r.get('QUERY_STRING'):
r['QUERY_STRING'] = force_str(parsed[4])
return self.request(**r) return self.request(**r)



class Client(RequestFactory): class Client(RequestFactory):
""" """
A class that can act as a client for testing purposes. A class that can act as a client for testing purposes.
Expand Down Expand Up @@ -392,7 +384,6 @@ def _session(self):
return {} return {}
session = property(_session) session = property(_session)



def request(self, **request): def request(self, **request):
""" """
The master request method. Composes the environment dictionary The master request method. Composes the environment dictionary
Expand Down Expand Up @@ -485,12 +476,11 @@ def head(self, path, data={}, follow=False, **extra):
return response return response


def options(self, path, data='', content_type='application/octet-stream', def options(self, path, data='', content_type='application/octet-stream',
follow=False, **extra): follow=False, **extra):
""" """
Request a response from the server using OPTIONS. Request a response from the server using OPTIONS.
""" """
response = super(Client, self).options(path, response = super(Client, self).options(path, data=data, content_type=content_type, **extra)
data=data, content_type=content_type, **extra)
if follow: if follow:
response = self._handle_redirects(response, **extra) response = self._handle_redirects(response, **extra)
return response return response
Expand All @@ -500,14 +490,13 @@ def put(self, path, data='', content_type='application/octet-stream',
""" """
Send a resource to the server using PUT. Send a resource to the server using PUT.
""" """
response = super(Client, self).put(path, response = super(Client, self).put(path, data=data, content_type=content_type, **extra)
data=data, content_type=content_type, **extra)
if follow: if follow:
response = self._handle_redirects(response, **extra) response = self._handle_redirects(response, **extra)
return response return response


def patch(self, path, data='', content_type='application/octet-stream', def patch(self, path, data='', content_type='application/octet-stream',
follow=False, **extra): follow=False, **extra):
""" """
Send a resource to the server using PATCH. Send a resource to the server using PATCH.
""" """
Expand All @@ -518,12 +507,12 @@ def patch(self, path, data='', content_type='application/octet-stream',
return response return response


def delete(self, path, data='', content_type='application/octet-stream', def delete(self, path, data='', content_type='application/octet-stream',
follow=False, **extra): follow=False, **extra):
""" """
Send a DELETE request to the server. Send a DELETE request to the server.
""" """
response = super(Client, self).delete(path, response = super(Client, self).delete(
data=data, content_type=content_type, **extra) path, data=data, content_type=content_type, **extra)
if follow: if follow:
response = self._handle_redirects(response, **extra) response = self._handle_redirects(response, **extra)
return response return response
Expand Down

0 comments on commit 4eeb8ec

Please sign in to comment.