mindflayer / python-mocket

a socket mock framework - for all kinds of socket animals, web-clients included
BSD 3-Clause "New" or "Revised" License
280 stars 42 forks source link

Strange behavior with multiple responses #158

Closed ykharko closed 2 years ago

ykharko commented 2 years ago

Describe the bug I wanted to test specific logic of my application when retry logic is used. I wanted to emulate couple of fail responses and then successful one. I tried to use Entry.register method as it looks like its interface allows to pass multiple responses. Almost everything works fine (difference responses are returned back) except for one thing: odd responses are missed.

To Reproduce Probably the easiest way to reproduce it is not to use retries but just specify multiple responses with different status codes:

from mocket import mocketize
from mocket.mockhttp import Entry, Response
import requests

TARGET_URL = 'http://merchant.store/webhook'

@mocketize
def main():
    Entry.register(
        Entry.POST,
        TARGET_URL,
        Response(body='{}', status=200),
        Response(body='{}', status=201),
        Response(body='{}', status=202)
    )

    response = requests.post(TARGET_URL, json={'test': 1})

    print(response.status_code)

if __name__ == '__main__':
    main()

Expected behavior In the given example I expect 200 status code is returned back, but actually 201 status code is returned.

Additional context OS: Ubuntu Python version: 3.8.10 Requests version: 2.25.1 Mocket version: 3.10.0

mindflayer commented 2 years ago

Hi @ykharko, this seems to be a very strange behaviour. I even noticed that changing the POST to

    response = requests.post(TARGET_URL, data="")

makes it behave normally.

EDIT: It seems to be related to POST data.

response = requests.post(TARGET_URL, data=json.dumps({'test': 1}))

This makes it "fail" again.

I'll look into it ASAP.

ykharko commented 2 years ago

Thank you very much for quick reply. :)

mindflayer commented 2 years ago

EDIT: I removed my previous comment because it was inaccurate. I am still working on it.

mindflayer commented 2 years ago

This issue was super-tricky to fix because requests is calling socket.sendall() twice for each transaction (the second one for sending the request body). This behaviour was basically fooling Mocket. So, everything was working properly only when an empty body was sent or a GET method was used, just because there was no need for a second sendall. I am going to release a new version supporting this use-case scenario.

mindflayer commented 2 years ago

Here it is: https://pypi.org/project/mocket/3.10.1/

Thanks again for opening the issue and making mocket a better tool for testing.

ykharko commented 2 years ago

Thank you very much for so quick fix!