/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * 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: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.api.environment.server; import org.eclipse.che.api.agent.server.AgentRegistry; import org.eclipse.che.api.agent.server.exception.AgentException; import org.eclipse.che.api.agent.shared.model.Agent; import org.eclipse.che.api.agent.shared.model.AgentKey; 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.Machine; import org.eclipse.che.api.core.model.machine.MachineLogMessage; import org.eclipse.che.api.core.model.machine.MachineStatus; import org.eclipse.che.api.core.model.workspace.ExtendedMachine; import org.eclipse.che.api.core.model.workspace.ServerConf2; import org.eclipse.che.api.core.notification.EventService; import org.eclipse.che.api.core.notification.EventSubscriber; import org.eclipse.che.api.core.util.LineConsumer; import org.eclipse.che.api.core.util.MessageConsumer; import org.eclipse.che.api.environment.server.exception.EnvironmentNotRunningException; import org.eclipse.che.api.environment.server.exception.EnvironmentStartInterruptedException; import org.eclipse.che.api.environment.server.model.CheServiceBuildContextImpl; import org.eclipse.che.api.environment.server.model.CheServiceImpl; import org.eclipse.che.api.environment.server.model.CheServicesEnvironmentImpl; import org.eclipse.che.api.machine.server.MachineInstanceProviders; import org.eclipse.che.api.machine.server.event.InstanceStateEvent; import org.eclipse.che.api.machine.server.exception.MachineException; import org.eclipse.che.api.machine.server.model.impl.MachineConfigImpl; import org.eclipse.che.api.machine.server.model.impl.MachineImpl; import org.eclipse.che.api.machine.server.model.impl.MachineLimitsImpl; import org.eclipse.che.api.machine.server.model.impl.MachineRuntimeInfoImpl; import org.eclipse.che.api.machine.server.model.impl.MachineSourceImpl; import org.eclipse.che.api.machine.server.model.impl.ServerConfImpl; import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl; import org.eclipse.che.api.machine.server.spi.Instance; import org.eclipse.che.api.machine.server.spi.InstanceProvider; import org.eclipse.che.api.machine.server.spi.SnapshotDao; import org.eclipse.che.api.machine.server.util.RecipeDownloader; import org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent; import org.eclipse.che.api.workspace.server.WorkspaceSharedPool; import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl; import org.eclipse.che.api.workspace.server.model.impl.EnvironmentRecipeImpl; import org.eclipse.che.api.workspace.server.model.impl.ExtendedMachineImpl; import org.eclipse.che.api.workspace.server.model.impl.ServerConf2Impl; import org.eclipse.che.commons.env.EnvironmentContext; import org.eclipse.che.commons.lang.Size; import org.eclipse.che.commons.subject.SubjectImpl; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; import static java.lang.String.format; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; 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.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotEquals; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; /** * @author Alexander Garagatyi * @author Alexander Andrienko */ @Listeners(MockitoTestNGListener.class) public class CheEnvironmentEngineTest { private static final int DEFAULT_MACHINE_MEM_LIMIT_MB = 256; private static final String API_ENDPOINT = "http://eclipse.che:8080/api"; @Mock private MessageConsumer<MachineLogMessage> messageConsumer; @Mock private InstanceProvider instanceProvider; @Mock private MachineInstanceProvider machineProvider; @Mock private MachineInstanceProviders machineInstanceProviders; @Mock private EventService eventService; @Mock private SnapshotDao snapshotDao; @Mock private RecipeDownloader recipeDownloader; @Mock private InfrastructureProvisioner infrastructureProvisioner; @Mock private ContainerNameGenerator containerNameGenerator; @Mock private AgentRegistry agentRegistry; @Mock private Agent agent; @Mock private EnvironmentParser environmentParser; @Mock private MachineStartedHandler startedHandler; @Mock private WorkspaceSharedPool sharedPool; @Captor ArgumentCaptor<EventSubscriber<InstanceStateEvent>> eventServiceSubscriberCaptor; private CheEnvironmentEngine engine; @BeforeMethod public void setUp() throws Exception { engine = spy(new CheEnvironmentEngine(snapshotDao, machineInstanceProviders, System.getProperty("java.io.tmpdir"), DEFAULT_MACHINE_MEM_LIMIT_MB, eventService, environmentParser, new DefaultServicesStartStrategy(), machineProvider, infrastructureProvisioner, API_ENDPOINT, recipeDownloader, containerNameGenerator, agentRegistry, sharedPool)); when(machineInstanceProviders.getProvider("docker")).thenReturn(instanceProvider); when(instanceProvider.getRecipeTypes()).thenReturn(Collections.singleton("dockerfile")); when(agentRegistry.getAgent(any(AgentKey.class))).thenReturn(agent); EnvironmentContext.getCurrent().setSubject(new SubjectImpl("name", "id", "token", false)); } @AfterMethod public void tearDown() throws Exception { EnvironmentContext.reset(); } @Test public void shouldBeAbleToGetMachinesOfEnv() throws Exception { // given List<Instance> instances = startEnv(); String workspaceId = instances.get(0).getWorkspaceId(); // when List<Instance> actualMachines = engine.getMachines(workspaceId); // then assertEquals(actualMachines, instances); } @Test(expectedExceptions = EnvironmentNotRunningException.class, expectedExceptionsMessageRegExp = "Environment with ID '.*' is not found") public void shouldThrowExceptionOnGetMachinesIfEnvironmentIsNotFound() throws Exception { engine.getMachines("wsIdOfNotRunningEnv"); } @Test public void shouldBeAbleToGetMachineOfEnv() throws Exception { // given List<Instance> instances = startEnv(); Instance instance = instances.get(0); String workspaceId = instance.getWorkspaceId(); // when Instance actualInstance = engine.getMachine(workspaceId, instance.getId()); // then assertEquals(actualInstance, instance); } @Test(expectedExceptions = EnvironmentNotRunningException.class, expectedExceptionsMessageRegExp = "Environment with ID '.*' is not found") public void shouldThrowExceptionOnGetMachineIfEnvironmentIsNotFound() throws Exception { // when engine.getMachine("wsIdOfNotRunningEnv", "nonExistingInstanceId"); } @Test(expectedExceptions = NotFoundException.class, expectedExceptionsMessageRegExp = "Machine with ID .* is not found in the environment of workspace .*") public void shouldThrowExceptionOnGetMachineIfMachineIsNotFound() throws Exception { // given List<Instance> instances = startEnv(); Instance instance = instances.get(0); String workspaceId = instance.getWorkspaceId(); // when engine.getMachine(workspaceId, "nonExistingInstanceId"); } @Test public void shouldBeAbleToStartEnvironment() throws Exception { // given EnvironmentImpl env = createEnv(); String envName = "env-1"; String workspaceId = "wsId"; List<Instance> expectedMachines = new ArrayList<>(); when(machineProvider.startService(anyString(), eq(workspaceId), eq(envName), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenAnswer(invocationOnMock -> { Object[] arguments = invocationOnMock.getArguments(); String machineName = (String)arguments[3]; boolean isDev = (boolean)arguments[4]; CheServiceImpl service = (CheServiceImpl)arguments[6]; Machine machine = createMachine(workspaceId, envName, service, machineName, isDev); NoOpMachineInstance instance = spy(new NoOpMachineInstance(machine)); expectedMachines.add(instance); return instance; }); when(environmentParser.parse(env)).thenReturn(createCheServicesEnv()); // when List<Instance> machines = engine.start(workspaceId, envName, env, false, messageConsumer, startedHandler); // then assertEquals(machines, expectedMachines); for (Instance expectedMachine : expectedMachines) { verify(startedHandler).started(eq(expectedMachine), any(ExtendedMachine.class)); } } @Test public void stopsTheEnvironmentWhileStartOfMachineIsInterrupted() throws Exception { // given EnvironmentImpl env = createEnv(); String envName = "env-1"; String workspaceId = "wsId"; int[] counter = new int[] {env.getMachines().size()}; ArrayList<Instance> created = new ArrayList<>(); when(machineProvider.startService(anyString(), eq(workspaceId), eq(envName), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenAnswer(invocationOnMock -> { // interrupt when the last machine from environment is started if (--counter[0] == 0) { Thread.currentThread().interrupt(); throw new ServerException("interrupted!"); } Object[] arguments = invocationOnMock.getArguments(); NoOpMachineInstance instance = spy(new NoOpMachineInstance(createMachine(workspaceId, envName, (CheServiceImpl)arguments[6], (String)arguments[3], (boolean)arguments[4]))); created.add(instance); return instance; }); when(environmentParser.parse(env)).thenReturn(createCheServicesEnv()); // when, then try { engine.start(workspaceId, envName, env, false, messageConsumer, startedHandler); fail("environment must not be running"); } catch (EnvironmentStartInterruptedException x) { assertEquals(x.getMessage(), format("Start of environment '%s' in workspace '%s' is interrupted", envName, workspaceId)); } // environment must not be running try { engine.getMachines(workspaceId); fail("environment must not be running"); } catch (EnvironmentNotRunningException x) { assertEquals(x.getMessage(), format("Environment with ID '%s' is not found", workspaceId)); } // all the machines expect of the last one must be destroyed for (Instance instance : created) { verify(instance).destroy(); } } @Test public void shouldSetDefaultRamToMachinesWithoutRamOnEnvironmentStart() throws Exception { // given EnvironmentImpl env = createEnv(); String machineName = "machineWithoutRam"; //prepare CheServicesEnvironmentImpl which should return compose parser CheServicesEnvironmentImpl cheServicesEnvironment = createCheServicesEnvByName(machineName); // when startEnv(env, cheServicesEnvironment); // then ArgumentCaptor<CheServiceImpl> captor = ArgumentCaptor.forClass(CheServiceImpl.class); verify(machineProvider).startService(anyString(), anyString(), anyString(), eq(machineName), eq(false), anyString(), captor.capture(), any(LineConsumer.class)); CheServiceImpl actualService = captor.getValue(); assertEquals((long)actualService.getMemLimit(), DEFAULT_MACHINE_MEM_LIMIT_MB * 1024L * 1024L); } @Test public void shouldUseConfiguredInServiceRamInsteadOfSetDefaultOnEnvironmentStart() throws Exception { // given EnvironmentImpl env = createEnv(); String machineName = "machineWithoutRam"; //prepare CheServicesEnvironmentImpl which should return compose parser CheServicesEnvironmentImpl cheServicesEnvironment = createCheServicesEnvByName(machineName); cheServicesEnvironment.getServices().get(machineName).withMemLimit(42943433L); // when startEnv(env, cheServicesEnvironment); // then ArgumentCaptor<CheServiceImpl> captor = ArgumentCaptor.forClass(CheServiceImpl.class); verify(machineProvider).startService(anyString(), anyString(), anyString(), eq(machineName), eq(false), anyString(), captor.capture(), any(LineConsumer.class)); CheServiceImpl actualService = captor.getValue(); assertEquals((long)actualService.getMemLimit(), 42943433L); } @Test public void shouldSetDockerfileContentInsteadOfUrlIfUrlPointsToCheApiOnEnvironmentStart() throws Exception { // given EnvironmentImpl env = createEnv(); String machineName = "machineWithDockerfileFromApi"; String dockerfileContent = "this is dockerfile content"; when(recipeDownloader.getRecipe(anyString())).thenReturn(dockerfileContent); //prepare CheServicesEnvironmentImpl which should return compose parser CheServicesEnvironmentImpl cheServicesEnvironment = createCheServicesEnvByName(machineName); cheServicesEnvironment.getServices() .get(machineName) .withBuild(new CheServiceBuildContextImpl().withContext(API_ENDPOINT + "/recipe/12345")); // when startEnv(env, cheServicesEnvironment); // then ArgumentCaptor<CheServiceImpl> captor = ArgumentCaptor.forClass(CheServiceImpl.class); verify(machineProvider).startService(anyString(), anyString(), anyString(), eq(machineName), eq(false), anyString(), captor.capture(), any(LineConsumer.class)); CheServiceImpl actualService = captor.getValue(); assertNull(actualService.getBuild().getContext()); assertNull(actualService.getBuild().getDockerfilePath()); assertEquals(actualService.getBuild().getDockerfileContent(), dockerfileContent); } @Test public void shouldNotSetDockerfileContentInsteadOfUrlIfUrlDoesNotPointToCheApiOnEnvironmentStart() throws Exception { // given EnvironmentImpl env = createEnv(); String machineName = "machineWithDockerfileNotFromApi"; String contextUrl = "http://another-server.com/recipe/12345"; //prepare CheServicesEnvironmentImpl which should return compose parser CheServicesEnvironmentImpl cheServicesEnvironment = createCheServicesEnvByName(machineName); cheServicesEnvironment.getServices() .get(machineName) .withBuild(new CheServiceBuildContextImpl().withContext(contextUrl)); // when startEnv(env, cheServicesEnvironment); // then ArgumentCaptor<CheServiceImpl> captor = ArgumentCaptor.forClass(CheServiceImpl.class); verify(machineProvider).startService(anyString(), anyString(), anyString(), eq(machineName), eq(false), anyString(), captor.capture(), any(LineConsumer.class)); CheServiceImpl actualService = captor.getValue(); assertNull(actualService.getBuild().getDockerfilePath()); assertNull(actualService.getBuild().getDockerfileContent()); assertEquals(actualService.getBuild().getContext(), contextUrl); } @Test public void shouldApplyAgentsOnEnvironmentStart() throws Exception { EnvironmentImpl env = createEnv(); String machineName = "extraMachine"; //prepare CheServicesEnvironmentImpl which should return compose parser CheServicesEnvironmentImpl cheServicesEnvironment = createCheServicesEnvByName(machineName); cheServicesEnvironment.getServices() .get(machineName) .withImage("codenvy/ubuntu_jdk8"); // when startEnv(env, cheServicesEnvironment); // then verify(machineProvider).startService(anyString(), anyString(), anyString(), eq(machineName), eq(false), anyString(), any(CheServiceImpl.class), any(LineConsumer.class)); verify(infrastructureProvisioner).provision(eq(env), any(CheServicesEnvironmentImpl.class)); verifyNoMoreInteractions(infrastructureProvisioner); } @Test public void shouldSetDefaultRamToMachineWithoutRamOnMachineStart() throws Exception { // given List<Instance> instances = startEnv(); String workspaceId = instances.get(0).getWorkspaceId(); when(engine.generateMachineId()).thenReturn("newMachineId"); Instance newMachine = mock(Instance.class); when(newMachine.getId()).thenReturn("newMachineId"); when(newMachine.getWorkspaceId()).thenReturn(workspaceId); when(machineProvider.startService(anyString(), anyString(), anyString(), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenReturn(newMachine); MachineConfigImpl config = createConfig(false); String machineName = "extraMachine"; config.setName(machineName); config.setLimits(null); // when engine.startMachine(workspaceId, config, emptyList()); // then ArgumentCaptor<CheServiceImpl> captor = ArgumentCaptor.forClass(CheServiceImpl.class); verify(machineProvider).startService(anyString(), anyString(), anyString(), eq(machineName), eq(false), anyString(), captor.capture(), any(LineConsumer.class)); CheServiceImpl actualService = captor.getValue(); assertEquals((long)actualService.getMemLimit(), DEFAULT_MACHINE_MEM_LIMIT_MB * 1024L * 1024L); } @Test public void shouldBeAbleToStartEnvironmentWithRecover() throws Exception { // given SnapshotImpl snapshot = mock(SnapshotImpl.class); MachineSourceImpl machineSource = new MachineSourceImpl("image", "registry.com/snapshot123:latest@sha256:abc1234567890", null); when(snapshotDao.getSnapshot(anyString(), anyString(), anyString())).thenReturn(snapshot); when(snapshot.getMachineSource()).thenReturn(machineSource); // given EnvironmentImpl env = createEnv(); String envName = "env-1"; String workspaceId = "wsId"; List<Instance> expectedMachines = new ArrayList<>(); when(machineProvider.startService(anyString(), eq(workspaceId), eq(envName), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenAnswer(invocationOnMock -> { Object[] arguments = invocationOnMock.getArguments(); String machineName = (String)arguments[3]; boolean isDev = (boolean)arguments[4]; CheServiceImpl service = (CheServiceImpl)arguments[6]; Machine machine = createMachine(workspaceId, envName, service, machineName, isDev); NoOpMachineInstance instance = spy(new NoOpMachineInstance(machine)); expectedMachines.add(instance); return instance; }); when(environmentParser.parse(env)).thenReturn(createCheServicesEnv()); // when List<Instance> machines = engine.start(workspaceId, envName, env, true, messageConsumer); // then assertEquals(machines, expectedMachines); ArgumentCaptor<CheServiceImpl> captor = ArgumentCaptor.forClass(CheServiceImpl.class); verify(machineProvider).startService(anyString(), anyString(), anyString(), anyString(), eq(false), anyString(), captor.capture(), any(LineConsumer.class)); CheServiceImpl actualService = captor.getValue(); assertEquals(actualService.getImage(), "registry.com/snapshot123:latest"); } @Test public void shouldBeAbleToStartEnvironmentWhenRecoverFailed() throws Exception { // given String machineImage = "che/ubuntu_jdk"; when(snapshotDao.getSnapshot(anyString(), anyString(), anyString())).thenThrow(new NotFoundException("Snapshot not found")); EnvironmentImpl env = createEnv(); String envName = "env-1"; String workspaceId = "wsId"; List<Instance> expectedMachines = new ArrayList<>(); when(machineProvider.startService(anyString(), eq(workspaceId), eq(envName), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenAnswer(invocationOnMock -> { Object[] arguments = invocationOnMock.getArguments(); String machineName = (String)arguments[3]; boolean isDev = (boolean)arguments[4]; CheServiceImpl service = (CheServiceImpl)arguments[6]; Machine machine = createMachine(workspaceId, envName, service, machineName, isDev); NoOpMachineInstance instance = spy(new NoOpMachineInstance(machine)); expectedMachines.add(instance); return instance; }); CheServicesEnvironmentImpl servicesEnvironment = createCheServicesEnv(); for (CheServiceImpl service : servicesEnvironment.getServices().values()) { service.setImage(machineImage); } when(environmentParser.parse(env)).thenReturn(servicesEnvironment); // when List<Instance> machines = engine.start(workspaceId, envName, env, true, messageConsumer); // then assertEquals(machines, expectedMachines); ArgumentCaptor<CheServiceImpl> captor = ArgumentCaptor.forClass(CheServiceImpl.class); verify(machineProvider).startService(anyString(), anyString(), anyString(), anyString(), eq(false), anyString(), captor.capture(), any(LineConsumer.class)); CheServiceImpl actualService = captor.getValue(); assertEquals(actualService.getImage(), machineImage); } @Test public void shouldUseConfiguredInMachineRamInsteadOfSetDefaultOnMachineStart() throws Exception { // given List<Instance> instances = startEnv(); String workspaceId = instances.get(0).getWorkspaceId(); when(engine.generateMachineId()).thenReturn("newMachineId"); Instance newMachine = mock(Instance.class); when(newMachine.getId()).thenReturn("newMachineId"); when(newMachine.getWorkspaceId()).thenReturn(workspaceId); when(machineProvider.startService(anyString(), anyString(), anyString(), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenReturn(newMachine); MachineConfigImpl config = createConfig(false); String machineName = "extraMachine"; config.setName(machineName); config.setLimits(new MachineLimitsImpl(4096)); // when engine.startMachine(workspaceId, config, emptyList()); // then ArgumentCaptor<CheServiceImpl> captor = ArgumentCaptor.forClass(CheServiceImpl.class); verify(machineProvider).startService(anyString(), anyString(), anyString(), eq(machineName), eq(false), anyString(), captor.capture(), any(LineConsumer.class)); CheServiceImpl actualService = captor.getValue(); assertEquals((long)actualService.getMemLimit(), 4096L * 1024L * 1024L); } @Test public void shouldSetDockerfileContentInsteadOfUrlIfUrlPointsToCheApiOnMachineStart() throws Exception { // given List<Instance> instances = startEnv(); String workspaceId = instances.get(0).getWorkspaceId(); when(engine.generateMachineId()).thenReturn("newMachineId"); Instance newMachine = mock(Instance.class); when(newMachine.getId()).thenReturn("newMachineId"); when(newMachine.getWorkspaceId()).thenReturn(workspaceId); when(machineProvider.startService(anyString(), anyString(), anyString(), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenReturn(newMachine); MachineConfigImpl config = createConfig(false); String machineName = "extraMachine"; config.setName(machineName); config.setSource(new MachineSourceImpl("docker").setLocation(API_ENDPOINT + "/recipe/12345")); String dockerfileContent = "this is dockerfile content"; when(recipeDownloader.getRecipe(anyString())).thenReturn("this is dockerfile content"); // when engine.startMachine(workspaceId, config, emptyList()); // then ArgumentCaptor<CheServiceImpl> captor = ArgumentCaptor.forClass(CheServiceImpl.class); verify(machineProvider).startService(anyString(), anyString(), anyString(), eq(machineName), eq(false), anyString(), captor.capture(), any(LineConsumer.class)); CheServiceImpl actualService = captor.getValue(); assertNull(actualService.getBuild().getContext()); assertNull(actualService.getBuild().getDockerfilePath()); assertEquals(actualService.getBuild().getDockerfileContent(), dockerfileContent); } @Test public void shouldNotSetDockerfileContentInsteadOfUrlIfUrlDoesNotPointToCheApiOnMachineStart() throws Exception { // given List<Instance> instances = startEnv(); String workspaceId = instances.get(0).getWorkspaceId(); when(engine.generateMachineId()).thenReturn("newMachineId"); Instance newMachine = mock(Instance.class); when(newMachine.getId()).thenReturn("newMachineId"); when(newMachine.getWorkspaceId()).thenReturn(workspaceId); when(machineProvider.startService(anyString(), anyString(), anyString(), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenReturn(newMachine); MachineConfigImpl config = createConfig(false); String machineName = "extraMachine"; config.setName(machineName); String contextUrl = "http://another-server.com/recipe/12345"; config.setSource(new MachineSourceImpl("docker").setLocation(contextUrl)); // when engine.startMachine(workspaceId, config, emptyList()); // then ArgumentCaptor<CheServiceImpl> captor = ArgumentCaptor.forClass(CheServiceImpl.class); verify(machineProvider).startService(anyString(), anyString(), anyString(), eq(machineName), eq(false), anyString(), captor.capture(), any(LineConsumer.class)); CheServiceImpl actualService = captor.getValue(); assertNull(actualService.getBuild().getDockerfilePath()); assertNull(actualService.getBuild().getDockerfileContent()); assertEquals(actualService.getBuild().getContext(), contextUrl); } @Test public void shouldApplyAgentsOnDockerMachineStart() throws Exception { // given List<Instance> instances = startEnv(); String workspaceId = instances.get(0).getWorkspaceId(); when(engine.generateMachineId()).thenReturn("newMachineId"); Instance newMachine = mock(Instance.class); when(newMachine.getId()).thenReturn("newMachineId"); when(newMachine.getWorkspaceId()).thenReturn(workspaceId); when(machineProvider.startService(anyString(), anyString(), anyString(), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenReturn(newMachine); MachineConfigImpl config = createConfig(false); List<String> agents = asList("agent1", "agent2"); // when engine.startMachine(workspaceId, config, agents); // then verify(infrastructureProvisioner).provision(any(ExtendedMachineImpl.class), any(CheServiceImpl.class)); } @Test public void envStartShouldFireEvents() throws Exception { // when List<Instance> instances = startEnv(); assertTrue(instances.size() > 1, "This test requires at least 2 instances in environment"); // then for (Instance instance : instances) { verify(eventService).publish(newDto(MachineStatusEvent.class) .withEventType(MachineStatusEvent.EventType.CREATING) .withDev(instance.getConfig().isDev()) .withMachineName(instance.getConfig().getName()) .withMachineId(instance.getId()) .withWorkspaceId(instance.getWorkspaceId())); verify(eventService).publish(newDto(MachineStatusEvent.class) .withEventType(MachineStatusEvent.EventType.RUNNING) .withDev(instance.getConfig().isDev()) .withMachineName(instance.getConfig().getName()) .withMachineId(instance.getId()) .withWorkspaceId(instance.getWorkspaceId())); } } @Test(expectedExceptions = ConflictException.class, expectedExceptionsMessageRegExp = "Environment of workspace '.*' already exists") public void envStartShouldThrowsExceptionIfSameEnvironmentExists() throws Exception { // given List<Instance> instances = startEnv(); Instance instance = instances.get(0); EnvironmentImpl env = createEnv(); String envName = "env-1"; // when engine.start(instance.getWorkspaceId(), envName, env, false, messageConsumer); } @Test public void shouldBeAbleToStopEnv() throws Exception { // given List<Instance> instances = startEnv(); Instance instance = instances.get(0); // when engine.stop(instance.getWorkspaceId()); // then for (Instance instance1 : instances) { verify(instance1).destroy(); } verify(machineProvider).destroyNetwork(anyString()); } @Test(expectedExceptions = EnvironmentNotRunningException.class, expectedExceptionsMessageRegExp = "Stop of not running environment of workspace with ID '.*' is not allowed.") public void shouldThrowExceptionOnEnvStopIfItIsNotRunning() throws Exception { engine.stop("wsIdOFNonExistingEnv"); } @Test public void destroyOfMachineOnEnvStopShouldNotPreventStopOfOthers() throws Exception { // given List<Instance> instances = startEnv(); assertTrue(instances.size() > 1, "This test requires at least 2 instances in environment"); Instance instance = instances.get(0); doThrow(new MachineException("test exception")).when(instance).destroy(); // when engine.stop(instance.getWorkspaceId()); // then InOrder inOrder = inOrder(instances.toArray()); for (Instance instance1 : instances) { inOrder.verify(instance1).destroy(); } } @Test public void stopOfEnvironmentShouldDestroyNetworkWhenNoMachineExists() throws Exception { // given List<Instance> instances = startEnv(); String workspaceId = instances.get(0).getWorkspaceId(); for (Instance instance : instances) { engine.removeMachineFromEnvironment(instance.getWorkspaceId(), instance.getId()); } // when engine.stop(workspaceId); // then for (Instance instance : instances) { verify(instance, never()).destroy(); } verify(machineProvider).destroyNetwork(anyString()); } @Test public void shouldBeAbleToStartMachine() throws Exception { // given List<Instance> instances = startEnv(); verify(machineProvider, times(2)).startService(anyString(), anyString(), anyString(), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class)); String workspaceId = instances.get(0).getWorkspaceId(); when(engine.generateMachineId()).thenReturn("newMachineId"); Instance newMachine = mock(Instance.class); when(newMachine.getId()).thenReturn("newMachineId"); when(newMachine.getWorkspaceId()).thenReturn(workspaceId); when(machineProvider.startService(anyString(), anyString(), anyString(), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenReturn(newMachine); MachineConfigImpl config = createConfig(false); // when Instance actualInstance = engine.startMachine(workspaceId, config, emptyList()); // then assertEquals(actualInstance, newMachine); verify(instanceProvider, never()).createInstance(any(Machine.class), any(LineConsumer.class)); verify(machineProvider, times(3)).startService(anyString(), anyString(), anyString(), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class)); } @Test public void shouldBeAbleToStartNonDockerMachine() throws Exception { // given ServerConf2 serverConf2 = mock(ServerConf2.class); when(serverConf2.getPort()).thenReturn("1111/tcp"); when(serverConf2.getProtocol()).thenReturn("http"); when(serverConf2.getProperties()).thenReturn(singletonMap("path", "some path")); when(agent.getServers()).thenAnswer(invocation -> singletonMap("ssh", serverConf2)); List<Instance> instances = startEnv(); String workspaceId = instances.get(0).getWorkspaceId(); when(engine.generateMachineId()).thenReturn("newMachineId"); Instance newMachine = mock(Instance.class); when(newMachine.getId()).thenReturn("newMachineId"); when(newMachine.getWorkspaceId()).thenReturn(workspaceId); when(machineInstanceProviders.getProvider("anotherType")).thenReturn(instanceProvider); doReturn(newMachine).when(instanceProvider).createInstance(any(Machine.class), any(LineConsumer.class)); MachineConfigImpl config = MachineConfigImpl.builder() .fromConfig(createConfig(false)) .setType("anotherType") .build(); // when Instance actualInstance = engine.startMachine(workspaceId, config, singletonList("agent")); // then assertEquals(actualInstance, newMachine); ArgumentCaptor<Machine> argumentCaptor = ArgumentCaptor.forClass(Machine.class); verify(instanceProvider).createInstance(argumentCaptor.capture(), any(LineConsumer.class)); MachineConfigImpl newConfig = new MachineConfigImpl(config); newConfig.setServers(singletonList(new ServerConfImpl("ssh", "1111/tcp", "http", "some path"))); assertEquals(argumentCaptor.getValue().getConfig(), newConfig); } @Test(expectedExceptions = EnvironmentNotRunningException.class, expectedExceptionsMessageRegExp = "Environment '.*' is not running") public void shouldThrowExceptionOnMachineStartIfEnvironmentIsNotRunning() throws Exception { MachineConfigImpl config = createConfig(false); // when engine.startMachine("wsIdOfNotRunningEnv", config, emptyList()); } @Test(expectedExceptions = ConflictException.class, expectedExceptionsMessageRegExp = "Machine with name '.*' already exists in environment of workspace '.*'") public void machineStartShouldThrowExceptionIfMachineWithTheSameNameAlreadyExistsInEnvironment() throws Exception { // given List<Instance> instances = startEnv(); Instance instance = instances.get(0); MachineConfigImpl config = createConfig(false); config.setName(instance.getConfig().getName()); // when engine.startMachine(instance.getWorkspaceId(), config, emptyList()); } @Test public void machineStartShouldPublishEvents() throws Exception { // given List<Instance> instances = startEnv(); Instance instance = instances.get(0); MachineConfigImpl config = createConfig(false); when(engine.generateMachineId()).thenReturn("newMachineId"); // when engine.startMachine(instance.getWorkspaceId(), config, emptyList()); // then verify(eventService).publish(newDto(MachineStatusEvent.class) .withEventType(MachineStatusEvent.EventType.CREATING) .withDev(config.isDev()) .withMachineName(config.getName()) .withMachineId("newMachineId") .withWorkspaceId(instance.getWorkspaceId())); verify(eventService).publish(newDto(MachineStatusEvent.class) .withEventType(MachineStatusEvent.EventType.RUNNING) .withDev(config.isDev()) .withMachineName(config.getName()) .withMachineId("newMachineId") .withWorkspaceId(instance.getWorkspaceId())); } @Test public void shouldBeAbleToStopMachine() throws Exception { // given List<Instance> instances = startEnv(); Optional<Instance> instanceOpt = instances.stream() .filter(machine -> !machine.getConfig().isDev()) .findAny(); assertTrue(instanceOpt.isPresent(), "Required for test non-dev machine is not found"); Instance instance = instanceOpt.get(); // when engine.stopMachine(instance.getWorkspaceId(), instance.getId()); // then verify(instance).destroy(); } @Test(expectedExceptions = EnvironmentNotRunningException.class, expectedExceptionsMessageRegExp = "Environment '.*' is not running") public void machineStopShouldThrowExceptionIfEnvDoesNotExist() throws Exception { engine.stopMachine("wsIdOfNotRunningEnv", "testMachineID"); } @Test(expectedExceptions = ConflictException.class, expectedExceptionsMessageRegExp = "Stop of dev machine is not allowed. Please, stop whole environment") public void devMachineStopShouldThrowException() throws Exception { // given List<Instance> instances = startEnv(); Optional<Instance> instanceOpt = instances.stream() .filter(machine -> machine.getConfig().isDev()) .findAny(); assertTrue(instanceOpt.isPresent(), "Required for test dev machine is not found"); Instance instance = instanceOpt.get(); // when engine.stopMachine(instance.getWorkspaceId(), instance.getId()); } @Test(expectedExceptions = NotFoundException.class, expectedExceptionsMessageRegExp = "Machine with ID '.*' is not found in environment of workspace '.*'") public void machineStopOfNonExistingMachineShouldThrowsException() throws Exception { // given List<Instance> instances = startEnv(); Instance instance = instances.get(0); // when engine.stopMachine(instance.getWorkspaceId(), "idOfNonExistingMachine"); } @Test public void machineStopShouldFireEvents() throws Exception { // given List<Instance> instances = startEnv(); Optional<Instance> instanceOpt = instances.stream() .filter(machine -> !machine.getConfig().isDev()) .findAny(); assertTrue(instanceOpt.isPresent(), "Required for test non-dev machine is not found"); Instance instance = instanceOpt.get(); // when engine.stopMachine(instance.getWorkspaceId(), instance.getId()); // then verify(eventService).publish(newDto(MachineStatusEvent.class) .withEventType(MachineStatusEvent.EventType.CREATING) .withDev(instance.getConfig().isDev()) .withMachineName(instance.getConfig().getName()) .withMachineId(instance.getId()) .withWorkspaceId(instance.getWorkspaceId())); verify(eventService).publish(newDto(MachineStatusEvent.class) .withEventType(MachineStatusEvent.EventType.RUNNING) .withDev(instance.getConfig().isDev()) .withMachineName(instance.getConfig().getName()) .withMachineId(instance.getId()) .withWorkspaceId(instance.getWorkspaceId())); } @Test public void shouldBeAbleToSaveMachineSnapshot() throws Exception { // given List<Instance> instances = startEnv(); Instance instance = instances.get(0); doReturn(new MachineSourceImpl("someType").setContent("some content")).when(instance).saveToSnapshot(); // when engine.saveSnapshot(instance.getWorkspaceId(), instance.getId()); // then verify(instance).saveToSnapshot(); } @Test(expectedExceptions = EnvironmentNotRunningException.class, expectedExceptionsMessageRegExp = "Environment .*' is not running") public void shouldThrowExceptionOnSaveSnapshotIfEnvIsNotRunning() throws Exception { engine.saveSnapshot("wsIdOfNotRunningEnv", "someId"); } @Test(expectedExceptions = NotFoundException.class, expectedExceptionsMessageRegExp = "Machine with id '.*' is not found in environment of workspace '.*'") public void shouldThrowExceptionOnSaveSnapshotIfMachineIsNotFound() throws Exception { // given List<Instance> instances = startEnv(); Instance instance = instances.get(0); // when engine.saveSnapshot(instance.getWorkspaceId(), "idOfNonExistingMachine"); } @Test public void shouldBeAbleToRemoveSnapshot() throws Exception { // given SnapshotImpl snapshot = mock(SnapshotImpl.class); MachineSourceImpl machineSource = mock(MachineSourceImpl.class); when(snapshot.getType()).thenReturn("docker"); when(snapshot.getMachineSource()).thenReturn(machineSource); // when engine.removeSnapshot(snapshot); // then verify(instanceProvider).removeInstanceSnapshot(machineSource); } @Test public void shouldReplaceServiceNameWithContainerNameInLinks() { //given final String serviceNameToLink = "service"; final String containerNameToLink = "container"; List<String> links = new ArrayList<>(); links.add(serviceNameToLink); CheServiceImpl serviceToNormalizeLinks = new CheServiceImpl().withLinks(links); CheServiceImpl service1 = mock(CheServiceImpl.class); CheServiceImpl service2 = mock(CheServiceImpl.class); Map<String, CheServiceImpl> allServices = new HashMap<>(); allServices.put("this", serviceToNormalizeLinks); allServices.put(serviceNameToLink, service1); allServices.put("anotherService", service2); when(service1.getContainerName()).thenReturn(containerNameToLink); // when engine.normalizeLinks(serviceToNormalizeLinks, allServices); // then assertEquals(serviceToNormalizeLinks.getLinks().size(), 1); assertEquals(serviceToNormalizeLinks.getLinks().get(0), containerNameToLink); } @Test public void shouldReplaceServiceNameWithContainerNameAndUseAliasInLinks() { //given final String serviceNameToLink = "service"; final String containerNameToLink = "container"; final String AliasToServiceToLink = "alias"; List<String> links = new ArrayList<>(); links.add(serviceNameToLink + ':' + AliasToServiceToLink); CheServiceImpl serviceToNormalizeLinks = new CheServiceImpl().withLinks(links); CheServiceImpl service1 = mock(CheServiceImpl.class); CheServiceImpl service2 = mock(CheServiceImpl.class); Map<String, CheServiceImpl> allServices = new HashMap<>(); allServices.put("this", serviceToNormalizeLinks); allServices.put(serviceNameToLink, service1); allServices.put("anotherService", service2); when(service1.getContainerName()).thenReturn(containerNameToLink); // when engine.normalizeLinks(serviceToNormalizeLinks, allServices); // then assertEquals(serviceToNormalizeLinks.getLinks().size(), 1); assertEquals(serviceToNormalizeLinks.getLinks().get(0), containerNameToLink + ':' + AliasToServiceToLink); } @Test public void shouldDestroyAndRemoveMachineFromEnvironmentIfEventAboutItsDeath() throws Exception { // given List<Instance> instances = startEnv(); Instance instance = instances.get(0); String machineId = instance.getId(); String workspaceId = instance.getWorkspaceId(); when(instance.getLogger()).thenReturn(LineConsumer.DEV_NULL); engine.init(); verify(eventService).subscribe(eventServiceSubscriberCaptor.capture()); EventSubscriber<InstanceStateEvent> subscriber = eventServiceSubscriberCaptor.getValue(); ArgumentCaptor<Runnable> runnableArgumentCaptor = ArgumentCaptor.forClass(Runnable.class); // when subscriber.onEvent(new InstanceStateEvent(machineId, workspaceId, InstanceStateEvent.Type.DIE)); // catch event actor verify(sharedPool).execute(runnableArgumentCaptor.capture()); Runnable eventActor = runnableArgumentCaptor.getValue(); // run event actor to verify its behavior eventActor.run(); // then for (Instance instance1 : instances) { // other machines are not destroyed if (instance1.equals(instance)) { verify(instance1).destroy(); } else { verify(instance1, never()).destroy(); } } for (Instance instance1 : engine.getMachines(workspaceId)) { assertNotEquals(instance1.getId(), machineId); } } @Test public void shouldDestroyAndRemoveMachineFromEnvironmentIfEventAboutItsOOM() throws Exception { // given List<Instance> instances = startEnv(); Instance instance = instances.get(0); String machineId = instance.getId(); String workspaceId = instance.getWorkspaceId(); when(instance.getLogger()).thenReturn(LineConsumer.DEV_NULL); engine.init(); verify(eventService).subscribe(eventServiceSubscriberCaptor.capture()); EventSubscriber<InstanceStateEvent> subscriber = eventServiceSubscriberCaptor.getValue(); ArgumentCaptor<Runnable> runnableArgumentCaptor = ArgumentCaptor.forClass(Runnable.class); // when subscriber.onEvent(new InstanceStateEvent(machineId, workspaceId, InstanceStateEvent.Type.OOM)); // catch event actor verify(sharedPool).execute(runnableArgumentCaptor.capture()); Runnable eventActor = runnableArgumentCaptor.getValue(); // run event actor to verify its behavior eventActor.run(); // then for (Instance instance1 : instances) { // other machines are not destroyed if (instance1.equals(instance)) { verify(instance1).destroy(); } else { verify(instance1, never()).destroy(); } } for (Instance instance1 : engine.getMachines(workspaceId)) { assertNotEquals(instance1.getId(), machineId); } } @Test public void shouldBeAbleToRestartEnvironmentAfterServerException() throws Exception { // given EnvironmentImpl env = createEnv(); String envName = "env-1"; String workspaceId = "wsId"; String testServerExcMessage = "test exception"; when(machineProvider.startService(anyString(), eq(workspaceId), eq(envName), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenThrow(new ServerException(testServerExcMessage)); when(environmentParser.parse(env)).thenReturn(createCheServicesEnv()); // when // env start must fails because of server exception try { engine.start(workspaceId, envName, env, false, messageConsumer, startedHandler); fail("Server exception should be thrown"); } catch (ServerException e) { assertEquals(e.getMessage(), testServerExcMessage); } when(machineProvider.startService(anyString(), eq(workspaceId), eq(envName), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenAnswer(invocationOnMock -> { Object[] arguments = invocationOnMock.getArguments(); String machineName = (String)arguments[3]; boolean isDev = (boolean)arguments[4]; CheServiceImpl service = (CheServiceImpl)arguments[6]; Machine machine = createMachine(workspaceId, envName, service, machineName, isDev); return new NoOpMachineInstance(machine); }); // then // env start succeeds engine.start(workspaceId, envName, env, false, messageConsumer, startedHandler); } @Test public void shouldBeAbleToRestartEnvironmentAfterRuntimeException() throws Exception { // given EnvironmentImpl env = createEnv(); String envName = "env-1"; String workspaceId = "wsId"; String testEnvExcMessage = "test exception"; when(machineProvider.startService(anyString(), eq(workspaceId), eq(envName), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenThrow(new RuntimeException(testEnvExcMessage)); when(environmentParser.parse(env)).thenReturn(createCheServicesEnv()); // when // env start must fails because of exception try { engine.start(workspaceId, envName, env, false, messageConsumer, startedHandler); fail("Environment exception should be thrown"); } catch (ServerException e) { assertEquals(e.getMessage(), testEnvExcMessage); } when(machineProvider.startService(anyString(), eq(workspaceId), eq(envName), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenAnswer(invocationOnMock -> { Object[] arguments = invocationOnMock.getArguments(); String machineName = (String)arguments[3]; boolean isDev = (boolean)arguments[4]; CheServiceImpl service = (CheServiceImpl)arguments[6]; Machine machine = createMachine(workspaceId, envName, service, machineName, isDev); return new NoOpMachineInstance(machine); }); // then // env start succeeds engine.start(workspaceId, envName, env, false, messageConsumer, startedHandler); } @Test public void shouldBeAbleToRestartEnvironmentAfterAgentException() throws Exception { // given EnvironmentImpl env = createEnv(); String envName = "env-1"; String workspaceId = "wsId"; when(machineProvider.startService(anyString(), eq(workspaceId), eq(envName), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenAnswer(invocationOnMock -> { Object[] arguments = invocationOnMock.getArguments(); String machineName = (String)arguments[3]; boolean isDev = (boolean)arguments[4]; CheServiceImpl service = (CheServiceImpl)arguments[6]; Machine machine = createMachine(workspaceId, envName, service, machineName, isDev); return new NoOpMachineInstance(machine); }); when(environmentParser.parse(env)).thenReturn(createCheServicesEnv()); String testAgentExcMessage = "test agent exception"; doThrow(new AgentException(testAgentExcMessage)).when(startedHandler) .started(any(Instance.class), any(ExtendedMachine.class)); // when // env start must fails because of agent exception try { engine.start(workspaceId, envName, env, false, messageConsumer, startedHandler); fail("Agent exception should be thrown"); } catch (AgentException e) { assertEquals(e.getMessage(), testAgentExcMessage); } doNothing().when(startedHandler).started(any(Instance.class), any(ExtendedMachine.class)); // then // env start succeeds engine.start(workspaceId, envName, env, false, messageConsumer, startedHandler); } private List<Instance> startEnv() throws Exception { EnvironmentImpl env = createEnv(); CheServicesEnvironmentImpl cheServicesEnv = createCheServicesEnv(); return startEnv(env, cheServicesEnv); } private List<Instance> startEnv(EnvironmentImpl env, CheServicesEnvironmentImpl cheServicesEnv) throws Exception { String envName = "env-1"; String workspaceId = "wsId"; when(machineProvider.startService(anyString(), eq(workspaceId), eq(envName), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))) .thenAnswer(invocationOnMock -> { Object[] arguments = invocationOnMock.getArguments(); String machineName = (String)arguments[3]; boolean isDev = (boolean)arguments[4]; CheServiceImpl service = (CheServiceImpl)arguments[6]; Machine machine = createMachine(workspaceId, envName, service, machineName, isDev); return spy(new NoOpMachineInstance(machine)); }); when(environmentParser.parse(env)).thenReturn(cheServicesEnv); // when return engine.start(workspaceId, envName, env, false, messageConsumer); } private static MachineConfigImpl createConfig(boolean isDev) { return MachineConfigImpl.builder() .setDev(isDev) .setType("docker") .setLimits(new MachineLimitsImpl(1024)) .setSource(new MachineSourceImpl("dockerfile").setLocation("location")) .setName(UUID.randomUUID().toString()) .build(); } private EnvironmentImpl createEnv() { // singletonMap, asList are wrapped into modifiable collections to ease env modifying by tests EnvironmentImpl env = new EnvironmentImpl(); Map<String, ExtendedMachineImpl> machines = new HashMap<>(); Map<String, ServerConf2Impl> servers = new HashMap<>(); servers.put("ref1", new ServerConf2Impl("8080/tcp", "proto1", singletonMap("prop1", "propValue"))); servers.put("ref2", new ServerConf2Impl("8080/udp", "proto1", null)); servers.put("ref3", new ServerConf2Impl("9090", "proto1", null)); machines.put("dev-machine", new ExtendedMachineImpl(asList("org.eclipse.che.ws-agent", "someAgent"), servers, singletonMap("memoryLimitBytes", "10000"))); machines.put("machine2", new ExtendedMachineImpl(asList("someAgent2", "someAgent3"), null, singletonMap("memoryLimitBytes", "10000"))); String environmentRecipeContent = "services:\n " + "dev-machine:\n image: codenvy/ubuntu_jdk8\n mem_limit: 4294967296\n " + "machine2:\n image: codenvy/ubuntu_jdk8\n mem_limit: 100000"; env.setRecipe(new EnvironmentRecipeImpl("compose", "application/x-yaml", environmentRecipeContent, null)); env.setMachines(machines); return env; } private CheServicesEnvironmentImpl createCheServicesEnv() { CheServicesEnvironmentImpl cheServicesEnvironment = new CheServicesEnvironmentImpl(); Map<String, CheServiceImpl> services = new HashMap<>(); services.put("dev-machine", new CheServiceImpl().withBuild(new CheServiceBuildContextImpl().withContext("image"))); services.put("machine2", new CheServiceImpl().withBuild(new CheServiceBuildContextImpl().withContext("image"))); cheServicesEnvironment.setServices(services); return cheServicesEnvironment; } private CheServicesEnvironmentImpl createCheServicesEnvByName(String name) { CheServicesEnvironmentImpl cheServicesEnvironment = new CheServicesEnvironmentImpl(); Map<String, CheServiceImpl> services = new HashMap<>(); services.put(name, new CheServiceImpl().withBuild(new CheServiceBuildContextImpl().withContext("image"))); cheServicesEnvironment.setServices(services); return cheServicesEnvironment; } private static MachineImpl createMachine(String workspaceId, String envName, CheServiceImpl service, String serviceName, boolean isDev) { MachineSourceImpl machineSource; if (service.getBuild() != null && service.getBuild().getContext() != null) { machineSource = new MachineSourceImpl("dockerfile").setLocation(service.getBuild().getContext()); } else if (service.getImage() != null) { machineSource = new MachineSourceImpl("image").setLocation(service.getImage()); } else if (service.getBuild() != null && service.getBuild().getContext() == null && service.getBuild().getDockerfileContent() != null) { machineSource = new MachineSourceImpl("dockerfile").setContent(service.getBuild().getDockerfileContent()); } else { throw new IllegalArgumentException("Build context or image should contain non empty value"); } MachineLimitsImpl limits = new MachineLimitsImpl((int)Size.parseSizeToMegabytes(service.getMemLimit() + "b")); return MachineImpl.builder() .setConfig(MachineConfigImpl.builder() .setDev(isDev) .setName(serviceName) .setSource(machineSource) .setLimits(limits) .setType("docker") .build()) .setId(service.getId()) .setOwner("userName") .setStatus(MachineStatus.RUNNING) .setWorkspaceId(workspaceId) .setEnvName(envName) .setRuntime(new MachineRuntimeInfoImpl(emptyMap(), emptyMap(), emptyMap())) .build(); } }