]> source.dussan.org Git - sonarqube.git/blob
78b85cd5d637971e7c5cbecefa2cac46b00ce525
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2022 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.platform.serverid;
21
22 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
23 import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
24 import org.junit.After;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.junit.runner.RunWith;
28 import org.sonar.api.CoreProperties;
29 import org.sonar.api.SonarEdition;
30 import org.sonar.api.SonarQubeSide;
31 import org.sonar.api.internal.SonarRuntimeImpl;
32 import org.sonar.api.utils.System2;
33 import org.sonar.api.utils.Version;
34 import org.sonar.core.platform.ServerId;
35 import org.sonar.db.DbClient;
36 import org.sonar.db.DbSession;
37 import org.sonar.db.DbTester;
38 import org.sonar.db.property.PropertyDto;
39 import org.sonar.server.platform.WebServer;
40 import org.sonar.server.property.InternalProperties;
41
42 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
43 import static org.assertj.core.api.Assertions.assertThat;
44 import static org.assertj.core.api.Assertions.assertThatThrownBy;
45 import static org.assertj.core.api.Assertions.fail;
46 import static org.mockito.ArgumentMatchers.any;
47 import static org.mockito.Mockito.mock;
48 import static org.mockito.Mockito.verify;
49 import static org.mockito.Mockito.when;
50 import static org.sonar.api.SonarQubeSide.COMPUTE_ENGINE;
51 import static org.sonar.api.SonarQubeSide.SERVER;
52 import static org.sonar.core.platform.ServerId.DATABASE_ID_LENGTH;
53 import static org.sonar.core.platform.ServerId.NOT_UUID_DATASET_ID_LENGTH;
54 import static org.sonar.core.platform.ServerId.UUID_DATASET_ID_LENGTH;
55
56 @RunWith(DataProviderRunner.class)
57 public class ServerIdManagerTest {
58
59   private static final ServerId WITH_DATABASE_ID_SERVER_ID = ServerId.of(randomAlphanumeric(DATABASE_ID_LENGTH), randomAlphanumeric(NOT_UUID_DATASET_ID_LENGTH));
60   private static final String CHECKSUM_1 = randomAlphanumeric(12);
61
62   @Rule
63   public final DbTester dbTester = DbTester.create(System2.INSTANCE);
64
65   private final ServerIdChecksum serverIdChecksum = mock(ServerIdChecksum.class);
66   private final ServerIdFactory serverIdFactory = mock(ServerIdFactory.class);
67   private final DbClient dbClient = dbTester.getDbClient();
68   private final DbSession dbSession = dbTester.getSession();
69   private final WebServer webServer = mock(WebServer.class);
70   private ServerIdManager underTest;
71
72   @After
73   public void tearDown() {
74     if (underTest != null) {
75       underTest.stop();
76     }
77   }
78
79   @Test
80   public void web_leader_persists_new_server_id_if_missing() {
81     mockCreateNewServerId();
82     mockChecksumOf(WITH_DATABASE_ID_SERVER_ID, CHECKSUM_1);
83     when(webServer.isStartupLeader()).thenReturn(true);
84
85     test(SERVER);
86
87     verifyDb(CHECKSUM_1);
88     verifyCreateNewServerIdFromScratch();
89   }
90
91   @Test
92   public void web_leader_persists_new_server_id_if_value_is_empty() {
93     insertServerId("");
94     mockCreateNewServerId();
95     mockChecksumOf(WITH_DATABASE_ID_SERVER_ID, CHECKSUM_1);
96     when(webServer.isStartupLeader()).thenReturn(true);
97
98     test(SERVER);
99
100     verifyDb(CHECKSUM_1);
101     verifyCreateNewServerIdFromScratch();
102   }
103
104   @Test
105   public void web_leader_keeps_existing_server_id_if_valid() {
106     insertServerId(WITH_DATABASE_ID_SERVER_ID);
107     insertChecksum(CHECKSUM_1);
108     mockChecksumOf(WITH_DATABASE_ID_SERVER_ID, CHECKSUM_1);
109     when(webServer.isStartupLeader()).thenReturn(true);
110
111     test(SERVER);
112
113     verifyDb(CHECKSUM_1);
114   }
115
116   @Test
117   public void web_leader_creates_server_id_from_current_serverId_with_databaseId_if_checksum_fails() {
118     ServerId currentServerId = ServerId.of(randomAlphanumeric(DATABASE_ID_LENGTH), randomAlphanumeric(UUID_DATASET_ID_LENGTH));
119     insertServerId(currentServerId);
120     insertChecksum("does_not_match_WITH_DATABASE_ID_SERVER_ID");
121     mockChecksumOf(currentServerId, "matches_WITH_DATABASE_ID_SERVER_ID");
122     mockCreateNewServerIdFrom(currentServerId);
123     mockChecksumOf(WITH_DATABASE_ID_SERVER_ID, CHECKSUM_1);
124     when(webServer.isStartupLeader()).thenReturn(true);
125
126     test(SERVER);
127
128     verifyDb(CHECKSUM_1);
129     verifyCreateNewServerIdFrom(currentServerId);
130   }
131
132   @Test
133   public void web_leader_generates_missing_checksum_for_current_serverId_with_databaseId() {
134     insertServerId(WITH_DATABASE_ID_SERVER_ID);
135     mockChecksumOf(WITH_DATABASE_ID_SERVER_ID, CHECKSUM_1);
136     when(webServer.isStartupLeader()).thenReturn(true);
137
138     test(SERVER);
139
140     verifyDb(CHECKSUM_1);
141   }
142
143   @Test
144   public void web_follower_does_not_fail_if_server_id_matches_checksum() {
145     insertServerId(WITH_DATABASE_ID_SERVER_ID);
146     insertChecksum(CHECKSUM_1);
147     mockChecksumOf(WITH_DATABASE_ID_SERVER_ID, CHECKSUM_1);
148     when(webServer.isStartupLeader()).thenReturn(false);
149
150     test(SERVER);
151
152     // no changes
153     verifyDb(CHECKSUM_1);
154   }
155
156   @Test
157   public void web_follower_fails_if_server_id_is_missing() {
158     when(webServer.isStartupLeader()).thenReturn(false);
159
160     expectMissingServerIdException(() -> test(SERVER));
161   }
162
163   @Test
164   public void web_follower_fails_if_server_id_is_empty() {
165     insertServerId("");
166     when(webServer.isStartupLeader()).thenReturn(false);
167
168     expectEmptyServerIdException(() -> test(SERVER));
169   }
170
171   @Test
172   public void web_follower_fails_if_checksum_does_not_match() {
173     String dbChecksum = "boom";
174     insertServerId(WITH_DATABASE_ID_SERVER_ID);
175     insertChecksum(dbChecksum);
176     mockChecksumOf(WITH_DATABASE_ID_SERVER_ID, CHECKSUM_1);
177     when(webServer.isStartupLeader()).thenReturn(false);
178
179     try {
180       test(SERVER);
181       fail("An ISE should have been raised");
182     } catch (IllegalStateException e) {
183       assertThat(e.getMessage()).isEqualTo("Server ID is invalid");
184       // no changes
185       verifyDb(dbChecksum);
186     }
187   }
188
189   @Test
190   public void compute_engine_does_not_fail_if_server_id_is_valid() {
191     insertServerId(WITH_DATABASE_ID_SERVER_ID);
192     insertChecksum(CHECKSUM_1);
193     mockChecksumOf(WITH_DATABASE_ID_SERVER_ID, CHECKSUM_1);
194
195     test(COMPUTE_ENGINE);
196
197     // no changes
198     verifyDb(CHECKSUM_1);
199   }
200
201   @Test
202   public void compute_engine_fails_if_server_id_is_missing() {
203     expectMissingServerIdException(() -> test(COMPUTE_ENGINE));
204   }
205
206   @Test
207   public void compute_engine_fails_if_server_id_is_empty() {
208     insertServerId("");
209
210     expectEmptyServerIdException(() -> test(COMPUTE_ENGINE));
211   }
212
213   @Test
214   public void compute_engine_fails_if_server_id_is_invalid() {
215     String dbChecksum = "boom";
216     insertServerId(WITH_DATABASE_ID_SERVER_ID);
217     insertChecksum(dbChecksum);
218     mockChecksumOf(WITH_DATABASE_ID_SERVER_ID, CHECKSUM_1);
219
220     try {
221       test(SERVER);
222       fail("An ISE should have been raised");
223     } catch (IllegalStateException e) {
224       assertThat(e.getMessage()).isEqualTo("Server ID is invalid");
225       // no changes
226       verifyDb(dbChecksum);
227     }
228   }
229
230   private void expectEmptyServerIdException(ThrowingCallable callback) {
231     assertThatThrownBy(callback)
232       .isInstanceOf(IllegalStateException.class)
233       .hasMessage("Property sonar.core.id is empty in database");
234   }
235
236   private void expectMissingServerIdException(ThrowingCallable callback) {
237     assertThatThrownBy(callback)
238       .isInstanceOf(IllegalStateException.class)
239       .hasMessage("Property sonar.core.id is missing in database");
240   }
241
242   private void verifyDb(String expectedChecksum) {
243     assertThat(dbClient.propertiesDao().selectGlobalProperty(dbSession, CoreProperties.SERVER_ID))
244       .extracting(PropertyDto::getValue)
245       .isEqualTo(ServerIdManagerTest.WITH_DATABASE_ID_SERVER_ID.toString());
246     assertThat(dbClient.internalPropertiesDao().selectByKey(dbSession, InternalProperties.SERVER_ID_CHECKSUM))
247       .hasValue(expectedChecksum);
248   }
249
250   private void mockCreateNewServerId() {
251     when(serverIdFactory.create()).thenReturn(WITH_DATABASE_ID_SERVER_ID);
252     when(serverIdFactory.create(any())).thenThrow(new IllegalStateException("new ServerId should not be created from current server id"));
253   }
254
255   private void mockCreateNewServerIdFrom(ServerId currentServerId) {
256     when(serverIdFactory.create()).thenThrow(new IllegalStateException("new ServerId should be created from current server id"));
257     when(serverIdFactory.create(currentServerId)).thenReturn(ServerIdManagerTest.WITH_DATABASE_ID_SERVER_ID);
258   }
259
260   private void verifyCreateNewServerIdFromScratch() {
261     verify(serverIdFactory).create();
262   }
263
264   private void verifyCreateNewServerIdFrom(ServerId currentServerId) {
265     verify(serverIdFactory).create(currentServerId);
266   }
267
268   private void mockChecksumOf(ServerId serverId, String checksum1) {
269     when(serverIdChecksum.computeFor(serverId.toString())).thenReturn(checksum1);
270   }
271
272   private void insertServerId(ServerId serverId) {
273     insertServerId(serverId.toString());
274   }
275
276   private void insertServerId(String serverId) {
277     dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto().setKey(CoreProperties.SERVER_ID).setValue(serverId),
278       null, null, null, null);
279     dbSession.commit();
280   }
281
282   private void insertChecksum(String value) {
283     dbClient.internalPropertiesDao().save(dbSession, InternalProperties.SERVER_ID_CHECKSUM, value);
284     dbSession.commit();
285   }
286
287   private void test(SonarQubeSide side) {
288     underTest = new ServerIdManager(serverIdChecksum, serverIdFactory, dbClient, SonarRuntimeImpl
289       .forSonarQube(Version.create(6, 7), side, SonarEdition.COMMUNITY), webServer);
290     underTest.start();
291   }
292 }