import org.sonar.api.rules.RuleQuery;
import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.core.debt.DefaultTechnicalDebtModel;
-import org.sonar.core.debt.db.CharacteristicDao;
-import org.sonar.core.debt.db.CharacteristicDto;
+import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
import java.util.Collection;
import java.util.List;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
import org.sonar.api.utils.internal.WorkDuration;
-import org.sonar.core.debt.DefaultTechnicalDebtModel;
-import org.sonar.core.debt.db.CharacteristicDao;
-import org.sonar.core.debt.db.CharacteristicDto;
+import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
+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;
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-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.utils.ValidationMessages;
-import org.sonar.core.debt.db.CharacteristicDao;
-import org.sonar.core.debt.db.CharacteristicDto;
-import org.sonar.core.persistence.MyBatis;
-
-import java.io.Reader;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-public class CharacteristicsDebtModelSynchronizer implements ServerExtension {
-
- private static final Logger LOG = LoggerFactory.getLogger(CharacteristicsDebtModelSynchronizer.class);
-
- private final MyBatis mybatis;
- private final CharacteristicDao dao;
- private final DebtModelPluginRepository languageModelFinder;
- private final CharacteristicsDebtModelXMLImporter importer;
-
- public CharacteristicsDebtModelSynchronizer(MyBatis mybatis, CharacteristicDao dao, DebtModelPluginRepository modelRepository, CharacteristicsDebtModelXMLImporter importer) {
- this.mybatis = mybatis;
- this.dao = dao;
- this.languageModelFinder = modelRepository;
- this.importer = importer;
- }
-
- public List<CharacteristicDto> synchronize(ValidationMessages messages) {
- SqlSession session = mybatis.openSession();
-
- List<CharacteristicDto> model = newArrayList();
- try {
- model = synchronize(messages, session);
- session.commit();
- } finally {
- MyBatis.closeQuietly(session);
- }
- return model;
- }
-
- public List<CharacteristicDto> synchronize(ValidationMessages messages, SqlSession session) {
- DefaultTechnicalDebtModel defaultModel = loadModelFromXml(DebtModelPluginRepository.DEFAULT_MODEL, messages);
- List<CharacteristicDto> model = loadOrCreateModelFromDb(defaultModel, session);
- messages.log(LOG);
- return model;
- }
-
- private List<CharacteristicDto> loadOrCreateModelFromDb(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
- List<CharacteristicDto> characteristicDtos = loadModel();
- if (characteristicDtos.isEmpty()) {
- return createTechnicalDebtModel(defaultModel, session);
- }
- return characteristicDtos;
- }
-
- private List<CharacteristicDto> loadModel() {
- return dao.selectEnabledCharacteristics();
- }
-
- private List<CharacteristicDto> createTechnicalDebtModel(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
- List<CharacteristicDto> characteristics = newArrayList();
- for (DefaultCharacteristic rootCharacteristic : defaultModel.rootCharacteristics()) {
- CharacteristicDto rootCharacteristicDto = CharacteristicDto.toDto(rootCharacteristic, null);
- dao.insert(rootCharacteristicDto, session);
- characteristics.add(rootCharacteristicDto);
- for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
- CharacteristicDto characteristicDto = CharacteristicDto.toDto(characteristic, rootCharacteristicDto.getId());
- dao.insert(characteristicDto, session);
- characteristics.add(characteristicDto);
- }
- }
- return characteristics;
- }
-
- public DefaultTechnicalDebtModel loadModelFromXml(String pluginKey, ValidationMessages messages) {
- Reader xmlFileReader = null;
- try {
- xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
- return importer.importXML(xmlFileReader, messages);
- } finally {
- IOUtils.closeQuietly(xmlFileReader);
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-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.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.utils.ValidationMessages;
-
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-
-import java.io.Reader;
-import java.io.StringReader;
-
-public class CharacteristicsDebtModelXMLImporter implements ServerExtension {
-
- private static final Logger LOG = LoggerFactory.getLogger(CharacteristicsDebtModelXMLImporter.class);
-
- public static final String CHARACTERISTIC = "chc";
- public static final String CHARACTERISTIC_KEY = "key";
- public static final String CHARACTERISTIC_NAME = "name";
-
- public DefaultTechnicalDebtModel importXML(String xml, ValidationMessages messages) {
- return importXML(new StringReader(xml), messages);
- }
-
- public DefaultTechnicalDebtModel importXML(Reader xml, ValidationMessages messages) {
- DefaultTechnicalDebtModel model = new DefaultTechnicalDebtModel();
- try {
- SMInputFactory inputFactory = initStax();
- SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
-
- // advance to <sqale>
- cursor.advance();
- SMInputCursor chcCursor = cursor.childElementCursor(CHARACTERISTIC);
-
- while (chcCursor.getNext() != null) {
- processCharacteristic(model, null, chcCursor, messages);
- }
-
- cursor.getStreamReader().closeCompletely();
-
- } catch (XMLStreamException e) {
- LOG.error("XML is not valid", e);
- messages.addErrorText("XML is not valid: " + e.getMessage());
- }
- return model;
- }
-
- private SMInputFactory initStax() {
- XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
- xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
- xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
- xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
- xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
- return new SMInputFactory(xmlFactory);
- }
-
- private DefaultCharacteristic processCharacteristic(DefaultTechnicalDebtModel model, DefaultCharacteristic parent, SMInputCursor chcCursor,
- ValidationMessages messages) throws XMLStreamException {
- DefaultCharacteristic characteristic = new DefaultCharacteristic();
- SMInputCursor cursor = chcCursor.childElementCursor();
- while (cursor.getNext() != null) {
- String node = cursor.getLocalName();
- if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
- 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);
-
- } else if (StringUtils.equals(node, CHARACTERISTIC_NAME)) {
- characteristic.setName(cursor.collectDescendantText().trim(), false);
-
- // <chc> can contain characteristics or requirements
- } else if (StringUtils.equals(node, CHARACTERISTIC)) {
- processCharacteristic(model, characteristic, cursor, messages);
-
- }
- }
-
- if (StringUtils.isNotBlank(characteristic.key()) && characteristic.isRoot()) {
- characteristic.setOrder(model.rootCharacteristics().size() + 1);
- model.addRootCharacteristic(characteristic);
- return characteristic;
- }
- return null;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Maps;
-import org.picocontainer.Startable;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
-
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-/**
- * <p>This class is used to find which technical debt model XML files exist in the Sonar instance.</p>
- * <p>
- * Those XML files are provided by language plugins that embed their own contribution to the definition of the Technical debt model.
- * They must be located in the classpath of those language plugins, more specifically in the "com.sonar.sqale" package, and
- * they must be named "<pluginKey>-model.xml".
- * </p>
- */
-public class DebtModelPluginRepository implements ServerExtension, Startable {
-
- public static final String DEFAULT_MODEL = "technical-debt";
-
- private static final String XML_FILE_SUFFIX = "-model.xml";
- private static final String XML_FILE_PREFIX = "com/sonar/sqale/";
-
- private String xmlFilePrefix;
-
- private PluginRepository pluginRepository;
- private Map<String, ClassLoader> contributingPluginKeyToClassLoader;
-
- public DebtModelPluginRepository(PluginRepository pluginRepository) {
- this.pluginRepository = pluginRepository;
- this.xmlFilePrefix = XML_FILE_PREFIX;
- }
-
- @VisibleForTesting
- DebtModelPluginRepository(PluginRepository pluginRepository, String xmlFilePrefix) {
- this.pluginRepository = pluginRepository;
- this.xmlFilePrefix = xmlFilePrefix;
- }
-
- @VisibleForTesting
- DebtModelPluginRepository(Map<String, ClassLoader> contributingPluginKeyToClassLoader, String xmlFilePrefix) {
- this.contributingPluginKeyToClassLoader = contributingPluginKeyToClassLoader;
- this.xmlFilePrefix = xmlFilePrefix;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void start() {
- findAvailableXMLFiles();
- }
-
- protected void findAvailableXMLFiles() {
- if (contributingPluginKeyToClassLoader == null) {
- contributingPluginKeyToClassLoader = Maps.newTreeMap();
- // Add default model
- contributingPluginKeyToClassLoader.put(DEFAULT_MODEL, getClass().getClassLoader());
- for (PluginMetadata metadata : pluginRepository.getMetadata()) {
- String pluginKey = metadata.getKey();
- ClassLoader classLoader = pluginRepository.getPlugin(pluginKey).getClass().getClassLoader();
- if (classLoader.getResource(getXMLFilePath(pluginKey)) != null) {
- contributingPluginKeyToClassLoader.put(pluginKey, classLoader);
- }
- }
- }
- contributingPluginKeyToClassLoader = Collections.unmodifiableMap(contributingPluginKeyToClassLoader);
- }
-
- @VisibleForTesting
- String getXMLFilePath(String model) {
- return xmlFilePrefix + model + XML_FILE_SUFFIX;
- }
-
- /**
- * Returns the list of plugins that can contribute to the technical debt model.
- *
- * @return the list of plugin keys
- */
- public Collection<String> getContributingPluginList() {
- return newArrayList(contributingPluginKeyToClassLoader.keySet());
- }
-
- /**
- * Creates a new {@link java.io.Reader} for the XML file that contains the model contributed by the given plugin.
- *
- * @param pluginKey the key of the plugin that contributes the XML file
- * @return the reader, that must be closed once its use is finished.
- */
- public Reader createReaderForXMLFile(String pluginKey) {
- ClassLoader classLoader = contributingPluginKeyToClassLoader.get(pluginKey);
- String xmlFilePath = getXMLFilePath(pluginKey);
- return new InputStreamReader(classLoader.getResourceAsStream(xmlFilePath));
- }
-
- @VisibleForTesting
- Map<String, ClassLoader> getContributingPluginKeyToClassLoader(){
- return contributingPluginKeyToClassLoader;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void stop() {
- // Nothing to do
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.technicaldebt.server.Characteristic;
-import org.sonar.api.technicaldebt.server.TechnicalDebtManager;
-import org.sonar.api.technicaldebt.server.internal.DefaultCharacteristic;
-import org.sonar.core.debt.db.CharacteristicDao;
-import org.sonar.core.debt.db.CharacteristicDto;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-/**
- * TODO This class should be replaced or created by a TechnicalDebtManagerBuilder
- */
-public class DefaultTechnicalDebtManager implements TechnicalDebtManager {
-
- private final CharacteristicDao dao;
- private final RuleFinder ruleFinder;
-
- public DefaultTechnicalDebtManager(CharacteristicDao dao, RuleFinder ruleFinder) {
- this.dao = dao;
- this.ruleFinder = ruleFinder;
- }
-
- public List<Characteristic> findRootCharacteristics() {
- List<CharacteristicDto> dtos = dao.selectEnabledRootCharacteristics();
- List<Characteristic> characteristics = newArrayList();
- for (CharacteristicDto dto : dtos) {
- characteristics.add(toCharacteristic(dto, null));
- }
- return characteristics;
- }
-
- @CheckForNull
- public Characteristic findCharacteristicById(Integer id) {
- CharacteristicDto dto = dao.selectById(id);
- if (dto != null) {
- return toCharacteristic(dto, null);
- }
- return null;
- }
-
- @CheckForNull
- public Characteristic findRequirementByRuleId(int ruleId) {
- CharacteristicDto requirementDto = dao.selectByRuleId(ruleId);
- if (requirementDto != null) {
- Rule rule = ruleFinder.findById(ruleId);
- if (rule == null) {
- throw new IllegalArgumentException(String.format("Rule with id '%s' do not exists.", ruleId));
- }
- return toCharacteristic(requirementDto, RuleKey.of(rule.getRepositoryKey(), rule.getKey()));
- }
- return null;
- }
-
- @CheckForNull
- public Characteristic findRequirementByRule(Rule rule) {
- CharacteristicDto requirementDto = dao.selectByRuleId(rule.getId());
- if (requirementDto != null) {
- return toCharacteristic(requirementDto, RuleKey.of(rule.getRepositoryKey(), rule.getKey()));
- }
- return null;
- }
-
- private static Characteristic toCharacteristic(CharacteristicDto dto, @Nullable RuleKey ruleKey) {
- Double factorValue = dto.getFactorValue();
- Double offsetValue = dto.getOffsetValue();
- return new DefaultCharacteristic()
- .setId(dto.getId())
- .setKey(dto.getKey())
- .setName(dto.getName())
- .setOrder(dto.getOrder())
- .setParentId(dto.getParentId())
- .setRootId(dto.getRootId())
- .setRuleKey(ruleKey)
- .setFunction(dto.getFunction())
- .setFactorValue(factorValue != null ? factorValue.intValue() : null)
- .setFactorUnit(DefaultCharacteristic.toUnit(dto.getFactorUnit()))
- .setOffsetValue(offsetValue != null ? offsetValue.intValue() : null)
- .setOffsetUnit(DefaultCharacteristic.toUnit(dto.getOffsetUnit()));
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-
-import javax.annotation.CheckForNull;
-
-import java.util.Collection;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-public class DefaultTechnicalDebtModel implements TechnicalDebtModel {
-
- private Collection<DefaultCharacteristic> rootCharacteristics;
-
- public DefaultTechnicalDebtModel() {
- rootCharacteristics = newArrayList();
- }
-
- public DefaultTechnicalDebtModel 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);
- }
-
- @CheckForNull
- public DefaultCharacteristic characteristicById(final Integer id){
- return Iterables.find(characteristics(), new Predicate<DefaultCharacteristic>() {
- @Override
- public boolean apply(DefaultCharacteristic input) {
- return input.id().equals(id);
- }
- }, null);
- }
-
- @CheckForNull
- public DefaultRequirement requirementsByRule(final RuleKey ruleKey) {
- return Iterables.find(requirements(), new Predicate<DefaultRequirement>() {
- @Override
- public boolean apply(DefaultRequirement input) {
- return input.ruleKey().equals(ruleKey);
- }
- }, null);
- }
-
- @CheckForNull
- public DefaultRequirement requirementsById(final Integer id){
- return Iterables.find(requirements(), new Predicate<DefaultRequirement>() {
- @Override
- public boolean apply(DefaultRequirement input) {
- return input.id().equals(id);
- }
- }, 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 List<DefaultRequirement> requirements() {
- List<DefaultRequirement> allRequirements = newArrayList();
- for (DefaultCharacteristic characteristic : characteristics()) {
- for (DefaultRequirement requirement : characteristic.requirements()) {
- allRequirements.add(requirement);
- }
- }
- return allRequirements;
- }
-
- public boolean isEmpty(){
- return rootCharacteristics.isEmpty();
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
-import com.google.common.collect.Iterables;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.math.NumberUtils;
-import org.codehaus.stax2.XMLInputFactory2;
-import org.codehaus.staxmate.SMInputFactory;
-import org.codehaus.staxmate.in.SMHierarchicCursor;
-import org.codehaus.staxmate.in.SMInputCursor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.rule.RemediationFunction;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.Duration;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-public class RulesDebtModelXMLImporter implements ServerExtension {
-
- private static final Logger LOG = LoggerFactory.getLogger(RulesDebtModelXMLImporter.class);
-
- public static final String CHARACTERISTIC = "chc";
- public static final String CHARACTERISTIC_KEY = "key";
- public static final String PROPERTY = "prop";
-
- public static final String PROPERTY_KEY = "key";
- public static final String PROPERTY_VALUE = "val";
- public static final String PROPERTY_TEXT_VALUE = "txt";
-
- public static final String REPOSITORY_KEY = "rule-repo";
- public static final String RULE_KEY = "rule-key";
-
- public static final String PROPERTY_FUNCTION = "remediationFunction";
- public static final String PROPERTY_FACTOR = "remediationFactor";
- public static final String PROPERTY_OFFSET = "offset";
-
- public List<RuleDebt> importXML(String xml) {
- return importXML(new StringReader(xml));
- }
-
- public List<RuleDebt> importXML(Reader xml) {
- List<RuleDebt> ruleDebts = newArrayList();
- try {
- SMInputFactory inputFactory = initStax();
- SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
-
- // advance to <sqale>
- cursor.advance();
- SMInputCursor rootCursor = cursor.childElementCursor(CHARACTERISTIC);
- while (rootCursor.getNext() != null) {
- processCharacteristic(ruleDebts, null, null, rootCursor);
- }
-
- cursor.getStreamReader().closeCompletely();
- } catch (XMLStreamException e) {
- LOG.error("XML is not valid", e);
- }
-
- return ruleDebts;
- }
-
- private SMInputFactory initStax() {
- XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
- xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
- xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
- xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
- xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
- return new SMInputFactory(xmlFactory);
- }
-
- private void processCharacteristic(List<RuleDebt> ruleDebts, @Nullable String rootKey, @Nullable String parentKey, SMInputCursor chcCursor) throws XMLStreamException {
- String currentCharacteristicKey = null;
- SMInputCursor cursor = chcCursor.childElementCursor();
- while (cursor.getNext() != null) {
- String node = cursor.getLocalName();
- if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
- currentCharacteristicKey = cursor.collectDescendantText().trim();
- } else if (StringUtils.equals(node, CHARACTERISTIC)) {
- processCharacteristic(ruleDebts, parentKey, currentCharacteristicKey, cursor);
- } else if (StringUtils.equals(node, REPOSITORY_KEY)) {
- RuleDebt ruleDebt = processRule(cursor);
- if (ruleDebt != null) {
- if (rootKey != null) {
- ruleDebt.characteristicKey = parentKey;
- ruleDebts.add(ruleDebt);
- } else {
- LOG.warn("Rule '" + ruleDebt.ruleKey + "' is ignored because it's defined directly under a root characteristic.");
- }
- }
- }
- }
- }
-
- private RuleDebt processRule(SMInputCursor cursor)
- throws XMLStreamException {
-
- RuleDebt ruleDebt = new RuleDebt();
- String ruleRepositoryKey = cursor.collectDescendantText().trim();
- String ruleKey = null;
- Properties properties = new Properties();
- while (cursor.getNext() != null) {
- String node = cursor.getLocalName();
- if (StringUtils.equals(node, PROPERTY)) {
- properties.add(processProperty(cursor));
- } else if (StringUtils.equals(node, RULE_KEY)) {
- ruleKey = cursor.collectDescendantText().trim();
- }
- }
- if (StringUtils.isNotBlank(ruleRepositoryKey) && StringUtils.isNotBlank(ruleKey)) {
- ruleDebt.ruleKey = RuleKey.of(ruleRepositoryKey, ruleKey);
- } else {
- return null;
- }
- return processFunctionsOnRequirement(ruleDebt, properties);
- }
-
- private Property processProperty(SMInputCursor cursor) throws XMLStreamException {
- SMInputCursor c = cursor.childElementCursor();
- String key = null;
- int value = 0;
- String textValue = null;
- while (c.getNext() != null) {
- String node = c.getLocalName();
- if (StringUtils.equals(node, PROPERTY_KEY)) {
- key = c.collectDescendantText().trim();
-
- } else if (StringUtils.equals(node, PROPERTY_VALUE)) {
- String s = c.collectDescendantText().trim();
- try {
- Double valueDouble = NumberUtils.createDouble(s);
- value = valueDouble.intValue();
- } catch (NumberFormatException ex) {
- LOG.error(String.format("Cannot import value '%s' for field %s - Expected a numeric value instead", s, key));
- }
- } else if (StringUtils.equals(node, PROPERTY_TEXT_VALUE)) {
- textValue = c.collectDescendantText().trim();
- }
- }
- return new Property(key, value, textValue);
- }
-
- @CheckForNull
- private RuleDebt processFunctionsOnRequirement(RuleDebt requirement, Properties properties) {
- Property function = properties.function();
- Property factor = properties.factor();
- Property offset = properties.offset();
-
- if (function != null) {
- // Init with default values
- requirement.factor = "0" + Duration.DAY;
- requirement.offset = "0" + Duration.DAY;
-
- String functionKey = function.getTextValue();
- if ("linear_threshold".equals(functionKey)) {
- function.setTextValue(RemediationFunction.LINEAR.name().toLowerCase());
- offset.setValue(0);
- offset.setTextValue(Duration.DAY);
- LOG.warn(String.format("Linear with threshold function is no longer used, remediation function of '%s' is replaced by linear.", requirement.ruleKey));
- } else if ("constant_resource".equals(functionKey)) {
- LOG.warn(String.format("Constant/file function is no longer used, technical debt definitions on '%s' are ignored.", requirement.ruleKey));
- return null;
- }
-
- requirement.function = RemediationFunction.valueOf(function.getTextValue().toUpperCase());
- if (factor != null) {
- requirement.factor = Integer.toString(factor.getValue());
- requirement.factor += !Strings.isNullOrEmpty(factor.getTextValue()) ? factor.getTextValue() : Duration.DAY;
- }
- if (offset != null) {
- requirement.offset = Integer.toString(offset.getValue());
- requirement.offset += !Strings.isNullOrEmpty(offset.getTextValue()) ? offset.getTextValue() : Duration.DAY;
- }
- return requirement;
- }
- return null;
- }
-
- private static class Properties {
- List<Property> properties;
-
- public Properties() {
- this.properties = newArrayList();
- }
-
- public Properties add(Property property) {
- this.properties.add(property);
- return this;
- }
-
- public Property function() {
- return find(PROPERTY_FUNCTION);
- }
-
- public Property factor() {
- return find(PROPERTY_FACTOR);
- }
-
- public Property offset() {
- return find(PROPERTY_OFFSET);
- }
-
- private Property find(final String key) {
- return Iterables.find(properties, new Predicate<Property>() {
- @Override
- public boolean apply(Property input) {
- return input.getKey().equals(key);
- }
- }, null);
- }
- }
-
- private static class Property {
- String key;
- int value;
- String textValue;
-
- private Property(String key, int value, String textValue) {
- this.key = key;
- this.value = value;
- this.textValue = textValue;
- }
-
- private Property setValue(int value) {
- this.value = value;
- return this;
- }
-
- private Property setTextValue(String textValue) {
- this.textValue = textValue;
- return this;
- }
-
- private String getKey() {
- return key;
- }
-
- private int getValue() {
- return value;
- }
-
- private String getTextValue() {
- return "mn".equals(textValue) ? Duration.MINUTE : textValue;
- }
- }
-
- public static class RuleDebt {
- private RuleKey ruleKey;
- private String characteristicKey;
- private RemediationFunction function;
- private String factor;
- private String offset;
-
- public RuleKey ruleKey() {
- return ruleKey;
- }
-
- public RuleDebt setRuleKey(RuleKey ruleKey) {
- this.ruleKey = ruleKey;
- return this;
- }
-
- public String characteristicKey() {
- return characteristicKey;
- }
-
- public RuleDebt setCharacteristicKey(String characteristicKey) {
- this.characteristicKey = characteristicKey;
- return this;
- }
-
- public RemediationFunction function() {
- return function;
- }
-
- public RuleDebt setFunction(RemediationFunction function) {
- this.function = function;
- return this;
- }
-
- public String factor() {
- return factor;
- }
-
- public RuleDebt setFactor(String factor) {
- this.factor = factor;
- return this;
- }
-
- public String offset() {
- return offset;
- }
-
- public RuleDebt setOffset(String offset) {
- this.offset = offset;
- return this;
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-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.rules.Rule;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.debt.db.CharacteristicDao;
-import org.sonar.core.debt.db.CharacteristicDto;
-import org.sonar.core.persistence.MyBatis;
-
-import javax.annotation.CheckForNull;
-
-import java.io.Reader;
-import java.util.Collection;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-public class TechnicalDebtModelSynchronizer implements ServerExtension {
-
- private static final Logger LOG = LoggerFactory.getLogger(TechnicalDebtModelSynchronizer.class);
-
- private final MyBatis mybatis;
- private final CharacteristicDao dao;
- private final DebtModelPluginRepository languageModelFinder;
- private final TechnicalDebtXMLImporter importer;
-
- public TechnicalDebtModelSynchronizer(MyBatis mybatis, CharacteristicDao dao,
- DebtModelPluginRepository modelRepository, TechnicalDebtXMLImporter importer) {
- this.mybatis = mybatis;
- this.dao = dao;
- this.languageModelFinder = modelRepository;
- this.importer = importer;
- }
-
- public List<CharacteristicDto> synchronize(ValidationMessages messages, TechnicalDebtRuleCache rulesCache) {
- SqlSession session = mybatis.openSession();
-
- List<CharacteristicDto> model = newArrayList();
- try {
- model = synchronize(messages, rulesCache, session);
- session.commit();
- } finally {
- MyBatis.closeQuietly(session);
- }
- return model;
- }
-
- public List<CharacteristicDto> synchronize(ValidationMessages messages, TechnicalDebtRuleCache rulesCache, SqlSession session) {
- DefaultTechnicalDebtModel defaultModel = loadModelFromXml(DebtModelPluginRepository.DEFAULT_MODEL, messages, rulesCache);
- List<CharacteristicDto> model = loadOrCreateModelFromDb(defaultModel, session);
- disableRequirementsOnRemovedRules(model, rulesCache, session);
- mergePlugins(model, defaultModel, messages, rulesCache, session);
- messages.log(LOG);
-
- return model;
- }
-
- private List<CharacteristicDto> loadOrCreateModelFromDb(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
- List<CharacteristicDto> characteristicDtos = loadModel();
- if (characteristicDtos.isEmpty()) {
- return createTechnicalDebtModel(defaultModel, session);
- }
- return characteristicDtos;
- }
-
- private List<CharacteristicDto> loadModel() {
- return dao.selectEnabledCharacteristics();
- }
-
- private List<CharacteristicDto> createTechnicalDebtModel(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
- List<CharacteristicDto> characteristics = newArrayList();
- for (DefaultCharacteristic rootCharacteristic : defaultModel.rootCharacteristics()) {
- CharacteristicDto rootCharacteristicDto = CharacteristicDto.toDto(rootCharacteristic, null);
- dao.insert(rootCharacteristicDto, session);
- characteristics.add(rootCharacteristicDto);
- for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
- CharacteristicDto characteristicDto = CharacteristicDto.toDto(characteristic, rootCharacteristicDto.getId());
- dao.insert(characteristicDto, session);
- characteristics.add(characteristicDto);
- }
- }
- return characteristics;
- }
-
- private void mergePlugins(List<CharacteristicDto> existingModel, DefaultTechnicalDebtModel defaultModel, ValidationMessages messages, TechnicalDebtRuleCache rulesCache,
- SqlSession session) {
- for (String pluginKey : getContributingPluginListWithoutSqale()) {
- DefaultTechnicalDebtModel pluginModel = loadModelFromXml(pluginKey, messages, rulesCache);
- checkPluginDoNotAddNewCharacteristic(pluginModel, defaultModel);
- mergePlugin(pluginModel, existingModel, messages, rulesCache, session);
- }
- }
-
- private void mergePlugin(DefaultTechnicalDebtModel pluginModel, List<CharacteristicDto> existingModel, ValidationMessages messages, TechnicalDebtRuleCache rulesCache,
- SqlSession session) {
- if (!messages.hasErrors()) {
- for (DefaultRequirement pluginRequirement : pluginModel.requirements()) {
- Rule rule = rulesCache.getByRuleKey(pluginRequirement.ruleKey());
- if (!isRequirementExists(existingModel, rule)) {
- CharacteristicDto characteristicDto = findCharacteristic(existingModel, pluginRequirement.characteristic().key());
- if (characteristicDto != null) {
- Integer rootId = characteristicDto.getRootId();
- if (rootId == null) {
- throw new IllegalArgumentException("Requirement on rule '" + pluginRequirement.ruleKey() + "' should not be linked on a root characteristic.");
- }
- CharacteristicDto requirementDto = CharacteristicDto.toDto(pluginRequirement, characteristicDto.getId(), rootId, rule.getId());
- dao.insert(requirementDto, session);
- }
- }
- }
- }
- }
-
- public DefaultTechnicalDebtModel loadModelFromXml(String pluginKey, ValidationMessages messages, TechnicalDebtRuleCache rulesCache) {
- Reader xmlFileReader = null;
- try {
- xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
- return importer.importXML(xmlFileReader, messages, rulesCache);
- } finally {
- IOUtils.closeQuietly(xmlFileReader);
- }
- }
-
- private void checkPluginDoNotAddNewCharacteristic(DefaultTechnicalDebtModel pluginModel, DefaultTechnicalDebtModel defaultModel) {
- List<DefaultCharacteristic> characteristics = defaultModel.characteristics();
- for (DefaultCharacteristic characteristic : pluginModel.characteristics()) {
- if (!characteristics.contains(characteristic)) {
- throw new IllegalArgumentException("The characteristic : " + characteristic.key() + " cannot be used as it's not available in default characteristics.");
- }
- }
- }
-
- private void disableRequirementsOnRemovedRules(List<CharacteristicDto> existingModel, TechnicalDebtRuleCache rulesCache, SqlSession session) {
- for (CharacteristicDto characteristicDto : existingModel) {
- Integer ruleId = characteristicDto.getRuleId();
- if (ruleId != null && !rulesCache.exists(ruleId)) {
- dao.disable(characteristicDto.getId(), session);
- }
- }
- }
-
- private Collection<String> getContributingPluginListWithoutSqale() {
- Collection<String> pluginList = newArrayList(languageModelFinder.getContributingPluginList());
- pluginList.remove(DebtModelPluginRepository.DEFAULT_MODEL);
- return pluginList;
- }
-
- @CheckForNull
- private CharacteristicDto findCharacteristic(List<CharacteristicDto> existingModel, final String key) {
- return Iterables.find(existingModel, new Predicate<CharacteristicDto>() {
- @Override
- public boolean apply(CharacteristicDto input) {
- String characteristicKey = input.getKey();
- return input.getRuleId() == null && characteristicKey != null && characteristicKey.equals(key);
- }
- }, null);
- }
-
- private boolean isRequirementExists(List<CharacteristicDto> existingModel, final Rule rule) {
- return Iterables.any(existingModel, new Predicate<CharacteristicDto>() {
- @Override
- public boolean apply(CharacteristicDto input) {
- Integer ruleId = input.getRuleId();
- return ruleId != null && ruleId.equals(rule.getId());
- }
- });
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import com.google.common.collect.Maps;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.rules.RuleQuery;
-
-import javax.annotation.CheckForNull;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-public class TechnicalDebtRuleCache {
-
- private final RuleFinder ruleFinder;
-
- private Map<String, Map<String, Rule>> cachedRules;
- private Map<Integer, Rule> cachedRulesId;
-
- public TechnicalDebtRuleCache(RuleFinder ruleFinder) {
- this.ruleFinder = ruleFinder;
- }
-
- @CheckForNull
- public Rule getByRuleKey(RuleKey ruleKey) {
- initRules();
- return lookUpRuleInCache(ruleKey.repository(), ruleKey.rule());
- }
-
- @CheckForNull
- public Rule getByRuleId(Integer ruleId) {
- initRules();
- return cachedRulesId.get(ruleId);
- }
-
- public boolean exists(Integer ruleId) {
- initRules();
- return getByRuleId(ruleId) != null;
- }
-
- public boolean exists(RuleKey ruleKey) {
- return getByRuleKey(ruleKey) != null;
- }
-
- private void initRules(){
- if(cachedRules == null) {
- loadRules();
- }
- }
-
- private void loadRules() {
- cachedRules = Maps.newHashMap();
- cachedRulesId = Maps.newHashMap();
- Collection<Rule> rules = ruleFinder.findAll(RuleQuery.create());
- for (Rule rule : rules) {
- if(!cachedRules.containsKey(rule.getRepositoryKey())) {
- cachedRules.put(rule.getRepositoryKey(), new HashMap<String, Rule>());
- }
- Map<String, Rule> cachedRepository = cachedRules.get(rule.getRepositoryKey());
- if(!cachedRepository.containsKey(rule.getKey())) {
- cachedRepository.put(rule.getKey(), rule);
- cachedRulesId.put(rule.getId(), rule);
- }
- }
- }
-
- @CheckForNull
- private Rule lookUpRuleInCache(String repository, String ruleKey) {
- Map<String, Rule> cachedRepository = cachedRules.get(repository);
- if(cachedRepository != null) {
- return cachedRepository.get(ruleKey);
- }
- return null;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
-import com.google.common.collect.Iterables;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.math.NumberUtils;
-import org.codehaus.stax2.XMLInputFactory2;
-import org.codehaus.staxmate.SMInputFactory;
-import org.codehaus.staxmate.in.SMHierarchicCursor;
-import org.codehaus.staxmate.in.SMInputCursor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.ServerExtension;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.api.utils.internal.WorkDuration;
-import org.sonar.core.debt.db.CharacteristicDto;
-
-import javax.annotation.CheckForNull;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.List;
-
-import static com.google.common.collect.Lists.newArrayList;
-
-public class TechnicalDebtXMLImporter implements ServerExtension {
-
- private static final Logger LOG = LoggerFactory.getLogger(TechnicalDebtXMLImporter.class);
-
- public static final String CHARACTERISTIC = "chc";
- public static final String CHARACTERISTIC_KEY = "key";
- public static final String CHARACTERISTIC_NAME = "name";
- public static final String PROPERTY = "prop";
-
- public static final String PROPERTY_KEY = "key";
- public static final String PROPERTY_VALUE = "val";
- public static final String PROPERTY_TEXT_VALUE = "txt";
-
- public static final String REPOSITORY_KEY = "rule-repo";
- public static final String RULE_KEY = "rule-key";
-
- public static final String PROPERTY_FUNCTION = "remediationFunction";
- public static final String PROPERTY_FACTOR = "remediationFactor";
- public static final String PROPERTY_OFFSET = "offset";
-
- public DefaultTechnicalDebtModel importXML(String xml, ValidationMessages messages, TechnicalDebtRuleCache technicalDebtRuleCache) {
- return importXML(new StringReader(xml), messages, technicalDebtRuleCache);
- }
-
- public DefaultTechnicalDebtModel importXML(Reader xml, ValidationMessages messages, TechnicalDebtRuleCache repositoryCache) {
- DefaultTechnicalDebtModel model = new DefaultTechnicalDebtModel();
- try {
- SMInputFactory inputFactory = initStax();
- SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
-
- // advance to <sqale>
- cursor.advance();
- SMInputCursor chcCursor = cursor.childElementCursor(CHARACTERISTIC);
-
- while (chcCursor.getNext() != null) {
- processCharacteristic(model, null, chcCursor, messages, repositoryCache);
- }
-
- cursor.getStreamReader().closeCompletely();
-
- } catch (XMLStreamException e) {
- LOG.error("XML is not valid", e);
- messages.addErrorText("XML is not valid: " + e.getMessage());
- }
- return model;
- }
-
- private SMInputFactory initStax() {
- XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
- xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
- xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
- xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
- xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
- return new SMInputFactory(xmlFactory);
- }
-
- private DefaultCharacteristic processCharacteristic(DefaultTechnicalDebtModel model, DefaultCharacteristic parent, SMInputCursor chcCursor, ValidationMessages messages,
- TechnicalDebtRuleCache technicalDebtRuleCache) throws XMLStreamException {
- DefaultCharacteristic characteristic = new DefaultCharacteristic();
- SMInputCursor cursor = chcCursor.childElementCursor();
- while (cursor.getNext() != null) {
- String node = cursor.getLocalName();
- if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
- 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);
-
- } else if (StringUtils.equals(node, CHARACTERISTIC_NAME)) {
- characteristic.setName(cursor.collectDescendantText().trim(), false);
-
- // <chc> can contain characteristics or requirements
- } else if (StringUtils.equals(node, CHARACTERISTIC)) {
- processCharacteristic(model, characteristic, cursor, messages, technicalDebtRuleCache);
-
- } else if (StringUtils.equals(node, REPOSITORY_KEY)) {
- DefaultRequirement requirement = processRequirement(cursor, messages, technicalDebtRuleCache);
- if (requirement != null) {
- addRequirement(requirement, parent, messages);
- }
- }
- }
-
- if (StringUtils.isNotBlank(characteristic.key()) && characteristic.isRoot()) {
- characteristic.setOrder(model.rootCharacteristics().size() + 1);
- model.addRootCharacteristic(characteristic);
- return characteristic;
- }
- return null;
- }
-
- private void addRequirement(DefaultRequirement requirement, DefaultCharacteristic parent, ValidationMessages messages) {
- DefaultCharacteristic root = parent.parent();
- if (root == null) {
- messages.addWarningText("Requirement '" + requirement.ruleKey() + "' is ignored because it's defined directly under a root characteristic.");
- } else {
- requirement.setCharacteristic(parent);
- requirement.setRootCharacteristic(root);
- }
- }
-
- private DefaultRequirement processRequirement(SMInputCursor cursor, ValidationMessages messages, TechnicalDebtRuleCache technicalDebtRuleCache)
- throws XMLStreamException {
-
- DefaultRequirement requirement = new DefaultRequirement();
- String ruleRepositoryKey = cursor.collectDescendantText().trim();
- String ruleKey = null;
- Properties properties = new Properties();
- while (cursor.getNext() != null) {
- String node = cursor.getLocalName();
- if (StringUtils.equals(node, PROPERTY)) {
- properties.add(processProperty(cursor, messages));
- } else if (StringUtils.equals(node, RULE_KEY)) {
- ruleKey = cursor.collectDescendantText().trim();
- }
- }
- fillRule(requirement, ruleRepositoryKey, ruleKey, messages, technicalDebtRuleCache);
- if (requirement.ruleKey() == null) {
- return null;
- }
- return processFunctionsOnRequirement(requirement, properties, messages);
- }
-
- private void fillRule(DefaultRequirement requirement, String ruleRepositoryKey, String ruleKey, ValidationMessages messages,
- TechnicalDebtRuleCache technicalDebtRuleCache) {
- if (StringUtils.isNotBlank(ruleRepositoryKey) && StringUtils.isNotBlank(ruleKey)) {
- Rule rule = technicalDebtRuleCache.getByRuleKey(RuleKey.of(ruleRepositoryKey, ruleKey));
- if (rule != null) {
- requirement.setRuleKey(RuleKey.of(ruleRepositoryKey, ruleKey));
- } else {
- messages.addWarningText("Rule not found: [repository=" + ruleRepositoryKey + ", key=" + ruleKey + "]");
- }
- }
- }
-
- private Property processProperty(SMInputCursor cursor, ValidationMessages messages) throws XMLStreamException {
- SMInputCursor c = cursor.childElementCursor();
- String key = null;
- int value = 0;
- String textValue = null;
- while (c.getNext() != null) {
- String node = c.getLocalName();
- if (StringUtils.equals(node, PROPERTY_KEY)) {
- key = c.collectDescendantText().trim();
-
- } else if (StringUtils.equals(node, PROPERTY_VALUE)) {
- String s = c.collectDescendantText().trim();
- try {
- // The value is still a double for the moment
- Double valueDouble = NumberUtils.createDouble(s);
- value = valueDouble.intValue();
- } catch (NumberFormatException ex) {
- messages.addErrorText(String.format("Cannot import value '%s' for field %s - Expected a numeric value instead", s, key));
- }
- } else if (StringUtils.equals(node, PROPERTY_TEXT_VALUE)) {
- textValue = c.collectDescendantText().trim();
- }
- }
- return new Property(key, value, textValue);
- }
-
- @CheckForNull
- private DefaultRequirement processFunctionsOnRequirement(DefaultRequirement requirement, Properties properties, ValidationMessages messages) {
- Property function = properties.function();
- Property factor = properties.factor();
- Property offset = properties.offset();
-
- if (function != null) {
- // Requirements should always have values, so we init it with default values
- requirement.setFactorValue(0);
- requirement.setFactorUnit(WorkDuration.UNIT.DAYS);
- requirement.setOffsetValue(0);
- requirement.setOffsetUnit(WorkDuration.UNIT.DAYS);
-
- String functionKey = function.getTextValue();
- if ("linear_threshold".equals(functionKey)) {
- function.setTextValue(DefaultRequirement.FUNCTION_LINEAR);
- offset.setValue(0);
- offset.setTextValue(CharacteristicDto.DAYS);
- messages.addWarningText(String.format("Linear with threshold function is no longer used, function of the requirement '%s' is replaced by linear.", requirement.ruleKey()));
- } else if ("constant_resource".equals(functionKey)) {
- messages.addWarningText(String.format("Constant/file function is no longer used, requirements '%s' are ignored.", requirement.ruleKey()));
- return null;
- }
-
- requirement.setFunction(function.getTextValue());
- if (factor != null) {
- requirement.setFactorValue(factor.getValue());
- if (!Strings.isNullOrEmpty(factor.getTextValue())) {
- requirement.setFactorUnit(DefaultRequirement.toUnit(factor.getTextValue()));
- }
- }
- if (offset != null) {
- requirement.setOffsetValue(offset.getValue());
- if (!Strings.isNullOrEmpty(offset.getTextValue())) {
- requirement.setOffsetUnit(DefaultRequirement.toUnit(offset.getTextValue()));
- }
- }
- return requirement;
- }
- return null;
- }
-
- private static class Properties {
- List<Property> properties;
-
- public Properties() {
- this.properties = newArrayList();
- }
-
- public Properties add(Property property) {
- this.properties.add(property);
- return this;
- }
-
- public Property function() {
- return find(PROPERTY_FUNCTION);
- }
-
- public Property factor() {
- return find(PROPERTY_FACTOR);
- }
-
- public Property offset() {
- return find(PROPERTY_OFFSET);
- }
-
- private Property find(final String key) {
- return Iterables.find(properties, new Predicate<Property>() {
- @Override
- public boolean apply(Property input) {
- return input.getKey().equals(key);
- }
- }, null);
- }
-
- }
-
- private static class Property {
- String key;
- int value;
- String textValue;
-
- private Property(String key, int value, String textValue) {
- this.key = key;
- this.value = value;
- this.textValue = textValue;
- }
-
- private Property setValue(int value) {
- this.value = value;
- return this;
- }
-
- private Property setTextValue(String textValue) {
- this.textValue = textValue;
- return this;
- }
-
- private String getKey() {
- return key;
- }
-
- private int getValue() {
- return value;
- }
-
- private String getTextValue() {
- return textValue;
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt.db;
-
-import org.apache.ibatis.session.SqlSession;
-import org.sonar.api.BatchComponent;
-import org.sonar.api.ServerComponent;
-import org.sonar.core.persistence.MyBatis;
-
-import javax.annotation.CheckForNull;
-
-import java.util.List;
-
-public class CharacteristicDao implements BatchComponent, ServerComponent {
-
- private final MyBatis mybatis;
-
- public CharacteristicDao(MyBatis mybatis) {
- this.mybatis = mybatis;
- }
-
- /**
- * @return enabled root characteristics, characteristics and requirements
- *
- * @deprecated since 4.3
- */
- @Deprecated
- public List<CharacteristicDto> selectEnabledCharacteristics() {
- SqlSession session = mybatis.openSession();
- try {
- return session.getMapper(CharacteristicMapper.class).selectEnabledCharacteristics();
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
- /**
- * @return enabled root characteristics, and characteristics
- *
- */
- public List<CharacteristicDto> selectCharacteristics() {
- SqlSession session = mybatis.openSession();
- try {
- return selectCharacteristics(session);
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
- public List<CharacteristicDto> selectCharacteristics(SqlSession session) {
- return session.getMapper(CharacteristicMapper.class).selectCharacteristics();
- }
-
- /**
- * @return only enabled root characteristics, order by order
- */
- public List<CharacteristicDto> selectEnabledRootCharacteristics() {
- SqlSession session = mybatis.openSession();
- CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
- try {
- return mapper.selectEnabledRootCharacteristics();
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
- @CheckForNull
- public CharacteristicDto selectByKey(String key) {
- SqlSession session = mybatis.openSession();
- CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
- try {
- return mapper.selectByKey(key);
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
- @CheckForNull
- public CharacteristicDto selectById(int id) {
- SqlSession session = mybatis.openSession();
- CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
- try {
- return mapper.selectById(id);
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
- @CheckForNull
- public CharacteristicDto selectByRuleId(Integer ruleId) {
- SqlSession session = mybatis.openSession();
- CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
- try {
- return mapper.selectByRuleId(ruleId);
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
- public void insert(CharacteristicDto dto, SqlSession session) {
- session.getMapper(CharacteristicMapper.class).insert(dto);
- }
-
- public void insert(CharacteristicDto dto) {
- SqlSession session = mybatis.openSession();
- try {
- insert(dto, session);
- session.commit();
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
- public void update(CharacteristicDto dto, SqlSession session) {
- session.getMapper(CharacteristicMapper.class).update(dto);
- }
-
- public void update(CharacteristicDto dto) {
- SqlSession session = mybatis.openSession();
- try {
- update(dto, session);
- session.commit();
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
- public void disable(Integer id, SqlSession session) {
- session.getMapper(CharacteristicMapper.class).disable(id);
- }
-
- public void disable(Integer id) {
- SqlSession session = mybatis.openSession();
- try {
- disable(id, session);
- session.commit();
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt.db;
-
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.internal.WorkDuration;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.io.Serializable;
-import java.util.Date;
-
-public class CharacteristicDto implements Serializable {
-
- public static final String DAYS = "d";
- public static final String MINUTES = "mn";
- public static final String HOURS = "h";
-
- private Integer id;
- private String kee;
- private String name;
- private Integer parentId;
- private Integer rootId;
- private Integer characteristicOrder;
- private Integer ruleId;
- private String functionKey;
- private Double factorValue;
- private String factorUnit;
- private Double offsetValue;
- private String offsetUnit;
- private Date createdAt;
- private Date updatedAt;
- private boolean enabled;
-
- public Integer getId() {
- return id;
- }
-
- public CharacteristicDto setId(Integer id) {
- this.id = id;
- return this;
- }
-
- @CheckForNull
- public String getKey() {
- return kee;
- }
-
- public CharacteristicDto setKey(@Nullable String s) {
- this.kee = s;
- return this;
- }
-
- @CheckForNull
- public String getName() {
- return name;
- }
-
- public CharacteristicDto setName(@Nullable String s) {
- this.name = s;
- return this;
- }
-
- @CheckForNull
- public Integer getParentId() {
- return parentId;
- }
-
- public CharacteristicDto setParentId(@Nullable Integer i) {
- this.parentId = i;
- return this;
- }
-
- @CheckForNull
- public Integer getRootId() {
- return rootId;
- }
-
- public CharacteristicDto setRootId(@Nullable Integer rootId) {
- this.rootId = rootId;
- return this;
- }
-
- @CheckForNull
- public Integer getOrder() {
- return characteristicOrder;
- }
-
- public CharacteristicDto setOrder(@Nullable Integer i) {
- this.characteristicOrder = i;
- return this;
- }
-
- @CheckForNull
- public Integer getRuleId() {
- return ruleId;
- }
-
- public CharacteristicDto setRuleId(@Nullable Integer ruleId) {
- this.ruleId = ruleId;
- return this;
- }
-
- @CheckForNull
- public String getFunction() {
- return functionKey;
- }
-
- public CharacteristicDto setFunction(@Nullable String function) {
- this.functionKey = function;
- return this;
- }
-
- @CheckForNull
- public Double getFactorValue() {
- return factorValue;
- }
-
- public CharacteristicDto setFactorValue(Double factor) {
- this.factorValue = factor;
- return this;
- }
-
- @CheckForNull
- public String getFactorUnit() {
- return factorUnit;
- }
-
- public CharacteristicDto setFactorUnit(@Nullable String factorUnit) {
- this.factorUnit = factorUnit;
- return this;
- }
-
- @CheckForNull
- public Double getOffsetValue() {
- return offsetValue;
- }
-
- public CharacteristicDto setOffsetValue(@Nullable Double offset) {
- this.offsetValue = offset;
- return this;
- }
-
- @CheckForNull
- public String getOffsetUnit() {
- return offsetUnit;
- }
-
- public CharacteristicDto setOffsetUnit(@Nullable String offsetUnit) {
- this.offsetUnit = offsetUnit;
- return this;
- }
-
- public Date getCreatedAt() {
- return createdAt;
- }
-
- public CharacteristicDto setCreatedAt(Date createdAt) {
- this.createdAt = createdAt;
- return this;
- }
-
- @CheckForNull
- public Date getUpdatedAt() {
- return updatedAt;
- }
-
- public CharacteristicDto setUpdatedAt(@Nullable Date updatedAt) {
- this.updatedAt = updatedAt;
- return this;
- }
-
- public boolean isEnabled() {
- return enabled;
- }
-
- public CharacteristicDto setEnabled(boolean enabled) {
- this.enabled = enabled;
- return this;
- }
-
- public DefaultCharacteristic toCharacteristic(@Nullable DefaultCharacteristic parent) {
- return new DefaultCharacteristic()
- .setId(id)
- .setKey(kee)
- .setName(name)
- .setOrder(characteristicOrder)
- .setParent(parent)
- .setRoot(parent)
- .setCreatedAt(createdAt)
- .setUpdatedAt(updatedAt);
- }
-
- public static CharacteristicDto toDto(DefaultCharacteristic characteristic, @Nullable Integer parentId) {
- return new CharacteristicDto()
- .setKey(characteristic.key())
- .setName(characteristic.name())
- .setOrder(characteristic.order())
- .setParentId(parentId)
- .setRootId(parentId)
- .setEnabled(true)
- .setCreatedAt(characteristic.createdAt())
- .setUpdatedAt(characteristic.updatedAt());
- }
-
- public DefaultRequirement toRequirement(RuleKey ruleKey, DefaultCharacteristic characteristic, DefaultCharacteristic rootCharacteristic) {
- return new DefaultRequirement()
- .setId(id)
- .setRuleKey(ruleKey)
- .setCharacteristic(characteristic)
- .setRootCharacteristic(rootCharacteristic)
- .setFunction(functionKey)
- .setFactorValue(factorValue.intValue())
- .setFactorUnit(toUnit(factorUnit))
- .setOffsetValue(offsetValue.intValue())
- .setOffsetUnit(toUnit(offsetUnit))
- .setCreatedAt(createdAt)
- .setUpdatedAt(updatedAt);
- }
-
- public static CharacteristicDto toDto(DefaultRequirement requirement, Integer characteristicId, Integer rootCharacteristicId, Integer ruleId) {
- return new CharacteristicDto()
- .setRuleId(ruleId)
- .setParentId(characteristicId)
- .setRootId(rootCharacteristicId)
- .setFunction(requirement.function())
- .setFactorValue((double) requirement.factorValue())
- .setFactorUnit(fromUnit(requirement.factorUnit()))
- .setOffsetValue((double) requirement.offsetValue())
- .setOffsetUnit(fromUnit(requirement.offsetUnit()))
- .setEnabled(true)
- .setCreatedAt(requirement.createdAt())
- .setUpdatedAt(requirement.updatedAt());
- }
-
- private static WorkDuration.UNIT toUnit(@Nullable String requirementUnit) {
- if (requirementUnit != null) {
- if (DAYS.equals(requirementUnit)) {
- return WorkDuration.UNIT.DAYS;
- } else if (HOURS.equals(requirementUnit)) {
- return WorkDuration.UNIT.HOURS;
- } else if (MINUTES.equals(requirementUnit)) {
- return WorkDuration.UNIT.MINUTES;
- }
- throw new IllegalStateException("Invalid unit : " + requirementUnit);
- }
- return null;
- }
-
- private static String fromUnit(@Nullable WorkDuration.UNIT unit) {
- if (unit != null) {
- if (WorkDuration.UNIT.DAYS.equals(unit)) {
- return DAYS;
- } else if (WorkDuration.UNIT.HOURS.equals(unit)) {
- return HOURS;
- } else if (WorkDuration.UNIT.MINUTES.equals(unit)) {
- return MINUTES;
- }
- throw new IllegalStateException("Invalid unit : " + unit);
- }
- return null;
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt.db;
-
-import java.util.List;
-
-public interface CharacteristicMapper {
-
- List<CharacteristicDto> selectEnabledCharacteristics();
-
- List<CharacteristicDto> selectCharacteristics();
-
- List<CharacteristicDto> selectEnabledRootCharacteristics();
-
- CharacteristicDto selectByKey(String key);
-
- CharacteristicDto selectById(int id);
-
- CharacteristicDto selectByRuleId(Integer ruleId);
-
- void insert(CharacteristicDto characteristic);
-
- int update(CharacteristicDto characteristic);
-
- int disable(Integer id);
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.
- */
-
-@ParametersAreNonnullByDefault
-package org.sonar.core.debt.db;
-
-import javax.annotation.ParametersAreNonnullByDefault;
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.core.debt;
-
-import javax.annotation.ParametersAreNonnullByDefault;
import com.google.common.collect.ImmutableList;
import org.sonar.core.dashboard.ActiveDashboardDao;
import org.sonar.core.dashboard.DashboardDao;
-import org.sonar.core.debt.db.CharacteristicDao;
import org.sonar.core.duplication.DuplicationDao;
import org.sonar.core.graph.jdbc.GraphDao;
import org.sonar.core.issue.db.*;
import org.sonar.core.rule.RuleTagDao;
import org.sonar.core.source.db.SnapshotDataDao;
import org.sonar.core.source.db.SnapshotSourceDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.template.LoadedTemplateDao;
import org.sonar.core.user.*;
import org.sonar.core.component.db.ComponentMapper;
import org.sonar.core.config.Logback;
import org.sonar.core.dashboard.*;
-import org.sonar.core.debt.db.CharacteristicDto;
-import org.sonar.core.debt.db.CharacteristicMapper;
import org.sonar.core.dependency.DependencyDto;
import org.sonar.core.dependency.DependencyMapper;
import org.sonar.core.dependency.ResourceSnapshotDto;
import org.sonar.core.source.db.SnapshotDataDto;
import org.sonar.core.source.db.SnapshotDataMapper;
import org.sonar.core.source.db.SnapshotSourceMapper;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+import org.sonar.core.technicaldebt.db.CharacteristicMapper;
import org.sonar.core.template.LoadedTemplateDto;
import org.sonar.core.template.LoadedTemplateMapper;
import org.sonar.core.user.*;
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+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.utils.ValidationMessages;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+
+import java.io.Reader;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class CharacteristicsDebtModelSynchronizer implements ServerExtension {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CharacteristicsDebtModelSynchronizer.class);
+
+ private final MyBatis mybatis;
+ private final CharacteristicDao dao;
+ private final DebtModelPluginRepository languageModelFinder;
+ private final CharacteristicsDebtModelXMLImporter importer;
+
+ public CharacteristicsDebtModelSynchronizer(MyBatis mybatis, CharacteristicDao dao, DebtModelPluginRepository modelRepository, CharacteristicsDebtModelXMLImporter importer) {
+ this.mybatis = mybatis;
+ this.dao = dao;
+ this.languageModelFinder = modelRepository;
+ this.importer = importer;
+ }
+
+ public List<CharacteristicDto> synchronize(ValidationMessages messages) {
+ SqlSession session = mybatis.openSession();
+
+ List<CharacteristicDto> model = newArrayList();
+ try {
+ model = synchronize(messages, session);
+ session.commit();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ return model;
+ }
+
+ public List<CharacteristicDto> synchronize(ValidationMessages messages, SqlSession session) {
+ DefaultTechnicalDebtModel defaultModel = loadModelFromXml(DebtModelPluginRepository.DEFAULT_MODEL, messages);
+ List<CharacteristicDto> model = loadOrCreateModelFromDb(defaultModel, session);
+ messages.log(LOG);
+ return model;
+ }
+
+ private List<CharacteristicDto> loadOrCreateModelFromDb(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
+ List<CharacteristicDto> characteristicDtos = loadModel();
+ if (characteristicDtos.isEmpty()) {
+ return createTechnicalDebtModel(defaultModel, session);
+ }
+ return characteristicDtos;
+ }
+
+ private List<CharacteristicDto> loadModel() {
+ return dao.selectEnabledCharacteristics();
+ }
+
+ private List<CharacteristicDto> createTechnicalDebtModel(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
+ List<CharacteristicDto> characteristics = newArrayList();
+ for (DefaultCharacteristic rootCharacteristic : defaultModel.rootCharacteristics()) {
+ CharacteristicDto rootCharacteristicDto = CharacteristicDto.toDto(rootCharacteristic, null);
+ dao.insert(rootCharacteristicDto, session);
+ characteristics.add(rootCharacteristicDto);
+ for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
+ CharacteristicDto characteristicDto = CharacteristicDto.toDto(characteristic, rootCharacteristicDto.getId());
+ dao.insert(characteristicDto, session);
+ characteristics.add(characteristicDto);
+ }
+ }
+ return characteristics;
+ }
+
+ public DefaultTechnicalDebtModel loadModelFromXml(String pluginKey, ValidationMessages messages) {
+ Reader xmlFileReader = null;
+ try {
+ xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
+ return importer.importXML(xmlFileReader, messages);
+ } finally {
+ IOUtils.closeQuietly(xmlFileReader);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.utils.ValidationMessages;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Reader;
+import java.io.StringReader;
+
+public class CharacteristicsDebtModelXMLImporter implements ServerExtension {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CharacteristicsDebtModelXMLImporter.class);
+
+ public static final String CHARACTERISTIC = "chc";
+ public static final String CHARACTERISTIC_KEY = "key";
+ public static final String CHARACTERISTIC_NAME = "name";
+
+ public DefaultTechnicalDebtModel importXML(String xml, ValidationMessages messages) {
+ return importXML(new StringReader(xml), messages);
+ }
+
+ public DefaultTechnicalDebtModel importXML(Reader xml, ValidationMessages messages) {
+ DefaultTechnicalDebtModel model = new DefaultTechnicalDebtModel();
+ try {
+ SMInputFactory inputFactory = initStax();
+ SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
+
+ // advance to <sqale>
+ cursor.advance();
+ SMInputCursor chcCursor = cursor.childElementCursor(CHARACTERISTIC);
+
+ while (chcCursor.getNext() != null) {
+ processCharacteristic(model, null, chcCursor, messages);
+ }
+
+ cursor.getStreamReader().closeCompletely();
+
+ } catch (XMLStreamException e) {
+ LOG.error("XML is not valid", e);
+ messages.addErrorText("XML is not valid: " + e.getMessage());
+ }
+ return model;
+ }
+
+ private SMInputFactory initStax() {
+ XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
+ xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
+ xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
+ xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
+ xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
+ return new SMInputFactory(xmlFactory);
+ }
+
+ private DefaultCharacteristic processCharacteristic(DefaultTechnicalDebtModel model, DefaultCharacteristic parent, SMInputCursor chcCursor,
+ ValidationMessages messages) throws XMLStreamException {
+ DefaultCharacteristic characteristic = new DefaultCharacteristic();
+ SMInputCursor cursor = chcCursor.childElementCursor();
+ while (cursor.getNext() != null) {
+ String node = cursor.getLocalName();
+ if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
+ 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);
+
+ } else if (StringUtils.equals(node, CHARACTERISTIC_NAME)) {
+ characteristic.setName(cursor.collectDescendantText().trim(), false);
+
+ // <chc> can contain characteristics or requirements
+ } else if (StringUtils.equals(node, CHARACTERISTIC)) {
+ processCharacteristic(model, characteristic, cursor, messages);
+
+ }
+ }
+
+ if (StringUtils.isNotBlank(characteristic.key()) && characteristic.isRoot()) {
+ characteristic.setOrder(model.rootCharacteristics().size() + 1);
+ model.addRootCharacteristic(characteristic);
+ return characteristic;
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Maps;
+import org.picocontainer.Startable;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.platform.PluginMetadata;
+import org.sonar.api.platform.PluginRepository;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+/**
+ * <p>This class is used to find which technical debt model XML files exist in the Sonar instance.</p>
+ * <p>
+ * Those XML files are provided by language plugins that embed their own contribution to the definition of the Technical debt model.
+ * They must be located in the classpath of those language plugins, more specifically in the "com.sonar.sqale" package, and
+ * they must be named "<pluginKey>-model.xml".
+ * </p>
+ */
+public class DebtModelPluginRepository implements ServerExtension, Startable {
+
+ public static final String DEFAULT_MODEL = "technical-debt";
+
+ private static final String XML_FILE_SUFFIX = "-model.xml";
+ private static final String XML_FILE_PREFIX = "com/sonar/sqale/";
+
+ private String xmlFilePrefix;
+
+ private PluginRepository pluginRepository;
+ private Map<String, ClassLoader> contributingPluginKeyToClassLoader;
+
+ public DebtModelPluginRepository(PluginRepository pluginRepository) {
+ this.pluginRepository = pluginRepository;
+ this.xmlFilePrefix = XML_FILE_PREFIX;
+ }
+
+ @VisibleForTesting
+ DebtModelPluginRepository(PluginRepository pluginRepository, String xmlFilePrefix) {
+ this.pluginRepository = pluginRepository;
+ this.xmlFilePrefix = xmlFilePrefix;
+ }
+
+ @VisibleForTesting
+ DebtModelPluginRepository(Map<String, ClassLoader> contributingPluginKeyToClassLoader, String xmlFilePrefix) {
+ this.contributingPluginKeyToClassLoader = contributingPluginKeyToClassLoader;
+ this.xmlFilePrefix = xmlFilePrefix;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void start() {
+ findAvailableXMLFiles();
+ }
+
+ protected void findAvailableXMLFiles() {
+ if (contributingPluginKeyToClassLoader == null) {
+ contributingPluginKeyToClassLoader = Maps.newTreeMap();
+ // Add default model
+ contributingPluginKeyToClassLoader.put(DEFAULT_MODEL, getClass().getClassLoader());
+ for (PluginMetadata metadata : pluginRepository.getMetadata()) {
+ String pluginKey = metadata.getKey();
+ ClassLoader classLoader = pluginRepository.getPlugin(pluginKey).getClass().getClassLoader();
+ if (classLoader.getResource(getXMLFilePath(pluginKey)) != null) {
+ contributingPluginKeyToClassLoader.put(pluginKey, classLoader);
+ }
+ }
+ }
+ contributingPluginKeyToClassLoader = Collections.unmodifiableMap(contributingPluginKeyToClassLoader);
+ }
+
+ @VisibleForTesting
+ String getXMLFilePath(String model) {
+ return xmlFilePrefix + model + XML_FILE_SUFFIX;
+ }
+
+ /**
+ * Returns the list of plugins that can contribute to the technical debt model.
+ *
+ * @return the list of plugin keys
+ */
+ public Collection<String> getContributingPluginList() {
+ return newArrayList(contributingPluginKeyToClassLoader.keySet());
+ }
+
+ /**
+ * Creates a new {@link java.io.Reader} for the XML file that contains the model contributed by the given plugin.
+ *
+ * @param pluginKey the key of the plugin that contributes the XML file
+ * @return the reader, that must be closed once its use is finished.
+ */
+ public Reader createReaderForXMLFile(String pluginKey) {
+ ClassLoader classLoader = contributingPluginKeyToClassLoader.get(pluginKey);
+ String xmlFilePath = getXMLFilePath(pluginKey);
+ return new InputStreamReader(classLoader.getResourceAsStream(xmlFilePath));
+ }
+
+ @VisibleForTesting
+ Map<String, ClassLoader> getContributingPluginKeyToClassLoader(){
+ return contributingPluginKeyToClassLoader;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void stop() {
+ // Nothing to do
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.technicaldebt.server.Characteristic;
+import org.sonar.api.technicaldebt.server.TechnicalDebtManager;
+import org.sonar.api.technicaldebt.server.internal.DefaultCharacteristic;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+/**
+ * TODO This class should be replaced or created by a TechnicalDebtManagerBuilder
+ */
+public class DefaultTechnicalDebtManager implements TechnicalDebtManager {
+
+ private final CharacteristicDao dao;
+ private final RuleFinder ruleFinder;
+
+ public DefaultTechnicalDebtManager(CharacteristicDao dao, RuleFinder ruleFinder) {
+ this.dao = dao;
+ this.ruleFinder = ruleFinder;
+ }
+
+ public List<Characteristic> findRootCharacteristics() {
+ List<CharacteristicDto> dtos = dao.selectEnabledRootCharacteristics();
+ List<Characteristic> characteristics = newArrayList();
+ for (CharacteristicDto dto : dtos) {
+ characteristics.add(toCharacteristic(dto, null));
+ }
+ return characteristics;
+ }
+
+ @CheckForNull
+ public Characteristic findCharacteristicById(Integer id) {
+ CharacteristicDto dto = dao.selectById(id);
+ if (dto != null) {
+ return toCharacteristic(dto, null);
+ }
+ return null;
+ }
+
+ @CheckForNull
+ public Characteristic findRequirementByRuleId(int ruleId) {
+ CharacteristicDto requirementDto = dao.selectByRuleId(ruleId);
+ if (requirementDto != null) {
+ Rule rule = ruleFinder.findById(ruleId);
+ if (rule == null) {
+ throw new IllegalArgumentException(String.format("Rule with id '%s' do not exists.", ruleId));
+ }
+ return toCharacteristic(requirementDto, RuleKey.of(rule.getRepositoryKey(), rule.getKey()));
+ }
+ return null;
+ }
+
+ @CheckForNull
+ public Characteristic findRequirementByRule(Rule rule) {
+ CharacteristicDto requirementDto = dao.selectByRuleId(rule.getId());
+ if (requirementDto != null) {
+ return toCharacteristic(requirementDto, RuleKey.of(rule.getRepositoryKey(), rule.getKey()));
+ }
+ return null;
+ }
+
+ private static Characteristic toCharacteristic(CharacteristicDto dto, @Nullable RuleKey ruleKey) {
+ Double factorValue = dto.getFactorValue();
+ Double offsetValue = dto.getOffsetValue();
+ return new DefaultCharacteristic()
+ .setId(dto.getId())
+ .setKey(dto.getKey())
+ .setName(dto.getName())
+ .setOrder(dto.getOrder())
+ .setParentId(dto.getParentId())
+ .setRootId(dto.getRootId())
+ .setRuleKey(ruleKey)
+ .setFunction(dto.getFunction())
+ .setFactorValue(factorValue != null ? factorValue.intValue() : null)
+ .setFactorUnit(DefaultCharacteristic.toUnit(dto.getFactorUnit()))
+ .setOffsetValue(offsetValue != null ? offsetValue.intValue() : null)
+ .setOffsetUnit(DefaultCharacteristic.toUnit(dto.getOffsetUnit()));
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+
+import javax.annotation.CheckForNull;
+
+import java.util.Collection;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class DefaultTechnicalDebtModel implements TechnicalDebtModel {
+
+ private Collection<DefaultCharacteristic> rootCharacteristics;
+
+ public DefaultTechnicalDebtModel() {
+ rootCharacteristics = newArrayList();
+ }
+
+ public DefaultTechnicalDebtModel 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);
+ }
+
+ @CheckForNull
+ public DefaultCharacteristic characteristicById(final Integer id){
+ return Iterables.find(characteristics(), new Predicate<DefaultCharacteristic>() {
+ @Override
+ public boolean apply(DefaultCharacteristic input) {
+ return input.id().equals(id);
+ }
+ }, null);
+ }
+
+ @CheckForNull
+ public DefaultRequirement requirementsByRule(final RuleKey ruleKey) {
+ return Iterables.find(requirements(), new Predicate<DefaultRequirement>() {
+ @Override
+ public boolean apply(DefaultRequirement input) {
+ return input.ruleKey().equals(ruleKey);
+ }
+ }, null);
+ }
+
+ @CheckForNull
+ public DefaultRequirement requirementsById(final Integer id){
+ return Iterables.find(requirements(), new Predicate<DefaultRequirement>() {
+ @Override
+ public boolean apply(DefaultRequirement input) {
+ return input.id().equals(id);
+ }
+ }, 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 List<DefaultRequirement> requirements() {
+ List<DefaultRequirement> allRequirements = newArrayList();
+ for (DefaultCharacteristic characteristic : characteristics()) {
+ for (DefaultRequirement requirement : characteristic.requirements()) {
+ allRequirements.add(requirement);
+ }
+ }
+ return allRequirements;
+ }
+
+ public boolean isEmpty(){
+ return rootCharacteristics.isEmpty();
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.math.NumberUtils;
+import org.codehaus.stax2.XMLInputFactory2;
+import org.codehaus.staxmate.SMInputFactory;
+import org.codehaus.staxmate.in.SMHierarchicCursor;
+import org.codehaus.staxmate.in.SMInputCursor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.rule.RemediationFunction;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.Duration;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class RulesDebtModelXMLImporter implements ServerExtension {
+
+ private static final Logger LOG = LoggerFactory.getLogger(RulesDebtModelXMLImporter.class);
+
+ public static final String CHARACTERISTIC = "chc";
+ public static final String CHARACTERISTIC_KEY = "key";
+ public static final String PROPERTY = "prop";
+
+ public static final String PROPERTY_KEY = "key";
+ public static final String PROPERTY_VALUE = "val";
+ public static final String PROPERTY_TEXT_VALUE = "txt";
+
+ public static final String REPOSITORY_KEY = "rule-repo";
+ public static final String RULE_KEY = "rule-key";
+
+ public static final String PROPERTY_FUNCTION = "remediationFunction";
+ public static final String PROPERTY_FACTOR = "remediationFactor";
+ public static final String PROPERTY_OFFSET = "offset";
+
+ public List<RuleDebt> importXML(String xml) {
+ return importXML(new StringReader(xml));
+ }
+
+ public List<RuleDebt> importXML(Reader xml) {
+ List<RuleDebt> ruleDebts = newArrayList();
+ try {
+ SMInputFactory inputFactory = initStax();
+ SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
+
+ // advance to <sqale>
+ cursor.advance();
+ SMInputCursor rootCursor = cursor.childElementCursor(CHARACTERISTIC);
+ while (rootCursor.getNext() != null) {
+ processCharacteristic(ruleDebts, null, null, rootCursor);
+ }
+
+ cursor.getStreamReader().closeCompletely();
+ } catch (XMLStreamException e) {
+ LOG.error("XML is not valid", e);
+ }
+
+ return ruleDebts;
+ }
+
+ private SMInputFactory initStax() {
+ XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
+ xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
+ xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
+ xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
+ xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
+ return new SMInputFactory(xmlFactory);
+ }
+
+ private void processCharacteristic(List<RuleDebt> ruleDebts, @Nullable String rootKey, @Nullable String parentKey, SMInputCursor chcCursor) throws XMLStreamException {
+ String currentCharacteristicKey = null;
+ SMInputCursor cursor = chcCursor.childElementCursor();
+ while (cursor.getNext() != null) {
+ String node = cursor.getLocalName();
+ if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
+ currentCharacteristicKey = cursor.collectDescendantText().trim();
+ } else if (StringUtils.equals(node, CHARACTERISTIC)) {
+ processCharacteristic(ruleDebts, parentKey, currentCharacteristicKey, cursor);
+ } else if (StringUtils.equals(node, REPOSITORY_KEY)) {
+ RuleDebt ruleDebt = processRule(cursor);
+ if (ruleDebt != null) {
+ if (rootKey != null) {
+ ruleDebt.characteristicKey = parentKey;
+ ruleDebts.add(ruleDebt);
+ } else {
+ LOG.warn("Rule '" + ruleDebt.ruleKey + "' is ignored because it's defined directly under a root characteristic.");
+ }
+ }
+ }
+ }
+ }
+
+ private RuleDebt processRule(SMInputCursor cursor)
+ throws XMLStreamException {
+
+ RuleDebt ruleDebt = new RuleDebt();
+ String ruleRepositoryKey = cursor.collectDescendantText().trim();
+ String ruleKey = null;
+ Properties properties = new Properties();
+ while (cursor.getNext() != null) {
+ String node = cursor.getLocalName();
+ if (StringUtils.equals(node, PROPERTY)) {
+ properties.add(processProperty(cursor));
+ } else if (StringUtils.equals(node, RULE_KEY)) {
+ ruleKey = cursor.collectDescendantText().trim();
+ }
+ }
+ if (StringUtils.isNotBlank(ruleRepositoryKey) && StringUtils.isNotBlank(ruleKey)) {
+ ruleDebt.ruleKey = RuleKey.of(ruleRepositoryKey, ruleKey);
+ } else {
+ return null;
+ }
+ return processFunctionsOnRequirement(ruleDebt, properties);
+ }
+
+ private Property processProperty(SMInputCursor cursor) throws XMLStreamException {
+ SMInputCursor c = cursor.childElementCursor();
+ String key = null;
+ int value = 0;
+ String textValue = null;
+ while (c.getNext() != null) {
+ String node = c.getLocalName();
+ if (StringUtils.equals(node, PROPERTY_KEY)) {
+ key = c.collectDescendantText().trim();
+
+ } else if (StringUtils.equals(node, PROPERTY_VALUE)) {
+ String s = c.collectDescendantText().trim();
+ try {
+ Double valueDouble = NumberUtils.createDouble(s);
+ value = valueDouble.intValue();
+ } catch (NumberFormatException ex) {
+ LOG.error(String.format("Cannot import value '%s' for field %s - Expected a numeric value instead", s, key));
+ }
+ } else if (StringUtils.equals(node, PROPERTY_TEXT_VALUE)) {
+ textValue = c.collectDescendantText().trim();
+ }
+ }
+ return new Property(key, value, textValue);
+ }
+
+ @CheckForNull
+ private RuleDebt processFunctionsOnRequirement(RuleDebt requirement, Properties properties) {
+ Property function = properties.function();
+ Property factor = properties.factor();
+ Property offset = properties.offset();
+
+ if (function != null) {
+ // Init with default values
+ requirement.factor = "0" + Duration.DAY;
+ requirement.offset = "0" + Duration.DAY;
+
+ String functionKey = function.getTextValue();
+ if ("linear_threshold".equals(functionKey)) {
+ function.setTextValue(RemediationFunction.LINEAR.name().toLowerCase());
+ offset.setValue(0);
+ offset.setTextValue(Duration.DAY);
+ LOG.warn(String.format("Linear with threshold function is no longer used, remediation function of '%s' is replaced by linear.", requirement.ruleKey));
+ } else if ("constant_resource".equals(functionKey)) {
+ LOG.warn(String.format("Constant/file function is no longer used, technical debt definitions on '%s' are ignored.", requirement.ruleKey));
+ return null;
+ }
+
+ requirement.function = RemediationFunction.valueOf(function.getTextValue().toUpperCase());
+ if (factor != null) {
+ requirement.factor = Integer.toString(factor.getValue());
+ requirement.factor += !Strings.isNullOrEmpty(factor.getTextValue()) ? factor.getTextValue() : Duration.DAY;
+ }
+ if (offset != null) {
+ requirement.offset = Integer.toString(offset.getValue());
+ requirement.offset += !Strings.isNullOrEmpty(offset.getTextValue()) ? offset.getTextValue() : Duration.DAY;
+ }
+ return requirement;
+ }
+ return null;
+ }
+
+ private static class Properties {
+ List<Property> properties;
+
+ public Properties() {
+ this.properties = newArrayList();
+ }
+
+ public Properties add(Property property) {
+ this.properties.add(property);
+ return this;
+ }
+
+ public Property function() {
+ return find(PROPERTY_FUNCTION);
+ }
+
+ public Property factor() {
+ return find(PROPERTY_FACTOR);
+ }
+
+ public Property offset() {
+ return find(PROPERTY_OFFSET);
+ }
+
+ private Property find(final String key) {
+ return Iterables.find(properties, new Predicate<Property>() {
+ @Override
+ public boolean apply(Property input) {
+ return input.getKey().equals(key);
+ }
+ }, null);
+ }
+ }
+
+ private static class Property {
+ String key;
+ int value;
+ String textValue;
+
+ private Property(String key, int value, String textValue) {
+ this.key = key;
+ this.value = value;
+ this.textValue = textValue;
+ }
+
+ private Property setValue(int value) {
+ this.value = value;
+ return this;
+ }
+
+ private Property setTextValue(String textValue) {
+ this.textValue = textValue;
+ return this;
+ }
+
+ private String getKey() {
+ return key;
+ }
+
+ private int getValue() {
+ return value;
+ }
+
+ private String getTextValue() {
+ return "mn".equals(textValue) ? Duration.MINUTE : textValue;
+ }
+ }
+
+ public static class RuleDebt {
+ private RuleKey ruleKey;
+ private String characteristicKey;
+ private RemediationFunction function;
+ private String factor;
+ private String offset;
+
+ public RuleKey ruleKey() {
+ return ruleKey;
+ }
+
+ public RuleDebt setRuleKey(RuleKey ruleKey) {
+ this.ruleKey = ruleKey;
+ return this;
+ }
+
+ public String characteristicKey() {
+ return characteristicKey;
+ }
+
+ public RuleDebt setCharacteristicKey(String characteristicKey) {
+ this.characteristicKey = characteristicKey;
+ return this;
+ }
+
+ public RemediationFunction function() {
+ return function;
+ }
+
+ public RuleDebt setFunction(RemediationFunction function) {
+ this.function = function;
+ return this;
+ }
+
+ public String factor() {
+ return factor;
+ }
+
+ public RuleDebt setFactor(String factor) {
+ this.factor = factor;
+ return this;
+ }
+
+ public String offset() {
+ return offset;
+ }
+
+ public RuleDebt setOffset(String offset) {
+ this.offset = offset;
+ return this;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+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.rules.Rule;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+
+import javax.annotation.CheckForNull;
+
+import java.io.Reader;
+import java.util.Collection;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class TechnicalDebtModelSynchronizer implements ServerExtension {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TechnicalDebtModelSynchronizer.class);
+
+ private final MyBatis mybatis;
+ private final CharacteristicDao dao;
+ private final DebtModelPluginRepository languageModelFinder;
+ private final TechnicalDebtXMLImporter importer;
+
+ public TechnicalDebtModelSynchronizer(MyBatis mybatis, CharacteristicDao dao,
+ DebtModelPluginRepository modelRepository, TechnicalDebtXMLImporter importer) {
+ this.mybatis = mybatis;
+ this.dao = dao;
+ this.languageModelFinder = modelRepository;
+ this.importer = importer;
+ }
+
+ public List<CharacteristicDto> synchronize(ValidationMessages messages, TechnicalDebtRuleCache rulesCache) {
+ SqlSession session = mybatis.openSession();
+
+ List<CharacteristicDto> model = newArrayList();
+ try {
+ model = synchronize(messages, rulesCache, session);
+ session.commit();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ return model;
+ }
+
+ public List<CharacteristicDto> synchronize(ValidationMessages messages, TechnicalDebtRuleCache rulesCache, SqlSession session) {
+ DefaultTechnicalDebtModel defaultModel = loadModelFromXml(DebtModelPluginRepository.DEFAULT_MODEL, messages, rulesCache);
+ List<CharacteristicDto> model = loadOrCreateModelFromDb(defaultModel, session);
+ disableRequirementsOnRemovedRules(model, rulesCache, session);
+ mergePlugins(model, defaultModel, messages, rulesCache, session);
+ messages.log(LOG);
+
+ return model;
+ }
+
+ private List<CharacteristicDto> loadOrCreateModelFromDb(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
+ List<CharacteristicDto> characteristicDtos = loadModel();
+ if (characteristicDtos.isEmpty()) {
+ return createTechnicalDebtModel(defaultModel, session);
+ }
+ return characteristicDtos;
+ }
+
+ private List<CharacteristicDto> loadModel() {
+ return dao.selectEnabledCharacteristics();
+ }
+
+ private List<CharacteristicDto> createTechnicalDebtModel(DefaultTechnicalDebtModel defaultModel, SqlSession session) {
+ List<CharacteristicDto> characteristics = newArrayList();
+ for (DefaultCharacteristic rootCharacteristic : defaultModel.rootCharacteristics()) {
+ CharacteristicDto rootCharacteristicDto = CharacteristicDto.toDto(rootCharacteristic, null);
+ dao.insert(rootCharacteristicDto, session);
+ characteristics.add(rootCharacteristicDto);
+ for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
+ CharacteristicDto characteristicDto = CharacteristicDto.toDto(characteristic, rootCharacteristicDto.getId());
+ dao.insert(characteristicDto, session);
+ characteristics.add(characteristicDto);
+ }
+ }
+ return characteristics;
+ }
+
+ private void mergePlugins(List<CharacteristicDto> existingModel, DefaultTechnicalDebtModel defaultModel, ValidationMessages messages, TechnicalDebtRuleCache rulesCache,
+ SqlSession session) {
+ for (String pluginKey : getContributingPluginListWithoutSqale()) {
+ DefaultTechnicalDebtModel pluginModel = loadModelFromXml(pluginKey, messages, rulesCache);
+ checkPluginDoNotAddNewCharacteristic(pluginModel, defaultModel);
+ mergePlugin(pluginModel, existingModel, messages, rulesCache, session);
+ }
+ }
+
+ private void mergePlugin(DefaultTechnicalDebtModel pluginModel, List<CharacteristicDto> existingModel, ValidationMessages messages, TechnicalDebtRuleCache rulesCache,
+ SqlSession session) {
+ if (!messages.hasErrors()) {
+ for (DefaultRequirement pluginRequirement : pluginModel.requirements()) {
+ Rule rule = rulesCache.getByRuleKey(pluginRequirement.ruleKey());
+ if (!isRequirementExists(existingModel, rule)) {
+ CharacteristicDto characteristicDto = findCharacteristic(existingModel, pluginRequirement.characteristic().key());
+ if (characteristicDto != null) {
+ Integer rootId = characteristicDto.getRootId();
+ if (rootId == null) {
+ throw new IllegalArgumentException("Requirement on rule '" + pluginRequirement.ruleKey() + "' should not be linked on a root characteristic.");
+ }
+ CharacteristicDto requirementDto = CharacteristicDto.toDto(pluginRequirement, characteristicDto.getId(), rootId, rule.getId());
+ dao.insert(requirementDto, session);
+ }
+ }
+ }
+ }
+ }
+
+ public DefaultTechnicalDebtModel loadModelFromXml(String pluginKey, ValidationMessages messages, TechnicalDebtRuleCache rulesCache) {
+ Reader xmlFileReader = null;
+ try {
+ xmlFileReader = languageModelFinder.createReaderForXMLFile(pluginKey);
+ return importer.importXML(xmlFileReader, messages, rulesCache);
+ } finally {
+ IOUtils.closeQuietly(xmlFileReader);
+ }
+ }
+
+ private void checkPluginDoNotAddNewCharacteristic(DefaultTechnicalDebtModel pluginModel, DefaultTechnicalDebtModel defaultModel) {
+ List<DefaultCharacteristic> characteristics = defaultModel.characteristics();
+ for (DefaultCharacteristic characteristic : pluginModel.characteristics()) {
+ if (!characteristics.contains(characteristic)) {
+ throw new IllegalArgumentException("The characteristic : " + characteristic.key() + " cannot be used as it's not available in default characteristics.");
+ }
+ }
+ }
+
+ private void disableRequirementsOnRemovedRules(List<CharacteristicDto> existingModel, TechnicalDebtRuleCache rulesCache, SqlSession session) {
+ for (CharacteristicDto characteristicDto : existingModel) {
+ Integer ruleId = characteristicDto.getRuleId();
+ if (ruleId != null && !rulesCache.exists(ruleId)) {
+ dao.disable(characteristicDto.getId(), session);
+ }
+ }
+ }
+
+ private Collection<String> getContributingPluginListWithoutSqale() {
+ Collection<String> pluginList = newArrayList(languageModelFinder.getContributingPluginList());
+ pluginList.remove(DebtModelPluginRepository.DEFAULT_MODEL);
+ return pluginList;
+ }
+
+ @CheckForNull
+ private CharacteristicDto findCharacteristic(List<CharacteristicDto> existingModel, final String key) {
+ return Iterables.find(existingModel, new Predicate<CharacteristicDto>() {
+ @Override
+ public boolean apply(CharacteristicDto input) {
+ String characteristicKey = input.getKey();
+ return input.getRuleId() == null && characteristicKey != null && characteristicKey.equals(key);
+ }
+ }, null);
+ }
+
+ private boolean isRequirementExists(List<CharacteristicDto> existingModel, final Rule rule) {
+ return Iterables.any(existingModel, new Predicate<CharacteristicDto>() {
+ @Override
+ public boolean apply(CharacteristicDto input) {
+ Integer ruleId = input.getRuleId();
+ return ruleId != null && ruleId.equals(rule.getId());
+ }
+ });
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import com.google.common.collect.Maps;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.RuleQuery;
+
+import javax.annotation.CheckForNull;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public class TechnicalDebtRuleCache {
+
+ private final RuleFinder ruleFinder;
+
+ private Map<String, Map<String, Rule>> cachedRules;
+ private Map<Integer, Rule> cachedRulesId;
+
+ public TechnicalDebtRuleCache(RuleFinder ruleFinder) {
+ this.ruleFinder = ruleFinder;
+ }
+
+ @CheckForNull
+ public Rule getByRuleKey(RuleKey ruleKey) {
+ initRules();
+ return lookUpRuleInCache(ruleKey.repository(), ruleKey.rule());
+ }
+
+ @CheckForNull
+ public Rule getByRuleId(Integer ruleId) {
+ initRules();
+ return cachedRulesId.get(ruleId);
+ }
+
+ public boolean exists(Integer ruleId) {
+ initRules();
+ return getByRuleId(ruleId) != null;
+ }
+
+ public boolean exists(RuleKey ruleKey) {
+ return getByRuleKey(ruleKey) != null;
+ }
+
+ private void initRules(){
+ if(cachedRules == null) {
+ loadRules();
+ }
+ }
+
+ private void loadRules() {
+ cachedRules = Maps.newHashMap();
+ cachedRulesId = Maps.newHashMap();
+ Collection<Rule> rules = ruleFinder.findAll(RuleQuery.create());
+ for (Rule rule : rules) {
+ if(!cachedRules.containsKey(rule.getRepositoryKey())) {
+ cachedRules.put(rule.getRepositoryKey(), new HashMap<String, Rule>());
+ }
+ Map<String, Rule> cachedRepository = cachedRules.get(rule.getRepositoryKey());
+ if(!cachedRepository.containsKey(rule.getKey())) {
+ cachedRepository.put(rule.getKey(), rule);
+ cachedRulesId.put(rule.getId(), rule);
+ }
+ }
+ }
+
+ @CheckForNull
+ private Rule lookUpRuleInCache(String repository, String ruleKey) {
+ Map<String, Rule> cachedRepository = cachedRules.get(repository);
+ if(cachedRepository != null) {
+ return cachedRepository.get(ruleKey);
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.math.NumberUtils;
+import org.codehaus.stax2.XMLInputFactory2;
+import org.codehaus.staxmate.SMInputFactory;
+import org.codehaus.staxmate.in.SMHierarchicCursor;
+import org.codehaus.staxmate.in.SMInputCursor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.ServerExtension;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.api.utils.internal.WorkDuration;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+
+import javax.annotation.CheckForNull;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class TechnicalDebtXMLImporter implements ServerExtension {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TechnicalDebtXMLImporter.class);
+
+ public static final String CHARACTERISTIC = "chc";
+ public static final String CHARACTERISTIC_KEY = "key";
+ public static final String CHARACTERISTIC_NAME = "name";
+ public static final String PROPERTY = "prop";
+
+ public static final String PROPERTY_KEY = "key";
+ public static final String PROPERTY_VALUE = "val";
+ public static final String PROPERTY_TEXT_VALUE = "txt";
+
+ public static final String REPOSITORY_KEY = "rule-repo";
+ public static final String RULE_KEY = "rule-key";
+
+ public static final String PROPERTY_FUNCTION = "remediationFunction";
+ public static final String PROPERTY_FACTOR = "remediationFactor";
+ public static final String PROPERTY_OFFSET = "offset";
+
+ public DefaultTechnicalDebtModel importXML(String xml, ValidationMessages messages, TechnicalDebtRuleCache technicalDebtRuleCache) {
+ return importXML(new StringReader(xml), messages, technicalDebtRuleCache);
+ }
+
+ public DefaultTechnicalDebtModel importXML(Reader xml, ValidationMessages messages, TechnicalDebtRuleCache repositoryCache) {
+ DefaultTechnicalDebtModel model = new DefaultTechnicalDebtModel();
+ try {
+ SMInputFactory inputFactory = initStax();
+ SMHierarchicCursor cursor = inputFactory.rootElementCursor(xml);
+
+ // advance to <sqale>
+ cursor.advance();
+ SMInputCursor chcCursor = cursor.childElementCursor(CHARACTERISTIC);
+
+ while (chcCursor.getNext() != null) {
+ processCharacteristic(model, null, chcCursor, messages, repositoryCache);
+ }
+
+ cursor.getStreamReader().closeCompletely();
+
+ } catch (XMLStreamException e) {
+ LOG.error("XML is not valid", e);
+ messages.addErrorText("XML is not valid: " + e.getMessage());
+ }
+ return model;
+ }
+
+ private SMInputFactory initStax() {
+ XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
+ xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
+ xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
+ xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
+ xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
+ return new SMInputFactory(xmlFactory);
+ }
+
+ private DefaultCharacteristic processCharacteristic(DefaultTechnicalDebtModel model, DefaultCharacteristic parent, SMInputCursor chcCursor, ValidationMessages messages,
+ TechnicalDebtRuleCache technicalDebtRuleCache) throws XMLStreamException {
+ DefaultCharacteristic characteristic = new DefaultCharacteristic();
+ SMInputCursor cursor = chcCursor.childElementCursor();
+ while (cursor.getNext() != null) {
+ String node = cursor.getLocalName();
+ if (StringUtils.equals(node, CHARACTERISTIC_KEY)) {
+ 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);
+
+ } else if (StringUtils.equals(node, CHARACTERISTIC_NAME)) {
+ characteristic.setName(cursor.collectDescendantText().trim(), false);
+
+ // <chc> can contain characteristics or requirements
+ } else if (StringUtils.equals(node, CHARACTERISTIC)) {
+ processCharacteristic(model, characteristic, cursor, messages, technicalDebtRuleCache);
+
+ } else if (StringUtils.equals(node, REPOSITORY_KEY)) {
+ DefaultRequirement requirement = processRequirement(cursor, messages, technicalDebtRuleCache);
+ if (requirement != null) {
+ addRequirement(requirement, parent, messages);
+ }
+ }
+ }
+
+ if (StringUtils.isNotBlank(characteristic.key()) && characteristic.isRoot()) {
+ characteristic.setOrder(model.rootCharacteristics().size() + 1);
+ model.addRootCharacteristic(characteristic);
+ return characteristic;
+ }
+ return null;
+ }
+
+ private void addRequirement(DefaultRequirement requirement, DefaultCharacteristic parent, ValidationMessages messages) {
+ DefaultCharacteristic root = parent.parent();
+ if (root == null) {
+ messages.addWarningText("Requirement '" + requirement.ruleKey() + "' is ignored because it's defined directly under a root characteristic.");
+ } else {
+ requirement.setCharacteristic(parent);
+ requirement.setRootCharacteristic(root);
+ }
+ }
+
+ private DefaultRequirement processRequirement(SMInputCursor cursor, ValidationMessages messages, TechnicalDebtRuleCache technicalDebtRuleCache)
+ throws XMLStreamException {
+
+ DefaultRequirement requirement = new DefaultRequirement();
+ String ruleRepositoryKey = cursor.collectDescendantText().trim();
+ String ruleKey = null;
+ Properties properties = new Properties();
+ while (cursor.getNext() != null) {
+ String node = cursor.getLocalName();
+ if (StringUtils.equals(node, PROPERTY)) {
+ properties.add(processProperty(cursor, messages));
+ } else if (StringUtils.equals(node, RULE_KEY)) {
+ ruleKey = cursor.collectDescendantText().trim();
+ }
+ }
+ fillRule(requirement, ruleRepositoryKey, ruleKey, messages, technicalDebtRuleCache);
+ if (requirement.ruleKey() == null) {
+ return null;
+ }
+ return processFunctionsOnRequirement(requirement, properties, messages);
+ }
+
+ private void fillRule(DefaultRequirement requirement, String ruleRepositoryKey, String ruleKey, ValidationMessages messages,
+ TechnicalDebtRuleCache technicalDebtRuleCache) {
+ if (StringUtils.isNotBlank(ruleRepositoryKey) && StringUtils.isNotBlank(ruleKey)) {
+ Rule rule = technicalDebtRuleCache.getByRuleKey(RuleKey.of(ruleRepositoryKey, ruleKey));
+ if (rule != null) {
+ requirement.setRuleKey(RuleKey.of(ruleRepositoryKey, ruleKey));
+ } else {
+ messages.addWarningText("Rule not found: [repository=" + ruleRepositoryKey + ", key=" + ruleKey + "]");
+ }
+ }
+ }
+
+ private Property processProperty(SMInputCursor cursor, ValidationMessages messages) throws XMLStreamException {
+ SMInputCursor c = cursor.childElementCursor();
+ String key = null;
+ int value = 0;
+ String textValue = null;
+ while (c.getNext() != null) {
+ String node = c.getLocalName();
+ if (StringUtils.equals(node, PROPERTY_KEY)) {
+ key = c.collectDescendantText().trim();
+
+ } else if (StringUtils.equals(node, PROPERTY_VALUE)) {
+ String s = c.collectDescendantText().trim();
+ try {
+ // The value is still a double for the moment
+ Double valueDouble = NumberUtils.createDouble(s);
+ value = valueDouble.intValue();
+ } catch (NumberFormatException ex) {
+ messages.addErrorText(String.format("Cannot import value '%s' for field %s - Expected a numeric value instead", s, key));
+ }
+ } else if (StringUtils.equals(node, PROPERTY_TEXT_VALUE)) {
+ textValue = c.collectDescendantText().trim();
+ }
+ }
+ return new Property(key, value, textValue);
+ }
+
+ @CheckForNull
+ private DefaultRequirement processFunctionsOnRequirement(DefaultRequirement requirement, Properties properties, ValidationMessages messages) {
+ Property function = properties.function();
+ Property factor = properties.factor();
+ Property offset = properties.offset();
+
+ if (function != null) {
+ // Requirements should always have values, so we init it with default values
+ requirement.setFactorValue(0);
+ requirement.setFactorUnit(WorkDuration.UNIT.DAYS);
+ requirement.setOffsetValue(0);
+ requirement.setOffsetUnit(WorkDuration.UNIT.DAYS);
+
+ String functionKey = function.getTextValue();
+ if ("linear_threshold".equals(functionKey)) {
+ function.setTextValue(DefaultRequirement.FUNCTION_LINEAR);
+ offset.setValue(0);
+ offset.setTextValue(CharacteristicDto.DAYS);
+ messages.addWarningText(String.format("Linear with threshold function is no longer used, function of the requirement '%s' is replaced by linear.", requirement.ruleKey()));
+ } else if ("constant_resource".equals(functionKey)) {
+ messages.addWarningText(String.format("Constant/file function is no longer used, requirements '%s' are ignored.", requirement.ruleKey()));
+ return null;
+ }
+
+ requirement.setFunction(function.getTextValue());
+ if (factor != null) {
+ requirement.setFactorValue(factor.getValue());
+ if (!Strings.isNullOrEmpty(factor.getTextValue())) {
+ requirement.setFactorUnit(DefaultRequirement.toUnit(factor.getTextValue()));
+ }
+ }
+ if (offset != null) {
+ requirement.setOffsetValue(offset.getValue());
+ if (!Strings.isNullOrEmpty(offset.getTextValue())) {
+ requirement.setOffsetUnit(DefaultRequirement.toUnit(offset.getTextValue()));
+ }
+ }
+ return requirement;
+ }
+ return null;
+ }
+
+ private static class Properties {
+ List<Property> properties;
+
+ public Properties() {
+ this.properties = newArrayList();
+ }
+
+ public Properties add(Property property) {
+ this.properties.add(property);
+ return this;
+ }
+
+ public Property function() {
+ return find(PROPERTY_FUNCTION);
+ }
+
+ public Property factor() {
+ return find(PROPERTY_FACTOR);
+ }
+
+ public Property offset() {
+ return find(PROPERTY_OFFSET);
+ }
+
+ private Property find(final String key) {
+ return Iterables.find(properties, new Predicate<Property>() {
+ @Override
+ public boolean apply(Property input) {
+ return input.getKey().equals(key);
+ }
+ }, null);
+ }
+
+ }
+
+ private static class Property {
+ String key;
+ int value;
+ String textValue;
+
+ private Property(String key, int value, String textValue) {
+ this.key = key;
+ this.value = value;
+ this.textValue = textValue;
+ }
+
+ private Property setValue(int value) {
+ this.value = value;
+ return this;
+ }
+
+ private Property setTextValue(String textValue) {
+ this.textValue = textValue;
+ return this;
+ }
+
+ private String getKey() {
+ return key;
+ }
+
+ private int getValue() {
+ return value;
+ }
+
+ private String getTextValue() {
+ return textValue;
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt.db;
+
+import org.apache.ibatis.session.SqlSession;
+import org.sonar.api.BatchComponent;
+import org.sonar.api.ServerComponent;
+import org.sonar.core.persistence.MyBatis;
+
+import javax.annotation.CheckForNull;
+
+import java.util.List;
+
+public class CharacteristicDao implements BatchComponent, ServerComponent {
+
+ private final MyBatis mybatis;
+
+ public CharacteristicDao(MyBatis mybatis) {
+ this.mybatis = mybatis;
+ }
+
+ /**
+ * @return enabled root characteristics, characteristics and requirements
+ *
+ * @deprecated since 4.3
+ */
+ @Deprecated
+ public List<CharacteristicDto> selectEnabledCharacteristics() {
+ SqlSession session = mybatis.openSession();
+ try {
+ return session.getMapper(CharacteristicMapper.class).selectEnabledCharacteristics();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ /**
+ * @return enabled root characteristics, and characteristics
+ *
+ */
+ public List<CharacteristicDto> selectCharacteristics() {
+ SqlSession session = mybatis.openSession();
+ try {
+ return selectCharacteristics(session);
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ public List<CharacteristicDto> selectCharacteristics(SqlSession session) {
+ return session.getMapper(CharacteristicMapper.class).selectCharacteristics();
+ }
+
+ /**
+ * @return only enabled root characteristics, order by order
+ */
+ public List<CharacteristicDto> selectEnabledRootCharacteristics() {
+ SqlSession session = mybatis.openSession();
+ CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
+ try {
+ return mapper.selectEnabledRootCharacteristics();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ @CheckForNull
+ public CharacteristicDto selectByKey(String key) {
+ SqlSession session = mybatis.openSession();
+ CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
+ try {
+ return mapper.selectByKey(key);
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ @CheckForNull
+ public CharacteristicDto selectById(int id) {
+ SqlSession session = mybatis.openSession();
+ CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
+ try {
+ return mapper.selectById(id);
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ @CheckForNull
+ public CharacteristicDto selectByRuleId(Integer ruleId) {
+ SqlSession session = mybatis.openSession();
+ CharacteristicMapper mapper = session.getMapper(CharacteristicMapper.class);
+ try {
+ return mapper.selectByRuleId(ruleId);
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ public void insert(CharacteristicDto dto, SqlSession session) {
+ session.getMapper(CharacteristicMapper.class).insert(dto);
+ }
+
+ public void insert(CharacteristicDto dto) {
+ SqlSession session = mybatis.openSession();
+ try {
+ insert(dto, session);
+ session.commit();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ public void update(CharacteristicDto dto, SqlSession session) {
+ session.getMapper(CharacteristicMapper.class).update(dto);
+ }
+
+ public void update(CharacteristicDto dto) {
+ SqlSession session = mybatis.openSession();
+ try {
+ update(dto, session);
+ session.commit();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ public void disable(Integer id, SqlSession session) {
+ session.getMapper(CharacteristicMapper.class).disable(id);
+ }
+
+ public void disable(Integer id) {
+ SqlSession session = mybatis.openSession();
+ try {
+ disable(id, session);
+ session.commit();
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt.db;
+
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.internal.WorkDuration;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.io.Serializable;
+import java.util.Date;
+
+public class CharacteristicDto implements Serializable {
+
+ public static final String DAYS = "d";
+ public static final String MINUTES = "mn";
+ public static final String HOURS = "h";
+
+ private Integer id;
+ private String kee;
+ private String name;
+ private Integer parentId;
+ private Integer rootId;
+ private Integer characteristicOrder;
+ private Integer ruleId;
+ private String functionKey;
+ private Double factorValue;
+ private String factorUnit;
+ private Double offsetValue;
+ private String offsetUnit;
+ private Date createdAt;
+ private Date updatedAt;
+ private boolean enabled;
+
+ public Integer getId() {
+ return id;
+ }
+
+ public CharacteristicDto setId(Integer id) {
+ this.id = id;
+ return this;
+ }
+
+ @CheckForNull
+ public String getKey() {
+ return kee;
+ }
+
+ public CharacteristicDto setKey(@Nullable String s) {
+ this.kee = s;
+ return this;
+ }
+
+ @CheckForNull
+ public String getName() {
+ return name;
+ }
+
+ public CharacteristicDto setName(@Nullable String s) {
+ this.name = s;
+ return this;
+ }
+
+ @CheckForNull
+ public Integer getParentId() {
+ return parentId;
+ }
+
+ public CharacteristicDto setParentId(@Nullable Integer i) {
+ this.parentId = i;
+ return this;
+ }
+
+ @CheckForNull
+ public Integer getRootId() {
+ return rootId;
+ }
+
+ public CharacteristicDto setRootId(@Nullable Integer rootId) {
+ this.rootId = rootId;
+ return this;
+ }
+
+ @CheckForNull
+ public Integer getOrder() {
+ return characteristicOrder;
+ }
+
+ public CharacteristicDto setOrder(@Nullable Integer i) {
+ this.characteristicOrder = i;
+ return this;
+ }
+
+ @CheckForNull
+ public Integer getRuleId() {
+ return ruleId;
+ }
+
+ public CharacteristicDto setRuleId(@Nullable Integer ruleId) {
+ this.ruleId = ruleId;
+ return this;
+ }
+
+ @CheckForNull
+ public String getFunction() {
+ return functionKey;
+ }
+
+ public CharacteristicDto setFunction(@Nullable String function) {
+ this.functionKey = function;
+ return this;
+ }
+
+ @CheckForNull
+ public Double getFactorValue() {
+ return factorValue;
+ }
+
+ public CharacteristicDto setFactorValue(Double factor) {
+ this.factorValue = factor;
+ return this;
+ }
+
+ @CheckForNull
+ public String getFactorUnit() {
+ return factorUnit;
+ }
+
+ public CharacteristicDto setFactorUnit(@Nullable String factorUnit) {
+ this.factorUnit = factorUnit;
+ return this;
+ }
+
+ @CheckForNull
+ public Double getOffsetValue() {
+ return offsetValue;
+ }
+
+ public CharacteristicDto setOffsetValue(@Nullable Double offset) {
+ this.offsetValue = offset;
+ return this;
+ }
+
+ @CheckForNull
+ public String getOffsetUnit() {
+ return offsetUnit;
+ }
+
+ public CharacteristicDto setOffsetUnit(@Nullable String offsetUnit) {
+ this.offsetUnit = offsetUnit;
+ return this;
+ }
+
+ public Date getCreatedAt() {
+ return createdAt;
+ }
+
+ public CharacteristicDto setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ @CheckForNull
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public CharacteristicDto setUpdatedAt(@Nullable Date updatedAt) {
+ this.updatedAt = updatedAt;
+ return this;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public CharacteristicDto setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ return this;
+ }
+
+ public DefaultCharacteristic toCharacteristic(@Nullable DefaultCharacteristic parent) {
+ return new DefaultCharacteristic()
+ .setId(id)
+ .setKey(kee)
+ .setName(name)
+ .setOrder(characteristicOrder)
+ .setParent(parent)
+ .setRoot(parent)
+ .setCreatedAt(createdAt)
+ .setUpdatedAt(updatedAt);
+ }
+
+ public static CharacteristicDto toDto(DefaultCharacteristic characteristic, @Nullable Integer parentId) {
+ return new CharacteristicDto()
+ .setKey(characteristic.key())
+ .setName(characteristic.name())
+ .setOrder(characteristic.order())
+ .setParentId(parentId)
+ .setRootId(parentId)
+ .setEnabled(true)
+ .setCreatedAt(characteristic.createdAt())
+ .setUpdatedAt(characteristic.updatedAt());
+ }
+
+ public DefaultRequirement toRequirement(RuleKey ruleKey, DefaultCharacteristic characteristic, DefaultCharacteristic rootCharacteristic) {
+ return new DefaultRequirement()
+ .setId(id)
+ .setRuleKey(ruleKey)
+ .setCharacteristic(characteristic)
+ .setRootCharacteristic(rootCharacteristic)
+ .setFunction(functionKey)
+ .setFactorValue(factorValue.intValue())
+ .setFactorUnit(toUnit(factorUnit))
+ .setOffsetValue(offsetValue.intValue())
+ .setOffsetUnit(toUnit(offsetUnit))
+ .setCreatedAt(createdAt)
+ .setUpdatedAt(updatedAt);
+ }
+
+ public static CharacteristicDto toDto(DefaultRequirement requirement, Integer characteristicId, Integer rootCharacteristicId, Integer ruleId) {
+ return new CharacteristicDto()
+ .setRuleId(ruleId)
+ .setParentId(characteristicId)
+ .setRootId(rootCharacteristicId)
+ .setFunction(requirement.function())
+ .setFactorValue((double) requirement.factorValue())
+ .setFactorUnit(fromUnit(requirement.factorUnit()))
+ .setOffsetValue((double) requirement.offsetValue())
+ .setOffsetUnit(fromUnit(requirement.offsetUnit()))
+ .setEnabled(true)
+ .setCreatedAt(requirement.createdAt())
+ .setUpdatedAt(requirement.updatedAt());
+ }
+
+ private static WorkDuration.UNIT toUnit(@Nullable String requirementUnit) {
+ if (requirementUnit != null) {
+ if (DAYS.equals(requirementUnit)) {
+ return WorkDuration.UNIT.DAYS;
+ } else if (HOURS.equals(requirementUnit)) {
+ return WorkDuration.UNIT.HOURS;
+ } else if (MINUTES.equals(requirementUnit)) {
+ return WorkDuration.UNIT.MINUTES;
+ }
+ throw new IllegalStateException("Invalid unit : " + requirementUnit);
+ }
+ return null;
+ }
+
+ private static String fromUnit(@Nullable WorkDuration.UNIT unit) {
+ if (unit != null) {
+ if (WorkDuration.UNIT.DAYS.equals(unit)) {
+ return DAYS;
+ } else if (WorkDuration.UNIT.HOURS.equals(unit)) {
+ return HOURS;
+ } else if (WorkDuration.UNIT.MINUTES.equals(unit)) {
+ return MINUTES;
+ }
+ throw new IllegalStateException("Invalid unit : " + unit);
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt.db;
+
+import java.util.List;
+
+public interface CharacteristicMapper {
+
+ List<CharacteristicDto> selectEnabledCharacteristics();
+
+ List<CharacteristicDto> selectCharacteristics();
+
+ List<CharacteristicDto> selectEnabledRootCharacteristics();
+
+ CharacteristicDto selectByKey(String key);
+
+ CharacteristicDto selectById(int id);
+
+ CharacteristicDto selectByRuleId(Integer ruleId);
+
+ void insert(CharacteristicDto characteristic);
+
+ int update(CharacteristicDto characteristic);
+
+ int disable(Integer id);
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.core.technicaldebt.db;
+
+import javax.annotation.ParametersAreNonnullByDefault;
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.core.technicaldebt;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mappei.dtd">
-
-<mapper namespace="org.sonar.core.debt.db.CharacteristicMapper">
-
- <sql id="characteristicColumns">
- c.id,
- c.kee as kee,
- c.name as name,
- c.parent_id as parentId,
- c.root_id as rootId,
- c.characteristic_order as characteristicOrder,
- c.rule_id as ruleId,
- c.function_key as functionKey,
- c.factor_value as factorValue,
- c.factor_unit as factorUnit,
- c.offset_value as offsetValue,
- c.offset_unit as offsetUnit,
- c.enabled as enabled,
- c.created_at as createdAt,
- c.updated_at as updatedAt
- </sql>
-
- <select id="selectEnabledCharacteristics" parameterType="map" resultType="Characteristic">
- select <include refid="characteristicColumns"/>
- from characteristics c
- <where>
- and c.enabled=${_true}
- </where>
- </select>
-
- <select id="selectCharacteristics" parameterType="map" resultType="Characteristic">
- select <include refid="characteristicColumns"/>
- from characteristics c
- <where>
- and c.rule_id is null
- and c.enabled=${_true}
- </where>
- </select>
-
- <select id="selectEnabledRootCharacteristics" parameterType="map" resultType="Characteristic">
- select <include refid="characteristicColumns"/>
- from characteristics c
- <where>
- and c.parent_id is null
- and c.rule_id is null
- and c.enabled=${_true}
- </where>
- order by characteristic_order asc
- </select>
-
- <select id="selectByKey" parameterType="String" resultType="Characteristic">
- select <include refid="characteristicColumns"/>
- from characteristics c
- <where>
- and c.kee=#{key}
- and c.enabled=${_true}
- </where>
- </select>
-
- <select id="selectById" parameterType="Integer" resultType="Characteristic">
- select <include refid="characteristicColumns"/>
- from characteristics c
- <where>
- and c.id=#{id}
- and c.enabled=${_true}
- </where>
- </select>
-
- <select id="selectByRuleId" parameterType="Integer" resultType="Characteristic">
- select <include refid="characteristicColumns"/>
- from characteristics c
- <where>
- and c.rule_id=#{ruleId}
- and c.enabled=${_true}
- </where>
- </select>
-
- <insert id="insert" parameterType="Characteristic" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
- INSERT INTO characteristics (kee, name, parent_id, root_id, characteristic_order,
- rule_id, function_key, factor_value, factor_unit, offset_value, offset_unit,
- enabled, created_at, updated_at)
- VALUES (#{kee}, #{name}, #{parentId}, #{rootId}, #{characteristicOrder},
- #{ruleId}, #{functionKey}, #{factorValue}, #{factorUnit}, #{offsetValue}, #{offsetUnit},
- #{enabled}, current_timestamp, current_timestamp)
- </insert>
-
- <update id="update" parameterType="Characteristic">
- update characteristics set
- name=#{name},
- parent_id=#{parentId},
- root_id=#{rootId},
- characteristic_order=#{characteristicOrder},
- rule_id=#{ruleId},
- function_key=#{functionKey},
- factor_value=#{factorValue},
- factor_unit=#{factorUnit},
- offset_value=#{offsetValue},
- offset_unit=#{offsetUnit},
- enabled=#{enabled},
- updated_at=current_timestamp
- where id=#{id}
- </update>
-
- <update id="disable" parameterType="Integer">
- update characteristics set
- enabled=${_false},
- updated_at=current_timestamp
- where id=#{id}
- </update>
-
-</mapper>
-
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mappei.dtd">
+
+<mapper namespace="org.sonar.core.technicaldebt.db.CharacteristicMapper">
+
+ <sql id="characteristicColumns">
+ c.id,
+ c.kee as kee,
+ c.name as name,
+ c.parent_id as parentId,
+ c.root_id as rootId,
+ c.characteristic_order as characteristicOrder,
+ c.rule_id as ruleId,
+ c.function_key as functionKey,
+ c.factor_value as factorValue,
+ c.factor_unit as factorUnit,
+ c.offset_value as offsetValue,
+ c.offset_unit as offsetUnit,
+ c.enabled as enabled,
+ c.created_at as createdAt,
+ c.updated_at as updatedAt
+ </sql>
+
+ <select id="selectEnabledCharacteristics" parameterType="map" resultType="Characteristic">
+ select <include refid="characteristicColumns"/>
+ from characteristics c
+ <where>
+ and c.enabled=${_true}
+ </where>
+ </select>
+
+ <select id="selectCharacteristics" parameterType="map" resultType="Characteristic">
+ select <include refid="characteristicColumns"/>
+ from characteristics c
+ <where>
+ and c.rule_id is null
+ and c.enabled=${_true}
+ </where>
+ </select>
+
+ <select id="selectEnabledRootCharacteristics" parameterType="map" resultType="Characteristic">
+ select <include refid="characteristicColumns"/>
+ from characteristics c
+ <where>
+ and c.parent_id is null
+ and c.rule_id is null
+ and c.enabled=${_true}
+ </where>
+ order by characteristic_order asc
+ </select>
+
+ <select id="selectByKey" parameterType="String" resultType="Characteristic">
+ select <include refid="characteristicColumns"/>
+ from characteristics c
+ <where>
+ and c.kee=#{key}
+ and c.enabled=${_true}
+ </where>
+ </select>
+
+ <select id="selectById" parameterType="Integer" resultType="Characteristic">
+ select <include refid="characteristicColumns"/>
+ from characteristics c
+ <where>
+ and c.id=#{id}
+ and c.enabled=${_true}
+ </where>
+ </select>
+
+ <select id="selectByRuleId" parameterType="Integer" resultType="Characteristic">
+ select <include refid="characteristicColumns"/>
+ from characteristics c
+ <where>
+ and c.rule_id=#{ruleId}
+ and c.enabled=${_true}
+ </where>
+ </select>
+
+ <insert id="insert" parameterType="Characteristic" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
+ INSERT INTO characteristics (kee, name, parent_id, root_id, characteristic_order,
+ rule_id, function_key, factor_value, factor_unit, offset_value, offset_unit,
+ enabled, created_at, updated_at)
+ VALUES (#{kee}, #{name}, #{parentId}, #{rootId}, #{characteristicOrder},
+ #{ruleId}, #{functionKey}, #{factorValue}, #{factorUnit}, #{offsetValue}, #{offsetUnit},
+ #{enabled}, current_timestamp, current_timestamp)
+ </insert>
+
+ <update id="update" parameterType="Characteristic">
+ update characteristics set
+ name=#{name},
+ parent_id=#{parentId},
+ root_id=#{rootId},
+ characteristic_order=#{characteristicOrder},
+ rule_id=#{ruleId},
+ function_key=#{functionKey},
+ factor_value=#{factorValue},
+ factor_unit=#{factorUnit},
+ offset_value=#{offsetValue},
+ offset_unit=#{offsetUnit},
+ enabled=#{enabled},
+ updated_at=current_timestamp
+ where id=#{id}
+ </update>
+
+ <update id="disable" parameterType="Integer">
+ update characteristics set
+ enabled=${_false},
+ updated_at=current_timestamp
+ where id=#{id}
+ </update>
+
+</mapper>
+
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import com.google.common.collect.Lists;
-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.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.debt.db.CharacteristicDao;
-import org.sonar.core.debt.db.CharacteristicDto;
-import org.sonar.core.persistence.MyBatis;
-
-import java.io.Reader;
-import java.util.Collections;
-import java.util.List;
-
-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 CharacteristicsDebtModelSynchronizerTest {
-
- @Mock
- MyBatis myBatis;
-
- @Mock
- SqlSession session;
-
- @Mock
- DebtModelPluginRepository debtModelPluginRepository;
-
- @Mock
- CharacteristicDao dao;
-
- @Mock
- CharacteristicsDebtModelXMLImporter xmlImporter;
-
- Integer currentId = 1;
-
- private DefaultTechnicalDebtModel defaultModel;
-
- private CharacteristicsDebtModelSynchronizer manager;
-
- @Before
- public void initAndMerge() throws Exception {
- when(myBatis.openSession()).thenReturn(session);
-
- defaultModel = new DefaultTechnicalDebtModel();
- Reader defaultModelReader = mock(Reader.class);
- when(debtModelPluginRepository.createReaderForXMLFile("technical-debt")).thenReturn(defaultModelReader);
- when(xmlImporter.importXML(eq(defaultModelReader), any(ValidationMessages.class))).thenReturn(defaultModel);
-
- 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));
-
-
- manager = new CharacteristicsDebtModelSynchronizer(myBatis, dao, debtModelPluginRepository, xmlImporter);
- }
-
- @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);
-
- when(debtModelPluginRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
- when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
-
- manager.synchronize(ValidationMessages.create());
-
- verify(dao).selectEnabledCharacteristics();
- ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
- verify(dao, times(2)).insert(characteristicCaptor.capture(), eq(session));
-
- List<CharacteristicDto> result = characteristicCaptor.getAllValues();
- assertThat(result.get(0).getKey()).isEqualTo("PORTABILITY");
- assertThat(result.get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
- verifyNoMoreInteractions(dao);
- }
-
- @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);
-
- when(debtModelPluginRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
- when(dao.selectEnabledCharacteristics()).thenReturn(Lists.newArrayList(new CharacteristicDto()));
-
- manager.synchronize(ValidationMessages.create());
-
- verify(dao, never()).insert(any(CharacteristicDto.class), eq(session));
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-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.utils.ValidationMessages;
-
-import java.io.IOException;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class CharacteristicsDebtModelXMLImporterTest {
-
- @Test
- public void import_characteristics() {
- String xml = getFileContent("import_characteristics.xml");
-
- ValidationMessages messages = ValidationMessages.create();
- DefaultTechnicalDebtModel debtModel = new CharacteristicsDebtModelXMLImporter().importXML(xml, messages);
-
- 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");
- }
-
- @Test
- public void import_badly_formatted_xml() {
- String xml = getFileContent("import_badly_formatted_xml.xml");
-
- ValidationMessages messages = ValidationMessages.create();
- DefaultTechnicalDebtModel debtModel = new CharacteristicsDebtModelXMLImporter().importXML(xml, messages);
-
- checkXmlCorrectlyImported(debtModel, messages);
- }
-
- private void checkXmlCorrectlyImported(DefaultTechnicalDebtModel sqale, ValidationMessages messages) {
- assertThat(messages.getErrors()).isEmpty();
-
- // characteristics
- assertThat(sqale.rootCharacteristics()).hasSize(2);
- DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
- assertThat(efficiency.name()).isEqualTo("Efficiency");
-
- // sub-characteristics
- assertThat(efficiency.children()).hasSize(1);
- DefaultCharacteristic memoryEfficiency = sqale.characteristicByKey("MEMORY_EFFICIENCY");
- assertThat(memoryEfficiency.name()).isEqualTo("Memory use");
- }
-
- private String getFileContent(String file) {
- try {
- return Resources.toString(Resources.getResource(CharacteristicsDebtModelXMLImporterTest.class, "CharacteristicsDebtModelXMLImporterTest/" + file), Charsets.UTF_8);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.io.Resources;
-import org.apache.commons.io.IOUtils;
-import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.sonar.api.SonarPlugin;
-import org.sonar.api.platform.PluginMetadata;
-import org.sonar.api.platform.PluginRepository;
-
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.io.Reader;
-import java.net.MalformedURLException;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import static org.fest.assertions.Assertions.assertThat;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class DebtModelPluginRepositoryTest {
-
- private static final String TEST_XML_PREFIX_PATH = "org/sonar/core/debt/TechnicalDebtModelRepositoryTest/";
-
- private DebtModelPluginRepository modelFinder;
-
- @Test
- public void test_component_initialization() throws Exception {
- // we do have the "csharp-model.xml" file in src/test/resources
- PluginMetadata csharpPluginMetadata = mock(PluginMetadata.class);
- when(csharpPluginMetadata.getKey()).thenReturn("csharp");
-
- // but we don' have the "php-model.xml" one
- PluginMetadata phpPluginMetadata = mock(PluginMetadata.class);
- when(phpPluginMetadata.getKey()).thenReturn("php");
-
- PluginRepository repository = mock(PluginRepository.class);
- when(repository.getMetadata()).thenReturn(Lists.newArrayList(csharpPluginMetadata, phpPluginMetadata));
- FakePlugin fakePlugin = new FakePlugin();
- when(repository.getPlugin(anyString())).thenReturn(fakePlugin);
- modelFinder = new DebtModelPluginRepository(repository, TEST_XML_PREFIX_PATH);
-
- // when
- modelFinder.start();
-
- // assert
- Collection<String> contributingPluginList = modelFinder.getContributingPluginList();
- assertThat(contributingPluginList.size()).isEqualTo(2);
- assertThat(contributingPluginList).containsOnly("technical-debt", "csharp");
- }
-
- @Test
- public void contributing_plugin_list() throws Exception {
- initModel();
- Collection<String> contributingPluginList = modelFinder.getContributingPluginList();
- assertThat(contributingPluginList.size()).isEqualTo(2);
- assertThat(contributingPluginList).contains("csharp", "java");
- }
-
- @Test
- public void get_content_for_xml_file() throws Exception {
- initModel();
- Reader xmlFileReader = null;
- try {
- xmlFileReader = modelFinder.createReaderForXMLFile("csharp");
- assertNotNull(xmlFileReader);
- List<String> lines = IOUtils.readLines(xmlFileReader);
- assertThat(lines.size()).isEqualTo(25);
- assertThat(lines.get(0)).isEqualTo("<sqale>");
- } catch (Exception e) {
- fail("Should be able to read the XML file.");
- } finally {
- IOUtils.closeQuietly(xmlFileReader);
- }
- }
-
- @Test
- public void return_xml_file_path_for_plugin() throws Exception {
- initModel();
- assertThat(modelFinder.getXMLFilePath("foo")).isEqualTo(TEST_XML_PREFIX_PATH + "foo-model.xml");
- }
-
- @Test
- public void contain_default_model() throws Exception {
- modelFinder = new DebtModelPluginRepository(mock(PluginRepository.class));
- modelFinder.start();
- assertThat(modelFinder.getContributingPluginKeyToClassLoader().keySet()).containsOnly("technical-debt");
- }
-
- private void initModel() throws MalformedURLException {
- Map<String, ClassLoader> contributingPluginKeyToClassLoader = Maps.newHashMap();
- contributingPluginKeyToClassLoader.put("csharp", newClassLoader());
- contributingPluginKeyToClassLoader.put("java", newClassLoader());
- modelFinder = new DebtModelPluginRepository(contributingPluginKeyToClassLoader, TEST_XML_PREFIX_PATH);
- }
-
- private ClassLoader newClassLoader() throws MalformedURLException {
- ClassLoader loader = mock(ClassLoader.class);
- when(loader.getResourceAsStream(anyString())).thenAnswer(new Answer<InputStream>() {
- public InputStream answer(InvocationOnMock invocation) throws Throwable {
- return new FileInputStream(Resources.getResource((String) invocation.getArguments()[0]).getPath());
- }
- });
- return loader;
- }
-
- class FakePlugin extends SonarPlugin {
- public List getExtensions() {
- return null;
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.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.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.technicaldebt.server.Characteristic;
-import org.sonar.api.utils.internal.WorkDuration;
-import org.sonar.core.debt.db.CharacteristicDao;
-import org.sonar.core.debt.db.CharacteristicDto;
-
-import java.util.List;
-
-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.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class DefaultTechnicalDebtManagerTest {
-
- @Mock
- CharacteristicDao dao;
-
- @Mock
- RuleFinder ruleFinder;
-
- DefaultTechnicalDebtManager finder;
-
- @Before
- public void setUp() throws Exception {
- finder = new DefaultTechnicalDebtManager(dao, ruleFinder);
- }
-
- @Test
- public void find_root_characteristics() throws Exception {
- CharacteristicDto rootCharacteristicDto = new CharacteristicDto()
- .setId(1)
- .setKey("MEMORY_EFFICIENCY")
- .setName("Memory use");
- when(dao.selectEnabledRootCharacteristics()).thenReturn(newArrayList(rootCharacteristicDto));
-
- List<Characteristic> result = finder.findRootCharacteristics();
- assertThat(result).hasSize(1);
-
- Characteristic rootCharacteristic = result.get(0);
- assertThat(rootCharacteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(rootCharacteristic.name()).isEqualTo("Memory use");
- assertThat(rootCharacteristic.parentId()).isNull();
- assertThat(rootCharacteristic.rootId()).isNull();
- }
-
- @Test
- public void find_requirement() throws Exception {
- Rule rule = Rule.create("repo", "key");
- rule.setId(1);
-
- when(dao.selectByRuleId(rule.getId())).thenReturn(
- new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear")
- .setFactorValue(30.0).setFactorUnit("mn")
- .setOffsetValue(0.0).setOffsetUnit("d")
- );
-
- Characteristic result = finder.findRequirementByRule(rule);
-
- assertThat(result.id()).isEqualTo(3);
- assertThat(result.parentId()).isEqualTo(2);
- assertThat(result.rootId()).isEqualTo(1);
- assertThat(result.ruleKey()).isEqualTo(RuleKey.of("repo", "key"));
- assertThat(result.function()).isEqualTo("linear");
- assertThat(result.factorValue()).isEqualTo(30);
- assertThat(result.factorUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
- assertThat(result.offsetValue()).isEqualTo(0);
- assertThat(result.offsetUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
- }
-
- @Test
- public void not_find_requirement() throws Exception {
- Rule rule = Rule.create("repo", "key");
- rule.setId(1);
-
- when(dao.selectByRuleId(rule.getId())).thenReturn(null);
-
- Characteristic result = finder.findRequirementByRule(rule);
- assertThat(result).isNull();
- }
-
- @Test
- public void find_characteristic() throws Exception {
- Rule rule = Rule.create("repo", "key");
- rule.setId(1);
-
- when(dao.selectById(2)).thenReturn(
- new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler").setParentId(1).setRootId(1));
-
- Characteristic result = finder.findCharacteristicById(2);
-
- assertThat(result.id()).isEqualTo(2);
- assertThat(result.parentId()).isEqualTo(1);
- assertThat(result.rootId()).isEqualTo(1);
- assertThat(result.key()).isEqualTo("COMPILER_RELATED_PORTABILITY");
- assertThat(result.name()).isEqualTo("Compiler");
- }
-
- @Test
- public void not_find_characteristic() throws Exception {
- Rule rule = Rule.create("repo", "key");
- rule.setId(1);
-
- when(dao.selectById(rule.getId())).thenReturn(null);
-
- Characteristic result = finder.findCharacteristicById(2);
- assertThat(result).isNull();
- }
-
- @Test
- public void find_requirement_by_rule_id() throws Exception {
- Rule rule = Rule.create("repo", "key");
- rule.setId(1);
-
- when(ruleFinder.findById(1)).thenReturn(rule);
-
- when(dao.selectByRuleId(rule.getId())).thenReturn(
- new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear")
- .setFactorValue(30.0).setFactorUnit("mn")
- .setOffsetValue(0.0).setOffsetUnit("d")
- );
-
- Characteristic result = finder.findRequirementByRuleId(1);
-
- assertThat(result.id()).isEqualTo(3);
- assertThat(result.parentId()).isEqualTo(2);
- assertThat(result.rootId()).isEqualTo(1);
- assertThat(result.ruleKey()).isEqualTo(RuleKey.of("repo", "key"));
- assertThat(result.function()).isEqualTo("linear");
- assertThat(result.factorValue()).isEqualTo(30);
- assertThat(result.factorUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
- assertThat(result.offsetValue()).isEqualTo(0);
- assertThat(result.offsetUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
-
- }
-
- @Test
- public void not_find_requirement_by_rule_id_on_unknown_requirement() throws Exception {
- Rule rule = Rule.create("repo", "key");
- rule.setId(1);
-
- when(ruleFinder.findById(1)).thenReturn(rule);
-
- when(dao.selectByRuleId(rule.getId())).thenReturn(null);
-
- assertThat(finder.findRequirementByRuleId(1)).isNull();
- }
-
- @Test
- public void fail_to_find_requirement_by_rule_id_if_unknown_rule_id() throws Exception {
- when(dao.selectByRuleId(1)).thenReturn(
- new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear").setFactorValue(30.0).setFactorUnit("mn"));
- when(ruleFinder.findById(1)).thenReturn(null);
- try {
- finder.findRequirementByRuleId(1);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(IllegalArgumentException.class);
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.internal.WorkDuration;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class DefaultTechnicalDebtModelTest {
-
- private DefaultTechnicalDebtModel sqaleModel;
-
- @Before
- public void setUp() throws Exception {
- sqaleModel = new DefaultTechnicalDebtModel();
- }
-
- @Test
- public void get_root_characteristics() throws Exception {
- DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
- .setKey("MEMORY_EFFICIENCY")
- .setName("Memory use");
-
- new DefaultCharacteristic()
- .setKey("EFFICIENCY")
- .setName("Efficiency")
- .setParent(rootCharacteristic);
-
- sqaleModel.addRootCharacteristic(rootCharacteristic);
-
- assertThat(sqaleModel.rootCharacteristics()).hasSize(1);
- DefaultCharacteristic resultRootCharacteristic = sqaleModel.rootCharacteristics().get(0);
- assertThat(resultRootCharacteristic).isEqualTo(rootCharacteristic);
- }
-
- @Test
- public void get_characteristic_by_key() throws Exception {
- DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
- .setKey("MEMORY_EFFICIENCY")
- .setName("Memory use");
-
- DefaultCharacteristic characteristic = new DefaultCharacteristic()
- .setKey("EFFICIENCY")
- .setName("Efficiency")
- .setParent(rootCharacteristic);
-
- sqaleModel.addRootCharacteristic(rootCharacteristic);
-
- assertThat(sqaleModel.characteristicByKey("MEMORY_EFFICIENCY")).isEqualTo(rootCharacteristic);
- assertThat(sqaleModel.characteristicByKey("EFFICIENCY")).isEqualTo(characteristic);
- assertThat(sqaleModel.characteristicByKey("EFFICIENCY").parent()).isEqualTo(rootCharacteristic);
-
- assertThat(sqaleModel.characteristicByKey("UNKNOWN")).isNull();
- }
-
- @Test
- public void get_requirement_by_rule_key() throws Exception {
- DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
- .setKey("MEMORY_EFFICIENCY")
- .setName("Memory use");
-
- DefaultCharacteristic characteristic = new DefaultCharacteristic()
- .setKey("EFFICIENCY")
- .setName("Efficiency")
- .setParent(rootCharacteristic);
-
- RuleKey ruleKey = RuleKey.of("checkstyle", "Regexp");
- DefaultRequirement requirement = new DefaultRequirement()
- .setCharacteristic(characteristic)
- .setRuleKey(ruleKey)
- .setFunction("linear")
- .setFactorValue(2)
- .setFactorUnit(WorkDuration.UNIT.HOURS)
- .setOffsetValue(0)
- .setOffsetUnit(WorkDuration.UNIT.HOURS);
-
- sqaleModel.addRootCharacteristic(rootCharacteristic);
-
- assertThat(sqaleModel.requirementsByRule(ruleKey)).isEqualTo(requirement);
- assertThat(sqaleModel.requirementsByRule(RuleKey.of("not", "found"))).isNull();
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import com.google.common.base.Charsets;
-import com.google.common.io.Resources;
-import org.junit.Test;
-import org.sonar.api.rule.RemediationFunction;
-import org.sonar.api.rule.RuleKey;
-
-import java.io.IOException;
-import java.util.List;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class RulesDebtModelXMLImporterTest {
-
- RulesDebtModelXMLImporter importer = new RulesDebtModelXMLImporter();
-
- @Test
- public void import_rules() {
- String xml = getFileContent("import_rules.xml");
-
- List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
- assertThat(results).hasSize(2);
- }
-
- @Test
- public void import_linear() {
- String xml = getFileContent("import_linear.xml");
-
- List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
- assertThat(results).hasSize(1);
-
- RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
- assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
- assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
- assertThat(ruleDebt.factor()).isEqualTo("3h");
- assertThat(ruleDebt.offset()).isEqualTo("0d");
- }
-
- @Test
- public void import_linear_with_offset() {
- String xml = getFileContent("import_linear_with_offset.xml");
-
- List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
- assertThat(results).hasSize(1);
-
- RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
- assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
- assertThat(ruleDebt.factor()).isEqualTo("3h");
- assertThat(ruleDebt.offset()).isEqualTo("1min");
- }
-
- @Test
- public void import_constant_issue() {
- String xml = getFileContent("import_constant_issue.xml");
-
- List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
- assertThat(results).hasSize(1);
-
- RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
- assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.CONSTANT_ISSUE);
- assertThat(ruleDebt.factor()).isEqualTo("0d");
- assertThat(ruleDebt.offset()).isEqualTo("3d");
- }
-
- @Test
- public void use_default_unit_when_no_unit() {
- String xml = getFileContent("use_default_unit_when_no_unit.xml");
-
- List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
- assertThat(results).hasSize(1);
-
- RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
- assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
- assertThat(ruleDebt.factor()).isEqualTo("3d");
- assertThat(ruleDebt.offset()).isEqualTo("1d");
- }
-
- @Test
- public void replace_mn_by_min() {
- String xml = getFileContent("replace_mn_by_min.xml");
-
- List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
- assertThat(results).hasSize(1);
-
- RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
- assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
- assertThat(ruleDebt.factor()).isEqualTo("3min");
- assertThat(ruleDebt.offset()).isEqualTo("0d");
- }
-
- @Test
- public void convert_deprecated_linear_with_threshold_function_by_linear_function() {
- String xml = getFileContent("convert_deprecated_linear_with_threshold_function_by_linear_function.xml");
-
- List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
- assertThat(results).hasSize(1);
-
- RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
- assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
- assertThat(ruleDebt.factor()).isEqualTo("3h");
- assertThat(ruleDebt.offset()).isEqualTo("0d");
- }
-
- @Test
- public void ignore_deprecated_constant_per_file_function() {
- String xml = getFileContent("ignore_deprecated_constant_per_file_function.xml");
-
- List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
- assertThat(results).isEmpty();
- }
-
- @Test
- public void ignore_rule_on_root_characteristics() {
- String xml = getFileContent("ignore_rule_on_root_characteristics.xml");
-
- List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
- assertThat(results).isEmpty();
- }
-
- @Test
- public void import_badly_formatted_xml() {
- String xml = getFileContent("import_badly_formatted_xml.xml");
-
- List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
- assertThat(results).hasSize(1);
-
- RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
- assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
- assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
- assertThat(ruleDebt.factor()).isEqualTo("3h");
- assertThat(ruleDebt.offset()).isEqualTo("0d");
- }
-
- @Test
- public void ignore_invalid_value() throws Exception {
- String xml = getFileContent("ignore_invalid_value.xml");
- List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
- assertThat(results).isEmpty();
- }
-
- private String getFileContent(String file) {
- try {
- return Resources.toString(Resources.getResource(RulesDebtModelXMLImporterTest.class, "RulesDebtModelXMLImporterTest/" + file), Charsets.UTF_8);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import com.google.common.collect.Lists;
-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.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.api.utils.internal.WorkDuration;
-import org.sonar.core.debt.db.CharacteristicDao;
-import org.sonar.core.debt.db.CharacteristicDto;
-import org.sonar.core.persistence.MyBatis;
-
-import java.io.Reader;
-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.fest.assertions.Fail.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.*;
-
-@RunWith(MockitoJUnitRunner.class)
-public class TechnicalDebtModelSynchronizerTest {
-
- @Mock
- MyBatis myBatis;
-
- @Mock
- SqlSession session;
-
- @Mock
- DebtModelPluginRepository debtModelPluginRepository;
-
- @Mock
- TechnicalDebtRuleCache ruleCache;
-
- @Mock
- CharacteristicDao dao;
-
- @Mock
- TechnicalDebtXMLImporter xmlImporter;
-
- Integer currentId = 1;
-
- private DefaultTechnicalDebtModel defaultModel;
-
- private TechnicalDebtModelSynchronizer manager;
-
- @Before
- public void initAndMerge() throws Exception {
- when(myBatis.openSession()).thenReturn(session);
-
- defaultModel = new DefaultTechnicalDebtModel();
- Reader defaultModelReader = mock(Reader.class);
- when(debtModelPluginRepository.createReaderForXMLFile("technical-debt")).thenReturn(defaultModelReader);
- when(xmlImporter.importXML(eq(defaultModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(defaultModel);
-
- 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));
-
-
- manager = new TechnicalDebtModelSynchronizer(myBatis, dao, debtModelPluginRepository, xmlImporter);
- }
-
- @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);
-
- when(debtModelPluginRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
- when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
-
- manager.synchronize(ValidationMessages.create(), ruleCache);
-
- verify(dao).selectEnabledCharacteristics();
- ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
- verify(dao, times(2)).insert(characteristicCaptor.capture(), eq(session));
-
- List<CharacteristicDto> result = characteristicCaptor.getAllValues();
- assertThat(result.get(0).getKey()).isEqualTo("PORTABILITY");
- assertThat(result.get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
- verifyNoMoreInteractions(dao);
- }
-
- @Test
- public void create_model_with_requirements_from_plugin_on_first_execution() throws Exception {
- // Default model
- DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
- new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic).setRoot(defaultRootCharacteristic);
- defaultModel.addRootCharacteristic(defaultRootCharacteristic);
-
- // No db model
- when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
-
- // Java model
- DefaultTechnicalDebtModel javaModel = new DefaultTechnicalDebtModel();
- DefaultCharacteristic javaRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
- DefaultCharacteristic javaCharacteristic = new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(javaRootCharacteristic).setRoot(javaRootCharacteristic);
- javaModel.addRootCharacteristic(javaRootCharacteristic);
-
- Rule rule = Rule.create();
- rule.setId(10);
- RuleKey ruleKey = RuleKey.of("checkstyle", "import");
- when(ruleCache.getByRuleKey(ruleKey)).thenReturn(rule);
- new DefaultRequirement().setRuleKey(ruleKey)
- .setFunction("linear")
- .setFactorValue(30)
- .setFactorUnit(WorkDuration.UNIT.MINUTES)
- .setCharacteristic(javaCharacteristic)
- .setRootCharacteristic(javaRootCharacteristic);
-
- Reader javaModelReader = mock(Reader.class);
- when(xmlImporter.importXML(eq(javaModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(javaModel);
- when(debtModelPluginRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
- when(debtModelPluginRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
-
- manager.synchronize(ValidationMessages.create(), ruleCache);
-
- verify(dao).selectEnabledCharacteristics();
- ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
- verify(dao, times(3)).insert(characteristicCaptor.capture(), eq(session));
-
- List<CharacteristicDto> result = characteristicCaptor.getAllValues();
- assertThat(result.get(0).getKey()).isEqualTo("PORTABILITY");
- assertThat(result.get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
- assertThat(result.get(2).getRuleId()).isEqualTo(10);
- verifyNoMoreInteractions(dao);
- }
-
- @Test
- public void add_new_requirements_from_plugin() throws Exception {
- // Default model
- DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
- new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic).setRoot(defaultRootCharacteristic);
- defaultModel.addRootCharacteristic(defaultRootCharacteristic);
-
- // Db model
- CharacteristicDto dbRootCharacteristic = new CharacteristicDto().setId(1).setKey("PORTABILITY");
- CharacteristicDto dbCharacteristic = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setParentId(1).setRootId(1);
- CharacteristicDto requirement = new CharacteristicDto().setId(3)
- .setRuleId(10).setParentId(2).setRootId(1).setFactorValue(30.0).setFactorUnit("mn");
-
- RuleKey ruleKey1 = RuleKey.of("checkstyle", "import");
- Rule rule1 = Rule.create();
- rule1.setId(10);
- when(ruleCache.getByRuleKey(ruleKey1)).thenReturn(rule1);
- when(ruleCache.exists(10)).thenReturn(true);
- when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(requirement, dbCharacteristic, dbRootCharacteristic));
-
- // Java model
- DefaultTechnicalDebtModel javaModel = new DefaultTechnicalDebtModel();
- DefaultCharacteristic javaRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
- DefaultCharacteristic javaCharacteristic = new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(javaRootCharacteristic).setRoot(javaRootCharacteristic);
- javaModel.addRootCharacteristic(javaRootCharacteristic);
-
- RuleKey ruleKey2 = RuleKey.of("checkstyle", "export");
- Rule rule2 = Rule.create();
- rule2.setId(11);
- when(ruleCache.getByRuleKey(ruleKey2)).thenReturn(rule2);
-
- // New requirement
- new DefaultRequirement().setRuleKey(ruleKey2)
- .setFunction("linear")
- .setFactorValue(1)
- .setFactorUnit(WorkDuration.UNIT.HOURS)
- .setCharacteristic(javaCharacteristic)
- .setRootCharacteristic(javaRootCharacteristic);
-
- Reader javaModelReader = mock(Reader.class);
- when(debtModelPluginRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
- when(xmlImporter.importXML(eq(javaModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(javaModel);
- when(debtModelPluginRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
-
- manager.synchronize(ValidationMessages.create(), ruleCache);
-
- verify(dao).selectEnabledCharacteristics();
- ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
- verify(dao).insert(characteristicCaptor.capture(), eq(session));
- assertThat(characteristicCaptor.getValue().getRuleId()).isEqualTo(11);
- verifyNoMoreInteractions(dao);
- }
-
- @Test
- public void disable_requirements_on_not_existing_rules() throws Exception {
- // Default model
- DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
- new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic);
- defaultModel.addRootCharacteristic(defaultRootCharacteristic);
-
- // Db model
- CharacteristicDto dbRootCharacteristic = new CharacteristicDto().setId(1).setKey("PORTABILITY");
- CharacteristicDto dbCharacteristic = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setParentId(1);
- // To be disabled as rule does not exists
- CharacteristicDto requirement = new CharacteristicDto().setId(3)
- .setRuleId(10).setParentId(2).setFactorValue(30.0).setFactorUnit("mn");
-
- when(ruleCache.exists(10)).thenReturn(false);
-
- when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(dbRootCharacteristic, dbCharacteristic, requirement));
-
- manager.synchronize(ValidationMessages.create(), ruleCache);
-
- verify(dao).selectEnabledCharacteristics();
- verify(dao).disable(eq(3), eq(session));
- verifyNoMoreInteractions(dao);
- }
-
- @Test
- public void fail_when_plugin_defines_characteristics_not_defined_in_default_model() throws Exception {
- try {
- // Default model
- DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
- new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic);
- defaultModel.addRootCharacteristic(defaultRootCharacteristic);
-
- // Db model
- CharacteristicDto dbRootCharacteristic = new CharacteristicDto().setId(1).setKey("PORTABILITY");
- CharacteristicDto dbCharacteristic = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setParentId(1);
- when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(dbRootCharacteristic, dbCharacteristic));
-
- // Java model
- DefaultTechnicalDebtModel javaModel = new DefaultTechnicalDebtModel();
- DefaultCharacteristic javaRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
- new DefaultCharacteristic().setKey("NEW_CHARACTERISTIC").setParent(javaRootCharacteristic);
- javaModel.addRootCharacteristic(javaRootCharacteristic);
-
- Reader javaModelReader = mock(Reader.class);
- when(debtModelPluginRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
- when(xmlImporter.importXML(eq(javaModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(javaModel);
- when(debtModelPluginRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
-
- manager.synchronize(ValidationMessages.create(), ruleCache);
- fail();
- } catch (Exception e) {
- assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The characteristic : NEW_CHARACTERISTIC cannot be used as it's not available in default characteristics.");
- } finally {
- verify(dao).selectEnabledCharacteristics();
- verifyNoMoreInteractions(dao);
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import com.google.common.collect.Lists;
-import org.fest.assertions.Assertions;
-import org.junit.Test;
-import org.mockito.Matchers;
-import org.mockito.Mockito;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.rules.RuleQuery;
-
-import java.util.Collections;
-
-public class TechnicalDebtRuleCacheTest {
-
- @Test
- public void lazy_load_rules_on_first_call() throws Exception {
-
- RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
- Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Collections.EMPTY_LIST);
-
- TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
- technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo1", "rule1"));
- technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo1", "rule1"));
-
- Mockito.verify(ruleFinder, Mockito.times(1)).findAll(Matchers.any(RuleQuery.class));
- }
-
- @Test
- public void return_matching_rule() throws Exception {
-
- Rule rule1 = Rule.create("repo1", "rule1");
- Rule rule2 = Rule.create("repo2", "rule2");
-
- RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
- Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(rule1, rule2));
-
- TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
- Rule actualRule1 = technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo1", "rule1"));
- Rule actualRule2 = technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo2", "rule2"));
-
- Assertions.assertThat(actualRule1).isEqualTo(rule1);
- Assertions.assertThat(actualRule2).isEqualTo(rule2);
- }
-
- @Test
- public void return_if_rule_exists() throws Exception {
-
- Rule rule1 = Rule.create("repo1", "rule1");
-
- RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
- Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(rule1));
-
- TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
-
- Assertions.assertThat(technicalDebtRuleCache.exists(RuleKey.of("repo1", "rule1"))).isTrue();
- Assertions.assertThat(technicalDebtRuleCache.exists(RuleKey.of("repo2", "rule2"))).isFalse();
- }
-
- @Test
- public void return_if_rule_id_exists() throws Exception {
-
- Rule rule1 = Rule.create("repo1", "rule1");
- rule1.setId(1);
-
- RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
- Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(rule1));
-
- TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
-
- Assertions.assertThat(technicalDebtRuleCache.exists(1)).isTrue();
- Assertions.assertThat(technicalDebtRuleCache.exists(2)).isFalse();
- }
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt;
-
-import com.google.common.base.Charsets;
-import com.google.common.collect.Lists;
-import com.google.common.io.Resources;
-import org.junit.Test;
-import org.mockito.Matchers;
-import org.mockito.Mockito;
-import org.sonar.api.rules.Rule;
-import org.sonar.api.rules.RuleFinder;
-import org.sonar.api.rules.RuleQuery;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.ValidationMessages;
-import org.sonar.api.utils.internal.WorkDuration;
-
-import java.io.IOException;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class TechnicalDebtXMLImporterTest {
-
- @Test
- public void import_characteristics() {
- TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
- String xml = getFileContent("import_characteristics.xml");
-
- ValidationMessages messages = ValidationMessages.create();
- DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
- assertThat(sqale.rootCharacteristics()).hasSize(2);
- assertThat(sqale.rootCharacteristics().get(0).key()).isEqualTo("PORTABILITY");
- assertThat(sqale.rootCharacteristics().get(1).key()).isEqualTo("MAINTAINABILITY");
-
- DefaultCharacteristic portability = sqale.characteristicByKey("PORTABILITY");
- assertThat(portability.order()).isEqualTo(1);
- assertThat(portability.children()).hasSize(2);
- assertThat(portability.children().get(0).key()).isEqualTo("COMPILER_RELATED_PORTABILITY");
- assertThat(sqale.characteristicByKey("COMPILER_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
- assertThat(portability.children().get(1).key()).isEqualTo("HARDWARE_RELATED_PORTABILITY");
- assertThat(sqale.characteristicByKey("HARDWARE_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
-
- DefaultCharacteristic maintainability = sqale.characteristicByKey("MAINTAINABILITY");
- assertThat(maintainability.order()).isEqualTo(2);
- assertThat(maintainability.children()).hasSize(1);
- assertThat(maintainability.children().get(0).key()).isEqualTo("READABILITY");
- assertThat(sqale.characteristicByKey("READABILITY").parent().key()).isEqualTo("MAINTAINABILITY");
- }
-
- @Test
- public void use_default_unit_when_no_unit() {
- TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
- String xml = getFileContent("use_default_unit_when_no_unit.xml");
-
- ValidationMessages messages = ValidationMessages.create();
- DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
- DefaultCharacteristic memoryEfficiency = sqale.characteristicByKey("MEMORY_EFFICIENCY");
- DefaultRequirement requirement = memoryEfficiency.requirements().get(0);
- assertThat(requirement.factorValue()).isEqualTo(3);
- assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
- assertThat(requirement.offsetValue()).isEqualTo(1);
- assertThat(requirement.offsetUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
- }
-
- @Test
- public void import_xml_with_linear_function() {
- TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
- String xml = getFileContent("shouldImportXML_with_linear.xml");
-
- ValidationMessages messages = ValidationMessages.create();
- DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
- checkXmlCorrectlyImported(sqale, messages);
- }
-
- @Test
- public void import_xml_with_linear_with_offset() {
- TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
- String xml = getFileContent("shouldImportXML_with_linear_with_offset.xml");
-
- ValidationMessages messages = ValidationMessages.create();
- DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
- checkXmlCorrectlyImported(sqale, 1, WorkDuration.UNIT.HOURS, messages);
- }
-
- @Test
- public void convert_deprecated_linear_with_threshold_function_by_linear_function() {
- TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
- String xml = getFileContent("shouldImportXML_with_deprecated_linear_with_threshold.xml");
-
- ValidationMessages messages = ValidationMessages.create();
- DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
- checkXmlCorrectlyImported(sqale, 0, WorkDuration.UNIT.DAYS, messages);
- assertThat(messages.getWarnings()).hasSize(1);
- }
-
- @Test
- public void ignore_deprecated_constant_per_file_function() {
- TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
- String xml = getFileContent("shouldImportXML_with_deprecated_constant_per_file.xml");
-
- ValidationMessages messages = ValidationMessages.create();
- DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
- assertThat(messages.getWarnings()).hasSize(1);
-
- // characteristics
- assertThat(sqale.rootCharacteristics()).hasSize(1);
- DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
- assertThat(efficiency.requirements()).isEmpty();
- }
-
- @Test
- public void ignore_requirement_on_root_characteristics() {
- TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
- String xml = getFileContent("ignore_requirement_on_root_characteristics.xml");
-
- ValidationMessages messages = ValidationMessages.create();
- DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
- assertThat(messages.getWarnings()).hasSize(1);
-
- assertThat(sqale.characteristics()).hasSize(1);
- DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
- assertThat(efficiency.requirements()).isEmpty();
- assertThat(messages.getWarnings().get(0)).contains("checkstyle");
- }
-
- @Test
- public void shouldBadlyFormattedImportXML() {
- TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
- String xml = getFileContent("shouldImportXML_badly-formatted.xml");
-
- ValidationMessages messages = ValidationMessages.create();
- DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
- checkXmlCorrectlyImported(sqale, messages);
- }
-
- @Test
- public void ignore_requirement_with_not_found_rule() {
- TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
- String xml = getFileContent("shouldLogWarningIfRuleNotFound.xml");
- ValidationMessages messages = ValidationMessages.create();
-
- DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
- assertThat(messages.getWarnings()).hasSize(1);
- assertThat(messages.getWarnings().get(0)).isEqualTo("Rule not found: [repository=findbugs, key=Foo]");
-
- // characteristics
- assertThat(sqale.rootCharacteristics()).hasSize(1);
- DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
- assertThat(efficiency.requirements()).isEmpty();
- assertThat(messages.getWarnings().get(0)).contains("findbugs");
- }
-
- @Test
- public void shouldNotifyOnUnexpectedValueTypeInXml() throws Exception {
-
- TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
-
- String xml = getFileContent("shouldRejectXML_with_invalid_value.xml");
- ValidationMessages messages = ValidationMessages.create();
-
- new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
-
- assertThat(messages.getErrors()).hasSize(1);
- assertThat(messages.getErrors().get(0)).isEqualTo("Cannot import value 'abc' for field factor - Expected a numeric value instead");
- }
-
- private TechnicalDebtRuleCache mockRuleCache() {
- RuleFinder finder = Mockito.mock(RuleFinder.class);
- Mockito.when(finder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(Rule.create("checkstyle", "Regexp", "Regular expression")));
- return new TechnicalDebtRuleCache(finder);
- }
-
- private void checkXmlCorrectlyImported(DefaultTechnicalDebtModel sqale, ValidationMessages messages) {
- checkXmlCorrectlyImported(sqale, 0, WorkDuration.UNIT.DAYS, messages);
- }
-
- private void checkXmlCorrectlyImported(DefaultTechnicalDebtModel sqale, Integer offsetValue, WorkDuration.UNIT offsetUnit, ValidationMessages messages) {
- assertThat(messages.getErrors()).isEmpty();
-
- // characteristics
- assertThat(sqale.rootCharacteristics()).hasSize(2);
- DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
- assertThat(efficiency.name()).isEqualTo("Efficiency");
-
- // sub-characteristics
- assertThat(efficiency.children()).hasSize(1);
- DefaultCharacteristic memoryEfficiency = sqale.characteristicByKey("MEMORY_EFFICIENCY");
- assertThat(memoryEfficiency.name()).isEqualTo("Memory use");
-
- // requirement
- assertThat(memoryEfficiency.requirements()).hasSize(1);
- DefaultRequirement requirement = memoryEfficiency.requirements().get(0);
- assertThat(requirement.ruleKey().repository()).isEqualTo("checkstyle");
- assertThat(requirement.ruleKey().rule()).isEqualTo("Regexp");
- assertThat(requirement.function()).isEqualTo("linear");
- assertThat(requirement.factorValue()).isEqualTo(3);
- assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.HOURS);
- assertThat(requirement.offsetValue()).isEqualTo(offsetValue);
- assertThat(requirement.offsetUnit()).isEqualTo(offsetUnit);
- assertThat(requirement.characteristic().key()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(requirement.rootCharacteristic().key()).isEqualTo("EFFICIENCY");
- }
-
- private String getFileContent(String file) {
- try {
- return Resources.toString(Resources.getResource(TechnicalDebtXMLImporterTest.class, "TechnicalDebtXMLImporterTest/" + file), Charsets.UTF_8);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt.db;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.core.persistence.AbstractDaoTestCase;
-
-import java.util.List;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class CharacteristicDaoTest extends AbstractDaoTestCase {
-
- private static final String[] EXCLUDED_COLUMNS = new String[]{"id", "depth", "description", "quality_model_id", "created_at", "updated_at"};
-
- CharacteristicDao dao;
-
- @Before
- public void createDao() {
- dao = new CharacteristicDao(getMyBatis());
- }
-
- @Test
- public void select_enabled_characteristics() {
- setupData("shared");
-
- List<CharacteristicDto> dtos = dao.selectEnabledCharacteristics();
-
- assertThat(dtos).hasSize(3);
-
- CharacteristicDto rootCharacteristic = dtos.get(0);
- assertThat(rootCharacteristic.getId()).isEqualTo(1);
- assertThat(rootCharacteristic.getKey()).isEqualTo("PORTABILITY");
- assertThat(rootCharacteristic.getName()).isEqualTo("Portability");
- assertThat(rootCharacteristic.getParentId()).isNull();
- assertThat(rootCharacteristic.getRootId()).isNull();
- assertThat(rootCharacteristic.getRuleId()).isNull();
- assertThat(rootCharacteristic.getOrder()).isEqualTo(1);
- assertThat(rootCharacteristic.isEnabled()).isTrue();
- assertThat(rootCharacteristic.getCreatedAt()).isNotNull();
- assertThat(rootCharacteristic.getUpdatedAt()).isNotNull();
-
- CharacteristicDto characteristic = dtos.get(1);
- assertThat(characteristic.getId()).isEqualTo(2);
- assertThat(characteristic.getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
- assertThat(characteristic.getName()).isEqualTo("Compiler related portability");
- assertThat(characteristic.getParentId()).isEqualTo(1);
- assertThat(characteristic.getRootId()).isEqualTo(1);
- assertThat(characteristic.getRuleId()).isNull();
- assertThat(characteristic.getOrder()).isNull();
- assertThat(characteristic.isEnabled()).isTrue();
- assertThat(characteristic.getCreatedAt()).isNotNull();
- assertThat(characteristic.getUpdatedAt()).isNotNull();
-
- CharacteristicDto requirement = dtos.get(2);
- assertThat(requirement.getId()).isEqualTo(3);
- assertThat(requirement.getKey()).isNull();
- assertThat(requirement.getName()).isNull();
- assertThat(requirement.getParentId()).isEqualTo(2);
- assertThat(requirement.getRootId()).isEqualTo(1);
- assertThat(requirement.getRuleId()).isEqualTo(1);
- assertThat(requirement.getOrder()).isNull();
- assertThat(requirement.getFunction()).isEqualTo("linear_offset");
- assertThat(requirement.getFactorValue()).isEqualTo(20.0);
- assertThat(requirement.getFactorUnit()).isEqualTo("mn");
- assertThat(requirement.getOffsetValue()).isEqualTo(30.0);
- assertThat(requirement.getOffsetUnit()).isEqualTo("h");
- assertThat(requirement.isEnabled()).isTrue();
- assertThat(requirement.getCreatedAt()).isNotNull();
- assertThat(requirement.getUpdatedAt()).isNull();
- }
-
- @Test
- public void select_characteristics() {
- setupData("shared");
-
- List<CharacteristicDto> dtos = dao.selectCharacteristics();
-
- assertThat(dtos).hasSize(2);
-
- CharacteristicDto rootCharacteristic = dtos.get(0);
- assertThat(rootCharacteristic.getId()).isEqualTo(1);
- assertThat(rootCharacteristic.getKey()).isEqualTo("PORTABILITY");
- assertThat(rootCharacteristic.getName()).isEqualTo("Portability");
- assertThat(rootCharacteristic.getParentId()).isNull();
- assertThat(rootCharacteristic.getRootId()).isNull();
- assertThat(rootCharacteristic.getOrder()).isEqualTo(1);
- assertThat(rootCharacteristic.isEnabled()).isTrue();
- assertThat(rootCharacteristic.getCreatedAt()).isNotNull();
- assertThat(rootCharacteristic.getUpdatedAt()).isNotNull();
-
- CharacteristicDto characteristic = dtos.get(1);
- assertThat(characteristic.getId()).isEqualTo(2);
- assertThat(characteristic.getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
- assertThat(characteristic.getName()).isEqualTo("Compiler related portability");
- assertThat(characteristic.getParentId()).isEqualTo(1);
- assertThat(characteristic.getRootId()).isEqualTo(1);
- assertThat(characteristic.getOrder()).isNull();
- assertThat(characteristic.isEnabled()).isTrue();
- assertThat(characteristic.getCreatedAt()).isNotNull();
- assertThat(characteristic.getUpdatedAt()).isNotNull();
- }
-
- @Test
- public void select_enabled_root_characteristics() {
- setupData("select_enabled_root_characteristics");
-
- List<CharacteristicDto> dtos = dao.selectEnabledRootCharacteristics();
-
- assertThat(dtos).hasSize(1);
-
- CharacteristicDto rootCharacteristic = dtos.get(0);
- assertThat(rootCharacteristic.getId()).isEqualTo(1);
- assertThat(rootCharacteristic.getKey()).isEqualTo("PORTABILITY");
- }
-
- @Test
- public void select_enabled_root_characteristics_order_by_characteristic_order() {
- setupData("select_enabled_root_characteristics_order_by_characteristic_order");
-
- List<CharacteristicDto> dtos = dao.selectEnabledRootCharacteristics();
-
- assertThat(dtos).hasSize(3);
- assertThat(dtos.get(0).getKey()).isEqualTo("TESTABILITY");
- assertThat(dtos.get(1).getKey()).isEqualTo("PORTABILITY");
- assertThat(dtos.get(2).getKey()).isEqualTo("MAINTAINABILITY");
- }
-
- @Test
- public void select_requirement() {
- setupData("shared");
-
- CharacteristicDto dto = dao.selectByRuleId(1);
-
- assertThat(dto).isNotNull();
- assertThat(dto.getId()).isEqualTo(3);
- assertThat(dto.getParentId()).isEqualTo(2);
- assertThat(dto.getRootId()).isEqualTo(1);
- }
-
- @Test
- public void select_characteristic_by_key() {
- setupData("shared");
-
- CharacteristicDto dto = dao.selectByKey("COMPILER_RELATED_PORTABILITY");
- assertThat(dto).isNotNull();
- assertThat(dto.getId()).isEqualTo(2);
- assertThat(dto.getParentId()).isEqualTo(1);
- assertThat(dto.getRootId()).isEqualTo(1);
-
- dto = dao.selectByKey("PORTABILITY");
- assertThat(dto).isNotNull();
- assertThat(dto.getId()).isEqualTo(1);
- assertThat(dto.getParentId()).isNull();
- assertThat(dto.getRootId()).isNull();
-
- assertThat(dao.selectByKey("UNKNOWN")).isNull();
- }
-
- @Test
- public void select_characteristic_by_id() {
- setupData("shared");
-
- assertThat(dao.selectById(2)).isNotNull();
- assertThat(dao.selectById(1)).isNotNull();
-
- assertThat(dao.selectById(10)).isNull();
- }
-
- @Test
- public void insert_characteristic() throws Exception {
- CharacteristicDto dto = new CharacteristicDto()
- .setKey("COMPILER_RELATED_PORTABILITY")
- .setName("Compiler related portability")
- .setOrder(1)
- .setEnabled(true)
- .setCreatedAt(DateUtils.parseDate("2013-11-20"));
-
- dao.insert(dto);
-
- checkTables("insert_characteristic", EXCLUDED_COLUMNS, "characteristics");
- }
-
- @Test
- public void insert_requirement() throws Exception {
- CharacteristicDto dto = new CharacteristicDto()
- .setParentId(2)
- .setRootId(1)
- .setRuleId(1)
- .setFunction("linear_offset")
- .setFactorValue(20.0)
- .setFactorUnit("mn")
- .setOffsetValue(30.0)
- .setOffsetUnit("h")
- .setCreatedAt(DateUtils.parseDate("2013-11-20"))
- .setEnabled(true);
-
- dao.insert(dto);
-
- checkTables("insert_requirement", EXCLUDED_COLUMNS, "characteristics");
- }
-
- @Test
- public void update_characteristic() throws Exception {
- setupData("update_characteristic");
-
- CharacteristicDto dto = new CharacteristicDto()
- .setId(1)
- // The Key should not be changed
- .setKey("NEW_KEY")
- .setName("New name")
- .setOrder(2)
- // Created date should not changed
- .setCreatedAt(DateUtils.parseDate("2013-11-22"))
- .setEnabled(false);
-
- dao.update(dto);
-
- checkTables("update_characteristic", new String[]{"id", "depth", "description", "quality_model_id", "updated_at"}, "characteristics");
- }
-
- @Test
- public void update_requirement() throws Exception {
- setupData("update_requirement");
-
- CharacteristicDto dto = new CharacteristicDto()
- .setId(1)
- .setParentId(3)
- .setRootId(1)
- .setRuleId(2)
- .setFunction("linear")
- .setFactorValue(21.0)
- .setFactorUnit("h")
- .setOffsetValue(null)
- .setOffsetUnit(null)
- // Created date should not changed
- .setCreatedAt(DateUtils.parseDate("2013-11-22"))
- .setEnabled(false);
-
- dao.update(dto);
-
- checkTables("update_requirement", EXCLUDED_COLUMNS, "characteristics");
- }
-
- @Test
- public void disable() throws Exception {
- setupData("disable");
-
- dao.disable(1);
-
- checkTables("disable", EXCLUDED_COLUMNS, "characteristics");
- }
-
-}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2013 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.core.debt.db;
-
-import org.junit.Test;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
-import org.sonar.api.utils.internal.WorkDuration;
-
-import java.util.Date;
-
-import static org.fest.assertions.Assertions.assertThat;
-
-public class CharacteristicDtoTest {
-
- @Test
- public void to_dto_from_requirement() throws Exception {
- DefaultRequirement requirement = new DefaultRequirement()
- .setFunction("constant_issue")
- .setFactorValue(10)
- .setFactorUnit(WorkDuration.UNIT.DAYS)
- .setOffsetValue(5)
- .setOffsetUnit(WorkDuration.UNIT.MINUTES)
- .setCreatedAt(new Date())
- .setUpdatedAt(new Date());
-
- CharacteristicDto dto = CharacteristicDto.toDto(requirement, 2, 1, 10);
- assertThat(dto.getRuleId()).isEqualTo(10);
- assertThat(dto.getParentId()).isEqualTo(2);
- assertThat(dto.getRootId()).isEqualTo(1);
- assertThat(dto.getFunction()).isEqualTo("constant_issue");
- assertThat(dto.getFactorValue()).isEqualTo(10d);
- assertThat(dto.getFactorUnit()).isEqualTo(CharacteristicDto.DAYS);
- assertThat(dto.getOffsetValue()).isEqualTo(5d);
- assertThat(dto.getOffsetUnit()).isEqualTo(CharacteristicDto.MINUTES);
- assertThat(dto.isEnabled()).isTrue();
- assertThat(dto.getCreatedAt()).isNotNull();
- assertThat(dto.getUpdatedAt()).isNotNull();
- }
-
- @Test
- public void to_requirement() throws Exception {
- CharacteristicDto requirementDto = new CharacteristicDto()
- .setId(3)
- .setParentId(2)
- .setRuleId(100)
- .setFunction("linear")
- .setFactorValue(2d)
- .setFactorUnit(CharacteristicDto.DAYS)
- .setOffsetValue(0d)
- .setOffsetUnit(CharacteristicDto.MINUTES)
- .setCreatedAt(new Date())
- .setUpdatedAt(new Date());
-
- DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
- .setKey("MEMORY_EFFICIENCY")
- .setName("Memory use");
-
- DefaultCharacteristic characteristic = new DefaultCharacteristic()
- .setKey("EFFICIENCY")
- .setName("Efficiency")
- .setParent(rootCharacteristic);
-
- DefaultRequirement requirement = requirementDto.toRequirement(RuleKey.of("squid", "S106"), characteristic, rootCharacteristic);
- assertThat(requirement.ruleKey()).isEqualTo(RuleKey.of("squid", "S106"));
- assertThat(requirement.characteristic()).isEqualTo(characteristic);
- assertThat(requirement.rootCharacteristic()).isEqualTo(rootCharacteristic);
- assertThat(requirement.function()).isEqualTo("linear");
- assertThat(requirement.factorValue()).isEqualTo(2);
- assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
- assertThat(requirement.offsetValue()).isEqualTo(0);
- assertThat(requirement.offsetUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
- assertThat(requirement.createdAt()).isNotNull();
- assertThat(requirement.updatedAt()).isNotNull();
-
- }
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import com.google.common.collect.Lists;
+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.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+
+import java.io.Reader;
+import java.util.Collections;
+import java.util.List;
+
+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 CharacteristicsDebtModelSynchronizerTest {
+
+ @Mock
+ MyBatis myBatis;
+
+ @Mock
+ SqlSession session;
+
+ @Mock
+ DebtModelPluginRepository debtModelPluginRepository;
+
+ @Mock
+ CharacteristicDao dao;
+
+ @Mock
+ CharacteristicsDebtModelXMLImporter xmlImporter;
+
+ Integer currentId = 1;
+
+ private DefaultTechnicalDebtModel defaultModel;
+
+ private CharacteristicsDebtModelSynchronizer manager;
+
+ @Before
+ public void initAndMerge() throws Exception {
+ when(myBatis.openSession()).thenReturn(session);
+
+ defaultModel = new DefaultTechnicalDebtModel();
+ Reader defaultModelReader = mock(Reader.class);
+ when(debtModelPluginRepository.createReaderForXMLFile("technical-debt")).thenReturn(defaultModelReader);
+ when(xmlImporter.importXML(eq(defaultModelReader), any(ValidationMessages.class))).thenReturn(defaultModel);
+
+ 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));
+
+
+ manager = new CharacteristicsDebtModelSynchronizer(myBatis, dao, debtModelPluginRepository, xmlImporter);
+ }
+
+ @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);
+
+ when(debtModelPluginRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
+ when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
+
+ manager.synchronize(ValidationMessages.create());
+
+ verify(dao).selectEnabledCharacteristics();
+ ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
+ verify(dao, times(2)).insert(characteristicCaptor.capture(), eq(session));
+
+ List<CharacteristicDto> result = characteristicCaptor.getAllValues();
+ assertThat(result.get(0).getKey()).isEqualTo("PORTABILITY");
+ assertThat(result.get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ verifyNoMoreInteractions(dao);
+ }
+
+ @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);
+
+ when(debtModelPluginRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
+ when(dao.selectEnabledCharacteristics()).thenReturn(Lists.newArrayList(new CharacteristicDto()));
+
+ manager.synchronize(ValidationMessages.create());
+
+ verify(dao, never()).insert(any(CharacteristicDto.class), eq(session));
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+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.utils.ValidationMessages;
+
+import java.io.IOException;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class CharacteristicsDebtModelXMLImporterTest {
+
+ @Test
+ public void import_characteristics() {
+ String xml = getFileContent("import_characteristics.xml");
+
+ ValidationMessages messages = ValidationMessages.create();
+ DefaultTechnicalDebtModel debtModel = new CharacteristicsDebtModelXMLImporter().importXML(xml, messages);
+
+ 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");
+ }
+
+ @Test
+ public void import_badly_formatted_xml() {
+ String xml = getFileContent("import_badly_formatted_xml.xml");
+
+ ValidationMessages messages = ValidationMessages.create();
+ DefaultTechnicalDebtModel debtModel = new CharacteristicsDebtModelXMLImporter().importXML(xml, messages);
+
+ checkXmlCorrectlyImported(debtModel, messages);
+ }
+
+ private void checkXmlCorrectlyImported(DefaultTechnicalDebtModel sqale, ValidationMessages messages) {
+ assertThat(messages.getErrors()).isEmpty();
+
+ // characteristics
+ assertThat(sqale.rootCharacteristics()).hasSize(2);
+ DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
+ assertThat(efficiency.name()).isEqualTo("Efficiency");
+
+ // sub-characteristics
+ assertThat(efficiency.children()).hasSize(1);
+ DefaultCharacteristic memoryEfficiency = sqale.characteristicByKey("MEMORY_EFFICIENCY");
+ assertThat(memoryEfficiency.name()).isEqualTo("Memory use");
+ }
+
+ private String getFileContent(String file) {
+ try {
+ return Resources.toString(Resources.getResource(CharacteristicsDebtModelXMLImporterTest.class, "CharacteristicsDebtModelXMLImporterTest/" + file), Charsets.UTF_8);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.io.Resources;
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.sonar.api.SonarPlugin;
+import org.sonar.api.platform.PluginMetadata;
+import org.sonar.api.platform.PluginRepository;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.Reader;
+import java.net.MalformedURLException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DebtModelPluginRepositoryTest {
+
+ private static final String TEST_XML_PREFIX_PATH = "org/sonar/core/technicaldebt/TechnicalDebtModelRepositoryTest/";
+
+ private DebtModelPluginRepository modelFinder;
+
+ @Test
+ public void test_component_initialization() throws Exception {
+ // we do have the "csharp-model.xml" file in src/test/resources
+ PluginMetadata csharpPluginMetadata = mock(PluginMetadata.class);
+ when(csharpPluginMetadata.getKey()).thenReturn("csharp");
+
+ // but we don' have the "php-model.xml" one
+ PluginMetadata phpPluginMetadata = mock(PluginMetadata.class);
+ when(phpPluginMetadata.getKey()).thenReturn("php");
+
+ PluginRepository repository = mock(PluginRepository.class);
+ when(repository.getMetadata()).thenReturn(Lists.newArrayList(csharpPluginMetadata, phpPluginMetadata));
+ FakePlugin fakePlugin = new FakePlugin();
+ when(repository.getPlugin(anyString())).thenReturn(fakePlugin);
+ modelFinder = new DebtModelPluginRepository(repository, TEST_XML_PREFIX_PATH);
+
+ // when
+ modelFinder.start();
+
+ // assert
+ Collection<String> contributingPluginList = modelFinder.getContributingPluginList();
+ assertThat(contributingPluginList.size()).isEqualTo(2);
+ assertThat(contributingPluginList).containsOnly("technical-debt", "csharp");
+ }
+
+ @Test
+ public void contributing_plugin_list() throws Exception {
+ initModel();
+ Collection<String> contributingPluginList = modelFinder.getContributingPluginList();
+ assertThat(contributingPluginList.size()).isEqualTo(2);
+ assertThat(contributingPluginList).contains("csharp", "java");
+ }
+
+ @Test
+ public void get_content_for_xml_file() throws Exception {
+ initModel();
+ Reader xmlFileReader = null;
+ try {
+ xmlFileReader = modelFinder.createReaderForXMLFile("csharp");
+ assertNotNull(xmlFileReader);
+ List<String> lines = IOUtils.readLines(xmlFileReader);
+ assertThat(lines.size()).isEqualTo(25);
+ assertThat(lines.get(0)).isEqualTo("<sqale>");
+ } catch (Exception e) {
+ fail("Should be able to read the XML file.");
+ } finally {
+ IOUtils.closeQuietly(xmlFileReader);
+ }
+ }
+
+ @Test
+ public void return_xml_file_path_for_plugin() throws Exception {
+ initModel();
+ assertThat(modelFinder.getXMLFilePath("foo")).isEqualTo(TEST_XML_PREFIX_PATH + "foo-model.xml");
+ }
+
+ @Test
+ public void contain_default_model() throws Exception {
+ modelFinder = new DebtModelPluginRepository(mock(PluginRepository.class));
+ modelFinder.start();
+ assertThat(modelFinder.getContributingPluginKeyToClassLoader().keySet()).containsOnly("technical-debt");
+ }
+
+ private void initModel() throws MalformedURLException {
+ Map<String, ClassLoader> contributingPluginKeyToClassLoader = Maps.newHashMap();
+ contributingPluginKeyToClassLoader.put("csharp", newClassLoader());
+ contributingPluginKeyToClassLoader.put("java", newClassLoader());
+ modelFinder = new DebtModelPluginRepository(contributingPluginKeyToClassLoader, TEST_XML_PREFIX_PATH);
+ }
+
+ private ClassLoader newClassLoader() throws MalformedURLException {
+ ClassLoader loader = mock(ClassLoader.class);
+ when(loader.getResourceAsStream(anyString())).thenAnswer(new Answer<InputStream>() {
+ public InputStream answer(InvocationOnMock invocation) throws Throwable {
+ return new FileInputStream(Resources.getResource((String) invocation.getArguments()[0]).getPath());
+ }
+ });
+ return loader;
+ }
+
+ class FakePlugin extends SonarPlugin {
+ public List getExtensions() {
+ return null;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+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.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.technicaldebt.server.Characteristic;
+import org.sonar.api.utils.internal.WorkDuration;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+
+import java.util.List;
+
+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.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DefaultTechnicalDebtManagerTest {
+
+ @Mock
+ CharacteristicDao dao;
+
+ @Mock
+ RuleFinder ruleFinder;
+
+ DefaultTechnicalDebtManager finder;
+
+ @Before
+ public void setUp() throws Exception {
+ finder = new DefaultTechnicalDebtManager(dao, ruleFinder);
+ }
+
+ @Test
+ public void find_root_characteristics() throws Exception {
+ CharacteristicDto rootCharacteristicDto = new CharacteristicDto()
+ .setId(1)
+ .setKey("MEMORY_EFFICIENCY")
+ .setName("Memory use");
+ when(dao.selectEnabledRootCharacteristics()).thenReturn(newArrayList(rootCharacteristicDto));
+
+ List<Characteristic> result = finder.findRootCharacteristics();
+ assertThat(result).hasSize(1);
+
+ Characteristic rootCharacteristic = result.get(0);
+ assertThat(rootCharacteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(rootCharacteristic.name()).isEqualTo("Memory use");
+ assertThat(rootCharacteristic.parentId()).isNull();
+ assertThat(rootCharacteristic.rootId()).isNull();
+ }
+
+ @Test
+ public void find_requirement() throws Exception {
+ Rule rule = Rule.create("repo", "key");
+ rule.setId(1);
+
+ when(dao.selectByRuleId(rule.getId())).thenReturn(
+ new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear")
+ .setFactorValue(30.0).setFactorUnit("mn")
+ .setOffsetValue(0.0).setOffsetUnit("d")
+ );
+
+ Characteristic result = finder.findRequirementByRule(rule);
+
+ assertThat(result.id()).isEqualTo(3);
+ assertThat(result.parentId()).isEqualTo(2);
+ assertThat(result.rootId()).isEqualTo(1);
+ assertThat(result.ruleKey()).isEqualTo(RuleKey.of("repo", "key"));
+ assertThat(result.function()).isEqualTo("linear");
+ assertThat(result.factorValue()).isEqualTo(30);
+ assertThat(result.factorUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
+ assertThat(result.offsetValue()).isEqualTo(0);
+ assertThat(result.offsetUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
+ }
+
+ @Test
+ public void not_find_requirement() throws Exception {
+ Rule rule = Rule.create("repo", "key");
+ rule.setId(1);
+
+ when(dao.selectByRuleId(rule.getId())).thenReturn(null);
+
+ Characteristic result = finder.findRequirementByRule(rule);
+ assertThat(result).isNull();
+ }
+
+ @Test
+ public void find_characteristic() throws Exception {
+ Rule rule = Rule.create("repo", "key");
+ rule.setId(1);
+
+ when(dao.selectById(2)).thenReturn(
+ new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setName("Compiler").setParentId(1).setRootId(1));
+
+ Characteristic result = finder.findCharacteristicById(2);
+
+ assertThat(result.id()).isEqualTo(2);
+ assertThat(result.parentId()).isEqualTo(1);
+ assertThat(result.rootId()).isEqualTo(1);
+ assertThat(result.key()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ assertThat(result.name()).isEqualTo("Compiler");
+ }
+
+ @Test
+ public void not_find_characteristic() throws Exception {
+ Rule rule = Rule.create("repo", "key");
+ rule.setId(1);
+
+ when(dao.selectById(rule.getId())).thenReturn(null);
+
+ Characteristic result = finder.findCharacteristicById(2);
+ assertThat(result).isNull();
+ }
+
+ @Test
+ public void find_requirement_by_rule_id() throws Exception {
+ Rule rule = Rule.create("repo", "key");
+ rule.setId(1);
+
+ when(ruleFinder.findById(1)).thenReturn(rule);
+
+ when(dao.selectByRuleId(rule.getId())).thenReturn(
+ new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear")
+ .setFactorValue(30.0).setFactorUnit("mn")
+ .setOffsetValue(0.0).setOffsetUnit("d")
+ );
+
+ Characteristic result = finder.findRequirementByRuleId(1);
+
+ assertThat(result.id()).isEqualTo(3);
+ assertThat(result.parentId()).isEqualTo(2);
+ assertThat(result.rootId()).isEqualTo(1);
+ assertThat(result.ruleKey()).isEqualTo(RuleKey.of("repo", "key"));
+ assertThat(result.function()).isEqualTo("linear");
+ assertThat(result.factorValue()).isEqualTo(30);
+ assertThat(result.factorUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
+ assertThat(result.offsetValue()).isEqualTo(0);
+ assertThat(result.offsetUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
+
+ }
+
+ @Test
+ public void not_find_requirement_by_rule_id_on_unknown_requirement() throws Exception {
+ Rule rule = Rule.create("repo", "key");
+ rule.setId(1);
+
+ when(ruleFinder.findById(1)).thenReturn(rule);
+
+ when(dao.selectByRuleId(rule.getId())).thenReturn(null);
+
+ assertThat(finder.findRequirementByRuleId(1)).isNull();
+ }
+
+ @Test
+ public void fail_to_find_requirement_by_rule_id_if_unknown_rule_id() throws Exception {
+ when(dao.selectByRuleId(1)).thenReturn(
+ new CharacteristicDto().setId(3).setRuleId(10).setParentId(2).setRootId(1).setFunction("linear").setFactorValue(30.0).setFactorUnit("mn"));
+ when(ruleFinder.findById(1)).thenReturn(null);
+ try {
+ finder.findRequirementByRuleId(1);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class);
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.internal.WorkDuration;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class DefaultTechnicalDebtModelTest {
+
+ private DefaultTechnicalDebtModel sqaleModel;
+
+ @Before
+ public void setUp() throws Exception {
+ sqaleModel = new DefaultTechnicalDebtModel();
+ }
+
+ @Test
+ public void get_root_characteristics() throws Exception {
+ DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
+ .setKey("MEMORY_EFFICIENCY")
+ .setName("Memory use");
+
+ new DefaultCharacteristic()
+ .setKey("EFFICIENCY")
+ .setName("Efficiency")
+ .setParent(rootCharacteristic);
+
+ sqaleModel.addRootCharacteristic(rootCharacteristic);
+
+ assertThat(sqaleModel.rootCharacteristics()).hasSize(1);
+ DefaultCharacteristic resultRootCharacteristic = sqaleModel.rootCharacteristics().get(0);
+ assertThat(resultRootCharacteristic).isEqualTo(rootCharacteristic);
+ }
+
+ @Test
+ public void get_characteristic_by_key() throws Exception {
+ DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
+ .setKey("MEMORY_EFFICIENCY")
+ .setName("Memory use");
+
+ DefaultCharacteristic characteristic = new DefaultCharacteristic()
+ .setKey("EFFICIENCY")
+ .setName("Efficiency")
+ .setParent(rootCharacteristic);
+
+ sqaleModel.addRootCharacteristic(rootCharacteristic);
+
+ assertThat(sqaleModel.characteristicByKey("MEMORY_EFFICIENCY")).isEqualTo(rootCharacteristic);
+ assertThat(sqaleModel.characteristicByKey("EFFICIENCY")).isEqualTo(characteristic);
+ assertThat(sqaleModel.characteristicByKey("EFFICIENCY").parent()).isEqualTo(rootCharacteristic);
+
+ assertThat(sqaleModel.characteristicByKey("UNKNOWN")).isNull();
+ }
+
+ @Test
+ public void get_requirement_by_rule_key() throws Exception {
+ DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
+ .setKey("MEMORY_EFFICIENCY")
+ .setName("Memory use");
+
+ DefaultCharacteristic characteristic = new DefaultCharacteristic()
+ .setKey("EFFICIENCY")
+ .setName("Efficiency")
+ .setParent(rootCharacteristic);
+
+ RuleKey ruleKey = RuleKey.of("checkstyle", "Regexp");
+ DefaultRequirement requirement = new DefaultRequirement()
+ .setCharacteristic(characteristic)
+ .setRuleKey(ruleKey)
+ .setFunction("linear")
+ .setFactorValue(2)
+ .setFactorUnit(WorkDuration.UNIT.HOURS)
+ .setOffsetValue(0)
+ .setOffsetUnit(WorkDuration.UNIT.HOURS);
+
+ sqaleModel.addRootCharacteristic(rootCharacteristic);
+
+ assertThat(sqaleModel.requirementsByRule(ruleKey)).isEqualTo(requirement);
+ assertThat(sqaleModel.requirementsByRule(RuleKey.of("not", "found"))).isNull();
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Resources;
+import org.junit.Test;
+import org.sonar.api.rule.RemediationFunction;
+import org.sonar.api.rule.RuleKey;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class RulesDebtModelXMLImporterTest {
+
+ RulesDebtModelXMLImporter importer = new RulesDebtModelXMLImporter();
+
+ @Test
+ public void import_rules() {
+ String xml = getFileContent("import_rules.xml");
+
+ List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+ assertThat(results).hasSize(2);
+ }
+
+ @Test
+ public void import_linear() {
+ String xml = getFileContent("import_linear.xml");
+
+ List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+ assertThat(results).hasSize(1);
+
+ RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+ assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
+ assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
+ assertThat(ruleDebt.factor()).isEqualTo("3h");
+ assertThat(ruleDebt.offset()).isEqualTo("0d");
+ }
+
+ @Test
+ public void import_linear_with_offset() {
+ String xml = getFileContent("import_linear_with_offset.xml");
+
+ List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+ assertThat(results).hasSize(1);
+
+ RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+ assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR_OFFSET);
+ assertThat(ruleDebt.factor()).isEqualTo("3h");
+ assertThat(ruleDebt.offset()).isEqualTo("1min");
+ }
+
+ @Test
+ public void import_constant_issue() {
+ String xml = getFileContent("import_constant_issue.xml");
+
+ List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+ assertThat(results).hasSize(1);
+
+ RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+ assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.CONSTANT_ISSUE);
+ assertThat(ruleDebt.factor()).isEqualTo("0d");
+ assertThat(ruleDebt.offset()).isEqualTo("3d");
+ }
+
+ @Test
+ public void use_default_unit_when_no_unit() {
+ String xml = getFileContent("use_default_unit_when_no_unit.xml");
+
+ List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+ assertThat(results).hasSize(1);
+
+ RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+ assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
+ assertThat(ruleDebt.factor()).isEqualTo("3d");
+ assertThat(ruleDebt.offset()).isEqualTo("1d");
+ }
+
+ @Test
+ public void replace_mn_by_min() {
+ String xml = getFileContent("replace_mn_by_min.xml");
+
+ List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+ assertThat(results).hasSize(1);
+
+ RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+ assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
+ assertThat(ruleDebt.factor()).isEqualTo("3min");
+ assertThat(ruleDebt.offset()).isEqualTo("0d");
+ }
+
+ @Test
+ public void convert_deprecated_linear_with_threshold_function_by_linear_function() {
+ String xml = getFileContent("convert_deprecated_linear_with_threshold_function_by_linear_function.xml");
+
+ List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+ assertThat(results).hasSize(1);
+
+ RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+ assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
+ assertThat(ruleDebt.factor()).isEqualTo("3h");
+ assertThat(ruleDebt.offset()).isEqualTo("0d");
+ }
+
+ @Test
+ public void ignore_deprecated_constant_per_file_function() {
+ String xml = getFileContent("ignore_deprecated_constant_per_file_function.xml");
+
+ List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+ assertThat(results).isEmpty();
+ }
+
+ @Test
+ public void ignore_rule_on_root_characteristics() {
+ String xml = getFileContent("ignore_rule_on_root_characteristics.xml");
+
+ List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+ assertThat(results).isEmpty();
+ }
+
+ @Test
+ public void import_badly_formatted_xml() {
+ String xml = getFileContent("import_badly_formatted_xml.xml");
+
+ List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+ assertThat(results).hasSize(1);
+
+ RulesDebtModelXMLImporter.RuleDebt ruleDebt = results.get(0);
+ assertThat(ruleDebt.characteristicKey()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(ruleDebt.ruleKey()).isEqualTo(RuleKey.of("checkstyle", "Regexp"));
+ assertThat(ruleDebt.function()).isEqualTo(RemediationFunction.LINEAR);
+ assertThat(ruleDebt.factor()).isEqualTo("3h");
+ assertThat(ruleDebt.offset()).isEqualTo("0d");
+ }
+
+ @Test
+ public void ignore_invalid_value() throws Exception {
+ String xml = getFileContent("ignore_invalid_value.xml");
+ List<RulesDebtModelXMLImporter.RuleDebt> results = importer.importXML(xml);
+ assertThat(results).isEmpty();
+ }
+
+ private String getFileContent(String file) {
+ try {
+ return Resources.toString(Resources.getResource(RulesDebtModelXMLImporterTest.class, "RulesDebtModelXMLImporterTest/" + file), Charsets.UTF_8);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import com.google.common.collect.Lists;
+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.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.api.utils.internal.WorkDuration;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+
+import java.io.Reader;
+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.fest.assertions.Fail.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TechnicalDebtModelSynchronizerTest {
+
+ @Mock
+ MyBatis myBatis;
+
+ @Mock
+ SqlSession session;
+
+ @Mock
+ DebtModelPluginRepository debtModelPluginRepository;
+
+ @Mock
+ TechnicalDebtRuleCache ruleCache;
+
+ @Mock
+ CharacteristicDao dao;
+
+ @Mock
+ TechnicalDebtXMLImporter xmlImporter;
+
+ Integer currentId = 1;
+
+ private DefaultTechnicalDebtModel defaultModel;
+
+ private TechnicalDebtModelSynchronizer manager;
+
+ @Before
+ public void initAndMerge() throws Exception {
+ when(myBatis.openSession()).thenReturn(session);
+
+ defaultModel = new DefaultTechnicalDebtModel();
+ Reader defaultModelReader = mock(Reader.class);
+ when(debtModelPluginRepository.createReaderForXMLFile("technical-debt")).thenReturn(defaultModelReader);
+ when(xmlImporter.importXML(eq(defaultModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(defaultModel);
+
+ 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));
+
+
+ manager = new TechnicalDebtModelSynchronizer(myBatis, dao, debtModelPluginRepository, xmlImporter);
+ }
+
+ @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);
+
+ when(debtModelPluginRepository.getContributingPluginList()).thenReturn(Collections.<String>emptyList());
+ when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
+
+ manager.synchronize(ValidationMessages.create(), ruleCache);
+
+ verify(dao).selectEnabledCharacteristics();
+ ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
+ verify(dao, times(2)).insert(characteristicCaptor.capture(), eq(session));
+
+ List<CharacteristicDto> result = characteristicCaptor.getAllValues();
+ assertThat(result.get(0).getKey()).isEqualTo("PORTABILITY");
+ assertThat(result.get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ verifyNoMoreInteractions(dao);
+ }
+
+ @Test
+ public void create_model_with_requirements_from_plugin_on_first_execution() throws Exception {
+ // Default model
+ DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+ new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic).setRoot(defaultRootCharacteristic);
+ defaultModel.addRootCharacteristic(defaultRootCharacteristic);
+
+ // No db model
+ when(dao.selectEnabledCharacteristics()).thenReturn(Lists.<CharacteristicDto>newArrayList());
+
+ // Java model
+ DefaultTechnicalDebtModel javaModel = new DefaultTechnicalDebtModel();
+ DefaultCharacteristic javaRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+ DefaultCharacteristic javaCharacteristic = new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(javaRootCharacteristic).setRoot(javaRootCharacteristic);
+ javaModel.addRootCharacteristic(javaRootCharacteristic);
+
+ Rule rule = Rule.create();
+ rule.setId(10);
+ RuleKey ruleKey = RuleKey.of("checkstyle", "import");
+ when(ruleCache.getByRuleKey(ruleKey)).thenReturn(rule);
+ new DefaultRequirement().setRuleKey(ruleKey)
+ .setFunction("linear")
+ .setFactorValue(30)
+ .setFactorUnit(WorkDuration.UNIT.MINUTES)
+ .setCharacteristic(javaCharacteristic)
+ .setRootCharacteristic(javaRootCharacteristic);
+
+ Reader javaModelReader = mock(Reader.class);
+ when(xmlImporter.importXML(eq(javaModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(javaModel);
+ when(debtModelPluginRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
+ when(debtModelPluginRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
+
+ manager.synchronize(ValidationMessages.create(), ruleCache);
+
+ verify(dao).selectEnabledCharacteristics();
+ ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
+ verify(dao, times(3)).insert(characteristicCaptor.capture(), eq(session));
+
+ List<CharacteristicDto> result = characteristicCaptor.getAllValues();
+ assertThat(result.get(0).getKey()).isEqualTo("PORTABILITY");
+ assertThat(result.get(1).getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ assertThat(result.get(2).getRuleId()).isEqualTo(10);
+ verifyNoMoreInteractions(dao);
+ }
+
+ @Test
+ public void add_new_requirements_from_plugin() throws Exception {
+ // Default model
+ DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+ new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic).setRoot(defaultRootCharacteristic);
+ defaultModel.addRootCharacteristic(defaultRootCharacteristic);
+
+ // Db model
+ CharacteristicDto dbRootCharacteristic = new CharacteristicDto().setId(1).setKey("PORTABILITY");
+ CharacteristicDto dbCharacteristic = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setParentId(1).setRootId(1);
+ CharacteristicDto requirement = new CharacteristicDto().setId(3)
+ .setRuleId(10).setParentId(2).setRootId(1).setFactorValue(30.0).setFactorUnit("mn");
+
+ RuleKey ruleKey1 = RuleKey.of("checkstyle", "import");
+ Rule rule1 = Rule.create();
+ rule1.setId(10);
+ when(ruleCache.getByRuleKey(ruleKey1)).thenReturn(rule1);
+ when(ruleCache.exists(10)).thenReturn(true);
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(requirement, dbCharacteristic, dbRootCharacteristic));
+
+ // Java model
+ DefaultTechnicalDebtModel javaModel = new DefaultTechnicalDebtModel();
+ DefaultCharacteristic javaRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+ DefaultCharacteristic javaCharacteristic = new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(javaRootCharacteristic).setRoot(javaRootCharacteristic);
+ javaModel.addRootCharacteristic(javaRootCharacteristic);
+
+ RuleKey ruleKey2 = RuleKey.of("checkstyle", "export");
+ Rule rule2 = Rule.create();
+ rule2.setId(11);
+ when(ruleCache.getByRuleKey(ruleKey2)).thenReturn(rule2);
+
+ // New requirement
+ new DefaultRequirement().setRuleKey(ruleKey2)
+ .setFunction("linear")
+ .setFactorValue(1)
+ .setFactorUnit(WorkDuration.UNIT.HOURS)
+ .setCharacteristic(javaCharacteristic)
+ .setRootCharacteristic(javaRootCharacteristic);
+
+ Reader javaModelReader = mock(Reader.class);
+ when(debtModelPluginRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
+ when(xmlImporter.importXML(eq(javaModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(javaModel);
+ when(debtModelPluginRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
+
+ manager.synchronize(ValidationMessages.create(), ruleCache);
+
+ verify(dao).selectEnabledCharacteristics();
+ ArgumentCaptor<CharacteristicDto> characteristicCaptor = ArgumentCaptor.forClass(CharacteristicDto.class);
+ verify(dao).insert(characteristicCaptor.capture(), eq(session));
+ assertThat(characteristicCaptor.getValue().getRuleId()).isEqualTo(11);
+ verifyNoMoreInteractions(dao);
+ }
+
+ @Test
+ public void disable_requirements_on_not_existing_rules() throws Exception {
+ // Default model
+ DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+ new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic);
+ defaultModel.addRootCharacteristic(defaultRootCharacteristic);
+
+ // Db model
+ CharacteristicDto dbRootCharacteristic = new CharacteristicDto().setId(1).setKey("PORTABILITY");
+ CharacteristicDto dbCharacteristic = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setParentId(1);
+ // To be disabled as rule does not exists
+ CharacteristicDto requirement = new CharacteristicDto().setId(3)
+ .setRuleId(10).setParentId(2).setFactorValue(30.0).setFactorUnit("mn");
+
+ when(ruleCache.exists(10)).thenReturn(false);
+
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(dbRootCharacteristic, dbCharacteristic, requirement));
+
+ manager.synchronize(ValidationMessages.create(), ruleCache);
+
+ verify(dao).selectEnabledCharacteristics();
+ verify(dao).disable(eq(3), eq(session));
+ verifyNoMoreInteractions(dao);
+ }
+
+ @Test
+ public void fail_when_plugin_defines_characteristics_not_defined_in_default_model() throws Exception {
+ try {
+ // Default model
+ DefaultCharacteristic defaultRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+ new DefaultCharacteristic().setKey("COMPILER_RELATED_PORTABILITY").setParent(defaultRootCharacteristic);
+ defaultModel.addRootCharacteristic(defaultRootCharacteristic);
+
+ // Db model
+ CharacteristicDto dbRootCharacteristic = new CharacteristicDto().setId(1).setKey("PORTABILITY");
+ CharacteristicDto dbCharacteristic = new CharacteristicDto().setId(2).setKey("COMPILER_RELATED_PORTABILITY").setParentId(1);
+ when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(dbRootCharacteristic, dbCharacteristic));
+
+ // Java model
+ DefaultTechnicalDebtModel javaModel = new DefaultTechnicalDebtModel();
+ DefaultCharacteristic javaRootCharacteristic = new DefaultCharacteristic().setKey("PORTABILITY");
+ new DefaultCharacteristic().setKey("NEW_CHARACTERISTIC").setParent(javaRootCharacteristic);
+ javaModel.addRootCharacteristic(javaRootCharacteristic);
+
+ Reader javaModelReader = mock(Reader.class);
+ when(debtModelPluginRepository.createReaderForXMLFile("java")).thenReturn(javaModelReader);
+ when(xmlImporter.importXML(eq(javaModelReader), any(ValidationMessages.class), eq(ruleCache))).thenReturn(javaModel);
+ when(debtModelPluginRepository.getContributingPluginList()).thenReturn(newArrayList("java"));
+
+ manager.synchronize(ValidationMessages.create(), ruleCache);
+ fail();
+ } catch (Exception e) {
+ assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("The characteristic : NEW_CHARACTERISTIC cannot be used as it's not available in default characteristics.");
+ } finally {
+ verify(dao).selectEnabledCharacteristics();
+ verifyNoMoreInteractions(dao);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import com.google.common.collect.Lists;
+import org.fest.assertions.Assertions;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.RuleQuery;
+
+import java.util.Collections;
+
+public class TechnicalDebtRuleCacheTest {
+
+ @Test
+ public void lazy_load_rules_on_first_call() throws Exception {
+
+ RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
+ Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Collections.EMPTY_LIST);
+
+ TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
+ technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo1", "rule1"));
+ technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo1", "rule1"));
+
+ Mockito.verify(ruleFinder, Mockito.times(1)).findAll(Matchers.any(RuleQuery.class));
+ }
+
+ @Test
+ public void return_matching_rule() throws Exception {
+
+ Rule rule1 = Rule.create("repo1", "rule1");
+ Rule rule2 = Rule.create("repo2", "rule2");
+
+ RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
+ Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(rule1, rule2));
+
+ TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
+ Rule actualRule1 = technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo1", "rule1"));
+ Rule actualRule2 = technicalDebtRuleCache.getByRuleKey(RuleKey.of("repo2", "rule2"));
+
+ Assertions.assertThat(actualRule1).isEqualTo(rule1);
+ Assertions.assertThat(actualRule2).isEqualTo(rule2);
+ }
+
+ @Test
+ public void return_if_rule_exists() throws Exception {
+
+ Rule rule1 = Rule.create("repo1", "rule1");
+
+ RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
+ Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(rule1));
+
+ TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
+
+ Assertions.assertThat(technicalDebtRuleCache.exists(RuleKey.of("repo1", "rule1"))).isTrue();
+ Assertions.assertThat(technicalDebtRuleCache.exists(RuleKey.of("repo2", "rule2"))).isFalse();
+ }
+
+ @Test
+ public void return_if_rule_id_exists() throws Exception {
+
+ Rule rule1 = Rule.create("repo1", "rule1");
+ rule1.setId(1);
+
+ RuleFinder ruleFinder = Mockito.mock(RuleFinder.class);
+ Mockito.when(ruleFinder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(rule1));
+
+ TechnicalDebtRuleCache technicalDebtRuleCache = new TechnicalDebtRuleCache(ruleFinder);
+
+ Assertions.assertThat(technicalDebtRuleCache.exists(1)).isTrue();
+ Assertions.assertThat(technicalDebtRuleCache.exists(2)).isFalse();
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.Lists;
+import com.google.common.io.Resources;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.RuleQuery;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.ValidationMessages;
+import org.sonar.api.utils.internal.WorkDuration;
+
+import java.io.IOException;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class TechnicalDebtXMLImporterTest {
+
+ @Test
+ public void import_characteristics() {
+ TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+ String xml = getFileContent("import_characteristics.xml");
+
+ ValidationMessages messages = ValidationMessages.create();
+ DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+ assertThat(sqale.rootCharacteristics()).hasSize(2);
+ assertThat(sqale.rootCharacteristics().get(0).key()).isEqualTo("PORTABILITY");
+ assertThat(sqale.rootCharacteristics().get(1).key()).isEqualTo("MAINTAINABILITY");
+
+ DefaultCharacteristic portability = sqale.characteristicByKey("PORTABILITY");
+ assertThat(portability.order()).isEqualTo(1);
+ assertThat(portability.children()).hasSize(2);
+ assertThat(portability.children().get(0).key()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ assertThat(sqale.characteristicByKey("COMPILER_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
+ assertThat(portability.children().get(1).key()).isEqualTo("HARDWARE_RELATED_PORTABILITY");
+ assertThat(sqale.characteristicByKey("HARDWARE_RELATED_PORTABILITY").parent().key()).isEqualTo("PORTABILITY");
+
+ DefaultCharacteristic maintainability = sqale.characteristicByKey("MAINTAINABILITY");
+ assertThat(maintainability.order()).isEqualTo(2);
+ assertThat(maintainability.children()).hasSize(1);
+ assertThat(maintainability.children().get(0).key()).isEqualTo("READABILITY");
+ assertThat(sqale.characteristicByKey("READABILITY").parent().key()).isEqualTo("MAINTAINABILITY");
+ }
+
+ @Test
+ public void use_default_unit_when_no_unit() {
+ TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+ String xml = getFileContent("use_default_unit_when_no_unit.xml");
+
+ ValidationMessages messages = ValidationMessages.create();
+ DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+ DefaultCharacteristic memoryEfficiency = sqale.characteristicByKey("MEMORY_EFFICIENCY");
+ DefaultRequirement requirement = memoryEfficiency.requirements().get(0);
+ assertThat(requirement.factorValue()).isEqualTo(3);
+ assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
+ assertThat(requirement.offsetValue()).isEqualTo(1);
+ assertThat(requirement.offsetUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
+ }
+
+ @Test
+ public void import_xml_with_linear_function() {
+ TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+ String xml = getFileContent("shouldImportXML_with_linear.xml");
+
+ ValidationMessages messages = ValidationMessages.create();
+ DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+ checkXmlCorrectlyImported(sqale, messages);
+ }
+
+ @Test
+ public void import_xml_with_linear_with_offset() {
+ TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+ String xml = getFileContent("shouldImportXML_with_linear_with_offset.xml");
+
+ ValidationMessages messages = ValidationMessages.create();
+ DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+ checkXmlCorrectlyImported(sqale, 1, WorkDuration.UNIT.HOURS, messages);
+ }
+
+ @Test
+ public void convert_deprecated_linear_with_threshold_function_by_linear_function() {
+ TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+ String xml = getFileContent("shouldImportXML_with_deprecated_linear_with_threshold.xml");
+
+ ValidationMessages messages = ValidationMessages.create();
+ DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+ checkXmlCorrectlyImported(sqale, 0, WorkDuration.UNIT.DAYS, messages);
+ assertThat(messages.getWarnings()).hasSize(1);
+ }
+
+ @Test
+ public void ignore_deprecated_constant_per_file_function() {
+ TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+ String xml = getFileContent("shouldImportXML_with_deprecated_constant_per_file.xml");
+
+ ValidationMessages messages = ValidationMessages.create();
+ DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+ assertThat(messages.getWarnings()).hasSize(1);
+
+ // characteristics
+ assertThat(sqale.rootCharacteristics()).hasSize(1);
+ DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
+ assertThat(efficiency.requirements()).isEmpty();
+ }
+
+ @Test
+ public void ignore_requirement_on_root_characteristics() {
+ TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+ String xml = getFileContent("ignore_requirement_on_root_characteristics.xml");
+
+ ValidationMessages messages = ValidationMessages.create();
+ DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+ assertThat(messages.getWarnings()).hasSize(1);
+
+ assertThat(sqale.characteristics()).hasSize(1);
+ DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
+ assertThat(efficiency.requirements()).isEmpty();
+ assertThat(messages.getWarnings().get(0)).contains("checkstyle");
+ }
+
+ @Test
+ public void shouldBadlyFormattedImportXML() {
+ TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+ String xml = getFileContent("shouldImportXML_badly-formatted.xml");
+
+ ValidationMessages messages = ValidationMessages.create();
+ DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+ checkXmlCorrectlyImported(sqale, messages);
+ }
+
+ @Test
+ public void ignore_requirement_with_not_found_rule() {
+ TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+ String xml = getFileContent("shouldLogWarningIfRuleNotFound.xml");
+ ValidationMessages messages = ValidationMessages.create();
+
+ DefaultTechnicalDebtModel sqale = new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+ assertThat(messages.getWarnings()).hasSize(1);
+ assertThat(messages.getWarnings().get(0)).isEqualTo("Rule not found: [repository=findbugs, key=Foo]");
+
+ // characteristics
+ assertThat(sqale.rootCharacteristics()).hasSize(1);
+ DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
+ assertThat(efficiency.requirements()).isEmpty();
+ assertThat(messages.getWarnings().get(0)).contains("findbugs");
+ }
+
+ @Test
+ public void shouldNotifyOnUnexpectedValueTypeInXml() throws Exception {
+
+ TechnicalDebtRuleCache technicalDebtRuleCache = mockRuleCache();
+
+ String xml = getFileContent("shouldRejectXML_with_invalid_value.xml");
+ ValidationMessages messages = ValidationMessages.create();
+
+ new TechnicalDebtXMLImporter().importXML(xml, messages, technicalDebtRuleCache);
+
+ assertThat(messages.getErrors()).hasSize(1);
+ assertThat(messages.getErrors().get(0)).isEqualTo("Cannot import value 'abc' for field factor - Expected a numeric value instead");
+ }
+
+ private TechnicalDebtRuleCache mockRuleCache() {
+ RuleFinder finder = Mockito.mock(RuleFinder.class);
+ Mockito.when(finder.findAll(Matchers.any(RuleQuery.class))).thenReturn(Lists.newArrayList(Rule.create("checkstyle", "Regexp", "Regular expression")));
+ return new TechnicalDebtRuleCache(finder);
+ }
+
+ private void checkXmlCorrectlyImported(DefaultTechnicalDebtModel sqale, ValidationMessages messages) {
+ checkXmlCorrectlyImported(sqale, 0, WorkDuration.UNIT.DAYS, messages);
+ }
+
+ private void checkXmlCorrectlyImported(DefaultTechnicalDebtModel sqale, Integer offsetValue, WorkDuration.UNIT offsetUnit, ValidationMessages messages) {
+ assertThat(messages.getErrors()).isEmpty();
+
+ // characteristics
+ assertThat(sqale.rootCharacteristics()).hasSize(2);
+ DefaultCharacteristic efficiency = sqale.characteristicByKey("EFFICIENCY");
+ assertThat(efficiency.name()).isEqualTo("Efficiency");
+
+ // sub-characteristics
+ assertThat(efficiency.children()).hasSize(1);
+ DefaultCharacteristic memoryEfficiency = sqale.characteristicByKey("MEMORY_EFFICIENCY");
+ assertThat(memoryEfficiency.name()).isEqualTo("Memory use");
+
+ // requirement
+ assertThat(memoryEfficiency.requirements()).hasSize(1);
+ DefaultRequirement requirement = memoryEfficiency.requirements().get(0);
+ assertThat(requirement.ruleKey().repository()).isEqualTo("checkstyle");
+ assertThat(requirement.ruleKey().rule()).isEqualTo("Regexp");
+ assertThat(requirement.function()).isEqualTo("linear");
+ assertThat(requirement.factorValue()).isEqualTo(3);
+ assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.HOURS);
+ assertThat(requirement.offsetValue()).isEqualTo(offsetValue);
+ assertThat(requirement.offsetUnit()).isEqualTo(offsetUnit);
+ assertThat(requirement.characteristic().key()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(requirement.rootCharacteristic().key()).isEqualTo("EFFICIENCY");
+ }
+
+ private String getFileContent(String file) {
+ try {
+ return Resources.toString(Resources.getResource(TechnicalDebtXMLImporterTest.class, "TechnicalDebtXMLImporterTest/" + file), Charsets.UTF_8);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt.db;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.core.persistence.AbstractDaoTestCase;
+
+import java.util.List;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class CharacteristicDaoTest extends AbstractDaoTestCase {
+
+ private static final String[] EXCLUDED_COLUMNS = new String[]{"id", "depth", "description", "quality_model_id", "created_at", "updated_at"};
+
+ CharacteristicDao dao;
+
+ @Before
+ public void createDao() {
+ dao = new CharacteristicDao(getMyBatis());
+ }
+
+ @Test
+ public void select_enabled_characteristics() {
+ setupData("shared");
+
+ List<CharacteristicDto> dtos = dao.selectEnabledCharacteristics();
+
+ assertThat(dtos).hasSize(3);
+
+ CharacteristicDto rootCharacteristic = dtos.get(0);
+ assertThat(rootCharacteristic.getId()).isEqualTo(1);
+ assertThat(rootCharacteristic.getKey()).isEqualTo("PORTABILITY");
+ assertThat(rootCharacteristic.getName()).isEqualTo("Portability");
+ assertThat(rootCharacteristic.getParentId()).isNull();
+ assertThat(rootCharacteristic.getRootId()).isNull();
+ assertThat(rootCharacteristic.getRuleId()).isNull();
+ assertThat(rootCharacteristic.getOrder()).isEqualTo(1);
+ assertThat(rootCharacteristic.isEnabled()).isTrue();
+ assertThat(rootCharacteristic.getCreatedAt()).isNotNull();
+ assertThat(rootCharacteristic.getUpdatedAt()).isNotNull();
+
+ CharacteristicDto characteristic = dtos.get(1);
+ assertThat(characteristic.getId()).isEqualTo(2);
+ assertThat(characteristic.getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ assertThat(characteristic.getName()).isEqualTo("Compiler related portability");
+ assertThat(characteristic.getParentId()).isEqualTo(1);
+ assertThat(characteristic.getRootId()).isEqualTo(1);
+ assertThat(characteristic.getRuleId()).isNull();
+ assertThat(characteristic.getOrder()).isNull();
+ assertThat(characteristic.isEnabled()).isTrue();
+ assertThat(characteristic.getCreatedAt()).isNotNull();
+ assertThat(characteristic.getUpdatedAt()).isNotNull();
+
+ CharacteristicDto requirement = dtos.get(2);
+ assertThat(requirement.getId()).isEqualTo(3);
+ assertThat(requirement.getKey()).isNull();
+ assertThat(requirement.getName()).isNull();
+ assertThat(requirement.getParentId()).isEqualTo(2);
+ assertThat(requirement.getRootId()).isEqualTo(1);
+ assertThat(requirement.getRuleId()).isEqualTo(1);
+ assertThat(requirement.getOrder()).isNull();
+ assertThat(requirement.getFunction()).isEqualTo("linear_offset");
+ assertThat(requirement.getFactorValue()).isEqualTo(20.0);
+ assertThat(requirement.getFactorUnit()).isEqualTo("mn");
+ assertThat(requirement.getOffsetValue()).isEqualTo(30.0);
+ assertThat(requirement.getOffsetUnit()).isEqualTo("h");
+ assertThat(requirement.isEnabled()).isTrue();
+ assertThat(requirement.getCreatedAt()).isNotNull();
+ assertThat(requirement.getUpdatedAt()).isNull();
+ }
+
+ @Test
+ public void select_characteristics() {
+ setupData("shared");
+
+ List<CharacteristicDto> dtos = dao.selectCharacteristics();
+
+ assertThat(dtos).hasSize(2);
+
+ CharacteristicDto rootCharacteristic = dtos.get(0);
+ assertThat(rootCharacteristic.getId()).isEqualTo(1);
+ assertThat(rootCharacteristic.getKey()).isEqualTo("PORTABILITY");
+ assertThat(rootCharacteristic.getName()).isEqualTo("Portability");
+ assertThat(rootCharacteristic.getParentId()).isNull();
+ assertThat(rootCharacteristic.getRootId()).isNull();
+ assertThat(rootCharacteristic.getOrder()).isEqualTo(1);
+ assertThat(rootCharacteristic.isEnabled()).isTrue();
+ assertThat(rootCharacteristic.getCreatedAt()).isNotNull();
+ assertThat(rootCharacteristic.getUpdatedAt()).isNotNull();
+
+ CharacteristicDto characteristic = dtos.get(1);
+ assertThat(characteristic.getId()).isEqualTo(2);
+ assertThat(characteristic.getKey()).isEqualTo("COMPILER_RELATED_PORTABILITY");
+ assertThat(characteristic.getName()).isEqualTo("Compiler related portability");
+ assertThat(characteristic.getParentId()).isEqualTo(1);
+ assertThat(characteristic.getRootId()).isEqualTo(1);
+ assertThat(characteristic.getOrder()).isNull();
+ assertThat(characteristic.isEnabled()).isTrue();
+ assertThat(characteristic.getCreatedAt()).isNotNull();
+ assertThat(characteristic.getUpdatedAt()).isNotNull();
+ }
+
+ @Test
+ public void select_enabled_root_characteristics() {
+ setupData("select_enabled_root_characteristics");
+
+ List<CharacteristicDto> dtos = dao.selectEnabledRootCharacteristics();
+
+ assertThat(dtos).hasSize(1);
+
+ CharacteristicDto rootCharacteristic = dtos.get(0);
+ assertThat(rootCharacteristic.getId()).isEqualTo(1);
+ assertThat(rootCharacteristic.getKey()).isEqualTo("PORTABILITY");
+ }
+
+ @Test
+ public void select_enabled_root_characteristics_order_by_characteristic_order() {
+ setupData("select_enabled_root_characteristics_order_by_characteristic_order");
+
+ List<CharacteristicDto> dtos = dao.selectEnabledRootCharacteristics();
+
+ assertThat(dtos).hasSize(3);
+ assertThat(dtos.get(0).getKey()).isEqualTo("TESTABILITY");
+ assertThat(dtos.get(1).getKey()).isEqualTo("PORTABILITY");
+ assertThat(dtos.get(2).getKey()).isEqualTo("MAINTAINABILITY");
+ }
+
+ @Test
+ public void select_requirement() {
+ setupData("shared");
+
+ CharacteristicDto dto = dao.selectByRuleId(1);
+
+ assertThat(dto).isNotNull();
+ assertThat(dto.getId()).isEqualTo(3);
+ assertThat(dto.getParentId()).isEqualTo(2);
+ assertThat(dto.getRootId()).isEqualTo(1);
+ }
+
+ @Test
+ public void select_characteristic_by_key() {
+ setupData("shared");
+
+ CharacteristicDto dto = dao.selectByKey("COMPILER_RELATED_PORTABILITY");
+ assertThat(dto).isNotNull();
+ assertThat(dto.getId()).isEqualTo(2);
+ assertThat(dto.getParentId()).isEqualTo(1);
+ assertThat(dto.getRootId()).isEqualTo(1);
+
+ dto = dao.selectByKey("PORTABILITY");
+ assertThat(dto).isNotNull();
+ assertThat(dto.getId()).isEqualTo(1);
+ assertThat(dto.getParentId()).isNull();
+ assertThat(dto.getRootId()).isNull();
+
+ assertThat(dao.selectByKey("UNKNOWN")).isNull();
+ }
+
+ @Test
+ public void select_characteristic_by_id() {
+ setupData("shared");
+
+ assertThat(dao.selectById(2)).isNotNull();
+ assertThat(dao.selectById(1)).isNotNull();
+
+ assertThat(dao.selectById(10)).isNull();
+ }
+
+ @Test
+ public void insert_characteristic() throws Exception {
+ CharacteristicDto dto = new CharacteristicDto()
+ .setKey("COMPILER_RELATED_PORTABILITY")
+ .setName("Compiler related portability")
+ .setOrder(1)
+ .setEnabled(true)
+ .setCreatedAt(DateUtils.parseDate("2013-11-20"));
+
+ dao.insert(dto);
+
+ checkTables("insert_characteristic", EXCLUDED_COLUMNS, "characteristics");
+ }
+
+ @Test
+ public void insert_requirement() throws Exception {
+ CharacteristicDto dto = new CharacteristicDto()
+ .setParentId(2)
+ .setRootId(1)
+ .setRuleId(1)
+ .setFunction("linear_offset")
+ .setFactorValue(20.0)
+ .setFactorUnit("mn")
+ .setOffsetValue(30.0)
+ .setOffsetUnit("h")
+ .setCreatedAt(DateUtils.parseDate("2013-11-20"))
+ .setEnabled(true);
+
+ dao.insert(dto);
+
+ checkTables("insert_requirement", EXCLUDED_COLUMNS, "characteristics");
+ }
+
+ @Test
+ public void update_characteristic() throws Exception {
+ setupData("update_characteristic");
+
+ CharacteristicDto dto = new CharacteristicDto()
+ .setId(1)
+ // The Key should not be changed
+ .setKey("NEW_KEY")
+ .setName("New name")
+ .setOrder(2)
+ // Created date should not changed
+ .setCreatedAt(DateUtils.parseDate("2013-11-22"))
+ .setEnabled(false);
+
+ dao.update(dto);
+
+ checkTables("update_characteristic", new String[]{"id", "depth", "description", "quality_model_id", "updated_at"}, "characteristics");
+ }
+
+ @Test
+ public void update_requirement() throws Exception {
+ setupData("update_requirement");
+
+ CharacteristicDto dto = new CharacteristicDto()
+ .setId(1)
+ .setParentId(3)
+ .setRootId(1)
+ .setRuleId(2)
+ .setFunction("linear")
+ .setFactorValue(21.0)
+ .setFactorUnit("h")
+ .setOffsetValue(null)
+ .setOffsetUnit(null)
+ // Created date should not changed
+ .setCreatedAt(DateUtils.parseDate("2013-11-22"))
+ .setEnabled(false);
+
+ dao.update(dto);
+
+ checkTables("update_requirement", EXCLUDED_COLUMNS, "characteristics");
+ }
+
+ @Test
+ public void disable() throws Exception {
+ setupData("disable");
+
+ dao.disable(1);
+
+ checkTables("disable", EXCLUDED_COLUMNS, "characteristics");
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.core.technicaldebt.db;
+
+import org.junit.Test;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
+import org.sonar.api.utils.internal.WorkDuration;
+
+import java.util.Date;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class CharacteristicDtoTest {
+
+ @Test
+ public void to_dto_from_requirement() throws Exception {
+ DefaultRequirement requirement = new DefaultRequirement()
+ .setFunction("constant_issue")
+ .setFactorValue(10)
+ .setFactorUnit(WorkDuration.UNIT.DAYS)
+ .setOffsetValue(5)
+ .setOffsetUnit(WorkDuration.UNIT.MINUTES)
+ .setCreatedAt(new Date())
+ .setUpdatedAt(new Date());
+
+ CharacteristicDto dto = CharacteristicDto.toDto(requirement, 2, 1, 10);
+ assertThat(dto.getRuleId()).isEqualTo(10);
+ assertThat(dto.getParentId()).isEqualTo(2);
+ assertThat(dto.getRootId()).isEqualTo(1);
+ assertThat(dto.getFunction()).isEqualTo("constant_issue");
+ assertThat(dto.getFactorValue()).isEqualTo(10d);
+ assertThat(dto.getFactorUnit()).isEqualTo(CharacteristicDto.DAYS);
+ assertThat(dto.getOffsetValue()).isEqualTo(5d);
+ assertThat(dto.getOffsetUnit()).isEqualTo(CharacteristicDto.MINUTES);
+ assertThat(dto.isEnabled()).isTrue();
+ assertThat(dto.getCreatedAt()).isNotNull();
+ assertThat(dto.getUpdatedAt()).isNotNull();
+ }
+
+ @Test
+ public void to_requirement() throws Exception {
+ CharacteristicDto requirementDto = new CharacteristicDto()
+ .setId(3)
+ .setParentId(2)
+ .setRuleId(100)
+ .setFunction("linear")
+ .setFactorValue(2d)
+ .setFactorUnit(CharacteristicDto.DAYS)
+ .setOffsetValue(0d)
+ .setOffsetUnit(CharacteristicDto.MINUTES)
+ .setCreatedAt(new Date())
+ .setUpdatedAt(new Date());
+
+ DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
+ .setKey("MEMORY_EFFICIENCY")
+ .setName("Memory use");
+
+ DefaultCharacteristic characteristic = new DefaultCharacteristic()
+ .setKey("EFFICIENCY")
+ .setName("Efficiency")
+ .setParent(rootCharacteristic);
+
+ DefaultRequirement requirement = requirementDto.toRequirement(RuleKey.of("squid", "S106"), characteristic, rootCharacteristic);
+ assertThat(requirement.ruleKey()).isEqualTo(RuleKey.of("squid", "S106"));
+ assertThat(requirement.characteristic()).isEqualTo(characteristic);
+ assertThat(requirement.rootCharacteristic()).isEqualTo(rootCharacteristic);
+ assertThat(requirement.function()).isEqualTo("linear");
+ assertThat(requirement.factorValue()).isEqualTo(2);
+ assertThat(requirement.factorUnit()).isEqualTo(WorkDuration.UNIT.DAYS);
+ assertThat(requirement.offsetValue()).isEqualTo(0);
+ assertThat(requirement.offsetUnit()).isEqualTo(WorkDuration.UNIT.MINUTES);
+ assertThat(requirement.createdAt()).isNotNull();
+ assertThat(requirement.updatedAt()).isNotNull();
+
+ }
+}
+++ /dev/null
-<!--
- ~ SonarQube, open source software quality management tool.
- ~ Copyright (C) 2008-2013 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.
- -->
-
-<sqale>
- <chc>
- <key>USABILITY
- </key>
- <name>Usability
- </name>
- <desc>Estimate usability
- </desc>
- </chc>
- <chc>
- <key>EFFICIENCY
- </key>
- <name>Efficiency
- </name>
- <chc>
- <key>MEMORY_EFFICIENCY
- </key>
- <name>Memory use
- </name>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>PORTABILITY</key>
- <name>Portability</name>
- <chc>
- <key>COMPILER_RELATED_PORTABILITY</key>
- <name>Compiler related portability</name>
- </chc>
- <chc>
- <key>HARDWARE_RELATED_PORTABILITY</key>
- <name>Hardware related portability</name>
- </chc>
- </chc>
- <chc>
- <key>MAINTAINABILITY</key>
- <name>Maintainability</name>
- <chc>
- <key>READABILITY</key>
- <name>Readability</name>
- </chc>
- </chc>
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFunction</key>
- <!-- Should be replaced by linear -->
- <txt>linear_threshold</txt>
- </prop>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <!-- Should be ignored -->
- <prop>
- <key>offset</key>
- <val>1.0</val>
- <txt>h</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <!-- Should be ignored -->
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>constant_resource</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>factor</key>
- <val>abc</val>
- </prop>
- <prop>
- <key>function</key>
- <txt>linear</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- </chc>
- </chc>
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY
- </key>
- <name>Usability
- </name>
- <desc>Estimate usability
- </desc>
- </chc>
- <chc>
- <key>EFFICIENCY
- </key>
- <name>Efficiency
- </name>
- <chc>
- <key>MEMORY_EFFICIENCY
- </key>
- <name>Memory use
- </name>
- <chc>
- <rule-repo>checkstyle
- </rule-repo>
- <rule-key>Regexp
- </rule-key>
- <prop>
- <key>remediationFactor
- </key>
- <val>3.0
- </val>
- <txt>h
- </txt>
- </prop>
- <prop>
- <key>remediationFunction
- </key>
- <txt>linear
- </txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>offset</key>
- <val>3.0</val>
- <txt>d</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>constant_issue</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<!--
- ~ SonarQube, open source software quality management tool.
- ~ Copyright (C) 2008-2013 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.
- -->
-
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear_offset</txt>
- </prop>
- <prop>
- <key>offset</key>
- <val>1.0</val>
- <txt>min</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- </chc>
- </chc>
- </chc>
- <chc>
- <key>PORTABILITY</key>
- <name>Portability</name>
- <chc>
- <key>COMPILER_RELATED_PORTABILITY</key>
- <name>Compiler related portability</name>
- </chc>
- <chc>
- <key>HARDWARE_RELATED_PORTABILITY</key>
- <name>Hardware related portability</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp2</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- <prop>
- <key>offset</key>
- <val>1.0</val>
- <txt>h</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-</sqale>
+++ /dev/null
-<!--
- ~ SonarQube, open source software quality management tool.
- ~ Copyright (C) 2008-2013 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.
- -->
-
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>mn</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- <prop>
- <key>offset</key>
- <val>1.0</val>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <rule-repo>gendarme</rule-repo>
- <rule-key>EnsureLocalDisposalRule</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>0.125</val>
- <txt>d</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- </chc>
- </chc>
-
-</sqale>
\ No newline at end of file
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <rule-repo>squid-cobol</rule-repo>
- <rule-key>CheckLoop</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>0.125</val>
- <txt>d</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- </chc>
- </chc>
-
-</sqale>
\ No newline at end of file
+++ /dev/null
-<sqale>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- </chc>
- </chc>
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>PORTABILITY</key>
- <name>Portability</name>
- <chc>
- <key>COMPILER_RELATED_PORTABILITY</key>
- <name>Compiler related portability</name>
- </chc>
- <chc>
- <key>HARDWARE_RELATED_PORTABILITY</key>
- <name>Hardware related portability</name>
- </chc>
- </chc>
- <chc>
- <key>MAINTAINABILITY</key>
- <name>Maintainability</name>
- <chc>
- <key>READABILITY</key>
- <name>Readability</name>
- </chc>
- </chc>
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY
- </key>
- <name>Usability
- </name>
- <desc>Estimate usability
- </desc>
- </chc>
- <chc>
- <key>EFFICIENCY
- </key>
- <name>Efficiency
- </name>
- <chc>
- <key>MEMORY_EFFICIENCY
- </key>
- <name>Memory use
- </name>
- <chc>
- <rule-repo>checkstyle
- </rule-repo>
- <rule-key>Regexp
- </rule-key>
- <prop>
- <key>remediationFactor
- </key>
- <val>3.0
- </val>
- <txt>h
- </txt>
- </prop>
- <prop>
- <key>remediationFunction
- </key>
- <txt>linear
- </txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <!-- Should be ignored -->
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>constant_resource</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFunction</key>
- <!-- Should be replaced by linear -->
- <txt>linear_threshold</txt>
- </prop>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <!-- Should be ignored -->
- <prop>
- <key>offset</key>
- <val>1.0</val>
- <txt>h</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- <prop>
- <key>offset</key>
- <val>1.0</val>
- <txt>h</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>findbugs</rule-repo>
- <rule-key>Foo</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- <txt>h</txt>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-</sqale>
+++ /dev/null
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>factor</key>
- <val>abc</val>
- </prop>
- <prop>
- <key>function</key>
- <txt>linear</txt>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<!--
- ~ SonarQube, open source software quality management tool.
- ~ Copyright (C) 2008-2013 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.
- -->
-
-<sqale>
- <chc>
- <key>USABILITY</key>
- <name>Usability</name>
- <desc>Estimate usability</desc>
- </chc>
- <chc>
- <key>EFFICIENCY</key>
- <name>Efficiency</name>
- <chc>
- <key>MEMORY_EFFICIENCY</key>
- <name>Memory use</name>
- <chc>
- <rule-repo>checkstyle</rule-repo>
- <rule-key>Regexp</rule-key>
- <prop>
- <key>remediationFactor</key>
- <val>3.0</val>
- </prop>
- <prop>
- <key>remediationFunction</key>
- <txt>linear</txt>
- </prop>
- <prop>
- <key>offset</key>
- <val>1.0</val>
- </prop>
- </chc>
- </chc>
- </chc>
-
-</sqale>
+++ /dev/null
-<dataset>
-
- <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
- created_at="2013-11-20" updated_at="[null]"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
- created_at="2013-11-20" updated_at="[null]"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <characteristics id="1" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1" characteristic_order="[null]"
- function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
- created_at="2013-11-20" updated_at="[null]"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
- <characteristics id="2" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="1" root_id="1" rule_id="[null]" characteristic_order="[null]"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
- <!-- requirement -->
- <characteristics id="3" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1"
- function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
- created_at="2013-11-20" updated_at="[null]"/>
-
- <!-- disabled characteristics -->
- <characteristics id="4" kee="DISABLED_CHARACTERISTIC" name="Disabled characteristic" parent_id="1" root_id="1" rule_id="[null]" characteristic_order="2"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
- <!-- disabled requirement -->
- <characteristics id="5" kee="[null]" name="[null]" parent_id="4" root_id="4" rule_id="1"
- function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
-
- <rules id="1" plugin_rule_key="import" plugin_config_key="regexp" plugin_name="checkstyle" description="[null]" priority="3" status="READY" cardinality="SINGLE" parent_id="[null]" name="Regular exp"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="2"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
- <characteristics id="2" kee="TESTABILITY" name="Testability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
- <characteristics id="3" kee="MAINTAINABILITY" name="Maintainability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="4"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <!-- Root characteristic -->
- <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
- <!-- Characteristic -->
- <characteristics id="2" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="1" root_id="1" rule_id="[null]" characteristic_order="[null]"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
- <!-- Requirement -->
- <characteristics id="3" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1"
- function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
- created_at="2013-11-20" updated_at="[null]"/>
-
- <!-- Disabled root characteristic -->
- <characteristics id="4" kee="DISABLED_ROOT_CHARACTERISTIC" name="Disabled root characteristic" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="2"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
- <!-- Disabled characteristic -->
- <characteristics id="5" kee="DISABLED_CHARACTERISTIC" name="Disabled characteristic" parent_id="4" root_id="4" rule_id="[null]" characteristic_order="[null]"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
- <!-- Disabled requirement -->
- <characteristics id="6" kee="[null]" name="[null]" parent_id="5" root_id="4" rule_id="1"
- function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
-
- <rules id="1" plugin_rule_key="import" plugin_config_key="regexp" plugin_name="checkstyle" description="[null]" priority="3" status="READY" cardinality="SINGLE" parent_id="[null]" name="Regular exp"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="New name" parent_id="[null]" rule_id="[null]" root_id="[null]" characteristic_order="2"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
- function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
- created_at="2013-11-20" updated_at="2013-11-20"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <characteristics id="1" kee="[null]" name="[null]" parent_id="3" root_id="1" rule_id="2" characteristic_order="[null]"
- function_key="linear" factor_value="21.0" factor_unit="h" offset_value="[null]" offset_unit="[null]" enabled="[false]"
- created_at="2013-11-20" updated_at="2013-11-22"/>
-
-</dataset>
+++ /dev/null
-<dataset>
-
- <characteristics id="1" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1" characteristic_order="[null]"
- function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
- created_at="2013-11-20" updated_at="[null]"/>
-
-</dataset>
--- /dev/null
+<!--
+ ~ SonarQube, open source software quality management tool.
+ ~ Copyright (C) 2008-2013 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.
+ -->
+
+<sqale>
+ <chc>
+ <key>USABILITY
+ </key>
+ <name>Usability
+ </name>
+ <desc>Estimate usability
+ </desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY
+ </key>
+ <name>Efficiency
+ </name>
+ <chc>
+ <key>MEMORY_EFFICIENCY
+ </key>
+ <name>Memory use
+ </name>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>PORTABILITY</key>
+ <name>Portability</name>
+ <chc>
+ <key>COMPILER_RELATED_PORTABILITY</key>
+ <name>Compiler related portability</name>
+ </chc>
+ <chc>
+ <key>HARDWARE_RELATED_PORTABILITY</key>
+ <name>Hardware related portability</name>
+ </chc>
+ </chc>
+ <chc>
+ <key>MAINTAINABILITY</key>
+ <name>Maintainability</name>
+ <chc>
+ <key>READABILITY</key>
+ <name>Readability</name>
+ </chc>
+ </chc>
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFunction</key>
+ <!-- Should be replaced by linear -->
+ <txt>linear_threshold</txt>
+ </prop>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <!-- Should be ignored -->
+ <prop>
+ <key>offset</key>
+ <val>1.0</val>
+ <txt>h</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <!-- Should be ignored -->
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>constant_resource</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>factor</key>
+ <val>abc</val>
+ </prop>
+ <prop>
+ <key>function</key>
+ <txt>linear</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ </chc>
+ </chc>
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY
+ </key>
+ <name>Usability
+ </name>
+ <desc>Estimate usability
+ </desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY
+ </key>
+ <name>Efficiency
+ </name>
+ <chc>
+ <key>MEMORY_EFFICIENCY
+ </key>
+ <name>Memory use
+ </name>
+ <chc>
+ <rule-repo>checkstyle
+ </rule-repo>
+ <rule-key>Regexp
+ </rule-key>
+ <prop>
+ <key>remediationFactor
+ </key>
+ <val>3.0
+ </val>
+ <txt>h
+ </txt>
+ </prop>
+ <prop>
+ <key>remediationFunction
+ </key>
+ <txt>linear
+ </txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>offset</key>
+ <val>3.0</val>
+ <txt>d</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>constant_issue</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<!--
+ ~ SonarQube, open source software quality management tool.
+ ~ Copyright (C) 2008-2013 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.
+ -->
+
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear_offset</txt>
+ </prop>
+ <prop>
+ <key>offset</key>
+ <val>1.0</val>
+ <txt>min</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+ <chc>
+ <key>PORTABILITY</key>
+ <name>Portability</name>
+ <chc>
+ <key>COMPILER_RELATED_PORTABILITY</key>
+ <name>Compiler related portability</name>
+ </chc>
+ <chc>
+ <key>HARDWARE_RELATED_PORTABILITY</key>
+ <name>Hardware related portability</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp2</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ <prop>
+ <key>offset</key>
+ <val>1.0</val>
+ <txt>h</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+</sqale>
--- /dev/null
+<!--
+ ~ SonarQube, open source software quality management tool.
+ ~ Copyright (C) 2008-2013 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.
+ -->
+
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>mn</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ <prop>
+ <key>offset</key>
+ <val>1.0</val>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <rule-repo>gendarme</rule-repo>
+ <rule-key>EnsureLocalDisposalRule</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>0.125</val>
+ <txt>d</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ </chc>
+ </chc>
+
+</sqale>
\ No newline at end of file
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <rule-repo>squid-cobol</rule-repo>
+ <rule-key>CheckLoop</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>0.125</val>
+ <txt>d</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ </chc>
+ </chc>
+
+</sqale>
\ No newline at end of file
--- /dev/null
+<sqale>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ </chc>
+ </chc>
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>PORTABILITY</key>
+ <name>Portability</name>
+ <chc>
+ <key>COMPILER_RELATED_PORTABILITY</key>
+ <name>Compiler related portability</name>
+ </chc>
+ <chc>
+ <key>HARDWARE_RELATED_PORTABILITY</key>
+ <name>Hardware related portability</name>
+ </chc>
+ </chc>
+ <chc>
+ <key>MAINTAINABILITY</key>
+ <name>Maintainability</name>
+ <chc>
+ <key>READABILITY</key>
+ <name>Readability</name>
+ </chc>
+ </chc>
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY
+ </key>
+ <name>Usability
+ </name>
+ <desc>Estimate usability
+ </desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY
+ </key>
+ <name>Efficiency
+ </name>
+ <chc>
+ <key>MEMORY_EFFICIENCY
+ </key>
+ <name>Memory use
+ </name>
+ <chc>
+ <rule-repo>checkstyle
+ </rule-repo>
+ <rule-key>Regexp
+ </rule-key>
+ <prop>
+ <key>remediationFactor
+ </key>
+ <val>3.0
+ </val>
+ <txt>h
+ </txt>
+ </prop>
+ <prop>
+ <key>remediationFunction
+ </key>
+ <txt>linear
+ </txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <!-- Should be ignored -->
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>constant_resource</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFunction</key>
+ <!-- Should be replaced by linear -->
+ <txt>linear_threshold</txt>
+ </prop>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <!-- Should be ignored -->
+ <prop>
+ <key>offset</key>
+ <val>1.0</val>
+ <txt>h</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ <prop>
+ <key>offset</key>
+ <val>1.0</val>
+ <txt>h</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>findbugs</rule-repo>
+ <rule-key>Foo</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ <txt>h</txt>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+</sqale>
--- /dev/null
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>factor</key>
+ <val>abc</val>
+ </prop>
+ <prop>
+ <key>function</key>
+ <txt>linear</txt>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<!--
+ ~ SonarQube, open source software quality management tool.
+ ~ Copyright (C) 2008-2013 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.
+ -->
+
+<sqale>
+ <chc>
+ <key>USABILITY</key>
+ <name>Usability</name>
+ <desc>Estimate usability</desc>
+ </chc>
+ <chc>
+ <key>EFFICIENCY</key>
+ <name>Efficiency</name>
+ <chc>
+ <key>MEMORY_EFFICIENCY</key>
+ <name>Memory use</name>
+ <chc>
+ <rule-repo>checkstyle</rule-repo>
+ <rule-key>Regexp</rule-key>
+ <prop>
+ <key>remediationFactor</key>
+ <val>3.0</val>
+ </prop>
+ <prop>
+ <key>remediationFunction</key>
+ <txt>linear</txt>
+ </prop>
+ <prop>
+ <key>offset</key>
+ <val>1.0</val>
+ </prop>
+ </chc>
+ </chc>
+ </chc>
+
+</sqale>
--- /dev/null
+<dataset>
+
+ <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
+ created_at="2013-11-20" updated_at="[null]"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <characteristics id="1" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1" characteristic_order="[null]"
+ function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+ <characteristics id="2" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="1" root_id="1" rule_id="[null]" characteristic_order="[null]"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+ <!-- requirement -->
+ <characteristics id="3" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1"
+ function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]"/>
+
+ <!-- disabled characteristics -->
+ <characteristics id="4" kee="DISABLED_CHARACTERISTIC" name="Disabled characteristic" parent_id="1" root_id="1" rule_id="[null]" characteristic_order="2"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+ <!-- disabled requirement -->
+ <characteristics id="5" kee="[null]" name="[null]" parent_id="4" root_id="4" rule_id="1"
+ function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+
+ <rules id="1" plugin_rule_key="import" plugin_config_key="regexp" plugin_name="checkstyle" description="[null]" priority="3" status="READY" cardinality="SINGLE" parent_id="[null]" name="Regular exp"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="2"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+ <characteristics id="2" kee="TESTABILITY" name="Testability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+ <characteristics id="3" kee="MAINTAINABILITY" name="Maintainability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="4"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <!-- Root characteristic -->
+ <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+ <!-- Characteristic -->
+ <characteristics id="2" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="1" root_id="1" rule_id="[null]" characteristic_order="[null]"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+ <!-- Requirement -->
+ <characteristics id="3" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1"
+ function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]"/>
+
+ <!-- Disabled root characteristic -->
+ <characteristics id="4" kee="DISABLED_ROOT_CHARACTERISTIC" name="Disabled root characteristic" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="2"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+ <!-- Disabled characteristic -->
+ <characteristics id="5" kee="DISABLED_CHARACTERISTIC" name="Disabled characteristic" parent_id="4" root_id="4" rule_id="[null]" characteristic_order="[null]"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+ <!-- Disabled requirement -->
+ <characteristics id="6" kee="[null]" name="[null]" parent_id="5" root_id="4" rule_id="1"
+ function_key="linear_offset" factor_value="30.0" factor_unit="mn" offset_value="20.0" offset_unit="h" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+
+ <rules id="1" plugin_rule_key="import" plugin_config_key="regexp" plugin_name="checkstyle" description="[null]" priority="3" status="READY" cardinality="SINGLE" parent_id="[null]" name="Regular exp"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="New name" parent_id="[null]" rule_id="[null]" root_id="[null]" characteristic_order="2"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <characteristics id="1" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="[null]" root_id="[null]" rule_id="[null]" characteristic_order="1"
+ function_key="[null]" factor_value="[null]" factor_unit="[null]" offset_value="[null]" offset_unit="[null]" enabled="[true]"
+ created_at="2013-11-20" updated_at="2013-11-20"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <characteristics id="1" kee="[null]" name="[null]" parent_id="3" root_id="1" rule_id="2" characteristic_order="[null]"
+ function_key="linear" factor_value="21.0" factor_unit="h" offset_value="[null]" offset_unit="[null]" enabled="[false]"
+ created_at="2013-11-20" updated_at="2013-11-22"/>
+
+</dataset>
--- /dev/null
+<dataset>
+
+ <characteristics id="1" kee="[null]" name="[null]" parent_id="2" root_id="1" rule_id="1" characteristic_order="[null]"
+ function_key="linear_offset" factor_value="20.0" factor_unit="mn" offset_value="30.0" offset_unit="h" enabled="[true]"
+ created_at="2013-11-20" updated_at="[null]"/>
+
+</dataset>
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
-import org.sonar.core.debt.DefaultTechnicalDebtManager;
import org.sonar.core.issue.workflow.Transition;
+import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager;
import org.sonar.markdown.Markdown;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.issue.ActionService;
import org.sonar.core.component.SnapshotPerspectives;
import org.sonar.core.component.db.ComponentDao;
import org.sonar.core.config.Logback;
-import org.sonar.core.debt.*;
import org.sonar.core.i18n.DefaultI18n;
import org.sonar.core.i18n.GwtI18n;
import org.sonar.core.i18n.RuleI18nManager;
import org.sonar.core.qualitygate.db.QualityGateDao;
import org.sonar.core.resource.DefaultResourcePermissions;
import org.sonar.core.rule.DefaultRuleFinder;
+import org.sonar.core.technicaldebt.*;
import org.sonar.core.test.TestPlanPerspectiveLoader;
import org.sonar.core.test.TestablePerspectiveLoader;
import org.sonar.core.timemachine.Periods;
import org.sonar.api.server.rule.RuleDefinitions;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.check.Cardinality;
-import org.sonar.core.debt.DebtModelPluginRepository;
-import org.sonar.core.debt.RulesDebtModelXMLImporter;
import org.sonar.core.i18n.RuleI18nManager;
+import org.sonar.core.technicaldebt.DebtModelPluginRepository;
+import org.sonar.core.technicaldebt.RulesDebtModelXMLImporter;
import javax.annotation.CheckForNull;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.TimeProfiler;
import org.sonar.check.Cardinality;
-import org.sonar.core.debt.db.CharacteristicDao;
-import org.sonar.core.debt.db.CharacteristicDto;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.qualityprofile.db.ActiveRuleDao;
import org.sonar.core.rule.*;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
import org.sonar.server.qualityprofile.ProfilesManager;
import org.sonar.server.startup.RegisterDebtCharacteristicModel;
import org.slf4j.LoggerFactory;
import org.sonar.api.utils.TimeProfiler;
import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.debt.CharacteristicsDebtModelSynchronizer;
+import org.sonar.core.technicaldebt.CharacteristicsDebtModelSynchronizer;
public class RegisterDebtCharacteristicModel {
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.utils.TimeProfiler;
import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.debt.TechnicalDebtModelSynchronizer;
-import org.sonar.core.debt.TechnicalDebtRuleCache;
+import org.sonar.core.technicaldebt.TechnicalDebtModelSynchronizer;
+import org.sonar.core.technicaldebt.TechnicalDebtRuleCache;
import org.sonar.server.rule.RuleRegistration;
public final class RegisterTechnicalDebtModel {
import org.sonar.api.ServerComponent;
import org.sonar.api.technicaldebt.server.Characteristic;
-import org.sonar.core.debt.DefaultTechnicalDebtManager;
+import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager;
import javax.annotation.CheckForNull;
import org.sonar.api.utils.Durations;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
-import org.sonar.core.debt.DefaultTechnicalDebtManager;
import org.sonar.core.issue.DefaultActionPlan;
import org.sonar.core.issue.DefaultIssueQueryResult;
import org.sonar.core.issue.workflow.Transition;
+import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager;
import org.sonar.core.user.DefaultUser;
import org.sonar.server.issue.ActionService;
import org.sonar.server.issue.IssueChangelog;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.RuleRepository;
import org.sonar.api.server.rule.RuleDefinitions;
-import org.sonar.core.debt.DebtModelPluginRepository;
-import org.sonar.core.debt.RulesDebtModelXMLImporter;
import org.sonar.core.i18n.RuleI18nManager;
+import org.sonar.core.technicaldebt.DebtModelPluginRepository;
+import org.sonar.core.technicaldebt.RulesDebtModelXMLImporter;
import java.io.Reader;
import java.util.Arrays;
import org.sonar.api.rule.Severity;
import org.sonar.api.server.rule.RuleDefinitions;
import org.sonar.api.utils.MessageException;
-import org.sonar.core.debt.db.CharacteristicDao;
import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.qualityprofile.db.ActiveRuleDao;
import org.sonar.core.rule.RuleDao;
import org.sonar.core.rule.RuleTagDao;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.server.qualityprofile.ProfilesManager;
import org.sonar.server.startup.RegisterDebtCharacteristicModel;
import org.junit.Test;
import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.debt.CharacteristicsDebtModelSynchronizer;
+import org.sonar.core.technicaldebt.CharacteristicsDebtModelSynchronizer;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.utils.ValidationMessages;
-import org.sonar.core.debt.TechnicalDebtModelSynchronizer;
-import org.sonar.core.debt.TechnicalDebtRuleCache;
+import org.sonar.core.technicaldebt.TechnicalDebtModelSynchronizer;
+import org.sonar.core.technicaldebt.TechnicalDebtRuleCache;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
import org.junit.Test;
import org.sonar.api.technicaldebt.server.Characteristic;
import org.sonar.api.technicaldebt.server.internal.DefaultCharacteristic;
-import org.sonar.core.debt.DefaultTechnicalDebtManager;
+import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager;
import java.util.List;