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