2121import io .netty .bootstrap .Bootstrap ;
2222import io .netty .channel .Channel ;
2323import io .netty .channel .ChannelFuture ;
24+ import io .netty .channel .ChannelPipeline ;
25+ import io .netty .handler .ssl .SslHandler ;
2426import org .junit .After ;
2527import org .junit .Before ;
2628import org .junit .Rule ;
2729import org .junit .Test ;
30+ import org .junit .rules .RuleChain ;
31+ import org .junit .rules .Timeout ;
2832
33+ import java .io .IOException ;
2934import java .net .ConnectException ;
35+ import java .net .ServerSocket ;
3036import java .util .concurrent .ExecutionException ;
3137import java .util .concurrent .TimeUnit ;
3238
3339import org .neo4j .driver .internal .BoltServerAddress ;
3440import org .neo4j .driver .internal .ConnectionSettings ;
41+ import org .neo4j .driver .internal .async .inbound .ConnectTimeoutHandler ;
3542import org .neo4j .driver .internal .security .SecurityPlan ;
3643import org .neo4j .driver .internal .util .FakeClock ;
3744import org .neo4j .driver .v1 .AuthToken ;
4249
4350import static org .hamcrest .Matchers .instanceOf ;
4451import static org .hamcrest .Matchers .startsWith ;
52+ import static org .junit .Assert .assertEquals ;
4553import static org .junit .Assert .assertFalse ;
54+ import static org .junit .Assert .assertNotNull ;
4655import static org .junit .Assert .assertNull ;
4756import static org .junit .Assert .assertThat ;
4857import static org .junit .Assert .assertTrue ;
5261
5362public class ChannelConnectorImplTest
5463{
64+ private final TestNeo4j neo4j = new TestNeo4j ();
5565 @ Rule
56- public final TestNeo4j neo4j = new TestNeo4j ( );
66+ public final RuleChain ruleChain = RuleChain . outerRule ( Timeout . seconds ( 20 ) ). around ( neo4j );
5767
5868 private Bootstrap bootstrap ;
5969
6070 @ Before
61- public void setUp () throws Exception
71+ public void setUp ()
6272 {
6373 bootstrap = BootstrapFactory .newBootstrap ( 1 );
6474 }
6575
6676 @ After
67- public void tearDown () throws Exception
77+ public void tearDown ()
6878 {
6979 if ( bootstrap != null )
7080 {
@@ -75,7 +85,7 @@ public void tearDown() throws Exception
7585 @ Test
7686 public void shouldConnect () throws Exception
7787 {
78- ChannelConnectorImpl connector = newConnector ( neo4j .authToken () );
88+ ChannelConnector connector = newConnector ( neo4j .authToken () );
7989
8090 ChannelFuture channelFuture = connector .connect ( neo4j .address (), bootstrap );
8191 assertTrue ( channelFuture .await ( 10 , TimeUnit .SECONDS ) );
@@ -85,10 +95,26 @@ public void shouldConnect() throws Exception
8595 assertTrue ( channel .isActive () );
8696 }
8797
98+ @ Test
99+ public void shouldSetupHandlers () throws Exception
100+ {
101+ ChannelConnector connector = newConnector ( neo4j .authToken (), SecurityPlan .forAllCertificates (), 10_000 );
102+
103+ ChannelFuture channelFuture = connector .connect ( neo4j .address (), bootstrap );
104+ assertTrue ( channelFuture .await ( 10 , TimeUnit .SECONDS ) );
105+
106+ Channel channel = channelFuture .channel ();
107+ ChannelPipeline pipeline = channel .pipeline ();
108+ assertTrue ( channel .isActive () );
109+
110+ assertNotNull ( pipeline .get ( SslHandler .class ) );
111+ assertNull ( pipeline .get ( ConnectTimeoutHandler .class ) );
112+ }
113+
88114 @ Test
89115 public void shouldFailToConnectToWrongAddress () throws Exception
90116 {
91- ChannelConnectorImpl connector = newConnector ( neo4j .authToken () );
117+ ChannelConnector connector = newConnector ( neo4j .authToken () );
92118
93119 ChannelFuture channelFuture = connector .connect ( new BoltServerAddress ( "wrong-localhost" ), bootstrap );
94120 assertTrue ( channelFuture .await ( 10 , TimeUnit .SECONDS ) );
@@ -112,7 +138,7 @@ public void shouldFailToConnectToWrongAddress() throws Exception
112138 public void shouldFailToConnectWithWrongCredentials () throws Exception
113139 {
114140 AuthToken authToken = AuthTokens .basic ( "neo4j" , "wrong-password" );
115- ChannelConnectorImpl connector = newConnector ( authToken );
141+ ChannelConnector connector = newConnector ( authToken );
116142
117143 ChannelFuture channelFuture = connector .connect ( neo4j .address (), bootstrap );
118144 assertTrue ( channelFuture .await ( 10 , TimeUnit .SECONDS ) );
@@ -131,10 +157,10 @@ public void shouldFailToConnectWithWrongCredentials() throws Exception
131157 assertFalse ( channel .isActive () );
132158 }
133159
134- @ Test ( timeout = 10000 )
160+ @ Test
135161 public void shouldEnforceConnectTimeout () throws Exception
136162 {
137- ChannelConnectorImpl connector = newConnector ( neo4j .authToken (), 1000 );
163+ ChannelConnector connector = newConnector ( neo4j .authToken (), 1000 );
138164
139165 // try connect to a non-routable ip address 10.0.0.0, it will never respond
140166 ChannelFuture channelFuture = connector .connect ( new BoltServerAddress ( "10.0.0.0" ), bootstrap );
@@ -151,15 +177,55 @@ public void shouldEnforceConnectTimeout() throws Exception
151177 }
152178 }
153179
180+ @ Test
181+ public void shouldFailWhenProtocolNegotiationTakesTooLong () throws Exception
182+ {
183+ // run without TLS so that Bolt handshake is the very first operation after connection is established
184+ testReadTimeoutOnConnect ( SecurityPlan .insecure () );
185+ }
186+
187+ @ Test
188+ public void shouldFailWhenTLSHandshakeTakesTooLong () throws Exception
189+ {
190+ // run with TLS so that TLS handshake is the very first operation after connection is established
191+ testReadTimeoutOnConnect ( SecurityPlan .forAllCertificates () );
192+ }
193+
194+ private void testReadTimeoutOnConnect ( SecurityPlan securityPlan ) throws IOException
195+ {
196+ try ( ServerSocket server = new ServerSocket ( 0 ) ) // server that accepts connections but does not reply
197+ {
198+ int timeoutMillis = 1_000 ;
199+ BoltServerAddress address = new BoltServerAddress ( "localhost" , server .getLocalPort () );
200+ ChannelConnector connector = newConnector ( neo4j .authToken (), securityPlan , timeoutMillis );
201+
202+ ChannelFuture channelFuture = connector .connect ( address , bootstrap );
203+ try
204+ {
205+ await ( channelFuture );
206+ fail ( "Exception expected" );
207+ }
208+ catch ( ServiceUnavailableException e )
209+ {
210+ assertEquals ( e .getMessage (), "Unable to establish connection in " + timeoutMillis + "ms" );
211+ }
212+ }
213+ }
214+
154215 private ChannelConnectorImpl newConnector ( AuthToken authToken ) throws Exception
155216 {
156217 return newConnector ( authToken , Integer .MAX_VALUE );
157218 }
158219
159220 private ChannelConnectorImpl newConnector ( AuthToken authToken , int connectTimeoutMillis ) throws Exception
160221 {
161- ConnectionSettings settings = new ConnectionSettings ( authToken , 1000 );
162- return new ChannelConnectorImpl ( settings , SecurityPlan .forAllCertificates (), DEV_NULL_LOGGING ,
163- new FakeClock () );
222+ return newConnector ( authToken , SecurityPlan .forAllCertificates (), connectTimeoutMillis );
223+ }
224+
225+ private ChannelConnectorImpl newConnector ( AuthToken authToken , SecurityPlan securityPlan ,
226+ int connectTimeoutMillis )
227+ {
228+ ConnectionSettings settings = new ConnectionSettings ( authToken , connectTimeoutMillis );
229+ return new ChannelConnectorImpl ( settings , securityPlan , DEV_NULL_LOGGING , new FakeClock () );
164230 }
165231}
0 commit comments