@@ -317,6 +317,71 @@ def test_transaction_does_not_retry_on_bad_bin_error_in_response(
317
317
318
318
assert card ._transact .call_count == 1
319
319
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
+
320
385
@pytest .mark .parametrize (
321
386
'rsp_expected,return_type' ,
322
387
[
0 commit comments