/******************************************************************************* * Copyright (c) 2015, 2016 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.dash.test; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.same; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; import static org.springframework.ide.eclipse.boot.dash.test.BootDashModelTest.waitForJobsToComplete; import static org.springframework.ide.eclipse.boot.dash.test.CloudFoundryTestHarness.APP_DELETE_TIMEOUT; import static org.springframework.ide.eclipse.boot.dash.test.CloudFoundryTestHarness.APP_DEPLOY_TIMEOUT; import static org.springframework.ide.eclipse.boot.test.BootProjectTestHarness.withPackaging; import static org.springframework.ide.eclipse.boot.test.BootProjectTestHarness.withStarters; import static org.springsource.ide.eclipse.commons.tests.util.StsTestCase.assertContains; import static org.springsource.ide.eclipse.commons.tests.util.StsTestCase.createFile; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.RandomStringUtils; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.jface.action.IAction; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.ide.eclipse.boot.core.SpringBootCore; import org.springframework.ide.eclipse.boot.dash.cloudfoundry.CloudAppDashElement; import org.springframework.ide.eclipse.boot.dash.cloudfoundry.CloudFoundryBootDashModel; import org.springframework.ide.eclipse.boot.dash.cloudfoundry.CloudFoundryRunTargetType; import org.springframework.ide.eclipse.boot.dash.cloudfoundry.CloudFoundryTargetWizardModel.LoginMethod; import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.CFClientParams; import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.CFCredentials; import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.CFCredentials.CFCredentialType; import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.HealthChecks; import org.springframework.ide.eclipse.boot.dash.cloudfoundry.client.v2.ReactorUtils; import org.springframework.ide.eclipse.boot.dash.dialogs.DeploymentPropertiesDialogModel.ManifestType; import org.springframework.ide.eclipse.boot.dash.dialogs.EditTemplateDialogModel; import org.springframework.ide.eclipse.boot.dash.dialogs.ManifestDiffDialogModel; import org.springframework.ide.eclipse.boot.dash.dialogs.StoreCredentialsMode; import org.springframework.ide.eclipse.boot.dash.metadata.IPropertyStore; import org.springframework.ide.eclipse.boot.dash.metadata.PropertyStoreApi; import org.springframework.ide.eclipse.boot.dash.model.AbstractBootDashModel; import org.springframework.ide.eclipse.boot.dash.model.BootDashElement; import org.springframework.ide.eclipse.boot.dash.model.BootDashModel; import org.springframework.ide.eclipse.boot.dash.model.BootDashModel.ElementStateListener; import org.springframework.ide.eclipse.boot.dash.model.BootDashModel.ModelStateListener; import org.springframework.ide.eclipse.boot.dash.model.LocalBootDashModel; import org.springframework.ide.eclipse.boot.dash.model.RefreshState; import org.springframework.ide.eclipse.boot.dash.model.RunState; import org.springframework.ide.eclipse.boot.dash.model.SecuredCredentialsStore; import org.springframework.ide.eclipse.boot.dash.model.UserInteractions; import org.springframework.ide.eclipse.boot.dash.model.runtargettypes.RunTargetType; import org.springframework.ide.eclipse.boot.dash.test.mocks.MockCFApplication; import org.springframework.ide.eclipse.boot.dash.test.mocks.MockCFSpace; import org.springframework.ide.eclipse.boot.dash.test.mocks.MockCloudFoundryClientFactory; import org.springframework.ide.eclipse.boot.dash.test.mocks.RunStateHistory; import org.springframework.ide.eclipse.boot.dash.test.util.ZipDiff; import org.springframework.ide.eclipse.boot.dash.util.CancelationTokens; import org.springframework.ide.eclipse.boot.dash.views.BootDashActions; import org.springframework.ide.eclipse.boot.dash.views.CustmomizeTargetLabelAction; import org.springframework.ide.eclipse.boot.dash.views.CustomizeTargetLabelDialogModel; import org.springframework.ide.eclipse.boot.test.AutobuildingEnablement; import org.springframework.ide.eclipse.boot.test.BootProjectTestHarness; import org.springframework.ide.eclipse.boot.test.util.TestBracketter; import org.springframework.util.StringUtils; import org.springsource.ide.eclipse.commons.frameworks.core.util.IOUtil; import org.springsource.ide.eclipse.commons.frameworks.test.util.ACondition; 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.ObservableSet; import org.springsource.ide.eclipse.commons.livexp.core.ValidationResult; import org.springsource.ide.eclipse.commons.livexp.core.ValueListener; import org.springsource.ide.eclipse.commons.livexp.util.ExceptionUtil; import org.springsource.ide.eclipse.commons.tests.util.StsTestUtil; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; import org.springframework.ide.eclipse.boot.core.internal.MavenSpringBootProject; /** * @author Kris De Volder */ public class CloudFoundryBootDashModelMockingTest { private TestBootDashModelContext context; private BootProjectTestHarness projects; private UserInteractions ui; private MockCloudFoundryClientFactory clientFactory; private CloudFoundryTestHarness harness; private BootDashActions actions; //////////////////////////////////////////////////////////// public CloudFoundryApplicationHarness appHarness = new CloudFoundryApplicationHarness(null); @Rule public AutobuildingEnablement disableAutoBuild = new AutobuildingEnablement(false); @Rule public TestBracketter testBracketter = new TestBracketter(); private SpringBootCore springBootCore = SpringBootCore.getDefault(); @Before public void setup() throws Exception { StsTestUtil.deleteAllProjects(); this.context = new TestBootDashModelContext( ResourcesPlugin.getWorkspace(), DebugPlugin.getDefault().getLaunchManager() ); this.clientFactory = new MockCloudFoundryClientFactory(); this.harness = CloudFoundryTestHarness.create(context, clientFactory); this.projects = new BootProjectTestHarness(context.getWorkspace()); this.ui = mock(UserInteractions.class); this.actions = new BootDashActions(harness.model, harness.selection.forReading(), harness.sectionSelection, ui); } @After public void tearDown() throws Exception { waitForJobsToComplete(); appHarness.dispose(); clientFactory.assertOnlyImplementedStubsCalled(); harness.dispose(); } //////////////////////////////////////////////////////////// @Test public void testCreateCfTarget() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel target = harness.createCfTarget(targetParams, StoreCredentialsMode.STORE_PASSWORD); assertNotNull(target); CFCredentials credentials = target.getRunTarget().getTargetProperties().getCredentials(); assertEquals(CFCredentialType.PASSWORD, credentials.getType()); assertNotNull(credentials.getSecret()); assertEquals(1, harness.getCfRunTargetModels().size()); } @Test public void testCreateCfTargetSsoAndStoreRefreshToken() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnvWithCredentials(CFCredentials.fromSsoToken(clientFactory.getSsoToken())); { clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel target = harness.createCfTarget(targetParams, StoreCredentialsMode.STORE_TOKEN); assertNotNull(target); CFCredentials credentials = target.getRunTarget().getTargetProperties().getCredentials(); assertEquals(CFCredentialType.REFRESH_TOKEN, credentials.getType()); assertEquals(MockCloudFoundryClientFactory.FAKE_REFRESH_TOKEN, credentials.getSecret()); assertEquals(1, harness.getCfRunTargetModels().size()); } harness.reload(); CloudFoundryBootDashModel target = harness.getCfTargetModel(); assertNotNull(target); CFCredentials credentials = target.getRunTarget().getTargetProperties().getCredentials(); assertEquals(CFCredentialType.REFRESH_TOKEN, credentials.getType()); assertEquals(MockCloudFoundryClientFactory.FAKE_REFRESH_TOKEN, credentials.getSecret()); assertEquals(StoreCredentialsMode.STORE_TOKEN, target.getRunTarget().getTargetProperties().getStoreCredentials()); waitForJobsToComplete(); assertTrue(target.isConnected()); //should auto connect. verifyZeroInteractions(ui); //should not prompt for password (but used stored pass). { SecuredCredentialsStore store = harness.getCredentialsStore(); assertFalse(store.isUnlocked()); //not unlocked because token is stored in simple private file } { IPropertyStore store = harness.getPrivateStore(); String key = harness.privateStoreKey(target); String storedCred = store.get(key); assertEquals(MockCloudFoundryClientFactory.FAKE_REFRESH_TOKEN, storedCred); } } @Test public void testCreateCfTargetSsoAndStoreNothing() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnvWithCredentials(CFCredentials.fromSsoToken(clientFactory.getSsoToken())); { clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel target = harness.createCfTarget(targetParams, StoreCredentialsMode.STORE_NOTHING); assertNotNull(target); CFCredentials credentials = target.getRunTarget().getTargetProperties().getCredentials(); assertEquals(CFCredentialType.REFRESH_TOKEN, credentials.getType()); assertEquals(MockCloudFoundryClientFactory.FAKE_REFRESH_TOKEN, credentials.getSecret()); assertEquals(1, harness.getCfRunTargetModels().size()); } harness.reload(); CloudFoundryBootDashModel target = harness.getCfTargetModel(); assertNotNull(target); CFCredentials credentials = target.getRunTarget().getTargetProperties().getCredentials(); assertNull(credentials); waitForJobsToComplete(); assertFalse(target.isConnected()); //should not auto connect. verifyZeroInteractions(ui); { SecuredCredentialsStore store = harness.getCredentialsStore(); assertFalse(store.isUnlocked()); //not unlocked because token is stored in simple private file assertNull(store.getCredentials(harness.secureStoreKey(target))); } { IPropertyStore store = harness.getPrivateStore(); String key = harness.privateStoreKey(target); String storedCred = store.get(key); assertNull(storedCred); } } @Test public void testCreateCfTargetSsoAndStorePassword() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnvWithCredentials(CFCredentials.fromSsoToken(clientFactory.getSsoToken())); { clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel target = harness.createCfTarget(targetParams, StoreCredentialsMode.STORE_PASSWORD, (wizard) -> { assertContains("'Store Password' is useless for a 'Temporary Code'", wizard.getValidator().getValue().msg); }); //STORE_PASSWORD is meaningless for sso login and should be ignored (so behaves as STORE_NOTHING instead) assertNotNull(target); CFCredentials credentials = target.getRunTarget().getTargetProperties().getCredentials(); assertEquals(CFCredentialType.REFRESH_TOKEN, credentials.getType()); assertEquals(MockCloudFoundryClientFactory.FAKE_REFRESH_TOKEN, credentials.getSecret()); assertEquals(1, harness.getCfRunTargetModels().size()); } harness.reload(); CloudFoundryBootDashModel target = harness.getCfTargetModel(); assertNotNull(target); CFCredentials credentials = target.getRunTarget().getTargetProperties().getCredentials(); assertNull(credentials); waitForJobsToComplete(); assertFalse(target.isConnected()); //should not auto connect. verifyZeroInteractions(ui); { SecuredCredentialsStore store = harness.getCredentialsStore(); assertFalse(store.isUnlocked()); //not unlocked because token is stored in simple private file assertNull(store.getCredentials(harness.secureStoreKey(target))); } { IPropertyStore store = harness.getPrivateStore(); String key = harness.privateStoreKey(target); String storedCred = store.get(key); assertNull(storedCred); } } @Test public void testCreateCfTargetAndStorePassword() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); { clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel target = harness.createCfTarget(targetParams, StoreCredentialsMode.STORE_PASSWORD); assertNotNull(target); CFCredentials credentials = target.getRunTarget().getTargetProperties().getCredentials(); assertEquals(CFCredentialType.PASSWORD, credentials.getType()); assertNotNull(credentials.getSecret()); assertEquals(1, harness.getCfRunTargetModels().size()); SecuredCredentialsStore store = harness.getCredentialsStore(); assertTrue(store.isUnlocked()); } harness.reload(); { CloudFoundryBootDashModel target = harness.getCfTargetModel(); String expectedPass = targetParams.getCredentials().getSecret(); assertNotNull(target); CFCredentials credentials = target.getRunTarget().getTargetProperties().getCredentials(); String password = credentials.getSecret(); assertEquals(CFCredentialType.PASSWORD, credentials.getType()); assertEquals(expectedPass, password); assertEquals(StoreCredentialsMode.STORE_PASSWORD, target.getRunTarget().getTargetProperties().getStoreCredentials()); waitForJobsToComplete(); assertTrue(target.isConnected()); //should auto connect. verifyZeroInteractions(ui); //should not prompt for password (but used stored pass). { SecuredCredentialsStore store = harness.getCredentialsStore(); assertTrue(store.isUnlocked()); String key = harness.secureStoreKey(target); String storedCred = store.getCredentials(key); assertEquals(expectedPass, storedCred); } { IPropertyStore store = harness.getPrivateStore(); String key = harness.privateStoreKey(target); String storedCred = store.get(key); assertNull(storedCred); } } } @Test public void testCreateCfTargetAndForgetPassword() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); { CloudFoundryBootDashModel target = harness.createCfTarget(targetParams, StoreCredentialsMode.STORE_NOTHING); assertNotNull(target); CFCredentials credentials = target.getRunTarget().getTargetProperties().getCredentials(); assertEquals(CFCredentialType.REFRESH_TOKEN, credentials.getType()); assertNotNull(credentials.getSecret()); assertEquals(1, harness.getCfRunTargetModels().size()); SecuredCredentialsStore store = harness.getCredentialsStore(); assertFalse(store.isUnlocked()); // should not have gotten unlocked. } harness.reload(); { CloudFoundryBootDashModel target = harness.getCfTargetModel(); waitForJobsToComplete(); assertEquals(StoreCredentialsMode.STORE_NOTHING, target.getRunTarget().getTargetProperties().getStoreCredentials()); assertNotNull(target); assertNull(target.getRunTarget().getTargetProperties().getCredentials()); assertFalse(target.isConnected()); // no auto connect if no creds are stored. { //check secure store is clean SecuredCredentialsStore store = harness.getCredentialsStore(); assertFalse(store.isUnlocked()); // should not have gotten unlocked. String storedCred = store.getCredentials(harness.secureStoreKey(target)); assertNull(storedCred); } { //check private store is clean IPropertyStore store = harness.getPrivateStore(); String storedCred = store.get(harness.privateStoreKey(target)); assertNull(storedCred); } verifyZeroInteractions(ui); //When we connect... the user should get prompted for password harness.answerPasswordPrompt(ui, (d) -> { d.getMethodVar().setValue(targetParams.getCredentials().getType().toLoginMethod()); d.getPasswordVar().setValue(targetParams.getCredentials().getSecret()); d.validateCredentials().block(); d.performOk(); }); harness.sectionSelection.setValue(target); IAction connectAction = actions.getToggleTargetConnectionAction(); connectAction.run(); ACondition.waitFor("connected to target", 5_000, () -> { assertTrue(target.isConnected()); }); verify(ui).openPasswordDialog(any()); verifyNoMoreInteractions(ui); } } @Test public void testCreateCfTargetAndStoreToken() throws Exception { { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); space.defApp("foo"); clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel target = harness.createCfTarget(targetParams, StoreCredentialsMode.STORE_TOKEN); assertNotNull(target); assertTrue(target.isConnected()); CFCredentials credentials = target.getRunTarget().getTargetProperties().getCredentials(); assertEquals(CFCredentialType.REFRESH_TOKEN, credentials.getType()); assertEquals(MockCloudFoundryClientFactory.FAKE_REFRESH_TOKEN, credentials.getSecret()); assertEquals(1, harness.getCfRunTargetModels().size()); } harness.reload(); { CloudFoundryBootDashModel target = harness.getCfTargetModel(); { //secure store shouldn't have been accessed (i.e. avoid opening it and popping password) SecuredCredentialsStore store = harness.getCredentialsStore(); assertFalse(store.isUnlocked()); String key = harness.secureStoreKey(target); String storedCred = store.getCredentials(key); assertNull(storedCred); } { IPropertyStore store = harness.getPrivateStore(); String key = harness.privateStoreKey(target); String storedCred = store.get(key); assertEquals(MockCloudFoundryClientFactory.FAKE_REFRESH_TOKEN, storedCred); } assertNotNull(target); CFCredentials credentials = target.getRunTarget().getTargetProperties().getCredentials(); assertEquals(MockCloudFoundryClientFactory.FAKE_REFRESH_TOKEN, credentials.getSecret()); assertEquals(CFCredentialType.REFRESH_TOKEN, credentials.getType()); assertEquals(StoreCredentialsMode.STORE_TOKEN, target.getRunTarget().getTargetProperties().getStoreCredentials()); waitForJobsToComplete(); assertTrue(target.isConnected()); //should auto connect. verifyZeroInteractions(ui); //should not prompt for password (but used stored token). } } @Test public void testAppsShownInBootDash() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); space.defApp("foo"); space.defApp("bar"); final CloudFoundryBootDashModel target = harness.createCfTarget(targetParams); new ACondition("wait for apps to appear", 3000) { @Override public boolean test() throws Exception { ImmutableSet<String> appNames = getNames(target.getApplications().getValues()); assertEquals(ImmutableSet.of("foo", "bar"), appNames); return true; } }; } @Test public void testBasicRefreshApps() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); space.defApp("foo"); space.defApp("bar"); final CloudFoundryBootDashModel target = harness.createCfTarget(targetParams); waitForApps(target, "foo", "bar"); space.defApp("anotherfoo"); space.defApp("anotherbar"); target.refresh(ui); waitForApps(target, "foo", "bar", "anotherfoo", "anotherbar"); } @Test public void testRefreshAppsRunState() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); final MockCFApplication foo = space.defApp("foo"); space.defApp("bar"); final CloudFoundryBootDashModel target = harness.createCfTarget(targetParams); waitForApps(target, "foo", "bar"); foo.start(CancelationTokens.NULL); target.refresh(ui); new ACondition("wait for app states", 3000) { @Override public boolean test() throws Exception { ImmutableSet<String> appNames = getNames(target.getApplications().getValues()); assertEquals(ImmutableSet.of("foo", "bar"), appNames); CloudAppDashElement appElement = harness.getCfTargetModel().getApplication("foo"); assertEquals(RunState.RUNNING, appElement.getRunState()); appElement = harness.getCfTargetModel().getApplication("bar"); assertEquals(RunState.INACTIVE, appElement.getRunState()); return true; } }; } @Test public void testRefreshAppsHealthCheck() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); final MockCFApplication foo = space.defApp("foo"); final CloudFoundryBootDashModel target = harness.createCfTarget(targetParams); waitForApps(target, "foo"); CloudAppDashElement appElement = harness.getCfTargetModel().getApplication("foo"); assertEquals(HealthChecks.HC_PORT, appElement.getHealthCheck()); foo.setHealthCheckType(HealthChecks.HC_NONE); target.refresh(ui); new ACondition("wait for app health check", 3000) { @Override public boolean test() throws Exception { ImmutableSet<String> appNames = getNames(target.getApplications().getValues()); assertEquals(ImmutableSet.of("foo"), appNames); CloudAppDashElement appElement = harness.getCfTargetModel().getApplication("foo"); assertEquals(HealthChecks.HC_NONE, appElement.getHealthCheck()); return true; } }; } @Test public void testRefreshServices() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); space.defApp("foo"); space.defService("elephantsql"); space.defService("cleardb"); final CloudFoundryBootDashModel target = harness.createCfTarget(targetParams); waitForApps(target, "foo"); waitForServices(target, "elephantsql", "cleardb"); waitForElements(target, "foo", "elephantsql", "cleardb"); space.defService("rabbit"); target.refresh(ui); waitForServices(target, "elephantsql", "cleardb", "rabbit"); waitForElements(target, "foo", "elephantsql", "cleardb", "rabbit"); } @Test public void testAppsAndServicesShownInBootDash() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); space.defApp("foo"); space.defApp("bar"); space.defService("a-sql"); space.defService("z-rabbit"); final CloudFoundryBootDashModel target = harness.createCfTarget(targetParams); assertTrue(target.isConnected()); debugListener("applications", target.getApplications()); debugListener("services", target.getServices()); debugListener("all", target.getElements()); new ACondition("wait for elements to appear", 3000) { @Override public boolean test() throws Exception { ImmutableSet<String> appNames = getNames(target.getApplications().getValues()); ImmutableSet<String> serviceNames = getNames(target.getServices().getValues()); ImmutableSet<String> allNames = getNames(target.getElements().getValues()); assertEquals(ImmutableSet.of("foo", "bar"), appNames); assertEquals(ImmutableSet.of("a-sql", "z-rabbit"), serviceNames); assertEquals(ImmutableSet.of("foo", "bar", "a-sql", "z-rabbit"), allNames); return true; } }; //Also test we sort this stuff in the right order. ArrayList<BootDashElement> elements = new ArrayList<>(target.getElements().getValues()); Collections.sort(elements, target.getElementComparator()); assertNames(elements, //first apps... alphabetic "bar", "foo", //then services... alphabetic "a-sql", "z-rabbit" ); //For https://www.pivotaltracker.com/story/show/114408475 // Apps and services should disappear when target is disconnected IAction toggleConnection = actions.getToggleTargetConnectionAction(); harness.sectionSelection.setValue(target); toggleConnection.run(); new ACondition("wait for elements to disappear", 10000) { @Override public boolean test() throws Exception { assertFalse(target.isConnected()); ImmutableSet<String> appNames = getNames(target.getApplications().getValues()); ImmutableSet<String> serviceNames = getNames(target.getServices().getValues()); ImmutableSet<String> allNames = getNames(target.getElements().getValues()); assertEquals(ImmutableSet.of(), appNames); assertEquals(ImmutableSet.of(), serviceNames); assertEquals(ImmutableSet.of(), allNames); return true; } }; } @Test public void testDeployActionsSorted() throws Exception { //Generate some random 'space' names. String orgName = "CloudRunAMock"; String[] spaceNames = new String[6]; for (int i = 0; i < spaceNames.length; i++) { spaceNames[i] = RandomStringUtils.randomAlphabetic(10).toLowerCase(); } //Define the spaces in the 'mock' cloud: for (String spaceName : spaceNames) { //Since this is just a mock client we creating, the params don't matter all that much at all. clientFactory.defSpace(orgName, spaceName); } //Create targets in the boot dash that connect to these spaces: for (String spaceName : spaceNames) { CFClientParams params = new CFClientParams( "http://api.run.cloud.mock.com", "some-user", CFCredentials.fromPassword(MockCloudFoundryClientFactory.FAKE_PASSWORD), false, orgName, spaceName, false ); harness.createCfTarget(params); } { ImmutableList<IAction> deployActions = actions.getDebugOnTargetActions(); assertEquals(spaceNames.length, deployActions.size()); assertSorted(deployActions); } { ImmutableList<IAction> deployActions = actions.getRunOnTargetActions(); assertEquals(spaceNames.length, deployActions.size()); assertSorted(deployActions); } } @Test public void targetTypeProperties() throws Exception { { CloudFoundryRunTargetType cfTargetType = harness.getCfTargetType(); PropertyStoreApi props = cfTargetType.getPersistentProperties(); props.put("testkey", "testvalue"); assertEquals("testvalue", props.get("testkey")); } harness.reload(); { CloudFoundryRunTargetType cfTargetType = harness.getCfTargetType(); PropertyStoreApi props = cfTargetType.getPersistentProperties(); assertEquals("testvalue", props.get("testkey")); } } @Test public void appsManagerDefaultHost() throws Exception { MockCFSpace space = clientFactory.defSpace("my-org", "foo"); String apiUrl = "http://api.some-cloud.com"; String username = "freddy"; String password = MockCloudFoundryClientFactory.FAKE_PASSWORD; CloudFoundryBootDashModel cfModel = harness.createCfTarget(new CFClientParams( apiUrl, username, CFCredentials.fromPassword(password), false, "my-org", "foo", false)); assertEquals("http://console.some-cloud.com", cfModel.getRunTarget().getAppsManagerHost()); assertEquals("http://console.some-cloud.com", cfModel.getRunTarget().getAppsManagerHostDefault()); assertEquals("http://console.some-cloud.com/organizations/" + space.getOrganization().getGuid() + "/spaces/" + space.getGuid(), cfModel.getRunTarget().getAppsManagerURL()); } @Test public void appsManagerCustomizedHost() throws Exception { MockCFSpace space = clientFactory.defSpace("my-org", "foo"); String apiUrl = "http://api.some-cloud.com"; String username = "freddy"; String password = MockCloudFoundryClientFactory.FAKE_PASSWORD; CloudFoundryBootDashModel cfModel = harness.createCfTarget(new CFClientParams(apiUrl, username, CFCredentials.fromPassword(password), false, "my-org", "foo", false )); cfModel.getRunTarget().setAppsManagerHost("http://totallyDifferentHost.com"); assertEquals("http://totallyDifferentHost.com", cfModel.getRunTarget().getAppsManagerHost()); assertEquals("http://console.some-cloud.com", cfModel.getRunTarget().getAppsManagerHostDefault()); assertEquals("http://totallyDifferentHost.com/organizations/" + space.getOrganization().getGuid() + "/spaces/" + space.getGuid(), cfModel.getRunTarget().getAppsManagerURL()); } @Test public void templateDrivenTargetNames() throws Exception { clientFactory.defSpace("my-org", "foo"); clientFactory.defSpace("your-org", "bar"); String apiUrl = "http://api.some-cloud.com"; String username = "freddy"; String password = MockCloudFoundryClientFactory.FAKE_PASSWORD; AbstractBootDashModel fooSpace = harness.createCfTarget(new CFClientParams(apiUrl, username, CFCredentials.fromPassword(password), false, "my-org", "foo", false)); AbstractBootDashModel barSpace = harness.createCfTarget(new CFClientParams(apiUrl, username, CFCredentials.fromPassword(password), false, "your-org", "bar", false)); //check the default rendering is like it used to be before introducing templates. assertEquals("my-org : foo - [http://api.some-cloud.com]", fooSpace.getDisplayName()); assertEquals("your-org : bar - [http://api.some-cloud.com]", barSpace.getDisplayName()); RunTargetType targetType = fooSpace.getRunTarget().getType(); //Let's try switching the order of org and space targetType.setNameTemplate("%s - %o @ %a"); assertEquals("foo - my-org @ http://api.some-cloud.com", fooSpace.getDisplayName()); assertEquals("bar - your-org @ http://api.some-cloud.com", barSpace.getDisplayName()); //Let's try adding 'username' into the label targetType.setNameTemplate("%u@%s"); assertEquals("freddy@foo", fooSpace.getDisplayName()); assertEquals("freddy@bar", barSpace.getDisplayName()); } @Test public void customizeTargetLabelAction() throws Exception { clientFactory.defSpace("my-org", "foo"); clientFactory.defSpace("your-org", "bar"); String apiUrl = "http://api.some-cloud.com"; String username = "freddy"; String password = MockCloudFoundryClientFactory.FAKE_PASSWORD; LocalBootDashModel local = harness.getLocalModel(); AbstractBootDashModel fooSpace = harness.createCfTarget(new CFClientParams(apiUrl, username, CFCredentials.fromPassword(password), false, "my-org", "foo", false)); AbstractBootDashModel barSpace = harness.createCfTarget(new CFClientParams(apiUrl, username, CFCredentials.fromPassword(password), false, "your-org", "bar", false)); CustmomizeTargetLabelAction action = actions.getCustomizeTargetLabelAction(); //////////// not applicable for local targets: harness.sectionSelection.setValue(local); assertFalse(action.isEnabled()); assertFalse(action.isVisible()); //////////// for cf targets ////////////////////////////////////////////////// harness.sectionSelection.setValue(fooSpace); assertTrue(action.isEnabled()); assertTrue(action.isVisible()); ModelStateListener modelStateListener = mock(ModelStateListener.class); fooSpace.addModelStateListener(modelStateListener); barSpace.addModelStateListener(modelStateListener); doAnswer(editSetTemplate("%s - %o @ %a")) .when(ui).openEditTemplateDialog(any(EditTemplateDialogModel.class)); action.run(); //Changing the template should result in modelStateListener firing on all the affected models verify(modelStateListener).stateChanged(same(fooSpace)); verify(modelStateListener).stateChanged(same(barSpace)); assertEquals("foo - my-org @ http://api.some-cloud.com", fooSpace.getDisplayName()); assertEquals("bar - your-org @ http://api.some-cloud.com", barSpace.getDisplayName()); //Let's also try a user interaction that involves the 'Restore Defaults' button... reset(ui, modelStateListener); doAnswer(restoreDefaultTemplate()) .when(ui).openEditTemplateDialog(any(EditTemplateDialogModel.class)); action.run(); verify(modelStateListener).stateChanged(same(fooSpace)); verify(modelStateListener).stateChanged(same(barSpace)); assertEquals("my-org : foo - [http://api.some-cloud.com]", fooSpace.getDisplayName()); assertEquals("your-org : bar - [http://api.some-cloud.com]", barSpace.getDisplayName()); } @Test public void customizeTargetLabelDialog() throws Exception { EditTemplateDialogModel dialog; clientFactory.defSpace("my-org", "foo"); clientFactory.defSpace("your-org", "bar"); String apiUrl = "http://api.some-cloud.com"; String username = "freddy"; String password = MockCloudFoundryClientFactory.FAKE_PASSWORD; AbstractBootDashModel fooSpace = harness.createCfTarget(new CFClientParams(apiUrl, username, CFCredentials.fromPassword(password), false, "my-org", "foo", false)); AbstractBootDashModel barSpace = harness.createCfTarget(new CFClientParams(apiUrl, username, CFCredentials.fromPassword(password), false, "your-org", "bar", false)); ModelStateListener modelStateListener = mock(ModelStateListener.class); fooSpace.addModelStateListener(modelStateListener); barSpace.addModelStateListener(modelStateListener); // Check initial state of the dialog when no custom labels have yet been set at all: dialog = CustomizeTargetLabelDialogModel.create(fooSpace); assertTrue(dialog.applyToAll.getValue()); assertEquals("%o : %s - [%a]", dialog.template.getValue()); //Check performOk only changes the one label when 'apply to all' is disabled. dialog.applyToAll.setValue(false); dialog.template.setValue("CHANGED %s -> %o"); dialog.performOk(); assertEquals("CHANGED foo -> my-org", fooSpace.getDisplayName()); assertEquals("your-org : bar - [http://api.some-cloud.com]", barSpace.getDisplayName()); verify(modelStateListener).stateChanged(same(fooSpace)); verify(modelStateListener, never()).stateChanged(same(barSpace)); //Opening the dialog now should have 'apply to all' disabled to avoid accidentally overwriting // existing individually customized labels... dialog = CustomizeTargetLabelDialogModel.create(fooSpace); assertFalse(dialog.applyToAll.getValue()); assertEquals("CHANGED %s -> %o", dialog.template.getValue()); //Also if we open the dialog on the other element!!! dialog = CustomizeTargetLabelDialogModel.create(barSpace); assertFalse(dialog.applyToAll.getValue()); assertEquals("%o : %s - [%a]", dialog.template.getValue()); //Selecting 'apply to all' should set the template on the type and erase custom templates on the // individual targets. dialog.applyToAll.setValue(true); dialog.template.setValue("DIFFERENT %s -> %o"); dialog.performOk(); assertEquals("DIFFERENT %s -> %o", harness.getCfTargetType().getNameTemplate()); for (BootDashModel target : harness.getCfRunTargetModels()) { assertFalse(target.hasCustomNameTemplate()); assertEquals("DIFFERENT %s -> %o", target.getNameTemplate()); } assertEquals("DIFFERENT foo -> my-org", fooSpace.getDisplayName()); assertEquals("DIFFERENT bar -> your-org", barSpace.getDisplayName()); } @Test public void testEnvVarsSetOnFirstDeploy() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel target = harness.createCfTarget(targetParams); final CloudFoundryBootDashModel model = harness.getCfTargetModel(); IProject project = projects.createBootProject("to-deploy", withStarters("actuator", "web")); final String appName = appHarness.randomAppName(); Map<String, String> env = new HashMap<>(); env.put("FOO", "something"); harness.answerDeploymentPrompt(ui, appName, appName, env); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); new ACondition("wait for app '"+ appName +"'to be RUNNING", 30000) { //why so long? JDT searching for main type. public boolean test() throws Exception { CloudAppDashElement element = model.getApplication(appName); assertEquals(RunState.RUNNING, element.getRunState()); return true; } }; Map<String,String> actualEnv = harness.fetchEnvironment(target, appName); assertEquals("something", actualEnv.get("FOO")); } @Test public void appToProjectBindingsPersisted() throws Exception { final String appName = "foo"; String projectName = "to-deploy"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); final IProject project = projects.createBootProject(projectName, withStarters("actuator", "web")); harness.createCfTarget(targetParams); { final CloudFoundryBootDashModel model = harness.getCfTargetModel(); deployApp(model, appName, project); CloudAppDashElement appByProject = getApplication(model, project); CloudAppDashElement appByName = model.getApplication(appName); assertNotNull(appByProject); assertEquals(appByProject, appByName); } harness.reload(); { final CloudFoundryBootDashModel model = harness.getCfTargetModel(); waitForApps(model, appName); CloudAppDashElement appByName = model.getApplication(appName); CloudAppDashElement appByProject = getApplication(model, project); assertNotNull(appByProject); assertEquals(appByProject, appByName); } } @Test public void appToProjectBindingsPersistedAfterDisconnectConnect() throws Exception { final String appName = "foo"; String projectName = "to-deploy"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); final IProject project = projects.createBootProject(projectName, withStarters("actuator", "web")); final CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); deployApp(model, appName, project); assertAppToProjectBinding(model, project, appName); IAction toggleConnectionAction = actions.getToggleTargetConnectionAction(); harness.sectionSelection.setValue(model); toggleConnectionAction.run(); waitForElements(model /*none*/); toggleConnectionAction.run(); waitForElements(model, appName); assertAppToProjectBinding(model, project, appName); } @Test public void appToProjectBindingChangedAfterProjectRename() throws Exception { final String appName = "foo"; String projectName = "to-deploy"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); space.defApp(appName); final IProject project = projects.createProject(projectName); final CloudFoundryBootDashModel target = harness.createCfTarget(targetParams); waitForApps(target, appName); CloudAppDashElement app = target.getApplication(appName); app.setProject(project); assertAppToProjectBinding(target, project, appName); ElementStateListener elementStateListener = mock(ElementStateListener.class); target.addElementStateListener(elementStateListener); final IProject newProject = projects.rename(project, projectName+"-RENAMED"); // resource listeners called synchronously by eclipse so we don't need ACondition assertAppToProjectBinding(target, newProject, appName); //state change event should have been fired (to update label of element in view) verify(elementStateListener).stateChanged(same(app)); } @Test public void appToProjectBindingForgottenAfterDelete() throws Exception { final String appName = "foo"; String projectName = "to-deploy"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); space.defApp(appName); final IProject project = projects.createProject(projectName); final CloudFoundryBootDashModel target = harness.createCfTarget(targetParams); waitForApps(target, appName); CloudAppDashElement app = target.getApplication(appName); app.setProject(project); assertAppToProjectBinding(target, project, appName); ElementStateListener elementStateListener = mock(ElementStateListener.class); target.addElementStateListener(elementStateListener); project.delete(true, new NullProgressMonitor()); assertNull(app.getProject(true)); verify(elementStateListener).stateChanged(same(app)); } @Test public void runstateBecomesUnknownWhenStartOperationFails() throws Exception { final String appName = "foo"; String projectName = "to-deploy"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); MockCFApplication app = space.defApp(appName); final IProject project = projects.createProject(projectName); final CloudFoundryBootDashModel target = harness.createCfTarget(targetParams); waitForApps(target, appName); CloudAppDashElement appElement = target.getApplication(appName); appElement.setProject(project); //The state refressh is asynch so until state becomes 'INACTIVE' it will be unknown. waitForState(appElement, RunState.INACTIVE, 3000); IAction restartAction = actions.getRestartOnlyApplicationAction(); RunStateHistory runstateHistory = new RunStateHistory(); appElement.getBaseRunStateExp().addListener(runstateHistory); doThrow(IOException.class).when(app).start(any()); System.out.println("restarting application..."); harness.selection.setElements(appElement); restartAction.run(); waitForState(appElement, RunState.UNKNOWN, 3000); runstateHistory.assertHistoryContains( RunState.INACTIVE, RunState.STARTING ); runstateHistory.assertLast( RunState.UNKNOWN ); } @Test public void refreshClearsErrorState() throws Exception { final String appName = "foo"; String projectName = "to-deploy"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); space.defApp(appName); final IProject project = projects.createProject(projectName); final CloudFoundryBootDashModel target = harness.createCfTarget(targetParams); waitForApps(target, appName); CloudAppDashElement appElement = target.getApplication(appName); appElement.setProject(project); waitForState(appElement, RunState.INACTIVE, 3000); //The state refressh is asynch so until state becomes 'INACTIVE' it will be unknown. appElement.setError(new IOException("Something bad happened")); waitForState(appElement, RunState.UNKNOWN, 3000); target.refresh(ui); waitForState(appElement, RunState.INACTIVE, 3000); } @Test public void simpleDeploy() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); IProject project = projects.createBootProject("to-deploy", withStarters("actuator", "web")); final String appName = appHarness.randomAppName(); harness.answerDeploymentPrompt(ui, appName, appName); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); waitForState(app, RunState.RUNNING, 10000); assertEquals((Integer)1, space.getPushCount(appName).getValue()); } @Test public void simpleDeployWithManifest() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); IProject project = projects.createBootProject("to-deploy", withStarters("actuator", "web")); final String appName = appHarness.randomAppName(); IFile manifestFile = createFile(project, "manifest.yml", "applications:\n" + "- name: "+appName+"\n" + " memory: 512M\n" ); harness.answerDeploymentPrompt(ui, (dialog) -> { dialog.okPressed(); }); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); waitForState(app, RunState.RUNNING, 10000); assertEquals((Integer)1, space.getPushCount(appName).getValue()); assertEquals(manifestFile, app.getDeploymentManifestFile()); assertEquals(512, (int) app.getMemory()); } @Test public void simpleDeployWithDefaultManualManifest() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); IProject project = projects.createBootProject("to-deploy", withStarters("actuator", "web")); final String appName = project.getName(); harness.answerDeploymentPrompt(ui, (dialog) -> { dialog.okPressed(); }); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); waitForState(app, RunState.RUNNING, 10000); assertEquals((Integer)1, space.getPushCount(appName).getValue()); assertNull(app.getDeploymentManifestFile()); assertEquals(1024, (int) app.getMemory()); assertEquals(appName, app.getName()); } @Test public void warDeploy() throws Exception { MavenSpringBootProject.DUMP_MAVEN_OUTPUT = true; try { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); IProject project = projects.createBootProject("to-deploy-war", withStarters("actuator", "web"), withPackaging("war") ); assertEquals("war", springBootCore.project(project).getPackaging()); String appName = project.getName(); harness.answerDeploymentPrompt(ui, (dialog) -> { dialog.okPressed(); }); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); waitForState(app, RunState.RUNNING, 10000); assertEquals((Integer)1, space.getPushCount(appName).getValue()); assertNull(app.getDeploymentManifestFile()); assertEquals(1024, (int) app.getMemory()); assertEquals(appName, app.getName()); File projectLocation = project.getLocation().toFile(); File warFile = new File(projectLocation, "target/"+project.getName()+"-0.0.1-SNAPSHOT.war"); assertTrue("war file not found: "+warFile, warFile.exists()); assertDeployedBytes(warFile, space.getApplication(appName)); } finally { MavenSpringBootProject.DUMP_MAVEN_OUTPUT = false; } } @Test public void stopCancelsDeploy() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); IProject project = projects.createBootProject("to-deploy", withStarters("actuator", "web")); final String appName = appHarness.randomAppName(); clientFactory.setAppStartDelay(TimeUnit.MINUTES, 2); harness.answerDeploymentPrompt(ui, appName, appName); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); waitForState(app, RunState.STARTING, 3000); ACondition.waitFor("stop hammering", 20000, () -> { app.stopAsync(ui); assertEquals(RunState.INACTIVE, app.getRunState()); }); //TODO: can we check that deployment related jobs are really canceled/finished somehow? // can we check that they didn't pop errors? } @Test public void stopCancelsStart() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); IProject project = projects.createBootProject("to-deploy", withStarters("web", "actuator")); final String appName = "foo"; space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); app.setProject(project); waitForApps(model, appName); clientFactory.setAppStartDelay(TimeUnit.MINUTES, 2); app.getBaseRunStateExp().addListener(new ValueListener<RunState>() { @Override public void gotValue(LiveExpression<RunState> exp, RunState value) { System.out.println("Runstate -> "+value); } }); System.out.println("Restaring app..."); app.restart(RunState.RUNNING, ui); waitForState(app, RunState.STARTING, 30000); System.out.println("Stopping app..."); app.stopAsync(ui); waitForState(app, RunState.INACTIVE, 20000); System.out.println("Stopped!"); } @Test public void stopCancelsRestartOnly() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); IProject project = projects.createProject("to-deploy"); final String appName = "foo"; space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); app.setProject(project); waitForApps(model, appName); clientFactory.setAppStartDelay(TimeUnit.MINUTES, 2); app.restartOnlyAsynch(ui, app.createCancelationToken()); waitForState(app, RunState.STARTING, 3000); app.stopAsync(ui); waitForState(app, RunState.INACTIVE, 20000); } @Test public void acceptDeployOfExistingApp() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); IProject project = projects.createBootProject("to-deploy", withStarters("actuator", "web")); final String appName = "foo"; MockCFApplication deployedApp = space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); app.setProject(null); assertNull(app.getProject()); waitForState(app, RunState.INACTIVE, 3000); harness.answerDeploymentPrompt(ui, appName, appName); Mockito.doReturn(true).when(ui).confirmApplicationReplacement(any(), any(), any()); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); System.out.println(app.getRunState()); waitForJobsToComplete(); System.out.println(app.getRunState()); assertEquals(project, app.getProject()); assertEquals(1, deployedApp.getPushCount()); verify(ui).confirmApplicationReplacement(any(), any(), any()); } @Test public void cancelDeployOfExistingApp() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); IProject project = projects.createBootProject("to-deploy", withStarters("web", "actuator")); final String appName = "foo"; MockCFApplication deployedApp = space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); app.setProject(null); assertNull(app.getProject()); harness.answerDeploymentPrompt(ui, appName, appName); doReturn(false).when(ui).confirmApplicationReplacement(any(), any(), any()); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForJobsToComplete(); assertNull(app.getProject()); // since op was canceled it should not have set the project on the app. assertEquals(0, deployedApp.getPushCount()); // since op was canceled it should not have deployed the app. verify(ui).confirmApplicationReplacement(any(), any(), any()); } @Test public void manifestDiffDialogNotShownWhenNothingChanged() throws Exception { final String appName = "foo"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); IProject project = projects.createBootProject("to-deploy", withStarters("web", "actuator")); createFile(project, "manifest.yml", "applications:\n" + "- name: "+appName+"\n" ); MockCFApplication deployedApp = space.defApp(appName); deployedApp.start(CancelationTokens.NULL); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); app.setDeploymentManifestFile(project.getFile("manifest.yml")); app.setProject(project); assertEquals(1, app.getActualInstances()); // deployedApp.scaleInstances(2); // change it 'externally' assertEquals(1, app.getActualInstances()); //The model doesn't know yet that it has changed! // harness.answerDeploymentPrompt(ui, appName, appName); app.restart(RunState.RUNNING, ui); waitForJobsToComplete(); //If no change was detected the manfiest compare dialog shouldn't have popped. verify(ui, never()).openManifestDiffDialog(any()); } @Test public void manifestDiffDialogShownWhenInstancesChangedExternally() throws Exception { final String appName = "foo"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); IProject project = projects.createBootProject("to-deploy", withStarters("web", "actuator")); createFile(project, "manifest.yml", "applications:\n" + "- name: "+appName+"\n" ); MockCFApplication deployedApp = space.defApp(appName); deployedApp.start(CancelationTokens.NULL); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName); waitForJobsToComplete(); CloudAppDashElement app = model.getApplication(appName); app.setDeploymentManifestFile(project.getFile("manifest.yml")); app.setProject(project); assertEquals(1, app.getActualInstances()); deployedApp.scaleInstances(2); // change it 'externally' assertEquals(1, app.getActualInstances()); //The model doesn't know yet that it has changed! app.restart(RunState.RUNNING, ui); waitForJobsToComplete(); //If the change was detected the deployment props dialog should have popped exactly once. verify(ui).openManifestDiffDialog(any()); } @Test public void manifestDiffDialogChooseUseManfifest() throws Exception { //Setup initial state for our test final String appName = "foo"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); IProject project = projects.createBootProject("to-deploy", withStarters("web", "actuator")); IFile manifest = createFile(project, "manifest.yml", "applications:\n" + "- name: "+appName+"\n" + " memory: 1111M\n" ); harness.answerDeploymentPrompt(ui, manifest); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); waitForState(app, RunState.RUNNING, APP_DEPLOY_TIMEOUT); { MockCFApplication appInCloud = space.getApplication(appName); assertEquals(1111, appInCloud.getMemory()); Mockito.reset(ui); //// real test begins here appInCloud.setMemory(2222); } harness.answerManifestDiffDialog(ui, (ManifestDiffDialogModel dialog) -> { //??? code to check what's in the dialog??? return ManifestDiffDialogModel.Result.USE_MANIFEST; }); app.restart(RunState.RUNNING, ui); waitForJobsToComplete(); { MockCFApplication appInCloud = space.getApplication(appName); assertEquals(2, appInCloud.getPushCount()); assertEquals(RunState.RUNNING, app.getRunState()); assertEquals(1111, appInCloud.getMemory()); assertEquals(1111, (int)app.getMemory()); } } @Test public void manifestDiffDialogChooseForgetManfifest() throws Exception { //Setup initial state for our test final String appName = "foo"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); IProject project = projects.createBootProject("to-deploy", withStarters("web", "actuator")); IFile manifest = createFile(project, "manifest.yml", "applications:\n" + "- name: "+appName+"\n" + " memory: 1111M\n" ); harness.answerDeploymentPrompt(ui, manifest); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); waitForState(app, RunState.RUNNING, APP_DEPLOY_TIMEOUT); MockCFApplication appInCloud = space.getApplication(appName); assertEquals(1111, appInCloud.getMemory()); Mockito.reset(ui); //// real test begins here appInCloud.setMemory(2222); harness.answerManifestDiffDialog(ui, (ManifestDiffDialogModel dialog) -> { //??? code to check what's in the dialog??? return ManifestDiffDialogModel.Result.FORGET_MANIFEST; }); app.restart(RunState.RUNNING, ui); waitForJobsToComplete(); assertEquals(2, appInCloud.getPushCount()); assertEquals(RunState.RUNNING, app.getRunState()); assertEquals(2222, appInCloud.getMemory()); assertEquals(2222, (int)app.getMemory()); } @Test public void testDeployManifestWithAbsolutePathAttribute() throws Exception { final String appName = "foo"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); IProject project = projects.createProject("to-deploy"); File zipFile = getTestZip("testapp"); IFile manifestFile = createFile(project, "manifest.yml", "applications:\n" + "- name: foo\n" + " path: "+zipFile.getAbsolutePath() + "\n" + " buildpack: staticfile_buildpack" ); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); harness.answerDeploymentPrompt(ui, manifestFile); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForApps(model, "foo"); CloudAppDashElement app = model.getApplication("foo"); waitForState(app, RunState.RUNNING, APP_DELETE_TIMEOUT); assertEquals(project, app.getProject()); assertEquals("some content here\n", space.getApplication(appName).getFileContents("test.txt")); verify(ui).promptApplicationDeploymentProperties(any()); verifyNoMoreInteractions(ui); } @Test public void testDeployManifestWithRelativePathAttribute() throws Exception { final String appName = "foo"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); IProject project = projects.createProject("to-deploy"); File zipFile = getTestZip("testapp"); project.getFolder("zips").create(true, true, new NullProgressMonitor()); project.getFolder("manifests").create(true, true, new NullProgressMonitor()); createFile(project, "zips/testapp.zip", zipFile); IFile manifestFile = createFile(project, "manifests/manifest.yml", "applications:\n" + "- name: foo\n" + " path: ../zips/testapp.zip\n" + " buildpack: staticfile_buildpack" ); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); harness.answerDeploymentPrompt(ui, manifestFile); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForApps(model, "foo"); CloudAppDashElement app = model.getApplication("foo"); waitForState(app, RunState.RUNNING, APP_DEPLOY_TIMEOUT); assertEquals(project, app.getProject()); assertEquals("some content here\n", space.getApplication(appName).getFileContents("test.txt")); verify(ui).promptApplicationDeploymentProperties(any()); verifyNoMoreInteractions(ui); } @Test public void testDeployManifestWithoutPathAttribute() throws Exception { String appName = "foo"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); IProject project = projects.createBootWebProject("empty-web-app"); IFile manifestFile = createFile(project, "manifest.yml", "applications:\n" + "- name: "+appName+"\n" ); File referenceJar = BootJarPackagingTest.packageAsJar(project, ui); harness.answerDeploymentPrompt(ui, manifestFile); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); waitForState(app, RunState.RUNNING, APP_DEPLOY_TIMEOUT); System.out.println("platform location = '"+Platform.getLocation()+"'"); assertDeployedBytes(referenceJar, space.getApplication(appName)); } @Test public void testSelectManifestActionEnablement() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); IProject project1 = projects.createProject("pr1"); IProject project2 = projects.createProject("pr2"); final String appName1 = "app1"; final String appName2 = "app2"; MockCFApplication cfApp1 = space.defApp(appName1); MockCFApplication cfApp2 = space.defApp(appName2); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName1, appName2); CloudAppDashElement app1 = model.getApplication(appName1); CloudAppDashElement app2 = model.getApplication(appName2); app1.setProject(project1); app2.setProject(project2); IAction action = actions.getSelectManifestAction(); assertTrue(harness.selection.getElements().isEmpty()); assertFalse(action.isEnabled()); harness.selection.setElements(ImmutableSet.of(app1)); assertNotNull(app1.getProject()); assertTrue(action.isEnabled()); harness.selection.setElements(ImmutableSet.of(app1, app2)); assertFalse(action.isEnabled()); app1.setProject(null); harness.selection.setElements(ImmutableSet.of(app1)); assertFalse(action.isEnabled()); harness.selection.setElements(ImmutableSet.of(app2)); assertTrue(action.isEnabled()); action.run(); } @Test public void testSelectManifestAction() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); IProject project = projects.createProject("pr"); final String appName = "app"; IFile manifestFile = createFile(project, "manifest.yml", "applications:\n" + "- name: "+appName+"\n" ); space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName); CloudAppDashElement app = model.getApplication(appName); app.setProject(project); harness.selection.setElements(ImmutableSet.of(app)); harness.answerDeploymentPrompt(ui, manifestFile); assertNull(app.getDeploymentManifestFile()); actions.getSelectManifestAction().run(); waitForJobsToComplete(); assertEquals(manifestFile, app.getDeploymentManifestFile()); verify(ui).promptApplicationDeploymentProperties(any()); verifyNoMoreInteractions(ui); } @Test public void disconnectTarget() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); String appName = "someApp"; space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName); harness.sectionSelection.setValue(model); IAction disconnectAction = actions.getToggleTargetConnectionAction(); assertTrue(disconnectAction.isEnabled()); disconnectAction.run(); waitForApps(model); assertFalse(model.isConnected()); assertEquals(RefreshState.READY, model.getRefreshState()); } @Test public void updateTargetPasswordInvalid() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); String appName = "someApp"; space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName); harness.sectionSelection.setValue(model); IAction updatePassword = actions.getUpdatePasswordAction(); assertTrue(updatePassword.isEnabled()); harness.answerPasswordPrompt(ui, (d) -> { d.getPasswordVar().setValue(targetParams.getCredentials().getSecret()); d.validateCredentials().block(); d.performOk(); }); updatePassword.run(); waitForJobsToComplete(); assertNotNull(model.getApplication(appName)); assertTrue(model.isConnected()); assertEquals(RefreshState.READY, model.getRefreshState()); // Clear out any mocks on the ui object set above reset(ui); CompletableFuture<ValidationResult> passwordValidation = new CompletableFuture<>(); harness.answerPasswordPrompt(ui, (d) -> { d.getPasswordVar().setValue("wrong password"); ReactorUtils.completeWith(passwordValidation, d.validateCredentials()); //d.performOk(); //shouldn't perform ok because we are expecting passwordValidation to fail }); updatePassword.run(); ValidationResult validationResult = passwordValidation.get(); assertEquals(IStatus.ERROR, validationResult.status); assertContains("Invalid credentials", validationResult.msg); } @Test public void pushWithHealthCheckNone() throws Exception { doPushWithHealthCheckType("none", "none"); } @Test public void pushWithHealthCheckDefault() throws Exception { doPushWithHealthCheckType(null, "port"); } @Test public void pushWithHealthCheckPort() throws Exception { doPushWithHealthCheckType("port", "port"); } private void doPushWithHealthCheckType(String specified, String expected) throws Exception { String appName = "someApp"; final IProject project = projects.createBootProject(appName, withStarters("actuator", "web")); CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); harness.answerDeploymentPrompt(ui, (dialog) -> { dialog.setManifestType(ManifestType.MANUAL); dialog.setManualManifest( "applications:\n" + "- name: "+appName+"\n" + (specified==null?"":" health-check-type: "+specified+"\n") ); dialog.okPressed(); }); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForApps(model, appName); waitForState(model.getApplication(appName), RunState.RUNNING, 4000); waitForJobsToComplete(); assertEquals(expected,space.getApplication(appName).getHealthCheckType()); ACondition.waitFor("hcType in model", 3000, () -> { assertEquals(expected, model.getApplication(appName).getHealthCheck()); }); } @Test public void updateTargetSsoAndStoreNothing() throws Exception { String appName = "someApp"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams, StoreCredentialsMode.STORE_TOKEN); waitForApps(model, appName); harness.sectionSelection.setValue(model); IAction updatePassword = actions.getUpdatePasswordAction(); assertTrue(updatePassword.isEnabled()); // Clear out any mocks on the ui object reset(ui); String newToken=clientFactory.getSsoToken(); harness.answerPasswordPrompt(ui, (d) -> { d.getMethodVar().setValue(LoginMethod.TEMPORARY_CODE); d.getPasswordVar().setValue(newToken); d.getStoreVar().setValue(StoreCredentialsMode.STORE_NOTHING); d.validateCredentials().block(); d.performOk(); }); updatePassword.run(); waitForJobsToComplete(); assertTrue(model.isConnected()); assertNotNull(model.getApplication(appName)); assertEquals(RefreshState.READY, model.getRefreshState()); { assertNull(harness.getCredentialsStore().getCredentials(harness.secureStoreKey(model))); assertNull(harness.getPrivateStore().get(harness.privateStoreKey(model))); } actions.getToggleTargetConnectionAction().run(); waitForJobsToComplete(); assertFalse(model.isConnected()); // Clear out any mocks on the ui object to get the right count below reset(ui); actions.getToggleTargetConnectionAction().run(); waitForJobsToComplete(); assertFalse(model.isConnected()); assertEquals(RefreshState.READY, model.getRefreshState()); assertNull(model.getApplication(appName)); verify(ui).openPasswordDialog(any()); verifyNoMoreInteractions(ui); } @Test public void updateTargetSsoAndStorePassword() throws Exception { String appName = "someApp"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams, StoreCredentialsMode.STORE_TOKEN); waitForApps(model, appName); harness.sectionSelection.setValue(model); IAction updatePassword = actions.getUpdatePasswordAction(); assertTrue(updatePassword.isEnabled()); // Clear out any mocks on the ui object reset(ui); LiveVariable<ValidationResult> capturedStoreValidator = new LiveVariable<>(null); String newToken=clientFactory.getSsoToken(); harness.answerPasswordPrompt(ui, (d) -> { d.getMethodVar().setValue(LoginMethod.TEMPORARY_CODE); d.getPasswordVar().setValue(newToken); d.getStoreVar().setValue(StoreCredentialsMode.STORE_PASSWORD); capturedStoreValidator.setValue(d.getStoreValidator().getValue()); d.validateCredentials().block(); d.performOk(); }); updatePassword.run(); waitForJobsToComplete(); assertContains("'Store Password' is useless for a 'Temporary Code'", capturedStoreValidator.getValue().msg); assertTrue(model.isConnected()); assertNotNull(model.getApplication(appName)); assertEquals(RefreshState.READY, model.getRefreshState()); //store password is ignored and treated as 'STORE_NOTHING' assertEquals(StoreCredentialsMode.STORE_NOTHING, model.getRunTarget().getTargetProperties().getStoreCredentials()); { assertNull(harness.getCredentialsStore().getCredentials(harness.secureStoreKey(model))); assertNull(harness.getPrivateStore().get(harness.privateStoreKey(model))); } actions.getToggleTargetConnectionAction().run(); waitForJobsToComplete(); assertFalse(model.isConnected()); // Clear out any mocks on the ui object to get the right count below reset(ui); actions.getToggleTargetConnectionAction().run(); waitForJobsToComplete(); assertFalse(model.isConnected()); assertEquals(RefreshState.READY, model.getRefreshState()); assertNull(model.getApplication(appName)); verify(ui).openPasswordDialog(any()); verifyNoMoreInteractions(ui); } @Test public void updateTargetSsoAndStoreToken() throws Exception { String appName = "someApp"; CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams, StoreCredentialsMode.STORE_PASSWORD); waitForApps(model, appName); harness.sectionSelection.setValue(model); IAction updatePassword = actions.getUpdatePasswordAction(); assertTrue(updatePassword.isEnabled()); // Clear out any mocks on the ui object reset(ui); String newToken=clientFactory.getSsoToken(); harness.answerPasswordPrompt(ui, (d) -> { d.getMethodVar().setValue(LoginMethod.TEMPORARY_CODE); d.getPasswordVar().setValue(newToken); d.getStoreVar().setValue(StoreCredentialsMode.STORE_TOKEN); d.validateCredentials().block(); d.performOk(); }); updatePassword.run(); waitForJobsToComplete(); assertTrue(model.isConnected()); assertNotNull(model.getApplication(appName)); assertEquals(RefreshState.READY, model.getRefreshState()); assertEquals(StoreCredentialsMode.STORE_TOKEN, model.getRunTarget().getTargetProperties().getStoreCredentials()); { assertNull(harness.getCredentialsStore().getCredentials(harness.secureStoreKey(model))); assertEquals(MockCloudFoundryClientFactory.FAKE_REFRESH_TOKEN, harness.getPrivateStore().get(harness.privateStoreKey(model))); } actions.getToggleTargetConnectionAction().run(); waitForJobsToComplete(); assertFalse(model.isConnected()); // Clear out any mocks on the ui object to get the right count below reset(ui); actions.getToggleTargetConnectionAction().run(); waitForJobsToComplete(); assertTrue(model.isConnected()); assertEquals(RefreshState.READY, model.getRefreshState()); assertNotNull(model.getApplication(appName)); verifyZeroInteractions(ui); //should have used stored token so no pw dialog! } @Test public void updateTargetPasswordAndStoreNothing() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); String appName = "someApp"; space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName); harness.sectionSelection.setValue(model); IAction updatePassword = actions.getUpdatePasswordAction(); assertTrue(updatePassword.isEnabled()); // Clear out any mocks on the ui object reset(ui); harness.answerPasswordPrompt(ui, (d) -> { d.getPasswordVar().setValue(targetParams.getCredentials().getSecret()); d.getStoreVar().setValue(StoreCredentialsMode.STORE_NOTHING); d.validateCredentials().block(); d.performOk(); }); updatePassword.run(); waitForJobsToComplete(); assertTrue(model.isConnected()); assertNotNull(model.getApplication(appName)); assertEquals(RefreshState.READY, model.getRefreshState()); { assertNull(harness.getCredentialsStore().getCredentials(harness.secureStoreKey(model))); assertNull(harness.getPrivateStore().get(harness.privateStoreKey(model))); } actions.getToggleTargetConnectionAction().run(); waitForJobsToComplete(); assertFalse(model.isConnected()); // Clear out any mocks on the ui object to get the right count below reset(ui); actions.getToggleTargetConnectionAction().run(); waitForJobsToComplete(); assertFalse(model.isConnected()); assertEquals(RefreshState.READY, model.getRefreshState()); assertNull(model.getApplication(appName)); verify(ui).openPasswordDialog(any()); verifyNoMoreInteractions(ui); } @Test public void updateTargetPasswordAndStorePassword() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); String appName = "someApp"; space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName); harness.sectionSelection.setValue(model); IAction updatePassword = actions.getUpdatePasswordAction(); assertTrue(updatePassword.isEnabled()); // Clear out any mocks on the ui object reset(ui); harness.answerPasswordPrompt(ui, (d) -> { d.getPasswordVar().setValue(targetParams.getCredentials().getSecret()); d.getStoreVar().setValue(StoreCredentialsMode.STORE_PASSWORD); d.validateCredentials().block(); d.performOk(); }); updatePassword.run(); waitForJobsToComplete(); actions.getToggleTargetConnectionAction().run(); waitForJobsToComplete(); assertFalse(model.isConnected()); // Clear out any mocks on the ui object to get the right count below reset(ui); actions.getToggleTargetConnectionAction().run(); waitForJobsToComplete(); assertTrue(model.isConnected()); assertEquals(RefreshState.READY, model.getRefreshState()); assertNotNull(model.getApplication(appName)); verifyNoMoreInteractions(ui); } @Test public void updateTargetPasswordAndStoreToken() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); MockCFSpace space = clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); String appName = "someApp"; space.defApp(appName); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); waitForApps(model, appName); harness.sectionSelection.setValue(model); IAction updatePassword = actions.getUpdatePasswordAction(); assertTrue(updatePassword.isEnabled()); // Clear out any mocks on the ui object reset(ui); harness.answerPasswordPrompt(ui, (d) -> { d.getPasswordVar().setValue(targetParams.getCredentials().getSecret()); d.getStoreVar().setValue(StoreCredentialsMode.STORE_TOKEN); d.validateCredentials().block(); d.performOk(); }); updatePassword.run(); waitForJobsToComplete(); actions.getToggleTargetConnectionAction().run(); waitForJobsToComplete(); assertFalse(model.isConnected()); // Clear out any mocks on the ui object to get the right count below reset(ui); actions.getToggleTargetConnectionAction().run(); waitForJobsToComplete(); assertTrue(model.isConnected()); CFCredentials creds = model.getRunTarget().getTargetProperties().getCredentials(); assertEquals(MockCloudFoundryClientFactory.FAKE_REFRESH_TOKEN, creds.getSecret()); assertEquals(CFCredentialType.REFRESH_TOKEN, creds.getType()); assertEquals(MockCloudFoundryClientFactory.FAKE_REFRESH_TOKEN, harness.getPrivateStore().get(harness.privateStoreKey(model))); assertNull(harness.getCredentialsStore().getCredentials(harness.secureStoreKey(model))); assertEquals(RefreshState.READY, model.getRefreshState()); assertNotNull(model.getApplication(appName)); verifyNoMoreInteractions(ui); } @Test public void apiVersionCheck() throws Exception { CFClientParams targetParams = CfTestTargetParams.fromEnv(); clientFactory.defSpace(targetParams.getOrgName(), targetParams.getSpaceName()); clientFactory.setApiVersion("1.1.0"); clientFactory.setSupportedApiVersion("1.1.1"); CloudFoundryBootDashModel model = harness.createCfTarget(targetParams); ACondition.waitFor("connected to target", 10_000, () -> model.isConnected()); waitForJobsToComplete(); assertTrue(model.getRefreshState().isWarning()); String msg = model.getRefreshState().getMessage(); assertContains("may not work as expected", msg); assertContains("1.1.1", msg); assertContains("1.1.0", msg); } /////////////////////////////////////////////////////////////////////////////////////////////// //Stuff below is 'cruft' intended to make the tests above more readable. Maybe this code could be // moved to some kind of 'harness' (if there is a case where it can be reused). private void assertDeployedBytes(File referenceJar, MockCFApplication app) throws IOException { try (InputStream actualBits = app.getBits()) { try (InputStream expectedBits = new BufferedInputStream(new FileInputStream(referenceJar))) { ZipDiff zipDiff = new ZipDiff(expectedBits); try { zipDiff.assertEqual(actualBits); } catch (Throwable e) { System.out.println("Failed: "+ExceptionUtil.getMessage(e)); saveArtefacts(referenceJar, app); throw e; } } } } private void saveArtefacts(File referenceJar, MockCFApplication app) throws IOException { System.out.println("Trying to save jars..."); File targetDir = getSaveDir(); System.out.println("targetDir = "+targetDir); if (targetDir!=null) { int id = uniqueId++; File referenceJarCopy = new File(targetDir, "deployed-reference-"+id+".jar"); File faultyJarCopy = new File(targetDir, "deployed-faulty-"+id+".jar"); FileUtils.copyFile(referenceJar, referenceJarCopy); System.out.println("Reference jar saved: "+referenceJarCopy); IOUtil.pipe(app.getBits(), faultyJarCopy); System.out.println("Faulty jar saved: "+faultyJarCopy); } } private static int uniqueId = 0; private File getSaveDir() { IPath targetDirPath = Platform.getLocation(); while (targetDirPath.segmentCount()>0 && !targetDirPath.lastSegment().equals("target")) { targetDirPath = targetDirPath.removeLastSegments(1); } if (targetDirPath.segmentCount()>0) { return targetDirPath.toFile(); } return new File(System.getProperty("user.home")); } private File getTestZip(String fileName) { File sourceWorkspace = new File( StsTestUtil.getSourceWorkspacePath("org.springframework.ide.eclipse.boot.dash.test")); File file = new File(sourceWorkspace, fileName + ".zip"); Assert.isTrue(file.exists(), ""+ file); return file; } private void assertAppToProjectBinding(CloudFoundryBootDashModel target, IProject project, String appName) throws Exception { CloudAppDashElement appByProject = getApplication(target, project); CloudAppDashElement appByName = target.getApplication(appName); assertNotNull(appByProject); assertEquals(appByProject, appByName); } private CloudAppDashElement getApplication(CloudFoundryBootDashModel model, IProject project) { for (CloudAppDashElement app : model.getApplicationValues()) { IProject p = app.getProject(); if (project.equals(p)) { return app; } } return null; } protected CloudAppDashElement deployApp(final CloudFoundryBootDashModel model, final String appName, IProject project) throws Exception { harness.answerDeploymentPrompt(ui, appName, appName); model.performDeployment(ImmutableSet.of(project), ui, RunState.RUNNING); waitForApps(model, appName); new ACondition("wait for app '"+ appName +"'to be RUNNING", 30000) { //why so long? JDT searching for main type. public boolean test() throws Exception { CloudAppDashElement element = model.getApplication(appName); assertEquals(RunState.RUNNING, element.getRunState()); return true; } }; return model.getApplication(appName); } protected void waitForApps(final CloudFoundryBootDashModel target, final String... names) throws Exception { new ACondition("wait for apps to appear", 120_000) { @Override public boolean test() throws Exception { ImmutableSet<String> appNames = getNames(target.getApplications().getValues()); assertEquals(ImmutableSet.copyOf(names), appNames); return true; } }; } protected void waitForServices(final CloudFoundryBootDashModel target, final String... names) throws Exception { new ACondition("wait for services to appear", 3000) { @Override public boolean test() throws Exception { ImmutableSet<String> serviceNames = getNames(target.getServices().getValues()); assertEquals(ImmutableSet.copyOf(names), serviceNames); return true; } }; } protected void waitForElements(final CloudFoundryBootDashModel target, final String... names) throws Exception { new ACondition("wait for elements to appear", 3000) { @Override public boolean test() throws Exception { ImmutableSet<String> elements = getNames(target.getElements().getValues()); assertEquals(ImmutableSet.copyOf(names), elements); return true; } }; } private Answer<Void> restoreDefaultTemplate() { return new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { EditTemplateDialogModel dialog = (EditTemplateDialogModel) invocation.getArguments()[0]; dialog.restoreDefaultsHandler.call(); dialog.performOk(); return null; } }; } /** * Create a mockito {@link Answer} that interacts with EditTemplateDialog by setting the template value and then * clicking the OK button. */ private Answer<Void> editSetTemplate(final String newText) { return new Answer<Void>() { @Override public Void answer(InvocationOnMock invocation) throws Throwable { EditTemplateDialogModel dialog = (EditTemplateDialogModel) invocation.getArguments()[0]; dialog.template.setValue(newText); dialog.performOk(); return null; } }; } private void assertSorted(ImmutableList<IAction> actions) { String[] actionNames = new String[actions.size()]; for (int i = 0; i < actionNames.length; i++) { actionNames[i] = actions.get(i).getText(); } String actual = StringUtils.arrayToDelimitedString(actionNames, "\n"); Arrays.sort(actionNames); String expected = StringUtils.arrayToDelimitedString(actionNames, "\n"); assertEquals(expected, actual); } private <T extends BootDashElement> void debugListener(final String name, ObservableSet<T> set) { set.addListener(new ValueListener<ImmutableSet<T>>() { @Override public void gotValue(LiveExpression<ImmutableSet<T>> exp, ImmutableSet<T> value) { StringBuilder elements = new StringBuilder(); for (BootDashElement e : exp.getValue()) { elements.append(e.getName()); elements.append(" "); } System.out.println(name+" -> "+elements); } }); } private void assertNames(ArrayList<BootDashElement> elements, String... expectNames) { String[] actualNames = new String[elements.size()]; for (int i = 0; i < actualNames.length; i++) { actualNames[i] = elements.get(i).getName(); } assertArrayEquals(expectNames, actualNames); } private ImmutableSet<String> getNames(ImmutableSet<? extends BootDashElement> values) { Builder<String> builder = ImmutableSet.builder(); for (BootDashElement e : values) { builder.add(e.getName()); } return builder.build(); } public static void waitForState(final BootDashElement element, final RunState state, long timeOut) throws Exception { new ACondition("Wait for state "+state, timeOut) { @Override public boolean test() throws Exception { assertEquals(state, element.getRunState()); return true; } }; } /////////////////////////////////////////////////////////////////////////////////// }