Reputation: 182
I have a Django Rest API and then, separately, a client that consume this API.
I pass a custom header using requests in the client:
r = requests.get(url, params=params, headers={'license': '12345'})
Then in API, in my custom permission, I get the header like:
app_license = request.META['HTTP_LICENSE']
I know django rewrites the custom headers for security reasons, so it works fine.
My problem is when I write the unittests in Django rest API:
response = self.client.get(self.url, params=params, headers={'license': '12345'})
Then it raise:
KeyError: 'HTTP_LICENSE'
But if I change the code like this, the test passes without problem but the consumer doesn't work:
request.META['headers']['license']
I can check if there is 'headers' key or not but I don't want to change the code only to pass the unittest, it must be some way to write a unittest that matches reality, right?
I tried to use:
from django.test import TestCase
And:
from rest_framework.test import APITestCase
Both with same result. There is any solution? Thank you!
Upvotes: 4
Views: 1820
Reputation: 82048
TL;DR — if you want something to show up in META, make it a kwarg
. The client.get
method is a different signature from requests.get
.
This is because the kwargs of self.client.get
map directly to HTTP attributes.
Take a look at the source. You'll notice the stack is:
get
generic
request
_base_environ
In that process, the kwargs
are carried to _base_environ
with very few alterations. They're then merged into a dictionary that includes all of the basic headers you'd expect:
# This is a minimal valid WSGI environ dictionary, plus:
# - HTTP_COOKIE: for cookie support,
# - REMOTE_ADDR: often useful, see #8551.
# See http://www.python.org/dev/peps/pep-3333/#environ-variables
environ = {
'HTTP_COOKIE': self.cookies.output(header='', sep='; '),
'PATH_INFO': '/',
'REMOTE_ADDR': '127.0.0.1',
'REQUEST_METHOD': 'GET',
'SCRIPT_NAME': '',
'SERVER_NAME': 'testserver',
'SERVER_PORT': '80',
'SERVER_PROTOCOL': 'HTTP/1.1',
'wsgi.version': (1, 0),
'wsgi.url_scheme': 'http',
'wsgi.input': FakePayload(b''),
'wsgi.errors': self.errors,
'wsgi.multiprocess': True,
'wsgi.multithread': False,
'wsgi.run_once': False,
}
environ.update(self.defaults)
environ.update(request)
return environ
The above is then passed into a WSGIRequest
object in the request
method. That class then takes the provided environ
dict and assigns it to the META property:
class WSGIRequest(HttpRequest):
def __init__(self, environ):
script_name = get_script_name(environ)
# If PATH_INFO is empty (e.g. accessing the SCRIPT_NAME URL without a
# trailing slash), operate as if '/' was requested.
path_info = get_path_info(environ) or '/'
##############################
## ##
## This is the line you're ##
## looking for. ##
## ##
##############################
self.environ = environ
self.path_info = path_info
Upvotes: 5