kevin1024 / vcrpy

Automatically mock your HTTP interactions to simplify and speed up testing
MIT License
2.65k stars 377 forks source link

Aiohttp json body is not recorded in a cassette. #507

Open vitalbmcdonald opened 4 years ago

vitalbmcdonald commented 4 years ago

When using aiohttp json parameter for put or post methods, the resulting cassette does not record the body. Instead the body is seen as null. Aiohttp using the data parameter appears to work fine and requests library works as expected.

Below is a script with tests for aiohttp using methods put and post with body passed in using data and json as well as similar tests for requests. Only two tests, test_aiohttp_json_post_body and test_aiohttp_json_put_body, fail.

Versions:

Python 3.6.9
vcrpy 4.0.2 
aiohttp 3.6.2
requests 2.22.0
pytest 5.3.2     
pytest-asyncio 0.10.0
import vcr
import aiohttp
import pytest
import requests

@pytest.mark.asyncio
async def test_aiohttp_json_post_body():
    with vcr.use_cassette(f"test_aiohttp_json_post_body.yml") as cass:
        async with aiohttp.ClientSession() as session:
            async with session.post(
                "https://postman-echo.com/post", json={"example": "json"},
            ) as response:

                ## verify postman-echo received request body
                assert response.status == 200
                data = await response.json()
                assert data["json"] == {"example": "json"}

        cass.rewind()

        assert len(cass) == 1
        assert cass.requests[0].body == b'{"example": "json"}'

@pytest.mark.asyncio
async def test_aiohttp_json_put_body():
    with vcr.use_cassette("test_aiohttp_json_put_body.yml") as cass:
        async with aiohttp.ClientSession() as session:
            async with session.put(
                "https://postman-echo.com/put", json={"example": "json"},
            ) as response:

                ## verify postman received request body
                assert response.status == 200
                data = await response.json()
                assert data["json"] == {"example": "json"}

        cass.rewind()

        assert len(cass) == 1
        assert cass.requests[0].body == b'{"example": "json"}'

@pytest.mark.asyncio
async def test_aiohttp_data_post_body():
    with vcr.use_cassette(f"test_aiohttp_data_post_body.yml") as cass:
        async with aiohttp.ClientSession() as session:
            async with session.post(
                "https://postman-echo.com/post",
                data=b'{"example": "json"}',
                headers={"Content-Type": "application/json"},
            ) as response:
                ## verify postman received request body
                assert response.status == 200
                data = await response.json()
                assert data["data"] == {"example": "json"}

        cass.rewind()

        assert len(cass) == 1
        assert cass.requests[0].body == b'{"example": "json"}'

@pytest.mark.asyncio
async def test_aiohttp_data_put_body():
    with vcr.use_cassette("test_aiohttp_data_put_body.yml") as cass:
        async with aiohttp.ClientSession() as session:
            async with session.put(
                "https://postman-echo.com/put",
                data=b'{"example": "json"}',
                headers={"Content-Type": "application/json"},
            ) as response:
                ## verify postman received request body
                assert response.status == 200
                data = await response.json()
                assert data["data"] == {"example": "json"}

        cass.rewind()

        assert len(cass) == 1
        assert cass.requests[0].body == b'{"example": "json"}'

def test_requests_json_post_body():
    with vcr.use_cassette(f"test_requests_json_post_body.yml") as cass:
        response = requests.post("https://postman-echo.com/post", json={"example": "json"},)

        ## verify postman received_code request body
        assert response.status_code == 200
        data = response.json()
        assert data["json"] == {"example": "json"}

        cass.rewind()

        assert len(cass) == 1
        assert cass.requests[0].body == b'{"example": "json"}'

def test_requests_json_put_body():
    with vcr.use_cassette("test_requests_json_put_body.yml") as cass:
        response = requests.put("https://postman-echo.com/put", json={"example": "json"},)

        ## verify postman received_code request body
        assert response.status_code == 200
        data = response.json()
        assert data["json"] == {"example": "json"}

        cass.rewind()

        assert len(cass) == 1
        assert cass.requests[0].body == b'{"example": "json"}'

def test_requests_data_post_body():
    with vcr.use_cassette(f"test_requests_data_post_body.yml") as cass:
        response = requests.post(
            "https://postman-echo.com/post",
            data=b'{"example": "json"}',
            headers={"Content-Type": "application/json"},
        )

        ## verify postman received request body
        assert response.status_code == 200
        data = response.json()
        assert data["data"] == {"example": "json"}

        cass.rewind()

        assert len(cass) == 1
        assert cass.requests[0].body == b'{"example": "json"}'

def test_requests_data_put_body():
    with vcr.use_cassette("test_requests_data_put_body.yml") as cass:
        response = requests.put(
            "https://postman-echo.com/put",
            data=b'{"example": "json"}',
            headers={"Content-Type": "application/json"},
        )

        ## verify postman received request body
        assert response.status_code == 200
        data = response.json()
        assert data["data"] == {"example": "json"}

        cass.rewind()

        assert len(cass) == 1
        assert cass.requests[0].body == b'{"example": "json"}'
neozenith commented 4 years ago

Thanks for reporting this issue! 🙏 And documenting the exact test scenarios.

Could you perhaps open a PR that adds these tests, which will obviously fail 👍 but it’ll make it infinitely easier for someone to fork your PR branch and apply a fix.

In the PR mention “Fixes #507” for it to link to this issue.

I’m also on leave until mid January so I’m not looking at PRs in detail until I get back to work.

vitalbmcdonald commented 4 years ago

After reviewing the tests it looked like there were tests in place that mimicked my own, but after some debugging and stress on my sanity, I figured out that the tests rely on session.request('POST' ... and the bug only occurs when doing session.post. That was a fun find.

I have created PR #508 with the tests added as requested. Let me know if this wasn't what you were looking for.

mikemoritz commented 3 years ago

Hi, I am also encountering this issue. Would it be possible to review/merge the PR? Thanks!