@@ -317,6 +317,71 @@ def test_transaction_does_not_retry_on_bad_bin_error_in_response(
317317
318318 assert card ._transact .call_count == 1
319319
320+ @pytest .mark .parametrize ('num_heartbeats,debug_enabled' , [
321+ (1 , False ),
322+ (4 , False ),
323+ (notecard .CARD_TRANSACTION_RETRIES + 1 , False ),
324+ (1 , True ),
325+ (4 , True ),
326+ (notecard .CARD_TRANSACTION_RETRIES + 1 , True ),
327+ ])
328+ def test_transaction_continues_after_heartbeat_to_get_valid_response (
329+ self , arrange_transaction_test , num_heartbeats , debug_enabled ):
330+ card = arrange_transaction_test ()
331+ card ._debug = debug_enabled
332+ req = {"req" : "note.add" }
333+
334+ # num_heartbeats of heartbeat responses followed by valid response
335+ heartbeat_response = b'{"err":"{heartbeat}","status":"testing"}\r \n '
336+ json_responses = [{'err' : '{heartbeat}' , 'status' : 'testing' }] * num_heartbeats + [{'total' : 42 }]
337+
338+ valid_response = b'{"total":42}\r \n '
339+ card ._transact .side_effect = [heartbeat_response ] * num_heartbeats + [valid_response ]
340+
341+ with patch ('notecard.notecard.json.loads' ) as mock_loads :
342+ mock_loads .side_effect = json_responses
343+ if debug_enabled :
344+ with patch ('builtins.print' ) as mock_print :
345+ result = card .Transaction (req )
346+ # Verify debug messages were printed for each heartbeat
347+ assert mock_print .call_count >= num_heartbeats
348+ else :
349+ result = card .Transaction (req )
350+
351+ assert card ._transact .call_count == num_heartbeats + 1
352+ assert result == {'total' : 42 }
353+
354+ def test_transaction_debug_heartbeat_with_and_without_status (
355+ self , arrange_transaction_test ):
356+ card = arrange_transaction_test ()
357+ card ._debug = True
358+ req = {"req" : "note.add" }
359+
360+ # First heartbeat has a status field, second doesn't, then valid response
361+ heartbeat_with_status = b'{"err":"{heartbeat}","status":"testing stsafe"}\r \n '
362+ heartbeat_without_status = b'{"err":"{heartbeat}"}\r \n '
363+ valid_response = b'{"total":42}\r \n '
364+ card ._transact .side_effect = [heartbeat_with_status , heartbeat_without_status , valid_response ]
365+
366+ json_responses = [
367+ {'err' : '{heartbeat}' , 'status' : 'testing stsafe' },
368+ {'err' : '{heartbeat}' },
369+ {'total' : 42 }
370+ ]
371+
372+ with patch ('notecard.notecard.json.loads' ) as mock_loads :
373+ mock_loads .side_effect = json_responses
374+ with patch ('builtins.print' ) as mock_print :
375+ result = card .Transaction (req )
376+
377+ # Verify the debug message was printed for first heartbeat (has status)
378+ mock_print .assert_any_call ('[DEBUG] testing stsafe' )
379+ # For second heartbeat (no status), exception is silently ignored (pass)
380+ # So we should only see one debug print call
381+ debug_calls = [call for call in mock_print .call_args_list if '[DEBUG]' in str (call )]
382+ assert len (debug_calls ) == 1
383+ assert result == {'total' : 42 }
384+
320385 @pytest .mark .parametrize (
321386 'rsp_expected,return_type' ,
322387 [
0 commit comments