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.Clientis a browser-like simulator. Each time you runself.client.post}}, {{self.client.get}}, etc., {{{Clientwill 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 usedjoserproperly. You just need to set updjoserin yoursettings.pyandurls.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.