3 * Copyright (C) 2009-2023 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.project;
22 import com.tngtech.java.junit.dataprovider.DataProvider;
23 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
24 import com.tngtech.java.junit.dataprovider.UseDataProvider;
25 import java.util.Collections;
26 import java.util.Random;
28 import java.util.stream.Collectors;
29 import java.util.stream.IntStream;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.mockito.InOrder;
33 import org.mockito.Mockito;
35 import static java.util.Collections.singleton;
36 import static org.assertj.core.api.Assertions.assertThatCode;
37 import static org.assertj.core.api.Assertions.assertThatThrownBy;
38 import static org.mockito.ArgumentMatchers.any;
39 import static org.mockito.ArgumentMatchers.same;
40 import static org.mockito.Mockito.doThrow;
41 import static org.mockito.Mockito.mock;
42 import static org.mockito.Mockito.verifyNoInteractions;
43 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
45 @RunWith(DataProviderRunner.class)
46 public class ProjectLifeCycleListenersImplTest {
48 private final ProjectLifeCycleListener listener1 = mock(ProjectLifeCycleListener.class);
49 private final ProjectLifeCycleListener listener2 = mock(ProjectLifeCycleListener.class);
50 private final ProjectLifeCycleListener listener3 = mock(ProjectLifeCycleListener.class);
51 private final ProjectLifeCycleListenersImpl underTestNoListeners = new ProjectLifeCycleListenersImpl();
52 private final ProjectLifeCycleListenersImpl underTestWithListeners = new ProjectLifeCycleListenersImpl(
53 new ProjectLifeCycleListener[] {listener1, listener2, listener3});
56 public void onProjectsDeleted_throws_NPE_if_set_is_null() {
57 assertThatThrownBy(() -> underTestWithListeners.onProjectsDeleted(null))
58 .isInstanceOf(NullPointerException.class)
59 .hasMessage("projects can't be null");
63 public void onProjectsDeleted_throws_NPE_if_set_is_null_even_if_no_listeners() {
64 assertThatThrownBy(() -> underTestNoListeners.onProjectsDeleted(null))
65 .isInstanceOf(NullPointerException.class)
66 .hasMessage("projects can't be null");
70 public void onProjectsDeleted_has_no_effect_if_set_is_empty() {
71 underTestNoListeners.onProjectsDeleted(Collections.emptySet());
73 underTestWithListeners.onProjectsDeleted(Collections.emptySet());
74 verifyNoInteractions(listener1, listener2, listener3);
78 @UseDataProvider("oneOrManyDeletedProjects")
79 public void onProjectsDeleted_does_not_fail_if_there_is_no_listener(Set<DeletedProject> projects) {
80 assertThatCode(() -> underTestNoListeners.onProjectsDeleted(projects)).doesNotThrowAnyException();
84 @UseDataProvider("oneOrManyDeletedProjects")
85 public void onProjectsDeleted_calls_all_listeners_in_order_of_addition_to_constructor(Set<DeletedProject> projects) {
86 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
88 underTestWithListeners.onProjectsDeleted(projects);
90 inOrder.verify(listener1).onProjectsDeleted(same(projects));
91 inOrder.verify(listener2).onProjectsDeleted(same(projects));
92 inOrder.verify(listener3).onProjectsDeleted(same(projects));
93 inOrder.verifyNoMoreInteractions();
97 @UseDataProvider("oneOrManyDeletedProjects")
98 public void onProjectsDeleted_calls_all_listeners_even_if_one_throws_an_Exception(Set<DeletedProject> projects) {
99 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
100 doThrow(new RuntimeException("Faking listener2 throwing an exception"))
102 .onProjectsDeleted(any());
104 underTestWithListeners.onProjectsDeleted(projects);
106 inOrder.verify(listener1).onProjectsDeleted(same(projects));
107 inOrder.verify(listener2).onProjectsDeleted(same(projects));
108 inOrder.verify(listener3).onProjectsDeleted(same(projects));
109 inOrder.verifyNoMoreInteractions();
113 @UseDataProvider("oneOrManyDeletedProjects")
114 public void onProjectsDeleted_calls_all_listeners_even_if_one_throws_an_Error(Set<DeletedProject> projects) {
115 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
116 doThrow(new Error("Faking listener2 throwing an Error"))
118 .onProjectsDeleted(any());
120 underTestWithListeners.onProjectsDeleted(projects);
122 inOrder.verify(listener1).onProjectsDeleted(same(projects));
123 inOrder.verify(listener2).onProjectsDeleted(same(projects));
124 inOrder.verify(listener3).onProjectsDeleted(same(projects));
125 inOrder.verifyNoMoreInteractions();
129 public void onProjectBranchesDeleted_throws_NPE_if_set_is_null() {
130 assertThatThrownBy(() -> underTestWithListeners.onProjectBranchesDeleted(null))
131 .isInstanceOf(NullPointerException.class)
132 .hasMessage("projects can't be null");
136 public void onProjectBranchesDeleted_throws_NPE_if_set_is_null_even_if_no_listeners() {
137 assertThatThrownBy(() -> underTestNoListeners.onProjectBranchesDeleted(null))
138 .isInstanceOf(NullPointerException.class)
139 .hasMessage("projects can't be null");
143 public void onProjectBranchesDeleted_has_no_effect_if_set_is_empty() {
144 underTestNoListeners.onProjectBranchesDeleted(Collections.emptySet());
146 underTestWithListeners.onProjectBranchesDeleted(Collections.emptySet());
147 verifyNoInteractions(listener1, listener2, listener3);
151 @UseDataProvider("oneOrManyProjects")
152 public void onProjectBranchesDeleted_does_not_fail_if_there_is_no_listener(Set<Project> projects) {
153 underTestNoListeners.onProjectBranchesDeleted(projects);
157 @UseDataProvider("oneOrManyProjects")
158 public void onProjectBranchesDeleted_calls_all_listeners_in_order_of_addition_to_constructor(Set<Project> projects) {
159 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
161 underTestWithListeners.onProjectBranchesDeleted(projects);
163 inOrder.verify(listener1).onProjectBranchesDeleted(same(projects));
164 inOrder.verify(listener2).onProjectBranchesDeleted(same(projects));
165 inOrder.verify(listener3).onProjectBranchesDeleted(same(projects));
166 inOrder.verifyNoMoreInteractions();
170 @UseDataProvider("oneOrManyProjects")
171 public void onProjectBranchesDeleted_calls_all_listeners_even_if_one_throws_an_Exception(Set<Project> projects) {
172 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
173 doThrow(new RuntimeException("Faking listener2 throwing an exception"))
175 .onProjectBranchesDeleted(any());
177 underTestWithListeners.onProjectBranchesDeleted(projects);
179 inOrder.verify(listener1).onProjectBranchesDeleted(same(projects));
180 inOrder.verify(listener2).onProjectBranchesDeleted(same(projects));
181 inOrder.verify(listener3).onProjectBranchesDeleted(same(projects));
182 inOrder.verifyNoMoreInteractions();
186 @UseDataProvider("oneOrManyProjects")
187 public void onProjectBranchesDeleted_calls_all_listeners_even_if_one_throws_an_Error(Set<Project> projects) {
188 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
189 doThrow(new Error("Faking listener2 throwing an Error"))
191 .onProjectBranchesDeleted(any());
193 underTestWithListeners.onProjectBranchesDeleted(projects);
195 inOrder.verify(listener1).onProjectBranchesDeleted(same(projects));
196 inOrder.verify(listener2).onProjectBranchesDeleted(same(projects));
197 inOrder.verify(listener3).onProjectBranchesDeleted(same(projects));
198 inOrder.verifyNoMoreInteractions();
202 public static Object[][] oneOrManyProjects() {
203 return new Object[][] {
204 {singleton(newUniqueProject())},
205 {IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> newUniqueProject()).collect(Collectors.toSet())}
210 public static Object[][] oneOrManyDeletedProjects() {
211 return new Object[][] {
212 {singleton(newUniqueProject())},
213 {IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> new DeletedProject(newUniqueProject(), "branch_" + i))
214 .collect(Collectors.toSet())}
220 public void onProjectsRekeyed_throws_NPE_if_set_is_null() {
221 assertThatThrownBy(() -> underTestWithListeners.onProjectsRekeyed(null))
222 .isInstanceOf(NullPointerException.class)
223 .hasMessage("rekeyedProjects can't be null");
227 public void onProjectsRekeyed_throws_NPE_if_set_is_null_even_if_no_listeners() {
228 assertThatThrownBy(() -> underTestNoListeners.onProjectsRekeyed(null))
229 .isInstanceOf(NullPointerException.class)
230 .hasMessage("rekeyedProjects can't be null");
234 public void onProjectsRekeyed_has_no_effect_if_set_is_empty() {
235 underTestNoListeners.onProjectsRekeyed(Collections.emptySet());
237 underTestWithListeners.onProjectsRekeyed(Collections.emptySet());
238 verifyNoInteractions(listener1, listener2, listener3);
242 @UseDataProvider("oneOrManyRekeyedProjects")
243 public void onProjectsRekeyed_does_not_fail_if_there_is_no_listener(Set<RekeyedProject> projects) {
244 underTestNoListeners.onProjectsRekeyed(projects);
248 @UseDataProvider("oneOrManyRekeyedProjects")
249 public void onProjectsRekeyed_calls_all_listeners_in_order_of_addition_to_constructor(Set<RekeyedProject> projects) {
250 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
252 underTestWithListeners.onProjectsRekeyed(projects);
254 inOrder.verify(listener1).onProjectsRekeyed(same(projects));
255 inOrder.verify(listener2).onProjectsRekeyed(same(projects));
256 inOrder.verify(listener3).onProjectsRekeyed(same(projects));
257 inOrder.verifyNoMoreInteractions();
261 @UseDataProvider("oneOrManyRekeyedProjects")
262 public void onProjectsRekeyed_calls_all_listeners_even_if_one_throws_an_Exception(Set<RekeyedProject> projects) {
263 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
264 doThrow(new RuntimeException("Faking listener2 throwing an exception"))
266 .onProjectsRekeyed(any());
268 underTestWithListeners.onProjectsRekeyed(projects);
270 inOrder.verify(listener1).onProjectsRekeyed(same(projects));
271 inOrder.verify(listener2).onProjectsRekeyed(same(projects));
272 inOrder.verify(listener3).onProjectsRekeyed(same(projects));
273 inOrder.verifyNoMoreInteractions();
277 @UseDataProvider("oneOrManyRekeyedProjects")
278 public void onProjectsRekeyed_calls_all_listeners_even_if_one_throws_an_Error(Set<RekeyedProject> projects) {
279 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
280 doThrow(new Error("Faking listener2 throwing an Error"))
282 .onProjectsRekeyed(any());
284 underTestWithListeners.onProjectsRekeyed(projects);
286 inOrder.verify(listener1).onProjectsRekeyed(same(projects));
287 inOrder.verify(listener2).onProjectsRekeyed(same(projects));
288 inOrder.verify(listener3).onProjectsRekeyed(same(projects));
289 inOrder.verifyNoMoreInteractions();
293 public static Object[][] oneOrManyRekeyedProjects() {
294 return new Object[][] {
295 {singleton(newUniqueRekeyedProject())},
296 {IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> newUniqueRekeyedProject()).collect(Collectors.toSet())}
300 private static Project newUniqueProject() {
301 return Project.from(newPrivateProjectDto());
304 private static int counter = 3_989;
306 private static RekeyedProject newUniqueRekeyedProject() {
307 int base = counter++;
308 Project project = Project.from(newPrivateProjectDto());
309 return new RekeyedProject(project, base + "_old_key");