/*******************************************************************************
* Copyright (c) 2015 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.boot.launch.test;
import static org.junit.Assert.assertArrayEquals;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.springframework.ide.eclipse.boot.launch.BootLaunchConfigurationDelegate;
import org.springframework.ide.eclipse.boot.launch.BootLaunchUIModel;
import org.springframework.ide.eclipse.boot.launch.IProfileHistory;
import org.springframework.ide.eclipse.boot.launch.LaunchTabSelectionModel;
import org.springframework.ide.eclipse.boot.launch.MainTypeNameLaunchTabModel;
import org.springframework.ide.eclipse.boot.launch.ProfileLaunchTabModel;
import org.springframework.ide.eclipse.boot.launch.SelectProjectLaunchTabModel;
import org.springframework.ide.eclipse.boot.launch.livebean.EnableJmxFeaturesModel;
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
import org.springsource.ide.eclipse.commons.livexp.core.LiveVariable;
import org.springsource.ide.eclipse.commons.livexp.core.ValidationResult;
import org.springsource.ide.eclipse.commons.livexp.core.Validator;
/**
* @author Kris De Volder
*/
public class BootLaunchUIModelTest extends BootLaunchTestCase {
private static final String[] NO_PROFILES = new String[0];
public class TestProfileHistory implements IProfileHistory {
private Map<String, String[]> map = new HashMap<>();
public String[] getHistory(IProject project) {
String[] h = map.get(project.getName());
if (h!=null) {
return h;
}
return NO_PROFILES;
}
public void setHistory(IProject p, String... history) {
map.put(p.getName(), history);
}
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
protected BootLaunchUIModel model;
protected TestProfileHistory profileHistory;
@Override
protected void setUp() throws Exception {
super.setUp();
profileHistory = new TestProfileHistory();
model = new BootLaunchUIModel(profileHistory);
}
///// project ////////////////////////////////////////////////////////////
public void testProjectValidator() throws Exception {
createPredefinedProject("empty-boot-project");
createGeneralProject("general");
assertError("No project selected", model.project.validator);
model.project.selection.setValue(getProject("non-existant"));
assertError("does not exist", model.project.validator);
model.project.selection.setValue(getProject("general"));
assertError("does not look like a Boot project", model.project.validator);
model.project.selection.setValue(getProject("empty-boot-project"));
assertOk(model.project.validator);
getProject("empty-boot-project").close(new NullProgressMonitor());
model.project.validator.refresh(); //manual refresh is needed
// no auto refresh when closing project. This is normal
// and it is okay since user can't open/close projects
// while using launch config dialog.
assertError("is closed", model.project.validator);
}
private ILaunchConfigurationWorkingCopy createWorkingCopy() throws CoreException {
return createWorkingCopy(BootLaunchConfigurationDelegate.TYPE_ID);
}
public void testProjectInitializeFrom() throws Exception {
IProject fooProject = getProject("foo");
SelectProjectLaunchTabModel project = model.project;
LiveVariable<Boolean> dirtyState = model.project.getDirtyState();
dirtyState.setValue(false);
project.selection.setValue(fooProject);
assertTrue(dirtyState.getValue());
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
project.initializeFrom(wc);
assertEquals(null, project.selection.getValue());
assertFalse(dirtyState.getValue());
BootLaunchConfigurationDelegate.setProject(wc, fooProject);
project.initializeFrom(wc);
assertEquals(fooProject, project.selection.getValue());
}
public void testProjectPerformApply() throws Exception {
IProject fooProject = getProject("foo");
SelectProjectLaunchTabModel project = model.project;
LiveVariable<Boolean> dirtyState = model.project.getDirtyState();
dirtyState.setValue(false);
project.selection.setValue(fooProject);
assertTrue(dirtyState.getValue());
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
assertEquals(null, BootLaunchConfigurationDelegate.getProject(wc));
project.performApply(wc);
assertFalse(dirtyState.getValue());
assertEquals(fooProject, BootLaunchConfigurationDelegate.getProject(wc));
}
public void testProjectSetDefaults() throws Exception {
IProject fooProject = getProject("foo");
SelectProjectLaunchTabModel project = model.project;
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
BootLaunchConfigurationDelegate.setProject(wc, fooProject);
assertEquals(fooProject, BootLaunchConfigurationDelegate.getProject(wc));
project.setDefaults(wc);
assertEquals(null, BootLaunchConfigurationDelegate.getProject(wc));
}
public void testProjectDirtyState() throws Exception {
SelectProjectLaunchTabModel project = model.project;
LiveVariable<Boolean> dirtyState = model.project.getDirtyState();
dirtyState.setValue(false);
project.selection.setValue(getProject("nono"));
assertTrue(dirtyState.getValue());
}
////// main type //////////////////////////////////////////////////////////
public void testMainTypeValidator() throws Exception {
assertEquals("", model.mainTypeName.selection.getValue());
assertError("No Main type selected", model.mainTypeName.validator);
model.mainTypeName.selection.setValue("something");
assertOk(model.mainTypeName.validator);
}
public void testMainTypeInitializeFrom() throws Exception {
MainTypeNameLaunchTabModel mainTypeName = model.mainTypeName;
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
LiveVariable<Boolean> dirtyState = model.mainTypeName.getDirtyState();
BootLaunchConfigurationDelegate.setMainType(wc, "Snuggem");
dirtyState.setValue(true);
mainTypeName.initializeFrom(wc);
assertFalse(dirtyState.getValue());
assertEquals("Snuggem", mainTypeName.selection.getValue());
}
public void testMainTypePerformApply() throws Exception {
MainTypeNameLaunchTabModel mainTypeName = model.mainTypeName;
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
LiveVariable<Boolean> dirtyState = model.mainTypeName.getDirtyState();
mainTypeName.selection.setValue("Koko");
assertTrue(dirtyState.getValue());
mainTypeName.performApply(wc);
assertEquals("Koko", getMainTypeName(wc));
assertFalse(dirtyState.getValue());
}
public void testMainTypeSetDefaults() throws Exception {
MainTypeNameLaunchTabModel mainTypeName = model.mainTypeName;
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
mainTypeName.setDefaults(wc);
assertEquals("", getMainTypeName(wc));
}
protected String getMainTypeName(ILaunchConfigurationWorkingCopy wc)
throws CoreException {
return wc.getAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, (String)null);
}
public void testMainTypeDirtyState() throws Exception {
MainTypeNameLaunchTabModel mainTypeName = model.mainTypeName;
LiveVariable<Boolean> dirtyState = model.mainTypeName.getDirtyState();
dirtyState.setValue(false);
mainTypeName.selection.setValue("something");
assertTrue(dirtyState.getValue());
}
////// profile ////////////////////////////////////////////////////////////////////
public void testProfileValidator() throws Exception {
assertEquals(Validator.OK, model.profile.validator);
//not much to test here, we don't validate profiles at all.
}
public void testProfileSetDefaults() throws Exception {
ProfileLaunchTabModel profile = model.profile;
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
profile.setDefaults(wc);
assertEquals("", BootLaunchConfigurationDelegate.getProfile(wc));
}
public void testProfileInitializeFrom() throws Exception {
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
ProfileLaunchTabModel profile = model.profile;
LiveVariable<Boolean> dirty = profile.getDirtyState();
dirty.setValue(true);
BootLaunchConfigurationDelegate.setProfile(wc,"some-profile");
profile.initializeFrom(wc);
assertFalse(dirty.getValue());
assertEquals("some-profile", BootLaunchConfigurationDelegate.getProfile(wc));
}
public void testProfilePerformApply() throws Exception {
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
ProfileLaunchTabModel profile = model.profile;
LiveVariable<Boolean> dirty = profile.getDirtyState();
profile.selection.setValue("some-other-profile");
assertTrue(dirty.getValue());
profile.performApply(wc);
assertFalse(dirty.getValue());
assertEquals("some-other-profile", BootLaunchConfigurationDelegate.getProfile(wc));
}
public void testProfileDirtyState() throws Exception {
ProfileLaunchTabModel profile = model.profile;
LiveVariable<Boolean> dirty = profile.getDirtyState();
dirty.setValue(false);
profile.selection.setValue("olla-polla");
assertTrue(dirty.getValue());
}
public void testProfilePulldownOptions() throws Exception {
IProject bootProject = createPredefinedProject("empty-boot-project");
IProject generalProject = createGeneralProject("general");
LiveVariable<IProject> project = model.project.selection;
ProfileLaunchTabModel profile = model.profile;
assertPulldown(profile /*empty*/);
createEmptyFile(bootProject, "src/main/resources/application-foo.properties");
createEmptyFile(bootProject, "src/main/resources/application-bar.properties");
project.setValue(bootProject);
assertPulldown(profile, "foo", "bar");
project.setValue(getProject("invalid"));
assertPulldown(profile /*empty*/);
profileHistory.setHistory(generalProject, "something", "borker");
project.setValue(generalProject);
assertPulldown(profile, "something", "borker");
profileHistory.setHistory(bootProject, "old", "older");
project.setValue(bootProject);
assertPulldown(profile, "foo", "bar", "old", "older");
profileHistory.setHistory(bootProject, "new", "newer", "foo");
profile.profileOptions().refresh(); // See [*] below
assertPulldown(profile, "foo", "bar", "new", "newer"); //only a single 'foo'!
// [*] Changing only the history doesn't trigger pull-down options to recompute.
//This is fine since its not possible to change the history while launch dialog is open.
//However, it means test code must force a refresh in cases where only the history
//changed.
}
///// EnableDebugSection///////////////////////////////////////////////////////
public void testDebugValidator() throws Exception {
assertEquals(Validator.OK, model.enableDebug.validator);
}
public void testDebugSetDefaults() throws Exception {
LaunchTabSelectionModel<Boolean> enableDebug = model.enableDebug;
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
enableDebug.setDefaults(wc);
assertEquals(false, BootLaunchConfigurationDelegate.getEnableDebugOutput(wc));
}
public void testDebugInitializeFrom() throws Exception {
LaunchTabSelectionModel<Boolean> enableDebug = model.enableDebug;
LiveVariable<Boolean> dirty = enableDebug.getDirtyState();
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
BootLaunchConfigurationDelegate.setEnableDebugOutput(wc, true);
dirty.setValue(true);
enableDebug.initializeFrom(wc);
assertFalse(dirty.getValue());
assertTrue(enableDebug.selection.getValue());
dirty.setValue(true);
BootLaunchConfigurationDelegate.setEnableDebugOutput(wc, false);
enableDebug.initializeFrom(wc);
assertFalse(dirty.getValue());
assertFalse(enableDebug.selection.getValue());
}
public void testDebugPerformApply() throws Exception {
LaunchTabSelectionModel<Boolean> enableDebug = model.enableDebug;
LiveVariable<Boolean> dirty = enableDebug.getDirtyState();
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
enableDebug.selection.setValue(true);
assertTrue(dirty.getValue());
enableDebug.performApply(wc);
assertFalse(dirty.getValue());
assertTrue(BootLaunchConfigurationDelegate.getEnableDebugOutput(wc));
enableDebug.selection.setValue(false);
assertTrue(dirty.getValue());
enableDebug.performApply(wc);
assertFalse(dirty.getValue());
assertFalse(BootLaunchConfigurationDelegate.getEnableDebugOutput(wc));
}
public void testDebugDirtyState() throws Exception {
LaunchTabSelectionModel<Boolean> enableDebug = model.enableDebug;
LiveVariable<Boolean> dirty = enableDebug.getDirtyState();
dirty.setValue(false);
enableDebug.selection.setValue(true);
assertTrue(dirty.getValue());
}
///// EnableJmxSectiom /////////////////////////////////////////////
public void testJmxValidator() throws Exception {
EnableJmxFeaturesModel eJmxModel = this.model.enableJmx;
LiveVariable<Boolean> jmx = eJmxModel.jmxEnabled;
LiveVariable<Boolean> liveBean = eJmxModel.liveBeanEnabled;
LiveVariable<Boolean> lifeCycle = eJmxModel.lifeCycleEnabled;
LiveVariable<String> port = eJmxModel.port;
LiveVariable<String> timeout = eJmxModel.terminationTimeout;
LiveExpression<ValidationResult> validator = eJmxModel.getValidator();
liveBean.setValue(true);
lifeCycle.setValue(true);
timeout.setValue("5000");
port.setValue("8888");
assertOk(validator);
port.setValue("Unparseable");
assertError("can't be parsed as an Integer", validator);
jmx.setValue(false);
liveBean.setValue(false);
lifeCycle.setValue(false);
assertOk(validator); //if disabled we shouldn't check the port as it doesn't matter.
jmx.setValue(true);
port.setValue("10000000");
liveBean.setValue(true);
assertError("should be smaller than", validator);
jmx.setValue(false);
liveBean.setValue(false);
port.setValue("-111");
assertOk(validator); //if disabled we shouldn't check the port as it doesn't matter.
jmx.setValue(true);
lifeCycle.setValue(true); //only enable lifeCycle
assertFalse(liveBean.getValue());
assertError("should be a positive", validator);
port.setValue("0");
assertOk(validator); // 0 is acceptable as it means 'choose dynamically'.
port.setValue(" 8888 ");
assertOk(validator); // tolerate spaces
port.setValue(null); //
assertError("JMX Port must be specified", validator);
port.setValue(" "); //
assertError("JMX Port must be specified", validator);
port.setValue("");
assertError("JMX Port must be specified", validator);
port.setValue("8888");
assertOk(validator);
timeout.setValue(null);
assertError("Termination timeout must be specified", validator);
timeout.setValue("");
assertError("Termination timeout must be specified", validator);
timeout.setValue(" ");
assertError("Termination timeout must be specified", validator);
timeout.setValue(" 8888 "); // tolerate spaces
assertOk(validator);
timeout.setValue(" -555");
assertError("Termination timeout must be positive", validator);
timeout.setValue("abc");
assertError("Termination timeout can't be parsed as an Integer", validator);
}
public void testJmxSetDefaults() throws Exception {
EnableJmxFeaturesModel eJmxModel = this.model.enableJmx;
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
eJmxModel.setDefaults(wc);
assertTrue(BootLaunchConfigurationDelegate.getEnableLiveBeanSupport(wc));
assertTrue(BootLaunchConfigurationDelegate.getEnableLifeCycle(wc));
int jmxPort = Integer.parseInt(BootLaunchConfigurationDelegate.getJMXPort(wc));
assertEquals(BootLaunchConfigurationDelegate.DEFAULT_JMX_PORT, jmxPort);
}
public void testJmxInitializeFrom() throws Exception {
EnableJmxFeaturesModel eJmxModel = this.model.enableJmx;
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
LiveVariable<Boolean> liveBean = eJmxModel.liveBeanEnabled;
LiveVariable<Boolean> lifeCycle = eJmxModel.lifeCycleEnabled;
LiveVariable<String> port = eJmxModel.port;
LiveVariable<Boolean> dirty = eJmxModel.getDirtyState();
boolean[] bools = {true, false};
for (boolean b1 : bools) {
for (boolean b2 : bools) {
BootLaunchConfigurationDelegate.setEnableLiveBeanSupport(wc, b1);
BootLaunchConfigurationDelegate.setEnableLifeCycle(wc, b2);
BootLaunchConfigurationDelegate.setJMXPort(wc, "3456");
dirty.setValue(true);
eJmxModel.initializeFrom(wc);
assertFalse(dirty.getValue());
assertEquals("3456", port.getValue());
assertEquals(b1, (boolean)liveBean.getValue());
assertEquals(b2, (boolean)lifeCycle.getValue());
}
}
}
public void testJmxPerformApply() throws Exception {
EnableJmxFeaturesModel eJmxModel = this.model.enableJmx;
ILaunchConfigurationWorkingCopy wc = createWorkingCopy();
LiveVariable<Boolean> liveBean = eJmxModel.liveBeanEnabled;
LiveVariable<Boolean> lifeCycle = eJmxModel.lifeCycleEnabled;
LiveVariable<String> port = eJmxModel.port;
LiveVariable<Boolean> dirty = eJmxModel.getDirtyState();
port.setValue("1234");
boolean[] bools = {true, false};
for (boolean b1 : bools) {
for (boolean b2 : bools) {
liveBean.setValue(b1);
lifeCycle.setValue(b2);
assertTrue(dirty.getValue());
eJmxModel.performApply(wc);
assertFalse(dirty.getValue());
assertEquals("1234", BootLaunchConfigurationDelegate.getJMXPort(wc));
assertEquals(b1, BootLaunchConfigurationDelegate.getEnableLiveBeanSupport(wc));
assertEquals(b2, BootLaunchConfigurationDelegate.getEnableLifeCycle(wc));
}
}
//port
port.setValue(" 8888 ");
assertTrue(dirty.getValue());
eJmxModel.performApply(wc);
assertFalse(dirty.getValue());
assertEquals("8888", BootLaunchConfigurationDelegate.getJMXPort(wc));
}
public void testLiveBeanDirtyState() throws Exception {
EnableJmxFeaturesModel eJmxModel = this.model.enableJmx;
LiveVariable<Boolean> liveBean = eJmxModel.liveBeanEnabled;
LiveVariable<Boolean> lifeCycle = eJmxModel.lifeCycleEnabled;
LiveVariable<String> port = eJmxModel.port;
LiveVariable<Boolean> dirty = eJmxModel.getDirtyState();
dirty.setValue(false);
port.setValue("something");
assertTrue(dirty.getValue());
dirty.setValue(false);
liveBean.setValue(!liveBean.getValue());
assertTrue(dirty.getValue());
dirty.setValue(false);
lifeCycle.setValue(!lifeCycle.getValue());
assertTrue(dirty.getValue());
}
///// PropertiesTableSection ??? can't be tested in its current form (no separate 'model' to test)
/**
* Verify contents of 'pulldown' menu. This ignores the order of the elements
* because discovered elements may come in different orders... but does not
* ignore when there are duplicates.
*/
private void assertPulldown(ProfileLaunchTabModel profile, String... expecteds) {
Arrays.sort(expecteds);
String [] actuals = profile.profileOptions().getValue();
actuals = Arrays.copyOf(actuals, actuals.length);
Arrays.sort(actuals);
assertArrayEquals(expecteds, actuals);
}
}