return getMapper(session).selectByCharacteristicOrSubCharacteristicId(characteristicOrSubCharacteristicId);
}
+ public List<RuleDto> selectOverridingDebt() {
+ SqlSession session = mybatis.openSession();
+ try {
+ return selectOverridingDebt(session);
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ public List<RuleDto> selectOverridingDebt(SqlSession session) {
+ return getMapper(session).selectOverridingDebt();
+ }
+
@CheckForNull
public RuleDto selectById(Integer id, SqlSession session) {
return getMapper(session).selectById(id);
List<RuleDto> selectByCharacteristicOrSubCharacteristicId(int id);
+ List<RuleDto> selectOverridingDebt();
+
RuleDto selectById(Integer id);
RuleDto selectByName(String name);
* they must be named "<pluginKey>-model.xml".
* </p>
*/
+// TODO move it to sonar-server and rename it DebtModelPluginRepository when it will be no more used by the SQALE plugin
public class TechnicalDebtModelRepository implements ServerExtension, Startable {
public static final String DEFAULT_MODEL = "technical-debt";
</where>
</select>
+ <select id="selectOverridingDebt" resultType="Rule">
+ SELECT <include refid="selectColumns"/> FROM rules
+ <where>
+ AND (characteristic_id is NOT NULL or remediation_function IS NOT NULL)
+ </where>
+ </select>
+
<update id="update" parameterType="Rule">
UPDATE rules SET
plugin_rule_key=#{ruleKey},
<insert id="insert" parameterType="Characteristic" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
INSERT INTO characteristics (kee, name, parent_id, characteristic_order, enabled, created_at, updated_at)
- VALUES (#{kee}, #{name}, #{parentId}, #{characteristicOrder}, #{enabled}, current_timestamp, current_timestamp)
+ VALUES (#{kee}, #{name}, #{parentId}, #{characteristicOrder}, #{enabled}, #{createdAt}, #{updatedAt})
</insert>
<update id="update" parameterType="Characteristic">
setupData("selectAll");
List<RuleDto> ruleDtos = dao.selectAll();
- assertThat(ruleDtos.size()).isEqualTo(1);
+ assertThat(ruleDtos).hasSize(1);
+
RuleDto ruleDto = ruleDtos.get(0);
assertThat(ruleDto.getId()).isEqualTo(1);
assertThat(ruleDto.getName()).isEqualTo("Avoid Null");
assertThat(ruleDtos).isEmpty();
}
+ @Test
+ public void select_overriding_debt_rules() throws Exception {
+ setupData("select_overriding_debt_rules");
+
+ assertThat(dao.selectOverridingDebt()).hasSize(3);
+ }
+
@Test
public void update() {
setupData("update");
public class CharacteristicDaoTest extends AbstractDaoTestCase {
- private static final String[] EXCLUDED_COLUMNS = new String[]{"id", "root_id", "rule_id", "function_key", "factor_unit", "factor_value", "offset_unit", "offset_value",
- "created_at", "updated_at"};
+ private static final String[] EXCLUDED_COLUMNS = new String[]{"id", "root_id", "rule_id", "function_key", "factor_unit", "factor_value", "offset_unit", "offset_value"};
CharacteristicDao dao;
--- /dev/null
+<dataset>
+
+ <!-- Rule overriding debt and with default debt should be returned -->
+ <rules id="1" plugin_rule_key="UselessImportCheck" plugin_name="squid" name="UselessImportCheck" description="Useless imports should be removed" status="READY"
+ characteristic_id="2" default_characteristic_id="50"
+ remediation_function="LINEAR_OFFSET" default_remediation_function="LINEAR_OFFSET"
+ remediation_factor="5d" default_remediation_factor="5d"
+ remediation_offset="10h" default_remediation_offset="10h" updated_at="2014-02-19"/>
+
+ <!-- Rule only overriding debt should be returned -->
+ <rules id="2" plugin_rule_key="LeftCurlyBraceStartLineCheck" plugin_name="squid" name="LeftCurlyBraceStartLineCheck" description="Left curly braces should be located at the beginning of lines of code" status="READY"
+ characteristic_id="3" default_characteristic_id="[null]"
+ remediation_function="LINEAR_OFFSET" default_remediation_function="[null]"
+ remediation_factor="5d" default_remediation_factor="[null]"
+ remediation_offset="10h" default_remediation_offset="[null]" updated_at="2014-02-19"/>
+
+ <!-- Rule with only default debt should be returned -->
+ <rules id="3" plugin_rule_key="CallToFileDeleteOnExitMethod" plugin_name="squid" name="CallToFileDeleteOnExitMethod" description="CallToFileDeleteOnExitMethod" status="READY"
+ characteristic_id="[null]" default_characteristic_id="50"
+ remediation_function="[null]" default_remediation_function="LINEAR_OFFSET"
+ remediation_factor="[null]" default_remediation_factor="5d"
+ remediation_offset="[null]" default_remediation_offset="10h" updated_at="2014-02-19"/>
+
+ <!-- Removed rule overriding debt : should be returned -->
+ <rules id="4" plugin_rule_key="ObjectFinalizeOverridenCallsSuperFinalizeCheck" plugin_name="squid" name="ObjectFinalizeOverridenCallsSuperFinalizeCheck" description="super.finalize() should be called at the end of Object.finalize() implementations" status="REMOVED"
+ characteristic_id="3" default_characteristic_id="50"
+ remediation_function="LINEAR" default_remediation_function="LINEAR_OFFSET"
+ remediation_factor="5d" default_remediation_factor="5min"
+ remediation_offset="[null]" default_remediation_offset="10h" updated_at="2014-02-19"/>
+
+</dataset>
import javax.annotation.CheckForNull;
+import java.util.Date;
+
/**
* @since 4.3
*/
@CheckForNull
Integer parentId();
+
+ Date createdAt();
+
+ @CheckForNull
+ Date updatedAt();
}
import org.sonar.api.server.debt.DebtCharacteristic;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.util.Date;
+
/**
* @since 4.3
*/
private String name;
private Integer order;
private Integer parentId;
+ private Date createdAt;
+ private Date updatedAt;
@Override
public Integer id() {
this.parentId = parentId;
return this;
}
+
+ public Date createdAt() {
+ return createdAt;
+ }
+
+ public DefaultDebtCharacteristic setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ @CheckForNull
+ public Date updatedAt() {
+ return updatedAt;
+ }
+
+ public DefaultDebtCharacteristic setUpdatedAt(@Nullable Date updatedAt) {
+ this.updatedAt = updatedAt;
+ return this;
+ }
+
}
import static com.google.common.collect.Lists.newArrayList;
+/**
+ * @deprecated since 4.3
+ */
+@Deprecated
public class DefaultCharacteristic implements Characteristic {
private Integer id;
package org.sonar.server.debt;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
import org.apache.commons.lang.StringUtils;
import org.codehaus.stax2.XMLInputFactory2;
import org.codehaus.staxmate.SMInputFactory;
import org.codehaus.staxmate.in.SMHierarchicCursor;
import org.codehaus.staxmate.in.SMInputCursor;
import org.sonar.api.ServerExtension;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import java.io.Reader;
import java.io.StringReader;
-import java.util.Collection;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
public class DebtCharacteristicsXMLImporter implements ServerExtension {
}
public DebtModel importXML(Reader xml) {
- DebtModel model = new DebtModel();
+ DebtModel debtModel = new DebtModel();
try {
SMInputFactory inputFactory = initStax();
SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
SMInputCursor chcCursor = cursor.childElementCursor(CHARACTERISTIC);
while (chcCursor.getNext() != null) {
- processCharacteristic(model, null, chcCursor);
+ process(debtModel, null, chcCursor);
}
cursor.getStreamReader().closeCompletely();
} catch (XMLStreamException e) {
throw new IllegalStateException("XML is not valid", e);
}
- return model;
+ return debtModel;
}
private SMInputFactory initStax() {
}
@CheckForNull
- private DefaultCharacteristic processCharacteristic(DebtModel model, @Nullable DefaultCharacteristic parent, SMInputCursor chcCursor) throws XMLStreamException {
- DefaultCharacteristic characteristic = new DefaultCharacteristic();
+ private void process(DebtModel debtModel, @Nullable String parent, SMInputCursor chcCursor) throws XMLStreamException {
+ DefaultDebtCharacteristic characteristic = new DefaultDebtCharacteristic();
SMInputCursor cursor = chcCursor.childElementCursor();
while (cursor.getNext() != null) {
String node = cursor.getLocalName();
if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
+ // TODO Attached to parent only if a key is existing, otherwise characteristic with empty key can be added.
characteristic.setKey(cursor.collectDescendantText().trim());
- // Attached to parent only if a key is existing, otherwise characteristic with empty key can be added.
- characteristic.setParent(parent);
+ if (parent == null) {
+ characteristic.setOrder(debtModel.rootCharacteristics().size() + 1);
+ debtModel.addRootCharacteristic(characteristic);
+ } else {
+ debtModel.addSubCharacteristic(characteristic, parent);
+ }
} else if (StringUtils.equals(node, CHARACTERISTIC_NAME)) {
- characteristic.setName(cursor.collectDescendantText().trim(), false);
+ characteristic.setName(cursor.collectDescendantText().trim());
// <chc> can contain characteristics or requirements
} else if (StringUtils.equals(node, CHARACTERISTIC)) {
- processCharacteristic(model, characteristic, cursor);
+ process(debtModel, characteristic.key(), cursor);
}
}
-
- if (StringUtils.isNotBlank(characteristic.key()) && characteristic.isRoot()) {
- characteristic.setOrder(model.rootCharacteristics().size() + 1);
- model.addRootCharacteristic(characteristic);
- return characteristic;
- }
- return null;
}
-
- static class DebtModel {
-
- private Collection<DefaultCharacteristic> rootCharacteristics;
-
- public DebtModel() {
- rootCharacteristics = newArrayList();
- }
-
- public DebtModel addRootCharacteristic(DefaultCharacteristic characteristic) {
- rootCharacteristics.add(characteristic);
- return this;
- }
-
- public List<DefaultCharacteristic> rootCharacteristics() {
- return newArrayList(Iterables.filter(rootCharacteristics, new Predicate<DefaultCharacteristic>() {
- @Override
- public boolean apply(DefaultCharacteristic input) {
- return input.isRoot();
- }
- }));
- }
-
- @CheckForNull
- public DefaultCharacteristic characteristicByKey(final String key) {
- return Iterables.find(characteristics(), new Predicate<DefaultCharacteristic>() {
- @Override
- public boolean apply(DefaultCharacteristic input) {
- return input.key().equals(key);
- }
- }, null);
- }
-
- public List<DefaultCharacteristic> characteristics() {
- List<DefaultCharacteristic> flatCharacteristics = newArrayList();
- for (DefaultCharacteristic rootCharacteristic : rootCharacteristics) {
- flatCharacteristics.add(rootCharacteristic);
- for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
- flatCharacteristics.add(characteristic);
- }
- }
- return flatCharacteristics;
- }
-
- public boolean isEmpty() {
- return rootCharacteristics.isEmpty();
- }
-
- }
-
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.debt;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+import org.sonar.api.server.debt.DebtCharacteristic;
+
+import javax.annotation.CheckForNull;
+
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+// TODO Maybe should be an inner class of DebtCharacteristicsXMLImporter? Will see following how will be implemented the Backup feature
+public class DebtModel {
+
+ private Multimap<String, DebtCharacteristic> characteristicsByRootKey;
+
+ public DebtModel() {
+ characteristicsByRootKey = ArrayListMultimap.create();
+ }
+
+ public DebtModel addRootCharacteristic(DebtCharacteristic characteristic) {
+ characteristicsByRootKey.put(null, characteristic);
+ return this;
+ }
+
+ public DebtModel addSubCharacteristic(DebtCharacteristic subCharacteristic, String characteristicKey) {
+ characteristicsByRootKey.put(characteristicKey, subCharacteristic);
+ return this;
+ }
+
+ public List<DebtCharacteristic> rootCharacteristics() {
+ return newArrayList(characteristicsByRootKey.get(null));
+ }
+
+ public List<DebtCharacteristic> subCharacteristics(String characteristicKey) {
+ return newArrayList(characteristicsByRootKey.get(characteristicKey));
+ }
+
+ @CheckForNull
+ public DebtCharacteristic characteristicByKey(final String key) {
+ return Iterables.find(characteristicsByRootKey.values(), new Predicate<DebtCharacteristic>() {
+ @Override
+ public boolean apply(DebtCharacteristic input) {
+ return key.equals(input.key());
+ }
+ }, null);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.debt;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.server.debt.DebtCharacteristic;
+import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+
+import javax.annotation.CheckForNull;
+
+import java.util.Collection;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class DebtModelLookup implements ServerComponent {
+
+ private final CharacteristicDao dao;
+
+ public DebtModelLookup(CharacteristicDao dao) {
+ this.dao = dao;
+ }
+
+ public List<DebtCharacteristic> rootCharacteristics() {
+ return toCharacteristics(dao.selectEnabledRootCharacteristics());
+ }
+
+ public List<DebtCharacteristic> characteristics() {
+ return toCharacteristics(dao.selectEnabledCharacteristics());
+ }
+
+ @CheckForNull
+ public DebtCharacteristic characteristicById(int id) {
+ CharacteristicDto dto = dao.selectById(id);
+ return dto != null ? toCharacteristic(dto) : null;
+ }
+
+ private static List<DebtCharacteristic> toCharacteristics(Collection<CharacteristicDto> dtos) {
+ return newArrayList(Iterables.transform(dtos, new Function<CharacteristicDto, DebtCharacteristic>() {
+ @Override
+ public DebtCharacteristic apply(CharacteristicDto input) {
+ return toCharacteristic(input);
+ }
+ }));
+ }
+
+ private static DebtCharacteristic toCharacteristic(CharacteristicDto dto) {
+ return new DefaultDebtCharacteristic()
+ .setId(dto.getId())
+ .setKey(dto.getKey())
+ .setName(dto.getName())
+ .setOrder(dto.getOrder())
+ .setParentId(dto.getParentId());
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.debt;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.ibatis.session.SqlSession;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.server.debt.DebtCharacteristic;
+import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
+import org.sonar.api.utils.System2;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.rule.RuleDao;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.util.Validation;
+
+import javax.annotation.Nullable;
+
+import java.util.Date;
+import java.util.List;
+
+public class DebtModelOperations implements ServerComponent {
+
+ private final MyBatis mybatis;
+ private final CharacteristicDao dao;
+ private final RuleDao ruleDao;
+ private final System2 system2;
+
+ public DebtModelOperations(MyBatis mybatis, CharacteristicDao dao, RuleDao ruleDao) {
+ this(mybatis, dao, ruleDao, System2.INSTANCE);
+ }
+
+ @VisibleForTesting
+ DebtModelOperations(MyBatis mybatis, CharacteristicDao dao, RuleDao ruleDao, System2 system2) {
+ this.mybatis = mybatis;
+ this.dao = dao;
+ this.ruleDao = ruleDao;
+ this.system2 = system2;
+ }
+
+ public DebtCharacteristic create(String name, @Nullable Integer parentId) {
+ checkPermission();
+
+ SqlSession session = mybatis.openSession();
+ try {
+ checkNotAlreadyExists(name, session);
+
+ CharacteristicDto newCharacteristic = new CharacteristicDto()
+ .setKey(name.toUpperCase().replace(" ", "_"))
+ .setName(name)
+ .setEnabled(true)
+ .setCreatedAt(new Date(system2.now()));
+
+ // New sub characteristic
+ if (parentId != null) {
+ CharacteristicDto parent = findCharacteristic(parentId, session);
+ if (parent.getParentId() != null) {
+ throw new BadRequestException("A sub characteristic can not have a sub characteristic as parent.");
+ }
+ newCharacteristic.setParentId(parent.getId());
+ } else {
+ // New root characteristic
+ newCharacteristic.setOrder(dao.selectMaxCharacteristicOrder(session) + 1);
+ }
+ dao.insert(newCharacteristic, session);
+ session.commit();
+ return toCharacteristic(newCharacteristic);
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ public DebtCharacteristic rename(int characteristicId, String newName) {
+ checkPermission();
+
+ SqlSession session = mybatis.openSession();
+ try {
+ checkNotAlreadyExists(newName, session);
+
+ CharacteristicDto dto = findCharacteristic(characteristicId, session);
+ if (!dto.getName().equals(newName)) {
+ dto.setName(newName);
+ dto.setUpdatedAt(new Date(system2.now()));
+ dao.update(dto, session);
+ session.commit();
+ }
+ return toCharacteristic(dto);
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ public DebtCharacteristic moveUp(int characteristicId) {
+ return move(characteristicId, true);
+ }
+
+ public DebtCharacteristic moveDown(int characteristicId) {
+ return move(characteristicId, false);
+ }
+
+ private DebtCharacteristic move(int characteristicId, boolean moveUpOrDown) {
+ checkPermission();
+
+ SqlSession session = mybatis.openSession();
+ try {
+ CharacteristicDto dto = findCharacteristic(characteristicId, session);
+ int currentOrder = dto.getOrder();
+ CharacteristicDto dtoToSwitchOrderWith = moveUpOrDown ? dao.selectPrevious(currentOrder, session) : dao.selectNext(currentOrder, session);
+
+ // Do nothing when characteristic is already to the new location
+ if (dtoToSwitchOrderWith == null) {
+ return toCharacteristic(dto);
+ }
+ int nextOrder = dtoToSwitchOrderWith.getOrder();
+ dtoToSwitchOrderWith.setOrder(currentOrder);
+ dtoToSwitchOrderWith.setUpdatedAt(new Date(system2.now()));
+ dao.update(dtoToSwitchOrderWith, session);
+
+ dto.setOrder(nextOrder);
+ dto.setUpdatedAt(new Date(system2.now()));
+ dao.update(dto, session);
+
+ session.commit();
+ return toCharacteristic(dto);
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ /**
+ * Disable characteristic and sub characteristic or only sub characteristic.
+ * Will also update every rules linked to sub characteristics by setting characteristic id to -1 and remove function, factor and offset.
+ */
+ public void delete(int characteristicOrSubCharacteristicId) {
+ checkPermission();
+
+ Date updateDate = new Date(system2.now());
+ SqlSession session = mybatis.openBatchSession();
+ try {
+ CharacteristicDto characteristicOrSubCharacteristic = findCharacteristic(characteristicOrSubCharacteristicId, session);
+ disableDebtRules(
+ ruleDao.selectByCharacteristicOrSubCharacteristicId(characteristicOrSubCharacteristic.getId(), session),
+ updateDate,
+ session
+ );
+
+ if (characteristicOrSubCharacteristic.getParentId() == null) {
+ List<CharacteristicDto> subChracteristics = dao.selectCharacteristicsByParentId(characteristicOrSubCharacteristic.getId(), session);
+ for (CharacteristicDto subCharacteristic : subChracteristics) {
+ disableCharacteristic(subCharacteristic, updateDate, session);
+ }
+ }
+ disableCharacteristic(characteristicOrSubCharacteristic, updateDate, session);
+
+ session.commit();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ public void disableDebtRules(List<RuleDto> ruleDtos, Date updateDate, SqlSession session){
+ for (RuleDto ruleDto : ruleDtos) {
+ ruleDto.setCharacteristicId(RuleDto.DISABLED_CHARACTERISTIC_ID);
+ ruleDto.setRemediationFunction(null);
+ ruleDto.setRemediationFactor(null);
+ ruleDto.setRemediationOffset(null);
+ ruleDto.setUpdatedAt(updateDate);
+ ruleDao.update(ruleDto, session);
+ // TODO update rules from E/S
+ }
+ }
+
+ public void disableCharacteristic(CharacteristicDto characteristic, Date updateDate, SqlSession session){
+ characteristic.setEnabled(false);
+ characteristic.setUpdatedAt(updateDate);
+ dao.update(characteristic, session);
+ }
+
+ private CharacteristicDto findCharacteristic(Integer id, SqlSession session) {
+ CharacteristicDto dto = dao.selectById(id, session);
+ if (dto == null) {
+ throw new NotFoundException(String.format("Characteristic with id %s does not exists.", id));
+ }
+ return dto;
+ }
+
+ private void checkNotAlreadyExists(String name, SqlSession session) {
+ if (dao.selectByName(name, session) != null) {
+ throw BadRequestException.ofL10n(Validation.IS_ALREADY_USED_MESSAGE, name);
+ }
+ }
+
+ private void checkPermission() {
+ UserSession.get().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
+ }
+
+ private static DebtCharacteristic toCharacteristic(CharacteristicDto dto) {
+ return new DefaultDebtCharacteristic()
+ .setId(dto.getId())
+ .setKey(dto.getKey())
+ .setName(dto.getName())
+ .setOrder(dto.getOrder())
+ .setParentId(dto.getParentId())
+ .setCreatedAt(dto.getCreatedAt())
+ .setUpdatedAt(dto.getUpdatedAt());
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.debt;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.ObjectUtils;
+import org.apache.ibatis.session.SqlSession;
+import org.sonar.api.ServerComponent;
+import org.sonar.api.server.debt.DebtCharacteristic;
+import org.sonar.api.utils.System2;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.rule.RuleDao;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+import org.sonar.server.user.UserSession;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.io.Reader;
+import java.util.Date;
+import java.util.List;
+
+public class DebtModelRestore implements ServerComponent {
+
+ private final MyBatis mybatis;
+ private final CharacteristicDao dao;
+ private final RuleDao ruleDao;
+ private final DebtModelOperations debtModelOperations;
+ private final TechnicalDebtModelRepository debtModelPluginRepository;
+ private final DebtCharacteristicsXMLImporter importer;
+ private final System2 system2;
+
+ public DebtModelRestore(MyBatis mybatis, CharacteristicDao dao, RuleDao ruleDao, DebtModelOperations debtModelOperations, TechnicalDebtModelRepository debtModelPluginRepository,
+ DebtCharacteristicsXMLImporter importer) {
+ this(mybatis, dao, ruleDao, debtModelOperations, debtModelPluginRepository, importer, System2.INSTANCE);
+ }
+
+ @VisibleForTesting
+ DebtModelRestore(MyBatis mybatis, CharacteristicDao dao, RuleDao ruleDao, DebtModelOperations debtModelOperations, TechnicalDebtModelRepository debtModelPluginRepository,
+ DebtCharacteristicsXMLImporter importer,
+ System2 system2) {
+ this.mybatis = mybatis;
+ this.dao = dao;
+ this.ruleDao = ruleDao;
+ this.debtModelOperations = debtModelOperations;
+ this.debtModelPluginRepository = debtModelPluginRepository;
+ this.importer = importer;
+ this.system2 = system2;
+ }
+
+ /**
+ * Restore model from all provided plugins
+ */
+ public void restoreFromProvidedModel() {
+ checkPermission();
+
+ Date updateDate = new Date(system2.now());
+ SqlSession session = mybatis.openSession();
+ try {
+ List<CharacteristicDto> persisted = dao.selectEnabledCharacteristics();
+ DebtModel providedModel = loadModelFromXml(TechnicalDebtModelRepository.DEFAULT_MODEL);
+ restoreCharacteristics(providedModel, persisted, updateDate, session);
+ resetOverridingRuleDebt(updateDate, session);
+
+ session.commit();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ private void resetOverridingRuleDebt(Date updateDate, SqlSession session) {
+ for (RuleDto rule : ruleDao.selectOverridingDebt(session)) {
+ rule.setCharacteristicId(null);
+ rule.setRemediationFunction(null);
+ rule.setRemediationFactor(null);
+ rule.setRemediationOffset(null);
+ rule.setUpdatedAt(updateDate);
+ ruleDao.update(rule, session);
+ // TODO index rules in E/S
+ }
+ }
+
+ @VisibleForTesting
+ void restoreCharacteristics(DebtModel targetModel, List<CharacteristicDto> sourceCharacteristics, Date updateDate, SqlSession session) {
+ // Restore not existing characteristics
+ for (DebtCharacteristic characteristic : targetModel.rootCharacteristics()) {
+ CharacteristicDto rootCharacteristicDto = restoreCharacteristic(characteristic, null, sourceCharacteristics, updateDate, session);
+ for (DebtCharacteristic subCharacteristic : targetModel.subCharacteristics(characteristic.key())) {
+ restoreCharacteristic(subCharacteristic, rootCharacteristicDto.getId(), sourceCharacteristics, updateDate, session);
+ }
+ }
+ // Disable no more existing characteristics
+ for (CharacteristicDto sourceCharacteristic : sourceCharacteristics) {
+ if (targetModel.characteristicByKey(sourceCharacteristic.getKey()) == null) {
+ debtModelOperations.disableCharacteristic(sourceCharacteristic, updateDate, session);
+ }
+ }
+ }
+
+ private CharacteristicDto restoreCharacteristic(DebtCharacteristic targetCharacteristic, @Nullable Integer parentId, List<CharacteristicDto> sourceCharacteristics,
+ Date updateDate, SqlSession session) {
+ CharacteristicDto sourceCharacteristic = dtoByKey(sourceCharacteristics, targetCharacteristic.key());
+ if (sourceCharacteristic == null) {
+ CharacteristicDto newCharacteristic = toDto(targetCharacteristic, parentId).setCreatedAt(updateDate);
+ dao.insert(newCharacteristic, session);
+ return newCharacteristic;
+ } else {
+ // Update only if modifications
+ if (ObjectUtils.notEqual(sourceCharacteristic.getName(), targetCharacteristic.name()) ||
+ ObjectUtils.notEqual(sourceCharacteristic.getOrder(), targetCharacteristic.order())) {
+ sourceCharacteristic.setName(targetCharacteristic.name());
+ sourceCharacteristic.setOrder(targetCharacteristic.order());
+ sourceCharacteristic.setUpdatedAt(updateDate);
+ dao.update(sourceCharacteristic, session);
+ }
+ return sourceCharacteristic;
+ }
+ }
+
+ private DebtModel loadModelFromXml(String pluginKey) {
+ Reader xmlFileReader = null;
+ try {
+ xmlFileReader = debtModelPluginRepository.createReaderForXMLFile(pluginKey);
+ return importer.importXML(xmlFileReader);
+ } finally {
+ IOUtils.closeQuietly(xmlFileReader);
+ }
+ }
+
+ @CheckForNull
+ private CharacteristicDto dtoByKey(List<CharacteristicDto> existingModel, final String key) {
+ return Iterables.find(existingModel, new Predicate<CharacteristicDto>() {
+ @Override
+ public boolean apply(CharacteristicDto input) {
+ return key.equals(input.getKey());
+ }
+ }, null);
+ }
+
+ private static CharacteristicDto toDto(DebtCharacteristic characteristic, @Nullable Integer parentId) {
+ return new CharacteristicDto()
+ .setKey(characteristic.key())
+ .setName(characteristic.name())
+ .setOrder(characteristic.order())
+ .setParentId(parentId)
+ .setEnabled(true)
+ .setCreatedAt(characteristic.createdAt())
+ .setUpdatedAt(characteristic.updatedAt());
+ }
+
+ private void checkPermission() {
+ UserSession.get().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
+ }
+
+
+}
package org.sonar.server.debt;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
-import org.apache.ibatis.session.SqlSession;
import org.sonar.api.server.debt.DebtCharacteristic;
import org.sonar.api.server.debt.DebtModel;
-import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
-import org.sonar.api.utils.System2;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.rule.RuleDao;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
-import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.user.UserSession;
-import org.sonar.server.util.Validation;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-import java.util.Collection;
-import java.util.Date;
import java.util.List;
-import static com.google.common.collect.Lists.newArrayList;
-
/**
* Used through ruby code <pre>Internal.debt</pre>
* Also used by SQALE plugin.
*/
public class DebtModelService implements DebtModel {
- private final MyBatis mybatis;
- private final CharacteristicDao dao;
- private final RuleDao ruleDao;
- private final System2 system2;
-
- public DebtModelService(MyBatis mybatis, CharacteristicDao dao, RuleDao ruleDao) {
- this(mybatis, dao, ruleDao, System2.INSTANCE);
- }
+ private final DebtModelOperations debtModelOperations;
+ private final DebtModelLookup debtModelLookup;
+ private final DebtModelRestore debtModelRestore;
- @VisibleForTesting
- DebtModelService(MyBatis mybatis, CharacteristicDao dao, RuleDao ruleDao, System2 system2) {
- this.mybatis = mybatis;
- this.dao = dao;
- this.ruleDao = ruleDao;
- this.system2 = system2;
+ public DebtModelService(DebtModelOperations debtModelOperations, DebtModelLookup debtModelLookup, DebtModelRestore debtModelRestore) {
+ this.debtModelOperations = debtModelOperations;
+ this.debtModelLookup = debtModelLookup;
+ this.debtModelRestore = debtModelRestore;
}
public List<DebtCharacteristic> rootCharacteristics() {
- return toCharacteristics(dao.selectEnabledRootCharacteristics());
+ return debtModelLookup.rootCharacteristics();
}
public List<DebtCharacteristic> characteristics() {
- return toCharacteristics(dao.selectEnabledCharacteristics());
+ return debtModelLookup.characteristics();
}
@CheckForNull
public DebtCharacteristic characteristicById(int id) {
- CharacteristicDto dto = dao.selectById(id);
- return dto != null ? toCharacteristic(dto) : null;
+ return debtModelLookup.characteristicById(id);
}
public DebtCharacteristic create(String name, @Nullable Integer parentId) {
- checkPermission();
-
- SqlSession session = mybatis.openSession();
- try {
- checkNotAlreadyExists(name, session);
-
- CharacteristicDto newCharacteristic = new CharacteristicDto()
- .setKey(name.toUpperCase().replace(" ", "_"))
- .setName(name)
- .setEnabled(true);
-
- // New sub characteristic
- if (parentId != null) {
- CharacteristicDto parent = findCharacteristic(parentId, session);
- if (parent.getParentId() != null) {
- throw new BadRequestException("A sub characteristic can not have a sub characteristic as parent.");
- }
- newCharacteristic.setParentId(parent.getId());
- } else {
- // New root characteristic
- newCharacteristic.setOrder(dao.selectMaxCharacteristicOrder(session) + 1);
- }
- dao.insert(newCharacteristic, session);
- session.commit();
- return toCharacteristic(newCharacteristic);
- } finally {
- MyBatis.closeQuietly(session);
- }
+ return debtModelOperations.create(name, parentId);
}
public DebtCharacteristic rename(int characteristicId, String newName) {
- checkPermission();
-
- SqlSession session = mybatis.openSession();
- try {
- checkNotAlreadyExists(newName, session);
-
- CharacteristicDto dto = findCharacteristic(characteristicId, session);
- if (!dto.getName().equals(newName)) {
- dto.setName(newName);
- dao.update(dto, session);
- session.commit();
- }
- return toCharacteristic(dto);
- } finally {
- MyBatis.closeQuietly(session);
- }
+ return debtModelOperations.rename(characteristicId, newName);
}
public DebtCharacteristic moveUp(int characteristicId) {
- return move(characteristicId, true);
+ return debtModelOperations.moveUp(characteristicId);
}
public DebtCharacteristic moveDown(int characteristicId) {
- return move(characteristicId, false);
- }
-
- private DebtCharacteristic move(int characteristicId, boolean moveUpOrDown) {
- checkPermission();
-
- SqlSession session = mybatis.openSession();
- try {
- CharacteristicDto dto = findCharacteristic(characteristicId, session);
- int currentOrder = dto.getOrder();
- CharacteristicDto dtoToSwitchOrderWith = moveUpOrDown ? dao.selectPrevious(currentOrder, session) : dao.selectNext(currentOrder, session);
-
- // Do nothing when characteristic is already to the new location
- if (dtoToSwitchOrderWith == null) {
- return toCharacteristic(dto);
- }
- int nextOrder = dtoToSwitchOrderWith.getOrder();
- dtoToSwitchOrderWith.setOrder(currentOrder);
- dao.update(dtoToSwitchOrderWith, session);
-
- dto.setOrder(nextOrder);
- dao.update(dto, session);
-
- session.commit();
- return toCharacteristic(dto);
- } finally {
- MyBatis.closeQuietly(session);
- }
+ return debtModelOperations.moveDown(characteristicId);
}
/**
* Will also update every rules linked to sub characteristics by setting characteristic id to -1 and remove function, factor and offset.
*/
public void delete(int characteristicOrSubCharactteristicId) {
- checkPermission();
-
- SqlSession session = mybatis.openBatchSession();
- try {
- Date now = new Date(system2.now());
-
- CharacteristicDto characteristicOrSubCharacteristicDto = findCharacteristic(characteristicOrSubCharactteristicId, session);
- List<RuleDto> ruleDtos = ruleDao.selectByCharacteristicOrSubCharacteristicId(characteristicOrSubCharacteristicDto.getId(), session);
- for (RuleDto ruleDto : ruleDtos) {
- ruleDto.setCharacteristicId(RuleDto.DISABLED_CHARACTERISTIC_ID);
- ruleDto.setRemediationFunction(null);
- ruleDto.setRemediationFactor(null);
- ruleDto.setRemediationOffset(null);
- ruleDto.setUpdatedAt(now);
- ruleDao.update(ruleDto, session);
-
- // TODO update rules from E/S
- }
-
- if (characteristicOrSubCharacteristicDto.getParentId() == null) {
- List<CharacteristicDto> dtos = dao.selectCharacteristicsByParentId(characteristicOrSubCharacteristicDto.getId(), session);
- for (CharacteristicDto subCharacteristicDto : dtos) {
- subCharacteristicDto.setEnabled(false);
- subCharacteristicDto.setUpdatedAt(now);
- dao.update(subCharacteristicDto, session);
- }
- }
- characteristicOrSubCharacteristicDto.setEnabled(false);
- characteristicOrSubCharacteristicDto.setUpdatedAt(now);
- dao.update(characteristicOrSubCharacteristicDto, session);
-
- session.commit();
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
- private CharacteristicDto findCharacteristic(Integer id, SqlSession session) {
- CharacteristicDto dto = dao.selectById(id, session);
- if (dto == null) {
- throw new NotFoundException(String.format("Characteristic with id %s does not exists.", id));
- }
- return dto;
- }
-
- private void checkNotAlreadyExists(String name, SqlSession session) {
- if (dao.selectByName(name, session) != null) {
- throw BadRequestException.ofL10n(Validation.IS_ALREADY_USED_MESSAGE, name);
- }
- }
-
- private void checkPermission() {
- UserSession.get().checkGlobalPermission(GlobalPermissions.SYSTEM_ADMIN);
- }
-
- private static List<DebtCharacteristic> toCharacteristics(Collection<CharacteristicDto> dtos) {
- return newArrayList(Iterables.transform(dtos, new Function<CharacteristicDto, DebtCharacteristic>() {
- @Override
- public DebtCharacteristic apply(CharacteristicDto input) {
- return toCharacteristic(input);
- }
- }));
+ debtModelOperations.delete(characteristicOrSubCharactteristicId);
}
- private static DebtCharacteristic toCharacteristic(CharacteristicDto dto) {
- return new DefaultDebtCharacteristic()
- .setId(dto.getId())
- .setKey(dto.getKey())
- .setName(dto.getName())
- .setOrder(dto.getOrder())
- .setParentId(dto.getParentId());
+ public void restore(){
+ debtModelRestore.restoreFromProvidedModel();
}
}
import org.apache.commons.io.IOUtils;
import org.apache.ibatis.session.SqlSession;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.sonar.api.ServerExtension;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.server.debt.DebtCharacteristic;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;
+import javax.annotation.Nullable;
+
import java.io.Reader;
import java.util.List;
public class DebtModelSynchronizer implements ServerExtension {
- private static final Logger LOG = LoggerFactory.getLogger(DebtModelSynchronizer.class);
-
private final MyBatis mybatis;
private final CharacteristicDao dao;
private final TechnicalDebtModelRepository languageModelFinder;
public List<CharacteristicDto> synchronize() {
SqlSession session = mybatis.openSession();
- List<CharacteristicDto> model = newArrayList();
+ List<CharacteristicDto> characteristics = newArrayList();
try {
- model = synchronize(session);
- session.commit();
+ DebtModel defaultModel = loadModelFromXml(TechnicalDebtModelRepository.DEFAULT_MODEL);
+ List<CharacteristicDto> existingCharacteristics = dao.selectEnabledCharacteristics();
+ if (existingCharacteristics.isEmpty()) {
+ return createDebtModel(defaultModel, session);
+ }
} finally {
MyBatis.closeQuietly(session);
}
- return model;
- }
-
- public List<CharacteristicDto> synchronize(SqlSession session) {
- DebtCharacteristicsXMLImporter.DebtModel defaultModel = loadModelFromXml(TechnicalDebtModelRepository.DEFAULT_MODEL);
- List<CharacteristicDto> model = loadOrCreateModelFromDb(defaultModel, session);
- return model;
- }
-
- private List<CharacteristicDto> loadOrCreateModelFromDb(DebtCharacteristicsXMLImporter.DebtModel defaultModel, SqlSession session) {
- List<CharacteristicDto> characteristicDtos = loadModel();
- if (characteristicDtos.isEmpty()) {
- return createTechnicalDebtModel(defaultModel, session);
- }
- return characteristicDtos;
- }
-
- private List<CharacteristicDto> loadModel() {
- return dao.selectEnabledCharacteristics();
+ return characteristics;
}
- private List<CharacteristicDto> createTechnicalDebtModel(DebtCharacteristicsXMLImporter.DebtModel defaultModel, SqlSession session) {
+ private List<CharacteristicDto> createDebtModel(DebtModel defaultModel, SqlSession session) {
List<CharacteristicDto> characteristics = newArrayList();
- for (DefaultCharacteristic rootCharacteristic : defaultModel.rootCharacteristics()) {
- CharacteristicDto rootCharacteristicDto = CharacteristicDto.toDto(rootCharacteristic, null);
+ for (DebtCharacteristic rootCharacteristic : defaultModel.rootCharacteristics()) {
+ CharacteristicDto rootCharacteristicDto = toDto(rootCharacteristic, null);
dao.insert(rootCharacteristicDto, session);
characteristics.add(rootCharacteristicDto);
- for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
- CharacteristicDto characteristicDto = CharacteristicDto.toDto(characteristic, rootCharacteristicDto.getId());
+ for (DebtCharacteristic characteristic : defaultModel.subCharacteristics(rootCharacteristic.key())) {
+ CharacteristicDto characteristicDto = toDto(characteristic, rootCharacteristicDto.getId());
dao.insert(characteristicDto, session);
characteristics.add(characteristicDto);
}
}
+ session.commit();
return characteristics;
}
- public DebtCharacteristicsXMLImporter.DebtModel loadModelFromXml(String pluginKey) {
+ private DebtModel loadModelFromXml(String pluginKey) {
Reader xmlFileReader = null;
try {
xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
}
}
+ private static CharacteristicDto toDto(DebtCharacteristic characteristic, @Nullable Integer parentId) {
+ return new CharacteristicDto()
+ .setKey(characteristic.key())
+ .setName(characteristic.name())
+ .setOrder(characteristic.order())
+ .setParentId(parentId)
+ .setEnabled(true)
+ .setCreatedAt(characteristic.createdAt())
+ .setUpdatedAt(characteristic.updatedAt());
+ }
+
}
import org.sonar.server.db.EmbeddedDatabaseFactory;
import org.sonar.server.db.migrations.DatabaseMigrations;
import org.sonar.server.db.migrations.DatabaseMigrator;
-import org.sonar.server.debt.DebtCharacteristicsXMLImporter;
-import org.sonar.server.debt.DebtModelService;
-import org.sonar.server.debt.DebtModelSynchronizer;
-import org.sonar.server.debt.DebtRulesXMLImporter;
+import org.sonar.server.debt.*;
import org.sonar.server.es.ESIndex;
import org.sonar.server.es.ESNode;
import org.sonar.server.issue.*;
// technical debt
pico.addSingleton(DebtModelService.class);
+ pico.addSingleton(DebtModelOperations.class);
+ pico.addSingleton(DebtModelLookup.class);
+ pico.addSingleton(DebtModelRestore.class);
pico.addSingleton(TechnicalDebtModelSynchronizer.class);
pico.addSingleton(DebtModelSynchronizer.class);
pico.addSingleton(TechnicalDebtModelRepository.class);
import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import org.junit.Test;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.server.debt.DebtCharacteristic;
import java.io.IOException;
+import java.util.List;
import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;
public void import_characteristics() {
String xml = getFileContent("import_characteristics.xml");
- DebtCharacteristicsXMLImporter.DebtModel debtModel = new DebtCharacteristicsXMLImporter().importXML(xml);
-
- assertThat(debtModel.rootCharacteristics()).hasSize(2);
- assertThat(debtModel.rootCharacteristics().get(0).key()).isEqualTo("PORTABILITY");
- assertThat(debtModel.rootCharacteristics().get(1).key()).isEqualTo("MAINTAINABILITY");
-
- DefaultCharacteristic portability = debtModel.characteristicByKey("PORTABILITY");
- assertThat(portability.order()).isEqualTo(1);
- assertThat(portability.children()).hasSize(2);
- assertThat(portability.children().get(0).key()).isEqualTo("COMPILER_RELATED_PORTABILITY");
- assertThat(debtModel.characteristicByKey("COMPILER_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
- assertThat(portability.children().get(1).key()).isEqualTo("HARDWARE_RELATED_PORTABILITY");
- assertThat(debtModel.characteristicByKey("HARDWARE_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
-
- DefaultCharacteristic maintainability = debtModel.characteristicByKey("MAINTAINABILITY");
- assertThat(maintainability.order()).isEqualTo(2);
- assertThat(maintainability.children()).hasSize(1);
- assertThat(maintainability.children().get(0).key()).isEqualTo("READABILITY");
- assertThat(debtModel.characteristicByKey("READABILITY").parent().key()).isEqualTo("MAINTAINABILITY");
+ DebtModel debtModel = new DebtCharacteristicsXMLImporter().importXML(xml);
+ List<DebtCharacteristic> rootCharacteristics = debtModel.rootCharacteristics();
+
+ assertThat(rootCharacteristics).hasSize(2);
+ assertThat(rootCharacteristics.get(0).key()).isEqualTo("PORTABILITY");
+ assertThat(rootCharacteristics.get(0).name()).isEqualTo("Portability");
+ assertThat(rootCharacteristics.get(0).order()).isEqualTo(1);
+
+ assertThat(rootCharacteristics.get(1).key()).isEqualTo("MAINTAINABILITY");
+ assertThat(rootCharacteristics.get(1).name()).isEqualTo("Maintainability");
+ assertThat(rootCharacteristics.get(1).order()).isEqualTo(2);
+
+ List<DebtCharacteristic> portabilitySubCharacteristics = debtModel.subCharacteristics("PORTABILITY");
+ assertThat(portabilitySubCharacteristics).hasSize(2);
+ assertThat(portabilitySubCharacteristics.get(0).key()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ assertThat(portabilitySubCharacteristics.get(0).name()).isEqualTo("Compiler related portability");
+ assertThat(portabilitySubCharacteristics.get(1).key()).isEqualTo("HARDWARE_RELATED_PORTABILITY");
+ assertThat(portabilitySubCharacteristics.get(1).name()).isEqualTo("Hardware related portability");
+
+ List<DebtCharacteristic> maintainabilitySubCharacteristics = debtModel.subCharacteristics("MAINTAINABILITY");
+ assertThat(maintainabilitySubCharacteristics).hasSize(1);
+ assertThat(maintainabilitySubCharacteristics.get(0).key()).isEqualTo("READABILITY");
+ assertThat(maintainabilitySubCharacteristics.get(0).name()).isEqualTo("Readability");
}
@Test
public void import_badly_formatted_xml() {
String xml = getFileContent("import_badly_formatted_xml.xml");
- DebtCharacteristicsXMLImporter.DebtModel debtModel = new DebtCharacteristicsXMLImporter().importXML(xml);
+ DebtModel debtModel = new DebtCharacteristicsXMLImporter().importXML(xml);
+ List<DebtCharacteristic> rootCharacteristics = debtModel.rootCharacteristics();
// characteristics
- assertThat(debtModel.rootCharacteristics()).hasSize(2);
- DefaultCharacteristic efficiency = debtModel.characteristicByKey("EFFICIENCY");
- assertThat(efficiency.name()).isEqualTo("Efficiency");
-
- // sub-characteristics
- assertThat(efficiency.children()).hasSize(1);
- DefaultCharacteristic memoryEfficiency = debtModel.characteristicByKey("MEMORY_EFFICIENCY");
- assertThat(memoryEfficiency.name()).isEqualTo("Memory use");
+ assertThat(rootCharacteristics).hasSize(2);
+ assertThat(rootCharacteristics.get(0).key()).isEqualTo("USABILITY");
+ assertThat(rootCharacteristics.get(0).name()).isEqualTo("Usability");
+
+ assertThat(rootCharacteristics.get(1).key()).isEqualTo("EFFICIENCY");
+ assertThat(rootCharacteristics.get(1).name()).isEqualTo("Efficiency");
+
+ // sub-characteristic
+ assertThat(debtModel.subCharacteristics("EFFICIENCY")).hasSize(1);
+ assertThat(debtModel.subCharacteristics("EFFICIENCY").get(0).key()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(debtModel.subCharacteristics("EFFICIENCY").get(0).name()).isEqualTo("Memory use");
}
@Test
try {
new DebtCharacteristicsXMLImporter().importXML(xml);
fail();
- } catch (Exception e){
+ } catch (Exception e) {
assertThat(e).isInstanceOf(IllegalStateException.class);
}
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.debt;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.server.debt.DebtCharacteristic;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DebtModelLookupTest {
+
+ @Mock
+ CharacteristicDao dao;
+
+ CharacteristicDto characteristicDto = new CharacteristicDto()
+ .setId(1)
+ .setKey("MEMORY_EFFICIENCY")
+ .setName("Memory use")
+ .setOrder(2)
+ .setEnabled(true);
+
+ DebtModelLookup service;
+
+ @Before
+ public void setUp() throws Exception {
+ service = new DebtModelLookup(dao);
+ }
+
+ @Test
+ public void find_root_characteristics() {
+ when(dao.selectEnabledRootCharacteristics()).thenReturn(newArrayList(characteristicDto));
+ assertThat(service.rootCharacteristics()).hasSize(1);
+ }
+
+ @Test
+ public void find_characteristics() {
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(characteristicDto));
+ assertThat(service.characteristics()).hasSize(1);
+ }
+
+ @Test
+ public void find_characteristic_by_id() {
+ when(dao.selectById(1)).thenReturn(characteristicDto);
+
+ DebtCharacteristic characteristic = service.characteristicById(1);
+ assertThat(characteristic.id()).isEqualTo(1);
+ assertThat(characteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(characteristic.name()).isEqualTo("Memory use");
+ assertThat(characteristic.order()).isEqualTo(2);
+ assertThat(characteristic.parentId()).isNull();
+
+ assertThat(service.characteristicById(111)).isNull();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.debt;
+
+import org.apache.ibatis.session.SqlSession;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.server.debt.DebtCharacteristic;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.BatchSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.rule.RuleDao;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.user.MockUserSession;
+
+import java.util.Date;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.assertions.Fail.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DebtModelOperationsTest {
+
+ @Mock
+ CharacteristicDao dao;
+
+ @Mock
+ RuleDao ruleDao;
+
+ @Mock
+ MyBatis mybatis;
+
+ @Mock
+ SqlSession session;
+
+ @Mock
+ System2 system2;
+
+ Date now = DateUtils.parseDate("2014-03-19");
+
+ CharacteristicDto characteristicDto = new CharacteristicDto()
+ .setId(1)
+ .setKey("MEMORY_EFFICIENCY")
+ .setName("Memory use")
+ .setOrder(2)
+ .setEnabled(true);
+
+ CharacteristicDto subCharacteristicDto = new CharacteristicDto()
+ .setId(2)
+ .setKey("EFFICIENCY")
+ .setName("Efficiency")
+ .setParentId(1)
+ .setEnabled(true);
+
+ int currentId;
+
+ DebtModelOperations service;
+
+ @Before
+ public void setUp() throws Exception {
+ when(system2.now()).thenReturn(now.getTime());
+
+ MockUserSession.set().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+
+ currentId = 10;
+ // Associate an id when inserting an object to simulate the db id generator
+ doAnswer(new Answer() {
+ public Object answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ CharacteristicDto dto = (CharacteristicDto) args[0];
+ dto.setId(++currentId);
+ return null;
+ }
+ }).when(dao).insert(any(CharacteristicDto.class), any(SqlSession.class));
+
+ when(mybatis.openSession()).thenReturn(session);
+ service = new DebtModelOperations(mybatis, dao, ruleDao,system2);
+ }
+
+ @Test
+ public void create_sub_characteristic() {
+ when(dao.selectById(1, session)).thenReturn(characteristicDto);
+
+ DebtCharacteristic result = service.create("Compilation name", 1);
+
+ assertThat(result.id()).isEqualTo(currentId);
+ assertThat(result.key()).isEqualTo("COMPILATION_NAME");
+ assertThat(result.name()).isEqualTo("Compilation name");
+ assertThat(result.parentId()).isEqualTo(1);
+ assertThat(result.createdAt()).isEqualTo(now);
+ }
+
+ @Test
+ public void fail_to_create_sub_characteristic_when_parent_id_is_not_a_root_characteristic() {
+ when(dao.selectById(1, session)).thenReturn(subCharacteristicDto);
+
+ try {
+ service.create("Compilation", 1);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("A sub characteristic can not have a sub characteristic as parent.");
+ }
+ }
+
+ @Test
+ public void fail_to_create_sub_characteristic_when_parent_does_not_exists() {
+ when(dao.selectById(1, session)).thenReturn(null);
+
+ try {
+ service.create("Compilation", 1);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("Characteristic with id 1 does not exists.");
+ }
+ }
+
+ @Test
+ public void fail_to_create_sub_characteristic_when_name_already_used() {
+ when(dao.selectByName("Compilation", session)).thenReturn(new CharacteristicDto());
+ when(dao.selectById(1, session)).thenReturn(characteristicDto);
+
+ try {
+ service.create("Compilation", 1);
+ fail();
+ } catch (BadRequestException e) {
+ assertThat(e.l10nKey()).isEqualTo("errors.is_already_used");
+ assertThat(e.l10nParams().iterator().next()).isEqualTo("Compilation");
+ }
+ }
+
+ @Test
+ public void fail_to_create_sub_characteristic_when_wrong_permission() {
+ MockUserSession.set().setGlobalPermissions(GlobalPermissions.DASHBOARD_SHARING);
+
+ try {
+ service.create("Compilation", 1);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(ForbiddenException.class);
+ }
+ }
+
+ @Test
+ public void create_characteristic() {
+ when(dao.selectMaxCharacteristicOrder(session)).thenReturn(2);
+
+ DebtCharacteristic result = service.create("Portability", null);
+
+ assertThat(result.id()).isEqualTo(currentId);
+ assertThat(result.key()).isEqualTo("PORTABILITY");
+ assertThat(result.name()).isEqualTo("Portability");
+ assertThat(result.order()).isEqualTo(3);
+ assertThat(result.createdAt()).isEqualTo(now);
+ }
+
+ @Test
+ public void create_first_characteristic() {
+ when(dao.selectMaxCharacteristicOrder(session)).thenReturn(0);
+
+ DebtCharacteristic result = service.create("Portability", null);
+
+ assertThat(result.id()).isEqualTo(currentId);
+ assertThat(result.key()).isEqualTo("PORTABILITY");
+ assertThat(result.name()).isEqualTo("Portability");
+ assertThat(result.order()).isEqualTo(1);
+ assertThat(result.createdAt()).isEqualTo(now);
+ }
+
+ @Test
+ public void rename_characteristic() {
+ when(dao.selectById(10, session)).thenReturn(subCharacteristicDto);
+
+ DebtCharacteristic result = service.rename(10, "New Efficiency");
+
+ assertThat(result.key()).isEqualTo("EFFICIENCY");
+ assertThat(result.name()).isEqualTo("New Efficiency");
+ assertThat(result.updatedAt()).isEqualTo(now);
+ }
+
+ @Test
+ public void not_rename_characteristic_when_renaming_with_same_name() {
+ when(dao.selectById(10, session)).thenReturn(subCharacteristicDto);
+
+ service.rename(10, "Efficiency");
+
+ verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
+ }
+
+ @Test
+ public void fail_to_rename_unknown_characteristic() {
+ when(dao.selectById(10, session)).thenReturn(null);
+
+ try {
+ service.rename(10, "New Efficiency");
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("Characteristic with id 10 does not exists.");
+ }
+ }
+
+ @Test
+ public void move_up() {
+ when(dao.selectById(10, session)).thenReturn(new CharacteristicDto().setId(10).setOrder(2));
+ when(dao.selectPrevious(2, session)).thenReturn(new CharacteristicDto().setId(2).setOrder(1));
+
+ DebtCharacteristic result = service.moveUp(10);
+
+ ArgumentCaptor<CharacteristicDto> argument = ArgumentCaptor.forClass(CharacteristicDto.class);
+ verify(dao, times(2)).update(argument.capture(), eq(session));
+
+ assertThat(result.order()).isEqualTo(1);
+ assertThat(argument.getAllValues().get(0).getOrder()).isEqualTo(2);
+ assertThat(argument.getAllValues().get(0).getUpdatedAt()).isEqualTo(now);
+ assertThat(argument.getAllValues().get(1).getOrder()).isEqualTo(1);
+ assertThat(argument.getAllValues().get(1).getUpdatedAt()).isEqualTo(now);
+ }
+
+ @Test
+ public void do_nothing_when_move_up_and_already_on_top() {
+ CharacteristicDto dto = new CharacteristicDto().setId(10).setOrder(1);
+ when(dao.selectById(10, session)).thenReturn(dto);
+ when(dao.selectPrevious(1, session)).thenReturn(null);
+
+ service.moveUp(10);
+
+ verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
+ }
+
+ @Test
+ public void move_down() {
+ when(dao.selectById(10, session)).thenReturn(new CharacteristicDto().setId(10).setOrder(2));
+ when(dao.selectNext(2, session)).thenReturn(new CharacteristicDto().setId(2).setOrder(3));
+
+ DebtCharacteristic result = service.moveDown(10);
+
+ ArgumentCaptor<CharacteristicDto> argument = ArgumentCaptor.forClass(CharacteristicDto.class);
+ verify(dao, times(2)).update(argument.capture(), eq(session));
+
+ assertThat(result.order()).isEqualTo(3);
+ assertThat(argument.getAllValues().get(0).getOrder()).isEqualTo(2);
+ assertThat(argument.getAllValues().get(0).getUpdatedAt()).isEqualTo(now);
+ assertThat(argument.getAllValues().get(1).getOrder()).isEqualTo(3);
+ assertThat(argument.getAllValues().get(1).getUpdatedAt()).isEqualTo(now);
+ }
+
+ @Test
+ public void do_nothing_when_move_down_and_already_on_bottom() {
+ CharacteristicDto dto = new CharacteristicDto().setId(10).setOrder(5);
+ when(dao.selectById(10, session)).thenReturn(dto);
+ when(dao.selectNext(5, session)).thenReturn(null);
+
+ service.moveDown(10);
+
+ verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
+ }
+
+ @Test
+ public void delete_sub_characteristic() {
+ BatchSession batchSession = mock(BatchSession.class);
+ when(mybatis.openBatchSession()).thenReturn(batchSession);
+
+ when(ruleDao.selectByCharacteristicOrSubCharacteristicId(2, batchSession)).thenReturn(newArrayList(
+ new RuleDto()
+ .setCharacteristicId(2).setRemediationFunction("LINEAR_OFFSET").setRemediationFactor("2h").setRemediationOffset("5min")
+ .setDefaultCharacteristicId(10).setDefaultRemediationFunction("LINEAR_OFFSET").setDefaultRemediationFactor("4h").setDefaultRemediationOffset("15min")
+ ));
+ when(dao.selectById(2, batchSession)).thenReturn(subCharacteristicDto);
+
+ service.delete(2);
+
+ ArgumentCaptor<RuleDto> ruleArgument = ArgumentCaptor.forClass(RuleDto.class);
+ verify(ruleDao).update(ruleArgument.capture(), eq(batchSession));
+ RuleDto ruleDto = ruleArgument.getValue();
+
+ // Overridden debt data are disabled
+ assertThat(ruleDto.getCharacteristicId()).isEqualTo(-1);
+ assertThat(ruleDto.getRemediationFunction()).isNull();
+ assertThat(ruleDto.getRemediationFactor()).isNull();
+ assertThat(ruleDto.getRemediationOffset()).isNull();
+ assertThat(ruleDto.getUpdatedAt()).isEqualTo(now);
+
+ // Default debt data should not be touched
+ assertThat(ruleDto.getDefaultCharacteristicId()).isEqualTo(10);
+ assertThat(ruleDto.getDefaultRemediationFunction()).isEqualTo("LINEAR_OFFSET");
+ assertThat(ruleDto.getDefaultRemediationFactor()).isEqualTo("4h");
+ assertThat(ruleDto.getDefaultRemediationOffset()).isEqualTo("15min");
+
+ ArgumentCaptor<CharacteristicDto> characteristicArgument = ArgumentCaptor.forClass(CharacteristicDto.class);
+ verify(dao).update(characteristicArgument.capture(), eq(batchSession));
+ CharacteristicDto characteristicDto = characteristicArgument.getValue();
+
+ // Sub characteristic is disable
+ assertThat(characteristicDto.getId()).isEqualTo(2);
+ assertThat(characteristicDto.isEnabled()).isFalse();
+ assertThat(characteristicDto.getUpdatedAt()).isEqualTo(now);
+ }
+
+ @Test
+ public void delete_characteristic() {
+ BatchSession batchSession = mock(BatchSession.class);
+ when(mybatis.openBatchSession()).thenReturn(batchSession);
+
+ when(ruleDao.selectByCharacteristicOrSubCharacteristicId(1, batchSession)).thenReturn(newArrayList(
+ new RuleDto().setCharacteristicId(2).setRemediationFunction("LINEAR_OFFSET").setRemediationFactor("2h").setRemediationOffset("5min")
+ ));
+ when(dao.selectCharacteristicsByParentId(1, batchSession)).thenReturn(newArrayList(
+ subCharacteristicDto
+ ));
+ when(dao.selectById(1, batchSession)).thenReturn(characteristicDto);
+
+ service.delete(1);
+
+ verify(ruleDao).update(any(RuleDto.class), eq(batchSession));
+
+ ArgumentCaptor<CharacteristicDto> characteristicArgument = ArgumentCaptor.forClass(CharacteristicDto.class);
+ verify(dao, times(2)).update(characteristicArgument.capture(), eq(batchSession));
+ CharacteristicDto subCharacteristicDto = characteristicArgument.getAllValues().get(0);
+ CharacteristicDto characteristicDto = characteristicArgument.getAllValues().get(1);
+
+ // Sub characteristic is disable
+ assertThat(subCharacteristicDto.getId()).isEqualTo(2);
+ assertThat(subCharacteristicDto.isEnabled()).isFalse();
+ assertThat(subCharacteristicDto.getUpdatedAt()).isEqualTo(now);
+
+ // Characteristic is disable
+ assertThat(characteristicDto.getId()).isEqualTo(1);
+ assertThat(characteristicDto.isEnabled()).isFalse();
+ assertThat(characteristicDto.getUpdatedAt()).isEqualTo(now);
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.debt;
+
+import org.apache.ibatis.session.SqlSession;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.rule.RuleDao;
+import org.sonar.core.rule.RuleDto;
+import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+import org.sonar.server.user.MockUserSession;
+
+import java.io.Reader;
+import java.util.Collections;
+import java.util.Date;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DebtModelRestoreTest {
+
+ @Mock
+ MyBatis myBatis;
+
+ @Mock
+ SqlSession session;
+
+ @Mock
+ TechnicalDebtModelRepository debtModelPluginRepository;
+
+ @Mock
+ CharacteristicDao dao;
+
+ @Mock
+ RuleDao ruleDao;
+
+ @Mock
+ DebtModelOperations debtModelOperations;
+
+ @Mock
+ DebtCharacteristicsXMLImporter characteristicsXMLImporter;
+
+ @Mock
+ System2 system2;
+
+ Date now = DateUtils.parseDate("2014-03-19");
+
+ int currentId;
+
+ DebtModel defaultModel = new DebtModel();
+
+ DebtModelRestore debtModelRestore;
+
+ @Before
+ public void setUp() throws Exception {
+ MockUserSession.set().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+
+ when(system2.now()).thenReturn(now.getTime());
+
+ currentId = 10;
+ // Associate an id when inserting an object to simulate the db id generator
+ doAnswer(new Answer() {
+ public Object answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ CharacteristicDto dto = (CharacteristicDto) args[0];
+ dto.setId(currentId++);
+ return null;
+ }
+ }).when(dao).insert(any(CharacteristicDto.class), any(SqlSession.class));
+
+ when(myBatis.openSession()).thenReturn(session);
+
+ Reader defaultModelReader = mock(Reader.class);
+ when(debtModelPluginRepository.createReaderForXMLFile("technical-debt")).thenReturn(defaultModelReader);
+ when(characteristicsXMLImporter.importXML(eq(defaultModelReader))).thenReturn(defaultModel);
+
+ debtModelRestore = new DebtModelRestore(myBatis, dao, ruleDao, debtModelOperations, debtModelPluginRepository, characteristicsXMLImporter, system2);
+ }
+
+ @Test
+ public void create_characteristics_when_restoring_characteristics() throws Exception {
+ debtModelRestore.restoreCharacteristics(
+ new DebtModel()
+ .addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler"), "PORTABILITY"),
+ Collections.<CharacteristicDto>emptyList(),
+ now,
+ session
+ );
+
+ ArgumentCaptor<CharacteristicDto> characteristicArgument = ArgumentCaptor.forClass(CharacteristicDto.class);
+ verify(dao, times(2)).insert(characteristicArgument.capture(), eq(session));
+ assertThat(characteristicArgument.getAllValues().get(0).getId()).isEqualTo(10);
+ assertThat(characteristicArgument.getAllValues().get(0).getKey()).isEqualTo("PORTABILITY");
+ assertThat(characteristicArgument.getAllValues().get(0).getName()).isEqualTo("Portability");
+ assertThat(characteristicArgument.getAllValues().get(0).getParentId()).isNull();
+ assertThat(characteristicArgument.getAllValues().get(0).getOrder()).isEqualTo(1);
+ assertThat(characteristicArgument.getAllValues().get(0).getCreatedAt()).isEqualTo(now);
+ assertThat(characteristicArgument.getAllValues().get(0).getUpdatedAt()).isNull();
+
+ assertThat(characteristicArgument.getAllValues().get(1).getId()).isEqualTo(11);
+ assertThat(characteristicArgument.getAllValues().get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ assertThat(characteristicArgument.getAllValues().get(1).getName()).isEqualTo("Compiler");
+ assertThat(characteristicArgument.getAllValues().get(1).getParentId()).isEqualTo(10);
+ assertThat(characteristicArgument.getAllValues().get(1).getOrder()).isNull();
+ assertThat(characteristicArgument.getAllValues().get(1).getCreatedAt()).isEqualTo(now);
+ assertThat(characteristicArgument.getAllValues().get(1).getUpdatedAt()).isNull();
+ }
+
+ @Test
+ public void update_characteristics_when_restoring_characteristics() throws Exception {
+ Date oldDate = DateUtils.parseDate("2014-01-01");
+
+ debtModelRestore.restoreCharacteristics(
+ new DebtModel()
+ .addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler"), "PORTABILITY"),
+ newArrayList(
+ new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability updated").setOrder(2).setCreatedAt(oldDate).setUpdatedAt(oldDate),
+ new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler updated").setParentId(1).setCreatedAt(oldDate).setUpdatedAt(oldDate)
+ ),
+ now,
+ session
+ );
+
+ ArgumentCaptor<CharacteristicDto> characteristicArgument = ArgumentCaptor.forClass(CharacteristicDto.class);
+ verify(dao, times(2)).update(characteristicArgument.capture(), eq(session));
+ assertThat(characteristicArgument.getAllValues().get(0).getId()).isEqualTo(1);
+ assertThat(characteristicArgument.getAllValues().get(0).getKey()).isEqualTo("PORTABILITY");
+ assertThat(characteristicArgument.getAllValues().get(0).getName()).isEqualTo("Portability");
+ assertThat(characteristicArgument.getAllValues().get(0).getParentId()).isNull();
+ assertThat(characteristicArgument.getAllValues().get(0).getOrder()).isEqualTo(1);
+ assertThat(characteristicArgument.getAllValues().get(0).getCreatedAt()).isEqualTo(oldDate);
+ assertThat(characteristicArgument.getAllValues().get(0).getUpdatedAt()).isEqualTo(now);
+
+ assertThat(characteristicArgument.getAllValues().get(1).getId()).isEqualTo(2);
+ assertThat(characteristicArgument.getAllValues().get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ assertThat(characteristicArgument.getAllValues().get(1).getName()).isEqualTo("Compiler");
+ assertThat(characteristicArgument.getAllValues().get(1).getParentId()).isEqualTo(1);
+ assertThat(characteristicArgument.getAllValues().get(1).getOrder()).isNull();
+ assertThat(characteristicArgument.getAllValues().get(1).getCreatedAt()).isEqualTo(oldDate);
+ assertThat(characteristicArgument.getAllValues().get(1).getUpdatedAt()).isEqualTo(now);
+ }
+
+ @Test
+ public void disable_no_more_existing_characteristics_when_restoring_characteristics() throws Exception {
+ CharacteristicDto dto1 = new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability").setOrder(1);
+ CharacteristicDto dto2 = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler").setParentId(1);
+
+ debtModelRestore.restoreCharacteristics(new DebtModel(), newArrayList(dto1, dto2), now, session);
+
+ verify(debtModelOperations).disableCharacteristic(dto1, now, session);
+ verify(debtModelOperations).disableCharacteristic(dto2, now, session);
+ }
+
+ @Test
+ public void restore_from_provided_model() throws Exception {
+ Date oldDate = DateUtils.parseDate("2014-01-01");
+
+ defaultModel
+ .addRootCharacteristic(new DefaultDebtCharacteristic().setKey("PORTABILITY").setName("Portability").setOrder(1))
+ .addSubCharacteristic(new DefaultDebtCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler"), "PORTABILITY");
+
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(
+ new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability updated").setOrder(2).setCreatedAt(oldDate),
+ new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler updated").setParentId(1).setCreatedAt(oldDate)
+ ));
+
+ when(ruleDao.selectOverridingDebt(session)).thenReturn(newArrayList(
+ new RuleDto().setCharacteristicId(10).setRemediationFunction("LINEAR_OFFSET").setRemediationFactor("2h").setRemediationOffset("15min")
+ .setCreatedAt(oldDate).setUpdatedAt(oldDate)
+ ));
+
+ debtModelRestore.restoreFromProvidedModel();
+
+ verify(dao).selectEnabledCharacteristics();
+ verify(dao, times(2)).update(any(CharacteristicDto.class), eq(session));
+ verifyNoMoreInteractions(dao);
+
+ verify(ruleDao).selectOverridingDebt(session);
+ ArgumentCaptor<RuleDto> ruleArgument = ArgumentCaptor.forClass(RuleDto.class);
+ verify(ruleDao).update(ruleArgument.capture(), eq(session));
+ verifyNoMoreInteractions(ruleDao);
+
+ RuleDto rule = ruleArgument.getValue();
+ assertThat(rule.getCharacteristicId()).isNull();
+ assertThat(rule.getRemediationFunction()).isNull();
+ assertThat(rule.getRemediationFactor()).isNull();
+ assertThat(rule.getRemediationOffset()).isNull();
+ assertThat(rule.getUpdatedAt()).isEqualTo(now);
+
+ verify(session).commit();
+ }
+}
*/
package org.sonar.server.debt;
-import org.apache.ibatis.session.SqlSession;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
-import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
-import org.mockito.stubbing.Answer;
-import org.sonar.api.server.debt.DebtCharacteristic;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.System2;
-import org.sonar.core.permission.GlobalPermissions;
-import org.sonar.core.persistence.BatchSession;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.rule.RuleDao;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.core.technicaldebt.db.CharacteristicDao;
-import org.sonar.core.technicaldebt.db.CharacteristicDto;
-import org.sonar.server.exceptions.BadRequestException;
-import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.user.MockUserSession;
-import java.util.Date;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.fest.assertions.Assertions.assertThat;
-import static org.fest.assertions.Fail.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.verify;
@RunWith(MockitoJUnitRunner.class)
public class DebtModelServiceTest {
@Mock
- CharacteristicDao dao;
-
- @Mock
- RuleDao ruleDao;
+ DebtModelOperations debtModelOperations;
@Mock
- MyBatis mybatis;
+ DebtModelLookup debtModelLookup;
@Mock
- SqlSession session;
-
- @Mock
- System2 system2;
-
- Date now = DateUtils.parseDate("2014-03-19");
-
- CharacteristicDto characteristicDto = new CharacteristicDto()
- .setId(1)
- .setKey("MEMORY_EFFICIENCY")
- .setName("Memory use")
- .setOrder(2)
- .setEnabled(true);
-
- CharacteristicDto subCharacteristicDto = new CharacteristicDto()
- .setId(2)
- .setKey("EFFICIENCY")
- .setName("Efficiency")
- .setParentId(1)
- .setEnabled(true);
-
- int currentId;
+ DebtModelRestore debtModelRestore;
DebtModelService service;
@Before
public void setUp() throws Exception {
- when(system2.now()).thenReturn(now.getTime());
-
- MockUserSession.set().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
-
- currentId = 10;
- // Associate an id when inserting an object to simulate the db id generator
- doAnswer(new Answer() {
- public Object answer(InvocationOnMock invocation) {
- Object[] args = invocation.getArguments();
- CharacteristicDto dto = (CharacteristicDto) args[0];
- dto.setId(++currentId);
- return null;
- }
- }).when(dao).insert(any(CharacteristicDto.class), any(SqlSession.class));
-
- when(mybatis.openSession()).thenReturn(session);
- service = new DebtModelService(mybatis, dao, ruleDao,system2);
+ service = new DebtModelService(debtModelOperations, debtModelLookup, debtModelRestore);
}
@Test
public void find_root_characteristics() {
- when(dao.selectEnabledRootCharacteristics()).thenReturn(newArrayList(characteristicDto));
- assertThat(service.rootCharacteristics()).hasSize(1);
+ service.rootCharacteristics();
+ verify(debtModelLookup).rootCharacteristics();
}
@Test
public void find_characteristics() {
- when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(characteristicDto));
- assertThat(service.characteristics()).hasSize(1);
+ service.characteristics();
+ verify(debtModelLookup).characteristics();
}
@Test
public void find_characteristic_by_id() {
- when(dao.selectById(1)).thenReturn(characteristicDto);
-
- DebtCharacteristic characteristic = service.characteristicById(1);
- assertThat(characteristic.id()).isEqualTo(1);
- assertThat(characteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(characteristic.name()).isEqualTo("Memory use");
- assertThat(characteristic.order()).isEqualTo(2);
- assertThat(characteristic.parentId()).isNull();
-
- assertThat(service.characteristicById(111)).isNull();
- }
-
- @Test
- public void create_sub_characteristic() {
- when(dao.selectById(1, session)).thenReturn(characteristicDto);
-
- DebtCharacteristic result = service.create("Compilation name", 1);
-
- assertThat(result.id()).isEqualTo(currentId);
- assertThat(result.key()).isEqualTo("COMPILATION_NAME");
- assertThat(result.name()).isEqualTo("Compilation name");
- assertThat(result.parentId()).isEqualTo(1);
- }
-
- @Test
- public void fail_to_create_sub_characteristic_when_parent_id_is_not_a_root_characteristic() {
- when(dao.selectById(1, session)).thenReturn(subCharacteristicDto);
-
- try {
- service.create("Compilation", 1);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(BadRequestException.class).hasMessage("A sub characteristic can not have a sub characteristic as parent.");
- }
- }
-
- @Test
- public void fail_to_create_sub_characteristic_when_parent_does_not_exists() {
- when(dao.selectById(1, session)).thenReturn(null);
-
- try {
- service.create("Compilation", 1);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("Characteristic with id 1 does not exists.");
- }
- }
-
- @Test
- public void fail_to_create_sub_characteristic_when_name_already_used() {
- when(dao.selectByName("Compilation", session)).thenReturn(new CharacteristicDto());
- when(dao.selectById(1, session)).thenReturn(characteristicDto);
-
- try {
- service.create("Compilation", 1);
- fail();
- } catch (BadRequestException e) {
- assertThat(e.l10nKey()).isEqualTo("errors.is_already_used");
- assertThat(e.l10nParams().iterator().next()).isEqualTo("Compilation");
- }
- }
-
- @Test
- public void fail_to_create_sub_characteristic_when_wrong_permission() {
- MockUserSession.set().setGlobalPermissions(GlobalPermissions.DASHBOARD_SHARING);
-
- try {
- service.create("Compilation", 1);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(ForbiddenException.class);
- }
+ service.characteristicById(111);
+ verify(debtModelLookup).characteristicById(111);
}
@Test
public void create_characteristic() {
- when(dao.selectMaxCharacteristicOrder(session)).thenReturn(2);
-
- DebtCharacteristic result = service.create("Portability", null);
-
- assertThat(result.id()).isEqualTo(currentId);
- assertThat(result.key()).isEqualTo("PORTABILITY");
- assertThat(result.name()).isEqualTo("Portability");
- assertThat(result.order()).isEqualTo(3);
- }
-
- @Test
- public void create_first_characteristic() {
- when(dao.selectMaxCharacteristicOrder(session)).thenReturn(0);
-
- DebtCharacteristic result = service.create("Portability", null);
-
- assertThat(result.id()).isEqualTo(currentId);
- assertThat(result.key()).isEqualTo("PORTABILITY");
- assertThat(result.name()).isEqualTo("Portability");
- assertThat(result.order()).isEqualTo(1);
+ service.create("Compilation name", 1);
+ verify(debtModelOperations).create("Compilation name", 1);
}
@Test
public void rename_characteristic() {
- when(dao.selectById(10, session)).thenReturn(subCharacteristicDto);
-
- DebtCharacteristic result = service.rename(10, "New Efficiency");
-
- assertThat(result.key()).isEqualTo("EFFICIENCY");
- assertThat(result.name()).isEqualTo("New Efficiency");
- }
-
- @Test
- public void not_rename_characteristic_when_renaming_with_same_name() {
- when(dao.selectById(10, session)).thenReturn(subCharacteristicDto);
-
- service.rename(10, "Efficiency");
-
- verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
- }
-
- @Test
- public void fail_to_rename_unknown_characteristic() {
- when(dao.selectById(10, session)).thenReturn(null);
-
- try {
- service.rename(10, "New Efficiency");
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("Characteristic with id 10 does not exists.");
- }
+ service.rename(10, "New Efficiency");
+ verify(debtModelOperations).rename(10, "New Efficiency");
}
@Test
public void move_up() {
- when(dao.selectById(10, session)).thenReturn(new CharacteristicDto().setId(10).setOrder(2));
- when(dao.selectPrevious(2, session)).thenReturn(new CharacteristicDto().setId(2).setOrder(1));
-
- DebtCharacteristic result = service.moveUp(10);
-
- ArgumentCaptor<CharacteristicDto> argument = ArgumentCaptor.forClass(CharacteristicDto.class);
- verify(dao, times(2)).update(argument.capture(), eq(session));
-
- assertThat(result.order()).isEqualTo(1);
- assertThat(argument.getAllValues().get(0).getOrder()).isEqualTo(2);
- assertThat(argument.getAllValues().get(1).getOrder()).isEqualTo(1);
- }
-
- @Test
- public void do_nothing_when_move_up_and_already_on_top() {
- CharacteristicDto dto = new CharacteristicDto().setId(10).setOrder(1);
- when(dao.selectById(10, session)).thenReturn(dto);
- when(dao.selectPrevious(1, session)).thenReturn(null);
-
service.moveUp(10);
-
- verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
+ verify(debtModelOperations).moveUp(10);
}
@Test
public void move_down() {
- when(dao.selectById(10, session)).thenReturn(new CharacteristicDto().setId(10).setOrder(2));
- when(dao.selectNext(2, session)).thenReturn(new CharacteristicDto().setId(2).setOrder(3));
-
- DebtCharacteristic result = service.moveDown(10);
-
- ArgumentCaptor<CharacteristicDto> argument = ArgumentCaptor.forClass(CharacteristicDto.class);
- verify(dao, times(2)).update(argument.capture(), eq(session));
-
- assertThat(result.order()).isEqualTo(3);
- assertThat(argument.getAllValues().get(0).getOrder()).isEqualTo(2);
- assertThat(argument.getAllValues().get(1).getOrder()).isEqualTo(3);
- }
-
- @Test
- public void do_nothing_when_move_down_and_already_on_bottom() {
- CharacteristicDto dto = new CharacteristicDto().setId(10).setOrder(5);
- when(dao.selectById(10, session)).thenReturn(dto);
- when(dao.selectNext(5, session)).thenReturn(null);
-
service.moveDown(10);
-
- verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
+ verify(debtModelOperations).moveDown(10);
}
@Test
- public void delete_sub_characteristic() {
- BatchSession batchSession = mock(BatchSession.class);
- when(mybatis.openBatchSession()).thenReturn(batchSession);
-
- when(ruleDao.selectByCharacteristicOrSubCharacteristicId(2, batchSession)).thenReturn(newArrayList(
- new RuleDto()
- .setCharacteristicId(2).setRemediationFunction("LINEAR_OFFSET").setRemediationFactor("2h").setRemediationOffset("5min")
- .setDefaultCharacteristicId(10).setDefaultRemediationFunction("LINEAR_OFFSET").setDefaultRemediationFactor("4h").setDefaultRemediationOffset("15min")
- ));
- when(dao.selectById(2, batchSession)).thenReturn(subCharacteristicDto);
-
+ public void delete_characteristic() {
service.delete(2);
-
- ArgumentCaptor<RuleDto> ruleArgument = ArgumentCaptor.forClass(RuleDto.class);
- verify(ruleDao).update(ruleArgument.capture(), eq(batchSession));
- RuleDto ruleDto = ruleArgument.getValue();
-
- // Overridden debt data are disabled
- assertThat(ruleDto.getCharacteristicId()).isEqualTo(-1);
- assertThat(ruleDto.getRemediationFunction()).isNull();
- assertThat(ruleDto.getRemediationFactor()).isNull();
- assertThat(ruleDto.getRemediationOffset()).isNull();
- assertThat(ruleDto.getUpdatedAt()).isEqualTo(now);
-
- // Default debt data should not be touched
- assertThat(ruleDto.getDefaultCharacteristicId()).isEqualTo(10);
- assertThat(ruleDto.getDefaultRemediationFunction()).isEqualTo("LINEAR_OFFSET");
- assertThat(ruleDto.getDefaultRemediationFactor()).isEqualTo("4h");
- assertThat(ruleDto.getDefaultRemediationOffset()).isEqualTo("15min");
-
- ArgumentCaptor<CharacteristicDto> characteristicArgument = ArgumentCaptor.forClass(CharacteristicDto.class);
- verify(dao).update(characteristicArgument.capture(), eq(batchSession));
- CharacteristicDto characteristicDto = characteristicArgument.getValue();
-
- // Sub characteristic is disable
- assertThat(characteristicDto.getId()).isEqualTo(2);
- assertThat(characteristicDto.isEnabled()).isFalse();
- assertThat(characteristicDto.getUpdatedAt()).isEqualTo(now);
+ verify(debtModelOperations).delete(2);
}
@Test
- public void delete_characteristic() {
- BatchSession batchSession = mock(BatchSession.class);
- when(mybatis.openBatchSession()).thenReturn(batchSession);
-
- when(ruleDao.selectByCharacteristicOrSubCharacteristicId(1, batchSession)).thenReturn(newArrayList(
- new RuleDto().setCharacteristicId(2).setRemediationFunction("LINEAR_OFFSET").setRemediationFactor("2h").setRemediationOffset("5min")
- ));
- when(dao.selectCharacteristicsByParentId(1, batchSession)).thenReturn(newArrayList(
- subCharacteristicDto
- ));
- when(dao.selectById(1, batchSession)).thenReturn(characteristicDto);
-
- service.delete(1);
-
- verify(ruleDao).update(any(RuleDto.class), eq(batchSession));
-
- ArgumentCaptor<CharacteristicDto> characteristicArgument = ArgumentCaptor.forClass(CharacteristicDto.class);
- verify(dao, times(2)).update(characteristicArgument.capture(), eq(batchSession));
- CharacteristicDto subCharacteristicDto = characteristicArgument.getAllValues().get(0);
- CharacteristicDto characteristicDto = characteristicArgument.getAllValues().get(1);
-
- // Sub characteristic is disable
- assertThat(subCharacteristicDto.getId()).isEqualTo(2);
- assertThat(subCharacteristicDto.isEnabled()).isFalse();
- assertThat(subCharacteristicDto.getUpdatedAt()).isEqualTo(now);
-
- // Characteristic is disable
- assertThat(characteristicDto.getId()).isEqualTo(1);
- assertThat(characteristicDto.isEnabled()).isFalse();
- assertThat(characteristicDto.getUpdatedAt()).isEqualTo(now);
+ public void restore_provided_model() {
+ service.restore();
+ verify(debtModelRestore).restoreFromProvidedModel();
}
}
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.server.debt.DebtCharacteristic;
+import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.technicaldebt.TechnicalDebtModelRepository;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import java.util.Collections;
import java.util.List;
+import static com.google.common.collect.Lists.newArrayList;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
Integer currentId = 1;
- private DebtCharacteristicsXMLImporter.DebtModel defaultModel;
+ DebtModel defaultModel = new DebtModel();
- private DebtModelSynchronizer manager;
+ DebtModelSynchronizer manager;
@Before
public void initAndMerge() throws Exception {
when(myBatis.openSession()).thenReturn(session);
- defaultModel = new DebtCharacteristicsXMLImporter.DebtModel();
Reader defaultModelReader = mock(Reader.class);
when(technicalDebtModelRepository.createReaderForXMLFile("technical-debt")).thenReturn(defaultModelReader);
when(xmlImporter.importXML(eq(defaultModelReader))).thenReturn(defaultModel);
@Test
public void create_default_model_on_first_execution_when_no_plugin() throws Exception {
- DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
- new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(rootCharacteristic);
- defaultModel.addRootCharacteristic(rootCharacteristic);
+ DebtCharacteristic characteristic = new DefaultDebtCharacteristic().setKey("PORTABILITY");
+ DebtCharacteristic subCharacteristic = new DefaultDebtCharacteristic().setKey("COMPILER_RELATED_PORTABILITY");
+ defaultModel.addRootCharacteristic(characteristic);
+ defaultModel.addSubCharacteristic(subCharacteristic, "PORTABILITY");
when(technicalDebtModelRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
@Test
public void not_create_default_model_if_already_exists() throws Exception {
- DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
- new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(rootCharacteristic);
- defaultModel.addRootCharacteristic(rootCharacteristic);
+ DebtCharacteristic characteristic = new DefaultDebtCharacteristic().setKey("PORTABILITY");
+ DebtCharacteristic subCharacteristic = new DefaultDebtCharacteristic().setKey("COMPILER_RELATED_PORTABILITY");
+ defaultModel.addRootCharacteristic(characteristic);
+ defaultModel.addSubCharacteristic(subCharacteristic, "PORTABILITY");
when(technicalDebtModelRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
- when(dao.selectEnabledCharacteristics()).thenReturn(Lists.newArrayList(new CharacteristicDto()));
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(new CharacteristicDto()));
manager.synchronize();