3 * Copyright (C) 2009-2022 SonarSource SA
4 * mailto:info AT sonarsource DOT com
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.
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.
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.
20 package org.sonar.server.telemetry;
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.io.StringWriter;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Locale;
31 import java.util.Random;
32 import java.util.stream.Collectors;
33 import java.util.stream.IntStream;
34 import org.apache.commons.codec.digest.DigestUtils;
35 import org.jetbrains.annotations.NotNull;
36 import org.junit.Test;
37 import org.junit.runner.RunWith;
38 import org.sonar.api.utils.text.JsonWriter;
39 import org.sonar.core.platform.EditionProvider;
40 import org.sonar.core.util.stream.MoreCollectors;
41 import org.sonar.db.user.UserTelemetryDto;
43 import static java.util.stream.Collectors.joining;
44 import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
45 import static org.assertj.core.api.Assertions.assertThat;
46 import static org.sonar.test.JsonAssert.assertJson;
48 @RunWith(DataProviderRunner.class)
49 public class TelemetryDataJsonWriterTest {
51 private final Random random = new Random();
53 private final TelemetryDataJsonWriter underTest = new TelemetryDataJsonWriter();
56 public void write_server_id_and_version() {
57 TelemetryData data = telemetryBuilder().build();
59 String json = writeTelemetryData(data);
61 assertJson(json).isSimilarTo("{" +
62 " \"id\": \"" + data.getServerId() + "\"," +
63 " \"version\": \"" + data.getVersion() + "\"" +
68 public void does_not_write_edition_if_null() {
69 TelemetryData data = telemetryBuilder().build();
71 String json = writeTelemetryData(data);
73 assertThat(json).doesNotContain("edition");
77 @UseDataProvider("allEditions")
78 public void writes_edition_if_non_null(EditionProvider.Edition edition) {
79 TelemetryData data = telemetryBuilder()
83 String json = writeTelemetryData(data);
85 assertJson(json).isSimilarTo("{" +
86 " \"edition\": \"" + edition.name().toLowerCase(Locale.ENGLISH) + "\"" +
91 public void does_not_write_license_type_if_null() {
92 TelemetryData data = telemetryBuilder().build();
94 String json = writeTelemetryData(data);
96 assertThat(json).doesNotContain("licenseType");
100 public void writes_licenseType_if_non_null() {
101 String expected = randomAlphabetic(12);
102 TelemetryData data = telemetryBuilder()
103 .setLicenseType(expected)
106 String json = writeTelemetryData(data);
108 assertJson(json).isSimilarTo("{" +
109 " \"licenseType\": \"" + expected + "\"" +
114 public void writes_database() {
115 String name = randomAlphabetic(12);
116 String version = randomAlphabetic(10);
117 TelemetryData data = telemetryBuilder()
118 .setDatabase(new TelemetryData.Database(name, version))
121 String json = writeTelemetryData(data);
123 assertJson(json).isSimilarTo("{" +
125 " \"name\": \"" + name + "\"," +
126 " \"version\": \"" + version + "\"" +
132 public void writes_no_plugins() {
133 TelemetryData data = telemetryBuilder()
134 .setPlugins(Collections.emptyMap())
137 String json = writeTelemetryData(data);
139 assertJson(json).isSimilarTo("{" +
145 public void writes_all_plugins() {
146 Map<String, String> plugins = IntStream.range(0, 1 + random.nextInt(10))
148 .collect(MoreCollectors.uniqueIndex(i -> "P" + i, i -> "V" + i));
149 TelemetryData data = telemetryBuilder()
153 String json = writeTelemetryData(data);
155 assertJson(json).isSimilarTo("{" +
158 plugins.entrySet().stream().map(e -> "{\"name\":\"" + e.getKey() + "\",\"version\":\"" + e.getValue() + "\"}").collect(joining(",")) +
164 public void does_not_write_installation_date_if_null() {
165 TelemetryData data = telemetryBuilder()
166 .setInstallationDate(null)
169 String json = writeTelemetryData(data);
171 assertThat(json).doesNotContain("installationDate");
175 public void write_installation_date_in_utc_format() {
176 TelemetryData data = telemetryBuilder()
177 .setInstallationDate(1_000L)
180 String json = writeTelemetryData(data);
182 assertJson(json).isSimilarTo("{" +
183 " \"installationDate\":\"1970-01-01T00:00:01+0000\"," +
188 public void does_not_write_installation_version_if_null() {
189 TelemetryData data = telemetryBuilder()
190 .setInstallationVersion(null)
193 String json = writeTelemetryData(data);
195 assertThat(json).doesNotContain("installationVersion");
199 public void write_installation_version() {
200 String installationVersion = randomAlphabetic(5);
201 TelemetryData data = telemetryBuilder()
202 .setInstallationVersion(installationVersion)
205 String json = writeTelemetryData(data);
207 assertJson(json).isSimilarTo("{" +
208 " \"installationVersion\":\"" + installationVersion + "\"" +
213 public void write_docker_flag() {
214 boolean inDocker = random.nextBoolean();
215 TelemetryData data = telemetryBuilder()
216 .setInDocker(inDocker)
219 String json = writeTelemetryData(data);
221 assertJson(json).isSimilarTo("{" +
222 " \"docker\":" + inDocker +
227 public void writes_security_custom_config() {
228 TelemetryData data = telemetryBuilder()
229 .setCustomSecurityConfigs(Arrays.asList("php", "java"))
232 String json = writeTelemetryData(data);
234 assertJson(json).isSimilarTo("{" +
235 " \"customSecurityConfig\": [\"php\", \"java\"]" +
240 public void writes_all_users_with_anonymous_md5_uuids() {
241 TelemetryData data = telemetryBuilder()
242 .setUsers(attachUsers())
245 String json = writeTelemetryData(data);
247 assertJson(json).isSimilarTo("{" +
250 " \"userUuid\":\"" + DigestUtils.sha3_224Hex("uuid-0") + "\"," +
251 " \"lastActivity\":\"1970-01-01T00:00:00+0000\"," +
252 " \"identityProvider\":\"gitlab\"," +
253 " \"lastSonarlintActivity\":\"1970-01-01T00:00:00+0000\"," +
254 " \"status\":\"active\"" +
257 " \"userUuid\":\"" + DigestUtils.sha3_224Hex("uuid-1") + "\"," +
258 " \"lastActivity\":\"1970-01-01T00:00:00+0000\"," +
259 " \"identityProvider\":\"gitlab\"," +
260 " \"lastSonarlintActivity\":\"1970-01-01T00:00:00+0000\"," +
261 " \"status\":\"inactive\"" +
264 " \"userUuid\":\"" + DigestUtils.sha3_224Hex("uuid-2") + "\"," +
265 " \"lastActivity\":\"1970-01-01T00:00:00+0000\"," +
266 " \"identityProvider\":\"gitlab\"," +
267 " \"lastSonarlintActivity\":\"1970-01-01T00:00:00+0000\"," +
268 " \"status\":\"active\"" +
275 public void writes_all_projects() {
276 TelemetryData data = telemetryBuilder()
277 .setProjects(attachProjects())
280 String json = writeTelemetryData(data);
282 assertJson(json).isSimilarTo("{" +
285 " \"projectUuid\": \"uuid-0\"," +
286 " \"lastAnalysis\":\"1970-01-01T00:00:00+0000\"," +
287 " \"language\": \"lang-0\"," +
291 " \"projectUuid\": \"uuid-1\"," +
292 " \"lastAnalysis\":\"1970-01-01T00:00:00+0000\"," +
293 " \"language\": \"lang-1\"," +
297 " \"projectUuid\": \"uuid-2\"," +
298 " \"lastAnalysis\":\"1970-01-01T00:00:00+0000\"," +
299 " \"language\": \"lang-2\"," +
307 public void writes_all_projects_stats_with_analyzed_languages() {
308 TelemetryData data = telemetryBuilder()
309 .setProjectStatistics(attachProjectStats(true))
312 String json = writeTelemetryData(data);
314 assertJson(json).isSimilarTo("{" +
315 " \"projects-general-stats\": [" +
317 " \"projectUuid\": \"uuid-0\"," +
318 " \"branchCount\": 2," +
319 " \"pullRequestCount\": 2," +
320 " \"scm\": \"scm-0\"," +
321 " \"ci\": \"ci-0\"," +
322 " \"devopsPlatform\": \"devops-0\"," +
323 " \"hasUnanalyzedC\": true," +
324 " \"hasUnanalyzedCpp\": false" +
327 " \"projectUuid\": \"uuid-1\"," +
328 " \"branchCount\": 4," +
329 " \"pullRequestCount\": 4," +
330 " \"scm\": \"scm-1\"," +
331 " \"ci\": \"ci-1\"," +
332 " \"devopsPlatform\": \"devops-1\"," +
333 " \"hasUnanalyzedC\": false," +
334 " \"hasUnanalyzedCpp\": true" +
337 " \"projectUuid\": \"uuid-2\"," +
338 " \"branchCount\": 6," +
339 " \"pullRequestCount\": 6," +
340 " \"scm\": \"scm-2\"," +
341 " \"ci\": \"ci-2\"," +
342 " \"devopsPlatform\": \"devops-2\"," +
343 " \"hasUnanalyzedC\": true," +
344 " \"hasUnanalyzedCpp\": false" +
351 public void writes_all_projects_stats_with_unanalyzed_languages() {
352 TelemetryData data = telemetryBuilder()
353 .setProjectStatistics(attachProjectStats(false))
356 String json = writeTelemetryData(data);
357 assertThat(json).doesNotContain("hasUnanalyzedC", "hasUnanalyzedCpp");
360 private static TelemetryData.Builder telemetryBuilder() {
361 return TelemetryData.builder()
364 .setPlugins(Collections.emptyMap())
365 .setDatabase(new TelemetryData.Database("H2", "11"));
369 private static List<UserTelemetryDto> attachUsers() {
370 return IntStream.range(0, 3)
372 i -> new UserTelemetryDto().setUuid("uuid-" + i).setActive(i % 2 == 0).setLastConnectionDate(1L).setLastSonarlintConnectionDate(2L).setExternalIdentityProvider("gitlab"))
373 .collect(Collectors.toList());
376 private static List<TelemetryData.Project> attachProjects() {
377 return IntStream.range(0, 3).mapToObj(i -> new TelemetryData.Project("uuid-" + i, 1L, "lang-" + i, (i + 1L) * 2L)).collect(Collectors.toList());
380 private List<TelemetryData.ProjectStatistics> attachProjectStats(boolean hasUnanalyzedLanguages) {
381 return IntStream.range(0, 3).mapToObj(i -> new TelemetryData.ProjectStatistics("uuid-" + i, (i + 1L) * 2L, (i + 1L) * 2L, hasUnanalyzedLanguages ? i % 2 == 0 : null, hasUnanalyzedLanguages ? i % 2 != 0 : null, "scm-" + i, "ci-" + i, "devops-" + i))
382 .collect(Collectors.toList());
386 public static Object[][] allEditions() {
387 return Arrays.stream(EditionProvider.Edition.values())
388 .map(t -> new Object[] {t})
389 .toArray(Object[][]::new);
392 private String writeTelemetryData(TelemetryData data) {
393 StringWriter jsonString = new StringWriter();
394 try (JsonWriter json = JsonWriter.of(jsonString)) {
395 underTest.writeTelemetryData(json, data);
397 return jsonString.toString();