]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-11306 add license type to telemetry
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Wed, 17 Oct 2018 14:07:37 +0000 (16:07 +0200)
committerSonarTech <sonartech@sonarsource.com>
Thu, 18 Oct 2018 18:20:55 +0000 (20:20 +0200)
server/sonar-server/src/main/java/org/sonar/server/telemetry/LicenseReader.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryData.java
server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryDataJsonWriter.java
server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryDataLoader.java
server/sonar-server/src/test/java/org/sonar/server/telemetry/TelemetryDaemonTest.java

diff --git a/server/sonar-server/src/main/java/org/sonar/server/telemetry/LicenseReader.java b/server/sonar-server/src/main/java/org/sonar/server/telemetry/LicenseReader.java
new file mode 100644 (file)
index 0000000..7b13141
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.util.Optional;
+import org.sonar.api.server.ServerSide;
+
+@ServerSide
+public interface LicenseReader {
+  Optional<License> read();
+
+  interface License {
+    String getType();
+  }
+}
index c39d336f43c35f302beda311040a7114c7ad5048..b7200c4a9634879f786a25a310bb59b2033942b3 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.server.telemetry;
 
 import java.util.Map;
 import java.util.Optional;
+import javax.annotation.Nullable;
 import org.sonar.core.platform.EditionProvider;
 import org.sonar.server.measure.index.ProjectMeasuresStatistics;
 
@@ -38,6 +39,7 @@ public class TelemetryData {
   private final Map<String, Long> projectCountByLanguage;
   private final Map<String, Long> nclocByLanguage;
   private final Optional<EditionProvider.Edition> edition;
+  private final String licenseType;
 
   private TelemetryData(Builder builder) {
     serverId = builder.serverId;
@@ -51,6 +53,7 @@ public class TelemetryData {
     projectCountByLanguage = builder.projectMeasuresStatistics.getProjectCountByLanguage();
     nclocByLanguage = builder.projectMeasuresStatistics.getNclocByLanguage();
     edition = builder.edition;
+    licenseType = builder.licenseType;
   }
 
   public String getServerId() {
@@ -97,6 +100,10 @@ public class TelemetryData {
     return edition;
   }
 
+  public Optional<String> getLicenseType() {
+    return Optional.ofNullable(licenseType);
+  }
+
   static Builder builder() {
     return new Builder();
   }
@@ -111,6 +118,7 @@ public class TelemetryData {
     private Long ncloc;
     private Boolean usingBranches;
     private Optional<EditionProvider.Edition> edition;
+    private String licenseType;
 
     private Builder() {
       // enforce static factory method
@@ -161,6 +169,11 @@ public class TelemetryData {
       return this;
     }
 
+    public Builder setLicenseType(@Nullable String licenseType) {
+      this.licenseType = licenseType;
+      return this;
+    }
+
     TelemetryData build() {
       requireNonNull(serverId);
       requireNonNull(version);
index e218ab44fb759efde075e6c3e2b3f2760ba34d46..2ee881d31bbcce0647b2a89342998285f8102f2b 100644 (file)
@@ -34,6 +34,7 @@ public class TelemetryDataJsonWriter {
     json.prop("id", statistics.getServerId());
     json.prop("version", statistics.getVersion());
     statistics.getEdition().ifPresent(e -> json.prop("edition", e.name().toLowerCase(Locale.ENGLISH)));
+    statistics.getLicenseType().ifPresent(e -> json.prop("licenseType", e));
     json.name("database");
     json.beginObject();
     json.prop("name", statistics.getDatabase().getName());
index 915bfb2afcdf9f388454864b18342db12e7984b3..31400eaa3d1aa0f536ac41f47cfe1f118a91ac47 100644 (file)
@@ -23,6 +23,8 @@ import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
 import java.util.Map;
 import java.util.function.Function;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 import org.sonar.api.platform.Server;
 import org.sonar.api.server.ServerSide;
 import org.sonar.core.platform.PlatformEditionProvider;
@@ -40,6 +42,8 @@ import org.sonar.server.telemetry.TelemetryData.Database;
 import org.sonar.server.user.index.UserIndex;
 import org.sonar.server.user.index.UserQuery;
 
+import static java.util.Optional.ofNullable;
+
 @ServerSide
 public class TelemetryDataLoader {
   private final Server server;
@@ -49,9 +53,16 @@ public class TelemetryDataLoader {
   private final ProjectMeasuresIndex projectMeasuresIndex;
   private final PlatformEditionProvider editionProvider;
   private final DefaultOrganizationProvider defaultOrganizationProvider;
+  @CheckForNull
+  private final LicenseReader licenseReader;
 
   public TelemetryDataLoader(Server server, DbClient dbClient, PluginRepository pluginRepository, UserIndex userIndex, ProjectMeasuresIndex projectMeasuresIndex,
     PlatformEditionProvider editionProvider, DefaultOrganizationProvider defaultOrganizationProvider) {
+    this(server, dbClient, pluginRepository, userIndex, projectMeasuresIndex, editionProvider, defaultOrganizationProvider, null);
+  }
+
+  public TelemetryDataLoader(Server server, DbClient dbClient, PluginRepository pluginRepository, UserIndex userIndex, ProjectMeasuresIndex projectMeasuresIndex,
+    PlatformEditionProvider editionProvider, DefaultOrganizationProvider defaultOrganizationProvider, @Nullable LicenseReader licenseReader) {
     this.server = server;
     this.dbClient = dbClient;
     this.pluginRepository = pluginRepository;
@@ -59,6 +70,7 @@ public class TelemetryDataLoader {
     this.projectMeasuresIndex = projectMeasuresIndex;
     this.editionProvider = editionProvider;
     this.defaultOrganizationProvider = defaultOrganizationProvider;
+    this.licenseReader = licenseReader;
   }
 
   public TelemetryData load() {
@@ -67,6 +79,9 @@ public class TelemetryDataLoader {
     data.setServerId(server.getId());
     data.setVersion(server.getVersion());
     data.setEdition(editionProvider.get());
+    ofNullable(licenseReader)
+      .flatMap(reader -> licenseReader.read())
+      .ifPresent(license -> data.setLicenseType(license.getType()));
     Function<PluginInfo, String> getVersion = plugin -> plugin.getVersion() == null ? "undefined" : plugin.getVersion().getName();
     Map<String, String> plugins = pluginRepository.getPluginInfos().stream().collect(MoreCollectors.uniqueIndex(PluginInfo::getKey, getVersion));
     data.setPlugins(plugins);
index e64eb8cc79224e577cd12fb1a28969e79cfe544c..e53b204d9babb34afe127dfc183d90fcd6221011 100644 (file)
@@ -29,7 +29,6 @@ import org.junit.After;
 import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
-import org.sonar.api.config.Configuration;
 import org.sonar.api.config.internal.MapSettings;
 import org.sonar.api.utils.internal.TestSystem2;
 import org.sonar.api.utils.log.LogTester;
@@ -55,6 +54,7 @@ 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.anyString;
@@ -81,7 +81,6 @@ public class TelemetryDaemonTest {
 
   private static final long ONE_HOUR = 60 * 60 * 1_000L;
   private static final long ONE_DAY = 24 * ONE_HOUR;
-  private static final Configuration emptyConfig = new MapSettings().asConfig();
 
   @Rule
   public UserSessionRule userSession = UserSessionRule.standalone();
@@ -102,13 +101,18 @@ public class TelemetryDaemonTest {
   private UserIndexer userIndexer = new UserIndexer(db.getDbClient(), es.client());
   private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
 
-  private final TelemetryDataLoader dataLoader = new TelemetryDataLoader(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2),
-    new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, new DefaultOrganizationProviderImpl(db.getDbClient()));
-  private TelemetryDaemon underTest = new TelemetryDaemon(dataLoader, client, settings.asConfig(), internalProperties, system2);
+  private final TelemetryDataLoader communityDataLoader = new TelemetryDataLoader(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2),
+    new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, new DefaultOrganizationProviderImpl(db.getDbClient()), null);
+  private TelemetryDaemon communityUnderTest = new TelemetryDaemon(communityDataLoader, client, settings.asConfig(), internalProperties, system2);
+
+  private final LicenseReader licenseReader = mock(LicenseReader.class);
+  private final TelemetryDataLoader commercialDataLoader = new TelemetryDataLoader(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2),
+    new ProjectMeasuresIndex(es.client(), null, system2), editionProvider, new DefaultOrganizationProviderImpl(db.getDbClient()), licenseReader);
+  private TelemetryDaemon commercialUnderTest = new TelemetryDaemon(commercialDataLoader, client, settings.asConfig(), internalProperties, system2);
 
   @After
   public void tearDown() {
-    underTest.stop();
+    communityUnderTest.stop();
   }
 
   @Test
@@ -144,7 +148,7 @@ public class TelemetryDaemonTest {
     db.measures().insertLiveMeasure(project2, nclocDistrib, m -> m.setValue(null).setData("java=300;kotlin=2500"));
     projectMeasuresIndexer.indexOnStartup(emptySet());
 
-    underTest.start();
+    communityUnderTest.start();
 
     ArgumentCaptor<String> jsonCaptor = captureJson();
     String json = jsonCaptor.getValue();
@@ -182,7 +186,7 @@ public class TelemetryDaemonTest {
     db.measures().insertLiveMeasure(shortBranch, ncloc, m -> m.setValue(30d));
     projectMeasuresIndexer.indexOnStartup(emptySet());
 
-    underTest.start();
+    communityUnderTest.start();
 
     ArgumentCaptor<String> jsonCaptor = captureJson();
     assertJson(jsonCaptor.getValue()).isSimilarTo("{\n" +
@@ -194,11 +198,51 @@ public class TelemetryDaemonTest {
   public void send_data_via_client_at_startup_after_initial_delay() throws IOException {
     initTelemetrySettingsToDefaultValues();
     settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
-    underTest.start();
+    communityUnderTest.start();
 
     verify(client, timeout(2_000).atLeastOnce()).upload(anyString());
   }
 
+  @Test
+  public void data_contains_no_license_type_on_community_edition() throws IOException {
+    initTelemetrySettingsToDefaultValues();
+    settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
+
+    communityUnderTest.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());
+
+    commercialUnderTest.start();
+
+    ArgumentCaptor<String> jsonCaptor = captureJson();
+    assertThat(jsonCaptor.getValue()).doesNotContain("licenseType");
+  }
+
+  @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));
+
+    commercialUnderTest.start();
+
+    ArgumentCaptor<String> jsonCaptor = captureJson();
+    assertJson(jsonCaptor.getValue()).isSimilarTo("{\n" +
+      "  \"licenseType\": \"" + licenseType + "\"\n" +
+      "}\n");
+  }
+
   @Test
   public void check_if_should_send_data_periodically() throws IOException {
     initTelemetrySettingsToDefaultValues();
@@ -207,7 +251,7 @@ public class TelemetryDaemonTest {
     long sevenDaysAgo = now - (ONE_DAY * 7L);
     internalProperties.write("telemetry.lastPing", String.valueOf(sixDaysAgo));
     settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
-    underTest.start();
+    communityUnderTest.start();
     verify(client, after(2_000).never()).upload(anyString());
     internalProperties.write("telemetry.lastPing", String.valueOf(sevenDaysAgo));
 
@@ -222,7 +266,7 @@ public class TelemetryDaemonTest {
     String version = randomAlphanumeric(10);
     server.setId(id);
     server.setVersion(version);
-    underTest.start();
+    communityUnderTest.start();
 
     ArgumentCaptor<String> json = captureJson();
     assertThat(json.getValue()).contains(id, version);
@@ -236,7 +280,7 @@ public class TelemetryDaemonTest {
     long sixDaysAgo = now - (ONE_DAY * 6L);
 
     internalProperties.write("telemetry.lastPing", String.valueOf(sixDaysAgo));
-    underTest.start();
+    communityUnderTest.start();
 
     verify(client, after(2_000).never()).upload(anyString());
   }
@@ -251,7 +295,7 @@ public class TelemetryDaemonTest {
     internalProperties.write("telemetry.lastPing", String.valueOf(sevenDaysAgo));
     reset(internalProperties);
 
-    underTest.start();
+    communityUnderTest.start();
 
     verify(internalProperties, timeout(4_000)).write("telemetry.lastPing", String.valueOf(today));
     verify(client).upload(anyString());
@@ -262,8 +306,8 @@ public class TelemetryDaemonTest {
     initTelemetrySettingsToDefaultValues();
     settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
     settings.setProperty("sonar.telemetry.enable", "false");
-    underTest.start();
-    underTest.start();
+    communityUnderTest.start();
+    communityUnderTest.start();
 
     verify(client, after(2_000).never()).upload(anyString());
     verify(client, timeout(2_000).times(1)).optOut(anyString());