GEODE-1945: split and refactor JSSESocketJUnitTest

The testing for ClientSocketFactory is extracted into the new test
ClientSocketFactoryIntegrationTest. Test has been updated to use
AssertJ and Rules.

The testing for SocketCreatorFactory and SSL is extract into the
new test SSLSocketIntegrationTest. Test has been updated to be more
readable and to use AssertJ, Awaitility and Rules.


Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/8c7efba8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/8c7efba8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/8c7efba8

Branch: refs/heads/feature/e2e-testing
Commit: 8c7efba86bcc8b6bc7009e75737e591b9f5afc4f
Parents: b196015
Author: Kirk Lund <kl...@apache.org>
Authored: Tue Sep 27 17:09:48 2016 -0700
Committer: Kirk Lund <kl...@apache.org>
Committed: Wed Sep 28 10:13:54 2016 -0700

----------------------------------------------------------------------
 .../net/ClientSocketFactoryIntegrationTest.java | 100 +++++++++
 .../geode/internal/net/JSSESocketJUnitTest.java | 223 -------------------
 .../internal/net/SSLSocketIntegrationTest.java  | 184 +++++++++++++++
 3 files changed, 284 insertions(+), 223 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/8c7efba8/geode-core/src/test/java/org/apache/geode/internal/net/ClientSocketFactoryIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/test/java/org/apache/geode/internal/net/ClientSocketFactoryIntegrationTest.java
 
b/geode-core/src/test/java/org/apache/geode/internal/net/ClientSocketFactoryIntegrationTest.java
new file mode 100644
index 0000000..72e5c4f
--- /dev/null
+++ 
b/geode-core/src/test/java/org/apache/geode/internal/net/ClientSocketFactoryIntegrationTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geode.internal.net;
+
+import static org.apache.geode.distributed.ConfigurationProperties.*;
+import static org.apache.geode.distributed.internal.DistributionConfig.*;
+import static 
org.apache.geode.internal.security.SecurableCommunicationChannel.*;
+import static org.assertj.core.api.Assertions.*;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.util.Properties;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.distributed.ClientSocketFactory;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.distributed.internal.DistributionConfigImpl;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Integration tests for ClientSocketFactory.
+ *
+ * <p>Extracted from {@code JSSESocketJUnitTest}.
+ */
+@Category(IntegrationTest.class)
+public class ClientSocketFactoryIntegrationTest {
+
+  private static final String EXCEPTION_MESSAGE = "TSocketFactory createSocket 
threw an IOException";
+
+  private static volatile boolean invokedCreateSocket;
+
+  private Socket socket;
+
+  @Rule
+  public RestoreSystemProperties restoreSystemProperties = new 
RestoreSystemProperties();
+
+  @Before
+  public void setUp() throws Exception {
+    System.setProperty(GEMFIRE_PREFIX + "clientSocketFactory", 
TSocketFactory.class.getName());
+
+    Properties properties = new Properties();
+    properties.setProperty(CLUSTER_SSL_ENABLED, "false");
+    DistributionConfig distributionConfig = new 
DistributionConfigImpl(properties);
+
+    SocketCreatorFactory.setDistributionConfig(distributionConfig);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (this.socket != null) {
+      this.socket.close();
+    }
+
+    System.clearProperty(GEMFIRE_PREFIX + "clientSocketFactory");
+    
SocketCreatorFactory.getSocketCreatorForComponent(CLUSTER).initializeClientSocketFactory();
+
+    invokedCreateSocket = false;
+  }
+
+  @Test
+  public void testClientSocketFactory() throws Exception {
+    assertThatThrownBy(() -> this.socket = 
SocketCreatorFactory.getSocketCreatorForComponent(CLUSTER).connectForClient("localhost",
 12345, 0))
+      .isExactlyInstanceOf(IOException.class)
+      .hasMessage(EXCEPTION_MESSAGE);
+
+    assertThat(invokedCreateSocket).isTrue();
+  }
+
+  private static class TSocketFactory implements ClientSocketFactory {
+
+    public TSocketFactory() {
+    }
+
+    public Socket createSocket(final InetAddress address, final int port) 
throws IOException {
+      invokedCreateSocket = true;
+      throw new IOException(EXCEPTION_MESSAGE);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/8c7efba8/geode-core/src/test/java/org/apache/geode/internal/net/JSSESocketJUnitTest.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/test/java/org/apache/geode/internal/net/JSSESocketJUnitTest.java
 
b/geode-core/src/test/java/org/apache/geode/internal/net/JSSESocketJUnitTest.java
deleted file mode 100755
index e63a46f..0000000
--- 
a/geode-core/src/test/java/org/apache/geode/internal/net/JSSESocketJUnitTest.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.geode.internal.net;
-
-import static org.apache.geode.distributed.ConfigurationProperties.*;
-import static org.junit.Assert.*;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.LineNumberReader;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.StringReader;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.util.Properties;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.core.Logger;
-import org.apache.logging.log4j.core.appender.AbstractAppender;
-import org.apache.logging.log4j.core.config.LoggerConfig;
-import org.apache.logging.log4j.core.layout.PatternLayout;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.contrib.java.lang.system.SystemErrRule;
-import org.junit.contrib.java.lang.system.SystemOutRule;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TestName;
-
-import org.apache.geode.distributed.ClientSocketFactory;
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.distributed.internal.DistributionConfigImpl;
-import org.apache.geode.internal.AvailablePort;
-import org.apache.geode.internal.logging.LogService;
-import org.apache.geode.internal.security.SecurableCommunicationChannel;
-import org.apache.geode.test.dunit.ThreadUtils;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-import org.apache.geode.util.test.TestUtil;
-
-/**
- * Test creation of server sockets and client sockets with various JSSE
- * configurations.
- */
-@Category(IntegrationTest.class)
-public class JSSESocketJUnitTest {
-
-  private static volatile boolean factoryInvoked;
-
-  private ServerSocket acceptor;
-  private Socket server;
-  private int randport;
-
-  @Rule
-  public TestName name = new TestName();
-
-  @Rule
-  public SystemOutRule systemOutRule = new SystemOutRule();
-
-  @Before
-  public void setUp() throws Exception {
-    randport = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    if (server != null) {
-      server.close();
-    }
-    if (acceptor != null) {
-      acceptor.close();
-    }
-    SocketCreatorFactory.close();
-  }
-
-  @Test
-  public void testSSLSocket() throws Exception {
-    systemOutRule.mute().enableLog();
-
-    final Object[] receiver = new Object[1];
-
-    // Get original base log level
-    Level originalBaseLevel = LogService.getBaseLogLevel();
-    try {
-      // Set base log level to debug to log the SSL messages
-      LogService.setBaseLogLevel(Level.DEBUG);
-      {
-        System.setProperty(DistributionConfig.GEMFIRE_PREFIX + MCAST_PORT, 
"0");
-        System.setProperty(DistributionConfig.GEMFIRE_PREFIX + 
CLUSTER_SSL_ENABLED, "true");
-        System.setProperty(DistributionConfig.GEMFIRE_PREFIX + 
CLUSTER_SSL_REQUIRE_AUTHENTICATION, "true");
-        System.setProperty(DistributionConfig.GEMFIRE_PREFIX + 
CLUSTER_SSL_CIPHERS, "any");
-        System.setProperty(DistributionConfig.GEMFIRE_PREFIX + 
CLUSTER_SSL_PROTOCOLS, "TLSv1.2");
-
-        File jks = findTestJKS();
-        System.setProperty("javax.net.ssl.trustStore", jks.getCanonicalPath());
-        System.setProperty("javax.net.ssl.trustStorePassword", "password");
-        System.setProperty("javax.net.ssl.keyStore", jks.getCanonicalPath());
-        System.setProperty("javax.net.ssl.keyStorePassword", "password");
-      }
-
-      DistributionConfigImpl distributionConfig = new 
DistributionConfigImpl(new Properties());
-
-      SocketCreatorFactory.setDistributionConfig(distributionConfig);
-      
assertTrue(SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.CLUSTER).useSSL());
-
-      final ServerSocket serverSocket = 
SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.CLUSTER).createServerSocket(randport,
 0, InetAddress.getByName("localhost"));
-
-      Thread serverThread = startServer(serverSocket, receiver);
-
-      Socket client = 
SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.CLUSTER).connectForServer(InetAddress.getByName("localhost"),
 randport);
-
-      ObjectOutputStream oos = new 
ObjectOutputStream(client.getOutputStream());
-      String expected = "testing " + name.getMethodName();
-      oos.writeObject(expected);
-      oos.flush();
-
-      ThreadUtils.join(serverThread, 30 * 1000);
-
-      client.close();
-      serverSocket.close();
-      assertEquals("Expected \"" + expected + "\" but received \"" + 
receiver[0] + "\"", expected, receiver[0]);
-
-      String stdOut = systemOutRule.getLog();
-      int foundExpectedString = 0;
-
-      Pattern pattern = Pattern.compile(".*peer CN=.*");
-      Matcher matcher = pattern.matcher(stdOut);
-      while (matcher.find()) {
-        foundExpectedString++;
-      }
-
-      assertEquals(2, foundExpectedString);
-
-    } finally {
-      // Reset original base log level
-      LogService.setBaseLogLevel(originalBaseLevel);
-    }
-  }
-
-  /**
-   * not actually related to this test class, but this is as good a place
-   * as any for this little test of the client-side ability to tell gemfire
-   * to use a given socket factory.  We just test the connectForClient method
-   * to see if it's used
-   */
-  @Test
-  public void testClientSocketFactory() {
-    System.getProperties().put(DistributionConfig.GEMFIRE_PREFIX + 
"clientSocketFactory", TSocketFactory.class.getName());
-    System.getProperties().put(DistributionConfig.GEMFIRE_PREFIX + 
CLUSTER_SSL_ENABLED, "false");
-    DistributionConfigImpl distributionConfig = new DistributionConfigImpl(new 
Properties());
-    SocketCreatorFactory.setDistributionConfig(distributionConfig);
-    factoryInvoked = false;
-    try {
-      try {
-        Socket sock = 
SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.CLUSTER).connectForClient("localhost",
 12345, 0);
-        sock.close();
-        fail("socket factory was invoked");
-      } catch (IOException e) {
-        assertTrue("socket factory was not invoked: " + factoryInvoked, 
factoryInvoked);
-      }
-    } finally {
-      System.getProperties().remove(DistributionConfig.GEMFIRE_PREFIX + 
"clientSocketFactory");
-      
SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.CLUSTER).initializeClientSocketFactory();
-    }
-  }
-
-  private File findTestJKS() {
-    return new File(TestUtil.getResourcePath(getClass(), 
"/ssl/trusted.keystore"));
-  }
-
-  private Thread startServer(final ServerSocket serverSocket, final Object[] 
receiver) throws Exception {
-    Thread t = new Thread(new Runnable() {
-      public void run() {
-        try {
-          Socket s = serverSocket.accept();
-          
SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.CLUSTER).configureServerSSLSocket(s);
-          ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
-          receiver[0] = ois.readObject();
-          server = s;
-          acceptor = serverSocket;
-        } catch (Exception e) {
-          e.printStackTrace();
-          receiver[0] = e;
-        }
-      }
-    }, name.getMethodName() + "-server");
-    t.start();
-    return t;
-  }
-
-  private static class TSocketFactory implements ClientSocketFactory {
-
-    public TSocketFactory() {
-    }
-
-    public Socket createSocket(InetAddress address, int port) throws 
IOException {
-      JSSESocketJUnitTest.factoryInvoked = true;
-      throw new IOException("splort!");
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/8c7efba8/geode-core/src/test/java/org/apache/geode/internal/net/SSLSocketIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/test/java/org/apache/geode/internal/net/SSLSocketIntegrationTest.java
 
b/geode-core/src/test/java/org/apache/geode/internal/net/SSLSocketIntegrationTest.java
new file mode 100755
index 0000000..70f12d7
--- /dev/null
+++ 
b/geode-core/src/test/java/org/apache/geode/internal/net/SSLSocketIntegrationTest.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.geode.internal.net;
+
+import static com.jayway.awaitility.Awaitility.*;
+import static org.apache.geode.distributed.ConfigurationProperties.*;
+import static 
org.apache.geode.internal.security.SecurableCommunicationChannel.*;
+import static org.assertj.core.api.Assertions.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ErrorCollector;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestName;
+
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.distributed.internal.DistributionConfigImpl;
+import org.apache.geode.internal.FileUtil;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Integration tests for SocketCreatorFactory with SSL.
+ * <p>
+ * <p>Renamed from {@code JSSESocketJUnitTest}.
+ *
+ * @see ClientSocketFactoryIntegrationTest
+ */
+@Category(IntegrationTest.class)
+public class SSLSocketIntegrationTest {
+
+  private static final String MESSAGE = 
SSLSocketIntegrationTest.class.getName() + " Message";
+
+  private AtomicReference<String> messageFromClient = new AtomicReference<>();
+
+  private DistributionConfig distributionConfig;
+  private SocketCreator socketCreator;
+  private InetAddress localHost;
+  private Thread serverThread;
+  private ServerSocket serverSocket;
+  private Socket clientSocket;
+
+  @Rule
+  public ErrorCollector errorCollector = new ErrorCollector();
+
+  @Rule
+  public RestoreSystemProperties restoreSystemProperties = new 
RestoreSystemProperties();
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Rule
+  public TestName testName = new TestName();
+
+  @Before
+  public void setUp() throws Exception {
+    File keystore = findTestKeystore();
+    System.setProperty("javax.net.ssl.trustStore", 
keystore.getCanonicalPath());
+    System.setProperty("javax.net.ssl.trustStorePassword", "password");
+    System.setProperty("javax.net.ssl.keyStore", keystore.getCanonicalPath());
+    System.setProperty("javax.net.ssl.keyStorePassword", "password");
+
+    Properties properties = new Properties();
+    properties.setProperty(MCAST_PORT, "0");
+    properties.setProperty(CLUSTER_SSL_ENABLED, "true");
+    properties.setProperty(CLUSTER_SSL_REQUIRE_AUTHENTICATION, "true");
+    properties.setProperty(CLUSTER_SSL_CIPHERS, "any");
+    properties.setProperty(CLUSTER_SSL_PROTOCOLS, "TLSv1.2");
+
+    this.distributionConfig = new DistributionConfigImpl(properties);
+
+    SocketCreatorFactory.setDistributionConfig(this.distributionConfig);
+    this.socketCreator = 
SocketCreatorFactory.getSocketCreatorForComponent(CLUSTER);
+
+    this.localHost = InetAddress.getLocalHost();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (this.clientSocket != null) {
+      this.clientSocket.close();
+    }
+    if (this.serverSocket != null) {
+      this.serverSocket.close();
+    }
+    if (this.serverThread != null && this.serverThread.isAlive()) {
+      this.serverThread.interrupt();
+    }
+    SocketCreatorFactory.close();
+  }
+
+  @Test
+  public void socketCreatorShouldUseSsl() throws Exception {
+    assertThat(this.socketCreator.useSSL()).isTrue();
+  }
+
+  @Test
+  public void securedSocketTransmissionShouldWork() throws Exception {
+    this.serverSocket = this.socketCreator.createServerSocket(0, 0, 
this.localHost);
+    this.serverThread = startServer(this.serverSocket);
+
+    int serverPort = this.serverSocket.getLocalPort();
+    this.clientSocket = this.socketCreator.connectForServer(this.localHost, 
serverPort);
+
+    // transmit expected string from Client to Server
+    ObjectOutputStream output = new 
ObjectOutputStream(this.clientSocket.getOutputStream());
+    output.writeObject(MESSAGE);
+    output.flush();
+
+    // this is the real assertion of this test
+    await().atMost(1, TimeUnit.MINUTES).until(() -> 
assertThat(this.messageFromClient.get()).isEqualTo(MESSAGE));
+  }
+
+  private File findTestKeystore() throws IOException {
+    return copyKeystoreResourceToFile("/ssl/trusted.keystore");
+  }
+
+  public File copyKeystoreResourceToFile(final String name) throws IOException 
{
+    URL resource = getClass().getResource(name);
+    assertThat(resource).isNotNull();
+
+    File file = this.temporaryFolder.newFile(name.replaceFirst(".*/", ""));
+    FileUtil.copy(resource, file);
+    return file;
+  }
+
+  private Thread startServer(final ServerSocket serverSocket) throws Exception 
{
+    Thread serverThread = new Thread(new 
MyThreadGroup(this.testName.getMethodName()), () -> {
+      try {
+        Socket socket = serverSocket.accept();
+        
SocketCreatorFactory.getSocketCreatorForComponent(CLUSTER).configureServerSSLSocket(socket);
+        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
+        messageFromClient.set((String) ois.readObject());
+      } catch (IOException | ClassNotFoundException e) {
+        throw new Error(e);
+      }
+    }, this.testName.getMethodName() + "-server");
+
+    serverThread.start();
+    return serverThread;
+  }
+
+  private class MyThreadGroup extends ThreadGroup {
+
+    public MyThreadGroup(final String name) {
+      super(name);
+    }
+
+    @Override
+    public void uncaughtException(final Thread thread, final Throwable 
throwable) {
+      errorCollector.addError(throwable);
+    }
+  }
+
+}

Reply via email to