From ab8e74fa2faa089899b99f66d81ce827e2c3006b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20W=C3=B3jciak?= Date: Wed, 20 Nov 2024 21:53:12 +0100 Subject: [PATCH] [feature/skip_response_cache] --- mocket/async_mocket.py | 8 +++++++- mocket/inject.py | 2 ++ mocket/mocket.py | 5 +++++ mocket/mocketizer.py | 21 +++++++++++++++++++-- mocket/socket.py | 8 ++++++-- tests/test_http.py | 19 +++++++++++++++++++ 6 files changed, 58 insertions(+), 5 deletions(-) diff --git a/mocket/async_mocket.py b/mocket/async_mocket.py index 709d225f..33b8c8e2 100644 --- a/mocket/async_mocket.py +++ b/mocket/async_mocket.py @@ -7,11 +7,17 @@ async def wrapper( truesocket_recording_dir=None, strict_mode=False, strict_mode_allowed=None, + skip_response_cache=False, *args, **kwargs, ): async with Mocketizer.factory( - test, truesocket_recording_dir, strict_mode, strict_mode_allowed, args + test, + truesocket_recording_dir, + strict_mode, + strict_mode_allowed, + skip_response_cache, + args, ): return await test(*args, **kwargs) diff --git a/mocket/inject.py b/mocket/inject.py index cba0b40b..51436ddb 100644 --- a/mocket/inject.py +++ b/mocket/inject.py @@ -41,6 +41,7 @@ def enable( namespace: str | None = None, truesocket_recording_dir: str | None = None, + skip_response_cache: bool = False, ) -> None: from mocket.mocket import Mocket from mocket.socket import MocketSocket, create_connection, socketpair @@ -48,6 +49,7 @@ def enable( Mocket._namespace = namespace Mocket._truesocket_recording_dir = truesocket_recording_dir + Mocket._skip_response_cache = skip_response_cache if truesocket_recording_dir and not os.path.isdir(truesocket_recording_dir): # JSON dumps will be saved here diff --git a/mocket/mocket.py b/mocket/mocket.py index 3476902d..dacd7b97 100644 --- a/mocket/mocket.py +++ b/mocket/mocket.py @@ -22,6 +22,7 @@ class Mocket: _requests: ClassVar[list] = [] _namespace: ClassVar[str] = str(id(_entries)) _truesocket_recording_dir: ClassVar[str | None] = None + _skip_response_cache: bool = False enable = mocket.inject.enable disable = mocket.inject.disable @@ -96,6 +97,10 @@ def get_namespace(cls) -> str: def get_truesocket_recording_dir(cls) -> str | None: return cls._truesocket_recording_dir + @classmethod + def get_skip_response_cache(cls) -> bool: + return cls._skip_response_cache + @classmethod def assert_fail_if_entries_not_served(cls) -> None: """Mocket checks that all entries have been served at least once.""" diff --git a/mocket/mocketizer.py b/mocket/mocketizer.py index 2bf2b9cd..aef49316 100644 --- a/mocket/mocketizer.py +++ b/mocket/mocketizer.py @@ -11,9 +11,11 @@ def __init__( truesocket_recording_dir=None, strict_mode=False, strict_mode_allowed=None, + skip_response_cache=False, ): self.instance = instance self.truesocket_recording_dir = truesocket_recording_dir + self.skip_response_cache = skip_response_cache self.namespace = namespace or str(id(self)) MocketMode().STRICT = strict_mode if strict_mode: @@ -27,6 +29,7 @@ def enter(self): Mocket.enable( namespace=self.namespace, truesocket_recording_dir=self.truesocket_recording_dir, + skip_response_cache=self.skip_response_cache, ) if self.instance: self.check_and_call("mocketize_setup") @@ -57,7 +60,14 @@ def check_and_call(self, method_name): method() @staticmethod - def factory(test, truesocket_recording_dir, strict_mode, strict_mode_allowed, args): + def factory( + test, + truesocket_recording_dir, + strict_mode, + strict_mode_allowed, + skip_response_cache, + args, + ): instance = args[0] if args else None namespace = None if truesocket_recording_dir: @@ -75,6 +85,7 @@ def factory(test, truesocket_recording_dir, strict_mode, strict_mode_allowed, ar truesocket_recording_dir=truesocket_recording_dir, strict_mode=strict_mode, strict_mode_allowed=strict_mode_allowed, + skip_response_cache=skip_response_cache, ) @@ -83,11 +94,17 @@ def wrapper( truesocket_recording_dir=None, strict_mode=False, strict_mode_allowed=None, + skip_response_cache=False, *args, **kwargs, ): with Mocketizer.factory( - test, truesocket_recording_dir, strict_mode, strict_mode_allowed, args + test, + truesocket_recording_dir, + strict_mode, + strict_mode_allowed, + skip_response_cache, + args, ): return test(*args, **kwargs) diff --git a/mocket/socket.py b/mocket/socket.py index e4be00b6..5a3b63e2 100644 --- a/mocket/socket.py +++ b/mocket/socket.py @@ -6,6 +6,7 @@ import select import socket import ssl +import uuid from datetime import datetime, timedelta from json.decoder import JSONDecodeError @@ -224,7 +225,10 @@ def true_sendall(self, data, *args, **kwargs): req = decode_from_bytes(data) # make request unique again - req_signature = _hash_request(hasher, req) + req_signature_source = ( + str(uuid.uuid4()) if Mocket.get_skip_response_cache() else req + ) + req_signature = _hash_request(hasher, req_signature_source) # port should be always a string port = str(self._port) @@ -250,7 +254,7 @@ def true_sendall(self, data, *args, **kwargs): except KeyError: if hasher is not hashlib.md5: # Fallback for backwards compatibility - req_signature = _hash_request(hashlib.md5, req) + req_signature = _hash_request(hashlib.md5, req_signature_source) response_dict = responses[self._host][port][req_signature] else: raise diff --git a/tests/test_http.py b/tests/test_http.py index d516068b..c55abe63 100644 --- a/tests/test_http.py +++ b/tests/test_http.py @@ -93,6 +93,25 @@ def test_truesendall_with_chunk_recording(self): assert len(responses["httpbin.local"]["80"].keys()) == 1 + def test_truesendall_with_recording_and_skip_response_cache(self): + with tempfile.TemporaryDirectory() as temp_dir, Mocketizer( + truesocket_recording_dir=temp_dir, + skip_response_cache=True, + ): + url = "http://httpbin.local/ip" + + requests.get(url) + requests.get(url) + + dump_filename = os.path.join( + Mocket.get_truesocket_recording_dir(), + Mocket.get_namespace() + ".json", + ) + with open(dump_filename) as f: + responses = json.load(f) + + self.assertEqual(len(responses["httpbin.local"]["80"].keys()), 2) + @mocketize def test_wrongpath_truesendall(self): Entry.register(