/* * R Service Bus * * Copyright (c) Copyright of Open Analytics NV, 2010-2015 * * =========================================================================== * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.openanalytics.rsb.component; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Calendar; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.junit.Before; import org.junit.Test; 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 org.springframework.context.MessageSource; import de.walware.rj.data.RObject; import de.walware.rj.data.defaultImpl.RCharacterDataImpl; import de.walware.rj.data.defaultImpl.RVectorImpl; import de.walware.rj.servi.RServi; import de.walware.rj.services.FunctionCall; import eu.openanalytics.rsb.config.Configuration; import eu.openanalytics.rsb.message.AbstractFunctionCallJob; import eu.openanalytics.rsb.message.AbstractFunctionCallResult; import eu.openanalytics.rsb.message.AbstractResult; import eu.openanalytics.rsb.message.MessageDispatcher; import eu.openanalytics.rsb.message.MultiFilesJob; import eu.openanalytics.rsb.message.MultiFilesResult; import eu.openanalytics.rsb.rservi.RServiInstanceProvider; import eu.openanalytics.rsb.rservi.RServiInstanceProvider.PoolingStrategy; import eu.openanalytics.rsb.rservi.RServiUriSelector; import eu.openanalytics.rsb.stats.JobStatisticsHandler; /** * @author "OpenAnalytics <rsb.development@openanalytics.eu>" */ @RunWith(MockitoJUnitRunner.class) public class JobProcessorTestCase { private JobProcessor jobProcessor; @Mock private Configuration configuration; @Mock private MessageDispatcher messageDispatcher; @Mock private RServiInstanceProvider rServiInstanceProvider; @Mock private JobStatisticsHandler jobStatisticsHandler; @Mock private RServiUriSelector rServiUriSelector; @Before public void prepareTest() throws URISyntaxException { jobProcessor = new JobProcessor(); jobProcessor.setConfiguration(configuration); jobProcessor.setMessageDispatcher(messageDispatcher); jobProcessor.setRServiUriSelector(rServiUriSelector); jobProcessor.setRServiInstanceProvider(rServiInstanceProvider); jobProcessor.setJobStatisticsHandler(jobStatisticsHandler); when(rServiUriSelector.getUriForApplication(anyString())).thenReturn(new URI("fake://default")); } @Test(expected = RuntimeException.class) public void processFunctionCallJobRserviProviderError() throws Exception { when( rServiInstanceProvider.getRServiInstance(anyString(), anyString(), eq(PoolingStrategy.IF_POSSIBLE))).thenThrow( new RuntimeException("simulated RServi provider issue")); jobProcessor.process(mock(AbstractFunctionCallJob.class)); } @Test public void processRserviError() throws Exception { final URI defaultPoolUri = new URI("fake://default"); when(configuration.getDefaultRserviPoolUri()).thenReturn(defaultPoolUri); final RServi rServi = mock(RServi.class); when( rServiInstanceProvider.getRServiInstance(anyString(), anyString(), eq(PoolingStrategy.IF_POSSIBLE))).thenReturn(rServi); final Throwable exception = new RuntimeException("simulated RServi issue"); when(rServi.createFunctionCall(anyString())).thenThrow(exception); final AbstractFunctionCallJob job = mock(AbstractFunctionCallJob.class); @SuppressWarnings("unchecked") final AbstractResult<Object> result = mock(AbstractResult.class); when(job.buildErrorResult(eq(exception), any(MessageSource.class))).thenAnswer(new Answer<Object>() { @Override public Object answer(final InvocationOnMock invocation) throws Throwable { return result; } }); jobProcessor.process(job); verify(messageDispatcher).dispatch(eq(result)); } @Test public void processDirect() throws Exception { final URI defaultPoolUri = new URI("fake://default"); final AbstractFunctionCallJob job = setupMocksForProcessingFunctionCallJob(defaultPoolUri); final AbstractFunctionCallResult result = setupResultMockForFunctionCallJob(job); final AbstractFunctionCallResult processDirectResult = (AbstractFunctionCallResult) jobProcessor.processDirect(job); verify(jobStatisticsHandler).storeJobStatistics(eq(job), any(Calendar.class), anyLong(), eq(defaultPoolUri.toString())); verifyZeroInteractions(messageDispatcher); assertThat(processDirectResult, is(result)); } @Test public void processFunctionCallJob() throws Exception { final URI defaultPoolUri = new URI("fake://default"); final AbstractFunctionCallJob job = setupMocksForProcessingFunctionCallJob(defaultPoolUri); final AbstractFunctionCallResult result = setupResultMockForFunctionCallJob(job); jobProcessor.process(job); verify(jobStatisticsHandler).storeJobStatistics(eq(job), any(Calendar.class), anyLong(), eq(defaultPoolUri.toString())); verify(messageDispatcher).dispatch(eq(result)); } @Test public void processMultiFilesJobNoRScript() throws Exception { final URI defaultPoolUri = new URI("fake://default"); when(configuration.getDefaultRserviPoolUri()).thenReturn(defaultPoolUri); final RServi rServi = mock(RServi.class); when(rServiInstanceProvider.getRServiInstance(anyString(), anyString(), eq(PoolingStrategy.NEVER))).thenReturn( rServi); final MultiFilesJob job = mock(MultiFilesJob.class); final MultiFilesResult result = mock(MultiFilesResult.class); when(job.buildErrorResult(any(IllegalArgumentException.class), any(MessageSource.class))).thenReturn( result); jobProcessor.process(job); verify(messageDispatcher).dispatch(eq(result)); } @Test public void processMultiFilesJob() throws Exception { final URI defaultPoolUri = new URI("fake://default"); when(configuration.getDefaultRserviPoolUri()).thenReturn(defaultPoolUri); final RServi rServi = mock(RServi.class); when(rServiInstanceProvider.getRServiInstance(anyString(), anyString(), eq(PoolingStrategy.NEVER))).thenReturn( rServi); final FunctionCall functionCall = mock(FunctionCall.class); when(rServi.createFunctionCall(anyString())).thenReturn(functionCall); final RObject rObject = new RVectorImpl<RCharacterDataImpl>(new RCharacterDataImpl(new String[0])); when(rServi.evalData(anyString(), (IProgressMonitor) isNull())).thenReturn(rObject); final MultiFilesJob job = mock(MultiFilesJob.class); final File scriptFile = File.createTempFile("rsb", "test"); scriptFile.deleteOnExit(); when(job.getRScriptFile()).thenReturn(scriptFile); when(job.getFiles()).thenReturn(new File[]{scriptFile}); final MultiFilesResult result = mock(MultiFilesResult.class); when(job.buildSuccessResult()).thenReturn(result); jobProcessor.process(job); verify(jobStatisticsHandler).storeJobStatistics(eq(job), any(Calendar.class), anyLong(), eq(defaultPoolUri.toString())); verify(messageDispatcher).dispatch(eq(result)); } private AbstractFunctionCallResult setupResultMockForFunctionCallJob(final AbstractFunctionCallJob job) throws IOException { final AbstractFunctionCallResult result = mock(AbstractFunctionCallResult.class); when(job.buildSuccessResult("fake_result")).thenReturn(result); return result; } private AbstractFunctionCallJob setupMocksForProcessingFunctionCallJob(final URI defaultPoolUri) throws Exception, CoreException, IOException { when(configuration.getDefaultRserviPoolUri()).thenReturn(defaultPoolUri); final RServi rServi = mock(RServi.class); when( rServiInstanceProvider.getRServiInstance(anyString(), anyString(), eq(PoolingStrategy.IF_POSSIBLE))).thenReturn(rServi); final FunctionCall functionCall = mock(FunctionCall.class); when(rServi.createFunctionCall(anyString())).thenReturn(functionCall); final RObject rObject = new RVectorImpl<RCharacterDataImpl>(new RCharacterDataImpl( new String[]{"fake_result"})); when(functionCall.evalData(null)).thenReturn(rObject); final AbstractFunctionCallJob job = mock(AbstractFunctionCallJob.class); return job; } }