1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.portal.service.daemon;
35
36 import java.lang.management.ManagementFactory;
37 import java.lang.management.ThreadInfo;
38 import java.lang.management.ThreadMXBean;
39 import java.time.Duration;
40 import java.time.Instant;
41 import java.util.concurrent.BrokenBarrierException;
42 import java.util.concurrent.CyclicBarrier;
43 import java.util.concurrent.TimeUnit;
44 import java.util.concurrent.TimeoutException;
45
46 import fr.paris.lutece.portal.service.plugin.PluginService;
47 import fr.paris.lutece.portal.service.util.AppLogService;
48 import fr.paris.lutece.test.LuteceTestCase;
49
50 public class ThreadLauncherDaemonTest extends LuteceTestCase
51 {
52 private static final long TIMEOUT_DURATION = 10L;
53 private static final TimeUnit TIMEOUT_TIMEUNIT = TimeUnit.SECONDS;
54 private boolean _runnableTimedOut;
55 private Boolean _bThreadLauncherDaemonInitialState;
56 private DaemonEntry _threadLauncherDaemonEntry;
57
58 @Override
59 protected void setUp( ) throws Exception
60 {
61 super.setUp( );
62
63 AppLogService.info( "Ensure ThreadLauncherDeamon is started" );
64 for ( DaemonEntry daemonEntry : AppDaemonService.getDaemonEntries( ) )
65 {
66 if ( daemonEntry.getId( ).equals( "threadLauncherDaemon" ) )
67 {
68 _threadLauncherDaemonEntry = daemonEntry;
69 _bThreadLauncherDaemonInitialState = daemonEntry.isRunning( );
70 break;
71 }
72 }
73 assertNotNull( "Did not find threadLauncherDaemon daemon", _bThreadLauncherDaemonInitialState );
74 AppDaemonService.startDaemon( "threadLauncherDaemon" );
75 }
76
77 @Override
78 protected void tearDown( ) throws Exception
79 {
80
81 AppLogService.info( "restore threadLauncherDaemon state ( {} )", _bThreadLauncherDaemonInitialState );
82 if ( !_bThreadLauncherDaemonInitialState.booleanValue( ) )
83 {
84 AppDaemonService.stopDaemon( "threadLauncherDaemon" );
85 }
86 super.tearDown( );
87 }
88
89 public void testAddItemToQueue( ) throws InterruptedException, BrokenBarrierException, TimeoutException
90 {
91 CyclicBarrier barrier = new CyclicBarrier( 2 );
92 _runnableTimedOut = false;
93
94 dumpStateWhileWaiting( 0L );
95
96 Instant start = Instant.now( );
97 ThreadLauncherDaemon.addItemToQueue( ( ) -> {
98 try
99 {
100 AppLogService.info( "testAddItemToQueue: Inside the task, going to await" );
101 barrier.await( TIMEOUT_DURATION, TIMEOUT_TIMEUNIT );
102 }
103 catch( InterruptedException | BrokenBarrierException | TimeoutException e )
104 {
105 _runnableTimedOut = true;
106 }
107 }, "key", PluginService.getCore( ) );
108
109 dumpStateWhileWaiting( 500L );
110
111 barrier.await( TIMEOUT_DURATION, TIMEOUT_TIMEUNIT );
112 AppLogService.info( "ThreadLauncherDaemonTest#testAddItemToQueue : task executed after {} ms",
113 ( ) -> Duration.between( start, Instant.now( ) ).toMillis( ) );
114 AppLogService.info( "Last Run Logs : {}", _threadLauncherDaemonEntry.getLastRunLogs( ) );
115 assertFalse( _runnableTimedOut );
116 }
117
118 private void dumpStateWhileWaiting( long lWait ) throws InterruptedException
119 {
120
121 Thread.sleep( lWait );
122 final StringBuilder dump = new StringBuilder( );
123 final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean( );
124 final ThreadInfo [ ] threadInfos = threadMXBean.getThreadInfo( threadMXBean.getAllThreadIds( ), 100 );
125 for ( ThreadInfo threadInfo : threadInfos )
126 {
127 dump.append( '"' );
128 dump.append( threadInfo.getThreadName( ) );
129 dump.append( "\" " );
130 final Thread.State state = threadInfo.getThreadState( );
131 dump.append( "\n java.lang.Thread.State: " );
132 dump.append( state );
133 final StackTraceElement [ ] stackTraceElements = threadInfo.getStackTrace( );
134 for ( final StackTraceElement stackTraceElement : stackTraceElements )
135 {
136 dump.append( "\n at " );
137 dump.append( stackTraceElement );
138 }
139 dump.append( "\n\n" );
140 }
141 AppLogService.info( "Current state : {}", dump );
142 }
143 }