@@ -260,6 +260,83 @@ def test_url_building(self) -> None:
260260 # Test without leading slash
261261 assert request ._build_url ("concepts" ) == "https://api.example.com/v1/concepts"
262262
263+ def test_get_raw_request (self , request_handler : Request ) -> None :
264+ """Test get_raw returns full response with data and meta."""
265+ with respx .mock :
266+ respx .get ("https://api.example.com/v1/search" ).mock (
267+ return_value = Response (
268+ 200 ,
269+ json = {
270+ "success" : True ,
271+ "data" : {"concepts" : [{"concept_id" : 1 }]},
272+ "meta" : {"pagination" : {"page" : 1 , "total_pages" : 5 }},
273+ },
274+ )
275+ )
276+ result = request_handler .get_raw ("/search" )
277+ assert "data" in result
278+ assert "meta" in result
279+ assert result ["meta" ]["pagination" ]["page" ] == 1
280+ assert result ["meta" ]["pagination" ]["total_pages" ] == 5
281+
282+ def test_get_raw_with_params (self , request_handler : Request ) -> None :
283+ """Test get_raw passes query parameters correctly."""
284+ with respx .mock :
285+ route = respx .get ("https://api.example.com/v1/search" ).mock (
286+ return_value = Response (
287+ 200 ,
288+ json = {
289+ "data" : {"concepts" : []},
290+ "meta" : {"pagination" : {"page" : 2 , "has_next" : True }},
291+ },
292+ )
293+ )
294+
295+ result = request_handler .get_raw ("/search" , params = {"query" : "test" , "page" : 2 })
296+
297+ url_str = str (route .calls [0 ].request .url )
298+ assert "query=test" in url_str
299+ assert "page=2" in url_str
300+ assert result ["meta" ]["pagination" ]["page" ] == 2
301+
302+ def test_get_raw_error_parsing (self , request_handler : Request ) -> None :
303+ """Test get_raw raises errors correctly."""
304+ with respx .mock :
305+ respx .get ("https://api.example.com/v1/test" ).mock (
306+ return_value = Response (
307+ 404 ,
308+ json = {"error" : {"message" : "Not found" }},
309+ headers = {"X-Request-Id" : "req_123" },
310+ )
311+ )
312+ with pytest .raises (NotFoundError ) as exc_info :
313+ request_handler .get_raw ("/test" )
314+ assert exc_info .value .request_id == "req_123"
315+
316+ def test_get_raw_rate_limit (self , request_handler : Request ) -> None :
317+ """Test get_raw handles rate limit with retry-after."""
318+ with respx .mock :
319+ respx .get ("https://api.example.com/v1/test" ).mock (
320+ return_value = Response (
321+ 429 ,
322+ json = {"error" : {"message" : "Rate limited" }},
323+ headers = {"Retry-After" : "45" },
324+ )
325+ )
326+ with pytest .raises (RateLimitError ) as exc_info :
327+ request_handler .get_raw ("/test" )
328+ assert exc_info .value .retry_after == 45
329+
330+ def test_get_raw_json_decode_error (self , request_handler : Request ) -> None :
331+ """Test get_raw handles invalid JSON."""
332+ with respx .mock :
333+ respx .get ("https://api.example.com/v1/test" ).mock (
334+ return_value = Response (200 , content = b"not json" )
335+ )
336+ with pytest .raises (OMOPHubError ) as exc_info :
337+ request_handler .get_raw ("/test" )
338+ assert "Invalid JSON" in str (exc_info .value )
339+
263340
264341class TestAsyncRequest :
265342 """Tests for asynchronous AsyncRequest class."""
@@ -407,3 +484,85 @@ async def test_async_rate_limit_error(self, request_handler: AsyncRequest) -> No
407484 await request_handler .get ("/test" )
408485
409486 assert exc_info .value .retry_after == 30
487+
488+ @pytest .mark .asyncio
489+ async def test_async_get_raw_request (self , request_handler : AsyncRequest ) -> None :
490+ """Test async get_raw returns full response with data and meta."""
491+ with respx .mock :
492+ respx .get ("https://api.example.com/v1/search" ).mock (
493+ return_value = Response (
494+ 200 ,
495+ json = {
496+ "data" : {"concepts" : [{"concept_id" : 42 }]},
497+ "meta" : {"pagination" : {"page" : 1 , "has_next" : True , "total_pages" : 3 }},
498+ },
499+ )
500+ )
501+ result = await request_handler .get_raw ("/search" )
502+ assert "data" in result
503+ assert "meta" in result
504+ assert result ["meta" ]["pagination" ]["page" ] == 1
505+ assert result ["meta" ]["pagination" ]["has_next" ] is True
506+
507+ @pytest .mark .asyncio
508+ async def test_async_get_raw_with_params (self , request_handler : AsyncRequest ) -> None :
509+ """Test async get_raw passes query parameters correctly."""
510+ with respx .mock :
511+ route = respx .get ("https://api.example.com/v1/search" ).mock (
512+ return_value = Response (
513+ 200 ,
514+ json = {
515+ "data" : {"concepts" : []},
516+ "meta" : {"pagination" : {"page" : 3 }},
517+ },
518+ )
519+ )
520+
521+ result = await request_handler .get_raw ("/search" , params = {"page" : 3 })
522+
523+ url_str = str (route .calls [0 ].request .url )
524+ assert "page=3" in url_str
525+ assert result ["meta" ]["pagination" ]["page" ] == 3
526+
527+ @pytest .mark .asyncio
528+ async def test_async_get_raw_error (self , request_handler : AsyncRequest ) -> None :
529+ """Test async get_raw raises errors correctly."""
530+ with respx .mock :
531+ respx .get ("https://api.example.com/v1/test" ).mock (
532+ return_value = Response (
533+ 404 ,
534+ json = {"error" : {"message" : "Not found" }},
535+ headers = {"X-Request-Id" : "req_async_456" },
536+ )
537+ )
538+ with pytest .raises (NotFoundError ) as exc_info :
539+ await request_handler .get_raw ("/test" )
540+ assert exc_info .value .request_id == "req_async_456"
541+
542+ @pytest .mark .asyncio
543+ async def test_async_get_raw_rate_limit (self , request_handler : AsyncRequest ) -> None :
544+ """Test async get_raw handles rate limit with retry-after."""
545+ with respx .mock :
546+ respx .get ("https://api.example.com/v1/test" ).mock (
547+ return_value = Response (
548+ 429 ,
549+ json = {"error" : {"message" : "Rate limited" }},
550+ headers = {"Retry-After" : "60" },
551+ )
552+ )
553+ with pytest .raises (RateLimitError ) as exc_info :
554+ await request_handler .get_raw ("/test" )
555+ assert exc_info .value .retry_after == 60
556+
557+ @pytest .mark .asyncio
558+ async def test_async_get_raw_json_decode_error (
559+ self , request_handler : AsyncRequest
560+ ) -> None :
561+ """Test async get_raw handles invalid JSON."""
562+ with respx .mock :
563+ respx .get ("https://api.example.com/v1/test" ).mock (
564+ return_value = Response (200 , content = b"invalid json response" )
565+ )
566+ with pytest .raises (OMOPHubError ) as exc_info :
567+ await request_handler .get_raw ("/test" )
568+ assert "Invalid JSON" in str (exc_info .value )
0 commit comments