You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2016/08/21 15:38:56 UTC

[4/4] mina-sshd git commit: [SSHD-691] Attempt to create server instance only once per test as much as possible

[SSHD-691] Attempt to create server instance only once per test as much as possible


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/ae8d1c99
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/ae8d1c99
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/ae8d1c99

Branch: refs/heads/master
Commit: ae8d1c9950c1faf4ffc6ff493aa5650709cd805d
Parents: b5bb002
Author: Lyor Goldstein <ly...@gmail.com>
Authored: Sun Aug 21 18:40:29 2016 +0300
Committer: Lyor Goldstein <ly...@gmail.com>
Committed: Sun Aug 21 18:40:29 2016 +0300

----------------------------------------------------------------------
 .../subsystem/sftp/AbstractSftpClient.java      |   9 +
 .../sshd/client/subsystem/sftp/SftpClient.java  |  10 +
 .../subsystem/sftp/SftpDirEntryIterator.java    |  93 +-
 .../client/subsystem/sftp/SftpFileSystem.java   |   8 +
 .../subsystem/sftp/SftpIterableDirEntry.java    |  14 +-
 .../subsystem/sftp/StfpIterableDirHandle.java   |  59 ++
 .../server/subsystem/sftp/DirectoryHandle.java  |   6 +-
 .../server/subsystem/sftp/SftpSubsystem.java    |   5 +-
 .../java/org/apache/sshd/KeepAliveTest.java     |  61 +-
 .../sshd/client/ClientSessionListenerTest.java  |  54 +-
 .../org/apache/sshd/client/kex/KexTest.java     | 106 ++-
 .../org/apache/sshd/client/scp/ScpTest.java     | 940 +++++++++----------
 .../sshd/client/session/ClientSessionTest.java  |  42 +-
 .../client/simple/SimpleSftpClientTest.java     |   8 +-
 .../sftp/AbstractSftpClientTestSupport.java     |  36 +-
 .../subsystem/sftp/SftpFileSystemTest.java      |  33 +-
 .../sshd/client/subsystem/sftp/SftpTest.java    | 840 ++++++++---------
 .../client/subsystem/sftp/SftpVersionsTest.java | 283 +++---
 .../helpers/AbstractCheckFileExtensionTest.java |  56 +-
 .../helpers/AbstractMD5HashExtensionTest.java   |  70 +-
 .../helpers/CopyDataExtensionImplTest.java      |  52 +-
 .../helpers/CopyFileExtensionImplTest.java      |  43 +-
 .../SpaceAvailableExtensionImplTest.java        |  32 +-
 .../openssh/helpers/OpenSSHExtensionsTest.java  |  40 +-
 .../apache/sshd/common/cipher/CipherTest.java   |  30 +-
 .../common/compression/CompressionTest.java     |  60 +-
 .../common/forward/PortForwardingLoadTest.java  |   1 +
 .../sshd/common/forward/PortForwardingTest.java |  77 +-
 .../sshd/common/kex/KexFactoryManagerTest.java  |   8 +-
 .../org/apache/sshd/common/mac/MacTest.java     |  34 +-
 .../AbstractSignatureFactoryTestSupport.java    | 130 ---
 .../signature/SignatureDSSFactoryTest.java      |  58 --
 .../signature/SignatureECDSAFactoryTest.java    |  68 --
 .../signature/SignatureFactoriesTest.java       | 184 ++++
 .../signature/SignatureRSAFactoryTest.java      |  58 --
 .../sshd/server/ServerSessionListenerTest.java  | 102 +-
 .../java/org/apache/sshd/server/ServerTest.java |   2 -
 .../sshd/server/auth/WelcomeBannerTest.java     |   4 +-
 38 files changed, 1788 insertions(+), 1928 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ae8d1c99/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
index 4284dc2..ecf6ffb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/AbstractSftpClient.java
@@ -1130,6 +1130,15 @@ public abstract class AbstractSftpClient extends AbstractSubsystemClient impleme
     }
 
     @Override
+    public Iterable<DirEntry> listDir(Handle handle) throws IOException {
+        if (!isOpen()) {
+            throw new IOException("listDir(" + handle + ") client is closed");
+        }
+
+        return new StfpIterableDirHandle(this, handle);
+    }
+
+    @Override
     public InputStream read(final String path, final int bufferSize, final Collection<OpenMode> mode) throws IOException {
         if (bufferSize < MIN_READ_BUFFER_SIZE) {
             throw new IllegalArgumentException("Insufficient read buffer size: " + bufferSize + ", min.=" + MIN_READ_BUFFER_SIZE);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ae8d1c99/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java
index 1673ebb..49d09f8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpClient.java
@@ -634,6 +634,16 @@ public interface SftpClient extends SubsystemClient {
     List<DirEntry> readDir(Handle handle, AtomicReference<Boolean> eolIndicator) throws IOException;
 
     /**
+     * @param handle A directory {@link Handle}
+     * @return An {@link Iterable} that can be used to iterate over all the
+     * directory entries (like {@link #readDir(String)}). <B>Note:</B> the
+     * iterable instance is not re-usable - i.e., files can be iterated
+     * only <U>once</U>
+     * @throws IOException If failed to access the directory
+     */
+    Iterable<DirEntry> listDir(Handle handle) throws IOException;
+
+    /**
      * The effective &quot;normalized&quot; remote path
      *
      * @param path The requested path - may be relative, and/or contain

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ae8d1c99/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirEntryIterator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirEntryIterator.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirEntryIterator.java
index c828015..e245589 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirEntryIterator.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpDirEntryIterator.java
@@ -18,14 +18,17 @@
  */
 package org.apache.sshd.client.subsystem.sftp;
 
+import java.io.Closeable;
 import java.io.IOException;
 import java.nio.channels.Channel;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
-import org.apache.sshd.client.subsystem.sftp.SftpClient.CloseableHandle;
 import org.apache.sshd.client.subsystem.sftp.SftpClient.DirEntry;
+import org.apache.sshd.client.subsystem.sftp.SftpClient.Handle;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.logging.AbstractLoggingBean;
 
@@ -39,27 +42,50 @@ import org.apache.sshd.common.util.logging.AbstractLoggingBean;
  */
 public class SftpDirEntryIterator extends AbstractLoggingBean implements Iterator<DirEntry>, Channel {
     private final AtomicReference<Boolean> eolIndicator = new AtomicReference<>();
+    private final AtomicBoolean open = new AtomicBoolean(true);
     private final SftpClient client;
     private final String dirPath;
-    private CloseableHandle dirHandle;
+    private final boolean closeOnFinished;
+    private Handle dirHandle;
     private List<DirEntry> dirEntries;
     private int index;
 
     /**
      * @param client The {@link SftpClient} instance to use for the iteration
      * @param path The remote directory path
+     * @throws IOException If failed to gain access to the remote directory patj
      */
-    public SftpDirEntryIterator(SftpClient client, String path) {
-        this.client = ValidateUtils.checkNotNull(client, "No SFTP client instance");
-        this.dirPath = path;
-        this.dirHandle = open(path);
+    public SftpDirEntryIterator(SftpClient client, String path) throws IOException {
+        this(client, path, client.openDir(path), true);
+    }
+
+    /**
+     * @param client The {@link SftpClient} instance to use for the iteration
+     * @param dirHandle The directory {@link Handle} to use for listing the entries
+     */
+    public SftpDirEntryIterator(SftpClient client, Handle dirHandle) {
+        this(client, Objects.toString(dirHandle, null), dirHandle, false);
+    }
+
+    /**
+     * @param client The {@link SftpClient} instance to use for the iteration
+     * @param path A hint as to the remote directory path - used only for logging
+     * @param dirHandle The directory {@link Handle} to use for listing the entries
+     * @param closeOnFinished If {@code true} then close the directory handle when
+     * all entries have been exahusted
+     */
+    public SftpDirEntryIterator(SftpClient client, String path, Handle dirHandle, boolean closeOnFinished) {
+        this.client = Objects.requireNonNull(client, "No SFTP client instance");
+        this.dirPath = ValidateUtils.checkNotNullAndNotEmpty(path, "No path");
+        this.dirHandle = Objects.requireNonNull(dirHandle, "No directory handle");
+        this.closeOnFinished = closeOnFinished;
         this.dirEntries = load(dirHandle);
     }
 
     /**
      * The client instance
      *
-     * @return {@link SftpClient} instance used to access the remote file
+     * @return {@link SftpClient} instance used to access the remote folder
      */
     public final SftpClient getClient() {
         return client;
@@ -68,12 +94,20 @@ public class SftpDirEntryIterator extends AbstractLoggingBean implements Iterato
     /**
      * The remotely accessed directory path
      *
-     * @return Remote directory path
+     * @return Remote directory hint - may be the handle's value if accessed directly
+     * via a {@link Handle} instead of via a path - used only for logging
      */
     public final String getPath() {
         return dirPath;
     }
 
+    /**
+     * @return The directory {@link Handle} used to access the remote directory
+     */
+    public final Handle getHandle() {
+        return dirHandle;
+    }
+
     @Override
     public boolean hasNext() {
         return (dirEntries != null) && (index < dirEntries.size());
@@ -86,7 +120,7 @@ public class SftpDirEntryIterator extends AbstractLoggingBean implements Iterato
             index = 0;
 
             try {
-                dirEntries = load(dirHandle);
+                dirEntries = load(getHandle());
             } catch (RuntimeException e) {
                 dirEntries = null;
                 throw e;
@@ -98,42 +132,33 @@ public class SftpDirEntryIterator extends AbstractLoggingBean implements Iterato
 
     @Override
     public boolean isOpen() {
-        return (dirHandle != null) && dirHandle.isOpen();
+        return open.get();
     }
 
-    @Override
-    public void close() throws IOException {
-        if (isOpen()) {
-            if (log.isDebugEnabled()) {
-                log.debug("close(" + getPath() + ") handle=" + dirHandle);
-            }
-            dirHandle.close();
-        }
+    public boolean isCloseOnFinished() {
+        return closeOnFinished;
     }
 
-    protected CloseableHandle open(String path) {
-        try {
-            CloseableHandle handle = client.openDir(path);
-            if (log.isDebugEnabled()) {
-                log.debug("open(" + path + ") handle=" + handle);
-            }
-
-            return handle;
-        } catch (IOException e) {
-            if (log.isDebugEnabled()) {
-                log.debug("open(" + path + ") failed (" + e.getClass().getSimpleName() + ") to open dir: " + e.getMessage());
+    @Override
+    public void close() throws IOException {
+        if (open.getAndSet(false)) {
+            Handle handle = getHandle();
+            if ((handle instanceof Closeable) && isCloseOnFinished()) {
+                if (log.isDebugEnabled()) {
+                    log.debug("close(" + getPath() + ") handle=" + handle);
+                }
+                ((Closeable) handle).close();
             }
-            throw new RuntimeException(e);
         }
     }
 
-    protected List<DirEntry> load(CloseableHandle handle) {
+    protected List<DirEntry> load(Handle handle) {
         try {
             // check if previous call yielded an end-of-list indication
             Boolean eolReached = eolIndicator.getAndSet(null);
             if ((eolReached != null) && eolReached.booleanValue()) {
                 if (log.isTraceEnabled()) {
-                    log.trace("load({}) exhausted all entries on previous call", getPath());
+                    log.trace("load({})[{}] exhausted all entries on previous call", getPath(), handle);
                 }
                 return null;
             }
@@ -142,7 +167,7 @@ public class SftpDirEntryIterator extends AbstractLoggingBean implements Iterato
             eolReached = eolIndicator.get();
             if ((entries == null) || ((eolReached != null) && eolReached.booleanValue())) {
                 if (log.isTraceEnabled()) {
-                    log.trace("load({}) exhausted all entries - EOL={}", getPath(), eolReached);
+                    log.trace("load({})[{}] exhausted all entries - EOL={}", getPath(), handle, eolReached);
                 }
                 close();
             }
@@ -164,6 +189,6 @@ public class SftpDirEntryIterator extends AbstractLoggingBean implements Iterato
 
     @Override
     public void remove() {
-        throw new UnsupportedOperationException("readDir(" + getPath() + ") Iterator#remove() N/A");
+        throw new UnsupportedOperationException("readDir(" + getPath() + ")[" + getHandle() + "] Iterator#remove() N/A");
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ae8d1c99/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java
index 11ff32e..4a1bc7a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileSystem.java
@@ -351,6 +351,14 @@ public class SftpFileSystem extends BaseFileSystem<SftpPath> implements ClientSe
         }
 
         @Override
+        public Iterable<DirEntry> listDir(Handle handle) throws IOException {
+            if (!isOpen()) {
+                throw new IOException("readDir(" + handle + ") client is closed");
+            }
+            return delegate.listDir(handle);
+        }
+
+        @Override
         public String canonicalPath(String path) throws IOException {
             if (!isOpen()) {
                 throw new IOException("canonicalPath(" + path + ") client is closed");

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ae8d1c99/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpIterableDirEntry.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpIterableDirEntry.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpIterableDirEntry.java
index 890c0cf..945e0d7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpIterableDirEntry.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpIterableDirEntry.java
@@ -18,7 +18,11 @@
  */
 package org.apache.sshd.client.subsystem.sftp;
 
+import java.io.IOException;
+import java.util.Objects;
+
 import org.apache.sshd.client.subsystem.sftp.SftpClient.DirEntry;
+import org.apache.sshd.common.util.ValidateUtils;
 
 /**
  * Provides an {@link Iterable} implementation of the {@link DirEntry}-ies
@@ -35,8 +39,8 @@ public class SftpIterableDirEntry implements Iterable<DirEntry> {
      * @param path The remote directory path
      */
     public SftpIterableDirEntry(SftpClient client, String path) {
-        this.client = client;
-        this.path = path;
+        this.client = Objects.requireNonNull(client, "No client instance");
+        this.path = ValidateUtils.checkNotNullAndNotEmpty(path, "No remote path");
     }
 
     /**
@@ -59,6 +63,10 @@ public class SftpIterableDirEntry implements Iterable<DirEntry> {
 
     @Override
     public SftpDirEntryIterator iterator() {
-        return new SftpDirEntryIterator(getClient(), getPath());
+        try {
+            return new SftpDirEntryIterator(getClient(), getPath());
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ae8d1c99/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/StfpIterableDirHandle.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/StfpIterableDirHandle.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/StfpIterableDirHandle.java
new file mode 100644
index 0000000..c3be157
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/StfpIterableDirHandle.java
@@ -0,0 +1,59 @@
+/*
+ * 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.sshd.client.subsystem.sftp;
+
+import java.util.Objects;
+
+import org.apache.sshd.client.subsystem.sftp.SftpClient.DirEntry;
+import org.apache.sshd.client.subsystem.sftp.SftpClient.Handle;
+
+public class StfpIterableDirHandle implements Iterable<DirEntry> {
+    private final SftpClient client;
+    private final Handle handle;
+
+    /**
+     * @param client The {@link SftpClient} to use for iteration
+     * @param handle The remote directory {@link Handle}
+     */
+    public StfpIterableDirHandle(SftpClient client, Handle handle) {
+        this.client = Objects.requireNonNull(client, "No client instance");
+        this.handle = handle;
+    }
+
+    /**
+     * The client instance
+     *
+     * @return {@link SftpClient} instance used to access the remote file
+     */
+    public final SftpClient getClient() {
+        return client;
+    }
+
+    /**
+     * @return The remote directory {@link Handle}
+     */
+    public final Handle getHandle() {
+        return handle;
+    }
+
+    @Override
+    public SftpDirEntryIterator iterator() {
+        return new SftpDirEntryIterator(getClient(), getHandle());
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ae8d1c99/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/DirectoryHandle.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/DirectoryHandle.java b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/DirectoryHandle.java
index 9a813ce..0319f6a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/DirectoryHandle.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/DirectoryHandle.java
@@ -30,7 +30,7 @@ import java.util.Iterator;
 public class DirectoryHandle extends Handle implements Iterator<Path> {
 
     private boolean done;
-    private boolean sendDotDot;
+    private boolean sendDotDot = true;
     private boolean sendDot = true;
     // the directory should be read once at "open directory"
     private DirectoryStream<Path> ds;
@@ -41,7 +41,9 @@ public class DirectoryHandle extends Handle implements Iterator<Path> {
         ds = Files.newDirectoryStream(file);
 
         Path parent = file.getParent();
-        sendDotDot = parent != null;  // if no parent then no need to send ".."
+        if (parent == null) {
+            sendDotDot = false;  // if no parent then no need to send ".."
+        }
         fileList = ds.iterator();
     }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ae8d1c99/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
index 89cb6f1..4aa4020 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
@@ -1838,12 +1838,13 @@ public class SftpSubsystem
                 reply = BufferUtils.clear(buffer);
                 reply.putByte((byte) SftpConstants.SSH_FXP_NAME);
                 reply.putInt(id);
+
                 int lenPos = reply.wpos();
                 reply.putInt(0);
 
-                int count = doReadDir(id, handle, dh, reply, PropertyResolverUtils.getIntProperty(getServerSession(), MAX_PACKET_LENGTH_PROP, DEFAULT_MAX_PACKET_LENGTH));
-                BufferUtils.updateLengthPlaceholder(reply, lenPos, count);
                 ServerSession session = getServerSession();
+                int count = doReadDir(id, handle, dh, reply, PropertyResolverUtils.getIntProperty(session, MAX_PACKET_LENGTH_PROP, DEFAULT_MAX_PACKET_LENGTH));
+                BufferUtils.updateLengthPlaceholder(reply, lenPos, count);
                 if ((!dh.isSendDot()) && (!dh.isSendDotDot()) && (!dh.hasNext())) {
                     dh.markDone();
                 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ae8d1c99/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java b/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
index 03c5375..15cef21 100644
--- a/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/KeepAliveTest.java
@@ -37,8 +37,11 @@ import org.apache.sshd.server.SshServer;
 import org.apache.sshd.util.test.BaseTestSupport;
 import org.apache.sshd.util.test.EchoShell;
 import org.apache.sshd.util.test.EchoShellFactory;
+import org.apache.sshd.util.test.Utils;
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.runners.MethodSorters;
@@ -55,34 +58,57 @@ public class KeepAliveTest extends BaseTestSupport {
     private static final long TIMEOUT = 2L * HEARTBEAT;
     private static final long WAIT = 2L * TIMEOUT;
 
-    private SshServer sshd;
-    private int port;
+    private static SshServer sshd;
+    private static int port;
+    private static SshClient client;
 
     public KeepAliveTest() {
         super();
     }
 
-    @Before
-    public void setUp() throws Exception {
-        sshd = setupTestServer();
-        PropertyResolverUtils.updateProperty(sshd, FactoryManager.IDLE_TIMEOUT, TIMEOUT);
+    @BeforeClass
+    public static void setupClientAndServer() throws Exception {
+        sshd = Utils.setupTestServer(KeepAliveTest.class);
         sshd.setShellFactory(new TestEchoShellFactory());
         sshd.start();
         port = sshd.getPort();
+
+        client = Utils.setupTestClient(KeepAliveTest.class);
+        client.start();
     }
 
-    @After
-    public void tearDown() throws Exception {
+    @AfterClass
+    public static void tearDownClientAndServer() throws Exception {
         if (sshd != null) {
-            sshd.stop(true);
+            try {
+                sshd.stop(true);
+            } finally {
+                sshd = null;
+            }
         }
+
+        if (client != null) {
+            try {
+                client.stop();
+            } finally {
+                client = null;
+            }
+        }
+    }
+
+    @Before
+    public void setUp() {
+        PropertyResolverUtils.updateProperty(sshd, FactoryManager.IDLE_TIMEOUT, TIMEOUT);
+    }
+
+    @After
+    public void tearDown() {
+        PropertyResolverUtils.updateProperty(sshd, FactoryManager.IDLE_TIMEOUT, FactoryManager.DEFAULT_IDLE_TIMEOUT);
+        PropertyResolverUtils.updateProperty(client, ClientFactoryManager.HEARTBEAT_INTERVAL, ClientFactoryManager.DEFAULT_HEARTBEAT_INTERVAL);
     }
 
     @Test
     public void testIdleClient() throws Exception {
-        SshClient client = setupTestClient();
-        client.start();
-
         try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
             session.addPasswordIdentity(getCurrentTestName());
             session.auth().verify(5L, TimeUnit.SECONDS);
@@ -92,17 +118,12 @@ public class KeepAliveTest extends BaseTestSupport {
                         channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), WAIT);
                 assertTrue("Wrong channel state: " + result, result.containsAll(EnumSet.of(ClientChannelEvent.CLOSED)));
             }
-        } finally {
-            client.stop();
         }
     }
 
     @Test
     public void testClientWithHeartBeat() throws Exception {
-        SshClient client = setupTestClient();
         PropertyResolverUtils.updateProperty(client, ClientFactoryManager.HEARTBEAT_INTERVAL, HEARTBEAT);
-        client.start();
-
         try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
             session.addPasswordIdentity(getCurrentTestName());
             session.auth().verify(5L, TimeUnit.SECONDS);
@@ -112,8 +133,6 @@ public class KeepAliveTest extends BaseTestSupport {
                         channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), WAIT);
                 assertTrue("Wrong channel state: " + result, result.contains(ClientChannelEvent.TIMEOUT));
             }
-        } finally {
-            client.stop();
         }
     }
 
@@ -121,9 +140,6 @@ public class KeepAliveTest extends BaseTestSupport {
     public void testShellClosedOnClientTimeout() throws Exception {
         TestEchoShell.latch = new CountDownLatch(1);
 
-        SshClient client = setupTestClient();
-        client.start();
-
         try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
             session.addPasswordIdentity(getCurrentTestName());
             session.auth().verify(5L, TimeUnit.SECONDS);
@@ -145,7 +161,6 @@ public class KeepAliveTest extends BaseTestSupport {
             }
         } finally {
             TestEchoShell.latch = null;
-            client.stop();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ae8d1c99/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
index a1cd3dc..291099d 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientSessionListenerTest.java
@@ -43,8 +43,9 @@ import org.apache.sshd.common.session.SessionListener;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.util.test.BaseTestSupport;
-import org.junit.After;
-import org.junit.Before;
+import org.apache.sshd.util.test.Utils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
 import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.runners.MethodSorters;
@@ -54,29 +55,40 @@ import org.junit.runners.MethodSorters;
  */
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public class ClientSessionListenerTest extends BaseTestSupport {
-    private SshServer sshd;
-    private SshClient client;
-    private int port;
+    private static SshServer sshd;
+    private static int port;
+    private static SshClient client;
 
     public ClientSessionListenerTest() {
         super();
     }
 
-    @Before
-    public void setUp() throws Exception {
-        client = setupTestClient();
-        sshd = setupTestServer();
+    @BeforeClass
+    public static void setupClientAndServer() throws Exception {
+        sshd = Utils.setupTestServer(ClientSessionListenerTest.class);
         sshd.start();
         port = sshd.getPort();
+
+        client = Utils.setupTestClient(ClientSessionListenerTest.class);
+        client.start();
     }
 
-    @After
-    public void tearDown() throws Exception {
+    @AfterClass
+    public static void tearDownClientAndServer() throws Exception {
         if (sshd != null) {
-            sshd.stop(true);
+            try {
+                sshd.stop(true);
+            } finally {
+                sshd = null;
+            }
         }
+
         if (client != null) {
-            client.stop();
+            try {
+                client.stop();
+            } finally {
+                client = null;
+            }
         }
     }
 
@@ -87,7 +99,7 @@ public class ClientSessionListenerTest extends BaseTestSupport {
         kexParams.put(KexProposalOption.C2SENC, getLeastFavorite(Cipher.class, client.getCipherFactories()));
         kexParams.put(KexProposalOption.C2SMAC, getLeastFavorite(Mac.class, client.getMacFactories()));
 
-        client.addSessionListener(new SessionListener() {
+        SessionListener listener = new SessionListener() {
             @Override
             @SuppressWarnings("unchecked")
             public void sessionCreated(Session session) {
@@ -95,9 +107,9 @@ public class ClientSessionListenerTest extends BaseTestSupport {
                 session.setCipherFactories(Collections.singletonList((NamedFactory<Cipher>) kexParams.get(KexProposalOption.C2SENC)));
                 session.setMacFactories(Collections.singletonList((NamedFactory<Mac>) kexParams.get(KexProposalOption.C2SMAC)));
             }
-        });
+        };
+        client.addSessionListener(listener);
 
-        client.start();
         try (ClientSession session = createTestClientSession()) {
             for (Map.Entry<KexProposalOption, ? extends NamedResource> ke : kexParams.entrySet()) {
                 KexProposalOption option = ke.getKey();
@@ -106,7 +118,7 @@ public class ClientSessionListenerTest extends BaseTestSupport {
                 assertEquals("Mismatched values for KEX=" + option, expected, actual);
             }
         } finally {
-            client.stop();
+            client.removeSessionListener(listener);
         }
     }
 
@@ -121,7 +133,7 @@ public class ClientSessionListenerTest extends BaseTestSupport {
             }
         };
 
-        client.addSessionListener(new SessionListener() {
+        SessionListener listener = new SessionListener() {
             @Override
             public void sessionEvent(Session session, Event event) {
                 if ((!session.isAuthenticated()) && (session instanceof ClientSession) && Event.KexCompleted.equals(event)) {
@@ -130,9 +142,9 @@ public class ClientSessionListenerTest extends BaseTestSupport {
                     clientSession.setUserInteraction(UserInteraction.NONE);
                 }
             }
-        });
+        };
+        client.addSessionListener(listener);
 
-        client.start();
         try (ClientSession session = createTestClientSession()) {
             assertNotSame("Invalid default user interaction", UserInteraction.NONE, client.getUserInteraction());
             assertNotSame("Invalid default server key verifier", verifier, client.getServerKeyVerifier());
@@ -140,7 +152,7 @@ public class ClientSessionListenerTest extends BaseTestSupport {
             assertSame("Mismatched session server key verifier", verifier, session.getServerKeyVerifier());
             assertEquals("Mismatched verification count", 1, verificationCount.get());
         } finally {
-            client.stop();
+            client.removeSessionListener(listener);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/ae8d1c99/sshd-core/src/test/java/org/apache/sshd/client/kex/KexTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/kex/KexTest.java b/sshd-core/src/test/java/org/apache/sshd/client/kex/KexTest.java
index f6ccfbd..291cfce 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/kex/KexTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/kex/KexTest.java
@@ -42,9 +42,10 @@ import org.apache.sshd.common.util.SecurityUtils;
 import org.apache.sshd.server.SshServer;
 import org.apache.sshd.util.test.BaseTestSupport;
 import org.apache.sshd.util.test.TeeOutputStream;
-import org.junit.After;
+import org.apache.sshd.util.test.Utils;
+import org.junit.AfterClass;
 import org.junit.Assume;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -60,10 +61,11 @@ import org.junit.runners.Parameterized.Parameters;
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @RunWith(Parameterized.class)   // see https://github.com/junit-team/junit/wiki/Parameterized-tests
 public class KexTest extends BaseTestSupport {
+    private static SshServer sshd;
+    private static int port;
+    private static SshClient client;
 
     private final BuiltinDHFactories factory;
-    private SshServer sshd;
-    private int port;
 
     public KexTest(BuiltinDHFactories factory) {
         this.factory = factory;
@@ -74,17 +76,33 @@ public class KexTest extends BaseTestSupport {
         return parameterize(BuiltinDHFactories.VALUES);
     }
 
-    @Before
-    public void setUp() throws Exception {
-        sshd = setupTestServer();
+
+    @BeforeClass
+    public static void setupClientAndServer() throws Exception {
+        sshd = Utils.setupTestServer(KexTest.class);
         sshd.start();
         port = sshd.getPort();
+
+        client = Utils.setupTestClient(KexTest.class);
+        client.start();
     }
 
-    @After
-    public void tearDown() throws Exception {
+    @AfterClass
+    public static void tearDownClientAndServer() throws Exception {
         if (sshd != null) {
-            sshd.stop(true);
+            try {
+                sshd.stop(true);
+            } finally {
+                sshd = null;
+            }
+        }
+
+        if (client != null) {
+            try {
+                client.stop();
+            } finally {
+                client = null;
+            }
         }
     }
 
@@ -103,44 +121,38 @@ public class KexTest extends BaseTestSupport {
         try (ByteArrayOutputStream sent = new ByteArrayOutputStream();
              ByteArrayOutputStream out = new ByteArrayOutputStream()) {
 
-            try (SshClient client = setupTestClient()) {
-                client.setKeyExchangeFactories(Collections.singletonList(kex));
-                client.start();
-
-                try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
-                    session.addPasswordIdentity(getCurrentTestName());
-                    session.auth().verify(5L, TimeUnit.SECONDS);
-
-                    try (ClientChannel channel = session.createChannel(Channel.CHANNEL_SHELL);
-                         PipedOutputStream pipedIn = new PipedOutputStream();
-                         InputStream inPipe = new PipedInputStream(pipedIn);
-                         ByteArrayOutputStream err = new ByteArrayOutputStream();
-                         OutputStream teeOut = new TeeOutputStream(sent, pipedIn)) {
-
-                        channel.setIn(inPipe);
-                        channel.setOut(out);
-                        channel.setErr(err);
-                        channel.open().verify(9L, TimeUnit.SECONDS);
-
-                        teeOut.write("this is my command\n".getBytes(StandardCharsets.UTF_8));
-                        teeOut.flush();
-
-                        StringBuilder sb = new StringBuilder();
-                        for (int i = 0; i < 10; i++) {
-                            sb.append("0123456789");
-                        }
-                        sb.append("\n");
-                        teeOut.write(sb.toString().getBytes(StandardCharsets.UTF_8));
-
-                        teeOut.write("exit\n".getBytes(StandardCharsets.UTF_8));
-                        teeOut.flush();
-
-                        Collection<ClientChannelEvent> result =
-                                channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), TimeUnit.SECONDS.toMillis(15L));
-                        assertFalse("Timeout while waiting for channel closure", result.contains(ClientChannelEvent.TIMEOUT));
+            client.setKeyExchangeFactories(Collections.singletonList(kex));
+            try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(7L, TimeUnit.SECONDS).getSession()) {
+                session.addPasswordIdentity(getCurrentTestName());
+                session.auth().verify(5L, TimeUnit.SECONDS);
+
+                try (ClientChannel channel = session.createChannel(Channel.CHANNEL_SHELL);
+                     PipedOutputStream pipedIn = new PipedOutputStream();
+                     InputStream inPipe = new PipedInputStream(pipedIn);
+                     ByteArrayOutputStream err = new ByteArrayOutputStream();
+                     OutputStream teeOut = new TeeOutputStream(sent, pipedIn)) {
+
+                    channel.setIn(inPipe);
+                    channel.setOut(out);
+                    channel.setErr(err);
+                    channel.open().verify(9L, TimeUnit.SECONDS);
+
+                    teeOut.write("this is my command\n".getBytes(StandardCharsets.UTF_8));
+                    teeOut.flush();
+
+                    StringBuilder sb = new StringBuilder();
+                    for (int i = 0; i < 10; i++) {
+                        sb.append("0123456789");
                     }
-                } finally {
-                    client.stop();
+                    sb.append("\n");
+                    teeOut.write(sb.toString().getBytes(StandardCharsets.UTF_8));
+
+                    teeOut.write("exit\n".getBytes(StandardCharsets.UTF_8));
+                    teeOut.flush();
+
+                    Collection<ClientChannelEvent> result =
+                            channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), TimeUnit.SECONDS.toMillis(15L));
+                    assertFalse("Timeout while waiting for channel closure", result.contains(ClientChannelEvent.TIMEOUT));
                 }
             }