import org.sonar.server.computation.issue.LoadComponentUuidsHavingOpenIssuesVisitor;
import org.sonar.server.computation.issue.NewDebtAggregator;
import org.sonar.server.computation.issue.NewDebtCalculator;
-import org.sonar.server.computation.issue.RuleCacheLoader;
import org.sonar.server.computation.issue.RuleRepositoryImpl;
import org.sonar.server.computation.issue.RuleTagsCopier;
import org.sonar.server.computation.issue.ScmAccountToUser;
ScmInfoRepositoryImpl.class,
// issues
- RuleCacheLoader.class,
RuleRepositoryImpl.class,
ScmAccountToUserLoader.class,
ScmAccountToUser.class,
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.computation.issue;
-
-import com.google.common.base.Optional;
-import java.util.Collection;
-import java.util.Map;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.MyBatis;
-import org.sonar.db.rule.RuleDto;
-import org.sonar.server.util.cache.CacheLoader;
-
-public class RuleCacheLoader implements CacheLoader<RuleKey, Rule> {
-
- private final DbClient dbClient;
-
- public RuleCacheLoader(DbClient dbClient) {
- this.dbClient = dbClient;
- }
-
- @Override
- public Rule load(RuleKey key) {
- DbSession session = dbClient.openSession(false);
- try {
- Optional<RuleDto> dto = dbClient.ruleDao().selectByKey(session, key);
- if (dto.isPresent()) {
- return new RuleImpl(dto.get());
- }
- return null;
- } finally {
- MyBatis.closeQuietly(session);
- }
- }
-
- @Override
- public Map<RuleKey, Rule> loadAll(Collection<? extends RuleKey> keys) {
- throw new UnsupportedOperationException("Not implemented yet");
- }
-}
*/
package org.sonar.server.computation.issue;
+import com.google.common.base.Optional;
import org.sonar.api.rule.RuleKey;
+/**
+ * Repository of every rule in DB (including manual rules) whichever their status.
+ */
public interface RuleRepository {
+ /**
+ * @throws NullPointerException if {@code key} is {@code null}
+ * @throws IllegalArgumentException when there is no Rule for the specified RuleKey in the repository
+ */
Rule getByKey(RuleKey key);
- boolean hasKey(RuleKey key);
+ /**
+ * @throws IllegalArgumentException when there is no Rule for the specified RuleKey in the repository
+ */
+ Rule getById(int id);
+
+ /**
+ * @throws NullPointerException if {@code key} is {@code null}
+ */
+ Optional<Rule> findByKey(RuleKey key);
+
+ Optional<Rule> findById(int id);
}
*/
package org.sonar.server.computation.issue;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import javax.annotation.CheckForNull;
import org.sonar.api.rule.RuleKey;
-import org.sonar.server.util.cache.MemoryCache;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.rule.RuleDto;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
public class RuleRepositoryImpl implements RuleRepository {
- private final MemoryCache<RuleKey, Rule> cache;
+ @CheckForNull
+ private Map<RuleKey, Rule> rulesByKey;
+ @CheckForNull
+ private Map<Integer, Rule> rulesById;
+
+ private final DbClient dbClient;
- public RuleRepositoryImpl(RuleCacheLoader cacheLoader) {
- this.cache = new MemoryCache<>(cacheLoader);
+ public RuleRepositoryImpl(DbClient dbClient) {
+ this.dbClient = dbClient;
}
@Override
public Rule getByKey(RuleKey key) {
- return cache.get(key);
+ verifyKeyArgument(key);
+
+ ensureInitialized();
+
+ Rule rule = rulesByKey.get(key);
+ checkArgument(rule != null, "Can not find rule for key %s. This rule does not exist in DB", key);
+ return rule;
}
@Override
- public boolean hasKey(RuleKey key) {
- return cache.getNullable(key) != null;
+ public Optional<Rule> findByKey(RuleKey key) {
+ verifyKeyArgument(key);
+
+ ensureInitialized();
+
+ return Optional.fromNullable(rulesByKey.get(key));
}
+
+ @Override
+ public Rule getById(int id) {
+ ensureInitialized();
+
+ Rule rule = rulesById.get(id);
+ checkArgument(rule != null, "Can not find rule for id %s. This rule does not exist in DB", id);
+ return rule;
+ }
+
+ @Override
+ public Optional<Rule> findById(int id) {
+ ensureInitialized();
+
+ return Optional.fromNullable(rulesById.get(id));
+ }
+
+ private static void verifyKeyArgument(RuleKey key) {
+ requireNonNull(key, "RuleKey can not be null");
+ }
+
+ private void ensureInitialized() {
+ if (rulesByKey == null) {
+ DbSession dbSession = dbClient.openSession(false);
+ try {
+ loadRulesFromDb(dbSession);
+ } finally {
+ dbClient.closeSession(dbSession);
+ }
+ }
+ }
+
+ private void loadRulesFromDb(DbSession dbSession) {
+ ImmutableMap.Builder<RuleKey, Rule> rulesByKeyBuilder = ImmutableMap.builder();
+ ImmutableMap.Builder<Integer, Rule> rulesByIdBuilder = ImmutableMap.builder();
+ for (RuleDto ruleDto : dbClient.ruleDao().selectAll(dbSession)) {
+ Rule rule = new RuleImpl(ruleDto);
+ rulesByKeyBuilder.put(ruleDto.getKey(), rule);
+ rulesByIdBuilder.put(ruleDto.getId(), rule);
+ }
+ this.rulesByKey = rulesByKeyBuilder.build();
+ this.rulesById = rulesByIdBuilder.build();
+ }
+
}
*/
package org.sonar.server.computation.step;
+import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import java.util.ArrayList;
import java.util.HashMap;
private class IsValid implements Predicate<ActiveRule> {
@Override
public boolean apply(@Nonnull ActiveRule input) {
- if (ruleRepository.hasKey(input.getRuleKey())) {
- Rule rule = ruleRepository.getByKey(input.getRuleKey());
- return rule.getStatus() != RuleStatus.REMOVED;
- }
- return false;
+ Optional<Rule> rule = ruleRepository.findByKey(input.getRuleKey());
+ return rule.isPresent() && rule.get().getStatus() != RuleStatus.REMOVED;
}
}
public DumbRule(RuleKey key) {
this.key = key;
+ this.id = key.hashCode();
}
@Override
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.computation.issue;
-
-import java.util.Collections;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbTester;
-import org.sonar.test.DbTests;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-
-@Category(DbTests.class)
-public class RuleCacheLoaderTest {
-
- @org.junit.Rule
- public DbTester dbTester = DbTester.create(System2.INSTANCE);
-
- @Before
- public void setUp() {
- dbTester.truncateTables();
- }
-
- @Test
- public void load_by_key() {
- dbTester.prepareDbUnit(getClass(), "shared.xml");
- RuleCacheLoader loader = new RuleCacheLoader(dbTester.getDbClient());
-
- Rule javaRule = loader.load(RuleKey.of("java", "JAV01"));
- assertThat(javaRule.getName()).isEqualTo("Java One");
-
- Rule jsRule = loader.load(RuleKey.of("js", "JS01"));
- assertThat(jsRule.getName()).isEqualTo("JS One");
-
- assertThat(loader.load(RuleKey.of("java", "MISSING"))).isNull();
- }
-
- @Test
- public void load_by_keys_is_not_supported() {
- RuleCacheLoader loader = new RuleCacheLoader(dbTester.getDbClient());
- try {
- loader.loadAll(Collections.<RuleKey>emptyList());
- fail();
- } catch (UnsupportedOperationException e) {
- // see RuleDao#getByKeys()
- }
- }
-
-}
*/
package org.sonar.server.computation.issue;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import org.junit.Before;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rule.RuleStatus;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.rule.RuleDao;
+import org.sonar.db.rule.RuleDto;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.guava.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.internal.verification.VerificationModeFactory.times;
-import static org.sonar.db.rule.RuleTesting.XOO_X1;
-import static org.sonar.db.rule.RuleTesting.XOO_X2;
public class RuleRepositoryImplTest {
- RuleCacheLoader cacheLoader = mock(RuleCacheLoader.class);
- RuleRepositoryImpl underTest = new RuleRepositoryImpl(cacheLoader);
+ private static final RuleDto AB_RULE = createABRuleDto();
+ private static final RuleKey AC_RULE_KEY = RuleKey.of("a", "c");
+ private static final int AC_RULE_ID = 684;
+
+ @org.junit.Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private DbClient dbClient = mock(DbClient.class);
+ private DbSession dbSession = mock(DbSession.class);
+ private RuleDao ruleDao = mock(RuleDao.class);
+
+ RuleRepositoryImpl underTest = new RuleRepositoryImpl(dbClient);
+
+ @Before
+ public void setUp() throws Exception {
+ when(dbClient.openSession(anyBoolean())).thenReturn(dbSession);
+ when(dbClient.ruleDao()).thenReturn(ruleDao);
+ when(ruleDao.selectAll(any(DbSession.class))).thenReturn(ImmutableList.of(AB_RULE));
+ }
+
+ @Test
+ public void constructor_does_not_query_DB_to_retrieve_rules() {
+ verifyNoMoreInteractions(dbClient);
+ }
+
+ @Test
+ public void first_call_to_getByKey_triggers_call_to_db_and_any_subsequent_get_or_find_call_does_not() {
+ underTest.getByKey(AB_RULE.getKey());
+
+ verify(ruleDao, times(1)).selectAll(any(DbSession.class));
+
+ verifyNoMethodCallTriggersCallToDB();
+ }
+
+ @Test
+ public void first_call_to_findByKey_triggers_call_to_db_and_any_subsequent_get_or_find_call_does_not() {
+ underTest.findByKey(AB_RULE.getKey());
+
+ verify(ruleDao, times(1)).selectAll(any(DbSession.class));
+
+ verifyNoMethodCallTriggersCallToDB();
+ }
+
+ @Test
+ public void first_call_to_getById_triggers_call_to_db_and_any_subsequent_get_or_find_call_does_not() {
+ underTest.getById(AB_RULE.getId());
+
+ verify(ruleDao, times(1)).selectAll(any(DbSession.class));
+
+ verifyNoMethodCallTriggersCallToDB();
+ }
+
+ @Test
+ public void first_call_to_findById_triggers_call_to_db_and_any_subsequent_get_or_find_call_does_not() {
+ underTest.findById(AB_RULE.getId());
+
+ verify(ruleDao, times(1)).selectAll(any(DbSession.class));
+
+ verifyNoMethodCallTriggersCallToDB();
+ }
+
+ @Test
+ public void getByKey_throws_NPE_if_key_argument_is_null() {
+ expectNullRuleKeyNPE();
+
+ underTest.getByKey(null);
+ }
+
+ @Test
+ public void getByKey_does_not_call_DB_if_key_argument_is_null() {
+ try {
+ underTest.getByKey(null);
+ } catch (NullPointerException e) {
+ assertNoCallToDb();
+ }
+ }
+
+ @Test
+ public void getByKey_returns_Rule_if_it_exists_in_DB() {
+ Rule rule = underTest.getByKey(AB_RULE.getKey());
+
+ assertIsABRule(rule);
+ }
+
+ @Test
+ public void getByKey_throws_IAE_if_rules_does_not_exist_in_DB() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Can not find rule for key a:c. This rule does not exist in DB");
+
+ underTest.getByKey(AC_RULE_KEY);
+ }
+
+ @Test
+ public void findByKey_throws_NPE_if_key_argument_is_null() {
+ expectNullRuleKeyNPE();
+
+ underTest.findByKey(null);
+ }
+
+ @Test
+ public void findByKey_does_not_call_DB_if_key_argument_is_null() {
+ try {
+ underTest.findByKey(null);
+ } catch (NullPointerException e) {
+ assertNoCallToDb();
+ }
+ }
+
+ @Test
+ public void findByKey_returns_absent_if_rule_does_not_exist_in_DB() {
+ Optional<Rule> rule = underTest.findByKey(AC_RULE_KEY);
+
+ assertThat(rule).isAbsent();
+ }
+
+ @Test
+ public void findByKey_returns_Rule_if_it_exists_in_DB() {
+ Optional<Rule> rule = underTest.findByKey(AB_RULE.getKey());
+
+ assertIsABRule(rule.get());
+ }
+
+ @Test
+ public void getById_returns_Rule_if_it_exists_in_DB() {
+ Rule rule = underTest.getById(AB_RULE.getId());
+
+ assertIsABRule(rule);
+ }
@Test
- public void getByKey() {
- when(cacheLoader.load(XOO_X1)).thenReturn(new DumbRule(XOO_X1));
+ public void getById_throws_IAE_if_rules_does_not_exist_in_DB() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Can not find rule for id " + AC_RULE_ID + ". This rule does not exist in DB");
- assertThat(underTest.getByKey(XOO_X1).getKey()).isEqualTo(XOO_X1);
+ underTest.getById(AC_RULE_ID);
+ }
+
+ @Test
+ public void findById_returns_absent_if_rule_does_not_exist_in_DB() {
+ Optional<Rule> rule = underTest.findById(AC_RULE_ID);
- // second call -> get from cache
- assertThat(underTest.getByKey(XOO_X1).getKey()).isEqualTo(XOO_X1);
- verify(cacheLoader, times(1)).load(XOO_X1);
+ assertThat(rule).isAbsent();
}
@Test
- public void hasKey() {
- when(cacheLoader.load(XOO_X1)).thenReturn(new DumbRule(XOO_X1));
+ public void findById_returns_Rule_if_it_exists_in_DB() {
+ Optional<Rule> rule = underTest.findById(AB_RULE.getId());
+
+ assertIsABRule(rule.get());
+ }
- assertThat(underTest.hasKey(XOO_X1)).isTrue();
- assertThat(underTest.hasKey(XOO_X2)).isFalse();
+ private void expectNullRuleKeyNPE() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("RuleKey can not be null");
}
+
+ private void verifyNoMethodCallTriggersCallToDB() {
+ reset(ruleDao);
+ underTest.getByKey(AB_RULE.getKey());
+ assertNoCallToDb();
+ reset(ruleDao);
+ underTest.findByKey(AB_RULE.getKey());
+ assertNoCallToDb();
+ reset(ruleDao);
+ underTest.getById(AB_RULE.getId());
+ assertNoCallToDb();
+ reset(ruleDao);
+ underTest.findById(AB_RULE.getId());
+ assertNoCallToDb();
+ }
+
+ private void assertNoCallToDb() {
+ verifyNoMoreInteractions(ruleDao);
+ }
+
+ private void assertIsABRule(Rule rule) {
+ assertThat(rule).isNotNull();
+ assertThat(rule.getId()).isEqualTo(AB_RULE.getId());
+ assertThat(rule.getKey()).isEqualTo(AB_RULE.getKey());
+ assertThat(rule.getRemediationFunction()).isNull();
+ assertThat(rule.getSubCharacteristicId()).isNull();
+ assertThat(rule.getStatus()).isEqualTo(RuleStatus.REMOVED);
+ }
+
+ private static RuleDto createABRuleDto() {
+ RuleKey ruleKey = RuleKey.of("a", "b");
+ RuleDto res = new RuleDto();
+ res.setId(ruleKey.hashCode());
+ res.setRepositoryKey(ruleKey.repository());
+ res.setRuleKey(ruleKey.rule());
+ res.setStatus(RuleStatus.REMOVED);
+ return res;
+ }
+
}
*/
package org.sonar.server.computation.issue;
+import com.google.common.base.Optional;
import java.util.HashMap;
import java.util.Map;
import org.junit.rules.ExternalResource;
import org.sonar.api.rule.RuleKey;
-import org.sonar.server.exceptions.NotFoundException;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
public class RuleRepositoryRule extends ExternalResource implements RuleRepository {
private final Map<RuleKey, Rule> rulesByKey = new HashMap<>();
+ private final Map<Integer, Rule> rulesById = new HashMap<>();
@Override
protected void after() {
rulesByKey.clear();
+ rulesById.clear();
}
@Override
public Rule getByKey(RuleKey key) {
- Rule rule = rulesByKey.get(key);
- if (rule == null) {
- throw new NotFoundException();
- }
+ Rule rule = rulesByKey.get(requireNonNull(key));
+ checkArgument(rule != null);
+ return rule;
+ }
+
+ @Override
+ public Rule getById(int id) {
+ Rule rule = rulesById.get(id);
+ checkArgument(rule != null);
return rule;
}
@Override
- public boolean hasKey(RuleKey key) {
- return rulesByKey.containsKey(key);
+ public Optional<Rule> findByKey(RuleKey key) {
+ return Optional.fromNullable(rulesByKey.get(requireNonNull(key)));
+ }
+
+ @Override
+ public Optional<Rule> findById(int id) {
+ return Optional.fromNullable(rulesById.get(id));
}
public DumbRule add(RuleKey key) {
DumbRule rule = new DumbRule(key);
+ rule.setId(key.hashCode());
rulesByKey.put(key, rule);
+ rulesById.put(rule.getId(), rule);
return rule;
}
public RuleRepositoryRule add(DumbRule rule) {
- rulesByKey.put(rule.getKey(), rule);
+ rulesByKey.put(requireNonNull(rule.getKey()), rule);
+ rulesById.put(requireNonNull(rule.getId()), rule);
return this;
}
import org.sonar.db.DbTester;
import org.sonar.server.computation.batch.BatchReportReaderRule;
import org.sonar.server.computation.issue.IssueCache;
-import org.sonar.server.computation.issue.RuleCacheLoader;
import org.sonar.server.computation.issue.RuleRepositoryImpl;
import org.sonar.server.computation.issue.UpdateConflictResolver;
when(system2.now()).thenReturn(NOW);
reportReader.setMetadata(BatchReport.Metadata.getDefaultInstance());
- step = new PersistIssuesStep(dbClient, system2, new UpdateConflictResolver(), new RuleRepositoryImpl(new RuleCacheLoader(dbClient)), issueCache);
+ step = new PersistIssuesStep(dbClient, system2, new UpdateConflictResolver(), new RuleRepositoryImpl(dbClient), issueCache);
}
@After
+++ /dev/null
-<dataset>
- <rules id="1" name="JS One" plugin_name="js" plugin_rule_key="JS01"
- plugin_config_key="[null]" description="[null]" priority="4"
- status="READY"
- is_template="[false]" template_id="[null]"
- tags="[null]" system_tags="[null]"/>
-
- <rules id="2" name="Java One" plugin_name="java" plugin_rule_key="JAV01"
- plugin_config_key="[null]" description="[null]" priority="4"
- status="READY"
- is_template="[false]" template_id="[null]"
- tags="[null]" system_tags="[null]"/>
-
-</dataset>