]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9482 Show ws returns profile related info only
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 28 Jun 2017 12:31:19 +0000 (14:31 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 4 Jul 2017 14:29:36 +0000 (16:29 +0200)
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ShowAction.java
server/sonar-server/src/main/resources/org/sonar/server/qualityprofile/ws/show-example.json
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ShowActionTest.java
sonar-ws/src/main/protobuf/ws-qualityprofiles.proto

index 7b4020baf943e41365aac3cdbfd46744e2dd4010..eb15750a717c12204b81ea17b924cee95aeba0c9 100644 (file)
  */
 package org.sonar.server.qualityprofile.ws;
 
+import java.util.Map;
+import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.server.ws.WebService.NewAction;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.qualityprofile.ActiveRuleCountQuery;
+import org.sonar.db.qualityprofile.QProfileDto;
 import org.sonarqube.ws.QualityProfiles.ShowWsResponse;
-import org.sonarqube.ws.QualityProfiles.ShowWsResponse.CompareToSonarWay;
+import org.sonarqube.ws.QualityProfiles.ShowWsResponse.QualityProfile;
 
+import static java.util.Collections.singletonList;
+import static org.sonar.api.rule.RuleStatus.DEPRECATED;
+import static org.sonar.api.utils.DateUtils.formatDateTime;
+import static org.sonar.core.util.Protobuf.setNullable;
 import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01;
+import static org.sonar.server.ws.WsUtils.checkFound;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_COMPARE_TO_SONAR_WAY;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE;
 
 public class ShowAction implements QProfileWsAction {
 
+  private final DbClient dbClient;
+  private final QProfileWsSupport qProfileWsSupport;
+  private final Languages languages;
+
+  public ShowAction(DbClient dbClient, QProfileWsSupport qProfileWsSupport, Languages languages) {
+    this.dbClient = dbClient;
+    this.qProfileWsSupport = qProfileWsSupport;
+    this.languages = languages;
+  }
+
   @Override
   public void define(WebService.NewController controller) {
     NewAction show = controller.createAction("show")
@@ -55,29 +78,50 @@ public class ShowAction implements QProfileWsAction {
 
   @Override
   public void handle(Request request, Response response) throws Exception {
-    ShowWsResponse showWsResponse = ShowWsResponse.newBuilder()
-      .setProfile(ShowWsResponse.QualityProfile.newBuilder()
-        .setKey("AU-TpxcA-iU5OvuD2FL3")
-        .setName("My Company Profile")
-        .setLanguage("cs")
-        .setLanguageName("C#")
-        .setIsInherited(true)
-        .setIsBuiltIn(false)
-        .setIsDefault(false)
-        .setParentKey("AU-TpxcA-iU5OvuD2FL1")
-        .setParentName("Parent Company Profile")
-        .setActiveRuleCount(10)
-        .setActiveDeprecatedRuleCount(0)
-        .setProjectCount(7)
-        .setRuleUpdatedAt("2016-12-22T19:10:03+0100")
-        .setLastUsed("2016-12-01T19:10:03+0100"))
-      .setCompareToSonarWay(CompareToSonarWay.newBuilder()
-        .setProfile("iU5OvuD2FLz")
-        .setProfileName("Sonar way")
-        .setMissingRuleCount(4)
-        .build())
-      .build();
-    writeProtobuf(showWsResponse, request, response);
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      QProfileDto profile = qProfileWsSupport.getProfile(dbSession, QProfileReference.fromKey(request.mandatoryParam(PARAM_PROFILE)));
+      OrganizationDto organization = qProfileWsSupport.getOrganization(dbSession, profile);
+      boolean isDefault = dbClient.defaultQProfileDao().isDefault(dbSession, profile.getOrganizationUuid(), profile.getKee());
+      ActiveRuleCountQuery.Builder builder = ActiveRuleCountQuery.builder().setOrganization(organization);
+      long activeRuleCount = countActiveRulesByQuery(dbSession, profile, builder);
+      long deprecatedActiveRuleCount = countActiveRulesByQuery(dbSession, profile, builder.setRuleStatus(DEPRECATED));
+      long projectCount = countProjectsByOrganizationAndProfiles(dbSession, organization, profile);
+      writeProtobuf(buildResponse(profile, isDefault, getLanguage(profile), activeRuleCount, deprecatedActiveRuleCount, projectCount), request, response);
+    }
+  }
+
+  private long countActiveRulesByQuery(DbSession dbSession, QProfileDto profile, ActiveRuleCountQuery.Builder queryBuilder) {
+    Map<String, Long> result = dbClient.activeRuleDao().countActiveRulesByQuery(dbSession, queryBuilder.setProfiles(singletonList(profile)).build());
+    return result.getOrDefault(profile.getKee(), 0L);
+  }
+
+  private long countProjectsByOrganizationAndProfiles(DbSession dbSession, OrganizationDto organization, QProfileDto profile) {
+    Map<String, Long> projects = dbClient.qualityProfileDao().countProjectsByOrganizationAndProfiles(dbSession, organization, singletonList(profile));
+    return projects.getOrDefault(profile.getKee(), 0L);
+  }
+
+  public Language getLanguage(QProfileDto profile) {
+    Language language = languages.get(profile.getLanguage());
+    checkFound(language, "Quality Profile with key '%s' does not exist", profile.getKee());
+    return language;
+  }
+
+  private static ShowWsResponse buildResponse(QProfileDto profile, boolean isDefault, Language language, long activeRules, long deprecatedActiveRules, long projects) {
+    QualityProfile.Builder profileBuilder = QualityProfile.newBuilder()
+      .setKey(profile.getKee())
+      .setName(profile.getName())
+      .setLanguage(profile.getLanguage())
+      .setLanguageName(language.getName())
+      .setIsBuiltIn(profile.isBuiltIn())
+      .setIsDefault(isDefault)
+      .setIsInherited(profile.getParentKee() != null)
+      .setActiveRuleCount(activeRules)
+      .setActiveDeprecatedRuleCount(deprecatedActiveRules)
+      .setProjectCount(projects);
+    setNullable(profile.getRulesUpdatedAt(), profileBuilder::setRulesUpdatedAt);
+    setNullable(profile.getLastUsed(), last -> profileBuilder.setLastUsed(formatDateTime(last)));
+    setNullable(profile.getUserUpdatedAt(), userUpdatedAt -> profileBuilder.setUserUpdatedAt(formatDateTime(userUpdatedAt)));
+    return ShowWsResponse.newBuilder().setProfile(profileBuilder).build();
   }
 
 }
index 60f03aaf168ed909878126ba7e4c2764713e0f39..a628efa37c27c3a05325c4c5a86f81eab4e7d642 100644 (file)
@@ -7,12 +7,10 @@
     "isInherited": true,
     "isBuiltIn": false,
     "isDefault": false,
-    "parentKey": "AU-TpxcA-iU5OvuD2FL1",
-    "parentName": "Parent Company Profile",
     "activeRuleCount": 10,
     "activeDeprecatedRuleCount": 0,
     "projectCount": 7,
-    "ruleUpdatedAt": "2016-12-22T19:10:03+0100",
+    "rulesUpdatedAt": "2016-12-22T19:10:03+0100",
     "lastUsed": "2016-12-01T19:10:03+0100"
   },
   "compareToSonarWay": {
index b7f9b98f35d6dd694cafa463a478f51b5619d1b8..5b90834477b79cc2dbbe9aa3365352ba49d538a5 100644 (file)
@@ -22,23 +22,45 @@ package org.sonar.server.qualityprofile.ws;
 
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 import org.sonar.api.resources.Language;
+import org.sonar.api.resources.Languages;
 import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.DateUtils;
 import org.sonar.db.DbTester;
 import org.sonar.db.qualityprofile.QProfileDto;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.organization.TestDefaultOrganizationProvider;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.MediaTypes;
+import org.sonarqube.ws.QualityProfiles.ShowWsResponse;
 
 import static java.util.stream.IntStream.range;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.rule.RuleStatus.DEPRECATED;
+import static org.sonar.api.utils.DateUtils.parseDateTime;
 import static org.sonar.server.language.LanguageTesting.newLanguage;
 import static org.sonar.test.JsonAssert.assertJson;
+import static org.sonarqube.ws.QualityProfiles.ShowWsResponse.QualityProfile;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE;
 
 public class ShowActionTest {
 
+  private static Language XOO1 = newLanguage("xoo1");
+  private static Language XOO2 = newLanguage("xoo2");
+  private static Languages LANGUAGES = new Languages(XOO1, XOO2);
+
   @Rule
   public DbTester db = DbTester.create();
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
 
-  private WsActionTester ws = new WsActionTester(new ShowAction());
+  private WsActionTester ws = new WsActionTester(
+    new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)), LANGUAGES));
 
   @Test
   public void test_definition() {
@@ -49,13 +71,11 @@ public class ShowActionTest {
     assertThat(action.since()).isEqualTo("6.5");
 
     WebService.Param profile = action.param("profile");
-    assertThat(profile).isNotNull();
     assertThat(profile.isRequired()).isTrue();
     assertThat(profile.isInternal()).isFalse();
     assertThat(profile.description()).isNotEmpty();
 
     WebService.Param compareToSonarWay = action.param("compareToSonarWay");
-    assertThat(compareToSonarWay).isNotNull();
     assertThat(compareToSonarWay.isRequired()).isFalse();
     assertThat(compareToSonarWay.isInternal()).isTrue();
     assertThat(compareToSonarWay.description()).isNotEmpty();
@@ -63,9 +83,102 @@ public class ShowActionTest {
   }
 
   @Test
-  public void test_example() {
+  public void profile_info() {
+    QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
+
+    ShowWsResponse result = call(ws.newRequest().setParam(PARAM_PROFILE, profile.getKee()));
+
+    assertThat(result.getProfile())
+      .extracting(QualityProfile::getKey, QualityProfile::getName, QualityProfile::getIsBuiltIn, QualityProfile::getLanguage, QualityProfile::getLanguageName,
+        QualityProfile::getIsInherited)
+      .containsExactly(profile.getKee(), profile.getName(), profile.isBuiltIn(), profile.getLanguage(), XOO1.getName(), false);
+  }
+
+  @Test
+  public void default_profile() {
+    QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
+    db.qualityProfiles().setAsDefault(profile);
+
+    ShowWsResponse result = call(ws.newRequest().setParam(PARAM_PROFILE, profile.getKee()));
+
+    assertThat(result.getProfile().getIsDefault()).isTrue();
+  }
+
+  @Test
+  public void non_default_profile() {
+    QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
+    QProfileDto defaultProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
+    db.qualityProfiles().setAsDefault(defaultProfile);
+
+    ShowWsResponse result = call(ws.newRequest().setParam(PARAM_PROFILE, profile.getKee()));
+
+    assertThat(result.getProfile().getIsDefault()).isFalse();
+  }
+
+  @Test
+  public void map_dates() {
+    long time = DateUtils.parseDateTime("2016-12-22T19:10:03+0100").getTime();
+    QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p
+      .setLanguage(XOO1.getKey())
+      .setRulesUpdatedAt("2016-12-21T19:10:03+0100")
+      .setLastUsed(time)
+      .setUserUpdatedAt(time));
+
+    ShowWsResponse result = call(ws.newRequest().setParam(PARAM_PROFILE, profile.getKee()));
+
+    assertThat(result.getProfile().getRulesUpdatedAt()).isEqualTo("2016-12-21T19:10:03+0100");
+    assertThat(parseDateTime(result.getProfile().getLastUsed()).getTime()).isEqualTo(time);
+    assertThat(parseDateTime(result.getProfile().getUserUpdatedAt()).getTime()).isEqualTo(time);
+  }
+
+  @Test
+  public void statistics() {
+    QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(XOO1.getKey()));
+    // Active rules
+    range(0, 10)
+      .mapToObj(i -> db.rules().insertRule(r -> r.setLanguage(XOO1.getKey())).getDefinition())
+      .forEach(r -> db.qualityProfiles().activateRule(profile, r));
+    // Deprecated rules
+    range(0, 3)
+      .mapToObj(i -> db.rules().insertRule(r -> r.setLanguage(XOO1.getKey()).setStatus(DEPRECATED)).getDefinition())
+      .forEach(r -> db.qualityProfiles().activateRule(profile, r));
+    // Projects
+    range(0, 7)
+      .mapToObj(i -> db.components().insertPrivateProject())
+      .forEach(project -> db.qualityProfiles().associateWithProject(project, profile));
+
+    ShowWsResponse result = call(ws.newRequest().setParam(PARAM_PROFILE, profile.getKee()));
+
+    assertThat(result.getProfile())
+      .extracting(QualityProfile::getActiveRuleCount, QualityProfile::getActiveDeprecatedRuleCount, QualityProfile::getProjectCount)
+      .containsExactly(13L, 3L, 7L);
+  }
+
+  @Test
+  public void fail_if_profile_language_is_not_supported() {
+    QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setKee("unknown-profile").setLanguage("kotlin"));
+
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("Quality Profile with key 'unknown-profile' does not exist");
+
+    call(ws.newRequest().setParam(PARAM_PROFILE, profile.getKee()));
+  }
+
+  @Test
+  public void fail_if_profile_does_not_exist() {
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("Quality Profile with key 'unknown-profile' does not exist");
+
+    call(ws.newRequest().setParam(PARAM_PROFILE, "unknown-profile"));
+  }
+
+  @Test
+  public void json_example() {
     Language cs = newLanguage("cs", "C#");
-    QProfileDto parentProfile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setKee("AU-TpxcA-iU5OvuD2FL1").setName("Parent Company Profile"));
+    QProfileDto parentProfile = db.qualityProfiles().insert(db.getDefaultOrganization(),
+      p -> p.setKee("AU-TpxcA-iU5OvuD2FL1")
+        .setName("Parent Company Profile")
+        .setLanguage(cs.getKey()));
     QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p
       .setKee("AU-TpxcA-iU5OvuD2FL3")
       .setName("My Company Profile")
@@ -82,8 +195,14 @@ public class ShowActionTest {
       .mapToObj(i -> db.components().insertPrivateProject())
       .forEach(project -> db.qualityProfiles().associateWithProject(project, profile));
 
-    String result = ws.newRequest().execute().getInput();
+    ws = new WsActionTester(new ShowAction(db.getDbClient(), new QProfileWsSupport(db.getDbClient(), userSession, TestDefaultOrganizationProvider.from(db)), new Languages(cs)));
+    String result = ws.newRequest().setParam(PARAM_PROFILE, profile.getKee()).execute().getInput();
+
+    assertJson(result).ignoreFields("rulesUpdatedAt", "lastUsed", "userUpdatedAt", "compareToSonarWay").isSimilarTo(ws.getDef().responseExampleAsString());
+  }
 
-    assertJson(result).isSimilarTo(ws.getDef().responseExampleAsString());
+  private ShowWsResponse call(TestRequest request) {
+    TestRequest wsRequest = request.setMediaType(MediaTypes.PROTOBUF);
+    return wsRequest.executeProtobuf(ShowWsResponse.class);
   }
 }
index 0dab9b3c06f35c326c4f33ba3b27a3d5989d4c2f..0f1ddd6cb0b1bbc7e39ded6a4661dda684f7238e 100644 (file)
@@ -111,17 +111,15 @@ message ShowWsResponse {
     optional string language = 3;
     optional string languageName = 4;
     optional bool isInherited = 5;
-    optional string parentKey = 6;
-    optional string parentName = 7;
-    optional bool isDefault = 8;
-    optional int64 activeRuleCount = 9;
-    optional int64 activeDeprecatedRuleCount = 12;
-    optional int64 projectCount = 10;
-    optional string ruleUpdatedAt = 11;
-    optional string lastUsed = 13;
-    optional string userUpdatedAt = 14;
-    optional string organization = 15;
-    optional bool isBuiltIn = 16;
+    optional bool isDefault = 6;
+    optional int64 activeRuleCount = 7;
+    optional int64 activeDeprecatedRuleCount = 8;
+    optional int64 projectCount = 9;
+    optional string rulesUpdatedAt = 10;
+    optional string lastUsed = 11;
+    optional string userUpdatedAt = 12;
+    optional string organization = 13;
+    optional bool isBuiltIn = 14;
   }
 
   message CompareToSonarWay {