77import static org .junit .Assert .assertTrue ;
88import static org .mockito .Mockito .mock ;
99
10+ import com .google .common .util .concurrent .Uninterruptibles ;
1011import com .google .protobuf .ByteString ;
1112import java .lang .reflect .Field ;
1213import java .lang .reflect .InvocationTargetException ;
@@ -551,6 +552,7 @@ public void testGetBlockProcessesOneBlock() throws Exception {
551552 @ Test (timeout = 8000 )
552553 @ SuppressWarnings ("unchecked" )
553554 public void testGetBlockShutdownPaths () throws Exception {
555+ boolean origFlag = getFlag ();
554556 long origID = atomicLong ("ID" ).get ();
555557 long origRemote = atomicLong ("remoteBlockNum" ).get ();
556558 Field clientField = getField ("databaseGrpcClient" );
@@ -560,6 +562,7 @@ public void testGetBlockShutdownPaths() throws Exception {
560562
561563 LinkedBlockingDeque <Block > queue =
562564 (LinkedBlockingDeque <Block >) getField ("blockQueue" ).get (solidityNode );
565+ Thread worker = null ;
563566 try {
564567 // ── Part 1: interrupt during blockQueue.put() ──────────────────────────
565568 // Fill the queue to capacity so the next put() call blocks.
@@ -581,18 +584,18 @@ public void testGetBlockShutdownPaths() throws Exception {
581584 Method getBlockM = SolidityNode .class .getDeclaredMethod ("getBlock" );
582585 getBlockM .setAccessible (true );
583586 AtomicReference <Throwable > workerFailure = new AtomicReference <>();
584- Thread t = new Thread (() -> {
587+ worker = new Thread (() -> {
585588 try {
586589 getBlockM .invoke (solidityNode );
587590 } catch (Exception e ) {
588591 workerFailure .set (e );
589592 }
590593 });
591- t .start ();
594+ worker .start ();
592595 Thread .sleep (200 ); // let the thread block inside blockQueue.put()
593- t .interrupt (); // simulate ExecutorService.shutdownNow()
594- t .join (4000 );
595- assertFalse ("getBlock must exit cleanly when interrupted during put()" , t .isAlive ());
596+ worker .interrupt (); // simulate ExecutorService.shutdownNow()
597+ worker .join (4000 );
598+ assertFalse ("getBlock must exit cleanly when interrupted during put()" , worker .isAlive ());
596599 Assert .assertNull ("getBlock worker failed" , workerFailure .get ());
597600 queue .clear ();
598601 setFlag (true );
@@ -612,7 +615,8 @@ public void testGetBlockShutdownPaths() throws Exception {
612615 // Must return without throwing and without infinite retry.
613616 getBlockM .invoke (solidityNode );
614617 } finally {
615- setFlag (true );
618+ stopWorker (worker );
619+ setFlag (origFlag );
616620 queue .clear ();
617621 atomicLong ("ID" ).set (origID );
618622 atomicLong ("remoteBlockNum" ).set (origRemote );
@@ -668,12 +672,12 @@ public void testProcessSolidityBlockProcessesQueuedBlock() throws Exception {
668672 */
669673 @ Test (timeout = 8000 )
670674 public void testProcessSolidityBlockHandlesInterrupt () throws Exception {
675+ boolean origFlag = getFlag ();
671676 TronNetDelegate mockDelegate = mock (TronNetDelegate .class );
672677 Mockito .when (mockDelegate .isHitDown ()).thenReturn (false );
673678
674679 Field delegateField = getField ("tronNetDelegate" );
675680 Object origDelegate = delegateField .get (solidityNode );
676- delegateField .set (solidityNode , mockDelegate );
677681
678682 Method m = SolidityNode .class .getDeclaredMethod ("processSolidityBlock" );
679683 m .setAccessible (true );
@@ -686,20 +690,32 @@ public void testProcessSolidityBlockHandlesInterrupt() throws Exception {
686690 }
687691 });
688692 try {
693+ delegateField .set (solidityNode , mockDelegate );
689694 t .start ();
690695 Thread .sleep (150 ); // let the thread enter blockQueue.poll(1000 ms)
691696 t .interrupt ();
692697 t .join (5000 );
693698 assertFalse ("processSolidityBlock must exit after interrupt" , t .isAlive ());
694699 Assert .assertNull ("processSolidityBlock worker failed" , workerFailure .get ());
695700 } finally {
696- setFlag (true );
701+ stopWorker (t );
702+ setFlag (origFlag );
697703 delegateField .set (solidityNode , origDelegate );
698704 }
699705 }
700706
701707 // ── private helpers ──────────────────────────────────────────────────────────
702708
709+ private void stopWorker (Thread worker ) throws Exception {
710+ // A timeout may interrupt the test thread before it reaches the normal shutdown path.
711+ setFlag (false );
712+ if (worker != null ) {
713+ worker .interrupt ();
714+ Uninterruptibles .joinUninterruptibly (worker , 5 , TimeUnit .SECONDS );
715+ assertFalse ("Test worker must stop before restoring shared state" , worker .isAlive ());
716+ }
717+ }
718+
703719 private static Field getField (String name ) throws Exception {
704720 Field f = SolidityNode .class .getDeclaredField (name );
705721 f .setAccessible (true );
0 commit comments