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.

TelemetryDaemonTest.java 7.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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.telemetry;
  21. import java.io.IOException;
  22. import java.util.Collections;
  23. import org.junit.After;
  24. import org.junit.Rule;
  25. import org.junit.Test;
  26. import org.sonar.api.config.internal.MapSettings;
  27. import org.sonar.api.impl.utils.TestSystem2;
  28. import org.sonar.api.utils.log.LogTester;
  29. import org.sonar.api.utils.log.LoggerLevel;
  30. import org.sonar.api.utils.text.JsonWriter;
  31. import org.sonar.server.property.InternalProperties;
  32. import org.sonar.server.property.MapInternalProperties;
  33. import org.sonar.server.util.GlobalLockManager;
  34. import org.sonar.server.util.GlobalLockManagerImpl;
  35. import static org.assertj.core.api.Assertions.assertThat;
  36. import static org.mockito.ArgumentMatchers.any;
  37. import static org.mockito.ArgumentMatchers.anyInt;
  38. import static org.mockito.ArgumentMatchers.anyString;
  39. import static org.mockito.ArgumentMatchers.same;
  40. import static org.mockito.Mockito.after;
  41. import static org.mockito.Mockito.doAnswer;
  42. import static org.mockito.Mockito.mock;
  43. import static org.mockito.Mockito.never;
  44. import static org.mockito.Mockito.reset;
  45. import static org.mockito.Mockito.spy;
  46. import static org.mockito.Mockito.timeout;
  47. import static org.mockito.Mockito.verify;
  48. import static org.mockito.Mockito.when;
  49. import static org.sonar.api.utils.DateUtils.parseDate;
  50. import static org.sonar.process.ProcessProperties.Property.SONAR_TELEMETRY_ENABLE;
  51. import static org.sonar.process.ProcessProperties.Property.SONAR_TELEMETRY_FREQUENCY_IN_SECONDS;
  52. import static org.sonar.process.ProcessProperties.Property.SONAR_TELEMETRY_URL;
  53. public class TelemetryDaemonTest {
  54. @Rule
  55. public LogTester logger = new LogTester().setLevel(LoggerLevel.DEBUG);
  56. private static final long ONE_HOUR = 60 * 60 * 1_000L;
  57. private static final long ONE_DAY = 24 * ONE_HOUR;
  58. private static final TelemetryData SOME_TELEMETRY_DATA = TelemetryData.builder()
  59. .setServerId("foo")
  60. .setVersion("bar")
  61. .setPlugins(Collections.emptyMap())
  62. .setDatabase(new TelemetryData.Database("H2", "11"))
  63. .build();
  64. private final TelemetryClient client = mock(TelemetryClient.class);
  65. private final InternalProperties internalProperties = spy(new MapInternalProperties());
  66. private final GlobalLockManager lockManager = mock(GlobalLockManagerImpl.class);
  67. private final TestSystem2 system2 = new TestSystem2().setNow(System.currentTimeMillis());
  68. private final MapSettings settings = new MapSettings();
  69. private final TelemetryDataLoader dataLoader = mock(TelemetryDataLoader.class);
  70. private final TelemetryDataJsonWriter dataJsonWriter = mock(TelemetryDataJsonWriter.class);
  71. private final TelemetryDaemon underTest = new TelemetryDaemon(dataLoader, dataJsonWriter, client, settings.asConfig(), internalProperties, lockManager, system2);
  72. @After
  73. public void tearDown() {
  74. underTest.stop();
  75. }
  76. @Test
  77. public void send_data_via_client_at_startup_after_initial_delay() throws IOException {
  78. initTelemetrySettingsToDefaultValues();
  79. when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
  80. settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
  81. when(dataLoader.load()).thenReturn(SOME_TELEMETRY_DATA);
  82. mockDataJsonWriterDoingSomething();
  83. underTest.start();
  84. verify(client, timeout(2_000).atLeastOnce()).upload(anyString());
  85. verify(dataJsonWriter).writeTelemetryData(any(JsonWriter.class), same(SOME_TELEMETRY_DATA));
  86. }
  87. private void mockDataJsonWriterDoingSomething() {
  88. doAnswer(t -> {
  89. JsonWriter json = t.getArgument(0);
  90. json.beginObject().prop("foo", "bar").endObject();
  91. return null;
  92. })
  93. .when(dataJsonWriter)
  94. .writeTelemetryData(any(), any());
  95. }
  96. @Test
  97. public void check_if_should_send_data_periodically() throws IOException {
  98. initTelemetrySettingsToDefaultValues();
  99. when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
  100. long now = system2.now();
  101. long twentyHoursAgo = now - (ONE_HOUR * 20L);
  102. long oneDayAgo = now - ONE_DAY;
  103. internalProperties.write("telemetry.lastPing", String.valueOf(twentyHoursAgo));
  104. settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
  105. when(dataLoader.load()).thenReturn(SOME_TELEMETRY_DATA);
  106. mockDataJsonWriterDoingSomething();
  107. underTest.start();
  108. verify(dataJsonWriter, after(2_000).never()).writeTelemetryData(any(JsonWriter.class), same(SOME_TELEMETRY_DATA));
  109. verify(client, never()).upload(anyString());
  110. internalProperties.write("telemetry.lastPing", String.valueOf(oneDayAgo));
  111. verify(client, timeout(2_000)).upload(anyString());
  112. verify(dataJsonWriter).writeTelemetryData(any(JsonWriter.class), same(SOME_TELEMETRY_DATA));
  113. }
  114. @Test
  115. public void do_not_send_data_if_last_ping_earlier_than_one_day_ago() throws IOException {
  116. initTelemetrySettingsToDefaultValues();
  117. when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
  118. settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
  119. long now = system2.now();
  120. long twentyHoursAgo = now - (ONE_HOUR * 20L);
  121. mockDataJsonWriterDoingSomething();
  122. internalProperties.write("telemetry.lastPing", String.valueOf(twentyHoursAgo));
  123. underTest.start();
  124. verify(client, after(2_000).never()).upload(anyString());
  125. }
  126. @Test
  127. public void send_data_if_last_ping_is_over_one_day_ago() throws IOException {
  128. initTelemetrySettingsToDefaultValues();
  129. when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
  130. settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
  131. long today = parseDate("2017-08-01").getTime();
  132. system2.setNow(today);
  133. long oneDayAgo = today - ONE_DAY - ONE_HOUR;
  134. internalProperties.write("telemetry.lastPing", String.valueOf(oneDayAgo));
  135. reset(internalProperties);
  136. mockDataJsonWriterDoingSomething();
  137. underTest.start();
  138. verify(internalProperties, timeout(4_000)).write("telemetry.lastPing", String.valueOf(today));
  139. verify(client).upload(anyString());
  140. }
  141. @Test
  142. public void opt_out_sent_once() throws IOException {
  143. initTelemetrySettingsToDefaultValues();
  144. when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
  145. settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
  146. settings.setProperty("sonar.telemetry.enable", "false");
  147. mockDataJsonWriterDoingSomething();
  148. underTest.start();
  149. underTest.start();
  150. verify(client, after(2_000).never()).upload(anyString());
  151. verify(client, timeout(2_000).times(1)).optOut(anyString());
  152. assertThat(logger.logs(LoggerLevel.INFO)).contains("Sharing of SonarQube statistics is disabled.");
  153. }
  154. private void initTelemetrySettingsToDefaultValues() {
  155. settings.setProperty(SONAR_TELEMETRY_ENABLE.getKey(), SONAR_TELEMETRY_ENABLE.getDefaultValue());
  156. settings.setProperty(SONAR_TELEMETRY_URL.getKey(), SONAR_TELEMETRY_URL.getDefaultValue());
  157. settings.setProperty(SONAR_TELEMETRY_FREQUENCY_IN_SECONDS.getKey(), SONAR_TELEMETRY_FREQUENCY_IN_SECONDS.getDefaultValue());
  158. }
  159. }