@@ -66,75 +66,117 @@ def test_invalid_authorization_various_types(auth_type_name):
6666def test_checkout_api_exception ():
6767 response = Mock ()
6868 response .status_code = 400
69- response .text = '{"error_type": "request_invalid", "error_codes": ["invalid_field"]}'
69+ response .text = '{"error_type": "request_invalid", "error_codes": ["invalid_field"], "request_id": "req_123456" }'
7070 response .json .return_value = {
7171 "error_type" : "request_invalid" ,
72- "error_codes" : ["invalid_field" ]
72+ "error_codes" : ["invalid_field" ],
73+ "request_id" : "req_123456"
7374 }
75+ response .headers = {}
7476
7577 with pytest .raises (CheckoutApiException ) as exc_info :
7678 raise CheckoutApiException (response )
7779 exception = exc_info .value
7880 assert exception .http_metadata .status_code == 400
7981 assert exception .error_type == "request_invalid"
8082 assert exception .error_details == ["invalid_field" ]
83+ assert exception .request_id == "req_123456"
8184
8285
8386def test_checkout_api_exception_without_error_details ():
8487 response = Mock ()
8588 response .status_code = 500
86- response .text = '{"message": "Internal Server Error"}'
89+ response .text = '{"message": "Internal Server Error", "request_id": "req_789012" }'
8790 response .json .return_value = {
88- "message" : "Internal Server Error"
91+ "message" : "Internal Server Error" ,
92+ "request_id" : "req_789012"
8993 }
94+ response .headers = {}
9095
9196 with pytest .raises (CheckoutApiException ) as exc_info :
9297 raise CheckoutApiException (response )
9398 exception = exc_info .value
9499 assert exception .http_metadata .status_code == 500
95100 assert exception .error_type is None
96101 assert exception .error_details is None
102+ assert exception .request_id == "req_789012"
97103
98104
99105def test_checkout_api_exception_empty_response ():
100106 response = Mock ()
101107 response .status_code = 404
102108 response .text = ''
103- response .json . return_value = {}
109+ response .headers = {'Cko-Request-Id' : 'header_req_345678' }
104110
105111 with pytest .raises (CheckoutApiException ) as exc_info :
106112 raise CheckoutApiException (response )
107113 exception = exc_info .value
108114 assert exception .http_metadata .status_code == 404
109115 assert exception .error_type is None
110116 assert exception .error_details is None
117+ assert exception .request_id == "header_req_345678"
111118
112119
113120def test_checkout_api_exception_non_json_response ():
114121 response = Mock ()
115122 response .status_code = 502
116123 response .text = 'Bad Gateway'
117124 response .json .side_effect = ValueError ("No JSON object could be decoded" )
125+ response .headers = {'Cko-Request-Id' : 'header_req_502502' }
118126
119127 with pytest .raises (CheckoutApiException ) as exc_info :
120128 raise CheckoutApiException (response )
121129 exception = exc_info .value
122130 assert exception .http_metadata .status_code == 502
123131 assert exception .error_type is None
124132 assert exception .error_details is None
133+ assert exception .request_id == "header_req_502502"
134+
135+
136+ def test_checkout_api_exception_request_id_from_header_fallback ():
137+ response = Mock ()
138+ response .status_code = 400
139+ response .text = '{"error_type": "request_invalid", "error_codes": ["invalid_field"]}'
140+ response .json .return_value = {
141+ "error_type" : "request_invalid" ,
142+ "error_codes" : ["invalid_field" ]
143+ }
144+ response .headers = {'Cko-Request-Id' : '0120e756-6d00-453c-a398-ff1643f9a873' }
145+
146+ with pytest .raises (CheckoutApiException ) as exc_info :
147+ raise CheckoutApiException (response )
148+ exception = exc_info .value
149+ assert exception .request_id == "0120e756-6d00-453c-a398-ff1643f9a873"
150+ assert exception .error_type == "request_invalid"
151+ assert exception .error_details == ["invalid_field" ]
152+
153+
154+ def test_checkout_api_exception_no_request_id_anywhere ():
155+ response = Mock ()
156+ response .status_code = 400
157+ response .text = '{"error_type": "request_invalid"}'
158+ response .json .return_value = {"error_type" : "request_invalid" }
159+ response .headers = {} # Sin Cko-Request-Id
160+
161+ with pytest .raises (CheckoutApiException ) as exc_info :
162+ raise CheckoutApiException (response )
163+ exception = exc_info .value
164+ assert exception .request_id is None
165+ assert exception .error_type == "request_invalid"
125166
126167
127168@pytest .mark .parametrize ("status_code" , [400 , 401 , 403 , 404 , 500 ])
128169def test_checkout_api_exception_various_status_codes (status_code ):
129170 response = Mock ()
130171 response .status_code = status_code
131172 response .text = ''
132- response .json . return_value = {}
173+ response .headers = {'Cko-Request-Id' : f'req_ { status_code } ' }
133174
134175 with pytest .raises (CheckoutApiException ) as exc_info :
135176 raise CheckoutApiException (response )
136177 exception = exc_info .value
137178 assert exception .http_metadata .status_code == status_code
179+ assert exception .request_id == f'req_{ status_code } '
138180
139181
140182def test_map_to_http_metadata ():
@@ -150,28 +192,46 @@ def test_map_to_http_metadata():
150192def test_checkout_api_exception_message ():
151193 response = Mock ()
152194 response .status_code = 400
153- response .text = '{"error_type": "invalid_request", "error_codes": ["bad_request"]}'
195+ response .text = '{"error_type": "invalid_request", "error_codes": ["bad_request"], "request_id": "msg_req_400" }'
154196 response .json .return_value = {
155197 "error_type" : "invalid_request" ,
156- "error_codes" : ["bad_request" ]
198+ "error_codes" : ["bad_request" ],
199+ "request_id" : "msg_req_400"
157200 }
201+ response .headers = {}
158202
159203 with pytest .raises (CheckoutApiException ) as exc_info :
160204 raise CheckoutApiException (response )
161205 exception = exc_info .value
162206 expected_message = "The API response status code (400) does not indicate success."
163207 assert str (exception ) == expected_message
208+ assert exception .request_id == "msg_req_400"
164209
165210
166211def test_checkout_api_exception_no_response_text ():
167212 response = Mock ()
168213 response .status_code = 400
169214 response .text = None
170- response .json . return_value = {}
215+ response .headers = {'Cko-Request-Id' : 'no_text_req_id' }
171216
172217 with pytest .raises (CheckoutApiException ) as exc_info :
173218 raise CheckoutApiException (response )
174219 exception = exc_info .value
175220 assert exception .http_metadata .status_code == 400
176221 assert exception .error_type is None
177222 assert exception .error_details is None
223+ assert exception .request_id == "no_text_req_id"
224+
225+
226+ def test_checkout_api_exception_logs_on_json_parse_error (caplog ):
227+ response = Mock ()
228+ response .status_code = 502
229+ response .text = 'Bad Gateway'
230+ response .json .side_effect = ValueError ("No JSON object could be decoded" )
231+ response .headers = {'Cko-Request-Id' : 'header_req_logging' }
232+
233+ with caplog .at_level ("ERROR" ):
234+ with pytest .raises (CheckoutApiException ):
235+ raise CheckoutApiException (response )
236+
237+ assert any ("Failed to parse response JSON payload" in m for m in caplog .messages )
0 commit comments