*/
package org.sonar.server.computation.step;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.util.logs.Profiler;
private static final Logger LOGGER = Loggers.get(ComputationStepExecutor.class);
private final ComputationSteps steps;
+ @CheckForNull
+ private final Listener listener;
+ /**
+ * Used when no {@link org.sonar.server.computation.step.ComputationStepExecutor.Listener} is available in pico
+ * container.
+ */
public ComputationStepExecutor(ComputationSteps steps) {
+ this(steps, null);
+ }
+
+ public ComputationStepExecutor(ComputationSteps steps, @Nullable Listener listener) {
this.steps = steps;
+ this.listener = listener;
}
public void execute() {
Profiler stepProfiler = Profiler.create(LOGGER);
+ boolean allStepsExecuted = false;
+ try {
+ executeSteps(stepProfiler);
+ allStepsExecuted = true;
+ } finally {
+ if (listener != null) {
+ listener.finished(allStepsExecuted);
+ }
+ }
+ }
+
+ private void executeSteps(Profiler stepProfiler) {
for (ComputationStep step : steps.instances()) {
stepProfiler.start();
step.execute();
stepProfiler.stopInfo(step.getDescription());
}
}
+
+ public interface Listener {
+ void finished(boolean allStepsExecuted);
+ }
}
import org.sonar.api.utils.log.LoggerLevel;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
public class ComputationStepExecutorTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
+ private final ComputationStepExecutor.Listener listener = mock(ComputationStepExecutor.Listener.class);
+ private final ComputationStep computationStep1 = mockComputationStep("step1");
+ private final ComputationStep computationStep2 = mockComputationStep("step2");
+ private final ComputationStep computationStep3 = mockComputationStep("step3");
+
@Test
public void execute_call_execute_on_each_ComputationStep_in_order_returned_by_instances_method() {
- ComputationStep computationStep1 = mockComputationStep("step1");
- ComputationStep computationStep2 = mockComputationStep("step2");
- ComputationStep computationStep3 = mockComputationStep("step3");
-
new ComputationStepExecutor(mockComputationSteps(computationStep1, computationStep2, computationStep3))
.execute();
@Test
public void execute_logs_end_timing_for_each_ComputationStep_called() {
- ComputationStep computationStep1 = mockComputationStep("step1");
- ComputationStep computationStep2 = mockComputationStep("step2");
-
new ComputationStepExecutor(mockComputationSteps(computationStep1, computationStep2))
.execute();
assertThat(infoLogs.get(1)).contains("step2 | time=");
}
+ @Test
+ public void execute_calls_listener_finished_method_with_all_step_runs() {
+ new ComputationStepExecutor(mockComputationSteps(computationStep1, computationStep2), listener)
+ .execute();
+
+ verify(listener).finished(true);
+ verifyNoMoreInteractions(listener);
+ }
+
+ @Test
+ public void execute_calls_listener_finished_method_even_if_a_step_throws_an_exception() {
+ RuntimeException toBeThrown = new RuntimeException("simulating failing execute Step method");
+ doThrow(toBeThrown)
+ .when(computationStep1)
+ .execute();
+
+ try {
+ new ComputationStepExecutor(mockComputationSteps(computationStep1, computationStep2), listener)
+ .execute();
+ fail("exception toBeThrown should have been raised");
+ } catch (RuntimeException e) {
+ assertThat(e).isSameAs(toBeThrown);
+ verify(listener).finished(false);
+ verifyNoMoreInteractions(listener);
+ }
+
+ }
+
private static ComputationSteps mockComputationSteps(ComputationStep... computationSteps) {
ComputationSteps steps = mock(ComputationSteps.class);
when(steps.instances()).thenReturn(Arrays.asList(computationSteps));