*/
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")
@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();
}
}
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() {
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();
}
@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")
.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);
}
}