]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6588 Add DebtModelHolder
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 11 Jun 2015 15:57:37 +0000 (17:57 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 12 Jun 2015 11:27:32 +0000 (13:27 +0200)
13 files changed:
server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/debt/Characteristic.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/debt/CharacteristicImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/debt/DebtModelHolder.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/debt/DebtModelHolderImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/debt/MutableDebtModelHolder.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedDebtModelStep.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/debt/CharacteristicImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/debt/DebtModelHolderImplTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedDebtModelStepTest.java [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/step/FeedDebtModelStepTest/shared.xml [new file with mode: 0644]
sonar-plugin-api/src/main/java/org/sonar/api/batch/debt/internal/DefaultDebtModel.java

index 959f20b081ba518c04c22ac55f4b3eb584fe9957..a3f6dc9c0608dd94845086d26456af4c160a7d36 100644 (file)
@@ -40,6 +40,7 @@ import org.sonar.server.computation.batch.BatchReportReaderImpl;
 import org.sonar.server.computation.component.DbIdsRepository;
 import org.sonar.server.computation.component.ProjectSettingsRepository;
 import org.sonar.server.computation.component.TreeRootHolderImpl;
+import org.sonar.server.computation.debt.DebtModelHolderImpl;
 import org.sonar.server.computation.event.EventRepositoryImpl;
 import org.sonar.server.computation.issue.IssueCache;
 import org.sonar.server.computation.issue.IssueComputation;
@@ -131,6 +132,7 @@ public class ComputeEngineContainerImpl extends ComponentContainer implements Co
       TreeRootHolderImpl.class,
       PeriodsHolderImpl.class,
       QualityGateHolderImpl.class,
+      DebtModelHolderImpl.class,
 
       BatchReportReaderImpl.class,
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/debt/Characteristic.java b/server/sonar-server/src/main/java/org/sonar/server/computation/debt/Characteristic.java
new file mode 100644 (file)
index 0000000..c3c7904
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.debt;
+
+public interface Characteristic {
+
+  int id();
+
+  String key();
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/debt/CharacteristicImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/debt/CharacteristicImpl.java
new file mode 100644 (file)
index 0000000..1bbbc3f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.debt;
+
+import com.google.common.base.Preconditions;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+
+public class CharacteristicImpl implements Characteristic {
+
+  private int id;
+  private String key;
+
+  public CharacteristicImpl(int id, String key) {
+    Preconditions.checkNotNull(key, "key cannot be null");
+    this.id = id;
+    this.key = key;
+  }
+
+  @Override
+  public int id() {
+    return id;
+  }
+
+  @Override
+  public String key() {
+    return key;
+  }
+
+  @Override
+  public String toString() {
+    return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/debt/DebtModelHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/debt/DebtModelHolder.java
new file mode 100644 (file)
index 0000000..9e944b8
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.debt;
+
+import java.util.Collection;
+import javax.annotation.CheckForNull;
+
+public interface DebtModelHolder {
+
+  /**
+   * Return a characteristic by its key
+   *
+   * @throws IllegalStateException if the holder is empty
+   */
+  @CheckForNull
+  Characteristic characteristicByKey(String key);
+
+  /**
+   * Return the list of root characteristics
+   *
+   * @throws IllegalStateException if the holder is empty
+   */
+  Collection<Characteristic> rootCharacteristics();
+
+  /**
+   * Return the list of sub characteristics from a root characteristic key
+   *
+   * @throws IllegalStateException if the holder is empty
+   */
+  Collection<Characteristic> subCharacteristicsByRootKey(String rootCharacteristicKey);
+
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/debt/DebtModelHolderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/debt/DebtModelHolderImpl.java
new file mode 100644 (file)
index 0000000..d818806
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.debt;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DebtModelHolderImpl implements MutableDebtModelHolder {
+
+  private Multimap<Characteristic, Characteristic> subCharacteristicsByRootCharacteristic = ArrayListMultimap.create();
+  private Map<String, Characteristic> characteristicByKey = new HashMap<>();
+
+  @Override
+  public void addCharacteristics(Characteristic rootCharacteristic, List<? extends Characteristic> subCharacteristics) {
+    Preconditions.checkNotNull(rootCharacteristic, "rootCharacteristic cannot be null");
+    Preconditions.checkNotNull(subCharacteristics, "subCharacteristics cannot be null");
+    Preconditions.checkState(!subCharacteristics.isEmpty(), "subCharacteristics cannot be empty");
+    subCharacteristicsByRootCharacteristic.putAll(rootCharacteristic, subCharacteristics);
+
+    characteristicByKey.put(rootCharacteristic.key(), rootCharacteristic);
+    for (Characteristic characteristic : subCharacteristics) {
+      characteristicByKey.put(characteristic.key(), characteristic);
+    }
+  }
+
+  @Override
+  public Collection<Characteristic> rootCharacteristics() {
+    checkCharacteristicsAreInitialized();
+    return ImmutableSet.copyOf(subCharacteristicsByRootCharacteristic.keySet());
+  }
+
+  @Override
+  public Collection<Characteristic> subCharacteristicsByRootKey(String rootCharacteristicKey) {
+    checkCharacteristicsAreInitialized();
+    Characteristic rootCharacteristic = characteristicByKey.get(rootCharacteristicKey);
+    if (rootCharacteristic == null) {
+      return Collections.emptyList();
+    }
+    return ImmutableList.copyOf(subCharacteristicsByRootCharacteristic.get(rootCharacteristic));
+  }
+
+  @Override
+  public Characteristic characteristicByKey(String key) {
+    checkCharacteristicsAreInitialized();
+    return characteristicByKey.get(key);
+  }
+
+  private void checkCharacteristicsAreInitialized() {
+    Preconditions.checkState(!characteristicByKey.isEmpty(), "Characteristics have not been initialized yet");
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/debt/MutableDebtModelHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/debt/MutableDebtModelHolder.java
new file mode 100644 (file)
index 0000000..9d76c5d
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.debt;
+
+import java.util.List;
+
+public interface MutableDebtModelHolder extends DebtModelHolder {
+
+  /**
+   * Sets the characteristics in the {@link DebtModelHolder}. Settings characteristics more than once is not allowed
+   *
+   * @param rootCharacteristic a root {@link Characteristic}, can not be {@code null}
+   * @param subCharacteristics list of sub characteristics of the root characteristic, can not be {@code null}
+   *
+   * @throws NullPointerException if {@code rootCharacteristic} is {@code null}
+   * @throws NullPointerException if {@code subCharacteristics} is {@code null}
+   */
+  void addCharacteristics(Characteristic rootCharacteristic, List<? extends Characteristic> subCharacteristics);
+}
index 2d13c1a15296c5f104dcdf337327ed0e6bed43b4..cf2f04079fca1db7a77d9b5847a1ce30b47ba8b5 100644 (file)
@@ -43,6 +43,7 @@ public class ComputationSteps {
       BuildComponentTreeStep.class,
       FillComponentsStep.class,
       ValidateProjectStep.class,
+      FeedDebtModelStep.class,
 
       // Read report
       ParseReportStep.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedDebtModelStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedDebtModelStep.java
new file mode 100644 (file)
index 0000000..5240356
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.step;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import com.google.common.collect.Multimap;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.technicaldebt.db.CharacteristicDto;
+import org.sonar.server.computation.debt.Characteristic;
+import org.sonar.server.computation.debt.CharacteristicImpl;
+import org.sonar.server.computation.debt.MutableDebtModelHolder;
+import org.sonar.server.db.DbClient;
+
+/**
+ * Populates the {@link org.sonar.server.computation.debt.DebtModelHolder}
+ */
+public class FeedDebtModelStep implements ComputationStep {
+
+  private final DbClient dbClient;
+  private final MutableDebtModelHolder mutableDebtModelHolder;
+  private final Function<CharacteristicDto, Characteristic> dtoToCharFunction;
+  private final Function<CharacteristicDto, Integer> dtoToParentIdFunction;
+  private final Predicate<CharacteristicDto> isRootPredicate;
+
+  public FeedDebtModelStep(DbClient dbClient, MutableDebtModelHolder mutableDebtModelHolder) {
+    this.dbClient = dbClient;
+    this.mutableDebtModelHolder = mutableDebtModelHolder;
+    this.dtoToCharFunction = new Function<CharacteristicDto, Characteristic>() {
+      @Nullable
+      @Override
+      public Characteristic apply(@Nonnull CharacteristicDto characteristicDto) {
+        return toCharacteristic(characteristicDto);
+      }
+    };
+    this.dtoToParentIdFunction = new Function<CharacteristicDto, Integer>() {
+      @Nullable
+      @Override
+      public Integer apply(@Nonnull CharacteristicDto characteristicDto) {
+        Integer parentId = characteristicDto.getParentId();
+        return parentId != null ? parentId : null;
+      }
+    };
+    this.isRootPredicate = new Predicate<CharacteristicDto>() {
+      @Override
+      public boolean apply(@Nonnull CharacteristicDto characteristicDto) {
+        return characteristicDto.getParentId() == null;
+      }
+    };
+  }
+
+  @Override
+  public void execute() {
+    DbSession session = dbClient.openSession(false);
+    try {
+      feedDebtModel(session);
+    } finally {
+      session.close();
+    }
+  }
+
+  private void feedDebtModel(DbSession session) {
+    List<CharacteristicDto> characteristicDtos = dbClient.debtCharacteristicDao().selectEnabledCharacteristics(session);
+    List<CharacteristicDto> rootCharacteristicDtos = FluentIterable.from(characteristicDtos)
+      .filter(isRootPredicate).toList();
+    Multimap<Integer, CharacteristicDto> subCharacteristicDtosByParentId = FluentIterable.from(characteristicDtos)
+      .filter(Predicates.not(isRootPredicate))
+      .index(dtoToParentIdFunction);
+    for (CharacteristicDto rootCharacteristicDto : rootCharacteristicDtos) {
+      Collection<CharacteristicDto> subCharacteristicDtos = subCharacteristicDtosByParentId.get(rootCharacteristicDto.getId());
+
+      Characteristic rootCharacteristic = toCharacteristic(rootCharacteristicDto);
+      List<Characteristic> subCharacteristic = FluentIterable.from(subCharacteristicDtos)
+        .transform(dtoToCharFunction)
+        .toList();
+      mutableDebtModelHolder.addCharacteristics(rootCharacteristic, subCharacteristic);
+    }
+  }
+
+  private static Characteristic toCharacteristic(CharacteristicDto dto) {
+    return new CharacteristicImpl(dto.getId(), dto.getKey());
+  }
+
+  @Override
+  public String getDescription() {
+    return "Feed technical debt model";
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/debt/CharacteristicImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/debt/CharacteristicImplTest.java
new file mode 100644 (file)
index 0000000..28f11f9
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.debt;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CharacteristicImplTest {
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Test
+  public void test_getter_and_setter() throws Exception {
+    CharacteristicImpl characteristic = new CharacteristicImpl(1, "PORTABILITY");
+    assertThat(characteristic.id()).isEqualTo(1);
+    assertThat(characteristic.key()).isEqualTo("PORTABILITY");
+  }
+
+  @Test
+  public void test_to_string() throws Exception {
+    assertThat(new CharacteristicImpl(1, "PORTABILITY").toString()).isNotEmpty();
+  }
+
+  @Test
+  public void creating_a_new_characteristic_with_null_key_throws_a_NPE() throws Exception {
+    thrown.expect(NullPointerException.class);
+    thrown.expectMessage("key cannot be null");
+
+    new CharacteristicImpl(1, null);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/debt/DebtModelHolderImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/debt/DebtModelHolderImplTest.java
new file mode 100644 (file)
index 0000000..f902b4a
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.debt;
+
+import java.util.Arrays;
+import java.util.Collections;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DebtModelHolderImplTest {
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  DebtModelHolderImpl sut = new DebtModelHolderImpl();
+
+  @Test
+  public void add_characteristics() throws Exception {
+    sut.addCharacteristics(new CharacteristicImpl(1, "PORTABILITY"),
+      Arrays.asList(new CharacteristicImpl(2, "COMPILER_RELATED_PORTABILITY"), new CharacteristicImpl(4, "READABILITY")));
+    sut.addCharacteristics(new CharacteristicImpl(3, "MAINTAINABILITY"), Collections.singletonList(new CharacteristicImpl(4, "READABILITY")));
+
+    assertThat(sut.rootCharacteristics()).hasSize(2);
+    assertThat(sut.subCharacteristicsByRootKey("PORTABILITY")).hasSize(2);
+  }
+
+  @Test
+  public void add_characteristics_fail_with_a_NPE_if_root_characteristic_is_null() throws Exception {
+    thrown.expect(NullPointerException.class);
+    thrown.expectMessage("rootCharacteristic cannot be null");
+
+    sut.addCharacteristics(null, Collections.singletonList(new CharacteristicImpl(2, "COMPILER_RELATED_PORTABILITY")));
+  }
+
+  @Test
+  public void add_characteristics_fail_with_a_NPE_if_sub_characteristics_are_null() throws Exception {
+    thrown.expect(NullPointerException.class);
+    thrown.expectMessage("subCharacteristics cannot be null");
+
+    sut.addCharacteristics(new CharacteristicImpl(1, "PORTABILITY"), null);
+  }
+
+  @Test
+  public void add_characteristics_fail_with_a_ISE_if_sub_characteristics_are_empty() throws Exception {
+    thrown.expect(IllegalStateException.class);
+    thrown.expectMessage("subCharacteristics cannot be empty");
+
+    sut.addCharacteristics(new CharacteristicImpl(1, "PORTABILITY"), Collections.<Characteristic>emptyList());
+  }
+
+  @Test
+  public void get_characteristic_by_key() throws Exception {
+    sut.addCharacteristics(new CharacteristicImpl(1, "PORTABILITY"), Collections.singletonList(new CharacteristicImpl(2, "COMPILER_RELATED_PORTABILITY")));
+
+    assertThat(sut.characteristicByKey("PORTABILITY")).isNotNull();
+    assertThat(sut.characteristicByKey("COMPILER_RELATED_PORTABILITY")).isNotNull();
+    assertThat(sut.characteristicByKey("UNKNOWN")).isNull();
+  }
+
+  @Test
+  public void get_characteristic_by_key_throws_a_ISE_when_not_initialized() throws Exception {
+    thrown.expect(IllegalStateException.class);
+    thrown.expectMessage("Characteristics have not been initialized yet");
+
+    sut.characteristicByKey("PORTABILITY");
+  }
+
+  @Test
+  public void get_root_characteristics() throws Exception {
+    sut.addCharacteristics(new CharacteristicImpl(1, "PORTABILITY"),
+      Arrays.asList(new CharacteristicImpl(2, "COMPILER_RELATED_PORTABILITY"), new CharacteristicImpl(4, "READABILITY")));
+    sut.addCharacteristics(new CharacteristicImpl(3, "MAINTAINABILITY"), Collections.singletonList(new CharacteristicImpl(4, "READABILITY")));
+
+    assertThat(sut.rootCharacteristics()).hasSize(2);
+  }
+
+  @Test
+  public void get_root_characteristics_throws_a_ISE_when_not_initialized() throws Exception {
+    thrown.expect(IllegalStateException.class);
+    thrown.expectMessage("Characteristics have not been initialized yet");
+
+    sut.rootCharacteristics();
+  }
+
+  @Test
+  public void get_sub_characteristics_by_root_key() throws Exception {
+    sut.addCharacteristics(new CharacteristicImpl(1, "PORTABILITY"),
+      Arrays.asList(new CharacteristicImpl(2, "COMPILER_RELATED_PORTABILITY"), new CharacteristicImpl(4, "READABILITY")));
+
+    assertThat(sut.subCharacteristicsByRootKey("PORTABILITY")).hasSize(2);
+    assertThat(sut.subCharacteristicsByRootKey("UNKNOWN")).isEmpty();
+  }
+
+  @Test
+  public void get_sub_characteristics_by_root_key_throws_a_ISE_when_not_initialized() throws Exception {
+    thrown.expect(IllegalStateException.class);
+    thrown.expectMessage("Characteristics have not been initialized yet");
+
+    sut.subCharacteristicsByRootKey("PORTABILITY");
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedDebtModelStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/FeedDebtModelStepTest.java
new file mode 100644 (file)
index 0000000..c733d0a
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.step;
+
+import java.util.Collection;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.core.technicaldebt.db.CharacteristicDao;
+import org.sonar.server.computation.debt.Characteristic;
+import org.sonar.server.computation.debt.DebtModelHolderImpl;
+import org.sonar.server.computation.debt.MutableDebtModelHolder;
+import org.sonar.server.db.DbClient;
+import org.sonar.test.DbTests;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Category(DbTests.class)
+public class FeedDebtModelStepTest extends BaseStepTest {
+
+  @ClassRule
+  public static final DbTester dbTester = new DbTester();
+
+  DbClient dbClient;
+
+  DbSession dbSession;
+
+  MutableDebtModelHolder debtModelHolder = new DebtModelHolderImpl();
+
+  FeedDebtModelStep sut;
+
+  @Before
+  public void setUp() throws Exception {
+    dbTester.truncateTables();
+    dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new CharacteristicDao(dbTester.myBatis()));
+    dbSession = dbClient.openSession(false);
+
+    sut = new FeedDebtModelStep(dbClient, debtModelHolder);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    dbSession.close();
+  }
+
+  @Override
+  protected ComputationStep step() {
+    return sut;
+  }
+
+  @Test
+  public void feed_characteristics() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+
+    sut.execute();
+
+    Collection<Characteristic> rootChars = debtModelHolder.rootCharacteristics();
+    assertThat(rootChars).extracting("id").containsOnly(1);
+    assertThat(rootChars).extracting("key").containsOnly("PORTABILITY");
+
+    Collection<Characteristic> subChars = debtModelHolder.subCharacteristicsByRootKey("PORTABILITY");
+    assertThat(subChars).extracting("id").containsOnly(2, 3);
+    assertThat(subChars).extracting("key").containsOnly("COMPILER_RELATED_PORTABILITY", "HARDWARE_RELATED_PORTABILITY");
+  }
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/FeedDebtModelStepTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/FeedDebtModelStepTest/shared.xml
new file mode 100644 (file)
index 0000000..7b9e2db
--- /dev/null
@@ -0,0 +1,15 @@
+<dataset>
+
+  <!-- Root characteristic -->
+  <characteristics id="1" kee="PORTABILITY" name="Portability" parent_id="[null]" characteristic_order="1"
+                   enabled="[true]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+
+  <!-- Sub characteristics of root characteristic -->
+  <characteristics id="2" kee="COMPILER_RELATED_PORTABILITY" name="Compiler related portability" parent_id="1" characteristic_order="[null]"
+                   enabled="[true]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+  <characteristics id="3" kee="HARDWARE_RELATED_PORTABILITY" name="Hardware related portability " parent_id="1" characteristic_order="[null]"
+                   enabled="[true]"
+                   created_at="2013-11-20" updated_at="2013-11-22"/>
+</dataset>
index 853412ac236af3270a1a9e40f2cf17c1c20eb0fa..291b1f2a9fb44a07f79b43884bd6d780d784dad1 100644 (file)
@@ -24,13 +24,11 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Multimap;
+import java.util.List;
+import javax.annotation.CheckForNull;
 import org.sonar.api.batch.debt.DebtCharacteristic;
 import org.sonar.api.batch.debt.DebtModel;
 
-import javax.annotation.CheckForNull;
-
-import java.util.List;
-
 import static com.google.common.collect.Lists.newArrayList;
 
 public class DefaultDebtModel implements DebtModel {
@@ -50,6 +48,7 @@ public class DefaultDebtModel implements DebtModel {
     return this;
   }
 
+
   public DefaultDebtModel addSubCharacteristic(DebtCharacteristic subCharacteristic, String characteristicKey) {
     characteristicsByKey.put(characteristicKey, subCharacteristic);
     return this;