1818
1919import com .fasterxml .jackson .annotation .JsonProperty ;
2020
21+ import java .util .concurrent .TimeUnit ;
2122import org .apache .http .client .ClientProtocolException ;
2223import org .apache .http .client .methods .CloseableHttpResponse ;
2324import org .apache .http .client .methods .HttpGet ;
3031import org .apache .kafka .common .config .types .Password ;
3132import org .apache .kafka .test .TestSslUtils ;
3233import org .apache .kafka .test .TestSslUtils .CertificateBuilder ;
33- import org .junit .Before ;
34+ import org .junit .AfterClass ;
35+ import org .junit .BeforeClass ;
3436import org .junit .Test ;
37+ import org .junit .rules .TemporaryFolder ;
3538import org .slf4j .Logger ;
3639import org .slf4j .LoggerFactory ;
3740
6063import static org .junit .Assert .assertEquals ;
6164import static org .junit .Assert .assertNotEquals ;
6265import static org .junit .Assert .assertTrue ;
66+ import static org .awaitility .Awaitility .await ;
67+ import static org .junit .Assert .fail ;
6368
6469public class SslTest {
6570 private static final Logger log = LoggerFactory .getLogger (SslTest .class );
6671
67- private File trustStore ;
68- private File clientKeystore ;
69- private File serverKeystore ;
70- private File serverKeystoreBak ;
71- private File serverKeystoreErr ;
72+ private static File trustStore ;
73+ private static File clientKeystore ;
74+ private static File serverKeystore ;
75+ private static File serverKeystoreBak ;
76+ private static File serverKeystoreErr ;
7277
7378 public static final String SSL_PASSWORD = "test1234" ;
7479 public static final String EXPECTED_200_MSG = "Response status must be 200." ;
75- public static final int CERT_RELOAD_WAIT_TIME = 30000 ;
76-
77- @ Before
78- public void setUp () throws Exception {
80+ public static final int CERT_RELOAD_WAIT_TIME = 20000 ;
81+
82+ private static TemporaryFolder tempFolder ;
83+
84+ @ BeforeClass
85+ public static void setUp () throws Exception {
86+
87+ /*
88+ * To make this test less flakey
89+ * - 1 don't create keystore files for every test method
90+ * - 2 cleanup keystore files on test exist so they don't have to be considerd by the FileWatcher
91+ * - 3 updated the FileWatcher and Application class to not have a single shared threadpool to
92+ * watch for changed files.
93+ *
94+ * By default temp files are not cleaned when up. Which isn't normally a problem unless you are
95+ * testing the ability of rest-utils apps to notice and reload updated ssl keystore files.
96+ *
97+ * Turns out the temp dir that Java+MacOs was continually using on my local machine had 1500
98+ * files in it. Also the Java "FileWatcher" for Mac works via polling a directory,
99+ * this seems to have added to the flakeyness.
100+ */
101+ tempFolder = new TemporaryFolder ();
102+ tempFolder .create ();
79103 try {
80- trustStore = File .createTempFile ("SslTest-truststore" , ".jks" );
81- clientKeystore = File .createTempFile ("SslTest-client-keystore" , ".jks" );
82- serverKeystore = File .createTempFile ("SslTest-server-keystore" , ".jks" );
83- serverKeystoreBak = File .createTempFile ("SslTest-server-keystore" , ".jks.bak" );
84- serverKeystoreErr = File .createTempFile ("SslTest-server-keystore" , ".jks.err" );
104+ trustStore = File .createTempFile ("SslTest-truststore" , ".jks" , tempFolder . getRoot () );
105+ clientKeystore = File .createTempFile ("SslTest-client-keystore" , ".jks" , tempFolder . getRoot () );
106+ serverKeystore = File .createTempFile ("SslTest-server-keystore" , ".jks" , tempFolder . getRoot () );
107+ serverKeystoreBak = File .createTempFile ("SslTest-server-keystore" , ".jks.bak" , tempFolder . getRoot () );
108+ serverKeystoreErr = File .createTempFile ("SslTest-server-keystore" , ".jks.err" , tempFolder . getRoot () );
85109 } catch (IOException ioe ) {
86110 throw new RuntimeException ("Unable to create temporary files for trust stores and keystores." );
87111 }
@@ -95,7 +119,12 @@ public void setUp() throws Exception {
95119 createWrongKeystoreWithCert (serverKeystoreErr , "server" , certs );
96120 }
97121
98- private void createKeystoreWithCert (File file , String alias , Map <String , X509Certificate > certs ) throws Exception {
122+ @ AfterClass
123+ public static void teardown () {
124+ tempFolder .delete ();
125+ }
126+
127+ private static void createKeystoreWithCert (File file , String alias , Map <String , X509Certificate > certs ) throws Exception {
99128 KeyPair keypair = TestSslUtils .generateKeyPair ("RSA" );
100129 CertificateBuilder certificateBuilder = new CertificateBuilder (30 , "SHA1withRSA" );
101130 X509Certificate cCert = certificateBuilder .sanDnsName ("localhost" )
@@ -128,7 +157,7 @@ private void enableSslClientAuth(Properties props) {
128157 props .put (RestConfig .SSL_CLIENT_AUTH_CONFIG , true );
129158 }
130159
131- private void createWrongKeystoreWithCert (File file , String alias , Map <String , X509Certificate > certs ) throws Exception {
160+ private static void createWrongKeystoreWithCert (File file , String alias , Map <String , X509Certificate > certs ) throws Exception {
132161 KeyPair keypair = TestSslUtils .generateKeyPair ("RSA" );
133162 CertificateBuilder certificateBuilder = new CertificateBuilder (30 , "SHA1withRSA" );
134163 X509Certificate cCert = certificateBuilder .sanDnsName ("fail" )
@@ -176,30 +205,44 @@ public void testHttpsWithAutoReload() throws Exception {
176205 SslTestApplication app = new SslTestApplication (config );
177206 try {
178207 app .start ();
179- int statusCode = makeGetRequest (httpsUri + "/test" ,
208+ int startingCode = makeGetRequest (httpsUri + "/test" ,
180209 clientKeystore .getAbsolutePath (), SSL_PASSWORD , SSL_PASSWORD );
181- assertEquals (EXPECTED_200_MSG , 200 , statusCode );
210+ assertEquals (EXPECTED_200_MSG , 200 , startingCode );
182211 assertMetricsCollected ();
183212
184213 // verify reload -- override the server keystore with a wrong one
185214 Files .copy (serverKeystoreErr .toPath (), serverKeystore .toPath (), StandardCopyOption .REPLACE_EXISTING );
186- Thread .sleep (CERT_RELOAD_WAIT_TIME );
187- boolean hitError = false ;
188- try {
189- makeGetRequest (httpsUri + "/test" ,
190- clientKeystore .getAbsolutePath (), SSL_PASSWORD , SSL_PASSWORD );
191- } catch (Exception e ) {
192- System .out .println (e );
193- hitError = true ;
194- }
215+ log .info ("\t Keystore reload test : Applied bad keystore file" );
216+
217+ await ().pollInterval (2 , TimeUnit .SECONDS ).atMost (30 , TimeUnit .SECONDS ).untilAsserted ( () -> {
218+ boolean hitError = false ;
219+ try {
220+ log .info ("\t Keystore reload test : Awaiting failed https connection" );
221+ makeGetRequest (httpsUri + "/test" , clientKeystore .getAbsolutePath (), SSL_PASSWORD , SSL_PASSWORD );
222+ } catch (Exception e ) {
223+ System .out .println (e );
224+ hitError = true ;
225+ }
226+ assertTrue ("Expecting to hit an error with new server cert" , hitError );
227+ });
195228
196229 // verify reload -- override the server keystore with a correct one
197230 Files .copy (serverKeystoreBak .toPath (), serverKeystore .toPath (), StandardCopyOption .REPLACE_EXISTING );
198- Thread .sleep (CERT_RELOAD_WAIT_TIME );
199- statusCode = makeGetRequest (httpsUri + "/test" ,
200- clientKeystore .getAbsolutePath (), SSL_PASSWORD , SSL_PASSWORD );
201- assertEquals (EXPECTED_200_MSG , 200 , statusCode );
202- assertEquals ("expect hit error with new server cert" , true , hitError );
231+ log .info ("\t Keystore reload test : keystore set back to good value" );
232+
233+ await ().pollInterval (2 , TimeUnit .SECONDS ).atMost (30 , TimeUnit .SECONDS ).untilAsserted ( () -> {
234+ try {
235+ log .info ("\t Keystore reload test : Awaiting a valid https connection" );
236+ int statusCode = makeGetRequest (httpsUri + "/test" , clientKeystore .getAbsolutePath (), SSL_PASSWORD , SSL_PASSWORD );
237+ assertEquals (EXPECTED_200_MSG , 200 , statusCode );
238+ log .info ("\t Keystore reload test : Valid connection found" );
239+ }
240+ catch (Exception e ) {
241+ fail ();
242+ // we have to wait for the good key to take affect
243+ }
244+ });
245+
203246 } finally {
204247 if (app != null ) {
205248 app .stop ();
@@ -332,7 +375,7 @@ public void testHttpsWithAuthAndBadClientCert() throws Exception {
332375 app .start ();
333376
334377 // create a new client cert that isn't in the server's trust store.
335- File untrustedClient = File .createTempFile ("SslTest-client-keystore" , ".jks" );
378+ File untrustedClient = File .createTempFile ("SslTest-client-keystore" , ".jks" , tempFolder . getRoot () );
336379 Map <String , X509Certificate > certs = new HashMap <>();
337380 createKeystoreWithCert (untrustedClient , "client" , certs );
338381 try {
0 commit comments