#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 [email protected].
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