]> source.dussan.org Git - sonarqube.git/blob
72987c21c9366666982148b21ecc4486bd0a7355
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2024 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.io.StringWriter;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.Map;
31 import java.util.Random;
32 import java.util.Set;
33 import java.util.stream.Collectors;
34 import java.util.stream.IntStream;
35 import org.jetbrains.annotations.NotNull;
36 import org.junit.Test;
37 import org.junit.runner.RunWith;
38 import org.sonar.api.utils.System2;
39 import org.sonar.api.utils.text.JsonWriter;
40 import org.sonar.core.platform.EditionProvider;
41 import org.sonar.core.telemetry.TelemetryExtension;
42 import org.sonar.db.project.CreationMethod;
43 import org.sonar.db.user.UserTelemetryDto;
44 import org.sonar.server.qualitygate.Condition;
45 import org.sonar.server.util.DigestUtil;
46
47 import static java.util.stream.Collectors.joining;
48 import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
49 import static org.assertj.core.api.Assertions.assertThat;
50 import static org.mockito.Mockito.mock;
51 import static org.mockito.Mockito.when;
52 import static org.sonar.db.newcodeperiod.NewCodePeriodType.NUMBER_OF_DAYS;
53 import static org.sonar.db.newcodeperiod.NewCodePeriodType.PREVIOUS_VERSION;
54 import static org.sonar.server.qualitygate.Condition.Operator.fromDbValue;
55 import static org.sonar.test.JsonAssert.assertJson;
56
57 @RunWith(DataProviderRunner.class)
58 public class TelemetryDataJsonWriterTest {
59
60   private final Random random = new Random();
61
62   private final TelemetryExtension extension = mock(TelemetryExtension.class);
63
64   private final System2 system2 = mock(System2.class);
65
66   private final TelemetryDataJsonWriter underTest = new TelemetryDataJsonWriter(List.of(extension), system2);
67
68   private static final int NCD_ID = 12345;
69
70   private static final TelemetryData.NewCodeDefinition NCD_INSTANCE = new TelemetryData.NewCodeDefinition(PREVIOUS_VERSION.name(), "", "instance");
71   private static final TelemetryData.NewCodeDefinition NCD_PROJECT = new TelemetryData.NewCodeDefinition(NUMBER_OF_DAYS.name(), "30", "project");
72
73   @Test
74   public void write_server_id_version_and_sequence() {
75     TelemetryData data = telemetryBuilder().build();
76
77     String json = writeTelemetryData(data);
78     assertJson(json).isSimilarTo("""
79       {
80         "id": "%s",
81         "version": "%s",
82         "messageSequenceNumber": %s
83       }
84       """.formatted(data.getServerId(), data.getVersion(), data.getMessageSequenceNumber()));
85   }
86
87   @Test
88   public void does_not_write_edition_if_null() {
89     TelemetryData data = telemetryBuilder().build();
90
91     String json = writeTelemetryData(data);
92
93     assertThat(json).doesNotContain("edition");
94   }
95
96   @Test
97   @UseDataProvider("allEditions")
98   public void writes_edition_if_non_null(EditionProvider.Edition edition) {
99     TelemetryData data = telemetryBuilder()
100       .setEdition(edition)
101       .build();
102
103     String json = writeTelemetryData(data);
104     assertJson(json).isSimilarTo("""
105       {
106         "edition": "%s"
107       }
108       """.formatted(edition.name().toLowerCase(Locale.ENGLISH)));
109   }
110
111   @Test
112   public void writes_default_qg() {
113     TelemetryData data = telemetryBuilder()
114       .setDefaultQualityGate("default-qg")
115       .build();
116
117     String json = writeTelemetryData(data);
118     assertJson(json).isSimilarTo("""
119       {
120         "defaultQualityGate": "%s"
121       }
122       """.formatted(data.getDefaultQualityGate()));
123   }
124
125   @Test
126   public void writes_sonarWay_qg() {
127     TelemetryData data = telemetryBuilder()
128       .setSonarWayQualityGate("sonarWayUUID")
129       .build();
130
131     String json = writeTelemetryData(data);
132     assertJson(json).isSimilarTo("""
133       {
134         "sonarway_quality_gate_uuid": "%s"
135       }
136       """.formatted(data.getSonarWayQualityGate()));
137   }
138
139   @Test
140   public void writes_database() {
141     String name = randomAlphabetic(12);
142     String version = randomAlphabetic(10);
143     TelemetryData data = telemetryBuilder()
144       .setDatabase(new TelemetryData.Database(name, version))
145       .build();
146
147     String json = writeTelemetryData(data);
148     assertJson(json).isSimilarTo("""
149       {
150         "database": {
151           "name": "%s",
152           "version": "%s"
153         }
154       }
155       """.formatted(name, version));
156   }
157
158   @Test
159   public void writes_no_plugins() {
160     TelemetryData data = telemetryBuilder()
161       .setPlugins(Collections.emptyMap())
162       .build();
163
164     String json = writeTelemetryData(data);
165
166     assertJson(json).isSimilarTo("""
167       {
168         "plugins": []
169       }
170       """);
171   }
172
173   @Test
174   public void writes_all_plugins() {
175     Map<String, String> plugins = IntStream.range(0, 1 + random.nextInt(10))
176       .boxed()
177       .collect(Collectors.toMap(i -> "P" + i, i1 -> "V" + i1));
178     TelemetryData data = telemetryBuilder()
179       .setPlugins(plugins)
180       .build();
181
182     String json = writeTelemetryData(data);
183     assertJson(json).isSimilarTo("""
184       {
185         "plugins": [%s]
186       }
187       """.formatted(plugins.entrySet().stream().map(e -> "{\"name\":\"" + e.getKey() + "\",\"version\":\"" + e.getValue() + "\"}").collect(joining(","))));
188   }
189
190   @Test
191   public void does_not_write_installation_date_if_null() {
192     TelemetryData data = telemetryBuilder()
193       .setInstallationDate(null)
194       .build();
195
196     String json = writeTelemetryData(data);
197
198     assertThat(json).doesNotContain("installationDate");
199   }
200
201   @Test
202   public void write_installation_date_in_utc_format() {
203     TelemetryData data = telemetryBuilder()
204       .setInstallationDate(1_000L)
205       .build();
206
207     String json = writeTelemetryData(data);
208
209     assertJson(json).isSimilarTo("""
210       {
211         "installationDate":"1970-01-01T00:00:01+0000"
212       }
213       """);
214   }
215
216   @Test
217   public void does_not_write_installation_version_if_null() {
218     TelemetryData data = telemetryBuilder()
219       .setInstallationVersion(null)
220       .build();
221
222     String json = writeTelemetryData(data);
223
224     assertThat(json).doesNotContain("installationVersion");
225   }
226
227   @Test
228   public void write_installation_version() {
229     String installationVersion = randomAlphabetic(5);
230     TelemetryData data = telemetryBuilder()
231       .setInstallationVersion(installationVersion)
232       .build();
233
234     String json = writeTelemetryData(data);
235     assertJson(json).isSimilarTo("""
236       {
237         "installationVersion": "%s"
238       }
239       """.formatted(installationVersion));
240   }
241
242   @Test
243   @UseDataProvider("getFeatureFlagEnabledStates")
244   public void write_container_flag(boolean isIncontainer) {
245     TelemetryData data = telemetryBuilder()
246       .setInContainer(isIncontainer)
247       .build();
248
249     String json = writeTelemetryData(data);
250     assertJson(json).isSimilarTo("""
251       {
252         "container": %s
253       }
254       """.formatted(isIncontainer));
255   }
256
257   @DataProvider
258   public static Object[][] getManagedInstanceData() {
259     return new Object[][] {
260       {true, "scim"},
261       {true, "github"},
262       {true, "gitlab"},
263       {false, null},
264     };
265   }
266
267   @Test
268   @UseDataProvider("getManagedInstanceData")
269   public void writeTelemetryData_encodesCorrectlyManagedInstanceInformation(boolean isManaged, String provider) {
270     TelemetryData data = telemetryBuilder()
271       .setManagedInstanceInformation(new TelemetryData.ManagedInstanceInformation(isManaged, provider))
272       .build();
273
274     String json = writeTelemetryData(data);
275
276     if (isManaged) {
277       assertJson(json).isSimilarTo("""
278         {
279         "managedInstanceInformation": {
280           "isManaged": true,
281             "provider": "%s"
282           }
283         }
284         """.formatted(provider));
285     } else {
286       assertJson(json).isSimilarTo("""
287         {
288         "managedInstanceInformation": {
289           "isManaged": false
290           }
291         }
292         """);
293     }
294   }
295
296   @Test
297   public void writeTelemetryData_shouldWriteCloudUsage() {
298     TelemetryData data = telemetryBuilder().build();
299
300     String json = writeTelemetryData(data);
301     assertJson(json).isSimilarTo("""
302       {
303         "cloudUsage": {
304           "kubernetes": true,
305           "kubernetesVersion": "1.27",
306           "kubernetesPlatform": "linux/amd64",
307           "kubernetesProvider": "5.4.181-99.354.amzn2.x86_64",
308           "officialHelmChart": "10.1.0",
309           "officialImage": false,
310           "containerRuntime": "docker"
311         }
312       }
313       """);
314   }
315
316   @Test
317   public void writes_has_unanalyzed_languages() {
318     TelemetryData data = telemetryBuilder()
319       .setHasUnanalyzedC(true)
320       .setHasUnanalyzedCpp(false)
321       .build();
322
323     String json = writeTelemetryData(data);
324
325     assertJson(json).isSimilarTo("""
326       {
327         "hasUnanalyzedC": true,
328         "hasUnanalyzedCpp": false,
329       }
330       """);
331   }
332
333   @Test
334   public void writes_security_custom_config() {
335     TelemetryData data = telemetryBuilder()
336       .setCustomSecurityConfigs(Set.of("php", "java"))
337       .build();
338
339     String json = writeTelemetryData(data);
340
341     assertJson(json).isSimilarTo("""
342       {
343         "customSecurityConfig": ["php", "java"]
344       }
345       """);
346   }
347
348   @Test
349   public void writes_local_timestamp() {
350     when(system2.now()).thenReturn(1000L);
351
352     TelemetryData data = telemetryBuilder().build();
353     String json = writeTelemetryData(data);
354
355     assertJson(json).isSimilarTo("""
356       {
357         "localTimestamp": "1970-01-01T00:00:01+0000"
358       }
359       """);
360   }
361
362   @Test
363   public void writes_all_users_with_anonymous_md5_uuids() {
364     TelemetryData data = telemetryBuilder()
365       .setUsers(attachUsers())
366       .build();
367
368     String json = writeTelemetryData(data);
369
370     assertJson(json).isSimilarTo("""
371       {
372         "users": [
373           {
374             "userUuid": "%s",
375             "status": "active",
376             "identityProvider": "gitlab",
377             "lastActivity": "1970-01-01T00:00:00+0000",
378             "lastSonarlintActivity": "1970-01-01T00:00:00+0000",
379             "managed": true
380           },
381           {
382             "userUuid": "%s",
383             "status": "inactive",
384             "identityProvider": "gitlab",
385             "lastActivity": "1970-01-01T00:00:00+0000",
386             "lastSonarlintActivity": "1970-01-01T00:00:00+0000",
387             "managed": false
388           },
389           {
390             "userUuid": "%s",
391             "status": "active",
392             "identityProvider": "gitlab",
393             "lastActivity": "1970-01-01T00:00:00+0000",
394             "lastSonarlintActivity": "1970-01-01T00:00:00+0000",
395             "managed": true
396           }
397         ]
398       }
399       """
400       .formatted(DigestUtil.sha3_224Hex("uuid-0"), DigestUtil.sha3_224Hex("uuid-1"), DigestUtil.sha3_224Hex("uuid-2")));
401   }
402
403   @Test
404   public void writes_all_projects() {
405     TelemetryData data = telemetryBuilder()
406       .setProjects(attachProjects())
407       .build();
408
409     String json = writeTelemetryData(data);
410
411     assertJson(json).isSimilarTo("""
412       {
413         "projects": [
414           {
415             "projectUuid": "uuid-0",
416             "lastAnalysis": "1970-01-01T00:00:00+0000",
417             "language": "lang-0",
418             "qualityProfile" : "qprofile-0",
419             "loc": 2
420           },
421           {
422             "projectUuid": "uuid-1",
423             "lastAnalysis": "1970-01-01T00:00:00+0000",
424             "language": "lang-1",
425             "qualityProfile" : "qprofile-1",
426             "loc": 4
427           },
428           {
429             "projectUuid": "uuid-2",
430             "lastAnalysis": "1970-01-01T00:00:00+0000",
431             "language": "lang-2",
432             "qualityProfile" : "qprofile-2",
433             "loc": 6
434           }
435         ]
436       }
437       """);
438   }
439
440   @Test
441   public void writeTelemetryData_whenAnalyzedLanguages_shouldwriteAllProjectsStats() {
442     TelemetryData data = telemetryBuilder()
443       .setProjectStatistics(attachProjectStatsWithMetrics())
444       .build();
445
446     String json = writeTelemetryData(data);
447
448     assertJson(json).isSimilarTo("""
449       {
450         "projects-general-stats": [
451           {
452             "projectUuid": "uuid-0",
453             "branchCount": 2,
454             "pullRequestCount": 2,
455             "qualityGate": "qg-0",
456             "scm": "scm-0",
457             "ci": "ci-0",
458             "devopsPlatform": "devops-0",
459             "bugs": 2,
460             "vulnerabilities": 3,
461             "securityHotspots": 4,
462             "technicalDebt": 60,
463             "developmentCost": 30,
464             "ncdId": 12345,
465             "externalSecurityReportExportedAt": 1500000,
466             "project_creation_method": "LOCAL_API",
467             "monorepo": true
468           },
469           {
470             "projectUuid": "uuid-1",
471             "branchCount": 4,
472             "pullRequestCount": 4,
473             "qualityGate": "qg-1",
474             "scm": "scm-1",
475             "ci": "ci-1",
476             "devopsPlatform": "devops-1",
477             "bugs": 4,
478             "vulnerabilities": 6,
479             "securityHotspots": 8,
480             "technicalDebt": 120,
481             "developmentCost": 60,
482             "ncdId": 12345,
483             "externalSecurityReportExportedAt": 1500001,
484             "project_creation_method": "LOCAL_API",
485             "monorepo": false
486           },
487           {
488             "projectUuid": "uuid-2",
489             "branchCount": 6,
490             "pullRequestCount": 6,
491             "qualityGate": "qg-2",
492             "scm": "scm-2",
493             "ci": "ci-2",
494             "devopsPlatform": "devops-2",
495             "bugs": 6,
496             "vulnerabilities": 9,
497             "securityHotspots": 12,
498             "technicalDebt": 180,
499             "developmentCost": 90,
500             "ncdId": 12345,
501             "externalSecurityReportExportedAt": 1500002,
502             "project_creation_method": "LOCAL_API",
503             "monorepo": true
504           }
505         ]
506       }
507       """);
508   }
509
510   @Test
511   public void writes_all_projects_stats_with_unanalyzed_languages() {
512     TelemetryData data = telemetryBuilder()
513       .setProjectStatistics(attachProjectStats())
514       .build();
515
516     String json = writeTelemetryData(data);
517     assertThat(json).doesNotContain("hasUnanalyzedC", "hasUnanalyzedCpp");
518   }
519
520   @Test
521   public void writes_all_projects_stats_without_missing_metrics() {
522     TelemetryData data = telemetryBuilder()
523       .setProjectStatistics(attachProjectStats())
524       .build();
525     String json = writeTelemetryData(data);
526     assertThat(json).doesNotContain("bugs", "vulnerabilities", "securityHotspots", "technicalDebt", "developmentCost");
527   }
528
529   @Test
530   public void writes_all_quality_gates() {
531     TelemetryData data = telemetryBuilder()
532       .setQualityGates(attachQualityGates())
533       .build();
534
535     String json = writeTelemetryData(data);
536     assertJson(json).isSimilarTo("""
537       {
538         "quality-gates": [
539            {
540              "uuid": "uuid-0",
541              "caycStatus": "non-compliant",
542              "conditions": [
543                {
544                  "metric": "new_coverage",
545                  "comparison_operator": "LT",
546                  "error_value": "80"
547                },
548                {
549                  "metric": "new_duplicated_lines_density",
550                  "comparison_operator": "GT",
551                  "error_value": "3"
552                }
553              ]
554            },
555            {
556              "uuid": "uuid-1",
557              "caycStatus": "compliant",
558              "conditions": [
559                {
560                  "metric": "new_coverage",
561                  "comparison_operator": "LT",
562                  "error_value": "80"
563                },
564                {
565                  "metric": "new_duplicated_lines_density",
566                  "comparison_operator": "GT",
567                  "error_value": "3"
568                }
569              ]
570            },
571            {
572              "uuid": "uuid-2",
573              "caycStatus": "over-compliant",
574              "conditions": [
575                {
576                  "metric": "new_coverage",
577                  "comparison_operator": "LT",
578                  "error_value": "80"
579                },
580                {
581                  "metric": "new_duplicated_lines_density",
582                  "comparison_operator": "GT",
583                  "error_value": "3"
584                }
585              ]
586            }
587          ]
588         }
589       """);
590   }
591
592   @Test
593   public void writeTelemetryData_shouldWriteQualityProfiles() {
594     TelemetryData data = telemetryBuilder()
595       .setQualityProfiles(List.of(
596         new TelemetryData.QualityProfile("uuid-1", "parent-uuid-1", "js", true, false, true, 2, 3, 4),
597         new TelemetryData.QualityProfile("uuid-1", null, "js", false, true, null, null, null, null)))
598       .build();
599
600     String json = writeTelemetryData(data);
601     assertJson(json).isSimilarTo("""
602       {
603         "quality-profiles": [
604           {
605             "uuid": "uuid-1",
606             "parentUuid": "parent-uuid-1",
607             "language": "js",
608             "default": true,
609             "builtIn": false,
610             "builtInParent": true,
611             "rulesOverriddenCount": 2,
612             "rulesActivatedCount": 3,
613             "rulesDeactivatedCount": 4
614           },
615           {
616             "uuid": "uuid-1",
617             "language": "js",
618             "default": false,
619             "builtIn": true
620           }
621       ]}
622       """);
623   }
624
625   @Test
626   public void writes_all_branches() {
627     TelemetryData data = telemetryBuilder()
628       .setBranches(attachBranches())
629       .build();
630
631     String json = writeTelemetryData(data);
632     assertJson(json).isSimilarTo("""
633       {
634         "branches": [
635           {
636             "projectUuid": "projectUuid1",
637             "branchUuid": "branchUuid1",
638             "ncdId": 12345,
639             "greenQualityGateCount": 1,
640             "analysisCount": 2,
641             "excludeFromPurge": true
642           },
643           {
644             "projectUuid": "projectUuid2",
645             "branchUuid": "branchUuid2",
646             "ncdId": 12345,
647             "greenQualityGateCount": 0,
648             "analysisCount": 2,
649             "excludeFromPurge": true
650           }
651         ]
652       }
653       """);
654   }
655
656   @Test
657   public void writes_new_code_definitions() {
658     TelemetryData data = telemetryBuilder()
659       .setNewCodeDefinitions(attachNewCodeDefinitions())
660       .build();
661
662     String json = writeTelemetryData(data);
663     assertJson(json).isSimilarTo("""
664       {
665         "new-code-definitions": [
666           {
667             "ncdId": %s,
668             "type": "%s",
669             "value": "%s",
670             "scope": "%s"
671           },
672           {
673             "ncdId": %s,
674             "type": "%s",
675             "value": "%s",
676             "scope": "%s"
677           },
678         ]
679
680       }
681       """.formatted(NCD_INSTANCE.hashCode(), NCD_INSTANCE.type(), NCD_INSTANCE.value(), NCD_INSTANCE.scope(), NCD_PROJECT.hashCode(),
682       NCD_PROJECT.type(), NCD_PROJECT.value(), NCD_PROJECT.scope()));
683   }
684
685   @Test
686   public void writes_instance_new_code_definition() {
687     TelemetryData data = telemetryBuilder().build();
688
689     String json = writeTelemetryData(data);
690     assertThat(json).contains("ncdId");
691
692   }
693
694   private static TelemetryData.Builder telemetryBuilder() {
695     return TelemetryData.builder()
696       .setServerId("foo")
697       .setVersion("bar")
698       .setMessageSequenceNumber(1L)
699       .setPlugins(Collections.emptyMap())
700       .setManagedInstanceInformation(new TelemetryData.ManagedInstanceInformation(false, null))
701       .setCloudUsage(new TelemetryData.CloudUsage(true, "1.27", "linux/amd64", "5.4.181-99.354.amzn2.x86_64", "10.1.0", "docker", false))
702       .setDatabase(new TelemetryData.Database("H2", "11"))
703       .setNcdId(NCD_ID);
704   }
705
706   @NotNull
707   private static List<UserTelemetryDto> attachUsers() {
708     return IntStream.range(0, 3)
709       .mapToObj(
710         i -> new UserTelemetryDto().setUuid("uuid-" + i).setActive(i % 2 == 0).setLastConnectionDate(1L)
711           .setLastSonarlintConnectionDate(2L).setExternalIdentityProvider("gitlab").setScimUuid(i % 2 == 0 ? "scim-uuid-" + i : null))
712       .toList();
713   }
714
715   private static List<TelemetryData.Project> attachProjects() {
716     return IntStream.range(0, 3).mapToObj(i -> new TelemetryData.Project("uuid-" + i, 1L, "lang-" + i, "qprofile-" + i, (i + 1L) * 2)).toList();
717   }
718
719   private static List<TelemetryData.ProjectStatistics> attachProjectStatsWithMetrics() {
720     return IntStream.range(0, 3).mapToObj(i -> getProjectStatisticsWithMetricBuilder(i).build()).toList();
721   }
722
723   private static List<TelemetryData.ProjectStatistics> attachProjectStats() {
724     return IntStream.range(0, 3).mapToObj(i -> getProjectStatisticsBuilder(i).build()).toList();
725   }
726
727   private static TelemetryData.ProjectStatistics.Builder getProjectStatisticsBuilder(int i) {
728     return new TelemetryData.ProjectStatistics.Builder()
729       .setProjectUuid("uuid-" + i)
730       .setBranchCount((i + 1L) * 2L)
731       .setPRCount((i + 1L) * 2L)
732       .setQG("qg-" + i).setCi("ci-" + i)
733       .setScm("scm-" + i)
734       .setDevops("devops-" + i)
735       .setNcdId(NCD_ID)
736       .setCreationMethod(CreationMethod.LOCAL_API)
737       .setMonorepo(false);
738   }
739
740   private static TelemetryData.ProjectStatistics.Builder getProjectStatisticsWithMetricBuilder(int i) {
741     return getProjectStatisticsBuilder(i)
742       .setBugs((i + 1L) * 2)
743       .setVulnerabilities((i + 1L) * 3)
744       .setSecurityHotspots((i + 1L) * 4)
745       .setDevelopmentCost((i + 1L) * 30d)
746       .setTechnicalDebt((i + 1L) * 60d)
747       .setExternalSecurityReportExportedAt(1_500_000L + i)
748       .setCreationMethod(CreationMethod.LOCAL_API)
749       .setMonorepo(i % 2 == 0);
750   }
751
752   private List<TelemetryData.QualityGate> attachQualityGates() {
753     List<Condition> qualityGateConditions = attachQualityGateConditions();
754     return List.of(new TelemetryData.QualityGate("uuid-0", "non-compliant", qualityGateConditions),
755       new TelemetryData.QualityGate("uuid-1", "compliant", qualityGateConditions),
756       new TelemetryData.QualityGate("uuid-2", "over-compliant", qualityGateConditions));
757   }
758
759   private List<Condition> attachQualityGateConditions() {
760     return List.of(new Condition("new_coverage", fromDbValue("LT"), "80"),
761       new Condition("new_duplicated_lines_density", fromDbValue("GT"), "3"));
762   }
763
764   private List<TelemetryData.Branch> attachBranches() {
765     return List.of(new TelemetryData.Branch("projectUuid1", "branchUuid1", NCD_ID, 1, 2, true),
766       new TelemetryData.Branch("projectUuid2", "branchUuid2", NCD_ID, 0, 2, true));
767   }
768
769   private List<TelemetryData.NewCodeDefinition> attachNewCodeDefinitions() {
770     return List.of(NCD_INSTANCE, NCD_PROJECT);
771   }
772
773   @DataProvider
774   public static Object[][] allEditions() {
775     return Arrays.stream(EditionProvider.Edition.values())
776       .map(t -> new Object[] {t})
777       .toArray(Object[][]::new);
778   }
779
780   private String writeTelemetryData(TelemetryData data) {
781     StringWriter jsonString = new StringWriter();
782     try (JsonWriter json = JsonWriter.of(jsonString)) {
783       underTest.writeTelemetryData(json, data);
784     }
785     return jsonString.toString();
786   }
787
788   @DataProvider
789   public static Set<Boolean> getFeatureFlagEnabledStates() {
790     return Set.of(true, false);
791   }
792 }