sanic-org / sanic-testing

Test clients for Sanic
https://sanic.dev/en/plugins/sanic-testing/getting-started.html
MIT License
31 stars 19 forks source link

Test responses missing `Content-Length` #57

Closed LiraNuna closed 1 year ago

LiraNuna commented 2 years ago

It seems as though sanic_testing does not full expose the final response.

import pytest
from sanic import Sanic
from sanic import response
from sanic_testing import TestManager

@pytest.fixture
def app():
    sanic_app = Sanic(__name__)
    TestManager(sanic_app)

    @sanic_app.get('/data.json')
    def get_data(request):
        return response.json({
            'data': [1, 2, 3, 4],
        })

    return sanic_app

@pytest.mark.asyncio
async def test_json_response(app):
    request, response = await app.asgi_client.get("/data.json")

    assert response.status == 200
    assert response.headers['Content-Type'] == 'application/json'
    assert response.headers['Content-Length'] == len(response.body)  # <- failure here

When running the same server and making a request to it, the Content-Length header is correctly set:

$ curl -v http://localhost:3000/data.json
*   Trying 127.0.0.1:3000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /data.json HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-length: 18
< connection: keep-alive
< content-type: application/json
< 
* Connection #0 to host localhost left intact
{"data":[1,2,3,4]}

I would like to add that Content-Type is the only response header sent as well, so Transfer-Encoding is not set either.

ahopkins commented 1 year ago

This is because you are using the ASGI client:

Unlike the SanicTestClient that spins up a server on every request, the SanicASGITestClient does not. Instead it makes use of the httpx library to execute Sanic as an ASGI application to reach inside and execute the route handlers.

Source

If you do not manually add a header like content-length, then the server does this for you. This is why you see it if you use test_client instead of asgi_client. In that case, Sanic server does run and does add the header.

When using asgi_client there is no server. And, in an actual ASGI setup your ASGI server would be adding that header.