]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9245 facet new_reliability_rating in search_projects WS
authorDaniel Schwarz <daniel.schwarz@sonarsource.com>
Thu, 18 May 2017 14:04:38 +0000 (16:04 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Fri, 9 Jun 2017 06:26:48 +0000 (08:26 +0200)
it/it-tests/src/test/java/it/Category4Suite.java
it/it-tests/src/test/java/it/Category6Suite.java
it/it-tests/src/test/java/it/projectSearch/SearchProjectsTest.java
it/it-tests/src/test/java/util/ItUtils.java
it/it-tests/src/test/resources/projectSearch/SearchProjectsTest/with-many-rules.xml [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/measure/index/ProjectMeasuresIndex.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchProjectsActionTest.java
server/sonar-server/src/test/java/org/sonar/server/measure/index/ProjectMeasuresIndexTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/component/ComponentsService.java
sonar-ws/src/test/java/org/sonarqube/ws/client/component/ComponentsServiceTest.java

index 20fc6409fec91e03f73c6fec7a5a4ed9fdee0470..878c8eb846db8b105df6b7c72f52a63ae56e6a02 100644 (file)
@@ -31,7 +31,6 @@ import it.duplication.DuplicationsTest;
 import it.duplication.NewDuplicationsTest;
 import it.projectEvent.EventTest;
 import it.projectEvent.ProjectActivityPageTest;
-import it.projectSearch.SearchProjectsTest;
 import it.qualityProfile.QualityProfilesPageTest;
 import it.qualityProfile.QualityProfilesRestoreAndSearchTest;
 import it.serverSystem.HttpHeadersTest;
@@ -85,8 +84,6 @@ import static util.ItUtils.xooPlugin;
   // project event
   EventTest.class,
   ProjectActivityPageTest.class,
-  // project search
-  SearchProjectsTest.class,
   // http
   HttpHeadersTest.class,
   // ui
index effe0c20cfb335e863f5c9d5645e76176ffd9eef..7c17870ee35b1250a1f1568db7080021b99eba1c 100644 (file)
@@ -25,6 +25,7 @@ import it.issue.OrganizationIssueAssignTest;
 import it.organization.BillingTest;
 import it.organization.OrganizationMembershipTest;
 import it.organization.OrganizationTest;
+import it.projectSearch.SearchProjectsTest;
 import it.qualityProfile.OrganizationQualityProfilesPageTest;
 import it.uiExtension.OrganizationUiExtensionsTest;
 import it.user.OrganizationIdentityProviderTest;
@@ -49,7 +50,8 @@ import static util.ItUtils.xooPlugin;
   OrganizationTest.class,
   OrganizationUiExtensionsTest.class,
   BillingTest.class,
-  IssueTagsTest.class
+  IssueTagsTest.class,
+  SearchProjectsTest.class
 })
 public class Category6Suite {
 
index 619c6b5dc2426c03f8adc7c0e48fe5a280b8735d..3dc6497bb82e923758f9afbd44fcbd1c5b606b6c 100644 (file)
 package it.projectSearch;
 
 import com.sonar.orchestrator.Orchestrator;
-import it.Category4Suite;
+import com.sonar.orchestrator.build.SonarScanner;
+import it.Category6Suite;
 import java.io.IOException;
+import org.assertj.core.groups.Tuple;
+import org.junit.After;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Test;
-import org.sonarqube.ws.Common.FacetValue;
+import org.sonarqube.ws.Common;
 import org.sonarqube.ws.WsComponents.Component;
 import org.sonarqube.ws.WsComponents.SearchProjectsWsResponse;
 import org.sonarqube.ws.client.component.SearchProjectsRequest;
+import org.sonarqube.ws.client.organization.CreateWsRequest;
+import org.sonarqube.ws.client.project.CreateRequest;
+import util.ItUtils;
 
 import static com.sonar.orchestrator.build.SonarScanner.create;
+import static it.Category6Suite.enableOrganizationsSupport;
+import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.groups.Tuple.tuple;
+import static util.ItUtils.deleteOrganizationsIfExists;
 import static util.ItUtils.newAdminWsClient;
+import static util.ItUtils.newProjectKey;
 import static util.ItUtils.projectDir;
+import static util.ItUtils.restoreProfile;
+import static util.ItUtils.setServerProperty;
 
 /**
  * Tests WS api/components/search_projects
  */
 public class SearchProjectsTest {
 
-  private static final String PROJECT_KEY = "sample";
-  private static final String PROJECT_NAME = "Sample";
-
   @ClassRule
-  public static Orchestrator orchestrator = Category4Suite.ORCHESTRATOR;
+  public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR;
+
+  private String organizationKey;
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    enableOrganizationsSupport();
+  }
 
   @Before
   public void setUp() throws Exception {
-    orchestrator.resetData();
+    organizationKey = ItUtils.newOrganizationKey();
+    newAdminWsClient(orchestrator).organizations().create(CreateWsRequest.builder()
+      .setKey(organizationKey)
+      .setName(organizationKey)
+      .build());
+    restoreProfile(orchestrator, SearchProjectsTest.class.getResource("/projectSearch/SearchProjectsTest/with-many-rules.xml"), organizationKey);
   }
 
-  @Test
-  public void filter_projects_by_measure_values() throws Exception {
-    orchestrator.executeBuild(create(projectDir("shared/xoo-sample")));
-
-    verifyFilterMatches("ncloc > 1");
-    verifyFilterMatches("ncloc > 1 and comment_lines < 10000");
-    verifyFilterDoesNotMatch("ncloc <= 1");
+  @After
+  public void tearDown() throws Exception {
+    deleteOrganizationsIfExists(orchestrator, organizationKey);
   }
 
   @Test
-  public void provisioned_projects_should_be_included_to_results() throws Exception {
-    orchestrator.getServer().provisionProject(PROJECT_KEY, PROJECT_NAME);
-
-    SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().build());
+  public void filter_projects_by_measure_values() throws Exception {
+    String projectKey = newProjectKey();
+    analyzeProject(projectKey, "shared/xoo-sample");
 
-    assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly(PROJECT_KEY);
+    verifyFilterMatches(projectKey, "ncloc > 1");
+    verifyFilterMatches(projectKey, "ncloc > 1 and comment_lines < 10000");
+    verifyFilterDoesNotMatch("ncloc <= 1");
   }
 
   @Test
@@ -90,27 +109,130 @@ public class SearchProjectsTest {
       .extracting(Component::getKey).containsExactly("project3");
     assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"nd\" AND ncloc > 50").build()).getComponentsList())
       .extracting(Component::getKey).containsExactly("project3", "project4");
-    assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"unknown\" AND ncloc > 50").build()).getComponentsList()).isEmpty();;
+    assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"unknown\" AND ncloc > 50").build()).getComponentsList()).isEmpty();
+    ;
 
     // Check facets
     assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"apache\"").setFacets(singletonList("ncloc")).build()).getFacets().getFacets(0).getValuesList())
-      .extracting(FacetValue::getVal, FacetValue::getCount)
+      .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
       .containsOnly(tuple("*-1000.0", 3L), tuple("1000.0-10000.0", 0L), tuple("10000.0-100000.0", 0L), tuple("100000.0-500000.0", 0L), tuple("500000.0-*", 0L));
     assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"unknown\"").setFacets(singletonList("ncloc")).build()).getFacets().getFacets(0)
-      .getValuesList()).extracting(FacetValue::getVal, FacetValue::getCount)
-      .containsOnly(tuple("*-1000.0", 0L), tuple("1000.0-10000.0", 0L), tuple("10000.0-100000.0", 0L), tuple("100000.0-500000.0", 0L), tuple("500000.0-*", 0L));
+      .getValuesList()).extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
+        .containsOnly(tuple("*-1000.0", 0L), tuple("1000.0-10000.0", 0L), tuple("10000.0-100000.0", 0L), tuple("100000.0-500000.0", 0L), tuple("500000.0-*", 0L));
+  }
+
+  @Test
+  public void provisioned_projects_should_be_included_to_results() throws Exception {
+    String projectKey = newProjectKey();
+    newAdminWsClient(orchestrator).projects().create(CreateRequest.builder().setKey(projectKey).setName(projectKey).setOrganization(organizationKey).build());
+
+    SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organizationKey).build());
+
+    assertThat(response.getComponentsList()).extracting(Component::getKey).contains(projectKey);
+  }
+
+  @Test
+  public void should_return_facets() throws Exception {
+    analyzeProject(newProjectKey(), "shared/xoo-sample");
+    analyzeProject(newProjectKey(), "shared/xoo-multi-modules-sample");
+
+    SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organizationKey).setFacets(asList(
+      "alert_status",
+      "coverage",
+      "duplicated_lines_density",
+      "languages",
+      "ncloc",
+      "reliability_rating",
+      "security_rating",
+      "sqale_rating",
+      "tags")).build());
+
+    checkFacet(response, "alert_status",
+      tuple("OK", 2L),
+      tuple("WARN", 0L),
+      tuple("ERROR", 0L));
+    checkFacet(response, "coverage",
+      tuple("*-30.0", 0L),
+      tuple("30.0-50.0", 0L),
+      tuple("50.0-70.0", 0L),
+      tuple("70.0-80.0", 0L),
+      tuple("80.0-*", 0L));
+    checkFacet(response, "duplicated_lines_density",
+      tuple("*-3.0", 2L),
+      tuple("3.0-5.0", 0L),
+      tuple("5.0-10.0", 0L),
+      tuple("10.0-20.0", 0L),
+      tuple("20.0-*", 0L));
+    checkFacet(response, "languages",
+      tuple("xoo", 2L));
+    checkFacet(response, "ncloc",
+      tuple("*-1000.0", 2L),
+      tuple("1000.0-10000.0", 0L),
+      tuple("10000.0-100000.0", 0L),
+      tuple("100000.0-500000.0", 0L),
+      tuple("500000.0-*", 0L));
+    checkFacet(response, "reliability_rating",
+      tuple("1", 2L),
+      tuple("2", 0L),
+      tuple("3", 0L),
+      tuple("4", 0L),
+      tuple("5", 0L));
+    checkFacet(response, "security_rating",
+      tuple("1", 2L),
+      tuple("2", 0L),
+      tuple("3", 0L),
+      tuple("4", 0L),
+      tuple("5", 0L));
+    checkFacet(response, "sqale_rating",
+      tuple("1", 0L),
+      tuple("2", 0L),
+      tuple("3", 0L),
+      tuple("4", 2L),
+      tuple("5", 0L));
+    checkFacet(response, "tags");
+  }
+
+  @Test
+  public void should_return_facets_on_leak() throws Exception {
+    setServerProperty(orchestrator, "sonar.leak.period", "previous_analysis");
+    String projectKey = newProjectKey();
+    analyzeProject(projectKey, "shared/xoo-history-v1");
+    analyzeProject(projectKey, "shared/xoo-history-v2");
+
+    SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organizationKey).setFacets(asList(
+      "new_reliability_rating")).build());
+
+    checkFacet(response, "new_reliability_rating",
+      tuple("1", 1L),
+      tuple("2", 0L),
+      tuple("3", 0L),
+      tuple("4", 0L),
+      tuple("5", 0L));
+  }
+
+  private void checkFacet(SearchProjectsWsResponse response, String facetKey, Tuple... values) {
+    Common.Facet facet = response.getFacets().getFacetsList().stream().filter(f -> f.getProperty().equals(facetKey)).findAny().get();
+    assertThat(facet.getValuesList()).extracting(Common.FacetValue::getVal, Common.FacetValue::getCount).containsExactly(values);
+  }
+
+  private void analyzeProject(String projectKey, String relativePath) {
+    orchestrator.executeBuild(SonarScanner.create(projectDir(relativePath),
+      "sonar.projectKey", projectKey,
+      "sonar.organization", organizationKey,
+      "sonar.profile", "with-many-rules",
+      "sonar.login", "admin", "sonar.password", "admin"));
   }
 
   private SearchProjectsWsResponse searchProjects(String filter) throws IOException {
-    return searchProjects(SearchProjectsRequest.builder().setFilter(filter).build());
+    return searchProjects(SearchProjectsRequest.builder().setOrganization(organizationKey).setFilter(filter).build());
   }
 
   private SearchProjectsWsResponse searchProjects(SearchProjectsRequest request) throws IOException {
     return newAdminWsClient(orchestrator).components().searchProjects(request);
   }
 
-  private void verifyFilterMatches(String filter) throws IOException {
-    assertThat(searchProjects(filter).getComponentsList()).extracting(Component::getKey).containsOnly(PROJECT_KEY);
+  private void verifyFilterMatches(String projectKey, String filter) throws IOException {
+    assertThat(searchProjects(filter).getComponentsList()).extracting(Component::getKey).containsOnly(projectKey);
   }
 
   private void verifyFilterDoesNotMatch(String filter) throws IOException {
index 367e3a724c849c54f2cd93dd7fd5bcc2fae36363..d3ad26424f6c7ec58970a05a2e20f5a7b27f5abe 100644 (file)
@@ -369,7 +369,7 @@ public class ItUtils {
   }
 
   public static String newProjectKey() {
-    return "key-" + randomAlphabetic(200);
+    return "key-" + randomAlphabetic(100);
   }
 
   public static void deleteOrganizationsIfExists(Orchestrator orchestrator, String... organizationKeys) {
diff --git a/it/it-tests/src/test/resources/projectSearch/SearchProjectsTest/with-many-rules.xml b/it/it-tests/src/test/resources/projectSearch/SearchProjectsTest/with-many-rules.xml
new file mode 100644 (file)
index 0000000..366a3ab
--- /dev/null
@@ -0,0 +1,43 @@
+<profile>
+  <name>with-many-rules</name>
+  <language>xoo</language>
+  <rules>
+    <rule>
+      <repositoryKey>xoo</repositoryKey>
+      <key>OneIssuePerLine</key>
+      <priority>MINOR</priority>
+    </rule>
+    <rule>
+      <repositoryKey>xoo</repositoryKey>
+      <key>OneIssuePerFile</key>
+      <priority>MAJOR</priority>
+    </rule>
+    <rule>
+      <repositoryKey>xoo</repositoryKey>
+      <key>OneIssuePerModule</key>
+      <priority>CRITICAL</priority>
+    </rule>
+    <rule>
+      <repositoryKey>xoo</repositoryKey>
+      <key>HasTag</key>
+      <priority>INFO</priority>
+      <parameters>
+        <parameter>
+          <key>tag</key>
+          <value>xoo</value>
+        </parameter>
+      </parameters>
+    </rule>
+    <rule>
+      <repositoryKey>common-xoo</repositoryKey>
+      <key>InsufficientLineCoverage</key>
+      <priority>BLOCKER</priority>
+      <parameters>
+        <parameter>
+          <key>minimumLineCoverageRatio</key>
+          <value>90</value>
+        </parameter>
+      </parameters>
+    </rule>
+  </rules>
+</profile>
index 9fa14bd5785bafa425cc3ff99149a4f9c6a1b6f3..3e2b76526ea58f028f1fb0a28733c530a1e3ac63 100644 (file)
@@ -65,6 +65,7 @@ import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
 import static org.sonar.api.measures.CoreMetrics.COVERAGE_KEY;
 import static org.sonar.api.measures.CoreMetrics.DUPLICATED_LINES_DENSITY_KEY;
 import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY;
 import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY;
 import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING_KEY;
 import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY;
@@ -90,6 +91,7 @@ public class ProjectMeasuresIndex {
     COVERAGE_KEY,
     SQALE_RATING_KEY,
     RELIABILITY_RATING_KEY,
+    NEW_RELIABILITY_RATING_KEY,
     SECURITY_RATING_KEY,
     ALERT_STATUS_KEY,
     FILTER_LANGUAGES,
@@ -104,6 +106,7 @@ public class ProjectMeasuresIndex {
     .put(COVERAGE_KEY, (esSearch, query, facetBuilder) -> addRangeFacet(esSearch, COVERAGE_KEY, facetBuilder, 30d, 50d, 70d, 80d))
     .put(SQALE_RATING_KEY, (esSearch, query, facetBuilder) -> addRatingFacet(esSearch, SQALE_RATING_KEY, facetBuilder))
     .put(RELIABILITY_RATING_KEY, (esSearch, query, facetBuilder) -> addRatingFacet(esSearch, RELIABILITY_RATING_KEY, facetBuilder))
+    .put(NEW_RELIABILITY_RATING_KEY, (esSearch, query, facetBuilder) -> addRatingFacet(esSearch, NEW_RELIABILITY_RATING_KEY, facetBuilder))
     .put(SECURITY_RATING_KEY, (esSearch, query, facetBuilder) -> addRatingFacet(esSearch, SECURITY_RATING_KEY, facetBuilder))
     .put(ALERT_STATUS_KEY, (esSearch, query, facetBuilder) -> esSearch.addAggregation(createStickyFacet(ALERT_STATUS_KEY, facetBuilder, createQualityGateFacet())))
     .put(FILTER_LANGUAGES, ProjectMeasuresIndex::addLanguagesFacet)
index 716ab38752566925e44edfa5392d592f52461fbf..bdbd3b21a8d69b74ce3a9bcaeae4568a18a02390 100644 (file)
@@ -42,7 +42,6 @@ import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentTesting;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.property.PropertyDto;
 import org.sonar.server.es.EsTester;
@@ -69,6 +68,8 @@ import static java.util.Optional.ofNullable;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.tuple;
 import static org.sonar.api.measures.CoreMetrics.NCLOC_LANGUAGE_DISTRIBUTION_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY;
+import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY;
 import static org.sonar.api.measures.Metric.ValueType.INT;
 import static org.sonar.api.measures.Metric.ValueType.LEVEL;
 import static org.sonar.api.server.ws.WebService.Param.ASCENDING;
@@ -158,23 +159,23 @@ public class SearchProjectsActionTest {
     Param facets = def.param("facets");
     assertThat(facets.defaultValue()).isNull();
     assertThat(facets.possibleValues()).containsOnly("ncloc", "duplicated_lines_density", "coverage", "sqale_rating", "reliability_rating", "security_rating", "alert_status",
-      "languages", "tags");
+      "languages", "tags", "new_reliability_rating");
   }
 
   @Test
   public void json_example() {
     OrganizationDto organization1Dto = db.organizations().insertForKey("my-org-key-1");
     OrganizationDto organization2Dto = db.organizations().insertForKey("my-org-key-2");
-    ComponentDto project1 = insertProjectInDbAndEs(ComponentTesting.newPublicProjectDto(organization1Dto)
+    ComponentDto project1 = insertProjectInDbAndEs(newPublicProjectDto(organization1Dto)
       .setUuid(Uuids.UUID_EXAMPLE_01)
       .setKey(KeyExamples.KEY_PROJECT_EXAMPLE_001)
       .setName("My Project 1")
       .setTagsString("finance, java"));
-    insertProjectInDbAndEs(ComponentTesting.newPublicProjectDto(organization1Dto)
+    insertProjectInDbAndEs(newPublicProjectDto(organization1Dto)
       .setUuid(Uuids.UUID_EXAMPLE_02)
       .setKey(KeyExamples.KEY_PROJECT_EXAMPLE_002)
       .setName("My Project 2"));
-    insertProjectInDbAndEs(ComponentTesting.newPublicProjectDto(organization2Dto)
+    insertProjectInDbAndEs(newPublicProjectDto(organization2Dto)
       .setUuid(Uuids.UUID_EXAMPLE_03)
       .setKey(KeyExamples.KEY_PROJECT_EXAMPLE_003)
       .setName("My Project 3")
@@ -190,9 +191,9 @@ public class SearchProjectsActionTest {
 
   @Test
   public void order_by_name_case_insensitive() {
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setName("Maven"));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setName("Apache"));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setName("guava"));
+    insertProjectInDbAndEs(newPrivateProjectDto(db.getDefaultOrganization()).setName("Maven"));
+    insertProjectInDbAndEs(newPrivateProjectDto(db.getDefaultOrganization()).setName("Apache"));
+    insertProjectInDbAndEs(newPrivateProjectDto(db.getDefaultOrganization()).setName("guava"));
 
     SearchProjectsWsResponse result = call(request);
 
@@ -202,7 +203,7 @@ public class SearchProjectsActionTest {
 
   @Test
   public void paginate_result() {
-    IntStream.rangeClosed(1, 9).forEach(i -> insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setName("PROJECT-" + i)));
+    IntStream.rangeClosed(1, 9).forEach(i -> insertProjectInDbAndEs(newPrivateProjectDto(db.getDefaultOrganization()).setName("PROJECT-" + i)));
 
     SearchProjectsWsResponse result = call(request.setPage(2).setPageSize(3));
 
@@ -229,7 +230,7 @@ public class SearchProjectsActionTest {
   @Test
   public void return_only_projects() {
     OrganizationDto organizationDto = db.organizations().insert();
-    ComponentDto project = ComponentTesting.newPrivateProjectDto(organizationDto).setName("SonarQube");
+    ComponentDto project = newPrivateProjectDto(organizationDto).setName("SonarQube");
     ComponentDto directory = newDirectory(project, "path");
     insertProjectInDbAndEs(project);
     componentDb.insertComponents(newModuleDto(project), newView(organizationDto), directory, newFileDto(project, directory));
@@ -243,9 +244,9 @@ public class SearchProjectsActionTest {
   @Test
   public void filter_projects_with_query() {
     OrganizationDto organizationDto = db.organizations().insertForKey("my-org-key-1");
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 10_000d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 10_000d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d)));
     insertMetrics(COVERAGE, NCLOC);
     request.setFilter("coverage <= 80 and ncloc <= 10000");
 
@@ -259,9 +260,9 @@ public class SearchProjectsActionTest {
   public void filter_projects_with_query_within_specified_organization() {
     OrganizationDto organization1 = db.organizations().insert();
     OrganizationDto organization2 = db.organizations().insert();
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization1).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 10_000d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization1).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization2).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization1).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 10_000d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization1).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization2).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d)));
     insertMetrics(COVERAGE, NCLOC);
 
     assertThat(call(request.setOrganization(null)).getComponentsList())
@@ -278,9 +279,9 @@ public class SearchProjectsActionTest {
   @Test
   public void filter_projects_by_quality_gate() {
     OrganizationDto organizationDto = db.organizations().insertForKey("my-org-key-1");
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Java"), "OK");
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Markdown"), "OK");
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Qube"), "ERROR");
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Java"), "OK");
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Markdown"), "OK");
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Qube"), "ERROR");
     insertMetrics(COVERAGE, NCLOC);
     request.setFilter("alert_status = OK");
 
@@ -292,10 +293,10 @@ public class SearchProjectsActionTest {
   @Test
   public void filter_projects_by_languages() {
     OrganizationDto organizationDto = db.organizations().insertForKey("my-org-key-1");
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81d)), null, asList("<null>", "java", "xoo"));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81)), null, asList("java", "xoo"));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d)), null, asList("xoo"));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d)), null, asList("<null>", "java", "xoo"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81d)), null, asList("<null>", "java", "xoo"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81)), null, asList("java", "xoo"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d)), null, asList("xoo"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d)), null, asList("<null>", "java", "xoo"));
     insertMetrics(COVERAGE, NCLOC_LANGUAGE_DISTRIBUTION_KEY);
     request.setFilter("languages IN (java, js, <null>)");
 
@@ -307,9 +308,9 @@ public class SearchProjectsActionTest {
   @Test
   public void filter_projects_by_tags() {
     OrganizationDto organizationDto = db.organizations().insertForKey("my-org-key-1");
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Java").setTags(newArrayList("finance", "platform")));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Markdown").setTags(singletonList("marketing")));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setName("Sonar Qube").setTags(newArrayList("offshore")));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Java").setTags(newArrayList("finance", "platform")));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Markdown").setTags(singletonList("marketing")));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setName("Sonar Qube").setTags(newArrayList("offshore")));
     request.setFilter("tags in (finance, offshore)");
 
     SearchProjectsWsResponse result = call(request);
@@ -320,10 +321,10 @@ public class SearchProjectsActionTest {
   @Test
   public void filter_projects_by_text_query() {
     OrganizationDto organizationDto = db.organizations().insertForKey("my-org-key-1");
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setKey("sonar-java").setName("Sonar Java"));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setKey("sonar-groovy").setName("Sonar Groovy"));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setKey("sonar-markdown").setName("Sonar Markdown"));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto).setKey("sonarqube").setName("Sonar Qube"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setKey("sonar-java").setName("Sonar Java"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setKey("sonar-groovy").setName("Sonar Groovy"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setKey("sonar-markdown").setName("Sonar Markdown"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto).setKey("sonarqube").setName("Sonar Qube"));
 
     assertThat(call(request.setFilter("query = \"Groovy\"")).getComponentsList()).extracting(Component::getName).containsOnly("Sonar Groovy");
     assertThat(call(request.setFilter("query = \"oNar\"")).getComponentsList()).extracting(Component::getName).containsOnly("Sonar Java", "Sonar Groovy", "Sonar Markdown",
@@ -340,13 +341,13 @@ public class SearchProjectsActionTest {
     OrganizationDto organization4 = db.organizations().insert();
     OrganizationDto organization5 = db.organizations().insert();
     List<Map<String, Object>> someMeasure = singletonList(newMeasure(COVERAGE, 81));
-    ComponentDto favourite1_1 = insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization1), someMeasure);
-    ComponentDto favourite1_2 = insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization1), someMeasure);
-    ComponentDto nonFavourite1 = insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization1), someMeasure);
-    ComponentDto favourite2 = insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization2), someMeasure);
-    ComponentDto nonFavourite2 = insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization2), someMeasure);
-    ComponentDto favourite3 = insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization3), someMeasure);
-    ComponentDto nonFavourite4 = insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization4), someMeasure);
+    ComponentDto favourite1_1 = insertProjectInDbAndEs(newPrivateProjectDto(organization1), someMeasure);
+    ComponentDto favourite1_2 = insertProjectInDbAndEs(newPrivateProjectDto(organization1), someMeasure);
+    ComponentDto nonFavourite1 = insertProjectInDbAndEs(newPrivateProjectDto(organization1), someMeasure);
+    ComponentDto favourite2 = insertProjectInDbAndEs(newPrivateProjectDto(organization2), someMeasure);
+    ComponentDto nonFavourite2 = insertProjectInDbAndEs(newPrivateProjectDto(organization2), someMeasure);
+    ComponentDto favourite3 = insertProjectInDbAndEs(newPrivateProjectDto(organization3), someMeasure);
+    ComponentDto nonFavourite4 = insertProjectInDbAndEs(newPrivateProjectDto(organization4), someMeasure);
     Stream.of(favourite1_1, favourite1_2, favourite2, favourite3)
       .forEach(this::addFavourite);
     insertMetrics(COVERAGE, NCLOC);
@@ -387,7 +388,7 @@ public class SearchProjectsActionTest {
       newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 10_000d)));
     ComponentDto markDownProject = insertProjectInDbAndEs(newPrivateProjectDto(db.getDefaultOrganization(), "markdown-id").setName("Sonar Markdown"),
       newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(db.organizations().insert()).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d)));
     addFavourite(javaProject);
     addFavourite(markDownProject);
     dbSession.commit();
@@ -403,7 +404,7 @@ public class SearchProjectsActionTest {
   public void filtering_on_favorites_returns_empty_results_if_not_logged_in() {
     ComponentDto javaProject = insertProjectInDbAndEs(newPrivateProjectDto(db.getDefaultOrganization(), "java-id").setName("Sonar Java"),
       newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 10_000d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(db.organizations().insert()).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_001d)));
     addFavourite(javaProject);
     dbSession.commit();
     request.setFilter("isFavorite");
@@ -416,7 +417,7 @@ public class SearchProjectsActionTest {
 
   @Test
   public void do_not_return_isFavorite_if_anonymous_user() {
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81)));
+    insertProjectInDbAndEs(newPrivateProjectDto(db.getDefaultOrganization()).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81)));
     insertMetrics(COVERAGE);
     userSession.anonymous();
 
@@ -428,7 +429,7 @@ public class SearchProjectsActionTest {
 
   @Test
   public void empty_list_if_isFavorite_filter_and_anonymous_user() {
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81)));
+    insertProjectInDbAndEs(newPrivateProjectDto(db.getDefaultOrganization()).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81)));
     insertMetrics(COVERAGE);
     userSession.anonymous();
     request.setFilter("isFavorite");
@@ -441,10 +442,10 @@ public class SearchProjectsActionTest {
   @Test
   public void return_nloc_facet() {
     OrganizationDto organization = db.getDefaultOrganization();
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 500_001d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 500_001d)));
     insertMetrics(COVERAGE, NCLOC);
 
     SearchProjectsWsResponse result = call(request.setFacets(singletonList(NCLOC)));
@@ -467,10 +468,10 @@ public class SearchProjectsActionTest {
   @Test
   public void return_languages_facet() {
     OrganizationDto organization = db.getDefaultOrganization();
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81d)), null, asList("<null>", "java", "xoo"));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81)), null, asList("java", "xoo"));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d)), null, asList("xoo"));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d)), null, asList("<null>", "java", "xoo"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81d)), null, asList("<null>", "java", "xoo"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81)), null, asList("java", "xoo"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d)), null, asList("xoo"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d)), null, asList("<null>", "java", "xoo"));
     insertMetrics(COVERAGE, NCLOC_LANGUAGE_DISTRIBUTION_KEY);
 
     SearchProjectsWsResponse result = call(request.setFacets(singletonList(FILTER_LANGUAGES)));
@@ -490,8 +491,8 @@ public class SearchProjectsActionTest {
   @Test
   public void return_languages_facet_with_language_having_no_project_if_language_is_in_filter() {
     OrganizationDto organization = db.getDefaultOrganization();
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81d)), null, asList("<null>", "java"));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81)), null, asList("java"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81d)), null, asList("<null>", "java"));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81)), null, asList("java"));
     insertMetrics(COVERAGE, NCLOC_LANGUAGE_DISTRIBUTION_KEY);
 
     SearchProjectsWsResponse result = call(request.setFilter("languages = xoo").setFacets(singletonList(FILTER_LANGUAGES)));
@@ -510,9 +511,9 @@ public class SearchProjectsActionTest {
   @Test
   public void return_tags_facet() {
     OrganizationDto organization = db.getDefaultOrganization();
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Java").setTags(newArrayList("finance", "platform")));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Markdown").setTags(singletonList("offshore")));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Qube").setTags(newArrayList("offshore")));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Java").setTags(newArrayList("finance", "platform")));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Markdown").setTags(singletonList("offshore")));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Qube").setTags(newArrayList("offshore")));
 
     SearchProjectsWsResponse result = call(request.setFacets(singletonList(FILTER_TAGS)));
 
@@ -531,9 +532,9 @@ public class SearchProjectsActionTest {
   @Test
   public void return_tags_facet_with_tags_having_no_project_if_tags_is_in_filter() {
     OrganizationDto organization = db.getDefaultOrganization();
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Java").setTags(newArrayList("finance", "platform")));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Markdown").setTags(singletonList("offshore")));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Qube").setTags(newArrayList("offshore")));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Java").setTags(newArrayList("finance", "platform")));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Markdown").setTags(singletonList("offshore")));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Qube").setTags(newArrayList("offshore")));
 
     SearchProjectsWsResponse result = call(request.setFilter("tags = marketing").setFacets(singletonList(FILTER_TAGS)));
 
@@ -549,13 +550,61 @@ public class SearchProjectsActionTest {
         tuple("marketing", 0L));
   }
 
+  @Test
+  public void return_reliability_rating_facet() throws Exception {
+    OrganizationDto organization = db.getDefaultOrganization();
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(RELIABILITY_RATING_KEY, 1d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(RELIABILITY_RATING_KEY, 1d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(RELIABILITY_RATING_KEY, 3d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(RELIABILITY_RATING_KEY, 5d)));
+    insertMetrics(RELIABILITY_RATING_KEY);
+
+    SearchProjectsWsResponse result = call(request.setFacets(singletonList(RELIABILITY_RATING_KEY)));
+
+    Common.Facet facet = result.getFacets().getFacetsList().stream()
+      .filter(oneFacet -> RELIABILITY_RATING_KEY.equals(oneFacet.getProperty()))
+      .findFirst().orElseThrow(IllegalStateException::new);
+    assertThat(facet.getValuesList())
+      .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
+      .containsExactly(
+        tuple("1", 2L),
+        tuple("2", 0L),
+        tuple("3", 1L),
+        tuple("4", 0L),
+        tuple("5", 1L));
+  }
+
+  @Test
+  public void return_new_reliability_rating_facet() throws Exception {
+    OrganizationDto organization = db.getDefaultOrganization();
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(NEW_RELIABILITY_RATING_KEY, 1d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(NEW_RELIABILITY_RATING_KEY, 1d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(NEW_RELIABILITY_RATING_KEY, 3d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(NEW_RELIABILITY_RATING_KEY, 5d)));
+    insertMetrics(NEW_RELIABILITY_RATING_KEY);
+
+    SearchProjectsWsResponse result = call(request.setFacets(singletonList(NEW_RELIABILITY_RATING_KEY)));
+
+    Common.Facet facet = result.getFacets().getFacetsList().stream()
+      .filter(oneFacet -> NEW_RELIABILITY_RATING_KEY.equals(oneFacet.getProperty()))
+      .findFirst().orElseThrow(IllegalStateException::new);
+    assertThat(facet.getValuesList())
+      .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount)
+      .containsExactly(
+        tuple("1", 2L),
+        tuple("2", 0L),
+        tuple("3", 1L),
+        tuple("4", 0L),
+        tuple("5", 1L));
+  }
+
   @Test
   public void default_sort_is_by_ascending_name() throws Exception {
     OrganizationDto organization = db.getDefaultOrganization();
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 500_001d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 500_001d)));
 
     SearchProjectsWsResponse result = call(request);
 
@@ -565,10 +614,10 @@ public class SearchProjectsActionTest {
   @Test
   public void sort_by_name() throws Exception {
     OrganizationDto organization = db.getDefaultOrganization();
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 500_001d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 500_001d)));
 
     assertThat(call(request.setSort("name").setAsc(true)).getComponentsList()).extracting(Component::getName)
       .containsExactly("Sonar Groovy", "Sonar Java", "Sonar Markdown", "Sonar Qube");
@@ -579,10 +628,10 @@ public class SearchProjectsActionTest {
   @Test
   public void sort_by_coverage() throws Exception {
     OrganizationDto organization = db.getDefaultOrganization();
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 500_001d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Java"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Groovy"), newArrayList(newMeasure(COVERAGE, 81), newMeasure(NCLOC, 5d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Markdown"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 10_000d)));
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Qube"), newArrayList(newMeasure(COVERAGE, 80d), newMeasure(NCLOC, 500_001d)));
     insertMetrics(COVERAGE);
 
     assertThat(call(request.setSort(COVERAGE).setAsc(true)).getComponentsList()).extracting(Component::getName)
@@ -594,10 +643,10 @@ public class SearchProjectsActionTest {
   @Test
   public void sort_by_quality_gate() throws Exception {
     OrganizationDto organization = db.getDefaultOrganization();
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Java"), "ERROR");
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Groovy"), "WARN");
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Markdown"), "OK");
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organization).setName("Sonar Qube"), "OK");
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Java"), "ERROR");
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Groovy"), "WARN");
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Markdown"), "OK");
+    insertProjectInDbAndEs(newPrivateProjectDto(organization).setName("Sonar Qube"), "OK");
     dbClient.metricDao().insert(dbSession, newMetricDto().setKey(QUALITY_GATE_STATUS).setValueType(LEVEL.name()).setEnabled(true).setHidden(false));
     db.commit();
 
@@ -610,13 +659,13 @@ public class SearchProjectsActionTest {
   @Test
   public void return_last_analysis_date() {
     OrganizationDto organizationDto = db.organizations().insert();
-    ComponentDto project1 = insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto));
+    ComponentDto project1 = insertProjectInDbAndEs(newPrivateProjectDto(organizationDto));
     db.components().insertSnapshot(newAnalysis(project1).setCreatedAt(10_000_000_000L).setLast(false));
     db.components().insertSnapshot(newAnalysis(project1).setCreatedAt(20_000_000_000L).setLast(true));
-    ComponentDto project2 = insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto));
+    ComponentDto project2 = insertProjectInDbAndEs(newPrivateProjectDto(organizationDto));
     db.components().insertSnapshot(newAnalysis(project2).setCreatedAt(30_000_000_000L).setLast(true));
     // No snapshot on project 3
-    insertProjectInDbAndEs(ComponentTesting.newPrivateProjectDto(organizationDto));
+    insertProjectInDbAndEs(newPrivateProjectDto(organizationDto));
 
     SearchProjectsWsResponse result = call(request.setAdditionalFields(singletonList("analysisDate")));
 
index 58ad169b97d751728be3ceaee375c7280c121bbc..2276b5edf5a92f1499626487503c2735e5571bf1 100644 (file)
@@ -69,6 +69,7 @@ public class ProjectMeasuresIndexTest {
 
   private static final String MAINTAINABILITY_RATING = "sqale_rating";
   private static final String RELIABILITY_RATING = "reliability_rating";
+  private static final String NEW_RELIABILITY_RATING = "new_reliability_rating";
   private static final String SECURITY_RATING = "security_rating";
   private static final String COVERAGE = "coverage";
   private static final String DUPLICATION = "duplicated_lines_density";
@@ -870,6 +871,41 @@ public class ProjectMeasuresIndexTest {
       entry("5", 5L));
   }
 
+  @Test
+  public void facet_new_reliability_rating() {
+    index(
+      // 3 docs with rating A
+      newDoc(NEW_RELIABILITY_RATING, 1d),
+      newDoc(NEW_RELIABILITY_RATING, 1d),
+      newDoc(NEW_RELIABILITY_RATING, 1d),
+      // 2 docs with rating B
+      newDoc(NEW_RELIABILITY_RATING, 2d),
+      newDoc(NEW_RELIABILITY_RATING, 2d),
+      // 4 docs with rating C
+      newDoc(NEW_RELIABILITY_RATING, 3d),
+      newDoc(NEW_RELIABILITY_RATING, 3d),
+      newDoc(NEW_RELIABILITY_RATING, 3d),
+      newDoc(NEW_RELIABILITY_RATING, 3d),
+      // 2 docs with rating D
+      newDoc(NEW_RELIABILITY_RATING, 4d),
+      newDoc(NEW_RELIABILITY_RATING, 4d),
+      // 5 docs with rating E
+      newDoc(NEW_RELIABILITY_RATING, 5d),
+      newDoc(NEW_RELIABILITY_RATING, 5d),
+      newDoc(NEW_RELIABILITY_RATING, 5d),
+      newDoc(NEW_RELIABILITY_RATING, 5d),
+      newDoc(NEW_RELIABILITY_RATING, 5d));
+
+    Facets facets = underTest.search(new ProjectMeasuresQuery(), new SearchOptions().addFacets(NEW_RELIABILITY_RATING)).getFacets();
+
+    assertThat(facets.get(NEW_RELIABILITY_RATING)).containsExactly(
+      entry("1", 3L),
+      entry("2", 2L),
+      entry("3", 4L),
+      entry("4", 2L),
+      entry("5", 5L));
+  }
+
   @Test
   public void facet_security_rating() {
     index(
@@ -1074,8 +1110,7 @@ public class ProjectMeasuresIndexTest {
       entry("ruby", 1L),
       entry("scala", 1L),
       entry("xoo", 1L),
-      entry("xml", 1L)
-    );
+      entry("xml", 1L));
   }
 
   @Test
@@ -1158,9 +1193,11 @@ public class ProjectMeasuresIndexTest {
       newDoc().setTags(newArrayList("finance1", "finance2", "finance3", "finance4", "finance5", "finance6", "finance7", "finance8", "finance9", "finance10")),
       newDoc().setTags(newArrayList("solo", "solo2")));
 
-    Map<String, Long> result = underTest.search(new ProjectMeasuresQuery().setTags(ImmutableSet.of("solo", "solo2")), new SearchOptions().addFacets(FIELD_TAGS)).getFacets().get(FIELD_TAGS);
+    Map<String, Long> result = underTest.search(new ProjectMeasuresQuery().setTags(ImmutableSet.of("solo", "solo2")), new SearchOptions().addFacets(FIELD_TAGS)).getFacets()
+      .get(FIELD_TAGS);
 
-    assertThat(result).hasSize(12).containsOnlyKeys("finance1", "finance2", "finance3", "finance4", "finance5", "finance6", "finance7", "finance8", "finance9", "finance10", "solo", "solo2");
+    assertThat(result).hasSize(12).containsOnlyKeys("finance1", "finance2", "finance3", "finance4", "finance5", "finance6", "finance7", "finance8", "finance9", "finance10", "solo",
+      "solo2");
   }
 
   @Test
index 202e7eb33ea41acb6a24ab0b3932d7df12cc1045..005e47d92ed1159522a56177811608d4e555eec3 100644 (file)
@@ -80,10 +80,11 @@ public class ComponentsService extends BaseService {
 
   public SearchProjectsWsResponse searchProjects(SearchProjectsRequest request) {
     List<String> additionalFields = request.getAdditionalFields();
+    List<String> facets = request.getFacets();
     GetRequest get = new GetRequest(path(ACTION_SEARCH_PROJECTS))
       .setParam(PARAM_ORGANIZATION, request.getOrganization())
       .setParam(PARAM_FILTER, request.getFilter())
-      .setParam(Param.FACETS, request.getFacets())
+      .setParam(Param.FACETS, !facets.isEmpty() ? inlineMultipleParamValue(facets) : null)
       .setParam(Param.SORT, request.getSort())
       .setParam(Param.ASCENDING, request.getAsc())
       .setParam(Param.PAGE, request.getPage())
index 1096ae434865dbac721cdc8a4ab6dfb7c8c476fe..36d6b5d565e2cd2b3758ca039edf063d84dbede8 100644 (file)
@@ -24,6 +24,7 @@ import org.junit.Test;
 import org.sonarqube.ws.client.ServiceTester;
 import org.sonarqube.ws.client.WsConnector;
 
+import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
 import static org.mockito.Mockito.mock;
 import static org.sonar.api.server.ws.WebService.Param.ASCENDING;
@@ -45,7 +46,7 @@ public class ComponentsServiceTest {
   public void search_projects() {
     underTest.searchProjects(SearchProjectsRequest.builder()
       .setFilter("ncloc > 10")
-      .setFacets(singletonList("ncloc"))
+      .setFacets(asList("ncloc", "duplicated_lines_density"))
       .setSort("coverage")
       .setAsc(true)
       .setPage(3)
@@ -56,7 +57,7 @@ public class ComponentsServiceTest {
     serviceTester.assertThat(serviceTester.getGetRequest())
       .hasPath("search_projects")
       .hasParam(PARAM_FILTER, "ncloc > 10")
-      .hasParam(FACETS, singletonList("ncloc"))
+      .hasParam(FACETS, "ncloc,duplicated_lines_density")
       .hasParam(SORT, "coverage")
       .hasParam(ASCENDING, true)
       .hasParam(PAGE, 3)