11from __future__ import annotations
22
3+ import json
4+ import time
35from typing import TYPE_CHECKING
46
57import pytest
8+ from werkzeug import Response
69
710from apify_client ._errors import ApifyApiError
811from apify_client ._http_client import HTTPClient , HTTPClientAsync
912
1013if TYPE_CHECKING :
14+ from collections .abc import Iterator
15+
1116 from pytest_httpserver import HTTPServer
17+ from werkzeug import Request
1218
1319_TEST_PATH = '/errors'
1420_EXPECTED_MESSAGE = 'some_message'
1723 'invalidItems' : {'0' : ["should have required property 'name'" ], '1' : ["should have required property 'name'" ]}
1824}
1925
26+ RAW_ERROR = (
27+ b'{\n '
28+ b' "error": {\n '
29+ b' "type": "insufficient-permissions",\n '
30+ b' "message": "Insufficient permissions for the Actor run. Make sure you\' '
31+ b're passing a correct API token and that it has the required permissions."\n '
32+ b' }\n '
33+ b'}'
34+ )
35+
2036
2137@pytest .fixture
2238def test_endpoint (httpserver : HTTPServer ) -> str :
@@ -26,6 +42,22 @@ def test_endpoint(httpserver: HTTPServer) -> str:
2642 return str (httpserver .url_for (_TEST_PATH ))
2743
2844
45+ def streaming_handler (_request : Request ) -> Response :
46+ """Handler for streaming log requests."""
47+
48+ def generate_response () -> Iterator [bytes ]:
49+ for i in range (len (RAW_ERROR )):
50+ yield RAW_ERROR [i : i + 1 ]
51+ time .sleep (0.01 )
52+
53+ return Response (
54+ response = (RAW_ERROR [i : i + 1 ] for i in range (len (RAW_ERROR ))),
55+ status = 403 ,
56+ mimetype = 'application/octet-stream' ,
57+ headers = {'Content-Length' : str (len (RAW_ERROR ))},
58+ )
59+
60+
2961def test_client_apify_api_error_with_data (test_endpoint : str ) -> None :
3062 """Test that client correctly throws ApifyApiError with error data from response."""
3163 client = HTTPClient ()
@@ -48,3 +80,35 @@ async def test_async_client_apify_api_error_with_data(test_endpoint: str) -> Non
4880 assert e .value .message == _EXPECTED_MESSAGE
4981 assert e .value .type == _EXPECTED_TYPE
5082 assert e .value .data == _EXPECTED_DATA
83+
84+
85+ def test_client_apify_api_error_streamed (httpserver : HTTPServer ) -> None :
86+ """Test that client correctly throws ApifyApiError when the response has stream."""
87+
88+ error = json .loads (RAW_ERROR .decode ())
89+
90+ client = HTTPClient ()
91+
92+ httpserver .expect_request ('/stream_error' ).respond_with_handler (streaming_handler )
93+
94+ with pytest .raises (ApifyApiError ) as e :
95+ client .call (method = 'GET' , url = httpserver .url_for ('/stream_error' ), stream = True , parse_response = False )
96+
97+ assert e .value .message == error ['error' ]['message' ]
98+ assert e .value .type == error ['error' ]['type' ]
99+
100+
101+ async def test_async_client_apify_api_error_streamed (httpserver : HTTPServer ) -> None :
102+ """Test that async client correctly throws ApifyApiError when the response has stream."""
103+
104+ error = json .loads (RAW_ERROR .decode ())
105+
106+ client = HTTPClientAsync ()
107+
108+ httpserver .expect_request ('/stream_error' ).respond_with_handler (streaming_handler )
109+
110+ with pytest .raises (ApifyApiError ) as e :
111+ await client .call (method = 'GET' , url = httpserver .url_for ('/stream_error' ), stream = True , parse_response = False )
112+
113+ assert e .value .message == error ['error' ]['message' ]
114+ assert e .value .type == error ['error' ]['type' ]
0 commit comments