9090public class OkHttpServerTransportTest {
9191 private static final int TIME_OUT_MS = 2000 ;
9292 private static final int INITIAL_WINDOW_SIZE = 65535 ;
93+ private static final long MAX_CONNECTION_IDLE = TimeUnit .SECONDS .toNanos (1 );
9394
9495 private MockServerTransportListener mockTransportListener = new MockServerTransportListener ();
9596 private ServerTransportListener transportListener
@@ -105,10 +106,11 @@ public class OkHttpServerTransportTest {
105106 private ExecutorService threadPool = Executors .newCachedThreadPool ();
106107 private HandshakerSocketFactory handshakerSocketFactory
107108 = mock (HandshakerSocketFactory .class , delegatesTo (new PlaintextHandshakerSocketFactory ()));
109+ private final FakeClock fakeClock = new FakeClock ();
108110 private OkHttpServerBuilder serverBuilder
109111 = new OkHttpServerBuilder (new InetSocketAddress (1234 ), handshakerSocketFactory )
110112 .executor (new FakeClock ().getScheduledExecutorService ()) // Executor unused
111- .scheduledExecutorService (new FakeClock () .getScheduledExecutorService ())
113+ .scheduledExecutorService (fakeClock .getScheduledExecutorService ())
112114 .transportExecutor (new Executor () {
113115 @ Override public void execute (Runnable runnable ) {
114116 if (runnable instanceof OkHttpServerTransport .FrameHandler ) {
@@ -119,7 +121,8 @@ public class OkHttpServerTransportTest {
119121 }
120122 }
121123 })
122- .flowControlWindow (INITIAL_WINDOW_SIZE );
124+ .flowControlWindow (INITIAL_WINDOW_SIZE )
125+ .maxConnectionIdle (MAX_CONNECTION_IDLE , TimeUnit .NANOSECONDS );
123126
124127 @ Rule public final Timeout globalTimeout = Timeout .seconds (10 );
125128
@@ -146,6 +149,64 @@ public void startThenShutdown() throws Exception {
146149 shutdownAndTerminate (/*lastStreamId=*/ 0 );
147150 }
148151
152+ @ Test
153+ public void maxConnectionIdleTimer () throws Exception {
154+ initTransport ();
155+ handshake ();
156+ clientFrameWriter .headers (1 , Arrays .asList (
157+ HTTP_SCHEME_HEADER ,
158+ METHOD_HEADER ,
159+ new Header (Header .TARGET_AUTHORITY , "example.com:80" ),
160+ new Header (Header .TARGET_PATH , "/com.example/SimpleService.doit" ),
161+ CONTENT_TYPE_HEADER ,
162+ TE_HEADER ));
163+ clientFrameWriter .synStream (true , false , 1 , -1 , Arrays .asList (
164+ new Header ("some-client-sent-trailer" , "trailer-value" )));
165+ pingPong ();
166+
167+ MockStreamListener streamListener = mockTransportListener .newStreams .pop ();
168+ assertThat (streamListener .messages .peek ()).isNull ();
169+ assertThat (streamListener .halfClosedCalled ).isTrue ();
170+
171+ streamListener .stream .close (Status .OK , new Metadata ());
172+
173+ List <Header > responseTrailers = Arrays .asList (
174+ new Header (":status" , "200" ),
175+ CONTENT_TYPE_HEADER ,
176+ new Header ("grpc-status" , "0" ));
177+ assertThat (clientFrameReader .nextFrame (clientFramesRead )).isTrue ();
178+ verify (clientFramesRead )
179+ .headers (false , true , 1 , -1 , responseTrailers , HeadersMode .HTTP_20_HEADERS );
180+
181+ fakeClock .forwardNanos (MAX_CONNECTION_IDLE );
182+ fakeClock .forwardNanos (MAX_CONNECTION_IDLE );
183+ verifyGracefulShutdown (1 );
184+ }
185+
186+ @ Test
187+ public void maxConnectionIdleTimer_respondWithError () throws Exception {
188+ initTransport ();
189+ handshake ();
190+
191+ clientFrameWriter .headers (1 , Arrays .asList (
192+ HTTP_SCHEME_HEADER ,
193+ METHOD_HEADER ,
194+ new Header (Header .TARGET_PATH , "/com.example/SimpleService.doit" ),
195+ CONTENT_TYPE_HEADER ,
196+ TE_HEADER ,
197+ new Header ("host" , "example.com:80" ),
198+ new Header ("host" , "example.com:80" )));
199+ clientFrameWriter .flush ();
200+
201+ verifyHttpError (
202+ 1 , 400 , Status .Code .INTERNAL , "Multiple host headers disallowed. RFC7230 section 5.4" );
203+
204+ pingPong ();
205+ fakeClock .forwardNanos (MAX_CONNECTION_IDLE );
206+ fakeClock .forwardNanos (MAX_CONNECTION_IDLE );
207+ verifyGracefulShutdown (1 );
208+ }
209+
149210 @ Test
150211 public void startThenShutdownTwice () throws Exception {
151212 initTransport ();
@@ -316,7 +377,8 @@ public void activeRpc_delaysShutdownTermination() throws Exception {
316377 clientFrameWriter .data (true , 1 , requestMessageFrame , (int ) requestMessageFrame .size ());
317378 pingPong ();
318379
319- shutdownAndVerifyGraceful (1 );
380+ serverTransport .shutdown ();
381+ verifyGracefulShutdown (1 );
320382 verify (transportListener , never ()).transportTerminated ();
321383
322384 MockStreamListener streamListener = mockTransportListener .newStreams .pop ();
@@ -1038,8 +1100,8 @@ private Metadata metadata(String... keysAndValues) {
10381100 return metadata ;
10391101 }
10401102
1041- private void shutdownAndVerifyGraceful (int lastStreamId ) throws IOException {
1042- serverTransport . shutdown ();
1103+ private void verifyGracefulShutdown (int lastStreamId )
1104+ throws IOException {
10431105 assertThat (clientFrameReader .nextFrame (clientFramesRead )).isTrue ();
10441106 verify (clientFramesRead ).goAway (2147483647 , ErrorCode .NO_ERROR , ByteString .EMPTY );
10451107 assertThat (clientFrameReader .nextFrame (clientFramesRead )).isTrue ();
@@ -1052,7 +1114,8 @@ private void shutdownAndVerifyGraceful(int lastStreamId) throws IOException {
10521114
10531115 private void shutdownAndTerminate (int lastStreamId ) throws IOException {
10541116 assertThat (serverTransport .getActiveStreams ().length ).isEqualTo (0 );
1055- shutdownAndVerifyGraceful (lastStreamId );
1117+ serverTransport .shutdown ();
1118+ verifyGracefulShutdown (lastStreamId );
10561119 assertThat (clientFrameReader .nextFrame (clientFramesRead )).isFalse ();
10571120 verify (transportListener , timeout (TIME_OUT_MS )).transportTerminated ();
10581121 }
0 commit comments