HADOOP-10823. TestReloadingX509TrustManager is flaky. Contributed by Mingliang Liu.

This commit is contained in:
Jitendra Pandey 2016-08-08 11:00:19 -07:00
parent 37d939a453
commit 625585950a
2 changed files with 53 additions and 22 deletions

View File

@ -23,6 +23,8 @@ import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.classification.InterfaceStability;
import com.google.common.annotations.VisibleForTesting;
import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
@ -44,8 +46,11 @@ import java.util.concurrent.atomic.AtomicReference;
public final class ReloadingX509TrustManager public final class ReloadingX509TrustManager
implements X509TrustManager, Runnable { implements X509TrustManager, Runnable {
private static final Log LOG = @VisibleForTesting
LogFactory.getLog(ReloadingX509TrustManager.class); static final Log LOG = LogFactory.getLog(ReloadingX509TrustManager.class);
@VisibleForTesting
static final String RELOAD_ERROR_MESSAGE =
"Could not load truststore (keep using existing one) : ";
private String type; private String type;
private File file; private File file;
@ -194,8 +199,7 @@ public final class ReloadingX509TrustManager
try { try {
trustManagerRef.set(loadTrustManager()); trustManagerRef.set(loadTrustManager());
} catch (Exception ex) { } catch (Exception ex) {
LOG.warn("Could not load truststore (keep using existing one) : " + LOG.warn(RELOAD_ERROR_MESSAGE + ex.toString(), ex);
ex.toString(), ex);
} }
} }
} }

View File

@ -19,6 +19,10 @@ package org.apache.hadoop.security.ssl;
import org.apache.hadoop.fs.FileUtil; import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.test.GenericTestUtils; import org.apache.hadoop.test.GenericTestUtils;
import org.apache.hadoop.test.GenericTestUtils.LogCapturer;
import com.google.common.base.Supplier;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
@ -30,11 +34,13 @@ import java.security.KeyPair;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeoutException;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.apache.hadoop.security.ssl.KeyStoreTestUtil.createTrustStore; import static org.apache.hadoop.security.ssl.KeyStoreTestUtil.createTrustStore;
import static org.apache.hadoop.security.ssl.KeyStoreTestUtil.generateCertificate; import static org.apache.hadoop.security.ssl.KeyStoreTestUtil.generateCertificate;
import static org.apache.hadoop.security.ssl.KeyStoreTestUtil.generateKeyPair; import static org.apache.hadoop.security.ssl.KeyStoreTestUtil.generateKeyPair;
import static org.junit.Assert.assertFalse;
public class TestReloadingX509TrustManager { public class TestReloadingX509TrustManager {
@ -43,6 +49,8 @@ public class TestReloadingX509TrustManager {
private X509Certificate cert1; private X509Certificate cert1;
private X509Certificate cert2; private X509Certificate cert2;
private final LogCapturer reloaderLog = LogCapturer.captureLogs(
ReloadingX509TrustManager.LOG);
@BeforeClass @BeforeClass
public static void setUp() throws Exception { public static void setUp() throws Exception {
@ -80,7 +88,7 @@ public class TestReloadingX509TrustManager {
} }
} }
@Test @Test (timeout = 30000)
public void testReload() throws Exception { public void testReload() throws Exception {
KeyPair kp = generateKeyPair("RSA"); KeyPair kp = generateKeyPair("RSA");
cert1 = generateCertificate("CN=Cert1", kp, 30, "SHA1withRSA"); cert1 = generateCertificate("CN=Cert1", kp, 30, "SHA1withRSA");
@ -88,7 +96,7 @@ public class TestReloadingX509TrustManager {
String truststoreLocation = BASEDIR + "/testreload.jks"; String truststoreLocation = BASEDIR + "/testreload.jks";
createTrustStore(truststoreLocation, "password", "cert1", cert1); createTrustStore(truststoreLocation, "password", "cert1", cert1);
ReloadingX509TrustManager tm = final ReloadingX509TrustManager tm =
new ReloadingX509TrustManager("jks", truststoreLocation, "password", 10); new ReloadingX509TrustManager("jks", truststoreLocation, "password", 10);
try { try {
tm.init(); tm.init();
@ -103,19 +111,18 @@ public class TestReloadingX509TrustManager {
certs.put("cert2", cert2); certs.put("cert2", cert2);
createTrustStore(truststoreLocation, "password", certs); createTrustStore(truststoreLocation, "password", certs);
// and wait to be sure reload has taken place GenericTestUtils.waitFor(new Supplier<Boolean>() {
assertEquals(10, tm.getReloadInterval()); @Override
public Boolean get() {
// Wait so that the file modification time is different return tm.getAcceptedIssuers().length == 2;
Thread.sleep((tm.getReloadInterval() + 200)); }
}, (int) tm.getReloadInterval(), 10000);
assertEquals(2, tm.getAcceptedIssuers().length);
} finally { } finally {
tm.destroy(); tm.destroy();
} }
} }
@Test @Test (timeout = 30000)
public void testReloadMissingTrustStore() throws Exception { public void testReloadMissingTrustStore() throws Exception {
KeyPair kp = generateKeyPair("RSA"); KeyPair kp = generateKeyPair("RSA");
cert1 = generateCertificate("CN=Cert1", kp, 30, "SHA1withRSA"); cert1 = generateCertificate("CN=Cert1", kp, 30, "SHA1withRSA");
@ -129,19 +136,22 @@ public class TestReloadingX509TrustManager {
tm.init(); tm.init();
assertEquals(1, tm.getAcceptedIssuers().length); assertEquals(1, tm.getAcceptedIssuers().length);
X509Certificate cert = tm.getAcceptedIssuers()[0]; X509Certificate cert = tm.getAcceptedIssuers()[0];
assertFalse(reloaderLog.getOutput().contains(
ReloadingX509TrustManager.RELOAD_ERROR_MESSAGE));
new File(truststoreLocation).delete(); new File(truststoreLocation).delete();
// Wait so that the file modification time is different waitForFailedReloadAtLeastOnce((int) tm.getReloadInterval());
Thread.sleep((tm.getReloadInterval() + 200));
assertEquals(1, tm.getAcceptedIssuers().length); assertEquals(1, tm.getAcceptedIssuers().length);
assertEquals(cert, tm.getAcceptedIssuers()[0]); assertEquals(cert, tm.getAcceptedIssuers()[0]);
} finally { } finally {
reloaderLog.stopCapturing();
tm.destroy(); tm.destroy();
} }
} }
@Test @Test (timeout = 30000)
public void testReloadCorruptTrustStore() throws Exception { public void testReloadCorruptTrustStore() throws Exception {
KeyPair kp = generateKeyPair("RSA"); KeyPair kp = generateKeyPair("RSA");
cert1 = generateCertificate("CN=Cert1", kp, 30, "SHA1withRSA"); cert1 = generateCertificate("CN=Cert1", kp, 30, "SHA1withRSA");
@ -154,22 +164,39 @@ public class TestReloadingX509TrustManager {
try { try {
tm.init(); tm.init();
assertEquals(1, tm.getAcceptedIssuers().length); assertEquals(1, tm.getAcceptedIssuers().length);
X509Certificate cert = tm.getAcceptedIssuers()[0]; final X509Certificate cert = tm.getAcceptedIssuers()[0];
// Wait so that the file modification time is different
Thread.sleep((tm.getReloadInterval() + 1000));
assertFalse(reloaderLog.getOutput().contains(
ReloadingX509TrustManager.RELOAD_ERROR_MESSAGE));
OutputStream os = new FileOutputStream(truststoreLocation); OutputStream os = new FileOutputStream(truststoreLocation);
os.write(1); os.write(1);
os.close(); os.close();
new File(truststoreLocation).setLastModified(System.currentTimeMillis() -
1000);
// Wait so that the file modification time is different waitForFailedReloadAtLeastOnce((int) tm.getReloadInterval());
Thread.sleep((tm.getReloadInterval() + 200));
assertEquals(1, tm.getAcceptedIssuers().length); assertEquals(1, tm.getAcceptedIssuers().length);
assertEquals(cert, tm.getAcceptedIssuers()[0]); assertEquals(cert, tm.getAcceptedIssuers()[0]);
} finally { } finally {
reloaderLog.stopCapturing();
tm.destroy(); tm.destroy();
} }
} }
/**Wait for the reloader thread to load the configurations at least once
* by probing the log of the thread if the reload fails.
*/
private void waitForFailedReloadAtLeastOnce(int reloadInterval)
throws InterruptedException, TimeoutException {
GenericTestUtils.waitFor(new Supplier<Boolean>() {
@Override
public Boolean get() {
return reloaderLog.getOutput().contains(
ReloadingX509TrustManager.RELOAD_ERROR_MESSAGE);
}
}, reloadInterval, 10 * 1000);
}
} }