package org.sonar.server.telemetry; | package org.sonar.server.telemetry; | ||||
import java.util.Map; | import java.util.Map; | ||||
import java.util.Optional; | |||||
import org.sonar.core.platform.EditionProvider; | |||||
import org.sonar.server.measure.index.ProjectMeasuresStatistics; | import org.sonar.server.measure.index.ProjectMeasuresStatistics; | ||||
import static java.util.Objects.requireNonNull; | import static java.util.Objects.requireNonNull; | ||||
private final Database database; | private final Database database; | ||||
private final Map<String, Long> projectCountByLanguage; | private final Map<String, Long> projectCountByLanguage; | ||||
private final Map<String, Long> nclocByLanguage; | private final Map<String, Long> nclocByLanguage; | ||||
private final Optional<EditionProvider.Edition> edition; | |||||
private TelemetryData(Builder builder) { | private TelemetryData(Builder builder) { | ||||
serverId = builder.serverId; | serverId = builder.serverId; | ||||
database = builder.database; | database = builder.database; | ||||
projectCountByLanguage = builder.projectMeasuresStatistics.getProjectCountByLanguage(); | projectCountByLanguage = builder.projectMeasuresStatistics.getProjectCountByLanguage(); | ||||
nclocByLanguage = builder.projectMeasuresStatistics.getNclocByLanguage(); | nclocByLanguage = builder.projectMeasuresStatistics.getNclocByLanguage(); | ||||
edition = builder.edition; | |||||
} | } | ||||
public String getServerId() { | public String getServerId() { | ||||
return nclocByLanguage; | return nclocByLanguage; | ||||
} | } | ||||
public Optional<EditionProvider.Edition> getEdition() { | |||||
return edition; | |||||
} | |||||
static Builder builder() { | static Builder builder() { | ||||
return new Builder(); | return new Builder(); | ||||
} | } | ||||
private ProjectMeasuresStatistics projectMeasuresStatistics; | private ProjectMeasuresStatistics projectMeasuresStatistics; | ||||
private Long ncloc; | private Long ncloc; | ||||
private Boolean usingBranches; | private Boolean usingBranches; | ||||
private Optional<EditionProvider.Edition> edition; | |||||
private Builder() { | private Builder() { | ||||
// enforce static factory method | // enforce static factory method | ||||
return this; | return this; | ||||
} | } | ||||
public Builder setEdition(Optional<EditionProvider.Edition> edition) { | |||||
this.edition = edition; | |||||
return this; | |||||
} | |||||
TelemetryData build() { | TelemetryData build() { | ||||
requireNonNull(serverId); | requireNonNull(serverId); | ||||
requireNonNull(version); | requireNonNull(version); | ||||
requireNonNull(ncloc); | requireNonNull(ncloc); | ||||
requireNonNull(database); | requireNonNull(database); | ||||
requireNonNull(usingBranches); | requireNonNull(usingBranches); | ||||
requireNonNull(edition); | |||||
return new TelemetryData(this); | return new TelemetryData(this); | ||||
} | } |
*/ | */ | ||||
package org.sonar.server.telemetry; | package org.sonar.server.telemetry; | ||||
import java.util.Locale; | |||||
import org.sonar.api.utils.text.JsonWriter; | import org.sonar.api.utils.text.JsonWriter; | ||||
import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; | import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY; | ||||
json.beginObject(); | json.beginObject(); | ||||
json.prop("id", statistics.getServerId()); | json.prop("id", statistics.getServerId()); | ||||
json.prop("version", statistics.getVersion()); | json.prop("version", statistics.getVersion()); | ||||
statistics.getEdition().ifPresent(e -> json.prop("edition", e.name().toLowerCase(Locale.ENGLISH))); | |||||
json.name("database"); | json.name("database"); | ||||
json.beginObject(); | json.beginObject(); | ||||
json.prop("name", statistics.getDatabase().getName()); | json.prop("name", statistics.getDatabase().getName()); |
import org.sonar.api.ce.ComputeEngineSide; | import org.sonar.api.ce.ComputeEngineSide; | ||||
import org.sonar.api.platform.Server; | import org.sonar.api.platform.Server; | ||||
import org.sonar.api.server.ServerSide; | import org.sonar.api.server.ServerSide; | ||||
import org.sonar.core.platform.PlatformEditionProvider; | |||||
import org.sonar.core.platform.PluginInfo; | import org.sonar.core.platform.PluginInfo; | ||||
import org.sonar.core.platform.PluginRepository; | import org.sonar.core.platform.PluginRepository; | ||||
import org.sonar.core.util.stream.MoreCollectors; | import org.sonar.core.util.stream.MoreCollectors; | ||||
private final PluginRepository pluginRepository; | private final PluginRepository pluginRepository; | ||||
private final UserIndex userIndex; | private final UserIndex userIndex; | ||||
private final ProjectMeasuresIndex projectMeasuresIndex; | private final ProjectMeasuresIndex projectMeasuresIndex; | ||||
private final PlatformEditionProvider editionProvider; | |||||
public TelemetryDataLoader(Server server, DbClient dbClient, PluginRepository pluginRepository, UserIndex userIndex, ProjectMeasuresIndex projectMeasuresIndex) { | |||||
public TelemetryDataLoader(Server server, DbClient dbClient, PluginRepository pluginRepository, UserIndex userIndex, ProjectMeasuresIndex projectMeasuresIndex, | |||||
PlatformEditionProvider editionProvider) { | |||||
this.server = server; | this.server = server; | ||||
this.dbClient = dbClient; | this.dbClient = dbClient; | ||||
this.pluginRepository = pluginRepository; | this.pluginRepository = pluginRepository; | ||||
this.userIndex = userIndex; | this.userIndex = userIndex; | ||||
this.projectMeasuresIndex = projectMeasuresIndex; | this.projectMeasuresIndex = projectMeasuresIndex; | ||||
this.editionProvider = editionProvider; | |||||
} | } | ||||
public TelemetryData load() { | public TelemetryData load() { | ||||
data.setServerId(server.getId()); | data.setServerId(server.getId()); | ||||
data.setVersion(server.getVersion()); | data.setVersion(server.getVersion()); | ||||
data.setEdition(editionProvider.get()); | |||||
Function<PluginInfo, String> getVersion = plugin -> plugin.getVersion() == null ? "undefined" : plugin.getVersion().getName(); | 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)); | Map<String, String> plugins = pluginRepository.getPluginInfos().stream().collect(MoreCollectors.uniqueIndex(PluginInfo::getKey, getVersion)); | ||||
data.setPlugins(plugins); | data.setPlugins(plugins); |
import java.sql.DatabaseMetaData; | import java.sql.DatabaseMetaData; | ||||
import java.sql.SQLException; | import java.sql.SQLException; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.Optional; | |||||
import java.util.stream.IntStream; | import java.util.stream.IntStream; | ||||
import org.junit.After; | import org.junit.After; | ||||
import org.junit.Rule; | import org.junit.Rule; | ||||
import org.sonar.api.utils.internal.TestSystem2; | import org.sonar.api.utils.internal.TestSystem2; | ||||
import org.sonar.api.utils.log.LogTester; | import org.sonar.api.utils.log.LogTester; | ||||
import org.sonar.api.utils.log.LoggerLevel; | 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.PluginInfo; | ||||
import org.sonar.core.platform.PluginRepository; | import org.sonar.core.platform.PluginRepository; | ||||
import org.sonar.db.DbSession; | import org.sonar.db.DbSession; | ||||
private MapSettings settings = new MapSettings(); | private MapSettings settings = new MapSettings(); | ||||
private ProjectMeasuresIndexer projectMeasuresIndexer = new ProjectMeasuresIndexer(db.getDbClient(), es.client()); | private ProjectMeasuresIndexer projectMeasuresIndexer = new ProjectMeasuresIndexer(db.getDbClient(), es.client()); | ||||
private UserIndexer userIndexer = new UserIndexer(db.getDbClient(), es.client()); | private UserIndexer userIndexer = new UserIndexer(db.getDbClient(), es.client()); | ||||
private PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class); | |||||
private TelemetryDaemon underTest = new TelemetryDaemon(new TelemetryDataLoader(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2), | |||||
new ProjectMeasuresIndex(es.client(), null, system2)), client, settings.asConfig(), internalProperties, system2); | |||||
private final TelemetryDataLoader dataLoader = new TelemetryDataLoader(server, db.getDbClient(), pluginRepository, new UserIndex(es.client(), system2), | |||||
new ProjectMeasuresIndex(es.client(), null, system2), editionProvider); | |||||
private TelemetryDaemon underTest = new TelemetryDaemon(dataLoader, client, settings.asConfig(), internalProperties, system2); | |||||
@After | @After | ||||
public void tearDown() { | public void tearDown() { | ||||
server.setVersion("7.5.4"); | server.setVersion("7.5.4"); | ||||
List<PluginInfo> plugins = asList(newPlugin("java", "4.12.0.11033"), newPlugin("scmgit", "1.2"), new PluginInfo("other")); | List<PluginInfo> plugins = asList(newPlugin("java", "4.12.0.11033"), newPlugin("scmgit", "1.2"), new PluginInfo("other")); | ||||
when(pluginRepository.getPluginInfos()).thenReturn(plugins); | when(pluginRepository.getPluginInfos()).thenReturn(plugins); | ||||
when(editionProvider.get()).thenReturn(Optional.of(EditionProvider.Edition.DEVELOPER)); | |||||
IntStream.range(0, 3).forEach(i -> db.users().insertUser()); | IntStream.range(0, 3).forEach(i -> db.users().insertUser()); | ||||
db.users().insertUser(u -> u.setActive(false)); | db.users().insertUser(u -> u.setActive(false)); | ||||
underTest.start(); | underTest.start(); | ||||
ArgumentCaptor<String> jsonCaptor = ArgumentCaptor.forClass(String.class); | |||||
verify(client, timeout(2_000).atLeastOnce()).upload(jsonCaptor.capture()); | |||||
ArgumentCaptor<String> jsonCaptor = captureJson(); | |||||
String json = jsonCaptor.getValue(); | String json = jsonCaptor.getValue(); | ||||
assertJson(json).ignoreFields("database").isSimilarTo(getClass().getResource("telemetry-example.json")); | assertJson(json).ignoreFields("database").isSimilarTo(getClass().getResource("telemetry-example.json")); | ||||
assertJson(getClass().getResource("telemetry-example.json")).ignoreFields("database").isSimilarTo(json); | assertJson(getClass().getResource("telemetry-example.json")).ignoreFields("database").isSimilarTo(json); | ||||
underTest.start(); | underTest.start(); | ||||
ArgumentCaptor<String> jsonCaptor = ArgumentCaptor.forClass(String.class); | |||||
verify(client, timeout(2_000).atLeastOnce()).upload(jsonCaptor.capture()); | |||||
ArgumentCaptor<String> jsonCaptor = captureJson(); | |||||
assertJson(jsonCaptor.getValue()).isSimilarTo("{\n" + | assertJson(jsonCaptor.getValue()).isSimilarTo("{\n" + | ||||
" \"ncloc\": 20\n" + | " \"ncloc\": 20\n" + | ||||
"}\n"); | "}\n"); | ||||
server.setVersion(version); | server.setVersion(version); | ||||
underTest.start(); | underTest.start(); | ||||
ArgumentCaptor<String> json = ArgumentCaptor.forClass(String.class); | |||||
verify(client, timeout(2_000).atLeastOnce()).upload(json.capture()); | |||||
ArgumentCaptor<String> json = captureJson(); | |||||
assertThat(json.getValue()).contains(id, version); | assertThat(json.getValue()).contains(id, version); | ||||
} | } | ||||
settings.setProperty(SONAR_TELEMETRY_URL.getKey(), SONAR_TELEMETRY_URL.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()); | 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; | |||||
} | |||||
} | } |
{ | { | ||||
"id": "AU-TpxcB-iU5OvuD2FL7", | "id": "AU-TpxcB-iU5OvuD2FL7", | ||||
"version": "7.5.4", | "version": "7.5.4", | ||||
"edition": "developer", | |||||
"database": { | "database": { | ||||
"name": "PostgreSQL", | "name": "PostgreSQL", | ||||
"version": "9.6.5" | "version": "9.6.5" |