"""Tests for the recorder module.""" from unittest.mock import MagicMock, patch from api_snapshot.recorder.recorder import ( RecordedRequest, RecordedResponse, RecordingSession, RequestResponsePair, record_multiple, record_session, ) class TestRecordedRequest: """Tests for RecordedRequest class.""" def test_create_request(self): """Test creating a recorded request.""" req = RecordedRequest( method="GET", url="https://api.example.com/users", headers={"Accept": "application/json"}, body=None, ) assert req.method == "GET" assert req.url == "https://api.example.com/users" assert req.headers == {"Accept": "application/json"} assert req.body is None assert req.timestamp is not None def test_request_to_dict(self): """Test converting request to dictionary.""" req = RecordedRequest( method="POST", url="https://api.example.com/data", headers={"Content-Type": "application/json"}, body='{"key": "value"}', ) data = req.to_dict() assert data["method"] == "POST" assert data["url"] == "https://api.example.com/data" assert data["headers"] == {"Content-Type": "application/json"} assert data["body"] == '{"key": "value"}' assert "timestamp" in data def test_request_from_dict(self): """Test creating request from dictionary.""" data = { "method": "PUT", "url": "https://api.example.com/resource/1", "headers": {"Authorization": "Bearer token"}, "body": "updated data", "timestamp": "2024-01-01T12:00:00", } req = RecordedRequest.from_dict(data) assert req.method == "PUT" assert req.url == "https://api.example.com/resource/1" assert req.headers == {"Authorization": "Bearer token"} assert req.body == "updated data" assert req.timestamp == "2024-01-01T12:00:00" class TestRecordedResponse: """Tests for RecordedResponse class.""" def test_create_response(self): """Test creating a recorded response.""" resp = RecordedResponse( status_code=200, headers={"Content-Type": "application/json"}, body='{"success": true}', latency_ms=150, ) assert resp.status_code == 200 assert resp.headers == {"Content-Type": "application/json"} assert resp.body == '{"success": true}' assert resp.latency_ms == 150 def test_response_to_dict(self): """Test converting response to dictionary.""" resp = RecordedResponse( status_code=404, headers={"Content-Type": "text/plain"}, body="Not Found", latency_ms=50, ) data = resp.to_dict() assert data["status_code"] == 404 assert data["headers"] == {"Content-Type": "text/plain"} assert data["body"] == "Not Found" assert data["latency_ms"] == 50 def test_response_from_dict(self): """Test creating response from dictionary.""" data = { "status_code": 500, "headers": {"Content-Type": "application/json"}, "body": '{"error": "internal"}', "latency_ms": 300, } resp = RecordedResponse.from_dict(data) assert resp.status_code == 500 assert resp.headers == {"Content-Type": "application/json"} assert resp.body == '{"error": "internal"}' assert resp.latency_ms == 300 class TestRequestResponsePair: """Tests for RequestResponsePair class.""" def test_create_pair(self, sample_request, sample_response): """Test creating a request-response pair.""" pair = RequestResponsePair( request=sample_request, response=sample_response, ) assert pair.request == sample_request assert pair.response == sample_response def test_pair_to_dict(self, sample_pair): """Test converting pair to dictionary.""" data = sample_pair.to_dict() assert "request" in data assert "response" in data assert data["request"]["method"] == "GET" assert data["response"]["status_code"] == 200 def test_pair_from_dict(self, sample_pair): """Test creating pair from dictionary.""" data = sample_pair.to_dict() restored = RequestResponsePair.from_dict(data) assert restored.request.method == sample_pair.request.method assert restored.response.status_code == sample_pair.response.status_code class TestRecordingSession: """Tests for RecordingSession class.""" def test_init_session(self): """Test initializing a recording session.""" session = RecordingSession() assert session.base_url is None assert session.on_request is None assert session.recordings == [] def test_init_with_base_url(self): """Test initializing with base URL.""" session = RecordingSession(base_url="https://api.example.com") assert session.base_url == "https://api.example.com" def test_build_url_absolute(self): """Test building URL for absolute URL.""" session = RecordingSession() url = session._build_url("https://other.com/api") assert url == "https://other.com/api" def test_build_url_relative(self): """Test building URL for relative URL.""" session = RecordingSession(base_url="https://api.example.com") url = session._build_url("/users") assert url == "https://api.example.com/users" def test_build_url_relative_no_base(self): """Test building URL for relative URL without base.""" session = RecordingSession() url = session._build_url("/users") assert url == "/users" def test_record_request_adds_to_recordings(self): """Test that record_request adds to recordings.""" session = RecordingSession() with patch( "api_snapshot.recorder.recorder.requests.Session.request" ) as mock_request: mock_response = MagicMock() mock_response.status_code = 200 mock_response.headers = {"Content-Type": "application/json"} mock_response.text = '{"success": true}' mock_request.return_value = mock_response session.record_request("GET", "https://api.example.com/users") assert len(session.recordings) == 1 assert session.recordings[0].request.method == "GET" assert session.recordings[0].response.status_code == 200 def test_on_request_callback(self): """Test on_request callback is called.""" callback = MagicMock() session = RecordingSession(on_request=callback) with patch( "api_snapshot.recorder.recorder.requests.Session.request" ) as mock_request: mock_response = MagicMock() mock_response.status_code = 200 mock_response.headers = {} mock_response.text = "{}" mock_request.return_value = mock_response session.record_request("GET", "https://api.example.com") callback.assert_called_once() def test_clear_recordings(self): """Test clearing recordings.""" session = RecordingSession() with patch( "api_snapshot.recorder.recorder.requests.Session.request" ) as mock_request: mock_response = MagicMock() mock_response.status_code = 200 mock_response.headers = {} mock_response.text = "{}" mock_request.return_value = mock_response session.record_request("GET", "https://api.example.com") assert len(session.recordings) == 1 session.clear() assert len(session.recordings) == 0 def test_get_recordings(self): """Test getting recordings.""" session = RecordingSession() with patch( "api_snapshot.recorder.recorder.requests.Session.request" ) as mock_request: mock_response = MagicMock() mock_response.status_code = 200 mock_response.headers = {} mock_response.text = "{}" mock_request.return_value = mock_response session.record_request("GET", "https://api.example.com/1") session.record_request("GET", "https://api.example.com/2") recordings = session.get_recordings() assert len(recordings) == 2 assert recordings[0].request.url.endswith("/1") assert recordings[1].request.url.endswith("/2") class TestRecordFunctions: """Tests for record_session and record_multiple functions.""" def test_record_session(self): """Test record_session function.""" with patch( "api_snapshot.recorder.recorder.requests.Session.request" ) as mock_request: mock_response = MagicMock() mock_response.status_code = 200 mock_response.headers = {"Content-Type": "application/json"} mock_response.text = '{"data": "test"}' mock_request.return_value = mock_response pairs = record_session( url="https://api.example.com/api", method="GET", ) assert len(pairs) == 1 assert pairs[0].request.method == "GET" assert pairs[0].response.status_code == 200 def test_record_multiple(self): """Test record_multiple function.""" with patch( "api_snapshot.recorder.recorder.requests.Session.request" ) as mock_request: mock_response = MagicMock() mock_response.status_code = 200 mock_response.headers = {} mock_response.text = "{}" mock_request.return_value = mock_response config = [ {"method": "GET", "url": "https://api.example.com/1"}, {"method": "POST", "url": "https://api.example.com/2"}, {"method": "DELETE", "url": "https://api.example.com/3"}, ] pairs = record_multiple(requests_config=config) assert len(pairs) == 3 assert pairs[0].request.method == "GET" assert pairs[1].request.method == "POST" assert pairs[2].request.method == "DELETE"