You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ServerIdManagerTest.java 12KB

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