makes tests more unique by moving much logic out TelemetryDaemonTest which will make this test faster (less tests) and more reliable (simpler)
as this test was troublesom because if was testing multithreaded code
return this;
}
- public void setProjectCountByLanguage(Map<String, Long> projectCountByLanguage) {
+ public Builder setProjectCountByLanguage(Map<String, Long> projectCountByLanguage) {
this.projectCountByLanguage = projectCountByLanguage;
+ return this;
}
public Builder setNclocByLanguage(Map<String, Long> nclocByLanguage) {
import java.util.Map;
import java.util.Optional;
+import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.core.platform.EditionProvider;
import org.sonar.server.measure.index.ProjectMeasuresStatistics;
private final Database database;
private final Map<String, Long> projectCountByLanguage;
private final Map<String, Long> nclocByLanguage;
- private final Optional<EditionProvider.Edition> edition;
+ @CheckForNull
+ private final EditionProvider.Edition edition;
private final String licenseType;
private final Long installationDate;
private final String installationVersion;
}
public Optional<EditionProvider.Edition> getEdition() {
- return edition;
+ return Optional.ofNullable(edition);
}
public Optional<String> getLicenseType() {
private ProjectMeasuresStatistics projectMeasuresStatistics;
private Long ncloc;
private Boolean usingBranches;
- private Optional<EditionProvider.Edition> edition;
+ private EditionProvider.Edition edition;
private String licenseType;
private Long installationDate;
private String installationVersion;
return this;
}
- public Builder setEdition(Optional<EditionProvider.Edition> edition) {
+ public Builder setEdition(@Nullable EditionProvider.Edition edition) {
this.edition = edition;
return this;
}
requireNonNull(ncloc);
requireNonNull(database);
requireNonNull(usingBranches);
- requireNonNull(edition);
return new TelemetryData(this);
}
import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
public class TelemetryDataJsonWriter {
- private TelemetryDataJsonWriter() {
- // static methods
- }
- public static void writeTelemetryData(JsonWriter json, TelemetryData statistics) {
+ public void writeTelemetryData(JsonWriter json, TelemetryData statistics) {
json.beginObject();
json.prop("id", statistics.getServerId());
json.prop("version", statistics.getVersion());
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.telemetry;
+
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+import java.util.stream.IntStream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.core.platform.EditionProvider;
+import org.sonar.core.util.stream.MoreCollectors;
+import org.sonar.server.measure.index.ProjectMeasuresStatistics;
+
+import static java.util.stream.Collectors.joining;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.test.JsonAssert.assertJson;
+
+@RunWith(DataProviderRunner.class)
+public class TelemetryDataJsonWriterTest {
+
+ private static final TelemetryData.Builder SOME_TELEMETRY_DATA = TelemetryData.builder()
+ .setServerId("foo")
+ .setVersion("bar")
+ .setPlugins(Collections.emptyMap())
+ .setProjectMeasuresStatistics(ProjectMeasuresStatistics.builder()
+ .setProjectCount(12)
+ .setProjectCountByLanguage(Collections.emptyMap())
+ .setNclocByLanguage(Collections.emptyMap())
+ .build())
+ .setNcloc(42L)
+ .setDatabase(new TelemetryData.Database("H2", "11"))
+ .setUsingBranches(true);
+
+ private final Random random = new Random();
+
+ private final TelemetryDataJsonWriter underTest = new TelemetryDataJsonWriter();
+
+ @Test
+ public void write_server_id_and_version() {
+ TelemetryData data = SOME_TELEMETRY_DATA.build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"id\": \"" + data.getServerId() + "\"," +
+ " \"version\": \"" + data.getVersion() + "\"" +
+ "}");
+ }
+
+ @Test
+ public void does_not_write_edition_if_null() {
+ TelemetryData data = SOME_TELEMETRY_DATA.build();
+
+ String json = writeTelemetryData(data);
+
+ assertThat(json).doesNotContain("edition");
+ }
+
+ @Test
+ @UseDataProvider("allEditions")
+ public void writes_edition_if_non_null(EditionProvider.Edition edition) {
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setEdition(edition)
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"edition\": \"" + edition.name().toLowerCase(Locale.ENGLISH) + "\"" +
+ "}");
+ }
+
+ @Test
+ public void does_not_write_license_type_if_null() {
+ TelemetryData data = SOME_TELEMETRY_DATA.build();
+
+ String json = writeTelemetryData(data);
+
+ assertThat(json).doesNotContain("licenseType");
+ }
+
+ @Test
+ public void writes_licenseType_if_non_null() {
+ String expected = randomAlphabetic(12);
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setLicenseType(expected)
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"licenseType\": \"" + expected + "\"" +
+ "}");
+ }
+
+ @Test
+ public void writes_database() {
+ String name = randomAlphabetic(12);
+ String version = randomAlphabetic(10);
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setDatabase(new TelemetryData.Database(name, version))
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"database\": {" +
+ " \"name\": \"" + name + "\"," +
+ " \"version\": \"" + version + "\"" +
+ " }" +
+ "}");
+ }
+
+ @Test
+ public void writes_no_plugins() {
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setPlugins(Collections.emptyMap())
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"plugins\": []" +
+ "}");
+ }
+
+ @Test
+ public void writes_all_plugins() {
+ Map<String, String> plugins = IntStream.range(0, 1 + random.nextInt(10))
+ .boxed()
+ .collect(MoreCollectors.uniqueIndex(i -> "P" + i, i -> "V" + i));
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setPlugins(plugins)
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"plugins\": " +
+ "[" +
+ plugins.entrySet().stream().map(e -> "{\"name\":\"" + e.getKey() + "\",\"version\":\"" + e.getValue() + "\"}").collect(joining(",")) +
+ "]" +
+ "}");
+ }
+
+ @Test
+ public void write_user_count() {
+ int userCount = random.nextInt(590);
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setUserCount(userCount)
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"userCount\": " + userCount +
+ "}");
+ }
+
+ @Test
+ public void write_project_count_and_ncloc_and_no_stat_by_language() {
+ int projectCount = random.nextInt(8909);
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setProjectMeasuresStatistics(ProjectMeasuresStatistics.builder()
+ .setProjectCount(projectCount)
+ .setProjectCountByLanguage(Collections.emptyMap())
+ .setNclocByLanguage(Collections.emptyMap())
+ .build())
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"projectCount\": " + projectCount + "," +
+ " \"projectCountByLanguage\": []," +
+ " \"nclocByLanguage\": []" +
+ "}");
+ }
+
+ @Test
+ public void write_project_stats_by_language() {
+ int projectCount = random.nextInt(8909);
+ Map<String, Long> countByLanguage = IntStream.range(0, 1 + random.nextInt(10))
+ .boxed()
+ .collect(MoreCollectors.uniqueIndex(i -> "P" + i, i -> 100L + i));
+ Map<String, Long> nclocByLanguage = IntStream.range(0, 1 + random.nextInt(10))
+ .boxed()
+ .collect(MoreCollectors.uniqueIndex(i -> "P" + i, i -> 1_000L + i));
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setProjectMeasuresStatistics(ProjectMeasuresStatistics.builder()
+ .setProjectCount(projectCount)
+ .setProjectCountByLanguage(countByLanguage)
+ .setNclocByLanguage(nclocByLanguage)
+ .build())
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"projectCount\": " + projectCount + "," +
+ " \"projectCountByLanguage\": " +
+ "[" +
+ countByLanguage.entrySet().stream().map(e -> "{\"language\":\"" + e.getKey() + "\",\"count\":" + e.getValue() + "}").collect(joining()) +
+ "]," +
+ " \"nclocByLanguage\": " +
+ "[" +
+ nclocByLanguage.entrySet().stream().map(e -> "{\"language\":\"" + e.getKey() + "\",\"ncloc\":" + e.getValue() + "}").collect(joining()) +
+ "]" +
+ "}");
+ }
+
+ @Test
+ public void does_not_write_installation_date_if_null() {
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setInstallationDate(null)
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertThat(json).doesNotContain("installationDate");
+ }
+
+ @Test
+ public void write_installation_date() {
+ long installationDate = random.nextInt(590);
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setInstallationDate(installationDate)
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"installationDate\": " + installationDate +
+ "}");
+ }
+
+ @Test
+ public void does_not_write_installation_version_if_null() {
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setInstallationVersion(null)
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertThat(json).doesNotContain("installationVersion");
+ }
+
+ @Test
+ public void write_installation_version() {
+ String installationVersion = randomAlphabetic(5);
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setInstallationVersion(installationVersion)
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"installationVersion\":\"" + installationVersion + "\"" +
+ "}");
+ }
+
+ @Test
+ public void write_docker_flag() {
+ boolean inDocker = random.nextBoolean();
+ TelemetryData data = SOME_TELEMETRY_DATA
+ .setInDocker(inDocker)
+ .build();
+
+ String json = writeTelemetryData(data);
+
+ assertJson(json).isSimilarTo("{" +
+ " \"docker\":" + inDocker +
+ "}");
+ }
+
+ @DataProvider
+ public static Object[][] allEditions() {
+ return Arrays.stream(EditionProvider.Edition.values())
+ .map(t -> new Object[] {t})
+ .toArray(Object[][]::new);
+ }
+
+ private String writeTelemetryData(TelemetryData data) {
+ StringWriter jsonString = new StringWriter();
+ try (JsonWriter json = JsonWriter.of(jsonString)) {
+ underTest.writeTelemetryData(json, data);
+ }
+ return jsonString.toString();
+ }
+}
import org.sonar.process.systeminfo.SystemInfoUtils;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import org.sonar.server.health.Health;
+import org.sonar.server.telemetry.TelemetryDataJsonWriter;
import org.sonar.server.telemetry.TelemetryDataLoader;
-import static org.sonar.server.telemetry.TelemetryDataJsonWriter.writeTelemetryData;
-
public abstract class AbstractSystemInfoWriter implements SystemInfoWriter {
private static final String[] ORDERED_SECTION_NAMES = {
// standalone
"Search State", "Search Indexes"};
private final TelemetryDataLoader telemetry;
+ private final TelemetryDataJsonWriter dataJsonWriter;
- AbstractSystemInfoWriter(TelemetryDataLoader telemetry) {
+ AbstractSystemInfoWriter(TelemetryDataLoader telemetry, TelemetryDataJsonWriter dataJsonWriter) {
this.telemetry = telemetry;
+ this.dataJsonWriter = dataJsonWriter;
}
protected void writeSections(Collection<ProtobufSystemInfo.Section> sections, JsonWriter json) {
protected void writeTelemetry(JsonWriter json) {
json.name("Statistics");
- writeTelemetryData(json, telemetry.load());
+ dataJsonWriter.writeTelemetryData(json, telemetry.load());
}
}
import org.sonar.server.platform.monitoring.cluster.GlobalInfoLoader;
import org.sonar.server.platform.monitoring.cluster.NodeInfo;
import org.sonar.server.platform.monitoring.cluster.SearchNodesInfoLoader;
+import org.sonar.server.telemetry.TelemetryDataJsonWriter;
import org.sonar.server.telemetry.TelemetryDataLoader;
public class ClusterSystemInfoWriter extends AbstractSystemInfoWriter {
private final HealthChecker healthChecker;
public ClusterSystemInfoWriter(GlobalInfoLoader globalInfoLoader, AppNodesInfoLoader appNodesInfoLoader, SearchNodesInfoLoader searchNodesInfoLoader,
- HealthChecker healthChecker, TelemetryDataLoader telemetry) {
- super(telemetry);
+ HealthChecker healthChecker, TelemetryDataLoader telemetry, TelemetryDataJsonWriter dataJsonWriter) {
+ super(telemetry, dataJsonWriter);
this.globalInfoLoader = globalInfoLoader;
this.appNodesInfoLoader = appNodesInfoLoader;
this.searchNodesInfoLoader = searchNodesInfoLoader;
import org.sonar.server.ce.http.CeHttpClient;
import org.sonar.server.health.Health;
import org.sonar.server.health.HealthChecker;
+import org.sonar.server.telemetry.TelemetryDataJsonWriter;
import org.sonar.server.telemetry.TelemetryDataLoader;
import static java.util.Arrays.stream;
private final HealthChecker healthChecker;
private final SystemInfoSection[] systemInfoSections;
- public StandaloneSystemInfoWriter(TelemetryDataLoader telemetry, CeHttpClient ceHttpClient, HealthChecker healthChecker, SystemInfoSection... systemInfoSections) {
- super(telemetry);
+ public StandaloneSystemInfoWriter(TelemetryDataLoader telemetry, CeHttpClient ceHttpClient, HealthChecker healthChecker,
+ TelemetryDataJsonWriter dataJsonWriter, SystemInfoSection... systemInfoSections) {
+ super(telemetry, dataJsonWriter);
this.ceHttpClient = ceHttpClient;
this.healthChecker = healthChecker;
this.systemInfoSections = systemInfoSections;
import static org.sonar.process.ProcessProperties.Property.SONAR_TELEMETRY_ENABLE;
import static org.sonar.process.ProcessProperties.Property.SONAR_TELEMETRY_FREQUENCY_IN_SECONDS;
import static org.sonar.process.ProcessProperties.Property.SONAR_TELEMETRY_URL;
-import static org.sonar.server.telemetry.TelemetryDataJsonWriter.writeTelemetryData;
@ServerSide
public class TelemetryDaemon implements Startable {
private static final String LOCK_DELAY_SEC = "sonar.telemetry.lock.delay";
private final TelemetryDataLoader dataLoader;
+ private final TelemetryDataJsonWriter dataJsonWriter;
private final TelemetryClient telemetryClient;
private final GlobalLockManager lockManager;
private final Configuration config;
private ScheduledExecutorService executorService;
- public TelemetryDaemon(TelemetryDataLoader dataLoader, TelemetryClient telemetryClient, Configuration config,
+ public TelemetryDaemon(TelemetryDataLoader dataLoader, TelemetryDataJsonWriter dataJsonWriter, TelemetryClient telemetryClient, Configuration config,
InternalProperties internalProperties, GlobalLockManager lockManager, System2 system2) {
this.dataLoader = dataLoader;
+ this.dataJsonWriter = dataJsonWriter;
this.telemetryClient = telemetryClient;
this.config = config;
this.internalProperties = internalProperties;
internalProperties.write(I_PROP_LAST_PING, String.valueOf(startOfDay(now)));
}
} catch (Exception e) {
- LOG.debug("Error while checking SonarQube statistics: {}", e.getMessage());
+ LOG.debug("Error while checking SonarQube statistics: {}", e);
}
// do not check at start up to exclude test instance which are not up for a long time
};
TelemetryData statistics = dataLoader.load();
StringWriter jsonString = new StringWriter();
try (JsonWriter json = JsonWriter.of(jsonString)) {
- writeTelemetryData(json, statistics);
+ dataJsonWriter.writeTelemetryData(json, statistics);
}
telemetryClient.upload(jsonString.toString());
}
data.setServerId(server.getId());
data.setVersion(server.getVersion());
- data.setEdition(editionProvider.get());
+ data.setEdition(editionProvider.get().orElse(null));
ofNullable(licenseReader)
.flatMap(reader -> licenseReader.read())
.ifPresent(license -> data.setLicenseType(license.getType()));
import org.sonar.server.platform.monitoring.cluster.GlobalInfoLoader;
import org.sonar.server.platform.monitoring.cluster.NodeInfo;
import org.sonar.server.platform.monitoring.cluster.SearchNodesInfoLoader;
+import org.sonar.server.telemetry.TelemetryDataJsonWriter;
import org.sonar.server.telemetry.TelemetryDataLoader;
import static org.assertj.core.api.Assertions.assertThat;
private SearchNodesInfoLoader searchNodesInfoLoader = mock(SearchNodesInfoLoader.class);
private HealthChecker healthChecker = mock(HealthChecker.class);
private TelemetryDataLoader telemetry = mock(TelemetryDataLoader.class, Mockito.RETURNS_MOCKS);
- private ClusterSystemInfoWriter underTest = new ClusterSystemInfoWriter(globalInfoLoader, appNodesInfoLoader, searchNodesInfoLoader, healthChecker, telemetry);
+ private TelemetryDataJsonWriter dataJsonWriter = new TelemetryDataJsonWriter();
+ private ClusterSystemInfoWriter underTest = new ClusterSystemInfoWriter(globalInfoLoader, appNodesInfoLoader,
+ searchNodesInfoLoader, healthChecker, telemetry, dataJsonWriter);
@Before
public void before() throws InterruptedException {
import org.sonar.process.systeminfo.SystemInfoSection;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import org.sonar.server.health.TestStandaloneHealthChecker;
+import org.sonar.server.telemetry.TelemetryDataJsonWriter;
import org.sonar.server.telemetry.TelemetryDataLoader;
import org.sonar.server.tester.UserSessionRule;
private CeHttpClient ceHttpClient = mock(CeHttpClientImpl.class, Mockito.RETURNS_MOCKS);
private TestStandaloneHealthChecker healthChecker = new TestStandaloneHealthChecker();
private TelemetryDataLoader telemetry = mock(TelemetryDataLoader.class, Mockito.RETURNS_MOCKS);
+ private TelemetryDataJsonWriter dataJsonWriter = new TelemetryDataJsonWriter();
- private StandaloneSystemInfoWriter underTest = new StandaloneSystemInfoWriter(telemetry, ceHttpClient, healthChecker, section1, section2);
+ private StandaloneSystemInfoWriter underTest = new StandaloneSystemInfoWriter(telemetry, ceHttpClient, healthChecker, dataJsonWriter, section1, section2);
@Test
public void write_json() {
package org.sonar.server.telemetry;
import java.io.IOException;
-import java.net.URL;
-import java.sql.DatabaseMetaData;
-import java.sql.SQLException;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.IntStream;
+import java.util.Collections;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
-import org.mockito.ArgumentCaptor;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.impl.utils.TestSystem2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.core.platform.EditionProvider;
-import org.sonar.core.platform.PlatformEditionProvider;
-import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.PluginRepository;
-import org.sonar.db.DbSession;
-import org.sonar.db.DbTester;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.db.metric.MetricDto;
-import org.sonar.server.es.EsTester;
-import org.sonar.server.measure.index.ProjectMeasuresIndex;
-import org.sonar.server.measure.index.ProjectMeasuresIndexer;
-import org.sonar.server.organization.DefaultOrganizationProviderImpl;
-import org.sonar.server.platform.DockerSupport;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.server.measure.index.ProjectMeasuresStatistics;
import org.sonar.server.property.InternalProperties;
import org.sonar.server.property.MapInternalProperties;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.user.index.UserIndex;
-import org.sonar.server.user.index.UserIndexer;
import org.sonar.server.util.GlobalLockManager;
import org.sonar.server.util.GlobalLockManagerImpl;
-import org.sonar.updatecenter.common.Version;
-import static java.util.Arrays.asList;
-import static java.util.Collections.emptySet;
-import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
-import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static org.sonar.api.measures.CoreMetrics.COVERAGE_KEY;
-import static org.sonar.api.measures.CoreMetrics.LINES_KEY;
-import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
-import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY;
import static org.sonar.api.utils.DateUtils.parseDate;
-import static org.sonar.db.component.BranchType.LONG;
-import static org.sonar.db.component.BranchType.SHORT;
import static org.sonar.process.ProcessProperties.Property.SONAR_TELEMETRY_ENABLE;
import static org.sonar.process.ProcessProperties.Property.SONAR_TELEMETRY_FREQUENCY_IN_SECONDS;
import static org.sonar.process.ProcessProperties.Property.SONAR_TELEMETRY_URL;
-import static org.sonar.test.JsonAssert.assertJson;
public class TelemetryDaemonTest {
+ @Rule
+ public LogTester logger = new LogTester().setLevel(LoggerLevel.DEBUG);
private static final long ONE_HOUR = 60 * 60 * 1_000L;
private static final long ONE_DAY = 24 * ONE_HOUR;
-
- @Rule
- public UserSessionRule userSession = UserSessionRule.standalone();
- @Rule
- public DbTester db = DbTester.create();
- @Rule
- public EsTester es = EsTester.create();
- @Rule
- public LogTester logger = new LogTester().setLevel(LoggerLevel.DEBUG);
+ private static final TelemetryData SOME_TELEMETRY_DATA = TelemetryData.builder()
+ .setServerId("foo")
+ .setVersion("bar")
+ .setPlugins(Collections.emptyMap())
+ .setProjectMeasuresStatistics(ProjectMeasuresStatistics.builder()
+ .setProjectCount(12)
+ .setProjectCountByLanguage(Collections.emptyMap())
+ .setNclocByLanguage(Collections.emptyMap())
+ .build())
+ .setNcloc(42L)
+ .setDatabase(new TelemetryData.Database("H2", "11"))
+ .setUsingBranches(true)
+ .build();
private TelemetryClient client = mock(TelemetryClient.class);
private InternalProperties internalProperties = spy(new MapInternalProperties());
private final GlobalLockManager lockManager = mock(GlobalLockManagerImpl.class);
- private FakeServer server = new FakeServer();
- private PluginRepository pluginRepository = mock(PluginRepository.class);
private TestSystem2 system2 = new TestSystem2().setNow(System.currentTimeMillis());
private MapSettings settings = new MapSettings();
- private ProjectMeasuresIndexer projectMeasuresIndexer = new ProjectMeasuresIndexer(db.getDbClient(), es.client());
- private UserIndexer userIndexer = new UserIndexer(db.getDbClient(), es.client());
- private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
-
- private final DockerSupport dockerSupport = mock(DockerSupport.class);
- private final TelemetryDataLoader communityDataLoader = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2),
- new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, new DefaultOrganizationProviderImpl(db.getDbClient()), internalProperties, dockerSupport, null);
- private TelemetryDaemon communityUnderTest = new TelemetryDaemon(communityDataLoader, client, settings.asConfig(), internalProperties, lockManager, system2);
- private final LicenseReader licenseReader = mock(LicenseReader.class);
- private final TelemetryDataLoader commercialDataLoader = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2),
- new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, new DefaultOrganizationProviderImpl(db.getDbClient()), internalProperties, dockerSupport, licenseReader);
- private TelemetryDaemon commercialUnderTest = new TelemetryDaemon(commercialDataLoader, client, settings.asConfig(), internalProperties, lockManager, system2);
+ private final TelemetryDataLoader dataLoader = mock(TelemetryDataLoader.class);
+ private final TelemetryDataJsonWriter dataJsonWriter = mock(TelemetryDataJsonWriter.class);
+ private TelemetryDaemon underTest = new TelemetryDaemon(dataLoader, dataJsonWriter, client, settings.asConfig(), internalProperties, lockManager, system2);
@After
public void tearDown() {
- communityUnderTest.stop();
- }
-
- @Test
- public void send_telemetry_data() throws IOException {
- initTelemetrySettingsToDefaultValues();
- settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
- server.setId("AU-TpxcB-iU5OvuD2FL7");
- server.setVersion("7.5.4");
- List<PluginInfo> plugins = asList(newPlugin("java", "4.12.0.11033"), newPlugin("scmgit", "1.2"), new PluginInfo("other"));
- when(pluginRepository.getPluginInfos()).thenReturn(plugins);
- when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER));
- when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
-
- IntStream.range(0, 3).forEach(i -> db.users().insertUser());
- db.users().insertUser(u -> u.setActive(false));
- userIndexer.indexOnStartup(emptySet());
-
- MetricDto lines = db.measures().insertMetric(m -> m.setKey(LINES_KEY));
- MetricDto ncloc = db.measures().insertMetric(m -> m.setKey(NCLOC_KEY));
- MetricDto coverage = db.measures().insertMetric(m -> m.setKey(COVERAGE_KEY));
- MetricDto nclocDistrib = db.measures().insertMetric(m -> m.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY));
-
- ComponentDto project1 = db.components().insertMainBranch(db.getDefaultOrganization());
- ComponentDto project1Branch = db.components().insertProjectBranch(project1);
- db.measures().insertLiveMeasure(project1, lines, m -> m.setValue(200d));
- db.measures().insertLiveMeasure(project1, ncloc, m -> m.setValue(100d));
- db.measures().insertLiveMeasure(project1, coverage, m -> m.setValue(80d));
- db.measures().insertLiveMeasure(project1, nclocDistrib, m -> m.setValue(null).setData("java=200;js=50"));
-
- ComponentDto project2 = db.components().insertMainBranch(db.getDefaultOrganization());
- db.measures().insertLiveMeasure(project2, lines, m -> m.setValue(300d));
- db.measures().insertLiveMeasure(project2, ncloc, m -> m.setValue(200d));
- db.measures().insertLiveMeasure(project2, coverage, m -> m.setValue(80d));
- db.measures().insertLiveMeasure(project2, nclocDistrib, m -> m.setValue(null).setData("java=300;kotlin=2500"));
- projectMeasuresIndexer.indexOnStartup(emptySet());
-
- communityUnderTest.start();
-
- ArgumentCaptor<String> jsonCaptor = captureJson();
- String json = jsonCaptor.getValue();
- URL url = getClass().getResource("telemetry-example.json");
- assertJson(json).ignoreFields("database").isSimilarTo(url);
- assertJson(url).ignoreFields("database").isSimilarTo(json);
- assertDatabaseMetadata(json);
- assertThat(logger.logs(LoggerLevel.INFO)).contains("Sharing of SonarQube statistics is enabled.");
- }
-
- private void assertDatabaseMetadata(String json) {
- try (DbSession dbSession = db.getDbClient().openSession(false)) {
- DatabaseMetaData metadata = dbSession.getConnection().getMetaData();
- assertJson(json).isSimilarTo("{\n" +
- " \"database\": {\n" +
- " \"name\": \"H2\",\n" +
- " \"version\": \"" + metadata.getDatabaseProductVersion() + "\"\n" +
- " }\n" +
- "}");
- } catch (SQLException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Test
- public void take_biggest_long_living_branches() throws IOException {
- initTelemetrySettingsToDefaultValues();
- when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
- settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
- server.setId("AU-TpxcB-iU5OvuD2FL7").setVersion("7.5.4");
- MetricDto ncloc = db.measures().insertMetric(m -> m.setKey(NCLOC_KEY));
- ComponentDto project = db.components().insertMainBranch(db.getDefaultOrganization());
- ComponentDto longBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(LONG));
- ComponentDto shortBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(SHORT));
- db.measures().insertLiveMeasure(project, ncloc, m -> m.setValue(10d));
- db.measures().insertLiveMeasure(longBranch, ncloc, m -> m.setValue(20d));
- db.measures().insertLiveMeasure(shortBranch, ncloc, m -> m.setValue(30d));
- projectMeasuresIndexer.indexOnStartup(emptySet());
-
- communityUnderTest.start();
-
- ArgumentCaptor<String> jsonCaptor = captureJson();
- assertJson(jsonCaptor.getValue()).isSimilarTo("{\n" +
- " \"ncloc\": 20\n" +
- "}\n");
+ underTest.stop();
}
@Test
initTelemetrySettingsToDefaultValues();
when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
- communityUnderTest.start();
+ when(dataLoader.load()).thenReturn(SOME_TELEMETRY_DATA);
+ mockDataJsonWriterDoingSomething();
- verify(client, timeout(2_000).atLeastOnce()).upload(anyString());
- }
-
- @Test
- public void data_contains_no_license_type_on_community_edition() throws IOException {
- initTelemetrySettingsToDefaultValues();
- when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
- settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
-
- communityUnderTest.start();
+ underTest.start();
- ArgumentCaptor<String> jsonCaptor = captureJson();
- assertThat(jsonCaptor.getValue()).doesNotContain("licenseType");
- }
-
- @Test
- public void data_contains_no_license_type_on_commercial_edition_if_no_license() throws IOException {
- initTelemetrySettingsToDefaultValues();
- settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
- when(licenseReader.read()).thenReturn(Optional.empty());
- when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
-
- commercialUnderTest.start();
-
- ArgumentCaptor<String> jsonCaptor = captureJson();
- assertThat(jsonCaptor.getValue()).doesNotContain("licenseType");
+ verify(client, timeout(2_000).atLeastOnce()).upload(anyString());
+ verify(dataJsonWriter).writeTelemetryData(any(JsonWriter.class), same(SOME_TELEMETRY_DATA));
}
- @Test
- public void data_has_license_type_on_commercial_edition_if_no_license() throws IOException {
- String licenseType = randomAlphabetic(12);
- initTelemetrySettingsToDefaultValues();
- settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
- LicenseReader.License license = mock(LicenseReader.License.class);
- when(license.getType()).thenReturn(licenseType);
- when(licenseReader.read()).thenReturn(Optional.of(license));
- when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
-
- commercialUnderTest.start();
-
- ArgumentCaptor<String> jsonCaptor = captureJson();
- assertJson(jsonCaptor.getValue()).isSimilarTo("{\n" +
- " \"licenseType\": \"" + licenseType + "\"\n" +
- "}\n");
+ private void mockDataJsonWriterDoingSomething() {
+ doAnswer(t -> {
+ JsonWriter json = t.getArgument(0);
+ json.beginObject().prop("foo", "bar").endObject();
+ return null;
+ })
+ .when(dataJsonWriter)
+ .writeTelemetryData(any(), any());
}
@Test
long sevenDaysAgo = now - (ONE_DAY * 7L);
internalProperties.write("telemetry.lastPing", String.valueOf(sixDaysAgo));
settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
- communityUnderTest.start();
- verify(client, after(2_000).never()).upload(anyString());
- internalProperties.write("telemetry.lastPing", String.valueOf(sevenDaysAgo));
+ when(dataLoader.load()).thenReturn(SOME_TELEMETRY_DATA);
+ mockDataJsonWriterDoingSomething();
- verify(client, timeout(2_000).atLeastOnce()).upload(anyString());
- }
+ underTest.start();
- @Test
- public void send_server_id_and_version() throws IOException {
- initTelemetrySettingsToDefaultValues();
- when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
- settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
- String id = randomAlphanumeric(40);
- String version = randomAlphanumeric(10);
- server.setId(id);
- server.setVersion(version);
- communityUnderTest.start();
+ verify(dataJsonWriter, after(2_000).never()).writeTelemetryData(any(JsonWriter.class), same(SOME_TELEMETRY_DATA));
+ verify(client, never()).upload(anyString());
- ArgumentCaptor<String> json = captureJson();
- assertThat(json.getValue()).contains(id, version);
- }
-
- @Test
- public void send_server_installation_date_and_installation_version() throws IOException {
- initTelemetrySettingsToDefaultValues();
- when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
- settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
- String installationVersion = "7.9.BEST.LTS.EVER";
- Long installationDate = 1546300800000L; // 2019/01/01
- internalProperties.write(InternalProperties.INSTALLATION_DATE, String.valueOf(installationDate));
- internalProperties.write(InternalProperties.INSTALLATION_VERSION, installationVersion);
-
- communityUnderTest.start();
-
- ArgumentCaptor<String> json = captureJson();
- assertThat(json.getValue()).contains(installationVersion, installationDate.toString());
- }
-
- @Test
- public void do_not_send_server_installation_details_if_missing_property() throws IOException {
- initTelemetrySettingsToDefaultValues();
- when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
- settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
-
- communityUnderTest.start();
+ internalProperties.write("telemetry.lastPing", String.valueOf(sevenDaysAgo));
- ArgumentCaptor<String> json = captureJson();
- assertThat(json.getValue()).doesNotContain("installationVersion", "installationDate");
+ verify(dataJsonWriter, timeout(2_000)).writeTelemetryData(any(JsonWriter.class), same(SOME_TELEMETRY_DATA));
+ verify(client).upload(anyString());
}
@Test
settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
long now = system2.now();
long sixDaysAgo = now - (ONE_DAY * 6L);
+ mockDataJsonWriterDoingSomething();
internalProperties.write("telemetry.lastPing", String.valueOf(sixDaysAgo));
- communityUnderTest.start();
+ underTest.start();
verify(client, after(2_000).never()).upload(anyString());
}
long sevenDaysAgo = today - (ONE_DAY * 7L);
internalProperties.write("telemetry.lastPing", String.valueOf(sevenDaysAgo));
reset(internalProperties);
+ mockDataJsonWriterDoingSomething();
- communityUnderTest.start();
+ underTest.start();
verify(internalProperties, timeout(4_000)).write("telemetry.lastPing", String.valueOf(today));
verify(client).upload(anyString());
when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
settings.setProperty("sonar.telemetry.enable", "false");
- communityUnderTest.start();
- communityUnderTest.start();
+ mockDataJsonWriterDoingSomething();
+
+ underTest.start();
+ underTest.start();
verify(client, after(2_000).never()).upload(anyString());
verify(client, timeout(2_000).times(1)).optOut(anyString());
assertThat(logger.logs(LoggerLevel.INFO)).contains("Sharing of SonarQube statistics is disabled.");
}
- private PluginInfo newPlugin(String key, String version) {
- return new PluginInfo(key)
- .setVersion(Version.create(version));
- }
-
private void initTelemetrySettingsToDefaultValues() {
settings.setProperty(SONAR_TELEMETRY_ENABLE.getKey(), SONAR_TELEMETRY_ENABLE.getDefaultValue());
settings.setProperty(SONAR_TELEMETRY_URL.getKey(), SONAR_TELEMETRY_URL.getDefaultValue());
settings.setProperty(SONAR_TELEMETRY_FREQUENCY_IN_SECONDS.getKey(), SONAR_TELEMETRY_FREQUENCY_IN_SECONDS.getDefaultValue());
}
- private ArgumentCaptor<String> captureJson() throws IOException {
- ArgumentCaptor<String> jsonCaptor = ArgumentCaptor.forClass(String.class);
- verify(client, timeout(2_000).atLeastOnce()).upload(jsonCaptor.capture());
- return jsonCaptor;
- }
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.telemetry;
+
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.IntStream;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.impl.utils.TestSystem2;
+import org.sonar.core.platform.PlatformEditionProvider;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.metric.MetricDto;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.measure.index.ProjectMeasuresIndex;
+import org.sonar.server.measure.index.ProjectMeasuresIndexer;
+import org.sonar.server.organization.DefaultOrganizationProviderImpl;
+import org.sonar.server.platform.DockerSupport;
+import org.sonar.server.property.InternalProperties;
+import org.sonar.server.property.MapInternalProperties;
+import org.sonar.server.user.index.UserIndex;
+import org.sonar.server.user.index.UserIndexer;
+import org.sonar.updatecenter.common.Version;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptySet;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.measures.CoreMetrics.COVERAGE_KEY;
+import static org.sonar.api.measures.CoreMetrics.LINES_KEY;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY;
+import static org.sonar.core.platform.EditionProvider.Edition.DEVELOPER;
+import static org.sonar.db.component.BranchType.LONG;
+import static org.sonar.db.component.BranchType.SHORT;
+
+public class TelemetryDataLoaderImplTest {
+ @Rule
+ public DbTester db = DbTester.create();
+ @Rule
+ public EsTester es = EsTester.create();
+
+ private final FakeServer server = new FakeServer();
+ private final PluginRepository pluginRepository = mock(PluginRepository.class);
+ private final TestSystem2 system2 = new TestSystem2().setNow(System.currentTimeMillis());
+ private final PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
+ private final DockerSupport dockerSupport = mock(DockerSupport.class);
+ private final InternalProperties internalProperties = spy(new MapInternalProperties());
+ private final ProjectMeasuresIndexer projectMeasuresIndexer = new ProjectMeasuresIndexer(db.getDbClient(), es.client());
+ private final UserIndexer userIndexer = new UserIndexer(db.getDbClient(), es.client());
+ private final LicenseReader licenseReader = mock(LicenseReader.class);
+
+ private final TelemetryDataLoader communityUnderTest = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2),
+ new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, new DefaultOrganizationProviderImpl(db.getDbClient()), internalProperties, dockerSupport, null);
+ private final TelemetryDataLoader commercialUnderTest = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2),
+ new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, new DefaultOrganizationProviderImpl(db.getDbClient()), internalProperties, dockerSupport, licenseReader);
+
+ @Test
+ public void send_telemetry_data() {
+ String serverId = "AU-TpxcB-iU5OvuD2FL7";
+ String version = "7.5.4";
+ server.setId(serverId);
+ server.setVersion(version);
+ List<PluginInfo> plugins = asList(newPlugin("java", "4.12.0.11033"), newPlugin("scmgit", "1.2"), new PluginInfo("other"));
+ when(pluginRepository.getPluginInfos()).thenReturn(plugins);
+ when(editionProvider.get()).thenReturn(Optional.of(DEVELOPER));
+
+ int userCount = 3;
+ IntStream.range(0, userCount).forEach(i -> db.users().insertUser());
+ db.users().insertUser(u -> u.setActive(false));
+ userIndexer.indexOnStartup(emptySet());
+
+ MetricDto lines = db.measures().insertMetric(m -> m.setKey(LINES_KEY));
+ MetricDto ncloc = db.measures().insertMetric(m -> m.setKey(NCLOC_KEY));
+ MetricDto coverage = db.measures().insertMetric(m -> m.setKey(COVERAGE_KEY));
+ MetricDto nclocDistrib = db.measures().insertMetric(m -> m.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY));
+
+ ComponentDto project1 = db.components().insertMainBranch(db.getDefaultOrganization());
+ ComponentDto project1Branch = db.components().insertProjectBranch(project1);
+ db.measures().insertLiveMeasure(project1, lines, m -> m.setValue(200d));
+ db.measures().insertLiveMeasure(project1, ncloc, m -> m.setValue(100d));
+ db.measures().insertLiveMeasure(project1, coverage, m -> m.setValue(80d));
+ db.measures().insertLiveMeasure(project1, nclocDistrib, m -> m.setValue(null).setData("java=200;js=50"));
+
+ ComponentDto project2 = db.components().insertMainBranch(db.getDefaultOrganization());
+ db.measures().insertLiveMeasure(project2, lines, m -> m.setValue(300d));
+ db.measures().insertLiveMeasure(project2, ncloc, m -> m.setValue(200d));
+ db.measures().insertLiveMeasure(project2, coverage, m -> m.setValue(80d));
+ db.measures().insertLiveMeasure(project2, nclocDistrib, m -> m.setValue(null).setData("java=300;kotlin=2500"));
+ projectMeasuresIndexer.indexOnStartup(emptySet());
+
+ TelemetryData data = communityUnderTest.load();
+ assertThat(data.getServerId()).isEqualTo(serverId);
+ assertThat(data.getVersion()).isEqualTo(version);
+ assertThat(data.getEdition()).contains(DEVELOPER);
+ assertDatabaseMetadata(data.getDatabase());
+ assertThat(data.getPlugins()).containsOnly(
+ entry("java", "4.12.0.11033"), entry("scmgit", "1.2"), entry("other", "undefined"));
+ assertThat(data.getUserCount()).isEqualTo(userCount);
+ assertThat(data.getProjectCount()).isEqualTo(2L);
+ assertThat(data.getNcloc()).isEqualTo(300L);
+ assertThat(data.getProjectCountByLanguage()).containsOnly(
+ entry("java", 2L), entry("kotlin", 1L), entry("js", 1L));
+ assertThat(data.getNclocByLanguage()).containsOnly(
+ entry("java", 500L), entry("kotlin", 2500L), entry("js", 50L));
+ assertThat(data.isInDocker()).isFalse();
+ }
+
+ private void assertDatabaseMetadata(TelemetryData.Database database) {
+ try (DbSession dbSession = db.getDbClient().openSession(false)) {
+ DatabaseMetaData metadata = dbSession.getConnection().getMetaData();
+ assertThat(database.getName()).isEqualTo("H2");
+ assertThat(database.getVersion()).isEqualTo(metadata.getDatabaseProductVersion());
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Test
+ public void take_biggest_long_living_branches() {
+ server.setId("AU-TpxcB-iU5OvuD2FL7").setVersion("7.5.4");
+ MetricDto ncloc = db.measures().insertMetric(m -> m.setKey(NCLOC_KEY));
+ ComponentDto project = db.components().insertMainBranch(db.getDefaultOrganization());
+ ComponentDto longBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(LONG));
+ ComponentDto shortBranch = db.components().insertProjectBranch(project, b -> b.setBranchType(SHORT));
+ db.measures().insertLiveMeasure(project, ncloc, m -> m.setValue(10d));
+ db.measures().insertLiveMeasure(longBranch, ncloc, m -> m.setValue(20d));
+ db.measures().insertLiveMeasure(shortBranch, ncloc, m -> m.setValue(30d));
+ projectMeasuresIndexer.indexOnStartup(emptySet());
+
+ TelemetryData data = communityUnderTest.load();
+
+ assertThat(data.getNcloc()).isEqualTo(20l);
+ }
+
+ @Test
+ public void data_contains_no_license_type_on_community_edition() {
+ TelemetryData data = communityUnderTest.load();
+
+ assertThat(data.getLicenseType()).isEmpty();
+ }
+
+ @Test
+ public void data_contains_no_license_type_on_commercial_edition_if_no_license() {
+ when(licenseReader.read()).thenReturn(Optional.empty());
+
+ TelemetryData data = commercialUnderTest.load();
+
+ assertThat(data.getLicenseType()).isEmpty();
+ }
+
+ @Test
+ public void data_has_license_type_on_commercial_edition_if_no_license() {
+ String licenseType = randomAlphabetic(12);
+ LicenseReader.License license = mock(LicenseReader.License.class);
+ when(license.getType()).thenReturn(licenseType);
+ when(licenseReader.read()).thenReturn(Optional.of(license));
+
+ TelemetryData data = commercialUnderTest.load();
+
+ assertThat(data.getLicenseType()).contains(licenseType);
+ }
+
+ @Test
+ public void send_server_id_and_version() {
+ String id = randomAlphanumeric(40);
+ String version = randomAlphanumeric(10);
+ server.setId(id);
+ server.setVersion(version);
+
+ TelemetryData data = communityUnderTest.load();
+ assertThat(data.getServerId()).isEqualTo(id);
+ assertThat(data.getVersion()).isEqualTo(version);
+
+ data = commercialUnderTest.load();
+ assertThat(data.getServerId()).isEqualTo(id);
+ assertThat(data.getVersion()).isEqualTo(version);
+ }
+
+ @Test
+ public void send_server_installation_date_and_installation_version() {
+ String installationVersion = "7.9.BEST.LTS.EVER";
+ Long installationDate = 1546300800000L; // 2019/01/01
+ internalProperties.write(InternalProperties.INSTALLATION_DATE, String.valueOf(installationDate));
+ internalProperties.write(InternalProperties.INSTALLATION_VERSION, installationVersion);
+
+ TelemetryData data = communityUnderTest.load();
+
+ assertThat(data.getInstallationDate()).isEqualTo(installationDate);
+ assertThat(data.getInstallationVersion()).isEqualTo(installationVersion);
+ }
+
+ @Test
+ public void do_not_send_server_installation_details_if_missing_property() {
+ TelemetryData data = communityUnderTest.load();
+ assertThat(data.getInstallationDate()).isNull();
+ assertThat(data.getInstallationVersion()).isNull();
+
+ data = commercialUnderTest.load();
+ assertThat(data.getInstallationDate()).isNull();
+ assertThat(data.getInstallationVersion()).isNull();
+ }
+
+ private PluginInfo newPlugin(String key, String version) {
+ return new PluginInfo(key)
+ .setVersion(Version.create(version));
+ }
+
+}
import org.sonar.server.startup.LogServerId;
import org.sonar.server.telemetry.TelemetryClient;
import org.sonar.server.telemetry.TelemetryDaemon;
+import org.sonar.server.telemetry.TelemetryDataJsonWriter;
import org.sonar.server.telemetry.TelemetryDataLoaderImpl;
import org.sonar.server.text.MacroInterpreter;
import org.sonar.server.ui.DeprecatedViews;
// telemetry
TelemetryDataLoaderImpl.class,
+ TelemetryDataJsonWriter.class,
TelemetryDaemon.class,
TelemetryClient.class