falconry / falcon

The no-magic web data plane API and microservices framework for Python developers, with a focus on reliability, correctness, and performance at scale.
https://falcon.readthedocs.io/en/stable/
Apache License 2.0
9.53k stars 945 forks source link

TestClient sets buffered_stream, but not stream #2208

Closed davetapley closed 9 months ago

davetapley commented 9 months ago

I did a bad thing: I wrote implementation code before a test (don't judge me), but at least I uncovered a bug 🤪

In my implementation I used request.stream.read(), and it worked when testing manually, but when I wrote the test using TestClient it failed with:

  File "falcon/app.py", line 374, in falcon.app.App.__call__
  File "/workspaces/ng/ng/core/admin/sensor.py", line 95, in on_post_meta
    body = request.stream.read()
           ^^^^^^^^^^^^^^^^^^^^^
  File "/home/codespace/.python/current/lib/python3.11/wsgiref/validate.py", line 197, in read
    assert_(len(args) == 1)
  File "/home/codespace/.python/current/lib/python3.11/wsgiref/validate.py", line 128, in assert_
    raise AssertionError(*args)
AssertionError

I was able to work around this by using request.bounded_stream.read().

I guess there's a clue in the docs which say:

Since this object is provided by the WSGI server itself, rather than by Falcon, it may behave differently depending on how you host your app. For example, attempting to read more bytes than are expected (as determined by the Content-Length header) may or may not block indefinitely. It’s a good idea to test your WSGI server to find out how it behaves.

Hopefully this can still be mocked out in TestClient?

I'd prefer to use stream because the docs also note:

For a slight performance cost, you may instead wish to use bounded_stream, which wraps the native WSGI input object to normalize its behavior.

CaselIT commented 9 months ago

Hi,

I'm not sure I understand the request. that check is performed by https://docs.python.org/3/library/wsgiref.html#module-wsgiref.validate

I think you can pass -1 to read everything

davetapley commented 9 months ago

Oh I see! Yes that works.

It looks like the WSGI server I'm using (CherryPy) allows None, which was the source of the confusion.

vytas7 commented 7 months ago

@davetapley Yes, the test client currently uses wsgiref for validation and gluing of some parts. AFAICT your issue is already tracked as #1617.