/******************************************************************************* * 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.ide.ext.machine.server.ssh; import org.eclipse.che.api.core.model.machine.MachineMetadata; 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.machine.server.MachineManager; import org.eclipse.che.api.machine.server.spi.Instance; import org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent; import org.eclipse.che.api.ssh.server.SshManager; import org.eclipse.che.api.ssh.server.model.impl.SshPairImpl; import org.eclipse.che.plugin.docker.client.DockerConnector; import org.eclipse.che.plugin.docker.client.Exec; import org.eclipse.che.plugin.docker.client.LogMessage; import org.eclipse.che.plugin.docker.client.MessageProcessor; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Listeners; import org.testng.annotations.Test; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; import static org.eclipse.che.dto.server.DtoFactory.newDto; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; /** * Test for {@link KeysInjector} * * @author Sergii Leschenko */ @Listeners(MockitoTestNGListener.class) public class KeysInjectorTest { private static final String MACHINE_ID = "machine123"; private static final String OWNER_ID = "user123"; private static final String CONTAINER_ID = "container123"; private static final String EXEC_ID = "exec123"; @Captor ArgumentCaptor<EventSubscriber<MachineStatusEvent>> subscriberCaptor; @Captor ArgumentCaptor<MessageProcessor<LogMessage>> messageProcessorCaptor; @Mock Instance instance; @Mock MachineMetadata metadata; @Mock Exec exec; @Mock LogMessage logMessage; @Mock LineConsumer lineConsumer; @Mock EventService eventService; @Mock DockerConnector docker; @Mock MachineManager machineManager; @Mock SshManager sshManager; EventSubscriber<MachineStatusEvent> subscriber; @InjectMocks KeysInjector keysInjector; @BeforeMethod public void setUp() throws Exception { final Map<String, String> metadataProperties = new HashMap<>(); metadataProperties.put("id", CONTAINER_ID); when(metadata.getProperties()).thenReturn(metadataProperties); when(machineManager.getMachine(MACHINE_ID)).thenReturn(instance); when(instance.getOwner()).thenReturn(OWNER_ID); when(instance.getMetadata()).thenReturn(metadata); when(instance.getLogger()).thenReturn(lineConsumer); keysInjector.start(); verify(eventService).subscribe(subscriberCaptor.capture()); subscriber = subscriberCaptor.getValue(); when(docker.createExec(anyString(), anyBoolean(), anyString())).thenReturn(exec); when(docker.createExec(anyString(), anyBoolean(), anyString(), anyString(), anyString())).thenReturn(exec); when(docker.createExec(anyString(), anyBoolean(), anyString())).thenReturn(exec); when(exec.getId()).thenReturn(EXEC_ID); } @Test public void shouldNotDoAnythingIfEventTypeDoesNotEqualToRunning() { subscriber.onEvent(newDto(MachineStatusEvent.class).withEventType(MachineStatusEvent.EventType.DESTROYING)); verifyZeroInteractions(docker, machineManager, sshManager); } @Test public void shouldNotInjectSshKeysWhenThereAreNotAnyPair() throws Exception { when(sshManager.getPairs(anyString(), anyString())).thenReturn(Collections.emptyList()); subscriber.onEvent(newDto(MachineStatusEvent.class).withEventType(MachineStatusEvent.EventType.RUNNING) .withMachineId(MACHINE_ID)); verify(machineManager).getMachine(eq(MACHINE_ID)); verify(sshManager).getPairs(eq(OWNER_ID), eq("machine")); verifyZeroInteractions(docker, machineManager, sshManager); } @Test public void shouldNotInjectSshKeysWhenThereAreNotAnyPairWithPublicKey() throws Exception { when(sshManager.getPairs(anyString(), anyString())) .thenReturn(Collections.singletonList(new SshPairImpl("machine", "myPair", null, null))); subscriber.onEvent(newDto(MachineStatusEvent.class).withEventType(MachineStatusEvent.EventType.RUNNING) .withMachineId(MACHINE_ID)); verify(machineManager).getMachine(eq(MACHINE_ID)); verify(sshManager).getPairs(eq(OWNER_ID), eq("machine")); verifyZeroInteractions(docker, machineManager, sshManager); } @Test public void shouldInjectSshKeysWhenThereAreAnyPairWithNotNullPublicKey() throws Exception { when(sshManager.getPairs(anyString(), anyString())) .thenReturn(Arrays.asList(new SshPairImpl("machine", "myPair", "publicKey1", null), new SshPairImpl("machine", "myPair", "publicKey2", null))); subscriber.onEvent(newDto(MachineStatusEvent.class).withEventType(MachineStatusEvent.EventType.RUNNING) .withMachineId(MACHINE_ID)); verify(machineManager).getMachine(eq(MACHINE_ID)); verify(sshManager).getPairs(eq(OWNER_ID), eq("machine")); verify(docker).createExec(anyString(), anyBoolean(), eq("/bin/bash"), eq("-c"), eq("mkdir ~/.ssh/ -p" + "&& echo 'publicKey1' >> ~/.ssh/authorized_keys" + "&& echo 'publicKey2' >> ~/.ssh/authorized_keys")); verify(docker).startExec(eq(EXEC_ID), anyObject()); verifyZeroInteractions(docker, machineManager, sshManager); } @Test public void shouldSendMessageInMachineLoggerWhenSomeErrorOcursOnKeysInjection() throws Exception { when(sshManager.getPairs(anyString(), anyString())) .thenReturn(Collections.singletonList(new SshPairImpl("machine", "myPair", "publicKey1", null))); when(logMessage.getType()).thenReturn(LogMessage.Type.STDERR); when(logMessage.getContent()).thenReturn("FAILED"); subscriber.onEvent(newDto(MachineStatusEvent.class).withEventType(MachineStatusEvent.EventType.RUNNING) .withMachineId(MACHINE_ID)); verify(docker).startExec(eq(EXEC_ID), messageProcessorCaptor.capture()); final MessageProcessor<LogMessage> value = messageProcessorCaptor.getValue(); value.process(logMessage); verify(lineConsumer).writeLine(eq("Error of injection public ssh keys. FAILED")); } }