/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.utils.ssh.jsch.executor;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.auth.UserAuth;
import org.apache.sshd.server.auth.password.UserAuthPasswordFactory;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.scp.ScpCommandFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import de.rcenvironment.core.toolkitbridge.transitional.ConcurrencyUtils;
import de.rcenvironment.core.utils.common.TempFileService;
import de.rcenvironment.core.utils.common.TempFileServiceAccess;
import de.rcenvironment.core.utils.ssh.jsch.DummyPasswordAuthenticator;
import de.rcenvironment.core.utils.ssh.jsch.JschSessionFactory;
import de.rcenvironment.core.utils.ssh.jsch.SshParameterException;
import de.rcenvironment.core.utils.ssh.jsch.SshTestUtils;
import de.rcenvironment.toolkit.modules.concurrency.api.RunnablesGroup;
import de.rcenvironment.toolkit.modules.concurrency.api.TaskDescription;
/**
* Test case for {@link JSchCommandLineExecutor}.
*
* @author Doreen Seider
*/
public class JSchCommandLineExecutorParallelTest {
private static final int TIMEOUT = 20000;
private static final String LOCALHOST = "localhost";
private TempFileService tempFileService = TempFileServiceAccess.getInstance();
private File localWorkdir;
private File remoteWorkdir;
/**
* Initial set up of test environment.
*
* @throws IOException on unexpected error
*/
@BeforeClass
public static void initialSetUp() throws IOException {
TempFileServiceAccess.setupUnitTestEnvironment();
}
/**
* Set up test environment.
*
* @throws IOException on unexpected error
**/
@Before
public void setUp() throws IOException {
remoteWorkdir = tempFileService.createManagedTempDir();
localWorkdir = tempFileService.createManagedTempDir();
}
/**
* Tear down test environment.
*
* @throws InterruptedException on error when stopping the server
* @throws IOException on unexpected error
**/
@After
public void tearDown() throws InterruptedException, IOException {
tempFileService.disposeManagedTempDirOrFile(remoteWorkdir);
tempFileService.disposeManagedTempDirOrFile(localWorkdir);
}
/**
* Tests parallel running of several SSH servers (as could happen i.e. on Jenkins)
*
* @author Brigitte Boden
* @throws Exception on unexpected errors
*/
@SuppressWarnings("serial")
@Test(timeout = TIMEOUT)
public void testParallelServers() throws Exception {
final int numServers = 10;
final CountDownLatch threadsCompletedLatch = new CountDownLatch(numServers);
RunnablesGroup runnablesGroup = ConcurrencyUtils.getFactory().createRunnablesGroup();
for (int i = 0; i < numServers; i++) {
runnablesGroup.add(new Runnable() {
@Override
@TaskDescription(value = "Running SSH server")
public void run() {
SshServer sshServer;
int port;
// Starting the SSH server will fail if the port is already in use, in that case it will be retried with another port.
int retry = 0;
do {
port = SshTestUtils.getRandomPortNumber();
sshServer = SshServer.setUpDefaultServer();
sshServer.setPort(port);
sshServer.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
sshServer.setUserAuthFactories(new ArrayList<NamedFactory<UserAuth>>() {
{
add(new UserAuthPasswordFactory());
}
});
sshServer.setPasswordAuthenticator(new DummyPasswordAuthenticator());
try {
sshServer.start();
break;
} catch (IOException e) {
if (retry++ > 3) {
throw new RuntimeException("Failed to start SSH server at port: "
+ port, e);
}
}
} while (true);
// Establish a connections and est downloading work dir
final String fileContent = RandomStringUtils.randomAlphabetic(6);
try {
Session session = JschSessionFactory.setupSession(LOCALHOST, port, DummyPasswordAuthenticator.USERNAME,
null, DummyPasswordAuthenticator.PASSWORD, null);
JSchCommandLineExecutor executor = new JSchCommandLineExecutor(session, remoteWorkdir.getAbsolutePath());
SshTestUtils.createFileOnServerSidesWorkDir(sshServer, session, remoteWorkdir,
RandomStringUtils.randomAlphabetic(6), fileContent, executor);
sshServer.setCommandFactory(new ScpCommandFactory());
File dir = TempFileServiceAccess.getInstance().createManagedTempDir();
executor.downloadWorkdir(dir);
assertEquals(1, dir.listFiles().length);
TempFileServiceAccess.getInstance().disposeManagedTempDirOrFile(dir);
} catch (JSchException | SshParameterException | IOException | InterruptedException e) {
throw new RuntimeException("Testing connection failed", e);
}
try {
sshServer.stop();
} catch (IOException e) {
throw new RuntimeException("Failed to stop server", e);
}
threadsCompletedLatch.countDown();
}
});
}
for (Exception e : runnablesGroup.executeParallel()) {
if (e != null) {
throw e;
}
}
threadsCompletedLatch.await();
}
}