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.IntStream;
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 import org.mockito.InOrder;
32 import org.mockito.Mockito;
33 import org.sonar.core.util.stream.MoreCollectors;
35 import static java.util.Collections.singleton;
36 import static org.mockito.ArgumentMatchers.any;
37 import static org.mockito.ArgumentMatchers.same;
38 import static org.mockito.Mockito.doThrow;
39 import static org.mockito.Mockito.mock;
40 import static org.mockito.Mockito.verifyNoInteractions;
41 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
42 import static org.assertj.core.api.Assertions.assertThatThrownBy;
44 @RunWith(DataProviderRunner.class)
45 public class ProjectLifeCycleListenersImplTest {
47 private final ProjectLifeCycleListener listener1 = mock(ProjectLifeCycleListener.class);
48 private final ProjectLifeCycleListener listener2 = mock(ProjectLifeCycleListener.class);
49 private final ProjectLifeCycleListener listener3 = mock(ProjectLifeCycleListener.class);
50 private final ProjectLifeCycleListenersImpl underTestNoListeners = new ProjectLifeCycleListenersImpl();
51 private final ProjectLifeCycleListenersImpl underTestWithListeners = new ProjectLifeCycleListenersImpl(
52 new ProjectLifeCycleListener[] {listener1, listener2, listener3});
55 public void onProjectsDeleted_throws_NPE_if_set_is_null() {
56 assertThatThrownBy(() -> underTestWithListeners.onProjectsDeleted(null))
57 .isInstanceOf(NullPointerException.class)
58 .hasMessage("projects can't be null");
62 public void onProjectsDeleted_throws_NPE_if_set_is_null_even_if_no_listeners() {
63 assertThatThrownBy(() -> underTestNoListeners.onProjectsDeleted(null))
64 .isInstanceOf(NullPointerException.class)
65 .hasMessage("projects can't be null");
69 public void onProjectsDeleted_has_no_effect_if_set_is_empty() {
70 underTestNoListeners.onProjectsDeleted(Collections.emptySet());
72 underTestWithListeners.onProjectsDeleted(Collections.emptySet());
73 verifyNoInteractions(listener1, listener2, listener3);
77 @UseDataProvider("oneOrManyProjects")
78 public void onProjectsDeleted_does_not_fail_if_there_is_no_listener(Set<Project> projects) {
79 underTestNoListeners.onProjectsDeleted(projects);
83 @UseDataProvider("oneOrManyProjects")
84 public void onProjectsDeleted_calls_all_listeners_in_order_of_addition_to_constructor(Set<Project> projects) {
85 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
87 underTestWithListeners.onProjectsDeleted(projects);
89 inOrder.verify(listener1).onProjectsDeleted(same(projects));
90 inOrder.verify(listener2).onProjectsDeleted(same(projects));
91 inOrder.verify(listener3).onProjectsDeleted(same(projects));
92 inOrder.verifyNoMoreInteractions();
96 @UseDataProvider("oneOrManyProjects")
97 public void onProjectsDeleted_calls_all_listeners_even_if_one_throws_an_Exception(Set<Project> projects) {
98 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
99 doThrow(new RuntimeException("Faking listener2 throwing an exception"))
101 .onProjectsDeleted(any());
103 underTestWithListeners.onProjectsDeleted(projects);
105 inOrder.verify(listener1).onProjectsDeleted(same(projects));
106 inOrder.verify(listener2).onProjectsDeleted(same(projects));
107 inOrder.verify(listener3).onProjectsDeleted(same(projects));
108 inOrder.verifyNoMoreInteractions();
112 @UseDataProvider("oneOrManyProjects")
113 public void onProjectsDeleted_calls_all_listeners_even_if_one_throws_an_Error(Set<Project> projects) {
114 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
115 doThrow(new Error("Faking listener2 throwing an Error"))
117 .onProjectsDeleted(any());
119 underTestWithListeners.onProjectsDeleted(projects);
121 inOrder.verify(listener1).onProjectsDeleted(same(projects));
122 inOrder.verify(listener2).onProjectsDeleted(same(projects));
123 inOrder.verify(listener3).onProjectsDeleted(same(projects));
124 inOrder.verifyNoMoreInteractions();
128 public void onProjectBranchesDeleted_throws_NPE_if_set_is_null() {
129 assertThatThrownBy(() -> underTestWithListeners.onProjectBranchesDeleted(null))
130 .isInstanceOf(NullPointerException.class)
131 .hasMessage("projects can't be null");
135 public void onProjectBranchesDeleted_throws_NPE_if_set_is_null_even_if_no_listeners() {
136 assertThatThrownBy(() -> underTestNoListeners.onProjectBranchesDeleted(null))
137 .isInstanceOf(NullPointerException.class)
138 .hasMessage("projects can't be null");
142 public void onProjectBranchesDeleted_has_no_effect_if_set_is_empty() {
143 underTestNoListeners.onProjectBranchesDeleted(Collections.emptySet());
145 underTestWithListeners.onProjectBranchesDeleted(Collections.emptySet());
146 verifyNoInteractions(listener1, listener2, listener3);
150 @UseDataProvider("oneOrManyProjects")
151 public void onProjectBranchesDeleted_does_not_fail_if_there_is_no_listener(Set<Project> projects) {
152 underTestNoListeners.onProjectBranchesDeleted(projects);
156 @UseDataProvider("oneOrManyProjects")
157 public void onProjectBranchesDeleted_calls_all_listeners_in_order_of_addition_to_constructor(Set<Project> projects) {
158 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
160 underTestWithListeners.onProjectBranchesDeleted(projects);
162 inOrder.verify(listener1).onProjectBranchesDeleted(same(projects));
163 inOrder.verify(listener2).onProjectBranchesDeleted(same(projects));
164 inOrder.verify(listener3).onProjectBranchesDeleted(same(projects));
165 inOrder.verifyNoMoreInteractions();
169 @UseDataProvider("oneOrManyProjects")
170 public void onProjectBranchesDeleted_calls_all_listeners_even_if_one_throws_an_Exception(Set<Project> projects) {
171 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
172 doThrow(new RuntimeException("Faking listener2 throwing an exception"))
174 .onProjectBranchesDeleted(any());
176 underTestWithListeners.onProjectBranchesDeleted(projects);
178 inOrder.verify(listener1).onProjectBranchesDeleted(same(projects));
179 inOrder.verify(listener2).onProjectBranchesDeleted(same(projects));
180 inOrder.verify(listener3).onProjectBranchesDeleted(same(projects));
181 inOrder.verifyNoMoreInteractions();
185 @UseDataProvider("oneOrManyProjects")
186 public void onProjectBranchesDeleted_calls_all_listeners_even_if_one_throws_an_Error(Set<Project> projects) {
187 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
188 doThrow(new Error("Faking listener2 throwing an Error"))
190 .onProjectBranchesDeleted(any());
192 underTestWithListeners.onProjectBranchesDeleted(projects);
194 inOrder.verify(listener1).onProjectBranchesDeleted(same(projects));
195 inOrder.verify(listener2).onProjectBranchesDeleted(same(projects));
196 inOrder.verify(listener3).onProjectBranchesDeleted(same(projects));
197 inOrder.verifyNoMoreInteractions();
201 public static Object[][] oneOrManyProjects() {
202 return new Object[][] {
203 {singleton(newUniqueProject())},
204 {IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> newUniqueProject()).collect(MoreCollectors.toSet())}
210 public void onProjectsRekeyed_throws_NPE_if_set_is_null() {
211 assertThatThrownBy(() -> underTestWithListeners.onProjectsRekeyed(null))
212 .isInstanceOf(NullPointerException.class)
213 .hasMessage("rekeyedProjects can't be null");
217 public void onProjectsRekeyed_throws_NPE_if_set_is_null_even_if_no_listeners() {
218 assertThatThrownBy(() -> underTestNoListeners.onProjectsRekeyed(null))
219 .isInstanceOf(NullPointerException.class)
220 .hasMessage("rekeyedProjects can't be null");
224 public void onProjectsRekeyed_has_no_effect_if_set_is_empty() {
225 underTestNoListeners.onProjectsRekeyed(Collections.emptySet());
227 underTestWithListeners.onProjectsRekeyed(Collections.emptySet());
228 verifyNoInteractions(listener1, listener2, listener3);
232 @UseDataProvider("oneOrManyRekeyedProjects")
233 public void onProjectsRekeyed_does_not_fail_if_there_is_no_listener(Set<RekeyedProject> projects) {
234 underTestNoListeners.onProjectsRekeyed(projects);
238 @UseDataProvider("oneOrManyRekeyedProjects")
239 public void onProjectsRekeyed_calls_all_listeners_in_order_of_addition_to_constructor(Set<RekeyedProject> projects) {
240 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
242 underTestWithListeners.onProjectsRekeyed(projects);
244 inOrder.verify(listener1).onProjectsRekeyed(same(projects));
245 inOrder.verify(listener2).onProjectsRekeyed(same(projects));
246 inOrder.verify(listener3).onProjectsRekeyed(same(projects));
247 inOrder.verifyNoMoreInteractions();
251 @UseDataProvider("oneOrManyRekeyedProjects")
252 public void onProjectsRekeyed_calls_all_listeners_even_if_one_throws_an_Exception(Set<RekeyedProject> projects) {
253 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
254 doThrow(new RuntimeException("Faking listener2 throwing an exception"))
256 .onProjectsRekeyed(any());
258 underTestWithListeners.onProjectsRekeyed(projects);
260 inOrder.verify(listener1).onProjectsRekeyed(same(projects));
261 inOrder.verify(listener2).onProjectsRekeyed(same(projects));
262 inOrder.verify(listener3).onProjectsRekeyed(same(projects));
263 inOrder.verifyNoMoreInteractions();
267 @UseDataProvider("oneOrManyRekeyedProjects")
268 public void onProjectsRekeyed_calls_all_listeners_even_if_one_throws_an_Error(Set<RekeyedProject> projects) {
269 InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
270 doThrow(new Error("Faking listener2 throwing an Error"))
272 .onProjectsRekeyed(any());
274 underTestWithListeners.onProjectsRekeyed(projects);
276 inOrder.verify(listener1).onProjectsRekeyed(same(projects));
277 inOrder.verify(listener2).onProjectsRekeyed(same(projects));
278 inOrder.verify(listener3).onProjectsRekeyed(same(projects));
279 inOrder.verifyNoMoreInteractions();
283 public static Object[][] oneOrManyRekeyedProjects() {
284 return new Object[][] {
285 {singleton(newUniqueRekeyedProject())},
286 {IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> newUniqueRekeyedProject()).collect(MoreCollectors.toSet())}
290 private static Project newUniqueProject() {
291 return Project.from(newPrivateProjectDto());
294 private static int counter = 3_989;
296 private static RekeyedProject newUniqueRekeyedProject() {
297 int base = counter++;
298 Project project = Project.from(newPrivateProjectDto());
299 return new RekeyedProject(project, base + "_old_key");