@@ -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