/*
* 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 static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.CommandFactory;
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.utils.common.StringUtils;
import de.rcenvironment.core.utils.common.TempFileService;
import de.rcenvironment.core.utils.common.TempFileServiceAccess;
import de.rcenvironment.core.utils.ssh.jsch.DummyCommand;
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;
/**
* Test case for {@link JSchCommandLineExecutor}.
*
* @author Doreen Seider
*/
public class JSchCommandLineExecutorTest {
private static final String WRONG_COMMAND = "Wrong command: ";
private static final String LOCALHOST = "localhost";
private static final String FULL_COMMAND_TEMPLATE = "cd %s && %s";
private SshServer sshServer;
private int port;
private File localWorkdir;
private File remoteWorkdir;
private TempFileService tempFileService = TempFileServiceAccess.getInstance();
/**
* 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
**/
@SuppressWarnings("serial")
@Before
public void setUp() throws IOException {
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());
sshServer.start();
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 {
sshServer.stop();
tempFileService.disposeManagedTempDirOrFile(remoteWorkdir);
tempFileService.disposeManagedTempDirOrFile(localWorkdir);
}
/**
* Test correct stdout stream.
*
* @throws SshParameterException on error
* @throws JSchException on error
* @throws IOException on error
* @throws InterruptedException on error
**/
@Test(timeout = SshTestUtils.TIMEOUT)
public void testStdout() throws JSchException, SshParameterException, IOException, InterruptedException {
final String out = "console standard output";
final String commandStdout = "command - exit value: 0, stdout";
sshServer.setCommandFactory(new CommandFactory() {
@Override
public Command createCommand(String commandString) {
if (commandString.equals(StringUtils.format(FULL_COMMAND_TEMPLATE, remoteWorkdir.getAbsolutePath(), commandStdout))) {
return new DummyCommand(out, null, 0);
} else {
throw new IllegalArgumentException(WRONG_COMMAND + commandString);
}
}
});
Session session = JschSessionFactory.setupSession(LOCALHOST, port, DummyPasswordAuthenticator.USERNAME,
null, DummyPasswordAuthenticator.PASSWORD, null);
JSchCommandLineExecutor executor = new JSchCommandLineExecutor(session, remoteWorkdir.getAbsolutePath());
executor.start(commandStdout);
try (InputStream stdoutStream = executor.getStdout(); InputStream stderrStream = executor.getStderr();) {
int exitValue = executor.waitForTermination();
assertEquals(out, IOUtils.toString(stdoutStream));
assertEquals(DummyCommand.EMPTY_STRING, IOUtils.toString(stderrStream));
assertEquals(0, exitValue);
}
}
/**
* Test stderr and stdout stream in parallel.
*
* @throws JSchException on error
* @throws SshParameterException on error
* @throws IOException on error
* @throws InterruptedException on error
*/
@Test(timeout = SshTestUtils.TIMEOUT)
public void testStdoutStderrResult() throws JSchException, SshParameterException, IOException, InterruptedException {
final String out = "console standard output";
final String err = "console standard error";
final String commandStdoutStderr = "command - exit value: 0, stdout, stderr";
sshServer.setCommandFactory(new CommandFactory() {
@Override
public Command createCommand(String commandString) {
if (commandString.equals(StringUtils.format(FULL_COMMAND_TEMPLATE, remoteWorkdir.getAbsolutePath(), commandStdoutStderr))) {
return new DummyCommand(out, err, 0);
} else {
throw new IllegalArgumentException(WRONG_COMMAND + commandString);
}
}
});
Session session = JschSessionFactory.setupSession(LOCALHOST, port, DummyPasswordAuthenticator.USERNAME,
null, DummyPasswordAuthenticator.PASSWORD, null);
JSchCommandLineExecutor executor = new JSchCommandLineExecutor(session, remoteWorkdir.getAbsolutePath());
executor.start(commandStdoutStderr);
try (InputStream stdoutStream = executor.getStdout(); InputStream stderrStream = executor.getStderr();) {
int exitValue = executor.waitForTermination();
assertEquals(0, exitValue);
assertEquals(out, IOUtils.toString(stdoutStream));
assertEquals(err, IOUtils.toString(stderrStream));
}
}
/**
* Test correct stderr stream.
*
* @throws JSchException on error
* @throws SshParameterException on error
* @throws IOException on error
* @throws InterruptedException on error
*/
@Test(timeout = SshTestUtils.TIMEOUT)
public void testStderrResult() throws JSchException, SshParameterException, IOException, InterruptedException {
final String err = "console standard error";
final String commandStderr = "command - exit value: 1, stderr";
sshServer.setCommandFactory(new CommandFactory() {
@Override
public Command createCommand(String commandString) {
if (commandString.equals(StringUtils.format(FULL_COMMAND_TEMPLATE, remoteWorkdir.getAbsolutePath(), commandStderr))) {
return new DummyCommand(null, err, 1);
} else {
throw new IllegalArgumentException(WRONG_COMMAND + commandString);
}
}
});
Session session = JschSessionFactory.setupSession(LOCALHOST, port, DummyPasswordAuthenticator.USERNAME,
null, DummyPasswordAuthenticator.PASSWORD, null);
JSchCommandLineExecutor executor = new JSchCommandLineExecutor(session, remoteWorkdir.getAbsolutePath());
executor.start(commandStderr);
try (InputStream stdoutStream = executor.getStdout(); InputStream stderrStream = executor.getStderr();) {
int exitValue = executor.waitForTermination();
assertEquals(DummyCommand.EMPTY_STRING, IOUtils.toString(stdoutStream));
assertEquals(err, IOUtils.toString(stderrStream));
assertEquals(1, exitValue);
}
}
// TODO test with stdin - seid_do
/**
* Test.
*
* @throws JSchException on error
* @throws SshParameterException on error
*/
@Test(timeout = SshTestUtils.TIMEOUT)
public void testGetRemoteWorkDir() throws JSchException, SshParameterException {
Session session = JschSessionFactory.setupSession(LOCALHOST, port, DummyPasswordAuthenticator.USERNAME,
null, DummyPasswordAuthenticator.PASSWORD, null);
JSchCommandLineExecutor executor = new JSchCommandLineExecutor(session, remoteWorkdir.getAbsolutePath());
assertTrue(executor.getWorkDirPath().contains(remoteWorkdir.getAbsolutePath()));
}
/**
* Test.
*
* @throws JSchException on error
* @throws SshParameterException on error
* @throws IOException on error
* @throws InterruptedException on error
*/
@Test(timeout = SshTestUtils.TIMEOUT)
public void testDownloadWorkdir() throws JSchException, SshParameterException, IOException, InterruptedException {
final String fileContent = RandomStringUtils.randomAlphabetic(6);
Session session = JschSessionFactory.setupSession(LOCALHOST, port, DummyPasswordAuthenticator.USERNAME,
null, DummyPasswordAuthenticator.PASSWORD, null);
JSchCommandLineExecutor executor = new JSchCommandLineExecutor(session, remoteWorkdir.getAbsolutePath());
SshTestUtils.createFileOnServerSide(sshServer, session, remoteWorkdir.getAbsolutePath() + 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);
}
/**
* Test.
*
* @throws JSchException on error
* @throws SshParameterException on error
* @throws IOException on error
* @throws InterruptedException on error
*/
@Test(timeout = SshTestUtils.TIMEOUT)
public void testUploadDownloadFileToFromWorkdir() throws JSchException, SshParameterException, IOException, InterruptedException {
final String srcFilename = RandomStringUtils.randomAlphabetic(5);
final String targetFilename = RandomStringUtils.randomAlphabetic(5);
final String fileContent = RandomStringUtils.randomAlphabetic(9);
sshServer.setCommandFactory(new ScpCommandFactory());
Session session = JschSessionFactory.setupSession(LOCALHOST, port, DummyPasswordAuthenticator.USERNAME,
null, DummyPasswordAuthenticator.PASSWORD, null);
JSchCommandLineExecutor executor = new JSchCommandLineExecutor(session, remoteWorkdir.getAbsolutePath());
File srcFile = new File(localWorkdir, srcFilename);
FileUtils.write(srcFile, fileContent);
executor.uploadFileToWorkdir(srcFile, srcFilename);
FileUtils.deleteQuietly(srcFile);
File targetFile = new File(localWorkdir, targetFilename);
executor.downloadFileFromWorkdir(srcFilename, targetFile);
assertEquals(fileContent, FileUtils.readFileToString(targetFile));
FileUtils.deleteQuietly(targetFile);
}
/**
* Test.
*
* @throws JSchException on error
* @throws SshParameterException on error
* @throws IOException on error
* @throws InterruptedException on error
*/
@Test(timeout = SshTestUtils.TIMEOUT)
public void testUploadDownloadDirToFromWorkdir() throws JSchException, SshParameterException, IOException, InterruptedException {
final String srcFilename = RandomStringUtils.randomAlphabetic(5);
final String srcDirname = RandomStringUtils.randomAlphabetic(5);
final String targetDirname = RandomStringUtils.randomAlphabetic(5);
final String fileContent = RandomStringUtils.randomAlphabetic(9);
Session session = JschSessionFactory.setupSession(LOCALHOST, port, DummyPasswordAuthenticator.USERNAME,
null, DummyPasswordAuthenticator.PASSWORD, null);
JSchCommandLineExecutor executor = new JSchCommandLineExecutor(session, remoteWorkdir.getAbsolutePath());
sshServer.setCommandFactory(new ScpCommandFactory() {
@Override
public Command createCommand(String command) {
if (command.startsWith("mkdir")) {
new File(command.split(" ")[2]).mkdirs();
return new DummyCommand();
} else {
return super.createCommand(command);
}
}
});
File srcDir = new File(localWorkdir.getAbsolutePath(), srcDirname);
srcDir.mkdirs();
File srcFile = new File(srcDir, srcFilename);
FileUtils.write(srcFile, fileContent);
assertEquals(1, srcDir.listFiles().length);
assertEquals(srcFilename, srcDir.listFiles()[0].getName());
executor.uploadDirectoryToWorkdir(srcDir, targetDirname);
FileUtils.deleteQuietly(srcDir);
File targetDir = new File(localWorkdir.getAbsolutePath(), RandomStringUtils.randomAlphabetic(5));
targetDir.mkdirs();
executor.downloadDirectoryFromWorkdir(targetDirname + "/" + srcDir.getName(), targetDir);
assertEquals(1, targetDir.listFiles().length);
assertEquals(srcFilename, targetDir.listFiles()[0].listFiles()[0].getName());
assertEquals(fileContent, FileUtils.readFileToString(targetDir.listFiles()[0].listFiles()[0]));
FileUtils.deleteQuietly(targetDir);
}
/**
* Test.
*
* @throws JSchException on error
* @throws SshParameterException on error
* @throws IOException on error
* @throws InterruptedException on error
*/
@Test(timeout = SshTestUtils.TIMEOUT)
public void testUploadDownloadFile() throws JSchException, SshParameterException, IOException, InterruptedException {
final String srcFilename = RandomStringUtils.randomAlphabetic(5);
final String targetFilename = RandomStringUtils.randomAlphabetic(5);
final String remotePath = RandomStringUtils.randomAlphabetic(5);
final String fileContent = RandomStringUtils.randomAlphabetic(9);
sshServer.setCommandFactory(new ScpCommandFactory());
Session session = JschSessionFactory.setupSession(LOCALHOST, port, DummyPasswordAuthenticator.USERNAME,
null, DummyPasswordAuthenticator.PASSWORD, null);
JSchCommandLineExecutor executor = new JSchCommandLineExecutor(session, remoteWorkdir.getAbsolutePath());
File srcFile = new File(localWorkdir, srcFilename);
FileUtils.write(srcFile, fileContent);
executor.uploadFile(srcFile, remoteWorkdir.getAbsolutePath() + remotePath);
FileUtils.deleteQuietly(srcFile);
File localTargetFile = new File(localWorkdir, targetFilename);
executor.downloadFile(remoteWorkdir.getAbsolutePath() + remotePath, localTargetFile);
assertEquals(fileContent, FileUtils.readFileToString(localTargetFile));
FileUtils.deleteQuietly(localTargetFile);
}
/**
* Test.
*
* @throws JSchException on error
* @throws SshParameterException on error
* @throws IOException on error
* @throws InterruptedException on error
*/
@Test(timeout = SshTestUtils.TIMEOUT)
public void testUploadDownloadDirectory() throws JSchException, SshParameterException, IOException, InterruptedException {
final String srcFilename = RandomStringUtils.randomAlphabetic(5);
final String srcDirname = RandomStringUtils.randomAlphabetic(5);
final String fileContent = RandomStringUtils.randomAlphabetic(9);
final String remoteDirpath = RandomStringUtils.randomAlphabetic(5);
sshServer.setCommandFactory(new ScpCommandFactory() {
@Override
public Command createCommand(String command) {
if (command.startsWith("mkdir")) {
new File(command.split(" ")[2]).mkdirs();
return new DummyCommand();
} else {
return super.createCommand(command);
}
}
});
Session session = JschSessionFactory.setupSession(LOCALHOST, port, DummyPasswordAuthenticator.USERNAME,
null, DummyPasswordAuthenticator.PASSWORD, null);
JSchCommandLineExecutor executor = new JSchCommandLineExecutor(session, remoteWorkdir.getAbsolutePath());
File srcDir = new File(remoteWorkdir.getAbsolutePath(), srcDirname);
srcDir.mkdirs();
File srcFile = new File(srcDir, srcFilename);
FileUtils.write(srcFile, fileContent);
assertEquals(1, srcDir.listFiles().length);
assertEquals(srcFilename, srcDir.listFiles()[0].getName());
executor.uploadDirectory(srcDir, remoteWorkdir.getAbsolutePath() + remoteDirpath);
FileUtils.deleteQuietly(srcDir);
File targetDir = new File(localWorkdir.getAbsolutePath(), RandomStringUtils.randomAlphabetic(5));
targetDir.mkdirs();
executor.downloadDirectory(remoteWorkdir.getAbsolutePath() + remoteDirpath + "/" + srcDir.getName(), targetDir);
assertEquals(1, targetDir.listFiles().length);
assertEquals(srcFilename, targetDir.listFiles()[0].listFiles()[0].getName());
assertEquals(fileContent, FileUtils.readFileToString(targetDir.listFiles()[0].listFiles()[0]));
FileUtils.deleteQuietly(targetDir);
}
/**
* Test.
*
* @throws JSchException on error
* @throws SshParameterException on error
* @throws IOException on error
* @throws InterruptedException on error
*/
// TODO combine test: upload, remote copy, download - seid_do
@Test(timeout = SshTestUtils.TIMEOUT)
public void testRemoteCopy() throws JSchException, SshParameterException, IOException, InterruptedException {
String src = "src";
String target = "target";
final String cpCommand = "cp " + src + " " + target;
final String failingCpCommand = "cp " + target + " " + src;
sshServer.setCommandFactory(SshTestUtils.createDummyCommandFactory(cpCommand, "stdout", failingCpCommand, "stderr"));
Session session = JschSessionFactory.setupSession(LOCALHOST, port, DummyPasswordAuthenticator.USERNAME,
null, DummyPasswordAuthenticator.PASSWORD, null);
JSchCommandLineExecutor executor = new JSchCommandLineExecutor(session, remoteWorkdir.getAbsolutePath());
executor.remoteCopy(src, target);
try {
executor.remoteCopy(target, src);
fail();
} catch (IOException e) {
assertTrue(true);
}
}
}