diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/MachineConfig.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/MachineConfig.java index 3acaaf29ba..5d35357603 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/MachineConfig.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/MachineConfig.java @@ -18,7 +18,6 @@ import java.util.Map; /** * @author gazarenkov */ -@Deprecated public interface MachineConfig { /** diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/MachineLimits.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/MachineLimits.java index b64af55228..886329bedb 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/MachineLimits.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/MachineLimits.java @@ -15,7 +15,6 @@ package org.eclipse.che.api.core.model.machine; * * @author Alexander Garagatyi */ -@Deprecated public interface MachineLimits { /** Get memory size (in megabytes) that is allocated for starting machine. */ int getRam(); diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/MachineSource.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/MachineSource.java index 037aadc3b4..8388bcc84f 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/MachineSource.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/MachineSource.java @@ -13,7 +13,6 @@ package org.eclipse.che.api.core.model.machine; /** * @author gazarenkov */ -@Deprecated public interface MachineSource { /** diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/ServerConf.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/ServerConf.java index c4e583c662..faf22b09c4 100644 --- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/ServerConf.java +++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/machine/ServerConf.java @@ -17,7 +17,6 @@ import org.eclipse.che.commons.annotation.Nullable; * * @author Alexander Garagatyi */ -@Deprecated public interface ServerConf { /** * Reference to this server. diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerMachineSource.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerMachineSource.java index 6109f88de9..b1c0804821 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerMachineSource.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/DockerMachineSource.java @@ -25,7 +25,6 @@ import static org.eclipse.che.plugin.docker.machine.DockerInstanceProvider.DOCKE * * @author Florent Benoit */ -@Deprecated public class DockerMachineSource extends MachineSourceImpl { /** diff --git a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/ext/provider/DockerExtConfBindingProvider.java b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/ext/provider/DockerExtConfBindingProvider.java index c3ac179428..6aa8ef24e2 100644 --- a/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/ext/provider/DockerExtConfBindingProvider.java +++ b/plugins/plugin-docker/che-plugin-docker-machine/src/main/java/org/eclipse/che/plugin/docker/machine/ext/provider/DockerExtConfBindingProvider.java @@ -48,8 +48,7 @@ public class DockerExtConfBindingProvider implements Provider { } File extConfDir = new File(localConfDir, PLUGIN_CONF); if (!extConfDir.isDirectory()) { - LOG.warn("DockerExtConfBindingProvider", - String.format("%s set to the %s but it must be directory not file", CheBootstrap.CHE_LOCAL_CONF_DIR, localConfDir)); + LOG.warn("{} set to the {} but it must be directory not file", CheBootstrap.CHE_LOCAL_CONF_DIR, localConfDir); return null; } diff --git a/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/MachineConfigDto.java b/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/MachineConfigDto.java index 12e81d492c..c009933df6 100644 --- a/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/MachineConfigDto.java +++ b/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/MachineConfigDto.java @@ -25,7 +25,6 @@ import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIO /** * @author Alexander Garagatyi */ -@Deprecated @DTO public interface MachineConfigDto extends MachineConfig, Hyperlinks { @Override diff --git a/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/MachineLimitsDto.java b/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/MachineLimitsDto.java index 74f06e8e32..5c47d80bd5 100644 --- a/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/MachineLimitsDto.java +++ b/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/MachineLimitsDto.java @@ -16,7 +16,6 @@ import org.eclipse.che.dto.shared.DTO; /** * @author Alexander Garagatyi */ -@Deprecated @DTO public interface MachineLimitsDto extends MachineLimits { MachineLimitsDto withRam(int memorySizeMB); diff --git a/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/MachineSourceDto.java b/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/MachineSourceDto.java index 72a30c46d9..02ca3d3c7a 100644 --- a/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/MachineSourceDto.java +++ b/wsmaster/che-core-api-machine-shared/src/main/java/org/eclipse/che/api/machine/shared/dto/MachineSourceDto.java @@ -20,7 +20,6 @@ import static org.eclipse.che.api.core.factory.FactoryParameter.Obligation.OPTIO /** * @author Alexander Garagatyi */ -@Deprecated @DTO public interface MachineSourceDto extends MachineSource { @Override diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineConfigImpl.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineConfigImpl.java index e1e26b2077..80ebcbc32e 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineConfigImpl.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineConfigImpl.java @@ -27,7 +27,6 @@ import java.util.stream.Collectors; * * @author Eugene Voevodin */ -@Deprecated public class MachineConfigImpl implements MachineConfig { public static MachineConfigImplBuilder builder() { diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineLimitsImpl.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineLimitsImpl.java index 238a5f2a21..f293fe8337 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineLimitsImpl.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineLimitsImpl.java @@ -15,7 +15,6 @@ import org.eclipse.che.api.core.model.machine.MachineLimits; /** * @author Alexander Garagatyi */ -@Deprecated public class MachineLimitsImpl implements MachineLimits { private final int memory; diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineSourceImpl.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineSourceImpl.java index d608e6c671..43e215b18d 100644 --- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineSourceImpl.java +++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/MachineSourceImpl.java @@ -23,7 +23,6 @@ import static java.util.Objects.hash; * * @author Eugene Voevodin */ -@Deprecated public class MachineSourceImpl implements MachineSource { private String type; diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentEngine.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentEngine.java index 36c26fc44d..721ec99d0f 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentEngine.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/environment/server/CheEnvironmentEngine.java @@ -469,17 +469,15 @@ public class CheEnvironmentEngine { * * @param snapshot * description of snapshot that should be removed + * @throws NotFoundException + * if snapshot is not found * @throws ServerException * if error occurs on snapshot removal */ - public void removeSnapshot(SnapshotImpl snapshot) throws ServerException { + public void removeSnapshot(SnapshotImpl snapshot) throws ServerException, NotFoundException { final String instanceType = snapshot.getType(); - try { - final InstanceProvider instanceProvider = machineInstanceProviders.getProvider(instanceType); - instanceProvider.removeInstanceSnapshot(snapshot.getMachineSource()); - } catch (NotFoundException e) { - throw new ServerException(e.getLocalizedMessage(), e); - } + final InstanceProvider instanceProvider = machineInstanceProviders.getProvider(instanceType); + instanceProvider.removeInstanceSnapshot(snapshot.getMachineSource()); } private void initializeEnvironment(String workspaceId, diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java index 7ae2e40801..b60705f93f 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java @@ -732,16 +732,9 @@ public class WorkspaceManager { .withWorkspaceId(workspaceId)); String devMachineSnapshotFailMessage = null; for (MachineImpl machine : runtime.getMachines()) { - try { - SnapshotImpl snapshot = runtimes.saveMachine(namespace, - workspaceId, - machine.getId()); - snapshotDao.saveSnapshot(snapshot); - } catch (ApiException apiEx) { - if (machine.getConfig().isDev()) { - devMachineSnapshotFailMessage = apiEx.getLocalizedMessage(); - } - LOG.error(apiEx.getLocalizedMessage(), apiEx); + String error = replaceSnapshot(machine, namespace); + if (error != null && machine.getConfig().isDev()) { + devMachineSnapshotFailMessage = error; } } if (devMachineSnapshotFailMessage != null) { @@ -757,6 +750,47 @@ public class WorkspaceManager { return devMachineSnapshotFailMessage == null; } + private String replaceSnapshot(MachineImpl machine, String namespace) { + try { + try { + SnapshotImpl oldSnapshot = snapshotDao.getSnapshot(machine.getWorkspaceId(), + machine.getEnvName(), + machine.getConfig().getName()); + snapshotDao.removeSnapshot(oldSnapshot.getId()); + + runtimes.removeSnapshot(oldSnapshot); + } catch (NotFoundException ignored) { + // Do nothing if no snapshot found + } + + SnapshotImpl snapshot = null; + try { + snapshot = runtimes.saveMachine(namespace, + machine.getWorkspaceId(), + machine.getId()); + + snapshotDao.saveSnapshot(snapshot); + } catch (ApiException e) { + if (snapshot != null) { + try { + runtimes.removeSnapshot(snapshot); + } catch (ApiException e1) { + LOG.error(format("Snapshot removal failed. Snapshot: %s. Error: %s", + snapshot, + e1.getLocalizedMessage()), + e1); + } + } + throw e; + } + + return null; + } catch (ApiException apiEx) { + LOG.error("Snapshot creation failed. Error: " + apiEx.getLocalizedMessage(), apiEx); + return apiEx.getLocalizedMessage(); + } + } + @VisibleForTesting void checkWorkspaceIsRunning(WorkspaceImpl workspace, String operation) throws ConflictException { if (workspace.getStatus() != RUNNING) { diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java index b1c36cf490..3f4be4dc25 100644 --- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java +++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java @@ -490,10 +490,12 @@ public class WorkspaceRuntimes { * * @param snapshot * description of snapshot that should be removed + * @throws NotFoundException + * if snapshot is not found * @throws ServerException * if error occurs */ - public void removeSnapshot(SnapshotImpl snapshot) throws ServerException { + public void removeSnapshot(SnapshotImpl snapshot) throws ServerException, NotFoundException { environmentEngine.removeSnapshot(snapshot); } diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java index 974b0d8647..3d7b5cc7d7 100644 --- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java +++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java @@ -12,6 +12,7 @@ package org.eclipse.che.api.workspace.server; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.NotFoundException; +import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.machine.MachineStatus; import org.eclipse.che.api.core.model.workspace.WorkspaceConfig; import org.eclipse.che.api.core.model.workspace.WorkspaceStatus; @@ -34,6 +35,7 @@ import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl; import org.eclipse.che.api.workspace.server.model.impl.WorkspaceRuntimeImpl; import org.eclipse.che.api.workspace.server.spi.WorkspaceDao; import org.eclipse.che.api.workspace.shared.Constants; +import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent; import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.subject.Subject; import org.eclipse.che.commons.subject.SubjectImpl; @@ -48,6 +50,7 @@ import org.testng.annotations.Test; import java.util.HashMap; import java.util.List; +import java.util.UUID; import static com.google.common.base.Strings.isNullOrEmpty; import static java.util.Arrays.asList; @@ -59,6 +62,10 @@ import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STOPPED; import static org.eclipse.che.api.workspace.server.WorkspaceManager.CREATED_ATTRIBUTE_NAME; import static org.eclipse.che.api.workspace.server.WorkspaceManager.UPDATED_ATTRIBUTE_NAME; import static org.eclipse.che.api.workspace.shared.Constants.AUTO_RESTORE_FROM_SNAPSHOT; +import static org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent.EventType.SNAPSHOT_CREATED; +import static org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent.EventType.SNAPSHOT_CREATING; +import static org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent.EventType.SNAPSHOT_CREATION_ERROR; +import static org.eclipse.che.dto.server.DtoFactory.newDto; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyObject; @@ -527,13 +534,16 @@ public class WorkspaceManagerTest { @Test public void shouldBeAbleToStopWorkspace() throws Exception { + // given final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); final RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); when(runtimes.get(any())).thenReturn(descriptor); when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + // when workspaceManager.stopWorkspace(workspace.getId()); + // then verify(runtimes, timeout(2000)).stop(workspace.getId()); assertNotNull(workspace.getAttributes().get(UPDATED_ATTRIBUTE_NAME)); } @@ -545,6 +555,11 @@ public class WorkspaceManagerTest { when(workspaceDao.get(workspace.getId())).thenReturn(workspace); final RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); workspaceManager.stopWorkspace(workspace.getId()); @@ -618,6 +633,7 @@ public class WorkspaceManagerTest { @Test public void shouldCreateWorkspaceSnapshotUsingDefaultValueForAutoRestore() throws Exception { + // given workspaceManager = spy(new WorkspaceManager(workspaceDao, runtimes, eventService, @@ -628,9 +644,16 @@ public class WorkspaceManagerTest { when(workspaceDao.get(workspace.getId())).thenReturn(workspace); final RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); + // then workspaceManager.stopWorkspace(workspace.getId()); + // then verify(workspaceManager, timeout(2000)).createSnapshotSync(workspace.getRuntime(), workspace.getNamespace(), workspace.getId()); verify(runtimes, timeout(2000)).stop(any()); } @@ -750,7 +773,7 @@ public class WorkspaceManagerTest { when(workspaceMock.getStatus()).thenReturn(RUNNING); when(workspaceMock.getRuntime()).thenReturn(wsRuntimeMock); when(wsRuntimeMock.getActiveEnv()).thenReturn(testActiveEnv); - MachineConfigImpl machineConfig = createMachine().getConfig(); + MachineConfigImpl machineConfig = createMachine(testWsId, testActiveEnv, false).getConfig(); // when workspaceManager.startMachine(machineConfig, testWsId); @@ -766,7 +789,7 @@ public class WorkspaceManagerTest { WorkspaceImpl workspaceMock = mock(WorkspaceImpl.class); doReturn(workspaceMock).when(workspaceManager).getWorkspace(testWsId); when(workspaceMock.getStatus()).thenReturn(STARTING); - MachineConfigImpl machineConfig = createMachine().getConfig(); + MachineConfigImpl machineConfig = createMachine(testWsId, "env1", false).getConfig(); // when workspaceManager.startMachine(machineConfig, testWsId); @@ -774,11 +797,16 @@ public class WorkspaceManagerTest { @Test public void shouldBeAbleToCreateSnapshot() throws Exception { - // then + // given final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); when(workspaceDao.get(workspace.getId())).thenReturn(workspace); RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); // when workspaceManager.createSnapshot(workspace.getId()); @@ -792,7 +820,7 @@ public class WorkspaceManagerTest { @Test(expectedExceptions = ConflictException.class, expectedExceptionsMessageRegExp = "Could not .* the workspace '.*' because its status is '.*'.") public void shouldNotCreateSnapshotIfWorkspaceIsNotRunning() throws Exception { - // then + // given final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); when(workspaceDao.get(workspace.getId())).thenReturn(workspace); RuntimeDescriptor descriptor = createDescriptor(workspace, STARTING); @@ -802,6 +830,295 @@ public class WorkspaceManagerTest { workspaceManager.createSnapshot(workspace.getId()); } + @Test + public void shouldSnapshotAllMachinesInWs() throws Exception { + // given + final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); + when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); + when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); + + // when + workspaceManager.createSnapshot(workspace.getId()); + + // then + verify(runtimes, timeout(1_000).times(2)).saveMachine(eq(workspace.getNamespace()), + eq(workspace.getId()), + anyString()); + verify(snapshotDao, timeout(1_000).times(2)).saveSnapshot(any(SnapshotImpl.class)); + } + + @Test + public void shouldSendEventOnStartSnapshotSaving() throws Exception { + // given + final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); + when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); + when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); + + // when + workspaceManager.createSnapshot(workspace.getId()); + + // then + verify(eventService, timeout(1_000)).publish(eq(newDto(WorkspaceStatusEvent.class) + .withEventType(SNAPSHOT_CREATING) + .withWorkspaceId(workspace.getId()))); + } + + @Test + public void shouldSendEventOnSuccessfulSnapshotSaving() throws Exception { + // given + final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); + when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); + when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); + + // when + workspaceManager.createSnapshot(workspace.getId()); + + // then + verify(eventService, timeout(1_000)).publish(eq(newDto(WorkspaceStatusEvent.class) + .withEventType(SNAPSHOT_CREATED) + .withWorkspaceId(workspace.getId()))); + } + + @Test + public void shouldSendSnapshotSavingFailedEventIfDevMachineSnapshotSavingFailed() throws Exception { + // given + final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); + when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); + when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); + for (MachineImpl machine : descriptor.getRuntime().getMachines()) { + if (machine.getConfig().isDev()) { + when(runtimes.saveMachine(workspace.getNamespace(), workspace.getId(), machine.getId())) + .thenThrow(new ServerException("test error")); + } + } + + // when + workspaceManager.createSnapshot(workspace.getId()); + + // then + verify(eventService, timeout(1_000)).publish(eq(newDto(WorkspaceStatusEvent.class) + .withEventType(SNAPSHOT_CREATION_ERROR) + .withWorkspaceId(workspace.getId()) + .withError("test error"))); + } + + @Test + public void shouldNotSendSnapshotSavingFailedEventIfNonDevMachineSnapshotSavingFailed() throws Exception { + // given + final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); + when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); + when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); + for (MachineImpl machine : descriptor.getRuntime().getMachines()) { + if (!machine.getConfig().isDev()) { + when(runtimes.saveMachine(workspace.getNamespace(), workspace.getId(), machine.getId())) + .thenThrow(new ServerException("test error")); + } + } + + // when + workspaceManager.createSnapshot(workspace.getId()); + + // then + verify(eventService, timeout(1_000)).publish(eq(newDto(WorkspaceStatusEvent.class) + .withEventType(SNAPSHOT_CREATED) + .withWorkspaceId(workspace.getId()))); + } + + @Test + public void shouldReturnFalseOnFailureSnapshotSavingIfDevMachineSavingFailed() throws Exception { + // given + final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); + when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); + when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); + for (MachineImpl machine : descriptor.getRuntime().getMachines()) { + if (machine.getConfig().isDev()) { + when(runtimes.saveMachine(workspace.getNamespace(), workspace.getId(), machine.getId())) + .thenThrow(new ServerException("test error")); + } + } + + // when + boolean snapshotSavingStatus = workspaceManager.createSnapshotSync( + new WorkspaceRuntimeImpl(descriptor.getRuntime()), workspace.getNamespace(), workspace.getId()); + + // then + assertFalse(snapshotSavingStatus); + } + + @Test + public void shouldReturnTrueOnSuccessfulSavingSnapshotsForSeveralMachines() throws Exception { + // given + final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); + when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); + when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); + + // when + boolean snapshotSavingStatus = workspaceManager.createSnapshotSync( + new WorkspaceRuntimeImpl(descriptor.getRuntime()), workspace.getNamespace(), workspace.getId()); + + // then + assertTrue(snapshotSavingStatus); + // ensure that multiple machines were saved + verify(snapshotDao, timeout(1_000).atLeast(2)).saveSnapshot(any(SnapshotImpl.class)); + } + + @Test + public void shouldReturnTrueOnSavingSnapshotsForSeveralMachinesWhenNonDevMachineSavingFailed() throws Exception { + // given + final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); + when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); + when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); + for (MachineImpl machine : descriptor.getRuntime().getMachines()) { + if (!machine.getConfig().isDev()) { + when(runtimes.saveMachine(workspace.getNamespace(), workspace.getId(), machine.getId())) + .thenThrow(new ServerException("test error")); + } + } + + // when + boolean snapshotSavingStatus = workspaceManager.createSnapshotSync( + new WorkspaceRuntimeImpl(descriptor.getRuntime()), workspace.getNamespace(), workspace.getId()); + + // then + assertTrue(snapshotSavingStatus); + } + + @Test + public void shouldRemoveRuntimeSnapshotIfSavingSnapshotInDaoFails() throws Exception { + // given + final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); + when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); + when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); + doThrow(new SnapshotException("test error")).when(snapshotDao).saveSnapshot(any(SnapshotImpl.class)); + + // when + workspaceManager.createSnapshot(workspace.getId()); + + // then + verify(runtimes, timeout(1_000).times(2)).removeSnapshot(any(SnapshotImpl.class)); + } + + @Test + public void shouldIgnoreNotFoundExceptionOnOldSnapshotRemoval1() throws Exception { + // given + final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); + when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); + when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); + doThrow(new NotFoundException("test error")).when(snapshotDao).removeSnapshot(anyString()); + + // when + workspaceManager.createSnapshot(workspace.getId()); + + // then + verify(workspaceManager, timeout(1_000)).createSnapshotSync(any(WorkspaceRuntimeImpl.class), + eq(workspace.getNamespace()), + eq(workspace.getId())); + } + + @Test + public void shouldIgnoreNotFoundExceptionOnOldSnapshotRemoval2() throws Exception { + // given + final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); + when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); + when(runtimes.get(any())).thenReturn(descriptor); + SnapshotImpl oldSnapshot = mock(SnapshotImpl.class); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenReturn(oldSnapshot); + doThrow(new NotFoundException("test error")).when(runtimes).removeSnapshot(any(SnapshotImpl.class)); + + // when + workspaceManager.createSnapshot(workspace.getId()); + + // then + verify(workspaceManager, timeout(1_000)).createSnapshotSync(any(WorkspaceRuntimeImpl.class), + eq(workspace.getNamespace()), + eq(workspace.getId())); + } + + @Test + public void shouldIgnoreNotFoundExceptionOnOldSnapshotRemoval3() throws Exception { + // given + final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), "user123", "account"); + when(workspaceDao.get(workspace.getId())).thenReturn(workspace); + RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING); + when(runtimes.get(any())).thenReturn(descriptor); + when(snapshotDao.getSnapshot(eq(workspace.getId()), + eq(workspace.getConfig().getDefaultEnv()), + anyString())) + .thenThrow(new NotFoundException("test error")); + + // when + workspaceManager.createSnapshot(workspace.getId()); + + // then + verify(workspaceManager, timeout(1_000)).createSnapshotSync(any(WorkspaceRuntimeImpl.class), + eq(workspace.getNamespace()), + eq(workspace.getId())); + } + @Test public void shouldBeAbleToStopMachine() throws Exception { // given @@ -868,9 +1185,9 @@ public class WorkspaceManagerTest { assertNotNull(environment); final WorkspaceRuntimeImpl runtime = new WorkspaceRuntimeImpl(workspace.getConfig().getDefaultEnv()); - MachineImpl machine = spy(createMachine()); + MachineImpl machine = spy(createMachine(workspace.getId(), workspace.getConfig().getDefaultEnv(), true)); runtime.getMachines().add(machine); - MachineImpl machine2 = spy(createMachine()); + MachineImpl machine2 = spy(createMachine(workspace.getId(), workspace.getConfig().getDefaultEnv(), false)); runtime.getMachines().add(machine2); final RuntimeDescriptor descriptor = mock(RuntimeDescriptor.class); @@ -895,20 +1212,20 @@ public class WorkspaceManagerTest { .build(); } - private MachineImpl createMachine() { + private MachineImpl createMachine(String workspaceId, String envName, boolean isDev) { return MachineImpl.builder() .setConfig(MachineConfigImpl.builder() - .setDev(false) - .setName("machineName") + .setDev(isDev) + .setName("machineName" + UUID.randomUUID()) .setSource(new MachineSourceImpl("type").setContent("content")) .setLimits(new MachineLimitsImpl(1024)) .setType("docker") .build()) - .setId("id") + .setId("id" + UUID.randomUUID()) .setOwner("userName") .setStatus(MachineStatus.RUNNING) - .setWorkspaceId("wsId") - .setEnvName("envName") + .setWorkspaceId(workspaceId) + .setEnvName(envName) .setRuntime(new MachineRuntimeInfoImpl(new HashMap<>(), new HashMap<>(), new HashMap<>()))