]> source.dussan.org Git - sonarqube.git/blob
84c76209d16f20e3062aaea61bfdc830a6b7781d
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2023 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
22 import com.tngtech.java.junit.dataprovider.DataProvider;
23 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
24 import com.tngtech.java.junit.dataprovider.UseDataProvider;
25 import java.sql.DatabaseMetaData;
26 import java.sql.SQLException;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Optional;
30 import java.util.Set;
31 import java.util.function.Consumer;
32 import java.util.function.Function;
33 import java.util.stream.Collectors;
34 import java.util.stream.IntStream;
35 import org.junit.Before;
36 import org.junit.Rule;
37 import org.junit.Test;
38 import org.junit.runner.RunWith;
39 import org.sonar.api.config.Configuration;
40 import org.sonar.api.impl.utils.TestSystem2;
41 import org.sonar.core.platform.PlatformEditionProvider;
42 import org.sonar.core.platform.PluginInfo;
43 import org.sonar.core.platform.PluginRepository;
44 import org.sonar.db.DbSession;
45 import org.sonar.db.DbTester;
46 import org.sonar.db.alm.setting.AlmSettingDto;
47 import org.sonar.db.component.AnalysisPropertyDto;
48 import org.sonar.db.component.ComponentDto;
49 import org.sonar.db.component.SnapshotDto;
50 import org.sonar.db.metric.MetricDto;
51 import org.sonar.db.newcodeperiod.NewCodePeriodType;
52 import org.sonar.db.qualitygate.QualityGateDto;
53 import org.sonar.db.user.UserDbTester;
54 import org.sonar.db.user.UserDto;
55 import org.sonar.db.user.UserTelemetryDto;
56 import org.sonar.server.management.ManagedInstanceService;
57 import org.sonar.server.platform.DockerSupport;
58 import org.sonar.server.property.InternalProperties;
59 import org.sonar.server.property.MapInternalProperties;
60 import org.sonar.server.qualitygate.QualityGateCaycChecker;
61 import org.sonar.server.qualitygate.QualityGateFinder;
62 import org.sonar.server.telemetry.TelemetryData.NewCodeDefinition;
63 import org.sonar.server.telemetry.TelemetryData.ProjectStatistics;
64 import org.sonar.updatecenter.common.Version;
65
66 import static java.util.Arrays.asList;
67 import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
68 import static org.assertj.core.api.Assertions.assertThat;
69 import static org.assertj.core.api.Assertions.entry;
70 import static org.assertj.core.groups.Tuple.tuple;
71 import static org.mockito.ArgumentMatchers.any;
72 import static org.mockito.Mockito.mock;
73 import static org.mockito.Mockito.spy;
74 import static org.mockito.Mockito.when;
75 import static org.sonar.api.measures.CoreMetrics.BUGS_KEY;
76 import static org.sonar.api.measures.CoreMetrics.COVERAGE_KEY;
77 import static org.sonar.api.measures.CoreMetrics.DEVELOPMENT_COST_KEY;
78 import static org.sonar.api.measures.CoreMetrics.LINES_KEY;
79 import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
80 import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY;
81 import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY;
82 import static org.sonar.api.measures.CoreMetrics.TECHNICAL_DEBT_KEY;
83 import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES_KEY;
84 import static org.sonar.core.config.CorePropertyDefinitions.SONAR_ANALYSIS_DETECTEDCI;
85 import static org.sonar.core.config.CorePropertyDefinitions.SONAR_ANALYSIS_DETECTEDSCM;
86 import static org.sonar.core.platform.EditionProvider.Edition.COMMUNITY;
87 import static org.sonar.core.platform.EditionProvider.Edition.DEVELOPER;
88 import static org.sonar.core.platform.EditionProvider.Edition.ENTERPRISE;
89 import static org.sonar.db.component.BranchType.BRANCH;
90 import static org.sonar.server.metric.UnanalyzedLanguageMetrics.UNANALYZED_CPP_KEY;
91 import static org.sonar.server.metric.UnanalyzedLanguageMetrics.UNANALYZED_C_KEY;
92 import static org.sonar.server.qualitygate.QualityGateCaycStatus.NON_COMPLIANT;
93
94 @RunWith(DataProviderRunner.class)
95 public class TelemetryDataLoaderImplTest {
96   private final static Long NOW = 100_000_000L;
97   private final TestSystem2 system2 = new TestSystem2().setNow(NOW);
98
99   @Rule
100   public DbTester db = DbTester.create(system2);
101
102   private final FakeServer server = new FakeServer();
103   private final PluginRepository pluginRepository = mock(PluginRepository.class);
104   private final Configuration configuration = mock(Configuration.class);
105   private final PlatformEditionProvider editionProvider = mock(PlatformEditionProvider.class);
106   private final DockerSupport dockerSupport = mock(DockerSupport.class);
107   private final QualityGateCaycChecker qualityGateCaycChecker = mock(QualityGateCaycChecker.class);
108   private final QualityGateFinder qualityGateFinder = new QualityGateFinder(db.getDbClient());
109   private final InternalProperties internalProperties = spy(new MapInternalProperties());
110   private final ManagedInstanceService managedInstanceService = mock(ManagedInstanceService.class);
111
112   private final TelemetryDataLoader communityUnderTest = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, editionProvider,
113     internalProperties, configuration, dockerSupport, qualityGateCaycChecker, qualityGateFinder, managedInstanceService);
114   private final TelemetryDataLoader commercialUnderTest = new TelemetryDataLoaderImpl(server, db.getDbClient(), pluginRepository, editionProvider,
115     internalProperties, configuration, dockerSupport, qualityGateCaycChecker, qualityGateFinder, managedInstanceService);
116
117   private QualityGateDto builtInDefaultQualityGate;
118   private MetricDto bugsDto;
119   private MetricDto vulnerabilitiesDto;
120   private MetricDto securityHotspotsDto;
121   private MetricDto technicalDebtDto;
122   private MetricDto developmentCostDto;
123
124   @Before
125   public void setUpBuiltInQualityGate() {
126     String builtInQgName = "Sonar Way";
127     builtInDefaultQualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName(builtInQgName).setBuiltIn(true));
128     when(qualityGateCaycChecker.checkCaycCompliant(any(), any())).thenReturn(NON_COMPLIANT);
129     db.qualityGates().setDefaultQualityGate(builtInDefaultQualityGate);
130
131     bugsDto = db.measures().insertMetric(m -> m.setKey(BUGS_KEY));
132     vulnerabilitiesDto = db.measures().insertMetric(m -> m.setKey(VULNERABILITIES_KEY));
133     securityHotspotsDto = db.measures().insertMetric(m -> m.setKey(SECURITY_HOTSPOTS_KEY));
134     technicalDebtDto = db.measures().insertMetric(m -> m.setKey(TECHNICAL_DEBT_KEY));
135     developmentCostDto = db.measures().insertMetric(m -> m.setKey(DEVELOPMENT_COST_KEY));
136   }
137
138   @Test
139   public void send_telemetry_data() {
140     String serverId = "AU-TpxcB-iU5OvuD2FL7";
141     String version = "7.5.4";
142     Long analysisDate = 1L;
143     Long lastConnectionDate = 5L;
144
145     server.setId(serverId);
146     server.setVersion(version);
147     List<PluginInfo> plugins = asList(newPlugin("java", "4.12.0.11033"), newPlugin("scmgit", "1.2"), new PluginInfo("other"));
148     when(pluginRepository.getPluginInfos()).thenReturn(plugins);
149     when(editionProvider.get()).thenReturn(Optional.of(DEVELOPER));
150
151     List<UserDto> activeUsers = composeActiveUsers(3);
152
153     // update last connection
154     activeUsers.forEach(u -> db.users().updateLastConnectionDate(u, 5L));
155
156     UserDto inactiveUser = db.users().insertUser(u -> u.setActive(false).setExternalIdentityProvider("provider0"));
157
158     MetricDto lines = db.measures().insertMetric(m -> m.setKey(LINES_KEY));
159     MetricDto ncloc = db.measures().insertMetric(m -> m.setKey(NCLOC_KEY));
160     MetricDto coverage = db.measures().insertMetric(m -> m.setKey(COVERAGE_KEY));
161     MetricDto nclocDistrib = db.measures().insertMetric(m -> m.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY));
162
163     ComponentDto project1 = db.components().insertPrivateProject().getMainBranchComponent();
164     db.measures().insertLiveMeasure(project1, lines, m -> m.setValue(110d));
165     db.measures().insertLiveMeasure(project1, ncloc, m -> m.setValue(110d));
166     db.measures().insertLiveMeasure(project1, coverage, m -> m.setValue(80d));
167     db.measures().insertLiveMeasure(project1, nclocDistrib, m -> m.setValue(null).setData("java=70;js=30;kotlin=10"));
168     db.measures().insertLiveMeasure(project1, bugsDto, m -> m.setValue(1d));
169     db.measures().insertLiveMeasure(project1, vulnerabilitiesDto, m -> m.setValue(1d).setData((String) null));
170     db.measures().insertLiveMeasure(project1, securityHotspotsDto, m -> m.setValue(1d).setData((String) null));
171     db.measures().insertLiveMeasure(project1, developmentCostDto, m -> m.setData("50").setValue(null));
172     db.measures().insertLiveMeasure(project1, technicalDebtDto, m -> m.setValue(5d).setData((String) null));
173
174     ComponentDto project2 = db.components().insertPrivateProject().getMainBranchComponent();
175     db.measures().insertLiveMeasure(project2, lines, m -> m.setValue(200d));
176     db.measures().insertLiveMeasure(project2, ncloc, m -> m.setValue(200d));
177     db.measures().insertLiveMeasure(project2, coverage, m -> m.setValue(80d));
178     db.measures().insertLiveMeasure(project2, nclocDistrib, m -> m.setValue(null).setData("java=180;js=20"));
179
180     SnapshotDto project1Analysis = db.components().insertSnapshot(project1, t -> t.setLast(true).setBuildDate(analysisDate));
181     SnapshotDto project2Analysis = db.components().insertSnapshot(project2, t -> t.setLast(true).setBuildDate(analysisDate));
182     db.measures().insertMeasure(project1, project1Analysis, nclocDistrib, m -> m.setData("java=70;js=30;kotlin=10"));
183     db.measures().insertMeasure(project2, project2Analysis, nclocDistrib, m -> m.setData("java=180;js=20"));
184
185     insertAnalysisProperty(project1Analysis, "prop-uuid-1", SONAR_ANALYSIS_DETECTEDCI, "ci-1");
186     insertAnalysisProperty(project2Analysis, "prop-uuid-2", SONAR_ANALYSIS_DETECTEDCI, "ci-2");
187     insertAnalysisProperty(project1Analysis, "prop-uuid-3", SONAR_ANALYSIS_DETECTEDSCM, "scm-1");
188     insertAnalysisProperty(project2Analysis, "prop-uuid-4", SONAR_ANALYSIS_DETECTEDSCM, "scm-2");
189
190     // alm
191     db.almSettings().insertAzureAlmSetting();
192     db.almSettings().insertGitHubAlmSetting();
193     AlmSettingDto almSettingDto = db.almSettings().insertAzureAlmSetting(a -> a.setUrl("https://dev.azure.com"));
194     AlmSettingDto gitHubAlmSetting = db.almSettings().insertGitHubAlmSetting(a -> a.setUrl("https://api.github.com"));
195     db.almSettings().insertAzureProjectAlmSetting(almSettingDto, db.components().getProjectDtoByMainBranch(project1));
196     db.almSettings().insertGitlabProjectAlmSetting(gitHubAlmSetting, db.components().getProjectDtoByMainBranch(project2));
197
198     // quality gates
199     QualityGateDto qualityGate1 = db.qualityGates().insertQualityGate(qg -> qg.setName("QG1").setBuiltIn(true));
200     QualityGateDto qualityGate2 = db.qualityGates().insertQualityGate(qg -> qg.setName("QG2"));
201
202     // link one project to a non-default QG
203     db.qualityGates().associateProjectToQualityGate(db.components().getProjectDtoByMainBranch(project1), qualityGate1);
204
205     var branch1 = db.components().insertProjectBranch(project1, branchDto -> branchDto.setKey("reference"));
206     var branch2 = db.components().insertProjectBranch(project1, branchDto -> branchDto.setKey("custom"));
207
208     var ncd1 = db.newCodePeriods().insert(project1.uuid(), NewCodePeriodType.NUMBER_OF_DAYS, "30");
209     var ncd2 = db.newCodePeriods().insert(project1.uuid(), branch2.branchUuid(), NewCodePeriodType.REFERENCE_BRANCH, "reference");
210
211     var instanceNcdId = NewCodeDefinition.getInstanceDefault().hashCode();
212     var projectNcdId = new NewCodeDefinition(NewCodePeriodType.NUMBER_OF_DAYS.name(), "30", "project").hashCode();
213     var branchNcdId = new NewCodeDefinition(NewCodePeriodType.REFERENCE_BRANCH.name(), branch1.uuid(), "branch").hashCode();
214
215     TelemetryData data = communityUnderTest.load();
216     assertThat(data.getServerId()).isEqualTo(serverId);
217     assertThat(data.getVersion()).isEqualTo(version);
218     assertThat(data.getEdition()).contains(DEVELOPER);
219     assertThat(data.getDefaultQualityGate()).isEqualTo(builtInDefaultQualityGate.getUuid());
220     assertThat(data.getNcdId()).isEqualTo(NewCodeDefinition.getInstanceDefault().hashCode());
221     assertThat(data.getMessageSequenceNumber()).isOne();
222     assertDatabaseMetadata(data.getDatabase());
223     assertThat(data.getPlugins()).containsOnly(
224       entry("java", "4.12.0.11033"), entry("scmgit", "1.2"), entry("other", "undefined"));
225     assertThat(data.isInDocker()).isFalse();
226
227     assertThat(data.getUserTelemetries())
228       .extracting(UserTelemetryDto::getUuid, UserTelemetryDto::getLastConnectionDate, UserTelemetryDto::getLastSonarlintConnectionDate, UserTelemetryDto::isActive)
229       .containsExactlyInAnyOrder(
230         tuple(activeUsers.get(0).getUuid(), lastConnectionDate, activeUsers.get(0).getLastSonarlintConnectionDate(), true),
231         tuple(activeUsers.get(1).getUuid(), lastConnectionDate, activeUsers.get(1).getLastSonarlintConnectionDate(), true),
232         tuple(activeUsers.get(2).getUuid(), lastConnectionDate, activeUsers.get(2).getLastSonarlintConnectionDate(), true),
233         tuple(inactiveUser.getUuid(), null, inactiveUser.getLastSonarlintConnectionDate(), false));
234     assertThat(data.getProjects())
235       .extracting(TelemetryData.Project::projectUuid, TelemetryData.Project::language, TelemetryData.Project::loc, TelemetryData.Project::lastAnalysis)
236       .containsExactlyInAnyOrder(
237         tuple(project1.uuid(), "java", 70L, analysisDate),
238         tuple(project1.uuid(), "js", 30L, analysisDate),
239         tuple(project1.uuid(), "kotlin", 10L, analysisDate),
240         tuple(project2.uuid(), "java", 180L, analysisDate),
241         tuple(project2.uuid(), "js", 20L, analysisDate));
242     assertThat(data.getProjectStatistics())
243       .extracting(ProjectStatistics::getBranchCount, ProjectStatistics::getPullRequestCount, ProjectStatistics::getQualityGate,
244         ProjectStatistics::getScm, ProjectStatistics::getCi, ProjectStatistics::getDevopsPlatform,
245         ProjectStatistics::getBugs, ProjectStatistics::getVulnerabilities, ProjectStatistics::getSecurityHotspots,
246         ProjectStatistics::getDevelopmentCost, ProjectStatistics::getTechnicalDebt, ProjectStatistics::getNcdId)
247       .containsExactlyInAnyOrder(
248         tuple(3L, 0L, qualityGate1.getUuid(), "scm-1", "ci-1", "azure_devops_cloud", Optional.of(1L), Optional.of(1L), Optional.of(1L), Optional.of(50L), Optional.of(5L),
249           projectNcdId),
250         tuple(1L, 0L, builtInDefaultQualityGate.getUuid(), "scm-2", "ci-2", "github_cloud", Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(),
251           Optional.empty(), instanceNcdId));
252
253     assertThat(data.getBranches())
254       .extracting(TelemetryData.Branch::branchUuid, TelemetryData.Branch::ncdId)
255       .containsExactlyInAnyOrder(
256         tuple(branch1.uuid(), projectNcdId),
257         tuple(branch2.uuid(), branchNcdId),
258         tuple(project1.uuid(), projectNcdId),
259         tuple(project2.uuid(), instanceNcdId));
260
261     assertThat(data.getNewCodeDefinitions())
262       .extracting(NewCodeDefinition::scope, NewCodeDefinition::type, NewCodeDefinition::value)
263       .containsExactlyInAnyOrder(
264         tuple("instance", NewCodePeriodType.PREVIOUS_VERSION.name(), ""),
265         tuple("project", NewCodePeriodType.NUMBER_OF_DAYS.name(), "30"),
266         tuple("branch", NewCodePeriodType.REFERENCE_BRANCH.name(), branch1.uuid()));
267
268     assertThat(data.getQualityGates())
269       .extracting(TelemetryData.QualityGate::uuid, TelemetryData.QualityGate::caycStatus)
270       .containsExactlyInAnyOrder(
271         tuple(builtInDefaultQualityGate.getUuid(), "non-compliant"),
272         tuple(qualityGate1.getUuid(), "non-compliant"),
273         tuple(qualityGate2.getUuid(), "non-compliant")
274       );
275   }
276
277   private List<UserDto> composeActiveUsers(int count) {
278     UserDbTester userDbTester = db.users();
279     Function<Integer, Consumer<UserDto>> userConfigurator = index -> user -> user.setExternalIdentityProvider("provider" + index).setLastSonarlintConnectionDate(index * 2L);
280
281     return IntStream
282       .rangeClosed(1, count)
283       .mapToObj(userConfigurator::apply)
284       .map(userDbTester::insertUser)
285       .collect(Collectors.toList());
286   }
287
288   private void assertDatabaseMetadata(TelemetryData.Database database) {
289     try (DbSession dbSession = db.getDbClient().openSession(false)) {
290       DatabaseMetaData metadata = dbSession.getConnection().getMetaData();
291       assertThat(database.name()).isEqualTo("H2");
292       assertThat(database.version()).isEqualTo(metadata.getDatabaseProductVersion());
293     } catch (SQLException e) {
294       throw new RuntimeException(e);
295     }
296   }
297
298   @Test
299   public void take_largest_branch_snapshot_project_data() {
300     server.setId("AU-TpxcB-iU5OvuD2FL7").setVersion("7.5.4");
301
302     MetricDto lines = db.measures().insertMetric(m -> m.setKey(LINES_KEY));
303     MetricDto ncloc = db.measures().insertMetric(m -> m.setKey(NCLOC_KEY));
304     MetricDto coverage = db.measures().insertMetric(m -> m.setKey(COVERAGE_KEY));
305     MetricDto nclocDistrib = db.measures().insertMetric(m -> m.setKey(NCLOC_LANGUAGE_DISTRIBUTION_KEY));
306
307     ComponentDto project = db.components().insertPublicProject().getMainBranchComponent();
308     db.measures().insertLiveMeasure(project, lines, m -> m.setValue(110d));
309     db.measures().insertLiveMeasure(project, ncloc, m -> m.setValue(110d));
310     db.measures().insertLiveMeasure(project, coverage, m -> m.setValue(80d));
311     db.measures().insertLiveMeasure(project, nclocDistrib, m -> m.setValue(null).setData("java=70;js=30;kotlin=10"));
312
313     ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH));
314     db.measures().insertLiveMeasure(branch, lines, m -> m.setValue(180d));
315     db.measures().insertLiveMeasure(branch, ncloc, m -> m.setValue(180d));
316     db.measures().insertLiveMeasure(branch, coverage, m -> m.setValue(80d));
317     db.measures().insertLiveMeasure(branch, nclocDistrib, m -> m.setValue(null).setData("java=100;js=50;kotlin=30"));
318
319     SnapshotDto project1Analysis = db.components().insertSnapshot(project, t -> t.setLast(true));
320     SnapshotDto project2Analysis = db.components().insertSnapshot(branch, t -> t.setLast(true));
321     db.measures().insertMeasure(project, project1Analysis, nclocDistrib, m -> m.setData("java=70;js=30;kotlin=10"));
322     db.measures().insertMeasure(branch, project2Analysis, nclocDistrib, m -> m.setData("java=100;js=50;kotlin=30"));
323
324     TelemetryData data = communityUnderTest.load();
325
326     assertThat(data.getProjects()).extracting(TelemetryData.Project::projectUuid, TelemetryData.Project::language, TelemetryData.Project::loc)
327       .containsExactlyInAnyOrder(
328         tuple(project.uuid(), "java", 100L),
329         tuple(project.uuid(), "js", 50L),
330         tuple(project.uuid(), "kotlin", 30L));
331     assertThat(data.getProjectStatistics())
332       .extracting(ProjectStatistics::getBranchCount, ProjectStatistics::getPullRequestCount,
333         ProjectStatistics::getScm, ProjectStatistics::getCi)
334       .containsExactlyInAnyOrder(
335         tuple(2L, 0L, "undetected", "undetected"));
336   }
337
338   @Test
339   public void test_ncd_on_community_edition() {
340     server.setId("AU-TpxcB-iU5OvuD2FL7").setVersion("7.5.4");
341     when(editionProvider.get()).thenReturn(Optional.of(COMMUNITY));
342
343     ComponentDto project = db.components().insertPublicProject().getMainBranchComponent();
344
345     ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH));
346
347     db.newCodePeriods().insert(project.uuid(), branch.branchUuid(), NewCodePeriodType.NUMBER_OF_DAYS, "30");
348
349     var projectNcdId = new NewCodeDefinition(NewCodePeriodType.NUMBER_OF_DAYS.name(), "30", "project").hashCode();
350
351     TelemetryData data = communityUnderTest.load();
352
353     assertThat(data.getProjectStatistics())
354       .extracting(ProjectStatistics::getBranchCount, ProjectStatistics::getNcdId)
355       .containsExactlyInAnyOrder(tuple(2L, projectNcdId));
356
357     assertThat(data.getBranches())
358       .extracting(TelemetryData.Branch::branchUuid, TelemetryData.Branch::ncdId)
359       .contains(tuple(branch.uuid(), projectNcdId));
360   }
361
362   @Test
363   public void data_contains_weekly_count_sonarlint_users() {
364     db.users().insertUser(c -> c.setLastSonarlintConnectionDate(NOW - 100_000L));
365     db.users().insertUser(c -> c.setLastSonarlintConnectionDate(NOW));
366     // these don't count
367     db.users().insertUser(c -> c.setLastSonarlintConnectionDate(NOW - 1_000_000_000L));
368     db.users().insertUser();
369
370     TelemetryData data = communityUnderTest.load();
371     assertThat(data.getUserTelemetries())
372       .hasSize(4);
373   }
374
375   @Test
376   public void send_server_id_and_version() {
377     String id = randomAlphanumeric(40);
378     String version = randomAlphanumeric(10);
379     server.setId(id);
380     server.setVersion(version);
381
382     TelemetryData data = communityUnderTest.load();
383     assertThat(data.getServerId()).isEqualTo(id);
384     assertThat(data.getVersion()).isEqualTo(version);
385
386     data = commercialUnderTest.load();
387     assertThat(data.getServerId()).isEqualTo(id);
388     assertThat(data.getVersion()).isEqualTo(version);
389   }
390
391   @Test
392   public void send_server_installation_date_and_installation_version() {
393     String installationVersion = "7.9.BEST.LTS.EVER";
394     Long installationDate = 1546300800000L; // 2019/01/01
395     internalProperties.write(InternalProperties.INSTALLATION_DATE, String.valueOf(installationDate));
396     internalProperties.write(InternalProperties.INSTALLATION_VERSION, installationVersion);
397
398     TelemetryData data = communityUnderTest.load();
399
400     assertThat(data.getInstallationDate()).isEqualTo(installationDate);
401     assertThat(data.getInstallationVersion()).isEqualTo(installationVersion);
402   }
403
404   @Test
405   public void send_correct_sequence_number() {
406     internalProperties.write(TelemetryDaemon.I_PROP_MESSAGE_SEQUENCE, "10");
407     TelemetryData data = communityUnderTest.load();
408     assertThat(data.getMessageSequenceNumber()).isEqualTo(11L);
409   }
410
411   @Test
412   public void do_not_send_server_installation_details_if_missing_property() {
413     TelemetryData data = communityUnderTest.load();
414     assertThat(data.getInstallationDate()).isNull();
415     assertThat(data.getInstallationVersion()).isNull();
416
417     data = commercialUnderTest.load();
418     assertThat(data.getInstallationDate()).isNull();
419     assertThat(data.getInstallationVersion()).isNull();
420   }
421
422   @Test
423   public void send_unanalyzed_languages_flags_when_edition_is_community() {
424     when(editionProvider.get()).thenReturn(Optional.of(COMMUNITY));
425     MetricDto unanalyzedC = db.measures().insertMetric(m -> m.setKey(UNANALYZED_C_KEY));
426     MetricDto unanalyzedCpp = db.measures().insertMetric(m -> m.setKey(UNANALYZED_CPP_KEY));
427     ComponentDto project1 = db.components().insertPublicProject().getMainBranchComponent();
428     ComponentDto project2 = db.components().insertPublicProject().getMainBranchComponent();
429     db.measures().insertLiveMeasure(project1, unanalyzedC);
430     db.measures().insertLiveMeasure(project2, unanalyzedC);
431     db.measures().insertLiveMeasure(project2, unanalyzedCpp);
432
433     TelemetryData data = communityUnderTest.load();
434
435     assertThat(data.hasUnanalyzedC().get()).isTrue();
436     assertThat(data.hasUnanalyzedCpp().get()).isTrue();
437   }
438
439   @Test
440   public void do_not_send_unanalyzed_languages_flags_when_edition_is_not_community() {
441     when(editionProvider.get()).thenReturn(Optional.of(DEVELOPER));
442     MetricDto unanalyzedC = db.measures().insertMetric(m -> m.setKey(UNANALYZED_C_KEY));
443     MetricDto unanalyzedCpp = db.measures().insertMetric(m -> m.setKey(UNANALYZED_CPP_KEY));
444     ComponentDto project1 = db.components().insertPublicProject().getMainBranchComponent();
445     ComponentDto project2 = db.components().insertPublicProject().getMainBranchComponent();
446     db.measures().insertLiveMeasure(project1, unanalyzedC);
447     db.measures().insertLiveMeasure(project2, unanalyzedCpp);
448
449     TelemetryData data = communityUnderTest.load();
450
451     assertThat(data.hasUnanalyzedC()).isEmpty();
452     assertThat(data.hasUnanalyzedCpp()).isEmpty();
453   }
454
455   @Test
456   public void unanalyzed_languages_flags_are_set_to_false_when_no_unanalyzed_languages_and_edition_is_community() {
457     when(editionProvider.get()).thenReturn(Optional.of(COMMUNITY));
458
459     TelemetryData data = communityUnderTest.load();
460
461     assertThat(data.hasUnanalyzedC().get()).isFalse();
462     assertThat(data.hasUnanalyzedCpp().get()).isFalse();
463   }
464
465   @Test
466   public void populate_security_custom_config_for_languages_on_enterprise() {
467     when(editionProvider.get()).thenReturn(Optional.of(ENTERPRISE));
468
469     when(configuration.get("sonar.security.config.javasecurity")).thenReturn(Optional.of("{}"));
470     when(configuration.get("sonar.security.config.phpsecurity")).thenReturn(Optional.of("{}"));
471     when(configuration.get("sonar.security.config.pythonsecurity")).thenReturn(Optional.of("{}"));
472     when(configuration.get("sonar.security.config.roslyn.sonaranalyzer.security.cs")).thenReturn(Optional.of("{}"));
473
474     TelemetryData data = commercialUnderTest.load();
475
476     assertThat(data.getCustomSecurityConfigs())
477       .containsExactlyInAnyOrder("java", "php", "python", "csharp");
478   }
479
480   @Test
481   public void skip_security_custom_config_on_community() {
482     when(editionProvider.get()).thenReturn(Optional.of(COMMUNITY));
483
484     TelemetryData data = communityUnderTest.load();
485
486     assertThat(data.getCustomSecurityConfigs()).isEmpty();
487   }
488
489   @Test
490   public void undetected_alm_ci_slm_data() {
491     server.setId("AU-TpxcB-iU5OvuD2FL7").setVersion("7.5.4");
492     db.components().insertPublicProject().getMainBranchComponent();
493     TelemetryData data = communityUnderTest.load();
494     assertThat(data.getProjectStatistics())
495       .extracting(ProjectStatistics::getDevopsPlatform, ProjectStatistics::getScm, ProjectStatistics::getCi)
496       .containsExactlyInAnyOrder(tuple("undetected", "undetected", "undetected"));
497   }
498
499   @Test
500   @UseDataProvider("getManagedInstanceData")
501   public void managedInstanceData_containsCorrectInformation(boolean isManaged, String provider) {
502     when(managedInstanceService.isInstanceExternallyManaged()).thenReturn(isManaged);
503     when(managedInstanceService.getProviderName()).thenReturn(provider);
504
505     TelemetryData data = commercialUnderTest.load();
506
507     TelemetryData.ManagedInstanceInformation managedInstance = data.getManagedInstanceInformation();
508     assertThat(managedInstance.isManaged()).isEqualTo(isManaged);
509     assertThat(managedInstance.provider()).isEqualTo(provider);
510   }
511
512   @Test
513   public void default_quality_gate_sent_with_project() {
514     db.components().insertPublicProject().getMainBranchComponent();
515     QualityGateDto qualityGate = db.qualityGates().insertQualityGate(qg -> qg.setName("anything").setBuiltIn(true));
516     db.qualityGates().setDefaultQualityGate(qualityGate);
517     TelemetryData data = communityUnderTest.load();
518     assertThat(data.getProjectStatistics())
519       .extracting(ProjectStatistics::getQualityGate)
520       .containsOnly(qualityGate.getUuid());
521   }
522
523   private PluginInfo newPlugin(String key, String version) {
524     return new PluginInfo(key)
525       .setVersion(Version.create(version));
526   }
527
528   private void insertAnalysisProperty(SnapshotDto snapshotDto, String uuid, String key, String value) {
529     db.getDbClient().analysisPropertiesDao().insert(db.getSession(), new AnalysisPropertyDto()
530       .setUuid(uuid)
531       .setAnalysisUuid(snapshotDto.getUuid())
532       .setKey(key)
533       .setValue(value)
534       .setCreatedAt(1L));
535   }
536
537   @DataProvider
538   public static Set<String> getScimFeatureStatues() {
539     HashSet<String> result = new HashSet<>();
540     result.add("true");
541     result.add("false");
542     result.add(null);
543     return result;
544   }
545
546   @DataProvider
547   public static Object[][] getManagedInstanceData() {
548     return new Object[][] {
549       {true, "scim"},
550       {true, "github"},
551       {true, "gitlab"},
552       {false, null},
553     };
554   }
555 }