Opened 5 years ago
Closed 5 years ago
#31533 closed Bug (invalid)
Test client request's post body can be read multiple times, unlike real requests.
Reported by: | Ben Beecher | Owned by: | nobody |
---|---|---|---|
Component: | Testing framework | Version: | 3.0 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I have a DRF based signup flow that looks like this:
def post(self, request, *args, **kwargs): register_serializer = self.get_serializer(data=request.data) login_serializer = settings.SERIALIZERS.token_create(data=request.data) if register_serializer.is_valid(): return self.create(request, *args, **kwargs) elif login_serializer.is_valid(): return TokenCreateView.as_view()(request=request._request) else: register_serializer.is_valid(raise_exception=True)
In short - try to sign a user up, then try to log them in.
with the following test I get a good response:
def test_register_but_really_login(self): response = self.client.post(self.url, self.form_data) self.assertEqual(response.status_code, s.HTTP_201_CREATED) response = self.client.post(self.url, self.form_data) self.assertEqual(response.status_code, s.HTTP_200_OK)
But when run for real I get this response with the same behavior:
10:57:18 backend.1 | 127.0.0.1 - - [03/May/2020 14:57:18] "POST /auth/register/ HTTP/1.1" 500 - 10:57:18 backend.1 | Traceback (most recent call last): 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/contrib/staticfiles/handlers.py", line 68, in __call__ 10:57:18 backend.1 | return self.application(environ, start_response) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/core/handlers/wsgi.py", line 133, in __call__ 10:57:18 backend.1 | response = self.get_response(request) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/core/handlers/base.py", line 75, in get_response 10:57:18 backend.1 | response = self._middleware_chain(request) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/core/handlers/exception.py", line 36, in inner 10:57:18 backend.1 | response = response_for_exception(request, exc) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception 10:57:18 backend.1 | response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info()) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/core/handlers/exception.py", line 125, in handle_uncaught_exception 10:57:18 backend.1 | return debug.technical_500_response(request, *exc_info) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django_extensions/management/technical_response.py", line 37, in null_technical_500_response 10:57:18 backend.1 | six.reraise(exc_type, exc_value, tb) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/six.py", line 702, in reraise 10:57:18 backend.1 | raise value.with_traceback(tb) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner 10:57:18 backend.1 | response = get_response(request) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/core/handlers/base.py", line 115, in _get_response 10:57:18 backend.1 | response = self.process_exception_by_middleware(e, request) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/core/handlers/base.py", line 113, in _get_response 10:57:18 backend.1 | response = wrapped_callback(request, *callback_args, **callback_kwargs) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view 10:57:18 backend.1 | return view_func(*args, **kwargs) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/views/generic/base.py", line 71, in view 10:57:18 backend.1 | return self.dispatch(request, *args, **kwargs) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/views.py", line 505, in dispatch 10:57:18 backend.1 | response = self.handle_exception(exc) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/views.py", line 465, in handle_exception 10:57:18 backend.1 | self.raise_uncaught_exception(exc) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception 10:57:18 backend.1 | raise exc 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/views.py", line 502, in dispatch 10:57:18 backend.1 | response = handler(request, *args, **kwargs) 10:57:18 backend.1 | File "/home/bbeecher/workspace/sampleapp/sampleapp/account/views.py", line 31, in post 10:57:18 backend.1 | return TokenCreateView.as_view()(request=request._request) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view 10:57:18 backend.1 | return view_func(*args, **kwargs) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/views/generic/base.py", line 71, in view 10:57:18 backend.1 | return self.dispatch(request, *args, **kwargs) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/views.py", line 505, in dispatch 10:57:18 backend.1 | response = self.handle_exception(exc) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/views.py", line 465, in handle_exception 10:57:18 backend.1 | self.raise_uncaught_exception(exc) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception 10:57:18 backend.1 | raise exc 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/views.py", line 502, in dispatch 10:57:18 backend.1 | response = handler(request, *args, **kwargs) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/djoser/utils.py", line 36, in post 10:57:18 backend.1 | serializer = self.get_serializer(data=request.data) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/request.py", line 209, in data 10:57:18 backend.1 | self._load_data_and_files() 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/request.py", line 272, in _load_data_and_files 10:57:18 backend.1 | self._data, self._files = self._parse() 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/request.py", line 322, in _parse 10:57:18 backend.1 | stream = self.stream 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/request.py", line 196, in stream 10:57:18 backend.1 | self._load_stream() 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/request.py", line 302, in _load_stream 10:57:18 backend.1 | self._stream = io.BytesIO(self.body) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/rest_framework/request.py", line 409, in __getattr__ 10:57:18 backend.1 | return getattr(self._request, attr) 10:57:18 backend.1 | File "/home/bbeecher/.virtualenvs/sampleapp/lib/python3.8/site-packages/django/http/request.py", line 292, in body 10:57:18 backend.1 | raise RawPostDataException("You cannot access body after reading from request's data stream") 10:57:18 backend.1 | django.http.request.RawPostDataException: You cannot access body after reading from request's data stream
The error message makes total sense - I am in fact trying to access the request body a second time. But I do the same thing in test successfully.
Change History (2)
comment:1 by , 5 years ago
comment:2 by , 5 years ago
Resolution: | → invalid |
---|---|
Status: | new → closed |
Summary: | Test client request's post body can be read multiple times, unlike real requests → Test client request's post body can be read multiple times, unlike real requests. |
test.Client.post() makes a new POST request on each call. I don't see any issue in this behavior.
Note:
See TracTickets
for help on using tickets.
Hi Ben,
Django's
django.test.Client
is a browser-like simulator. Each time you runself.client.post}}, {{self.client.get}}, etc., {{{Client
will create a new, different request even though the body is the same.Are you using
djoser
? If yes, I think that's not how you usedjoser
properly. You just need to set updjoser
in yoursettings.py
andurls.py
, then use that URL to create tokens or something else. You don't need to recalldjoser
's view inside your view using your own request intended for your view, it will be problemmatic in some places.