44
55* Module-level functions in :mod:`stream_chat.webhook`:
66
7- * primitives - ``ungzip_payload ``, ``decode_sqs_payload``,
7+ * primitives - ``gunzip_payload ``, ``decode_sqs_payload``,
88 ``decode_sns_payload``, ``verify_signature``, ``parse_event``
99 * composite helpers - ``verify_and_parse_webhook``, ``parse_sqs``,
1010 ``parse_sns``
2727import pytest
2828
2929from stream_chat import StreamChat , StreamChatAsync
30- from stream_chat .base .exceptions import WebhookSignatureError
30+ from stream_chat .base .exceptions import (
31+ INVALID_WEBHOOK_GZIP_FAILED ,
32+ INVALID_WEBHOOK_INVALID_BASE64 ,
33+ INVALID_WEBHOOK_INVALID_JSON ,
34+ INVALID_WEBHOOK_SIGNATURE_MISMATCH ,
35+ InvalidWebhookError ,
36+ )
3137from stream_chat .webhook import (
3238 GZIP_MAGIC ,
3339 decode_sns_payload ,
3440 decode_sqs_payload ,
41+ gunzip_payload ,
3542 parse_event ,
3643 parse_sns ,
3744 parse_sqs ,
38- ungzip_payload ,
3945 verify_and_parse_webhook ,
4046 verify_signature ,
4147)
@@ -66,31 +72,31 @@ def sync_client() -> StreamChat:
6672 return StreamChat (api_key = API_KEY , api_secret = API_SECRET )
6773
6874
69- class TestUngzipPayload :
75+ class TestGunzipPayload :
7076 def test_passthrough_plain_bytes (self ):
71- assert ungzip_payload (JSON_BODY ) == JSON_BODY
77+ assert gunzip_payload (JSON_BODY ) == JSON_BODY
7278
7379 def test_passthrough_str_input (self ):
74- assert ungzip_payload (JSON_BODY .decode ("utf-8" )) == JSON_BODY
80+ assert gunzip_payload (JSON_BODY .decode ("utf-8" )) == JSON_BODY
7581
7682 def test_inflates_gzip_bytes (self ):
77- assert ungzip_payload (_gzip (JSON_BODY )) == JSON_BODY
83+ assert gunzip_payload (_gzip (JSON_BODY )) == JSON_BODY
7884
7985 def test_returns_bytes (self ):
80- assert isinstance (ungzip_payload (JSON_BODY ), bytes )
81- assert isinstance (ungzip_payload (_gzip (JSON_BODY )), bytes )
86+ assert isinstance (gunzip_payload (JSON_BODY ), bytes )
87+ assert isinstance (gunzip_payload (_gzip (JSON_BODY )), bytes )
8288
8389 def test_empty_input (self ):
84- assert ungzip_payload (b"" ) == b""
90+ assert gunzip_payload (b"" ) == b""
8591
8692 def test_short_input_below_magic_length (self ):
87- assert ungzip_payload (b"ab" ) == b"ab"
93+ assert gunzip_payload (b"ab" ) == b"ab"
8894
8995 def test_truncated_gzip_with_magic_raises (self ):
9096 bad = GZIP_MAGIC + b"\x00 \x00 \x00 "
91- with pytest .raises (WebhookSignatureError ) as exc_info :
92- ungzip_payload (bad )
93- assert "decompress" in str (exc_info .value ). lower ()
97+ with pytest .raises (InvalidWebhookError ) as exc_info :
98+ gunzip_payload (bad )
99+ assert str (exc_info .value ) == INVALID_WEBHOOK_GZIP_FAILED
94100
95101
96102class TestDecodeSqsPayload :
@@ -110,9 +116,9 @@ def test_accepts_bytes_input(self):
110116 assert decode_sqs_payload (encoded ) == JSON_BODY
111117
112118 def test_invalid_base64_raises (self ):
113- with pytest .raises (WebhookSignatureError ) as exc_info :
119+ with pytest .raises (InvalidWebhookError ) as exc_info :
114120 decode_sqs_payload ("!!!not-valid-base64!!!" )
115- assert "base64" in str (exc_info .value ). lower ()
121+ assert str (exc_info .value ) == INVALID_WEBHOOK_INVALID_BASE64
116122
117123
118124def _sns_envelope (inner_message : str ) -> str :
@@ -178,7 +184,7 @@ def test_non_ascii_bytes_signature_returns_false(self):
178184 assert verify_signature (JSON_BODY , b"\xff " * 32 , API_SECRET ) is False
179185
180186 def test_non_ascii_str_signature_returns_false (self ):
181- assert verify_signature (JSON_BODY , "\u2603 " * 64 , API_SECRET ) is False
187+ assert verify_signature (JSON_BODY , "☃ " * 64 , API_SECRET ) is False
182188
183189 def test_non_string_signature_returns_false (self ):
184190 assert verify_signature (JSON_BODY , 12345 , API_SECRET ) is False # type: ignore[arg-type]
@@ -196,8 +202,9 @@ def test_unknown_event_type_still_parses(self):
196202 assert parse_event (body ) == {"type" : "a.future.event" , "custom" : 42 }
197203
198204 def test_malformed_json_raises (self ):
199- with pytest .raises (json . JSONDecodeError ) :
205+ with pytest .raises (InvalidWebhookError ) as exc_info :
200206 parse_event (b"not json" )
207+ assert str (exc_info .value ) == INVALID_WEBHOOK_INVALID_JSON
201208
202209
203210class TestVerifyAndParseWebhook :
@@ -215,30 +222,30 @@ def test_returns_dict(self):
215222 assert isinstance (result , dict )
216223
217224 def test_signature_mismatch_raises (self ):
218- with pytest .raises (WebhookSignatureError ) as exc_info :
225+ with pytest .raises (InvalidWebhookError ) as exc_info :
219226 verify_and_parse_webhook (JSON_BODY , "0" * 64 , API_SECRET )
220- assert "invalid webhook signature" in str (exc_info .value ). lower ()
227+ assert str (exc_info .value ) == INVALID_WEBHOOK_SIGNATURE_MISMATCH
221228
222229 def test_signature_must_be_over_uncompressed_bytes (self ):
223230 compressed = _gzip (JSON_BODY )
224231 sig_over_compressed = _sign (compressed )
225- with pytest .raises (WebhookSignatureError ):
232+ with pytest .raises (InvalidWebhookError ):
226233 verify_and_parse_webhook (compressed , sig_over_compressed , API_SECRET )
227234
228235 def test_wrong_secret_raises (self ):
229236 sig = _sign (JSON_BODY , secret = "other" )
230- with pytest .raises (WebhookSignatureError ):
237+ with pytest .raises (InvalidWebhookError ):
231238 verify_and_parse_webhook (JSON_BODY , sig , API_SECRET )
232239
233240 def test_signature_can_be_bytes (self ):
234241 sig = _sign (JSON_BODY ).encode ()
235242 assert verify_and_parse_webhook (JSON_BODY , sig , API_SECRET ) == EVENT_DICT
236243
237244 def test_malformed_signature_surfaces_as_webhook_error (self ):
238- with pytest .raises (WebhookSignatureError ):
245+ with pytest .raises (InvalidWebhookError ):
239246 verify_and_parse_webhook (JSON_BODY , b"\xff " * 32 , API_SECRET )
240- with pytest .raises (WebhookSignatureError ):
241- verify_and_parse_webhook (JSON_BODY , "\u2603 " * 64 , API_SECRET )
247+ with pytest .raises (InvalidWebhookError ):
248+ verify_and_parse_webhook (JSON_BODY , "☃ " * 64 , API_SECRET )
242249
243250
244251class TestParseSqs :
@@ -280,7 +287,7 @@ def test_parse_sns(self, sync_client: StreamChat):
280287 assert sync_client .parse_sns (wrapped ) == EVENT_DICT
281288
282289 def test_signature_mismatch_via_client (self , sync_client : StreamChat ):
283- with pytest .raises (WebhookSignatureError ):
290+ with pytest .raises (InvalidWebhookError ):
284291 sync_client .verify_and_parse_webhook (JSON_BODY , "0" * 64 )
285292
286293
0 commit comments