/*******************************************************************************
* Copyright (c) 2012-2016 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.plugin.docker.machine.integration;
/*import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.model.machine.MachineStatus;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.core.util.LineConsumer;
import org.eclipse.che.api.core.util.ValueHolder;
import org.eclipse.che.api.machine.server.MachineInstanceProviders;
import org.eclipse.che.api.machine.server.MachineManager;
import org.eclipse.che.api.machine.server.MachineRegistry;
import org.eclipse.che.api.machine.server.MachineService;
import org.eclipse.che.api.machine.server.dao.SnapshotDao;
import org.eclipse.che.api.machine.server.exception.MachineException;
import org.eclipse.che.api.machine.server.impl.SnapshotImpl;
import org.eclipse.che.api.machine.server.model.impl.MachineImpl;
import org.eclipse.che.api.machine.server.model.impl.MachineStateImpl;
import org.eclipse.che.api.machine.server.spi.InstanceProvider;
import org.eclipse.che.api.machine.shared.dto.CommandDto;
import org.eclipse.che.api.machine.shared.dto.MachineProcessDto;
import org.eclipse.che.api.machine.shared.dto.recipe.MachineRecipe;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.user.User;
import org.eclipse.che.commons.user.UserImpl;
import org.eclipse.che.inject.ConfigurationProperties;
import org.eclipse.che.plugin.docker.client.DockerConnector;
import org.eclipse.che.plugin.docker.client.InitialAuthConfig;
import org.eclipse.che.plugin.docker.client.ProgressLineFormatterImpl;
import org.eclipse.che.plugin.docker.client.json.ContainerConfig;
import org.eclipse.che.plugin.docker.client.json.HostConfig;
import org.eclipse.che.plugin.docker.client.json.PortBinding;
import org.eclipse.che.plugin.docker.machine.DockerInstanceKey;
import org.eclipse.che.plugin.docker.machine.DockerInstanceProvider;
import org.eclipse.che.plugin.docker.machine.DockerInstanceStopDetector;
import org.eclipse.che.plugin.docker.machine.DockerMachineFactory;
import org.eclipse.che.plugin.docker.machine.node.DockerNode;
import org.eclipse.che.plugin.docker.machine.TestDockerMachineFactory;
import org.eclipse.che.plugin.docker.machine.WorkspaceFolderNodePathProvider;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
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.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;*/
// TODO rework authentication
// TODO check removeSnapshotTest with https and password
// TODO bind, unbind
// TODO should we check result of tests with native calls?
/**
* @author Alexander Garagatyi
*/
//@Listeners(value = {MockitoTestNGListener.class})
public class ServiceTest {
/* private static final String USER = "userId";
private static final String SNAPSHOT_ID = "someSnapshotId";
private static LineConsumer lineConsumer = new StdErrLineConsumer();
// set in method {@link saveSnapshotTest}
// used in methods {@link createMachineFromSnapshotTest} and {@link removeSnapshotTest}
private DockerInstanceKey pushedImage;
private SnapshotDao snapshotDao;
private MachineRegistry machineRegistry;
private DockerConnector docker;
private MachineManager machineManager;
private MachineService machineService;
private String registryContainerId;
@Mock
private WorkspaceFolderNodePathProvider workspaceFolderNodePathProvider;
@Mock
private ConfigurationProperties configurationProperties;
@Mock
private DockerInstanceStopDetector dockerInstanceStopDetector;
private DockerMachineFactory dockerMachineFactory;
@BeforeClass
public void setUpClass() throws Exception {
when(configurationProperties.getProperties(anyString())).thenReturn(Collections.<String, String>emptyMap());
InitialAuthConfig authConfigs = new InitialAuthConfig(configurationProperties);
docker = new DockerConnector(authConfigs);
machineRegistry = new MachineRegistry();
assertTrue(pull("registry", "latest", null));
dockerMachineFactory = new TestDockerMachineFactory(docker);
final ContainerConfig containerConfig = new ContainerConfig()
.withImage("registry")
.withExposedPorts(singletonMap("5000/tcp", Collections.<String, String>emptyMap()))
.withHostConfig(new HostConfig().withPortBindings(
singletonMap("5000/tcp", new PortBinding[]{new PortBinding().withHostPort("5000")})));
registryContainerId = docker.createContainer(containerConfig, null).getId();
docker.startContainer(registryContainerId, null);
}
@AfterClass
public void tearDownClass() throws IOException {
docker.killContainer(registryContainerId);
docker.removeContainer(registryContainerId, true, false);
}
@BeforeMethod
public void setUp() throws Exception {
snapshotDao = mock(SnapshotDao.class);
DockerNode dockerNode = mock(DockerNode.class);
EventService eventService = mock(EventService.class);
RuntimeWorkspaceRegistry runtimeWorkspaceRegistry = mock(RuntimeWorkspaceRegistry.class);
EnvironmentContext envCont = new EnvironmentContext();
envCont.setUser(new UserImpl("user", null, null, null, false));
EnvironmentContext.setCurrent(envCont);
RuntimeWorkspaceImpl runtimeWorkspaceImpl = mock(RuntimeWorkspaceImpl.class);
when(runtimeWorkspaceRegistry.get(any())).thenReturn(runtimeWorkspaceImpl);
when(runtimeWorkspaceImpl.getName()).thenReturn("workspace");
InstanceProvider dockerInstanceProvider = new DockerInstanceProvider(docker,
dockerMachineFactory,
dockerInstanceStopDetector,
Collections.emptySet(),
Collections.emptySet(),
Collections.emptySet(),
Collections.emptySet(),
null,
"fake",
workspaceFolderNodePathProvider);
machineManager = new MachineManager(snapshotDao,
machineRegistry,
new MachineInstanceProviders(Collections.singleton(dockerInstanceProvider)),
"/tmp",
eventService,
100);
machineService = spy(new MachineService(machineManager));
EnvironmentContext.getCurrent().setUser(new User() {
@Override
public String getName() {
return null;
}
@Override
public boolean isMemberOf(String s) {
return false;
}
@Override
public String getToken() {
return null;
}
@Override
public String getId() {
return USER;
}
@Override
public boolean isTemporary() {
return false;
}
});
when(dockerNode.getProjectsFolder()).thenReturn(System.getProperty("user.dir"));
}
@AfterMethod
public void tearDown() throws Exception {
for (MachineStateImpl machine : new ArrayList<>(machineManager.getMachinesStates())) {
machineManager.destroy(machine.getId(), false);
}
EnvironmentContext.reset();
}
@Test
public void createFromRecipeTest() throws Exception {
final MachineStateDescriptor machine = machineService.createMachineFromRecipe(
newDto(RecipeMachineCreationMetadata.class)
.withType("docker")
.withDisplayName("MachineDisplayName")
.withWorkspaceId("wsId")
.withRecipe(newDto(MachineRecipe.class)
.withType("Dockerfile")
.withScript("FROM ubuntu\nCMD tail -f /dev/null\n")));
waitMachineIsRunning(machine.getId());
}
@Test(dependsOnMethods = "saveSnapshotTest", enabled = false)
public void createMachineFromSnapshotTest() throws Exception {
// remove local copy of image to check pulling
docker.removeImage(pushedImage.getImageId(), true);
SnapshotImpl snapshot = mock(SnapshotImpl.class);
when(snapshotDao.getSnapshot(SNAPSHOT_ID)).thenReturn(snapshot);
when(snapshot.getType()).thenReturn("docker");
when(snapshot.getWorkspaceId()).thenReturn("wsId");
when(snapshot.getInstanceKey()).thenReturn(pushedImage);
when(snapshot.getOwner()).thenReturn(USER);
final MachineStateDescriptor machine = machineService
.createMachineFromSnapshot(newDto(SnapshotMachineCreationMetadata.class).withSnapshotId(SNAPSHOT_ID));
waitMachineIsRunning(machine.getId());
}
@Test
public void getMachineTest() throws Exception {
final MachineImpl machine = createMachineAndWaitRunningState();
final MachineDescriptor machineById = machineService.getMachineById(machine.getId());
assertEquals(machineById.getId(), machine.getId());
}
@Test
public void getMachinesTest() throws Exception {
Set<String> expected = new HashSet<>();
expected.add(createMachineAndWaitRunningState().getId());
expected.add(createMachineAndWaitRunningState().getId());
Set<String> actual = machineManager.getMachinesStates()
.stream()
.map(MachineImpl::getId)
.collect(Collectors.toSet());
assertEquals(actual, expected);
}
@Test
public void destroyMachineTest() throws Exception {
final MachineImpl machine = createMachineAndWaitRunningState();
machineService.destroyMachine(machine.getId());
assertEquals(machineService.getMachineStateById(machine.getId()).getStatus(), MachineStatus.DESTROYING);
int counter = 0;
while (++counter < 1000) {
try {
machineManager.getMachine(machine.getId());
} catch (NotFoundException e) {
return;
}
Thread.sleep(500);
}
fail();
}
@Test(enabled = false)// TODO Add ability to check when snapshot creation is finishes or fails
public void saveSnapshotTest() throws Exception {
final MachineImpl machine = createMachineAndWaitRunningState();
// use machine manager instead of machine service because it returns future with snapshot
// that allows check operation result
final SnapshotImpl snapshot = machineManager.save(machine.getId(), USER, "test description");
for (int i = 0; snapshot.getInstanceKey() == null && i < 10; ++i) {
Thread.sleep(500);
}
assertNotNull(snapshot.getInstanceKey());
final DockerInstanceKey instanceKey = (DockerInstanceKey)snapshot.getInstanceKey();
final boolean pullIsSuccessful = pull(instanceKey.getRepository(), instanceKey.getTag(), instanceKey.getRegistry());
assertTrue(pullIsSuccessful);
pushedImage = instanceKey;
}
// depends on saveSnapshotTest to be able to remove image from registry
// actually doesn't depend on createMachineFromSnapshotTest,
// but this test will fail createMachineFromSnapshotTest if called before
@Test(dependsOnMethods = {"saveSnapshotTest", "createMachineFromSnapshotTest"}, enabled = false)// TODO
public void removeSnapshotTest() throws Exception {
SnapshotImpl snapshot = mock(SnapshotImpl.class);
when(snapshotDao.getSnapshot(SNAPSHOT_ID)).thenReturn(snapshot);
when(snapshot.getType()).thenReturn("docker");
when(snapshot.getOwner()).thenReturn(USER);
when(snapshot.getInstanceKey()).thenReturn(pushedImage);
machineService.removeSnapshot(SNAPSHOT_ID);
verify(snapshotDao).removeSnapshot(SNAPSHOT_ID);
try {
final boolean isPullSuccessful = pull(pushedImage.getRepository(), pushedImage.getTag(), pushedImage.getRegistry());
assertFalse(isPullSuccessful);
} catch (Exception e) {
fail(e.getLocalizedMessage(), e);
}
}
@Test
public void executeTest() throws Exception {
final MachineImpl machine = createMachineAndWaitRunningState();
String commandInMachine = "echo \"command in machine\" && tail -f /dev/null";
machineService.executeCommandInMachine(machine.getId(),
DtoFactory.newDto(CommandDto.class).withCommandLine(commandInMachine),
null);
Thread.sleep(500);
final List<MachineProcessDto> processes = machineService.getProcesses(machine.getId());
assertEquals(processes.size(), 1);
assertEquals(processes.get(0).getCommandLine(), commandInMachine);
}
@Test
public void getProcessesTest() throws Exception {
final MachineImpl machine = createMachineAndWaitRunningState();
Set<String> commands = new HashSet<>(2);
commands.add("tail -f /dev/null");
commands.add("sleep 10000");
for (String command : commands) {
machineService.executeCommandInMachine(machine.getId(), DtoFactory.newDto(CommandDto.class).withCommandLine(command), null);
}
Thread.sleep(500);
final List<MachineProcessDto> processes = machineService.getProcesses(machine.getId());
assertEquals(processes.size(), 2);
Set<String> actualCommandLines = new HashSet<>(2);
for (MachineProcessDto process : processes) {
assertTrue(process.getPid() > 0);
actualCommandLines.add(process.getCommandLine());
}
assertEquals(actualCommandLines, commands);
}
@Test
public void stopProcessTest() throws Exception {
final MachineImpl machine = createMachineAndWaitRunningState();
String commandInMachine = "echo \"command in machine\" && tail -f /dev/null";
machineService.executeCommandInMachine(machine.getId(),
DtoFactory.newDto(CommandDto.class).withCommandLine(commandInMachine),
null);
Thread.sleep(500);
final List<MachineProcessDto> processes = machineService.getProcesses(machine.getId());
assertEquals(processes.size(), 1);
assertEquals(processes.get(0).getCommandLine(), commandInMachine);
machineService.stopProcess(machine.getId(), processes.get(0).getPid());
assertTrue(machineService.getProcesses(machine.getId()).isEmpty());
}
@Test(expectedExceptions = NotFoundException.class, expectedExceptionsMessageRegExp = "Process with pid .* not found")
public void shouldThrowNotFoundExceptionOnProcessKillIfProcessPidMissing() throws Exception {
final MachineImpl machine = createMachineAndWaitRunningState();
String commandInMachine = "echo \"command in machine\" && tail -f /dev/null";
machineService.executeCommandInMachine(machine.getId(),
DtoFactory.newDto(CommandDto.class).withCommandLine(commandInMachine),
null);
Thread.sleep(500);
final List<MachineProcessDto> processes = machineService.getProcesses(machine.getId());
assertEquals(processes.size(), 1);
assertEquals(processes.get(0).getCommandLine(), commandInMachine);
machineService.stopProcess(machine.getId(), processes.get(0).getPid() + 100);
}
private MachineImpl createMachineAndWaitRunningState() throws Exception {
final MachineImpl machine = machineManager.create(newDto(RecipeMachineCreationMetadata.class)
.withWorkspaceId("wsId")
.withType("docker")
.withDisplayName("MachineDisplayName")
.withRecipe(newDto(MachineRecipe.class)
.withType("Dockerfile")
.withScript(
"FROM ubuntu\nCMD tail -f " +
"/dev/null\n"))
.withDev(false)
.withDisplayName("displayName" + System.currentTimeMillis())
, false);
waitMachineIsRunning(machine.getId());
return machine;
}
private void waitMachineIsRunning(String machineId) throws NotFoundException, InterruptedException, MachineException {
while (MachineStatus.RUNNING != machineManager.getMachineState(machineId).getStatus()) {
Thread.sleep(500);
}
}
private boolean pull(String image, String tag, String registry) throws Exception {
final ValueHolder<Boolean> isSuccessfulValueHolder = new ValueHolder<>(true);
final ProgressLineFormatterImpl progressLineFormatter = new ProgressLineFormatterImpl();
docker.pull(image, tag, registry, currentProgressStatus -> {
try {
if (currentProgressStatus.getError() != null) {
isSuccessfulValueHolder.set(false);
}
lineConsumer.writeLine(progressLineFormatter.format(currentProgressStatus));
} catch (IOException ignored) {
}
});
return isSuccessfulValueHolder.get();
}
private static class StdErrLineConsumer implements LineConsumer {
@Override
public void writeLine(String line) throws IOException {
System.err.println(line);
}
@Override
public void close() throws IOException {
}
}*/
}