package uk.ac.ox.zoo.seeg.abraid.mp.modelwrapper.model; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import uk.ac.ox.zoo.seeg.abraid.mp.common.domain.ModelRunStatus; import uk.ac.ox.zoo.seeg.abraid.mp.modelwrapper.config.run.RunConfiguration; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Future; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; /** * Tests for ModelRunnerAsyncWrapperImpl. * Copyright (c) 2014 University of Oxford */ public class ModelRunnerAsyncWrapperTest { @Test public void startModelTriggersAModelRun() throws Exception { // Arrange RunConfiguration expectedRunConfig = mock(RunConfiguration.class); ModelStatusReporter expectedModelStatusReporter = mock(ModelStatusReporter.class); ModelProcessHandler expectedResult = mock(ModelProcessHandler.class); ModelRunner mockModelRunner = mock(ModelRunner.class); when(mockModelRunner.runModel(expectedRunConfig, expectedModelStatusReporter)).thenReturn(expectedResult); ModelRunnerAsyncWrapper target = new ModelRunnerAsyncWrapperImpl(mockModelRunner); // Act Future<ModelProcessHandler> future = target.startModel(expectedRunConfig, expectedModelStatusReporter); // At this stage ModelRunner.runModel may or may not have been called yet (threads) // Future.get allows use to wait for the model run thread to complete and get the result ModelProcessHandler result = future.get(); // Assert assertThat(result).isSameAs(expectedResult); verify(mockModelRunner).runModel(expectedRunConfig, expectedModelStatusReporter); } @Test public void startModelReportsErrorsDuringModelSetup() throws Exception { // Arrange ModelStatusReporter mockModelStatusReporter = mock(ModelStatusReporter.class); ModelRunner mockModelRunner = mock(ModelRunner.class); when(mockModelRunner.runModel(any(RunConfiguration.class), any(ModelStatusReporter.class))) .thenThrow(new IOException("message")); ModelRunnerAsyncWrapper target = new ModelRunnerAsyncWrapperImpl(mockModelRunner); // Act Future<ModelProcessHandler> future = target.startModel( mock(RunConfiguration.class), mockModelStatusReporter); future.get(); // Assert verify(mockModelStatusReporter).report(ModelRunStatus.FAILED, "", "Model setup failed: java.io.IOException: message"); } private List<String> actions = new ArrayList<>(); private boolean pauseModelRun = true; private boolean readyToAssert = false; @Test public void startModelDoesNotTriggerASecondModelRunUntilTheFirstHasCompleted() throws Exception { // Arrange actions.clear(); ModelStatusReporter expectedModelStatusReporter = mock(ModelStatusReporter.class); final RunConfiguration firstExpectedRunConfig = mock(RunConfiguration.class); final ModelProcessHandler firstExpectedHandler = mock(ModelProcessHandler.class); final RunConfiguration secondExpectedRunConfig = mock(RunConfiguration.class); final ModelProcessHandler secondExpectedHandler = mock(ModelProcessHandler.class); ModelRunner mockModelRunner = mock(ModelRunner.class); when(mockModelRunner.runModel(firstExpectedRunConfig, expectedModelStatusReporter)).thenAnswer( new Answer<ModelProcessHandler>() { @Override public ModelProcessHandler answer(InvocationOnMock invocationOnMock) throws Throwable { actions.add("first run started"); return firstExpectedHandler; } }); when(firstExpectedHandler.waitForCompletion()).thenAnswer(new Answer<Integer>() { @Override public Integer answer(InvocationOnMock invocationOnMock) throws Throwable { actions.add("first run paused"); readyToAssert = true; while (pauseModelRun) { Thread.sleep(1); } actions.add("first run completed"); return 0; } }); when(mockModelRunner.runModel(secondExpectedRunConfig, expectedModelStatusReporter)).thenAnswer( new Answer<ModelProcessHandler>() { @Override public ModelProcessHandler answer(InvocationOnMock invocationOnMock) throws Throwable { actions.add("second run started"); return secondExpectedHandler; } }); when(secondExpectedHandler.waitForCompletion()).thenAnswer(new Answer<Integer>() { @Override public Integer answer(InvocationOnMock invocationOnMock) throws Throwable { actions.add("second run completed"); return 0; } }); ModelRunnerAsyncWrapper target = new ModelRunnerAsyncWrapperImpl(mockModelRunner); // Act actions.add("first run triggered"); Future<ModelProcessHandler> future1 = target.startModel(firstExpectedRunConfig, expectedModelStatusReporter); actions.add("second run triggered"); Future<ModelProcessHandler> future2 = target.startModel(secondExpectedRunConfig, expectedModelStatusReporter); // Assert while (!readyToAssert) { Thread.sleep(1); } assertThat(actions).containsOnly("first run triggered", "second run triggered", "first run started", "first run paused"); pauseModelRun = false; future1.get(); future2.get(); assertThat(actions).containsSequence("first run completed", "second run started", "second run completed"); } }