44import io
55from typing import TYPE_CHECKING
66
7+ import brotli
8+ import pytest
79from werkzeug import Request , Response
810
911from apify_client import ApifyClient , ApifyClientAsync
1012
1113if TYPE_CHECKING :
1214 from pytest_httpserver import HTTPServer
1315
16+ from apify_client .types import HttpCompressionAlgorithm
17+
1418_MOCKED_KVS_ID = 'test_kvs_id'
1519_RECORD_PATH = f'/v2/key-value-stores/{ _MOCKED_KVS_ID } /records/f'
1620
1721
22+ @pytest .fixture (
23+ params = [
24+ pytest .param (('gzip' , 'gzip' ), id = 'gzip' ),
25+ pytest .param (('brotli' , 'br' ), id = 'brotli' ),
26+ ]
27+ )
28+ def compression_case (request : pytest .FixtureRequest ) -> tuple [HttpCompressionAlgorithm , str ]:
29+ """Run each test over both supported request-body compression algorithms, as (algorithm, content-encoding)."""
30+ return request .param
31+
32+
1833def decode_body (request : Request ) -> bytes :
34+ """Decompress a captured request body according to its `Content-Encoding`."""
1935 raw = request .get_data ()
20- return gzip .decompress (raw ) if request .headers .get ('Content-Encoding' ) == 'gzip' else raw
36+ encoding = request .headers .get ('Content-Encoding' )
37+ if encoding == 'gzip' :
38+ return gzip .decompress (raw )
39+ if encoding == 'br' :
40+ return brotli .decompress (raw )
41+ return raw
2142
2243
23- def test_set_record_reads_file_like_value_sync (httpserver : HTTPServer ) -> None :
44+ def test_set_record_reads_file_like_value_sync (
45+ httpserver : HTTPServer , compression_case : tuple [HttpCompressionAlgorithm , str ]
46+ ) -> None :
2447 """Regression test: a file-like value is read and its bytes are uploaded, not passed through unread."""
48+ algorithm , content_encoding = compression_case
2549 captured_requests : list [Request ] = []
2650
2751 def capture_request (request : Request ) -> Response :
@@ -31,17 +55,21 @@ def capture_request(request: Request) -> Response:
3155 httpserver .expect_request (_RECORD_PATH , method = 'PUT' ).respond_with_handler (capture_request )
3256
3357 api_url = httpserver .url_for ('/' ).removesuffix ('/' )
34- client = ApifyClient (token = 'test_token' , api_url = api_url )
58+ client = ApifyClient (token = 'test_token' , api_url = api_url , compression = algorithm )
3559
3660 client .key_value_store (_MOCKED_KVS_ID ).set_record ('f' , io .BytesIO (b'buffer data' ))
3761
3862 assert len (captured_requests ) == 1
63+ assert captured_requests [0 ].headers ['content-encoding' ] == content_encoding
3964 assert decode_body (captured_requests [0 ]) == b'buffer data'
4065 assert captured_requests [0 ].headers ['content-type' ] == 'application/octet-stream'
4166
4267
43- async def test_set_record_reads_file_like_value_async (httpserver : HTTPServer ) -> None :
68+ async def test_set_record_reads_file_like_value_async (
69+ httpserver : HTTPServer , compression_case : tuple [HttpCompressionAlgorithm , str ]
70+ ) -> None :
4471 """Regression test: a file-like value is read and its bytes are uploaded, not passed through unread."""
72+ algorithm , content_encoding = compression_case
4573 captured_requests : list [Request ] = []
4674
4775 def capture_request (request : Request ) -> Response :
@@ -51,17 +79,21 @@ def capture_request(request: Request) -> Response:
5179 httpserver .expect_request (_RECORD_PATH , method = 'PUT' ).respond_with_handler (capture_request )
5280
5381 api_url = httpserver .url_for ('/' ).removesuffix ('/' )
54- client = ApifyClientAsync (token = 'test_token' , api_url = api_url )
82+ client = ApifyClientAsync (token = 'test_token' , api_url = api_url , compression = algorithm )
5583
5684 await client .key_value_store (_MOCKED_KVS_ID ).set_record ('f' , io .BytesIO (b'buffer data' ))
5785
5886 assert len (captured_requests ) == 1
87+ assert captured_requests [0 ].headers ['content-encoding' ] == content_encoding
5988 assert decode_body (captured_requests [0 ]) == b'buffer data'
6089 assert captured_requests [0 ].headers ['content-type' ] == 'application/octet-stream'
6190
6291
63- def test_set_record_reads_stringio_value_sync (httpserver : HTTPServer ) -> None :
92+ def test_set_record_reads_stringio_value_sync (
93+ httpserver : HTTPServer , compression_case : tuple [HttpCompressionAlgorithm , str ]
94+ ) -> None :
6495 """Regression test: a text file-like value is read and uploaded as text/plain through the HTTP stack."""
96+ algorithm , content_encoding = compression_case
6597 captured_requests : list [Request ] = []
6698
6799 def capture_request (request : Request ) -> Response :
@@ -71,10 +103,11 @@ def capture_request(request: Request) -> Response:
71103 httpserver .expect_request (_RECORD_PATH , method = 'PUT' ).respond_with_handler (capture_request )
72104
73105 api_url = httpserver .url_for ('/' ).removesuffix ('/' )
74- client = ApifyClient (token = 'test_token' , api_url = api_url )
106+ client = ApifyClient (token = 'test_token' , api_url = api_url , compression = algorithm )
75107
76108 client .key_value_store (_MOCKED_KVS_ID ).set_record ('f' , io .StringIO ('buffer data' ))
77109
78110 assert len (captured_requests ) == 1
111+ assert captured_requests [0 ].headers ['content-encoding' ] == content_encoding
79112 assert decode_body (captured_requests [0 ]) == b'buffer data'
80113 assert captured_requests [0 ].headers ['content-type' ] == 'text/plain; charset=utf-8'
0 commit comments