munch-ease-backend/tests/httpx_mocks.py

128 lines
4 KiB
Python
Raw Permalink Normal View History

2024-09-29 05:04:10 +00:00
import httpx
import json
import os
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
class RecordingAsyncClient:
def __init__(self, save_dir: str):
self.save_dir = save_dir
os.makedirs(self.save_dir, exist_ok=True)
self.client = None # Will be initialized in __aenter__
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
async def __aenter__(self):
# Initialize the actual AsyncClient when entering the context manager
self.client = httpx.AsyncClient()
return self
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
async def __aexit__(self, exc_type, exc_value, traceback):
# Ensure the client is closed when exiting the context manager
await self.client.aclose()
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
async def request(self, method: str, url: str, **kwargs):
# Send the actual request
response = await self.client.request(method, url, **kwargs)
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
# Record the request and response
record = {
"request": {
"method": method,
"url": url,
"headers": dict(response.request.headers),
2025-10-18 03:26:42 +00:00
"content": response.request.content.decode("utf-8", errors="ignore"),
2024-09-29 05:04:10 +00:00
},
"response": {
"status_code": response.status_code,
"headers": dict(response.headers),
"content": response.text,
"cookies": dict(response.cookies),
2025-10-18 03:26:42 +00:00
},
2024-09-29 05:04:10 +00:00
}
# Generate a filename based on the URL and method
record_file = os.path.join(self.save_dir, f"{method}_{url.replace('/', '_')}.json")
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
# Save the record to a file
2025-10-18 03:26:42 +00:00
with open(record_file, "w") as f:
2024-09-29 05:04:10 +00:00
json.dump(record, f, indent=4)
return response
async def get(self, url: str, **kwargs):
return await self.request("GET", url, **kwargs)
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
async def post(self, url: str, **kwargs):
return await self.request("POST", url, **kwargs)
async def put(self, url: str, **kwargs):
return await self.request("PUT", url, **kwargs)
async def delete(self, url: str, **kwargs):
return await self.request("DELETE", url, **kwargs)
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
from unittest.mock import Mock
import os
import json
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
class MockAsyncClient:
def __init__(self, load_dir: str):
self.load_dir = load_dir
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
async def __aenter__(self):
# No actual client to initialize, just return the instance
return self
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
async def __aexit__(self, exc_type, exc_value, traceback):
# No actual client to close
pass
async def request(self, method: str, url: str, **kwargs):
# Generate the filename based on the URL and method
record_file = os.path.join(self.load_dir, f"{method}_{url.replace('/', '_')}.json")
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
if not os.path.exists(record_file):
raise FileNotFoundError(f"Recorded response not found for {method} {url}")
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
# Load the recorded response from the file
2025-10-18 03:26:42 +00:00
with open(record_file, "r") as f:
2024-09-29 05:04:10 +00:00
record = json.load(f)
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
# Create a mock response object
mock_response = Mock()
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
# Mock the status code
2025-10-18 03:26:42 +00:00
mock_response.status_code = record["response"]["status_code"]
2024-09-29 05:04:10 +00:00
# Mock the json method to return the content as a parsed JSON
def mock_json():
try:
2025-10-18 03:26:42 +00:00
return json.loads(record["response"]["content"])
2024-09-29 05:04:10 +00:00
except json.JSONDecodeError:
2025-10-18 03:26:42 +00:00
return record["response"]["content"]
2024-09-29 05:04:10 +00:00
mock_response.json = mock_json
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
# Mock the cookies as a dictionary
2025-10-18 03:26:42 +00:00
mock_response.cookies = record["response"]["cookies"]
2024-09-29 05:04:10 +00:00
# Mock the headers as a dictionary
2025-10-18 03:26:42 +00:00
mock_response.headers = record["response"]["headers"]
2024-09-29 05:04:10 +00:00
# Mock the text attribute
2025-10-18 03:26:42 +00:00
mock_response.text = record["response"]["content"]
2024-09-29 05:04:10 +00:00
return mock_response
async def get(self, url: str, **kwargs):
return await self.request("GET", url, **kwargs)
2025-10-18 03:26:42 +00:00
2024-09-29 05:04:10 +00:00
async def post(self, url: str, **kwargs):
return await self.request("POST", url, **kwargs)
async def put(self, url: str, **kwargs):
return await self.request("PUT", url, **kwargs)
async def delete(self, url: str, **kwargs):
return await self.request("DELETE", url, **kwargs)