77import static org .easymock .EasyMock .isA ;
88
99import java .io .File ;
10+ import java .io .IOException ;
11+ import java .util .List ;
1012import java .util .concurrent .ThreadFactory ;
1113
1214import org .jooby .spi .HttpHandler ;
4244import io .netty .util .concurrent .DefaultThreadFactory ;
4345import io .netty .util .concurrent .EventExecutorGroup ;
4446import io .netty .util .concurrent .Future ;
47+ import io .netty .util .concurrent .GenericFutureListener ;
4548
4649@ RunWith (PowerMockRunner .class )
4750@ PrepareForTest ({NettyServer .class , NioEventLoopGroup .class , DefaultThreadFactory .class ,
4851 DefaultEventExecutorGroup .class , ServerBootstrap .class , SslContextBuilder .class , File .class ,
49- Epoll .class , EpollEventLoopGroup .class , NettySslContext .class })
52+ Epoll .class , EpollEventLoopGroup .class , NettySslContext .class , GenericFutureListener . class })
5053public class NettyServerTest {
5154
5255 Config config = ConfigFactory .empty ()
@@ -75,8 +78,9 @@ public class NettyServerTest {
7578 unit .registerMock (NioEventLoopGroup .class , eventLoop );
7679
7780 Future future = unit .mock (Future .class );
81+ expect (future .addListener (unit .capture (GenericFutureListener .class ))).andReturn (future );
7882 expect (eventLoop .shutdownGracefully ()).andReturn (future );
79- expect (eventLoop .isShutdown ()).andReturn (true );
83+ expect (eventLoop .isShuttingDown ()).andReturn (false );
8084 };
8185
8286 private Block taskThreadFactory = unit -> {
@@ -130,6 +134,35 @@ public void defaultServer() throws Exception {
130134 });
131135 }
132136
137+ @ Test
138+ public void eventLoopIsShuttingDown () throws Exception {
139+ new MockUnit (HttpHandler .class )
140+ .expect (parentThreadFactory ("nio-boss" ))
141+ .expect (noepoll )
142+ .expect (unit -> {
143+ NioEventLoopGroup eventLoop = unit .constructor (NioEventLoopGroup .class )
144+ .args (int .class , ThreadFactory .class )
145+ .build (1 , unit .get (ThreadFactory .class ));
146+ unit .registerMock (EventLoopGroup .class , eventLoop );
147+ unit .registerMock (NioEventLoopGroup .class , eventLoop );
148+
149+ expect (eventLoop .isShuttingDown ()).andReturn (true );
150+ })
151+ .expect (taskThreadFactory )
152+ .expect (taskExecutor )
153+ .expect (channel )
154+ .expect (bootstrap (6789 ))
155+ .run (unit -> {
156+ NettyServer server = new NettyServer (unit .get (HttpHandler .class ), config );
157+ try {
158+ server .start ();
159+ server .join ();
160+ } finally {
161+ server .stop ();
162+ }
163+ });
164+ }
165+
133166 private Block parentThreadFactory (final String name ) {
134167 return unit -> {
135168 DefaultThreadFactory factory = unit .constructor (DefaultThreadFactory .class )
@@ -156,8 +189,9 @@ public void epollServer() throws Exception {
156189 unit .registerMock (EpollEventLoopGroup .class , eventLoop );
157190
158191 Future future = unit .mock (Future .class );
192+ expect (future .addListener (unit .capture (GenericFutureListener .class ))).andReturn (future );
159193 expect (eventLoop .shutdownGracefully ()).andReturn (future );
160- expect (eventLoop .isShutdown ()).andReturn (true );
194+ expect (eventLoop .isShuttingDown ()).andReturn (false );
161195 })
162196 .expect (taskThreadFactory )
163197 .expect (taskExecutor )
@@ -216,7 +250,65 @@ public void serverWithWorkerEventLoop() throws Exception {
216250 unit .registerMock (EventLoopGroup .class , eventLoop );
217251
218252 Future future = unit .mock (Future .class );
253+ expect (future .addListener (unit .capture (GenericFutureListener .class ))).andReturn (future );
254+ expect (eventLoop .shutdownGracefully ()).andReturn (future );
255+ expect (eventLoop .isShuttingDown ()).andReturn (false );
256+ })
257+ .expect (unit -> {
258+ DefaultThreadFactory factory = unit .constructor (DefaultThreadFactory .class )
259+ .args (String .class , int .class )
260+ .build ("nio-worker" , false );
261+ unit .registerMock (DefaultThreadFactory .class , factory );
262+ })
263+ .expect (unit -> {
264+ NioEventLoopGroup eventLoop = unit .constructor (NioEventLoopGroup .class )
265+ .args (int .class , ThreadFactory .class )
266+ .build (1 , unit .get (DefaultThreadFactory .class ));
267+ unit .registerMock (NioEventLoopGroup .class , eventLoop );
268+
269+ Future future = unit .mock (Future .class );
270+ expect (future .isSuccess ()).andReturn (true );
271+ expect (future .addListener (unit .capture (GenericFutureListener .class ))).andReturn (future );
272+ expect (eventLoop .shutdownGracefully ()).andReturn (future );
273+ expect (eventLoop .isShuttingDown ()).andReturn (false );
274+ unit .registerMock (Future .class , future );
275+ })
276+ .expect (taskThreadFactory )
277+ .expect (taskExecutor )
278+ .expect (channel )
279+ .expect (bootstrap (6789 ))
280+ .run (unit -> {
281+ NettyServer server = new NettyServer (unit .get (HttpHandler .class ), config );
282+ try {
283+ server .start ();
284+ server .join ();
285+ } finally {
286+ server .stop ();
287+ }
288+ }, unit -> {
289+ List <GenericFutureListener > captured = unit .captured (GenericFutureListener .class );
290+ captured .get (0 )
291+ .operationComplete (unit .get (Future .class ));
292+ });
293+ }
294+
295+ @ SuppressWarnings ({"unchecked" , "rawtypes" })
296+ @ Test
297+ public void eventLoopError () throws Exception {
298+ Config config = this .config .withValue ("netty.threads.Worker" , ConfigValueFactory .fromAnyRef (1 ));
299+ new MockUnit (HttpHandler .class )
300+ .expect (parentThreadFactory ("nio-boss" ))
301+ .expect (noepoll )
302+ .expect (unit -> {
303+ NioEventLoopGroup eventLoop = unit .constructor (NioEventLoopGroup .class )
304+ .args (int .class , ThreadFactory .class )
305+ .build (1 , unit .get (ThreadFactory .class ));
306+ unit .registerMock (EventLoopGroup .class , eventLoop );
307+
308+ Future future = unit .mock (Future .class );
309+ expect (future .addListener (unit .capture (GenericFutureListener .class ))).andReturn (future );
219310 expect (eventLoop .shutdownGracefully ()).andReturn (future );
311+ expect (eventLoop .isShuttingDown ()).andReturn (false );
220312 })
221313 .expect (unit -> {
222314 DefaultThreadFactory factory = unit .constructor (DefaultThreadFactory .class )
@@ -231,8 +323,12 @@ public void serverWithWorkerEventLoop() throws Exception {
231323 unit .registerMock (NioEventLoopGroup .class , eventLoop );
232324
233325 Future future = unit .mock (Future .class );
234- expect (eventLoop .isShutdown ()).andReturn (false );
326+ expect (future .isSuccess ()).andReturn (false );
327+ expect (future .cause ()).andReturn (new IOException ("intentional err" ));
328+ expect (future .addListener (unit .capture (GenericFutureListener .class ))).andReturn (future );
235329 expect (eventLoop .shutdownGracefully ()).andReturn (future );
330+ expect (eventLoop .isShuttingDown ()).andReturn (false );
331+ unit .registerMock (Future .class , future );
236332 })
237333 .expect (taskThreadFactory )
238334 .expect (taskExecutor )
@@ -246,6 +342,10 @@ public void serverWithWorkerEventLoop() throws Exception {
246342 } finally {
247343 server .stop ();
248344 }
345+ }, unit -> {
346+ List <GenericFutureListener > captured = unit .captured (GenericFutureListener .class );
347+ captured .get (0 )
348+ .operationComplete (unit .get (Future .class ));
249349 });
250350 }
251351
0 commit comments