#34063: request.POST not populated for multipart/form-data via AsyncClient
---------------------------------------------+------------------------
               Reporter:  Timo Ludwig        |          Owner:  nobody
                   Type:  Bug                |         Status:  new
              Component:  Testing framework  |        Version:  4.0
               Severity:  Normal             |       Keywords:
           Triage Stage:  Unreviewed         |      Has patch:  0
    Needs documentation:  0                  |    Needs tests:  0
Patch needs improvement:  0                  |  Easy pickings:  0
                  UI/UX:  0                  |
---------------------------------------------+------------------------
 In test cases with the `AsyncClient` and requests with the default content
 type `"multipart/form-data"`, I cannot test views which access
 `request.POST` before accessing `request.body`.
 I'm very sorry if this is a duplicate of #32189 and this is the expected
 behavior, but the way I understood it is that `request.POST` should be
 populated for all form requests, so both `application/x-www-form-
 urlencoded` and `multipart/form-data`, right?

 If I just copy the
 
[https://github.com/django/django/blob/9b0c9821ed4dd9920cc7c5e7b657720d91a89bdc/tests/test_client/tests.py#L132-L140
 test_post] case from the sync `ClientTest` (and adapt it to the async
 structure as follows):
 {{{
 diff --git a/tests/test_client/tests.py b/tests/test_client/tests.py
 index 57dc22ea0c..8cebaae9e7 100644
 --- a/tests/test_client/tests.py
 +++ b/tests/test_client/tests.py
 @@ -1103,6 +1103,16 @@ class AsyncClientTest(TestCase):
          response = await self.async_client.get("/get_view/", {"var":
 "val"})
          self.assertContains(response, "This is a test. val is the
 value.")

 +    async def test_post(self):
 +        "POST some data to a view"
 +        post_data = {"value": 37}
 +        response = await self.async_client.post("/post_view/", post_data)
 +
 +        # Check some response details
 +        self.assertContains(response, "Data received")
 +        self.assertEqual(response.context["data"], "37")
 +        self.assertEqual(response.templates[0].name, "POST Template")
 +

  @override_settings(ROOT_URLCONF="test_client.urls")
  class AsyncRequestFactoryTest(SimpleTestCase):
 }}}

 the test case fails with:

 {{{
 FAIL: test_post (test_client.tests.AsyncClientTest)
 POST some data to a view
 ----------------------------------------------------------------------
 Traceback (most recent call last):
   File "/usr/lib/python3.10/unittest/case.py", line 59, in
 testPartExecutor
     yield
   File "/usr/lib/python3.10/unittest/case.py", line 591, in run
     self._callTestMethod(testMethod)
   File "/usr/lib/python3.10/unittest/case.py", line 549, in
 _callTestMethod
     method()
   File "/home/user/.local/lib/python3.10/site-packages/asgiref/sync.py",
 line 218, in __call__
     return call_result.result()
   File "/usr/lib/python3.10/concurrent/futures/_base.py", line 451, in
 result
     return self.__get_result()
   File "/usr/lib/python3.10/concurrent/futures/_base.py", line 403, in
 __get_result
     raise self._exception
   File "/home/user/.local/lib/python3.10/site-packages/asgiref/sync.py",
 line 284, in main_wrap
     result = await self.awaitable(*args, **kwargs)
   File "/home/django/tests/test_client/tests.py", line 1109, in test_post
     response = await self.async_client.post("/post_view/", post_data)
   File "/home/user/django/django/test/client.py", line 1072, in request
     self.check_exception(response)
   File "/home/user/django/django/test/client.py", line 666, in
 check_exception
     raise exc_value
   File "/home/user/.local/lib/python3.10/site-packages/asgiref/sync.py",
 line 472, in thread_handler
     raise exc_info[1]
   File "/home/user/django/django/core/handlers/exception.py", line 42, in
 inner
     response = await get_response(request)
   File "/home/user/django/django/core/handlers/base.py", line 253, in
 _get_response_async
     response = await wrapped_callback(
   File "/home/user/.local/lib/python3.10/site-packages/asgiref/sync.py",
 line 435, in __call__
     ret = await asyncio.wait_for(future, timeout=None)
   File "/usr/lib/python3.10/asyncio/tasks.py", line 408, in wait_for
     return await fut
   File "/home/user/.local/lib/python3.10/site-
 packages/asgiref/current_thread_executor.py", line 22, in run
     result = self.fn(*self.args, **self.kwargs)
   File "/home/user/.local/lib/python3.10/site-packages/asgiref/sync.py",
 line 476, in thread_handler
     return func(*args, **kwargs)
   File "/home/django/tests/test_client/views.py", line 83, in post_view
     if request.POST:
   File "/home/user/django/django/core/handlers/asgi.py", line 113, in
 _get_post
     self._load_post_and_files()
   File "/home/user/django/django/http/request.py", line 386, in
 _load_post_and_files
     self._post, self._files = self.parse_file_upload(self.META, data)
   File "/home/user/django/django/http/request.py", line 334, in
 parse_file_upload
     return parser.parse()
   File "/home/user/django/django/http/multipartparser.py", line 165, in
 parse
     for item_type, meta_data, field_stream in Parser(stream,
 self._boundary):
   File "/home/user/django/django/http/multipartparser.py", line 703, in
 __iter__
     for sub_stream in boundarystream:
   File "/home/user/django/django/http/multipartparser.py", line 533, in
 __next__
     return LazyStream(BoundaryIter(self._stream, self._boundary))
   File "/home/user/django/django/http/multipartparser.py", line 560, in
 __init__
     unused_char = self._stream.read(1)
   File "/home/user/django/django/http/multipartparser.py", line 427, in
 read
     return b"".join(parts())
   File "/home/user/django/django/http/multipartparser.py", line 418, in
 parts
     chunk = next(self)
   File "/home/user/django/django/http/multipartparser.py", line 440, in
 __next__
     output = next(self._producer)
   File "/home/user/django/django/http/multipartparser.py", line 507, in
 __next__
     data = self.flo.read(self.chunk_size)
   File "/home/user/django/django/http/request.py", line 421, in read
     return self._stream.read(*args, **kwargs)
   File "/home/user/django/django/test/client.py", line 82, in read
     assert (
 AssertionError: Cannot read more than the available bytes from the HTTP
 incoming data.
 }}}

 While the same test case (and the same content type) succeeds for the sync
 `Client`.
  I would be willing to provide a patch if someone could point me in the
 right direction.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34063>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/010701838a386409-2c5530a3-1542-4c4e-b0ba-adb255564c5d-000000%40eu-central-1.amazonses.com.

Reply via email to