/* * SonarQube * Copyright (C) 2009-2017 SonarSource SA * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonar.server.computation.task.step; import java.util.Arrays; import java.util.List; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.InOrder; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; import org.sonar.server.computation.task.ChangeLogLevel; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.mockito.Matchers.anyBoolean; 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 LogTester logTester = new LogTester(); @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() { new ComputationStepExecutor(mockComputationSteps(computationStep1, computationStep2, computationStep3)) .execute(); InOrder inOrder = inOrder(computationStep1, computationStep2, computationStep3); inOrder.verify(computationStep1).execute(); inOrder.verify(computationStep1).getDescription(); inOrder.verify(computationStep2).execute(); inOrder.verify(computationStep2).getDescription(); inOrder.verify(computationStep3).execute(); inOrder.verify(computationStep3).getDescription(); inOrder.verifyNoMoreInteractions(); } @Test public void execute_let_exception_thrown_by_ComputationStep_go_up_as_is() { String message = "Exception should go up"; ComputationStep computationStep = mockComputationStep("step1"); doThrow(new RuntimeException(message)) .when(computationStep) .execute(); ComputationStepExecutor computationStepExecutor = new ComputationStepExecutor(mockComputationSteps(computationStep)); expectedException.expect(RuntimeException.class); expectedException.expectMessage(message); computationStepExecutor.execute(); } @Test public void execute_does_not_log_end_timing_for_each_ComputationStep_called_when_level_is_INFO() { List<String> infoLogs = execute_logs_end_timing_for_each_ComputationStep_called_when_(LoggerLevel.INFO); assertThat(infoLogs).isEmpty(); } @Test public void execute_logs_end_timing_for_each_ComputationStep_called_when_level_is_DEBUG() { List<String> infoLogs = execute_logs_end_timing_for_each_ComputationStep_called_when_(LoggerLevel.DEBUG); assertThat(infoLogs).hasSize(2); assertThat(infoLogs.get(0)).contains("step1 | time="); assertThat(infoLogs.get(1)).contains("step2 | time="); } @Test public void execute_logs_end_timing_for_each_ComputationStep_called_when_level_is_TRACE() { List<String> infoLogs = execute_logs_end_timing_for_each_ComputationStep_called_when_(LoggerLevel.TRACE); assertThat(infoLogs).hasSize(2); assertThat(infoLogs.get(0)).contains("step1 | time="); assertThat(infoLogs.get(1)).contains("step2 | time="); } private List<String> execute_logs_end_timing_for_each_ComputationStep_called_when_(LoggerLevel level) { try (ChangeLogLevel executor = new ChangeLogLevel(ComputationStepExecutor.class, level); ChangeLogLevel step1 = new ChangeLogLevel(computationStep1.getClass(), level); ChangeLogLevel step2 = new ChangeLogLevel(computationStep2.getClass(), level)) { new ComputationStepExecutor(mockComputationSteps(computationStep1, computationStep2)) .execute(); return logTester.logs(LoggerLevel.DEBUG); } } @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); } } @Test public void execute_does_not_fail_if_listener_throws_Throwable() { ComputationStepExecutor.Listener listener = mock(ComputationStepExecutor.Listener.class); doThrow(new Error("Facking error thrown by Listener")) .when(listener) .finished(anyBoolean()); new ComputationStepExecutor(mockComputationSteps(computationStep1), listener).execute(); } private static ComputationSteps mockComputationSteps(ComputationStep... computationSteps) { ComputationSteps steps = mock(ComputationSteps.class); when(steps.instances()).thenReturn(Arrays.asList(computationSteps)); return steps; } private static ComputationStep mockComputationStep(String desc) { ComputationStep mock = mock(ComputationStep.class); when(mock.getDescription()).thenReturn(desc); return mock; } }