]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9498 show correct n. of "more" items in quality profile changelog
authorDaniel Schwarz <daniel.schwarz@sonarsource.com>
Mon, 2 Oct 2017 14:03:03 +0000 (16:03 +0200)
committerDaniel Schwarz <bartfastiel@users.noreply.github.com>
Wed, 4 Oct 2017 11:32:03 +0000 (13:32 +0200)
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDao.java
server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/QProfileChangeMapper.java
server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QProfileChangeMapper.xml
server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QProfileChangeDaoTest.java
server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ChangelogAction.java
server/sonar-server/src/test/java/org/sonar/server/qualityprofile/ws/ChangelogActionTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/ChangelogWsRequest.java [new file with mode: 0644]
sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesService.java
tests/src/test/java/org/sonarqube/tests/qualityProfile/QualityProfilesWsTest.java

index fcf6ae54add3686aeb1ba48dc78a8ce1bc4e8013..2505550a070db4055e184704723d983e01198da5 100644 (file)
@@ -50,8 +50,11 @@ public class QProfileChangeDao implements Dao {
     return mapper(dbSession).selectByQuery(query);
   }
 
-  public int countForQProfileUuid(DbSession dbSession, String profileUuid) {
-    return mapper(dbSession).countForQProfileUuid(profileUuid);
+  /**
+   * Note: offset and limit of the query object will be ignored
+   */
+  public int countByQuery(DbSession dbSession, QProfileChangeQuery query) {
+    return mapper(dbSession).countByQuery(query);
   }
 
   public void deleteByRulesProfileUuids(DbSession dbSession, Collection<String> ruleProfileUuids) {
index 8177b689ad640ac99bf231d5d26b19983bc97e90..dfcd26080ac12e3c885271faf7418059ba15e647 100644 (file)
@@ -29,7 +29,7 @@ public interface QProfileChangeMapper {
 
   List<QProfileChangeDto> selectByQuery(@Param("query") QProfileChangeQuery query);
 
-  int countForQProfileUuid(@Param("qProfileUuid") String qProfileUuid);
+  int countByQuery(@Param("query") QProfileChangeQuery query);
 
   void deleteByRuleProfileUuids(@Param("ruleProfileUuids") Collection<String> uuids);
 }
index 684354d2b4b3095ce2ff2ab9d39474fddcf8bea7..9e9b5e8d76b2ad6f9d7f5bb89442a0072a6174fe 100644 (file)
     )
   </insert>
 
-  <select id="countForQProfileUuid" resultType="int">
+  <select id="countByQuery" resultType="int">
     select count(qpc.kee)
-    from qprofile_changes qpc
-    inner join rules_profiles rp on rp.kee = qpc.rules_profile_uuid
-    inner join org_qprofiles oqp on oqp.rules_profile_uuid = rp.kee
-    where
-      oqp.uuid = #{qProfileUuid, jdbcType=VARCHAR}
+    <include refid="sqlSelectByQuery" />
   </select>
 
   <select id="selectByQuery" resultType="org.sonar.db.qualityprofile.QProfileChangeDto">
+    select <include refid="selectColumns" />
     <include refid="sqlSelectByQuery" />
+    order by qpc.created_at desc
     limit #{query.limit}
     offset #{query.offset}
   </select>
 
   <select id="selectByQuery" databaseId="mssql" resultType="org.sonar.db.qualityprofile.QProfileChangeDto">
+    select <include refid="selectColumns" />
     <include refid="sqlSelectByQuery" />
+    order by qpc.created_at desc
     offset #{query.offset} rows
     fetch next #{query.limit} rows only
   </select>
@@ -55,7 +55,9 @@
   <select id="selectByQuery" databaseId="oracle" resultType="org.sonar.db.qualityprofile.QProfileChangeDto">
     select "uuid", rulesProfileUuid, createdAt, login, changeType, data from (
     select rownum rnum, "uuid", rulesProfileUuid, createdAt, login, changeType, data from (
+    select <include refid="selectColumns" />
     <include refid="sqlSelectByQuery" />
+    order by qpc.created_at desc
     )
     where rownum &lt;= #{query.total}
     )
@@ -63,7 +65,6 @@
   </select>
 
   <sql id="sqlSelectByQuery">
-    select <include refid="selectColumns" />
     from qprofile_changes qpc
     inner join rules_profiles rp on rp.kee = qpc.rules_profile_uuid
     inner join org_qprofiles oqp on oqp.rules_profile_uuid = rp.kee
@@ -75,7 +76,6 @@
       <if test="query.toExcluded != null">
         and qpc.created_at &lt; #{query.toExcluded}
       </if>
-    order by qpc.created_at desc
   </sql>
 
   <delete id="deleteByRuleProfileUuids" parameterType="String">
index 7e62fc60387dca18866bda6b578ef9f046e3fe4d..4ab6fce2cb7704beb335af95b8819854076ffb05 100644 (file)
@@ -188,16 +188,26 @@ public class QProfileChangeDaoTest {
   }
 
   @Test
-  public void countForQProfileUuid() {
+  public void countByQuery() {
     QProfileDto profile1 = db.qualityProfiles().insert(db.getDefaultOrganization());
     QProfileDto profile2 = db.qualityProfiles().insert(db.getDefaultOrganization());
+    long start = system2.now();
     insertChange(profile1, "ACTIVATED", null, null);
     insertChange(profile1, "ACTIVATED", null, null);
     insertChange(profile2, "ACTIVATED", null, null);
+    long end = system2.now();
 
-    assertThat(underTest.countForQProfileUuid(dbSession, profile1.getKee())).isEqualTo(2);
-    assertThat(underTest.countForQProfileUuid(dbSession, profile2.getKee())).isEqualTo(1);
-    assertThat(underTest.countForQProfileUuid(dbSession, "does_not_exist")).isEqualTo(0);
+    assertThat(underTest.countByQuery(dbSession, new QProfileChangeQuery(profile1.getKee()))).isEqualTo(2);
+    assertThat(underTest.countByQuery(dbSession, new QProfileChangeQuery(profile2.getKee()))).isEqualTo(1);
+    assertThat(underTest.countByQuery(dbSession, new QProfileChangeQuery("does_not_exist"))).isEqualTo(0);
+
+    QProfileChangeQuery query = new QProfileChangeQuery(profile1.getKee());
+    query.setToExcluded(start);
+    assertThat(underTest.countByQuery(dbSession, query)).isEqualTo(0);
+
+    QProfileChangeQuery query2 = new QProfileChangeQuery(profile1.getKee());
+    query2.setToExcluded(end);
+    assertThat(underTest.countByQuery(dbSession, query2)).isEqualTo(2);
   }
 
   @Test
@@ -210,8 +220,8 @@ public class QProfileChangeDaoTest {
 
     underTest.deleteByRulesProfileUuids(dbSession, asList(profile1.getRulesProfileUuid()));
 
-    assertThat(underTest.countForQProfileUuid(dbSession, profile1.getKee())).isEqualTo(0);
-    assertThat(underTest.countForQProfileUuid(dbSession, profile2.getKee())).isEqualTo(1);
+    assertThat(underTest.countByQuery(dbSession, new QProfileChangeQuery(profile1.getKee()))).isEqualTo(0);
+    assertThat(underTest.countByQuery(dbSession, new QProfileChangeQuery(profile2.getKee()))).isEqualTo(1);
   }
 
   @Test
@@ -221,7 +231,7 @@ public class QProfileChangeDaoTest {
 
     underTest.deleteByRulesProfileUuids(dbSession, asList("does not exist"));
 
-    assertThat(underTest.countForQProfileUuid(dbSession, profile1.getKee())).isEqualTo(1);
+    assertThat(underTest.countByQuery(dbSession, new QProfileChangeQuery(profile1.getKee()))).isEqualTo(1);
   }
 
   private QProfileChangeDto insertChange(QProfileDto profile, String type, @Nullable String login, @Nullable String data) {
index d53298df16fd82d41da41d4ddaa3fe699b285bad..86a122661310856d70372db6e5169457791c2bd3 100644 (file)
@@ -108,7 +108,7 @@ public class ChangelogAction implements QProfileWsAction {
       int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
       query.setPage(page, pageSize);
 
-      int total = dbClient.qProfileChangeDao().countForQProfileUuid(dbSession, query.getProfileUuid());
+      int total = dbClient.qProfileChangeDao().countByQuery(dbSession, query);
 
       List<Change> changelogs = load(dbSession, query);
       writeResponse(response.newJsonWriter(), total, page, pageSize, changelogs);
index 77c6b0da904b059c78db2d660d7e54cfc4a60a62..4051d824ad7c22671fc0b81b3d399b1b7f583d15 100644 (file)
@@ -57,6 +57,7 @@ import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_ORGANIZATION;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_QUALITY_PROFILE;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_SINCE;
 
 public class ChangelogActionTest {
 
@@ -232,6 +233,37 @@ public class ChangelogActionTest {
     assertThat(response).contains("\"total\":1");
   }
 
+  @Test
+  public void changelog_filter_by_since() throws Exception {
+    QProfileDto qualityProfile = dbTester.qualityProfiles().insert(organization);
+    system2.setNow(DateUtils.parseDateTime("2011-04-25T01:15:42+0100").getTime());
+    QProfileChangeDto change = QualityProfileTesting.newQProfileChangeDto()
+      .setUuid(null)
+      .setCreatedAt(0)
+      .setRulesProfileUuid(qualityProfile.getRulesProfileUuid());
+    DbSession session = dbTester.getSession();
+    dbTester.getDbClient().qProfileChangeDao().insert(session, change);
+    session.commit();
+
+    String response = ws.newRequest()
+      .setMethod("GET")
+      .setParam(PARAM_KEY, qualityProfile.getKee())
+      .setParam(PARAM_SINCE, "2011-04-25T01:15:42+0100")
+      .execute()
+      .getInput();
+
+    assertThat(response).contains("\"total\":1");
+
+    String response2 = ws.newRequest()
+      .setMethod("GET")
+      .setParam(PARAM_KEY, qualityProfile.getKee())
+      .setParam(PARAM_SINCE, "2011-04-25T01:15:43+0100")
+      .execute()
+      .getInput();
+
+    assertThat(response2).contains("\"total\":0");
+  }
+
   @Test
   public void sort_changelog_events_in_reverse_chronological_order() {
     QProfileDto profile = dbTester.qualityProfiles().insert(organization);
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/ChangelogWsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/ChangelogWsRequest.java
new file mode 100644 (file)
index 0000000..d470246
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonarqube.ws.client.qualityprofile;
+
+public class ChangelogWsRequest {
+
+  private final String language;
+  private final String organization;
+  private final Integer p;
+  private final Integer ps;
+  private final String qualityProfile;
+  private final String since;
+  private final String to;
+
+  private ChangelogWsRequest(Builder builder) {
+    this.language = builder.language;
+    this.organization = builder.organization;
+    this.p = builder.p;
+    this.ps = builder.ps;
+    this.qualityProfile = builder.qualityProfile;
+    this.since = builder.since;
+    this.to = builder.to;
+  }
+
+  public String getLanguage() {
+    return language;
+  }
+
+  public String getOrganization() {
+    return organization;
+  }
+
+  public Integer getP() {
+    return p;
+  }
+
+  public Integer getPs() {
+    return ps;
+  }
+
+  public String getQualityProfile() {
+    return qualityProfile;
+  }
+
+  public String getSince() {
+    return since;
+  }
+
+  public String getTo() {
+    return to;
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public static class Builder {
+    private String language;
+    private String organization;
+    private Integer p;
+    private Integer ps;
+    private String qualityProfile;
+    private String since;
+    private String to;
+
+    private Builder() {
+    }
+
+    public Builder setLanguage(String language) {
+      this.language = language;
+      return this;
+    }
+
+    public Builder setOrganization(String organization) {
+      this.organization = organization;
+      return this;
+    }
+
+    public Builder setP(Integer p) {
+      this.p = p;
+      return this;
+    }
+
+    public Builder setPs(Integer ps) {
+      this.ps = ps;
+      return this;
+    }
+
+    public Builder setQualityProfile(String qualityProfile) {
+      this.qualityProfile = qualityProfile;
+      return this;
+    }
+
+    public Builder setSince(String since) {
+      this.since = since;
+      return this;
+    }
+
+    public Builder setTo(String to) {
+      this.to = to;
+      return this;
+    }
+
+    public ChangelogWsRequest build() {
+      return new ChangelogWsRequest(this);
+    }
+  }
+}
index fe2a4171b73570a02398e6e82b43ddb832614771..2364a1dae5058587c967fde7406748ac7af742b0 100644 (file)
@@ -59,15 +59,14 @@ import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_DEFAULTS;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_FROM_KEY;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_GROUP;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_KEY;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE;
-import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_NAME;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LOGIN;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_NAME;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_ORGANIZATION;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PARAMS;
-import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PARENT_QUALITY_PROFILE;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PARENT_KEY;
-import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_KEY;
-import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_QUALITY_PROFILE;
+import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PARENT_QUALITY_PROFILE;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_KEY;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_UUID;
 import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_QUALITY_PROFILE;
@@ -243,4 +242,24 @@ public class QualityProfilesService extends BaseService {
         .setParam(PAGE_SIZE, request.getPageSize()),
       SearchGroupsResponse.parser());
   }
+
+  public String changelog(ChangelogWsRequest request) {
+    PostRequest postRequest = new PostRequest(path("changelog"))
+      .setParam("language", request.getLanguage())
+      .setParam("organization", request.getOrganization())
+      .setParam("qualityProfile", request.getQualityProfile());
+    if (request.getP() != null) {
+      postRequest.setParam("p", request.getP());
+    }
+    if (request.getPs() != null) {
+      postRequest.setParam("ps", request.getPs());
+    }
+    if (request.getSince() != null) {
+      postRequest.setParam("since", request.getSince());
+    }
+    if (request.getTo() != null) {
+      postRequest.setParam("to", request.getTo());
+    }
+    return call(postRequest).content();
+  }
 }
index 6047ae1230d1f4b7f0148e1d1ed3dc166cb60481..b88ad7121fbd1267642635828c2bd12b13f7a9db 100644 (file)
@@ -21,9 +21,12 @@ package org.sonarqube.tests.qualityProfile;
 
 import com.sonar.orchestrator.Orchestrator;
 import java.util.function.Predicate;
+import org.json.JSONException;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.skyscreamer.jsonassert.JSONCompareMode;
 import org.sonarqube.tests.Category6Suite;
 import org.sonarqube.tests.Tester;
 import org.sonarqube.ws.Organizations.Organization;
@@ -35,6 +38,7 @@ import org.sonarqube.ws.QualityProfiles.ShowResponse.QualityProfile;
 import org.sonarqube.ws.client.GetRequest;
 import org.sonarqube.ws.client.PostRequest;
 import org.sonarqube.ws.client.WsResponse;
+import org.sonarqube.ws.client.qualityprofile.ChangelogWsRequest;
 import org.sonarqube.ws.client.qualityprofile.SearchWsRequest;
 import org.sonarqube.ws.client.qualityprofile.ShowRequest;
 
@@ -44,6 +48,12 @@ public class QualityProfilesWsTest {
   private static final String RULE_ONE_BUG_PER_LINE = "xoo:OneBugIssuePerLine";
   private static final String RULE_ONE_ISSUE_PER_LINE = "xoo:OneIssuePerLine";
 
+  private static final String EXPECTED_CHANGELOG = "{\"total\":2,\"p\":1,\"ps\":50,\"events\":[" +
+    "{\"authorLogin\":\"admin\",\"authorName\":\"Administrator\",\"action\":\"ACTIVATED\",\"ruleKey\":\"xoo:OneIssuePerLine\",\"ruleName\":\"One Issue Per Line\",\"params\":{\"severity\":\"MAJOR\"}}," +
+    "{\"authorLogin\":\"admin\",\"authorName\":\"Administrator\",\"action\":\"ACTIVATED\",\"ruleKey\":\"xoo:OneBugIssuePerLine\",\"ruleName\":\"One Bug Issue Per Line\",\"params\":{\"severity\":\"MAJOR\"}}" +
+    "]}";
+  private static final String EXPECTED_CHANGELOG_EMPTY = "{\"total\":0,\"p\":1,\"ps\":50,\"events\":[]}";
+
   @ClassRule
   public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR;
 
@@ -118,6 +128,37 @@ public class QualityProfilesWsTest {
       .isEqualTo("xoo -> empty -> 0");
   }
 
+  @Test
+  public void changelog() throws JSONException {
+    Organization org = tester.organizations().generate();
+    CreateWsResponse.QualityProfile profile = tester.qProfiles().createXooProfile(org);
+
+    String changelog = tester.wsClient().qualityProfiles().changelog(ChangelogWsRequest.builder()
+      .setOrganization(org.getKey())
+      .setLanguage(profile.getLanguage())
+      .setQualityProfile(profile.getName())
+      .build());
+    JSONAssert.assertEquals(EXPECTED_CHANGELOG_EMPTY, changelog, JSONCompareMode.STRICT);
+
+    tester.qProfiles().activateRule(profile, RULE_ONE_BUG_PER_LINE);
+    tester.qProfiles().activateRule(profile, RULE_ONE_ISSUE_PER_LINE);
+
+    String changelog2 = tester.wsClient().qualityProfiles().changelog(ChangelogWsRequest.builder()
+      .setOrganization(org.getKey())
+      .setLanguage(profile.getLanguage())
+      .setQualityProfile(profile.getName())
+      .build());
+    JSONAssert.assertEquals(EXPECTED_CHANGELOG, changelog2, JSONCompareMode.LENIENT);
+
+    String changelog3 = tester.wsClient().qualityProfiles().changelog(ChangelogWsRequest.builder()
+      .setOrganization(org.getKey())
+      .setLanguage(profile.getLanguage())
+      .setQualityProfile(profile.getName())
+      .setSince("2999-12-31T23:59:59+0000")
+      .build());
+    JSONAssert.assertEquals(EXPECTED_CHANGELOG_EMPTY, changelog3, JSONCompareMode.STRICT);
+  }
+
   private SearchWsResponse.QualityProfile getProfile(Organization organization, Predicate<SearchWsResponse.QualityProfile> filter) {
     return tester.qProfiles().service().search(new SearchWsRequest()
       .setOrganizationKey(organization.getKey())).getProfilesList()