/* * Copyright Siemens AG, 2015. Part of the SW360 Portal Project. * * 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 */ package org.eclipse.sw360.fossology.ssh; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.Session; import org.eclipse.sw360.datahandler.thrift.SW360Exception; import org.eclipse.sw360.fossology.config.FossologySettings; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.runners.MockitoJUnitRunner; import org.mockito.stubbing.Answer; import java.io.InputStream; import java.io.OutputStream; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) public class FossologySshConnectorTest { FossologySshConnector fossologySshConnector; @Mock private FossologySettings fossologySettings; @Mock private JSchSessionProvider jSchSessionProvider; @Mock private Session session; @Mock private ChannelExec channel; @Rule public ExpectedException expectedException = ExpectedException.none(); private int connectionTimeout = 10000; private long executionTimeout = 203004; @Before public void setUp() throws Exception { when(jSchSessionProvider.getSession(connectionTimeout)).thenReturn(session); when(session.openChannel(eq("exec"))).thenReturn(channel); when(channel.isConnected()).thenReturn(true); when(session.isConnected()).thenReturn(true); when(fossologySettings.getFossologyConnectionTimeout()).thenReturn(connectionTimeout); when(fossologySettings.getFossologyExecutionTimeout()).thenReturn(executionTimeout); fossologySshConnector = new FossologySshConnector(jSchSessionProvider, fossologySettings); fossologySshConnector = spy(fossologySshConnector); doNothing().when(fossologySshConnector).waitCompletion(channel, executionTimeout); } @After public void tearDown() { verify(fossologySettings).getFossologyConnectionTimeout(); verify(fossologySettings).getFossologyExecutionTimeout(); verifyNoMoreInteractions(jSchSessionProvider, fossologySettings); } @Test public void testRunInFossologyViaSsh() throws Exception { final int exitCode = fossologySshConnector.runInFossologyViaSsh("cmd"); assertThat(exitCode, greaterThanOrEqualTo(0)); verify(jSchSessionProvider).getSession(connectionTimeout); verify(jSchSessionProvider, atLeastOnce()).closeSession(session); // isConnected is mocked: it is disconnected twice verify(channel, atLeastOnce()).disconnect(); // isConnected is mocked: it is disconnected twice } @Test public void testRunInFossologyViaSsh1() throws Exception { InputStream stdin = mock(InputStream.class); final int exitCode = fossologySshConnector.runInFossologyViaSsh("cmd", stdin); assertThat(exitCode, greaterThanOrEqualTo(0)); verify(jSchSessionProvider).getSession(connectionTimeout); verify(jSchSessionProvider, atLeastOnce()).closeSession(any(Session.class)); // isConnected is mocked: it is disconnected twice verify(channel, atLeastOnce()).disconnect(); // isConnected is mocked: it is disconnected twice } @Test public void testRunInFossologyViaSsh2() throws Exception { InputStream stdin = mock(InputStream.class); OutputStream stdout = mock(OutputStream.class); final int exitCode = fossologySshConnector.runInFossologyViaSsh("cmd", stdin, stdout); assertThat(exitCode, greaterThanOrEqualTo(0)); verify(jSchSessionProvider).getSession(connectionTimeout); verify(channel, atLeastOnce()).disconnect(); // isConnected is mocked: it is disconnected twice verify(jSchSessionProvider, atLeastOnce()).closeSession(session); // isConnected is mocked: it is disconnected twice } @Test public void testRunInFossologyViaSsh3() throws Exception { OutputStream stdout = mock(OutputStream.class); doAnswer(new Answer<Integer>() { @Override public Integer answer(InvocationOnMock invocation) throws Throwable { final Object[] arguments = invocation.getArguments(); final InputStream inputStream = (InputStream) arguments[1]; assertThat(inputStream.read(), is(-1)); return 1; } }).when(fossologySshConnector).runInFossologyViaSsh(anyString(), any(InputStream.class), any(OutputStream.class)); final int exitCode = fossologySshConnector.runInFossologyViaSsh("cmd", stdout); assertThat(exitCode, greaterThanOrEqualTo(0)); verify(fossologySshConnector).runInFossologyViaSsh(eq("cmd"), any(InputStream.class), eq(stdout)); } @Test public void testRunInFossologyViaSshReturnErrorOnTimeout() throws Exception { doThrow(new SW360Exception()).when(fossologySshConnector).waitCompletion(channel, executionTimeout); final int exitCode = fossologySshConnector.runInFossologyViaSsh("cmd"); assertThat(exitCode, lessThan(0)); verify(jSchSessionProvider).getSession(connectionTimeout); verify(jSchSessionProvider).getServerString(); verify(channel, atLeastOnce()).disconnect(); // isConnected is mocked: it is disconnected twice verify(jSchSessionProvider, atLeastOnce()).closeSession(session); // isConnected is mocked: it is disconnected twice } @Test public void testWaitCompletion() throws SW360Exception { executionTimeout = 100; doCallRealMethod().when(fossologySshConnector).waitCompletion(channel, executionTimeout); // reset spy when(channel.isClosed()).thenReturn(true); fossologySshConnector.waitCompletion(channel, executionTimeout); } @Test public void testWaitCompletionThrowsOnTimeout() throws SW360Exception { executionTimeout = 100; doCallRealMethod().when(fossologySshConnector).waitCompletion(channel, executionTimeout); // reset spy expectedException.expect(SW360Exception.class); when(channel.isClosed()).thenReturn(false); fossologySshConnector.waitCompletion(channel, executionTimeout); } }