aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-db
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2016-09-11 10:12:36 +0200
committerSimon Brandhof <simon.brandhof@sonarsource.com>2016-09-12 14:11:59 +0200
commit6c0b5563fbc8b0fbf9ed0aa722302a8f1e74cdf4 (patch)
treeb777f55fbb3408d696260c54a369bc0d9f3227eb /sonar-db
parentb5851d0ff8318549c2356b20df36401b879fc5a2 (diff)
downloadsonarqube-6c0b5563fbc8b0fbf9ed0aa722302a8f1e74cdf4.tar.gz
sonarqube-6c0b5563fbc8b0fbf9ed0aa722302a8f1e74cdf4.zip
SONAR-7851 add QProfileChangeDao
Diffstat (limited to 'sonar-db')
-rw-r--r--sonar-db/src/main/java/org/sonar/db/DaoModule.java7
-rw-r--r--sonar-db/src/main/java/org/sonar/db/DbClient.java7
-rw-r--r--sonar-db/src/main/java/org/sonar/db/MyBatis.java3
-rw-r--r--sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDao.java56
-rw-r--r--sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDto.java117
-rw-r--r--sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeMapper.java32
-rw-r--r--sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeQuery.java92
-rw-r--r--sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java4
-rw-r--r--sonar-db/src/main/resources/org/sonar/db/qualityprofile/QProfileChangeMapper.xml74
-rw-r--r--sonar-db/src/test/java/org/sonar/db/DaoModuleTest.java2
-rw-r--r--sonar-db/src/test/java/org/sonar/db/DbTester.java2
-rw-r--r--sonar-db/src/test/java/org/sonar/db/qualityprofile/QProfileChangeDaoTest.java213
-rw-r--r--sonar-db/src/test/java/org/sonar/db/qualityprofile/QProfileChangeDtoTest.java45
-rw-r--r--sonar-db/src/test/java/org/sonar/db/qualityprofile/QualityProfileTesting.java22
-rw-r--r--sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java2
15 files changed, 669 insertions, 9 deletions
diff --git a/sonar-db/src/main/java/org/sonar/db/DaoModule.java b/sonar-db/src/main/java/org/sonar/db/DaoModule.java
index 880090dcdde..630f07632b9 100644
--- a/sonar-db/src/main/java/org/sonar/db/DaoModule.java
+++ b/sonar-db/src/main/java/org/sonar/db/DaoModule.java
@@ -25,6 +25,7 @@ import org.sonar.core.platform.Module;
import org.sonar.db.activity.ActivityDao;
import org.sonar.db.ce.CeActivityDao;
import org.sonar.db.ce.CeQueueDao;
+import org.sonar.db.ce.CeScannerContextDao;
import org.sonar.db.ce.CeTaskInputDao;
import org.sonar.db.component.ComponentDao;
import org.sonar.db.component.ComponentKeyUpdaterDao;
@@ -59,9 +60,9 @@ import org.sonar.db.qualitygate.ProjectQgateAssociationDao;
import org.sonar.db.qualitygate.QualityGateConditionDao;
import org.sonar.db.qualitygate.QualityGateDao;
import org.sonar.db.qualityprofile.ActiveRuleDao;
+import org.sonar.db.qualityprofile.QProfileChangeDao;
import org.sonar.db.qualityprofile.QualityProfileDao;
import org.sonar.db.rule.RuleDao;
-import org.sonar.db.ce.CeScannerContextDao;
import org.sonar.db.source.FileSourceDao;
import org.sonar.db.user.AuthorDao;
import org.sonar.db.user.AuthorizationDao;
@@ -110,6 +111,7 @@ public class DaoModule extends Module {
QualityGateDao.class,
QualityGateConditionDao.class,
QualityProfileDao.class,
+ QProfileChangeDao.class,
CeScannerContextDao.class,
RuleDao.class,
ActiveRuleDao.class,
@@ -122,7 +124,8 @@ public class DaoModule extends Module {
UserGroupDao.class,
UserTokenDao.class,
WidgetDao.class,
- WidgetPropertyDao.class).build();
+ WidgetPropertyDao.class
+ ).build();
@Override
protected void configureModule() {
diff --git a/sonar-db/src/main/java/org/sonar/db/DbClient.java b/sonar-db/src/main/java/org/sonar/db/DbClient.java
index 6a6f4d182ca..ceabd8c62ae 100644
--- a/sonar-db/src/main/java/org/sonar/db/DbClient.java
+++ b/sonar-db/src/main/java/org/sonar/db/DbClient.java
@@ -60,6 +60,7 @@ import org.sonar.db.qualitygate.ProjectQgateAssociationDao;
import org.sonar.db.qualitygate.QualityGateConditionDao;
import org.sonar.db.qualitygate.QualityGateDao;
import org.sonar.db.qualityprofile.ActiveRuleDao;
+import org.sonar.db.qualityprofile.QProfileChangeDao;
import org.sonar.db.qualityprofile.QualityProfileDao;
import org.sonar.db.rule.RuleDao;
import org.sonar.db.source.FileSourceDao;
@@ -125,6 +126,7 @@ public class DbClient {
private final GroupDao groupDao;
private final RuleDao ruleDao;
private final ActiveRuleDao activeRuleDao;
+ private final QProfileChangeDao qProfileChangeDao;
public DbClient(Database database, MyBatis myBatis, Dao... daos) {
this.database = database;
@@ -183,6 +185,7 @@ public class DbClient {
groupDao = getDao(map, GroupDao.class);
ruleDao = getDao(map, RuleDao.class);
activeRuleDao = getDao(map, ActiveRuleDao.class);
+ qProfileChangeDao = getDao(map, QProfileChangeDao.class);
}
public DbSession openSession(boolean batch) {
@@ -393,6 +396,10 @@ public class DbClient {
return activeRuleDao;
}
+ public QProfileChangeDao qProfileChangeDao() {
+ return qProfileChangeDao;
+ }
+
protected <K extends Dao> K getDao(Map<Class, Dao> map, Class<K> clazz) {
return (K) map.get(clazz);
}
diff --git a/sonar-db/src/main/java/org/sonar/db/MyBatis.java b/sonar-db/src/main/java/org/sonar/db/MyBatis.java
index e2d37996d3c..ca25a31117a 100644
--- a/sonar-db/src/main/java/org/sonar/db/MyBatis.java
+++ b/sonar-db/src/main/java/org/sonar/db/MyBatis.java
@@ -108,6 +108,7 @@ import org.sonar.db.qualitygate.QualityGateMapper;
import org.sonar.db.qualityprofile.ActiveRuleDto;
import org.sonar.db.qualityprofile.ActiveRuleMapper;
import org.sonar.db.qualityprofile.ActiveRuleParamDto;
+import org.sonar.db.qualityprofile.QProfileChangeMapper;
import org.sonar.db.qualityprofile.QualityProfileDto;
import org.sonar.db.qualityprofile.QualityProfileMapper;
import org.sonar.db.rule.RuleDto;
@@ -236,7 +237,7 @@ public class MyBatis {
UserMapper.class, GroupMapper.class, UserGroupMapper.class, UserTokenMapper.class,
FileSourceMapper.class,
NotificationQueueMapper.class,
- GroupMembershipMapper.class, QualityProfileMapper.class, ActiveRuleMapper.class,
+ GroupMembershipMapper.class, QualityProfileMapper.class, ActiveRuleMapper.class, QProfileChangeMapper.class,
MeasureMapper.class, MetricMapper.class, CustomMeasureMapper.class, QualityGateMapper.class, QualityGateConditionMapper.class, ComponentMapper.class, SnapshotMapper.class,
ProjectQgateAssociationMapper.class, EventMapper.class,
CeQueueMapper.class, CeActivityMapper.class, CeTaskInputMapper.class, CeScannerContextMapper.class,
diff --git a/sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDao.java b/sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDao.java
new file mode 100644
index 00000000000..41c6474d4e4
--- /dev/null
+++ b/sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDao.java
@@ -0,0 +1,56 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonar.db.qualityprofile;
+
+import java.util.List;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.Dao;
+import org.sonar.db.DbSession;
+
+import static com.google.common.base.Preconditions.checkState;
+
+public class QProfileChangeDao implements Dao {
+
+ private final System2 system2;
+ private final UuidFactory uuidFactory;
+
+ public QProfileChangeDao(System2 system2, UuidFactory uuidFactory) {
+ this.system2 = system2;
+ this.uuidFactory = uuidFactory;
+ }
+
+ public void insert(DbSession dbSession, QProfileChangeDto dto) {
+ checkState(dto.getKey() == null, "Key of QProfileChangeDto must be set by DAO only. Got %s.", dto.getKey());
+ checkState(dto.getCreatedAt() == 0L, "Date of QProfileChangeDto must be set by DAO only. Got %s.", dto.getCreatedAt());
+
+ dto.setKey(uuidFactory.create());
+ dto.setCreatedAt(system2.now());
+ dbSession.getMapper(QProfileChangeMapper.class).insert(dto);
+ }
+
+ public List<QProfileChangeDto> selectByQuery(DbSession dbSession, QProfileChangeQuery query) {
+ return dbSession.getMapper(QProfileChangeMapper.class).selectByQuery(query);
+ }
+
+ public int countForProfileKey(DbSession dbSession, String profileKey) {
+ return dbSession.getMapper(QProfileChangeMapper.class).countForProfileKey(profileKey);
+ }
+}
diff --git a/sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDto.java b/sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDto.java
new file mode 100644
index 00000000000..ab12cb0908f
--- /dev/null
+++ b/sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeDto.java
@@ -0,0 +1,117 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonar.db.qualityprofile;
+
+import java.util.Collections;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.utils.KeyValueFormat;
+
+public class QProfileChangeDto {
+
+ private String key;
+ private String profileKey;
+ // can't be named "type" because it's a reserved word in Oracle
+ // (used by Mybatis to map DB column with DTO field)
+ private String changeType;
+ private String login;
+ private String data;
+ private long createdAt;
+
+ public String getKey() {
+ return key;
+ }
+
+ public QProfileChangeDto setKey(String s) {
+ this.key = s;
+ return this;
+ }
+
+ public String getProfileKey() {
+ return profileKey;
+ }
+
+ public QProfileChangeDto setProfileKey(String s) {
+ this.profileKey = s;
+ return this;
+ }
+
+ public String getChangeType() {
+ return changeType;
+ }
+
+ public QProfileChangeDto setChangeType(String s) {
+ this.changeType = s;
+ return this;
+ }
+
+ public long getCreatedAt() {
+ return createdAt;
+ }
+
+ public QProfileChangeDto setCreatedAt(long l) {
+ this.createdAt = l;
+ return this;
+ }
+
+ @CheckForNull
+ public String getLogin() {
+ return login;
+ }
+
+ public QProfileChangeDto setLogin(@Nullable String s) {
+ this.login = s;
+ return this;
+ }
+
+ @CheckForNull
+ public String getData() {
+ return data;
+ }
+
+ public Map<String, String> getDataAsMap() {
+ if (data == null) {
+ return Collections.emptyMap();
+ }
+ return KeyValueFormat.parse(data);
+ }
+
+ public QProfileChangeDto setData(@Nullable String csv) {
+ this.data = csv;
+ return this;
+ }
+
+ public QProfileChangeDto setData(@Nullable Map m) {
+ if (m == null || m.isEmpty()) {
+ this.data = null;
+ } else {
+ this.data = KeyValueFormat.format(m);
+ }
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+}
diff --git a/sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeMapper.java b/sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeMapper.java
new file mode 100644
index 00000000000..a50c9b8cbf1
--- /dev/null
+++ b/sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeMapper.java
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonar.db.qualityprofile;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+
+public interface QProfileChangeMapper {
+
+ void insert(QProfileChangeDto dto);
+
+ List<QProfileChangeDto> selectByQuery(@Param("query") QProfileChangeQuery query);
+
+ int countForProfileKey(@Param("profileKey") String profileKey);
+}
diff --git a/sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeQuery.java b/sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeQuery.java
new file mode 100644
index 00000000000..334dbaab240
--- /dev/null
+++ b/sonar-db/src/main/java/org/sonar/db/qualityprofile/QProfileChangeQuery.java
@@ -0,0 +1,92 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonar.db.qualityprofile;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+
+import static java.util.Objects.requireNonNull;
+
+public class QProfileChangeQuery {
+
+ private final String profileKey;
+ private Long fromIncluded;
+ private Long toExcluded;
+ private int offset = 0;
+ private int limit = 100;
+
+ public QProfileChangeQuery(String profileKey) {
+ this.profileKey = requireNonNull(profileKey);
+ }
+
+ public String getProfileKey() {
+ return profileKey;
+ }
+
+ @CheckForNull
+ public Long getFromIncluded() {
+ return fromIncluded;
+ }
+
+ public void setFromIncluded(@Nullable Long l) {
+ this.fromIncluded = l;
+ }
+
+ @CheckForNull
+ public Long getToExcluded() {
+ return toExcluded;
+ }
+
+ public void setToExcluded(@Nullable Long l) {
+ this.toExcluded = l;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+
+ public void setOffset(int offset) {
+ this.offset = offset;
+ }
+
+ public int getLimit() {
+ return limit;
+ }
+
+ public void setLimit(int limit) {
+ this.limit = limit;
+ }
+
+ public void setPage(int page, int pageSize) {
+ offset = (page -1) * pageSize;
+ limit = pageSize;
+ }
+
+ public int getTotal() {
+ return offset + limit;
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+}
diff --git a/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java b/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
index 9bd60db038d..3d97895f8ac 100644
--- a/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
+++ b/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
@@ -322,13 +322,9 @@ public class MigrationStepModule extends Module {
ShrinkModuleUuidPathOfProjects.class,
AddBUuidPathToProjects.class,
AddErrorColumnsToCeActivity.class,
-<<<<<<< HEAD
PopulateTableProperties2.class,
- RemoveViewsDefinitionFromProperties.class);
-=======
RemoveViewsDefinitionFromProperties.class,
CopyActivitiesToQprofileChanges.class
);
->>>>>>> SONAR-7851 copy activities to qprofile_changes
}
}
diff --git a/sonar-db/src/main/resources/org/sonar/db/qualityprofile/QProfileChangeMapper.xml b/sonar-db/src/main/resources/org/sonar/db/qualityprofile/QProfileChangeMapper.xml
new file mode 100644
index 00000000000..d2a3b3b6490
--- /dev/null
+++ b/sonar-db/src/main/resources/org/sonar/db/qualityprofile/QProfileChangeMapper.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+
+<mapper namespace="org.sonar.db.qualityprofile.QProfileChangeMapper">
+
+ <insert id="insert" useGeneratedKeys="false" parameterType="org.sonar.db.qualityprofile.QProfileChangeDto">
+ insert into qprofile_changes
+ (
+ kee,
+ qprofile_key,
+ created_at,
+ user_login,
+ change_type,
+ data
+ ) values (
+ #{key,jdbcType=VARCHAR},
+ #{profileKey,jdbcType=VARCHAR},
+ #{createdAt,jdbcType=BIGINT},
+ #{login,jdbcType=VARCHAR},
+ #{changeType,jdbcType=VARCHAR},
+ #{data,jdbcType=VARCHAR}
+ )
+ </insert>
+
+ <select id="countForProfileKey" resultType="int">
+ select count(kee) from qprofile_changes
+ where qprofile_key = #{profileKey}
+ </select>
+
+ <select id="selectByQuery" resultType="org.sonar.db.qualityprofile.QProfileChangeDto">
+ <include refid="sqlSelectByQuery" />
+ limit #{query.limit}
+ offset #{query.offset}
+ </select>
+
+ <select id="selectByQuery" databaseId="mssql" resultType="org.sonar.db.qualityprofile.QProfileChangeDto">
+ <include refid="sqlSelectByQuery" />
+ offset #{query.offset} rows
+ fetch next #{query.limit} rows only
+ </select>
+
+ <select id="selectByQuery" databaseId="oracle" resultType="org.sonar.db.qualityprofile.QProfileChangeDto">
+ select "key", profileKey, createdAt, login, changeType, data from (
+ select rownum rnum, "key", profileKey, createdAt, login, changeType, data from (
+ <include refid="sqlSelectByQuery" />
+ )
+ where rownum &lt;= #{query.total}
+ )
+ where rnum > #{query.offset}
+ </select>
+
+ <sql id="sqlColumns">
+ kee as "key",
+ qprofile_key as profileKey,
+ created_at as createdAt,
+ user_login as login,
+ change_type as changeType,
+ data
+ </sql>
+
+ <sql id="sqlSelectByQuery">
+ select <include refid="sqlColumns" />
+ from qprofile_changes
+ where qprofile_key = #{query.profileKey}
+ <if test="query.fromIncluded != null">
+ and created_at &gt;= #{query.fromIncluded}
+ </if>
+ <if test="query.toExcluded != null">
+ and created_at &lt; #{query.toExcluded}
+ </if>
+ order by created_at desc
+ </sql>
+</mapper>
+
diff --git a/sonar-db/src/test/java/org/sonar/db/DaoModuleTest.java b/sonar-db/src/test/java/org/sonar/db/DaoModuleTest.java
index 8e8d42a1996..8e7a117b0eb 100644
--- a/sonar-db/src/test/java/org/sonar/db/DaoModuleTest.java
+++ b/sonar-db/src/test/java/org/sonar/db/DaoModuleTest.java
@@ -29,6 +29,6 @@ public class DaoModuleTest {
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new DaoModule().configure(container);
- assertThat(container.size()).isEqualTo(2 + 49);
+ assertThat(container.size()).isEqualTo(2 + 50);
}
}
diff --git a/sonar-db/src/test/java/org/sonar/db/DbTester.java b/sonar-db/src/test/java/org/sonar/db/DbTester.java
index b2b6f08716d..f56843dd329 100644
--- a/sonar-db/src/test/java/org/sonar/db/DbTester.java
+++ b/sonar-db/src/test/java/org/sonar/db/DbTester.java
@@ -57,6 +57,7 @@ import org.junit.rules.ExternalResource;
import org.picocontainer.containers.TransientPicoContainer;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.Loggers;
+import org.sonar.core.util.SequenceUuidFactory;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Lists.newArrayList;
@@ -123,6 +124,7 @@ public class DbTester extends ExternalResource {
TransientPicoContainer ioc = new TransientPicoContainer();
ioc.addComponent(db.getMyBatis());
ioc.addComponent(system2);
+ ioc.addComponent(new SequenceUuidFactory());
for (Class daoClass : DaoModule.classes()) {
ioc.addComponent(daoClass);
}
diff --git a/sonar-db/src/test/java/org/sonar/db/qualityprofile/QProfileChangeDaoTest.java b/sonar-db/src/test/java/org/sonar/db/qualityprofile/QProfileChangeDaoTest.java
new file mode 100644
index 00000000000..80fb2ce73d4
--- /dev/null
+++ b/sonar-db/src/test/java/org/sonar/db/qualityprofile/QProfileChangeDaoTest.java
@@ -0,0 +1,213 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonar.db.qualityprofile;
+
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.utils.System2;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+
+import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class QProfileChangeDaoTest {
+
+ private static final long A_DATE = 1_500_000_000_000L;
+
+ private System2 system2 = mock(System2.class);
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Rule
+ public DbTester dbTester = DbTester.create(system2);
+
+ private DbSession dbSession = dbTester.getSession();
+ private UuidFactory uuidFactory = mock(UuidFactory.class);
+ private QProfileChangeDao underTest = new QProfileChangeDao(system2, uuidFactory);
+
+ @Test
+ public void test_insert_without_null_fields() {
+ when(system2.now()).thenReturn(A_DATE);
+ when(uuidFactory.create()).thenReturn("C1");
+
+ String profileKey = "P1";
+ String login = "marcel";
+ String type = "ACTIVATED";
+ String data = "some_data";
+ insertChange(profileKey, type, login, data);
+
+ Map<String, Object> row = selectChangeByKey("C1");
+ assertThat(row.get("qprofileKey")).isEqualTo(profileKey);
+ assertThat(row.get("createdAt")).isEqualTo(A_DATE);
+ assertThat(row.get("login")).isEqualTo(login);
+ assertThat(row.get("changeType")).isEqualTo(type);
+ assertThat(row.get("data")).isEqualTo(data);
+ }
+
+ /**
+ * user_login and data can be null
+ */
+ @Test
+ public void test_insert_with_nullable_fields() {
+ when(system2.now()).thenReturn(A_DATE);
+ when(uuidFactory.create()).thenReturn("C1");
+
+ insertChange("P1", "ACTIVATED", null, null);
+
+ Map<String, Object> row = selectChangeByKey("C1");
+ assertThat(row.get("qprofileKey")).isEqualTo("P1");
+ assertThat(row.get("createdAt")).isEqualTo(A_DATE);
+ assertThat(row.get("changeType")).isEqualTo("ACTIVATED");
+ assertThat(row.get("login")).isNull();
+ assertThat(row.get("data")).isNull();
+ }
+
+ @Test
+ public void insert_throws_ISE_if_key_is_already_set() {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Key of QProfileChangeDto must be set by DAO only. Got C1.");
+
+ underTest.insert(dbSession, new QProfileChangeDto().setKey("C1"));
+ }
+
+ @Test
+ public void insert_throws_ISE_if_date_is_already_set() {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Date of QProfileChangeDto must be set by DAO only. Got 123.");
+
+ underTest.insert(dbSession, new QProfileChangeDto().setCreatedAt(123L));
+ }
+
+ @Test
+ public void selectByQuery_returns_empty_list_if_no_profile_changes() {
+ List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, new QProfileChangeQuery("P1"));
+ assertThat(changes).isEmpty();
+ }
+
+ @Test
+ public void selectByQuery_returns_changes_ordered_by_descending_date() {
+ when(system2.now()).thenReturn(A_DATE, A_DATE + 1, A_DATE + 2);
+ when(uuidFactory.create()).thenReturn("C1", "C2", "C3");
+
+ // profile P1
+ insertChange("P1", "ACTIVATED", null, null);// key: C1
+ insertChange("P1", "ACTIVATED", null, null);// key: C2
+ // profile P2: C3
+ insertChange("P2", "ACTIVATED", null, null);// key: C3
+
+ List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, new QProfileChangeQuery("P1"));
+ assertThat(changes).extracting(QProfileChangeDto::getKey).containsExactly("C2", "C1");
+ }
+
+ @Test
+ public void selectByQuery_supports_pagination_of_changes() {
+ when(system2.now()).thenReturn(A_DATE, A_DATE + 10, A_DATE + 20, A_DATE + 30);
+ when(uuidFactory.create()).thenReturn("C1", "C2", "C3", "C4");
+ insertChange("P1", "ACTIVATED", null, null);// key: C1
+ insertChange("P1", "ACTIVATED", null, null);// key: C2
+ insertChange("P1", "ACTIVATED", null, null);// key: C3
+ insertChange("P1", "ACTIVATED", null, null);// key: C4
+
+ QProfileChangeQuery query = new QProfileChangeQuery("P1");
+ query.setOffset(2);
+ query.setLimit(1);
+ List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, query);
+ assertThat(changes).extracting(QProfileChangeDto::getKey).containsExactly("C2");
+ }
+
+ @Test
+ public void selectByQuery_returns_changes_after_given_date() {
+ when(system2.now()).thenReturn(A_DATE, A_DATE + 10, A_DATE + 20);
+ when(uuidFactory.create()).thenReturn("C1", "C2", "C3", "C4");
+ insertChange("P1", "ACTIVATED", null, null);// key: C1
+ insertChange("P1", "ACTIVATED", null, null);// key: C2
+ insertChange("P1", "ACTIVATED", null, null);// key: C3
+
+ QProfileChangeQuery query = new QProfileChangeQuery("P1");
+ query.setFromIncluded(A_DATE + 10);
+ List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, query);
+ assertThat(changes).extracting(QProfileChangeDto::getKey).containsExactly("C3", "C2");
+ }
+
+ @Test
+ public void selectByQuery_returns_changes_before_given_date() {
+ when(system2.now()).thenReturn(A_DATE, A_DATE + 10, A_DATE + 20);
+ when(uuidFactory.create()).thenReturn("C1", "C2", "C3", "C4");
+ insertChange("P1", "ACTIVATED", null, null);// key: C1
+ insertChange("P1", "ACTIVATED", null, null);// key: C2
+ insertChange("P1", "ACTIVATED", null, null);// key: C3
+
+ QProfileChangeQuery query = new QProfileChangeQuery("P1");
+ query.setToExcluded(A_DATE + 12);
+ List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, query);
+ assertThat(changes).extracting(QProfileChangeDto::getKey).containsExactly("C2", "C1");
+ }
+
+ @Test
+ public void selectByQuery_returns_changes_in_a_range_of_dates() {
+ when(system2.now()).thenReturn(A_DATE, A_DATE + 10, A_DATE + 20, A_DATE + 30);
+ when(uuidFactory.create()).thenReturn("C1", "C2", "C3", "C4");
+ insertChange("P1", "ACTIVATED", null, null);// key: C1
+ insertChange("P1", "ACTIVATED", null, null);// key: C2
+ insertChange("P1", "ACTIVATED", null, null);// key: C3
+ insertChange("P1", "ACTIVATED", null, null);// key: C4
+
+ QProfileChangeQuery query = new QProfileChangeQuery("P1");
+ query.setFromIncluded(A_DATE + 8);
+ query.setToExcluded(A_DATE + 22);
+ List<QProfileChangeDto> changes = underTest.selectByQuery(dbSession, query);
+ assertThat(changes).extracting(QProfileChangeDto::getKey).containsExactly("C3", "C2");
+ }
+
+ @Test
+ public void test_countForProfileKey() {
+ when(system2.now()).thenReturn(A_DATE, A_DATE + 10);
+ when(uuidFactory.create()).thenReturn("C1", "C2");
+
+ insertChange("P1", "ACTIVATED", null, null);// key: C1
+ insertChange("P1", "ACTIVATED", null, null);// key: C2
+
+ assertThat(underTest.countForProfileKey(dbSession, "P1")).isEqualTo(2);
+ assertThat(underTest.countForProfileKey(dbSession, "P2")).isEqualTo(0);
+ }
+
+ private void insertChange(String profileKey, String type, @Nullable String login, @Nullable String data) {
+ QProfileChangeDto dto = new QProfileChangeDto()
+ .setProfileKey(profileKey)
+ .setLogin(login)
+ .setChangeType(type)
+ .setData(data);
+ underTest.insert(dbSession, dto);
+ }
+
+ private Map<String, Object> selectChangeByKey(String key) {
+ return dbTester.selectFirst(dbSession,
+ "select qprofile_key as \"qprofileKey\", created_at as \"createdAt\", user_login as \"login\", change_type as \"changeType\", data as \"data\" from qprofile_changes where kee='"
+ + key + "'");
+ }
+}
diff --git a/sonar-db/src/test/java/org/sonar/db/qualityprofile/QProfileChangeDtoTest.java b/sonar-db/src/test/java/org/sonar/db/qualityprofile/QProfileChangeDtoTest.java
new file mode 100644
index 00000000000..d3912dcd6f6
--- /dev/null
+++ b/sonar-db/src/test/java/org/sonar/db/qualityprofile/QProfileChangeDtoTest.java
@@ -0,0 +1,45 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonar.db.qualityprofile;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Collections;
+import java.util.Map;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.data.MapEntry.entry;
+
+public class QProfileChangeDtoTest {
+
+ private QProfileChangeDto underTest = new QProfileChangeDto();
+
+ @Test
+ public void convert_data_to_map() {
+ underTest.setData((Map) null);
+ assertThat(underTest.getDataAsMap()).isEmpty();
+
+ underTest.setData(Collections.emptyMap());
+ assertThat(underTest.getDataAsMap()).isEmpty();
+
+ underTest.setData(ImmutableMap.of("k1", "v1", "k2", "v2"));
+ assertThat(underTest.getDataAsMap()).containsOnly(entry("k1", "v1"), entry("k2", "v2"));
+ }
+}
diff --git a/sonar-db/src/test/java/org/sonar/db/qualityprofile/QualityProfileTesting.java b/sonar-db/src/test/java/org/sonar/db/qualityprofile/QualityProfileTesting.java
index 836b5beca31..0dccace4541 100644
--- a/sonar-db/src/test/java/org/sonar/db/qualityprofile/QualityProfileTesting.java
+++ b/sonar-db/src/test/java/org/sonar/db/qualityprofile/QualityProfileTesting.java
@@ -22,11 +22,15 @@ package org.sonar.db.qualityprofile;
import java.util.Date;
import org.sonar.core.util.Uuids;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import static java.util.Arrays.stream;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.apache.commons.lang.math.RandomUtils.nextLong;
public class QualityProfileTesting {
+
public static QualityProfileDto newQualityProfileDto() {
String uuid = Uuids.createFast();
QualityProfileDto dto = QualityProfileDto.createFor(uuid)
@@ -37,4 +41,22 @@ public class QualityProfileTesting {
.setUpdatedAt(new Date());
return dto;
}
+
+ public static QProfileChangeDto newQProfileChangeDto() {
+ return new QProfileChangeDto()
+ .setKey(randomAlphanumeric(40))
+ .setProfileKey(randomAlphanumeric(40))
+ .setCreatedAt(nextLong())
+ .setChangeType("ACTIVATED")
+ .setLogin(randomAlphanumeric(10));
+ }
+
+ public static void insert(DbTester dbTester, QProfileChangeDto... dtos) {
+ // do not use QProfileChangeDao so that generated fields key and creation date
+ // can be defined by tests
+ DbSession dbSession = dbTester.getSession();
+ QProfileChangeMapper mapper = dbSession.getMapper(QProfileChangeMapper.class);
+ stream(dtos).forEach(dto -> mapper.insert(dto));
+ dbSession.commit();
+ }
}
diff --git a/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java b/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
index d7acef90b52..d1dfd506a72 100644
--- a/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
+++ b/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
@@ -29,6 +29,6 @@ public class MigrationStepModuleTest {
public void verify_count_of_added_MigrationStep_types() {
ComponentContainer container = new ComponentContainer();
new MigrationStepModule().configure(container);
- assertThat(container.size()).isEqualTo(134);
+ assertThat(container.size()).isEqualTo(135);
}
}