package com.constellio.data.threads; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicBoolean; import org.joda.time.Duration; import org.joda.time.LocalDateTime; import org.joda.time.LocalTime; import org.junit.Before; import org.junit.Test; import org.mockito.InOrder; import org.mockito.Mock; import com.constellio.data.dao.services.factories.DataLayerFactory; import com.constellio.sdk.tests.ConstellioTest; public class BackgroundThreadCommandUnitTest extends ConstellioTest { @Mock DataLayerFactory dataLayerFactory; AtomicBoolean systemStarted = new AtomicBoolean(true); AtomicBoolean stopRequested = new AtomicBoolean(false); TestRunnable nestedCommand; String zeId = "zeId"; BackgroundThreadConfiguration configuration; BackgroundThreadCommand command; @Before public void setUp() throws Exception { nestedCommand = spy(new TestRunnable()); configuration = spy( BackgroundThreadConfiguration.repeatingAction(zeId, nestedCommand).executedEvery(Duration.standardSeconds(42))); command = spy( new BackgroundThreadCommand(configuration, systemStarted, stopRequested, new Semaphore(10), dataLayerFactory)); } @Test public void givenNoTimeIntervalWhenRunningThenLogAndRunNestedCommand() throws Exception { doNothing().when(command).runAndHandleException(); command.run(); verify(command).runAndHandleException(); } @Test public void givenInsideTimeIntervalWhenRunningThenLogAndRunNestedCommand() throws Exception { configuration.between(new LocalTime(11, 45, 00), new LocalTime(12, 45, 00)); givenTimeIs(new LocalDateTime(2010, 02, 02, 11, 45, 01)); doNothing().when(command).runAndHandleException(); command.run(); verify(command).runAndHandleException(); } @Test public void givenBeforeTimeIntervalWhenRunningThenLogAndRunNestedCommand() throws Exception { configuration.between(new LocalTime(11, 45, 00), new LocalTime(12, 45, 00)); givenTimeIs(new LocalDateTime(2010, 02, 02, 11, 44, 59)); doNothing().when(command).runAndHandleException(); command.run(); verify(command, never()).runAndHandleException(); } @Test public void givenAfterTimeIntervalWhenRunningThenLogAndRunNestedCommand() throws Exception { configuration.between(new LocalTime(11, 45, 00), new LocalTime(12, 45, 00)); givenTimeIs(new LocalDateTime(2010, 02, 02, 12, 45, 01)); doNothing().when(command).runAndHandleException(); command.run(); verify(command, never()).runAndHandleException(); } @Test public void givenInsideTimeIntervalOnTwoDayWhenRunningThenLogAndRunNestedCommand() throws Exception { configuration.between(new LocalTime(20, 45, 00), new LocalTime(2, 45, 00)); givenTimeIs(new LocalDateTime(2010, 02, 02, 20, 45, 01)); doNothing().when(command).runAndHandleException(); command.run(); verify(command).runAndHandleException(); } @Test public void givenBeforeTimeIntervalOnTwoDayWhenRunningThenLogAndRunNestedCommand() throws Exception { configuration.between(new LocalTime(20, 45, 00), new LocalTime(2, 45, 00)); givenTimeIs(new LocalDateTime(2010, 02, 02, 20, 44, 59)); doNothing().when(command).runAndHandleException(); command.run(); verify(command, never()).runAndHandleException(); } @Test public void givenAfterTimeIntervalOnTwoDayWhenRunningThenLogAndRunNestedCommand() throws Exception { configuration.between(new LocalTime(20, 45, 00), new LocalTime(2, 45, 00)); givenTimeIs(new LocalDateTime(2010, 02, 02, 2, 45, 01)); doNothing().when(command).runAndHandleException(); command.run(); verify(command, never()).runAndHandleException(); } @Test public void whenRunHandlingExceptionThenLogAndSetThreadName() throws Exception { String threadName = zeId + " (" + TestRunnable.class.getName() + ")"; command.run(); InOrder inOrder = inOrder(command, nestedCommand); inOrder.verify(command).setCurrentThreadName(); //inOrder.verify(command).logCommandCall(); inOrder.verify(nestedCommand).run(); //inOrder.verify(command).logCommandCallEnd(); } @Test public void givenStoppingOnExceptionWhenAnExceptionOccurThenLogAndRethrow() throws Exception { configuration.handlingExceptionWith(BackgroundThreadExceptionHandling.STOP); RuntimeException e = new RuntimeException(); doThrow(e).when(nestedCommand).run(); try { command.run(); fail("Exception expected"); } catch (RuntimeException e2) { assertThat(e2).isEqualTo(e); } String threadName = zeId + " (" + TestRunnable.class.getName() + ")"; InOrder inOrder = inOrder(command, nestedCommand); inOrder.verify(command).setCurrentThreadName(); //inOrder.verify(command).logCommandCall(); inOrder.verify(nestedCommand).run(); inOrder.verify(command).logCommandCallEndedWithException(e); } @Test public void givenContinuingOnExceptionWhenAnExceptionOccurThenLogAndReturnNormally() throws Exception { configuration.handlingExceptionWith(BackgroundThreadExceptionHandling.CONTINUE); RuntimeException e = new RuntimeException(); doThrow(e).when(nestedCommand).run(); command.run(); String threadName = zeId + " (" + TestRunnable.class.getName() + ")"; InOrder inOrder = inOrder(command, nestedCommand); inOrder.verify(command).setCurrentThreadName(); //inOrder.verify(command).logCommandCall(); inOrder.verify(nestedCommand).run(); inOrder.verify(command).logCommandCallEndedWithException(e); } public static class TestRunnable implements Runnable { @Override public void run() { } } }