/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.instancemanagement.internal;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import de.rcenvironment.core.configuration.ConfigurationException;
import de.rcenvironment.core.configuration.ConfigurationSegment;
import de.rcenvironment.core.configuration.internal.ConfigurationStore;
import de.rcenvironment.core.configuration.internal.ConfigurationStoreImpl;
import de.rcenvironment.core.instancemanagement.InstanceManagementService.ConfigurationFlag;
import de.rcenvironment.core.instancemanagement.internal.ConfigurationSegmentFactory.SegmentBuilder;
import de.rcenvironment.core.utils.common.TempFileService;
import de.rcenvironment.core.utils.common.TempFileServiceAccess;
import de.rcenvironment.core.utils.common.textstream.receivers.LoggingTextOutReceiver;
/**
* Unit tests for {@link InstanceManagementServiceImpl} that can be run without triggering heavy-weight I/O operations.
*
* @author Robert Mischke
* @author David Scholz
*/
public class InstanceManagementServiceImplTest {
private static final String CONFIG_PATH = "/instanceManagementTest/configuration.json";
private static final String OK_ID = "ok";
private static final String NOT_EXISTING_SHUTDOWN_ID = "bob";
private static final String INVALID_ID_1 = "";
private static final String INVALID_ID_2 = "..";
/**
* Expected exception.
*/
@Rule
public ExpectedException thrown = ExpectedException.none();
private LoggingTextOutReceiver userOutputReceiver;
private InstanceManagementServiceImpl imService;
private SegmentBuilder segmentBuilder = ConfigurationSegmentFactory.getSegmentBuilder();
private ConfigurationStore configStore;
private ConfigurationChangeSequence sequence = new ConfigurationChangeSequence();
private TempFileService tempFileService;
private File testFile;
/**
* Common setup.
*
* @throws IOException on failure.
*/
@Before
public void setUp() throws IOException {
TempFileServiceAccess.setupUnitTestEnvironment();
tempFileService = TempFileServiceAccess.getInstance();
File tempDir = tempFileService.createManagedTempDir();
testFile = tempFileService.createTempFileWithFixedFilename("configuration.json");
imService = new InstanceManagementServiceImpl();
userOutputReceiver = new LoggingTextOutReceiver("");
copyResourceToFile(CONFIG_PATH, testFile);
configStore = new ConfigurationStoreImpl(testFile);
imService.setProfilesRootDir(new File(tempDir.getParentFile().getPath()));
imService.validateLocalConfig();
}
private void copyResourceToFile(String resourcePath, File file) throws IOException, FileNotFoundException {
InputStream testDataStream = getClass().getResourceAsStream(resourcePath);
assertNotNull("Expected test resource not found", testDataStream);
try (FileOutputStream fos = new FileOutputStream(file)) {
IOUtils.copy(testDataStream, fos);
}
}
/**
*
* Clean up.
*
* @throws IOException on failure.
* @throws ConfigurationException on config failure.
*/
@After
public void cleanUp() throws IOException, ConfigurationException {
}
/**
* Tests that stopping an instance, which doesn't exist, won't lead to new folder creation.
*
* @throws IOException on expected failure.
*/
@Test
public void stopingNotExistingInstanceIsProperlyHandled() {
List<String> paramList = new ArrayList<>();
Exception exception = null;
paramList.add(NOT_EXISTING_SHUTDOWN_ID);
try {
imService.stopInstance(paramList, userOutputReceiver, 0);
} catch (IOException e) {
exception = e;
} finally {
assertTrue(exception != null);
assertTrue(exception.getMessage().contains("tried to shutdown instance, which doesn't exist"));
final File profileDir = new File(imService.getProfilesRootDir(), NOT_EXISTING_SHUTDOWN_ID);
assertFalse(profileDir.exists());
}
// fallback solution if {@link InstanceManagementServiceImpl#stopInstance(List<String>, String, TextOutputReceiver)} method
// actually succeeds.
assertTrue(exception != null);
}
/**
* Tests that identical ids in the parameter list of the {@link InstanceManagementServiceImpl#startInstance(List<String>, String,
* de.rcenvironment.core.utils.common.textstream.TextOutputReceiver)} method are rejected.
*
* @throws IOException on expected failure.
*/
@Test
public void identicalIdsAreProperlyRejected() {
List<String> paramList = new ArrayList<>();
List<Exception> exceptionList = new ArrayList<>();
paramList.add(OK_ID);
paramList.add(OK_ID);
String message = "";
boolean success = false;
try {
imService.startInstance(OK_ID, paramList, userOutputReceiver, 0, false);
} catch (IOException e) {
exceptionList.add(e);
} finally {
try {
imService.stopInstance(paramList, userOutputReceiver, 0);
} catch (IOException e) {
exceptionList.add(e);
} finally {
assertTrue(exceptionList.size() == 2);
for (Exception e : exceptionList) {
message = e.getMessage();
if (message.contains("multiple instances with identical id")) {
success = true;
break;
}
}
}
}
if (success) {
assertTrue(message.contains("multiple instances with identical id"));
}
// fallback solution if {@link InstanceManagementServiceImpl#startInstance(List<String>, String, TextOutputReceiver)} method
// actually succeeds.
assertTrue(exceptionList.size() == 2);
}
/**
* Tests that malformed instance ids are properly rejected by all public methods, ie an exception with an appropriate text is thrown.
*
* @throws IOException on failure.
*/
@Test
public void invalidInstanceIdsAreProperlyRejected() throws IOException {
List<String> paramList = new ArrayList<>();
paramList.add(INVALID_ID_1);
thrown.expect(IOException.class);
thrown.expectMessage("Malformed id:");
imService.stopInstance(paramList, userOutputReceiver, 0);
paramList.remove(INVALID_ID_1);
paramList.add(INVALID_ID_2);
imService.stopInstance(paramList, userOutputReceiver, 0);
paramList.remove(INVALID_ID_2);
paramList.add(null);
thrown.expectMessage("Malformed command: either no installation id or instance id defined.");
imService.stopInstance(paramList, userOutputReceiver, 0);
}
/**
* Tests that malformed installation ids are properly rejected by all public methods, ie an exception with an appropriate text is
* thrown.
*
* @throws IOException on failure.
*/
@Test
public void invalidInstalaltionIdsAreProperlyRejected() throws IOException {
List<String> paramList = new ArrayList<>();
paramList.add(OK_ID);
thrown.expect(IOException.class);
thrown.expectMessage("Malformed command: either no installation id or instance id defined.");
imService.startInstance(null, paramList, userOutputReceiver, 0, false);
String id = "Berta";
thrown.expectMessage("Installation with id: " + id + " does not exist.");
paramList.add(id);
imService.startInstance(OK_ID, paramList, userOutputReceiver, 0, false);
}
/**
*
* Test if setting the instance name works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testSettingInstanceName() throws IOException {
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.SET_NAME, String.class, "Bruno"));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.general().getPath());
assertEquals(segment.getString(segmentBuilder.general().instanceName().getConfigurationKey()), "Bruno");
}
/**
*
* Test if setting the instance comment works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testSettingInstanceComment() throws IOException {
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.SET_COMMENT, String.class, "Java ist nice"));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.general().getPath());
assertEquals(segment.getString(segmentBuilder.general().comment().getConfigurationKey()), "Java ist nice");
}
/**
*
* Test if setting the workflow host flag works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testSettingWorkflowHost() throws IOException {
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ENABLE_WORKFLOWHOST, Boolean.class, true));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.general().getPath());
assertEquals(segment.getBoolean(segmentBuilder.general().isWorkflowHost().getConfigurationKey()), true);
}
/**
*
* Test if setting the relay flag works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testSettingRelayFlag() throws IOException {
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ENABLE_RELAY, Boolean.class, true));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.general().getPath());
assertEquals(segment.getBoolean(segmentBuilder.general().isRelay().getConfigurationKey()), true);
}
/**
*
* Test if setting the temp directory works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testSettingTempDir() throws IOException {
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.TEMP_DIR, String.class, "Rachel"));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.general().getPath());
assertEquals(segment.getString(segmentBuilder.general().tempDirectory().getConfigurationKey()), "Rachel");
}
/**
*
* Test if setting the deprecated input tab works corretly.
*
* @throws IOException on failure.
*/
@Test
public void testSettingEnabledDepInTab() throws IOException {
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ENABLE_DEP_INPUT_TAB,
Boolean.class, true));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.general().getPath());
assertEquals(segment.getBoolean(segmentBuilder.general().enableDeprecatedInputTab().getConfigurationKey()), true);
}
/**
*
* Test if setting the background monitoring works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testEnableBackgroundMonitoring() throws IOException {
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("Donna", 2);
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.SET_BACKGROUND_MONITORING, Object.class, map));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.backgroundMonitoring().getPath());
assertEquals(segment.getString(segmentBuilder.backgroundMonitoring().enableIds().getConfigurationKey()), "Donna");
assertTrue(segment.getInteger(segmentBuilder.backgroundMonitoring().intervalSeconds().getConfigurationKey()) == 2);
}
/**
*
* Test if setting the request timeout works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testSettingRequestTimeout() throws IOException {
final long niceValue = 42;
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.REQUEST_TIMEOUT,
Long.class, niceValue));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.network().getPath());
assertTrue(segment.getLong(segmentBuilder.network().requestTimeoutMsec().getConfigurationKey()) == niceValue);
}
/**
*
* Test if setting the forwarding timeout works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testSettingForwardingTimeout() throws IOException {
final long niceValue = 42;
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.FORWARDING_TIMEOUT,
Long.class, niceValue));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.network().getPath());
assertTrue(segment.getLong(segmentBuilder.network().forwardingTimeoutMsec().getConfigurationKey()) == niceValue);
}
/**
*
* Test if adding a new connection correctly.
*
* @throws IOException on failure.
*/
@Test
public void testAddingConnection() throws IOException {
final String name = "Mike";
final String host = "Ross";
final int port = 42;
final boolean connectOnStartup = false;
final long autoRetrylInitDelay = 42;
final long autoRetryMax = 42;
final int multi = 42;
ConfigurationConnection connection =
new ConfigurationConnection(name, host, port, connectOnStartup, autoRetrylInitDelay, autoRetryMax, multi);
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ADD_CONNECTION, ConfigurationConnection.class, connection));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.network().connections().getOrCreateConnection(name).getPath());
assertTrue(segment.getInteger(segmentBuilder.network().connections().getOrCreateConnection(name).autoRetryDelayMultiplier()
.getConfigurationKey()) == multi);
assertTrue(segment.getLong(segmentBuilder.network().connections().getOrCreateConnection(name).autoRetryInitialDelay()
.getConfigurationKey()) == autoRetrylInitDelay);
assertTrue(segment.getLong(segmentBuilder.network().connections().getOrCreateConnection(name).autoRetryMaximumDelay()
.getConfigurationKey()) == autoRetryMax);
assertEquals(
segment.getBoolean(segmentBuilder.network().connections().getOrCreateConnection(name).connectOnStartup().getConfigurationKey()),
false);
assertTrue(segment.getInteger(segmentBuilder.network().connections().getOrCreateConnection(name).port()
.getConfigurationKey()) == port);
assertEquals(segment.getString(segmentBuilder.network().connections().getOrCreateConnection(name).host()
.getConfigurationKey()), host);
}
/**
*
* Test if adding a new server port works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testAddingServerPort() throws IOException {
final int testPort = 42;
List<String> objList = new LinkedList<>();
String name = "sillyPort";
String ip = "niceIP";
String port = Integer.toString(testPort);
objList.add(name);
objList.add(ip);
objList.add(port);
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ADD_SERVER_PORT, Object.class, objList));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.network().ports().getOrCreateServerPort(name).getPath());
assertEquals(segment.getString(segmentBuilder.network().ports().getOrCreateServerPort(name).ip().getConfigurationKey()), ip);
assertEquals(Integer.valueOf(testPort),
segment.getInteger(segmentBuilder.network().ports().getOrCreateServerPort(name).port().getConfigurationKey()));
}
/**
*
* Test if setting the ip filter works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testSettingIpFilter() throws IOException {
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ENABLE_DEP_INPUT_TAB, Boolean.class, true));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.general().getPath());
assertEquals(segment.getBoolean(segmentBuilder.general().enableDeprecatedInputTab().getConfigurationKey()), true);
}
/**
*
* Test if adding an allowed ip works correctly.
*
* @throws IOException on failure.
* @throws ConfigurationException on config failure.
*/
@Test
public void testAddingAllowedIP() throws IOException, ConfigurationException {
String ip = "Jessica";
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ADD_ALLOWED_IP, String.class, ip));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.network().ipFilter().getPath());
assertTrue(segment.getStringArray(segmentBuilder.network().ipFilter().allowedIps().getConfigurationKey()).contains(ip));
}
/**
*
* Test if adding new ssh connection works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testAddingSshConnection() throws IOException {
final String name = "niceConnection";
final String displayName = "nice";
final String host = "bestHost";
final int port = 42;
final String loginName = "nicerLoginName";
ConfigurationSshConnection connection = new ConfigurationSshConnection(name, displayName, host, port, loginName);
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ADD_SSH_CONNECTION, ConfigurationSshConnection.class, connection));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment =
root.getSubSegment(segmentBuilder.sshRemoteAccess().sshConnections().getOrCreateSshConnection(name).getPath());
assertEquals(
segment.getString(segmentBuilder.sshRemoteAccess().sshConnections().getOrCreateSshConnection(name).displayName()
.getConfigurationKey()), displayName);
assertEquals(segment.getString(segmentBuilder.sshRemoteAccess().sshConnections().getOrCreateSshConnection(name).host()
.getConfigurationKey()), host);
assertEquals(
segment.getString(segmentBuilder.sshRemoteAccess().sshConnections().getOrCreateSshConnection(name).loginName()
.getConfigurationKey()), loginName);
assertTrue(segment.getInteger(segmentBuilder.sshRemoteAccess().sshConnections().getOrCreateSshConnection(name).port()
.getConfigurationKey()) == port);
}
/**
*
* Test if adding new published component correctly.
*
* @throws IOException on failure.
* @throws ConfigurationException on config failure.
*/
@Test
public void testAddingPublishedComponent() throws IOException, ConfigurationException {
String component = "heftigeKomponente";
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.PUBLISH_COMPONENT, String.class, component));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.publishing().getPath());
assertTrue(segment.getStringArray(segmentBuilder.publishing().components().getConfigurationKey()).contains(component));
}
/**
*
* Test if setting the ssh server works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testSettingSshServer() throws IOException {
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.ENABLE_SSH_SERVER, Boolean.class, true));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.sshServer().getPath());
assertEquals(segment.getBoolean(segmentBuilder.sshServer().enabled().getConfigurationKey()), true);
}
/**
*
* Test if setting the ssh server ip works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testSettingSshServerIP() throws IOException {
String ip = "Harvey";
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.SET_SSH_SERVER_IP, String.class, ip));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.sshServer().getPath());
assertEquals(segment.getString(segmentBuilder.sshServer().ip().getConfigurationKey()), ip);
}
/**
*
* Test if setting the ssh server port works correctly.
*
* @throws IOException on failure.
*/
@Test
public void testSettingSshServerPort() throws IOException {
final int port = 42;
sequence.append(new ConfigurationChangeEntry(ConfigurationFlag.SET_SSH_SERVER_PORT, Integer.class, port));
imService.configureInstance(testFile.getParentFile().getName(), sequence, userOutputReceiver);
ConfigurationSegment root = configStore.getSnapshotOfRootSegment();
ConfigurationSegment segment = root.getSubSegment(segmentBuilder.sshServer().getPath());
assertTrue(segment.getInteger(segmentBuilder.sshServer().port().getConfigurationKey()) == port);
}
}