@@ -203,6 +203,10 @@ public class RuleDao implements Dao { | |||
return executeLargeInputs(ruleKeys, mapper(session)::selectParamsByRuleKeys); | |||
} | |||
public List<RuleParamDto> selectAllRuleParams(DbSession session) { | |||
return mapper(session).selectAllRuleParams(); | |||
} | |||
public List<RuleParamDto> selectRuleParamsByRuleUuids(DbSession dbSession, Collection<String> ruleUuids) { | |||
return executeLargeInputs(ruleUuids, mapper(dbSession)::selectParamsByRuleUuids); | |||
} |
@@ -81,6 +81,8 @@ public interface RuleMapper { | |||
List<RuleParamDto> selectParamsByRuleKeys(@Param("ruleKeys") List<RuleKey> ruleKeys); | |||
List<RuleParamDto> selectAllRuleParams(); | |||
void insertParameter(RuleParamDto param); | |||
void updateParameter(RuleParamDto param); |
@@ -36,7 +36,7 @@ | |||
inner join rules r on r.uuid = a.rule_uuid | |||
</sql> | |||
<insert id="insert" parameterType="ActiveRule"> | |||
<insert id="insert" parameterType="ActiveRule" useGeneratedKeys="false"> | |||
insert into active_rules ( | |||
uuid, | |||
profile_uuid, | |||
@@ -56,7 +56,7 @@ | |||
) | |||
</insert> | |||
<update id="update" parameterType="ActiveRule"> | |||
<update id="update" parameterType="ActiveRule" useGeneratedKeys="false"> | |||
update active_rules | |||
set | |||
failure_level = #{severity, jdbcType=INTEGER}, |
@@ -148,7 +148,7 @@ | |||
</select> | |||
<select id="selectIndexingRuleExtensionsByIds" parameterType="map" resultType="org.sonar.db.rule.RuleExtensionForIndexingDto"> | |||
<include refid="sqlSelectIndexingRuleExtensions" /> | |||
<include refid="sqlSelectIndexingRuleExtensions"/> | |||
and | |||
<foreach collection="ruleExtensionIds" index="index" item="ruleExtId" open="" separator=" or " close=""> | |||
( r.uuid = #{ruleExtId, jdbcType=VARCHAR} ) | |||
@@ -263,7 +263,8 @@ | |||
order by r.created_at asc | |||
</select> | |||
<select id="scrollIndexingRules" resultType="org.sonar.db.rule.RuleForIndexingDto" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY"> | |||
<select id="scrollIndexingRules" resultType="org.sonar.db.rule.RuleForIndexingDto" fetchSize="${_scrollFetchSize}" | |||
resultSetType="FORWARD_ONLY"> | |||
<include refid="sqlSelectIndexingRules"/> | |||
order by r.created_at asc | |||
</select> | |||
@@ -324,8 +325,10 @@ | |||
<include refid="outerJoinRulesMetadata"/> | |||
where | |||
r.status != 'REMOVED' and r.is_external=${_false} and r.is_template=${_false} | |||
and r.rule_type in <foreach collection="types" item="type" separator="," open="(" close=")">#{type, jdbcType=INTEGER}</foreach> | |||
and r.language in <foreach collection="languages" item="language" separator="," open="(" close=")">#{language, jdbcType=VARCHAR}</foreach> | |||
and r.rule_type in | |||
<foreach collection="types" item="type" separator="," open="(" close=")">#{type, jdbcType=INTEGER}</foreach> | |||
and r.language in | |||
<foreach collection="languages" item="language" separator="," open="(" close=")">#{language, jdbcType=VARCHAR}</foreach> | |||
</select> | |||
<insert id="insertDefinition" parameterType="org.sonar.db.rule.RuleDefinitionDto" useGeneratedKeys="false"> | |||
@@ -506,6 +509,13 @@ | |||
</foreach> | |||
</select> | |||
<select id="selectAllRuleParams" resultType="RuleParam"> | |||
select | |||
<include refid="paramColumns"/> | |||
from | |||
rules_parameters p | |||
</select> | |||
<select id="selectParamsByRuleKey" resultType="RuleParam" parameterType="org.sonar.api.rule.RuleKey"> | |||
select | |||
<include refid="paramColumns"/> | |||
@@ -606,7 +616,8 @@ | |||
</foreach> | |||
</delete> | |||
<insert id="insertDeprecatedRuleKey" parameterType="org.sonar.db.rule.DeprecatedRuleKeyDto" keyColumn="uuid" useGeneratedKeys="false" keyProperty="uuid"> | |||
<insert id="insertDeprecatedRuleKey" parameterType="org.sonar.db.rule.DeprecatedRuleKeyDto" keyColumn="uuid" useGeneratedKeys="false" | |||
keyProperty="uuid"> | |||
INSERT INTO deprecated_rule_keys ( | |||
uuid, | |||
rule_uuid, |
@@ -42,9 +42,6 @@ import org.sonar.db.rule.RuleDto; | |||
import org.sonar.db.rule.RuleParamDto; | |||
import org.sonar.markdown.Markdown; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static java.util.Optional.empty; | |||
/** | |||
* Will be removed in the future. | |||
*/ | |||
@@ -61,12 +58,25 @@ public class DefaultRuleFinder implements ServerRuleFinder { | |||
@Override | |||
public Optional<RuleDefinitionDto> findDtoByKey(RuleKey key) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
Optional<RuleDefinitionDto> rule = ruleDao.selectDefinitionByKey(dbSession, key); | |||
if (rule.isPresent() && rule.get().getStatus() != RuleStatus.REMOVED) { | |||
return rule; | |||
} else { | |||
return empty(); | |||
} | |||
return ruleDao.selectDefinitionByKey(dbSession, key) | |||
.filter(r -> r.getStatus() != RuleStatus.REMOVED); | |||
} | |||
} | |||
@Override | |||
public Optional<RuleDefinitionDto> findDtoByUuid(String uuid) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
return ruleDao.selectDefinitionByUuid(uuid, dbSession) | |||
.filter(r -> r.getStatus() != RuleStatus.REMOVED); | |||
} | |||
} | |||
@Override | |||
public Collection<RuleDefinitionDto> findAll() { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
List<RuleDefinitionDto> list = new ArrayList<>(); | |||
ruleDao.selectEnabled(dbSession, r -> list.add(r.getResultObject())); | |||
return list; | |||
} | |||
} | |||
@@ -150,7 +160,7 @@ public class DefaultRuleFinder implements ServerRuleFinder { | |||
} | |||
} | |||
List<org.sonar.api.rules.RuleParam> apiParams = newArrayList(); | |||
List<org.sonar.api.rules.RuleParam> apiParams = new ArrayList<>(); | |||
for (RuleParamDto param : params) { | |||
apiParams.add(new org.sonar.api.rules.RuleParam(apiRule, param.getName(), param.getDescription(), param.getType()) | |||
.setDefaultValue(param.getDefaultValue())); |
@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.server.rule; | |||
import java.util.Collection; | |||
import java.util.Optional; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rules.RuleFinder; | |||
@@ -26,4 +27,9 @@ import org.sonar.db.rule.RuleDefinitionDto; | |||
public interface ServerRuleFinder extends RuleFinder { | |||
Optional<RuleDefinitionDto> findDtoByKey(RuleKey key); | |||
Optional<RuleDefinitionDto> findDtoByUuid(String uuid); | |||
Collection<RuleDefinitionDto> findAll(); | |||
} |
@@ -22,6 +22,7 @@ package org.sonar.server.rule; | |||
import com.google.common.collect.ImmutableSet; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
import org.sonar.api.rule.RuleKey; | |||
import org.sonar.api.rule.RuleStatus; | |||
import org.sonar.api.rules.Rule; | |||
import org.sonar.api.rules.RuleQuery; | |||
@@ -41,10 +42,10 @@ public class DefaultRuleFinderTest { | |||
@org.junit.Rule | |||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
private DbClient dbClient = dbTester.getDbClient(); | |||
private DbSession session = dbTester.getSession(); | |||
private final DbClient dbClient = dbTester.getDbClient(); | |||
private final DbSession session = dbTester.getSession(); | |||
private RuleDto rule1 = new RuleDto() | |||
private final RuleDto rule1 = new RuleDto() | |||
.setName("Check Header") | |||
.setConfigKey("Checker/Treewalker/HeaderCheck") | |||
.setRuleKey("com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck") | |||
@@ -53,7 +54,7 @@ public class DefaultRuleFinderTest { | |||
.setScope(Scope.MAIN) | |||
.setStatus(RuleStatus.READY); | |||
private RuleDto rule2 = new RuleDto() | |||
private final RuleDto rule2 = new RuleDto() | |||
.setName("Disabled checked") | |||
.setConfigKey("Checker/Treewalker/DisabledCheck") | |||
.setRuleKey("DisabledCheck") | |||
@@ -62,7 +63,7 @@ public class DefaultRuleFinderTest { | |||
.setScope(Scope.MAIN) | |||
.setStatus(RuleStatus.REMOVED); | |||
private RuleDto rule3 = new RuleDto() | |||
private final RuleDto rule3 = new RuleDto() | |||
.setName("Check Annotation") | |||
.setConfigKey("Checker/Treewalker/AnnotationUseStyleCheck") | |||
.setRuleKey("com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationUseStyleCheck") | |||
@@ -71,7 +72,7 @@ public class DefaultRuleFinderTest { | |||
.setScope(Scope.MAIN) | |||
.setStatus(RuleStatus.READY); | |||
private RuleDto rule4 = new RuleDto() | |||
private final RuleDto rule4 = new RuleDto() | |||
.setName("Call Super First") | |||
.setConfigKey("rulesets/android.xml/CallSuperFirst") | |||
.setRuleKey("CallSuperFirst") | |||
@@ -80,7 +81,7 @@ public class DefaultRuleFinderTest { | |||
.setScope(Scope.MAIN) | |||
.setStatus(RuleStatus.READY); | |||
private DefaultRuleFinder underTest = new DefaultRuleFinder(dbClient); | |||
private final DefaultRuleFinder underTest = new DefaultRuleFinder(dbClient); | |||
@Before | |||
public void setup() { | |||
@@ -108,19 +109,31 @@ public class DefaultRuleFinderTest { | |||
// find_all_enabled | |||
assertThat(underTest.findAll(RuleQuery.create())).extracting("ruleKey").containsOnly(rule1.getKey(), rule3.getKey(), rule4.getKey()); | |||
assertThat(underTest.findAll(RuleQuery.create())).hasSize(3); | |||
// find_all | |||
assertThat(underTest.findAll()).extracting("ruleKey").containsOnly(rule1.getKey().rule(), rule3.getKey().rule(), rule4.getKey().rule()); | |||
// do_not_find_disabled_rules | |||
assertThat(underTest.findByKey("checkstyle", "DisabledCheck")).isNull(); | |||
// do_not_find_unknown_rules | |||
assertThat(underTest.findAll(RuleQuery.create().withRepositoryKey("unknown_repository"))).isEmpty(); | |||
assertThat(underTest.findDtoByKey(RuleKey.of("pmd", "CallSuperFirst")).get().getUuid()).isEqualTo(rule4.getUuid()); | |||
assertThat(underTest.findDtoByUuid(rule4.getUuid())).isPresent(); | |||
} | |||
@Test | |||
public void should_fail_find() { | |||
assertThat(underTest.findDtoByKey(RuleKey.of("pmd", "unknown"))).isEmpty(); | |||
assertThat(underTest.findDtoByUuid("unknown")).isEmpty(); | |||
} | |||
@Test | |||
public void find_all_not_include_removed_rule() { | |||
// rule 3 is REMOVED | |||
assertThat(underTest.findAll(RuleQuery.create())).extracting("ruleKey").containsOnly(rule1.getKey(), rule3.getKey(), rule4.getKey()); | |||
assertThat(underTest.findAll()).extracting("ruleKey").containsOnly(rule1.getKey().rule(), rule3.getKey().rule(), rule4.getKey().rule()); | |||
} | |||
@Test |
@@ -0,0 +1,108 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.plugins; | |||
import java.util.Map; | |||
import java.util.stream.Collectors; | |||
import org.sonar.api.Startable; | |||
import org.sonar.api.utils.Preconditions; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.api.utils.log.Profiler; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.plugin.PluginDto; | |||
import static java.util.function.Function.identity; | |||
public class DetectPluginChange implements Startable { | |||
private static final Logger LOG = Loggers.get(DetectPluginChange.class); | |||
private final ServerPluginRepository serverPluginRepository; | |||
private final DbClient dbClient; | |||
private Boolean changesDetected = null; | |||
public DetectPluginChange(ServerPluginRepository serverPluginRepository, DbClient dbClient) { | |||
this.serverPluginRepository = serverPluginRepository; | |||
this.dbClient = dbClient; | |||
} | |||
@Override | |||
public void start() { | |||
Preconditions.checkState(changesDetected == null, "Can only call #start() once"); | |||
Profiler profiler = Profiler.create(LOG).startInfo("Detect plugin changes"); | |||
changesDetected = anyChange(); | |||
if (changesDetected) { | |||
LOG.info("Plugin changes detected"); | |||
} else { | |||
LOG.debug("No plugin changes detected"); | |||
} | |||
profiler.stopDebug(); | |||
} | |||
/** | |||
* @throws NullPointerException if {@link #start} hasn't been called | |||
*/ | |||
public boolean anyPluginChanged() { | |||
return changesDetected; | |||
} | |||
private boolean anyChange() { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
Map<String, PluginDto> dbPluginsByKey = dbClient.pluginDao().selectAll(dbSession).stream() | |||
.collect(Collectors.toMap(PluginDto::getKee, identity())); | |||
Map<String, ServerPlugin> filePluginsByKey = serverPluginRepository.getPlugins().stream() | |||
.collect(Collectors.toMap(p -> p.getPluginInfo().getKey(), p -> p)); | |||
if (!dbPluginsByKey.keySet().equals(filePluginsByKey.keySet())) { | |||
return true; | |||
} | |||
// TODO ideally we would detect plugins that were removed and added again, because we don't delete removed plugins from the plugins table. | |||
for (ServerPlugin installed : filePluginsByKey.values()) { | |||
PluginDto dbPlugin = dbPluginsByKey.get(installed.getPluginInfo().getKey()); | |||
if (changed(dbPlugin, installed)) { | |||
return true; | |||
} | |||
} | |||
} | |||
return false; | |||
} | |||
private boolean changed(PluginDto dbPlugin, ServerPlugin filePlugin) { | |||
return !dbPlugin.getFileHash().equals(filePlugin.getJar().getMd5()) || !dbPlugin.getType().equals(toTypeDto(filePlugin.getType())); | |||
} | |||
static PluginDto.Type toTypeDto(PluginType type) { | |||
switch (type) { | |||
case EXTERNAL: | |||
return PluginDto.Type.EXTERNAL; | |||
case BUNDLED: | |||
return PluginDto.Type.BUNDLED; | |||
default: | |||
throw new IllegalStateException("Unknown type: " + type); | |||
} | |||
} | |||
@Override | |||
public void stop() { | |||
// Nothing to do | |||
} | |||
} |
@@ -19,10 +19,8 @@ | |||
*/ | |||
package org.sonar.server.rule; | |||
import com.google.common.collect.ImmutableListMultimap; | |||
import com.google.common.collect.ImmutableMap; | |||
import com.google.common.collect.ListMultimap; | |||
import com.google.common.collect.Ordering; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.Date; | |||
@@ -30,7 +28,6 @@ import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
@@ -48,8 +45,8 @@ import org.sonar.db.rule.RuleDto; | |||
import org.sonar.db.rule.RuleParamDto; | |||
import org.sonar.markdown.Markdown; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static org.sonar.core.util.stream.MoreCollectors.toSet; | |||
import static java.util.Collections.emptyList; | |||
import static java.util.Collections.unmodifiableMap; | |||
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; | |||
/** | |||
@@ -61,6 +58,7 @@ public class CachingRuleFinder implements ServerRuleFinder { | |||
private static final Ordering<Map.Entry<RuleDefinitionDto, Rule>> FIND_BY_QUERY_ORDER = Ordering.natural().reverse().onResultOf(entry -> entry.getKey().getUpdatedAt()); | |||
private final Map<RuleKey, RuleDefinitionDto> ruleDtosByKey; | |||
private final Map<String, RuleDefinitionDto> ruleDtosByUuid; | |||
private final Map<RuleDefinitionDto, Rule> rulesByRuleDefinition; | |||
private final Map<RuleKey, Rule> rulesByKey; | |||
@@ -68,6 +66,7 @@ public class CachingRuleFinder implements ServerRuleFinder { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
List<RuleDefinitionDto> dtos = dbClient.ruleDao().selectAllDefinitions(dbSession); | |||
this.ruleDtosByKey = dtos.stream().collect(Collectors.toMap(RuleDefinitionDto::getKey, d -> d)); | |||
this.ruleDtosByUuid = dtos.stream().collect(Collectors.toMap(RuleDefinitionDto::getUuid, d -> d)); | |||
this.rulesByRuleDefinition = buildRulesByRuleDefinitionDto(dbClient, dbSession, dtos); | |||
this.rulesByKey = this.rulesByRuleDefinition.entrySet().stream() | |||
.collect(uniqueIndex(entry -> entry.getKey().getKey(), Map.Entry::getValue)); | |||
@@ -75,22 +74,17 @@ public class CachingRuleFinder implements ServerRuleFinder { | |||
} | |||
private static Map<RuleDefinitionDto, Rule> buildRulesByRuleDefinitionDto(DbClient dbClient, DbSession dbSession, List<RuleDefinitionDto> dtos) { | |||
Set<RuleKey> ruleKeys = dtos.stream().map(RuleDefinitionDto::getKey).collect(toSet(dtos.size())); | |||
ListMultimap<String, RuleParamDto> ruleParamsByRuleUuid = retrieveRuleParameters(dbClient, dbSession, ruleKeys); | |||
Map<String, List<RuleParamDto>> ruleParamsByRuleUuid = retrieveRuleParameters(dbClient, dbSession); | |||
Map<RuleDefinitionDto, Rule> rulesByDefinition = new HashMap<>(dtos.size()); | |||
for (RuleDefinitionDto definition : dtos) { | |||
rulesByDefinition.put(definition, toRule(definition, ruleParamsByRuleUuid.get(definition.getUuid()))); | |||
rulesByDefinition.put(definition, toRule(definition, ruleParamsByRuleUuid.getOrDefault(definition.getUuid(), emptyList()))); | |||
} | |||
return ImmutableMap.copyOf(rulesByDefinition); | |||
return unmodifiableMap(rulesByDefinition); | |||
} | |||
private static ImmutableListMultimap<String, RuleParamDto> retrieveRuleParameters(DbClient dbClient, DbSession dbSession, Set<RuleKey> ruleKeys) { | |||
if (ruleKeys.isEmpty()) { | |||
return ImmutableListMultimap.of(); | |||
} | |||
return dbClient.ruleDao().selectRuleParamsByRuleKeys(dbSession, ruleKeys) | |||
.stream() | |||
.collect(MoreCollectors.index(RuleParamDto::getRuleUuid)); | |||
private static Map<String, List<RuleParamDto>> retrieveRuleParameters(DbClient dbClient, DbSession dbSession) { | |||
return dbClient.ruleDao().selectAllRuleParams(dbSession).stream() | |||
.collect(Collectors.groupingBy(RuleParamDto::getRuleUuid)); | |||
} | |||
@Override | |||
@@ -178,7 +172,7 @@ public class CachingRuleFinder implements ServerRuleFinder { | |||
} | |||
} | |||
List<org.sonar.api.rules.RuleParam> apiParams = newArrayList(); | |||
List<org.sonar.api.rules.RuleParam> apiParams = new ArrayList<>(); | |||
for (RuleParamDto param : params) { | |||
apiParams.add(new org.sonar.api.rules.RuleParam(apiRule, param.getName(), param.getDescription(), param.getType()) | |||
.setDefaultValue(param.getDefaultValue())); | |||
@@ -192,4 +186,15 @@ public class CachingRuleFinder implements ServerRuleFinder { | |||
public Optional<RuleDefinitionDto> findDtoByKey(RuleKey key) { | |||
return Optional.ofNullable(this.ruleDtosByKey.get(key)); | |||
} | |||
@Override | |||
public Optional<RuleDefinitionDto> findDtoByUuid(String uuid) { | |||
return Optional.ofNullable(this.ruleDtosByUuid.get(uuid)); | |||
} | |||
@Override | |||
public Collection<RuleDefinitionDto> findAll() { | |||
return ruleDtosByUuid.values(); | |||
} | |||
} |
@@ -78,4 +78,15 @@ public class WebServerRuleFinderImpl implements WebServerRuleFinder { | |||
public Optional<RuleDefinitionDto> findDtoByKey(RuleKey key) { | |||
return delegate.findDtoByKey(key); | |||
} | |||
@Override | |||
public Optional<RuleDefinitionDto> findDtoByUuid(String uuid) { | |||
return delegate.findDtoByUuid(uuid); | |||
} | |||
@Override | |||
public Collection<RuleDefinitionDto> findAll() { | |||
return delegate.findAll(); | |||
} | |||
} |
@@ -0,0 +1,116 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.plugins; | |||
import org.junit.Ignore; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.Plugin; | |||
import org.sonar.core.platform.PluginInfo; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.plugin.PluginDto; | |||
import org.sonar.server.plugins.PluginFilesAndMd5.FileAndMd5; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.junit.Assert.assertThrows; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
public class DetectPluginChangeTest { | |||
@Rule | |||
public DbTester dbTester = DbTester.create(); | |||
private final ServerPluginRepository pluginRepository = new ServerPluginRepository(); | |||
private final DetectPluginChange detectPluginChange = new DetectPluginChange(pluginRepository, dbTester.getDbClient()); | |||
@Test | |||
public void detect_changed_plugin() { | |||
addPluginToDb("plugin1", "hash1", PluginDto.Type.BUNDLED); | |||
addPluginToFs("plugin1", "hash2", PluginType.BUNDLED); | |||
detectPluginChange.start(); | |||
assertThat(detectPluginChange.anyPluginChanged()).isTrue(); | |||
} | |||
@Test | |||
public void detect_changed_type() { | |||
addPluginToDb("plugin1", "hash1", PluginDto.Type.BUNDLED); | |||
addPluginToFs("plugin1", "hash1", PluginType.EXTERNAL); | |||
detectPluginChange.start(); | |||
assertThat(detectPluginChange.anyPluginChanged()).isTrue(); | |||
} | |||
@Test | |||
public void detect_new_plugin() { | |||
addPluginToDb("plugin1", "hash1", PluginDto.Type.BUNDLED); | |||
addPluginToFs("plugin2", "hash1", PluginType.BUNDLED); | |||
detectPluginChange.start(); | |||
assertThat(detectPluginChange.anyPluginChanged()).isTrue(); | |||
} | |||
@Ignore | |||
@Test | |||
public void detect_missing_plugin() { | |||
// TODO | |||
addPluginToDb("plugin1", "hash1", PluginDto.Type.BUNDLED); | |||
addPluginToFs("plugin1", "hash1", PluginType.BUNDLED); | |||
detectPluginChange.start(); | |||
assertThat(detectPluginChange.anyPluginChanged()).isTrue(); | |||
} | |||
@Test | |||
public void detect_no_changes_bundled() { | |||
addPluginToDb("plugin1", "hash1", PluginDto.Type.BUNDLED); | |||
addPluginToFs("plugin1", "hash1", PluginType.BUNDLED); | |||
addPluginToDb("plugin2", "hash2", PluginDto.Type.EXTERNAL); | |||
addPluginToFs("plugin2", "hash2", PluginType.EXTERNAL); | |||
detectPluginChange.start(); | |||
assertThat(detectPluginChange.anyPluginChanged()).isFalse(); | |||
} | |||
@Test | |||
public void fail_if_start_twice() { | |||
detectPluginChange.start(); | |||
assertThrows(IllegalStateException.class, detectPluginChange::start); | |||
} | |||
@Test | |||
public void fail_if_not_started() { | |||
assertThrows(NullPointerException.class, detectPluginChange::anyPluginChanged); | |||
} | |||
private void addPluginToDb(String key, String hash, PluginDto.Type type) { | |||
dbTester.pluginDbTester().insertPlugin(p -> p.setKee(key).setFileHash(hash).setType(type)); | |||
} | |||
private void addPluginToFs(String key, String hash, PluginType type) { | |||
PluginInfo pluginInfo = new PluginInfo(key); | |||
Plugin plugin = mock(Plugin.class); | |||
FileAndMd5 fileAndMd5 = mock(FileAndMd5.class); | |||
when(fileAndMd5.getMd5()).thenReturn(hash); | |||
ServerPlugin serverPlugin = new ServerPlugin(pluginInfo, type, plugin, fileAndMd5, null); | |||
pluginRepository.addPlugin(serverPlugin); | |||
} | |||
} |
@@ -35,7 +35,7 @@ import static org.sonar.server.property.InternalProperties.DEFAULT_ADMIN_CREDENT | |||
/** | |||
* Detect usage of an active admin account with default credential in order to ask this account to reset its password during authentication. | |||
*/ | |||
public class DefaultAdminCredentialsVerifierImpl implements Startable, DefaultAdminCredentialsVerifier { | |||
public class DefaultAdminCredentialsVerifierImpl implements DefaultAdminCredentialsVerifier { | |||
private static final Logger LOGGER = Loggers.get(STARTUP_LOGGER_NAME); | |||
@@ -49,8 +49,7 @@ public class DefaultAdminCredentialsVerifierImpl implements Startable, DefaultAd | |||
this.notificationManager = notificationManager; | |||
} | |||
@Override | |||
public void start() { | |||
public void runAtStart() { | |||
try (DbSession session = dbClient.openSession(false)) { | |||
UserDto admin = getAdminUser(session); | |||
if (admin == null || !isDefaultCredentialUser(session, admin)) { | |||
@@ -63,6 +62,7 @@ public class DefaultAdminCredentialsVerifierImpl implements Startable, DefaultAd | |||
} | |||
} | |||
@Override | |||
public boolean hasDefaultCredentialUser() { | |||
try (DbSession session = dbClient.openSession(false)) { | |||
UserDto admin = getAdminUser(session); | |||
@@ -105,9 +105,4 @@ public class DefaultAdminCredentialsVerifierImpl implements Startable, DefaultAd | |||
notificationManager.scheduleForSending(new DefaultAdminCredentialsVerifierNotification()); | |||
dbClient.internalPropertiesDao().save(session, DEFAULT_ADMIN_CREDENTIAL_USAGE_EMAIL, Boolean.TRUE.toString()); | |||
} | |||
@Override | |||
public void stop() { | |||
// Nothing to do | |||
} | |||
} |
@@ -20,17 +20,14 @@ | |||
package org.sonar.server.qualityprofile; | |||
import com.google.common.base.Splitter; | |||
import com.google.common.collect.ImmutableSet; | |||
import com.google.common.collect.Sets; | |||
import java.util.Collections; | |||
import java.util.Date; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import java.util.function.Function; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
@@ -51,22 +48,27 @@ import org.sonar.db.qualityprofile.RulesProfileDto; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.db.rule.RuleParamDto; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; | |||
import org.sonar.server.rule.ServerRuleFinder; | |||
import org.sonar.server.util.TypeValidations; | |||
import static com.google.common.base.MoreObjects.firstNonNull; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import static java.util.Collections.emptySet; | |||
import static java.util.Objects.requireNonNull; | |||
public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert { | |||
private final DbClient dbClient; | |||
private final ServerRuleFinder ruleFinder; | |||
private final System2 system2; | |||
private final UuidFactory uuidFactory; | |||
private final TypeValidations typeValidations; | |||
private final ActiveRuleIndexer activeRuleIndexer; | |||
private RuleRepository ruleRepository; | |||
public BuiltInQProfileInsertImpl(DbClient dbClient, System2 system2, UuidFactory uuidFactory, TypeValidations typeValidations, ActiveRuleIndexer activeRuleIndexer) { | |||
public BuiltInQProfileInsertImpl(DbClient dbClient, ServerRuleFinder ruleFinder, System2 system2, UuidFactory uuidFactory, | |||
TypeValidations typeValidations, ActiveRuleIndexer activeRuleIndexer) { | |||
this.dbClient = dbClient; | |||
this.ruleFinder = ruleFinder; | |||
this.system2 = system2; | |||
this.uuidFactory = uuidFactory; | |||
this.typeValidations = typeValidations; | |||
@@ -80,9 +82,8 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert { | |||
Date now = new Date(system2.now()); | |||
RulesProfileDto ruleProfile = insertRulesProfile(dbSession, builtInQProfile, now); | |||
List<ActiveRuleChange> changes = builtInQProfile.getActiveRules() | |||
.stream() | |||
.map(activeRule -> insertActiveRule(dbSession, ruleProfile, activeRule, now.getTime())) | |||
List<ActiveRuleChange> changes = builtInQProfile.getActiveRules().stream() | |||
.map(activeRule -> insertActiveRule(dbSession, batchDbSession, ruleProfile, activeRule, now.getTime())) | |||
.collect(MoreCollectors.toList()); | |||
changes.forEach(change -> dbClient.qProfileChangeDao().insert(batchDbSession, change.toDto(null))); | |||
@@ -95,6 +96,7 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert { | |||
activeRuleIndexer.commitAndIndex(dbSession, changes); | |||
} | |||
private void createDefaultAndOrgQProfiles(DbSession dbSession, DbSession batchDbSession, BuiltInQProfile builtIn, RulesProfileDto rulesProfileDto) { | |||
Optional<String> qProfileUuid = dbClient.defaultQProfileDao().selectDefaultQProfileUuid(dbSession, builtIn.getLanguage()); | |||
@@ -102,7 +104,7 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert { | |||
.setRulesProfileUuid(rulesProfileDto.getUuid()) | |||
.setUuid(uuidFactory.create()); | |||
if (builtIn.isDefault() && !qProfileUuid.isPresent()) { | |||
if (builtIn.isDefault() && qProfileUuid.isEmpty()) { | |||
DefaultQProfileDto defaultQProfileDto = new DefaultQProfileDto() | |||
.setQProfileUuid(dto.getUuid()) | |||
.setLanguage(builtIn.getLanguage()); | |||
@@ -114,7 +116,7 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert { | |||
private void initRuleRepository(DbSession dbSession) { | |||
if (ruleRepository == null) { | |||
ruleRepository = new RuleRepository(dbClient, dbSession); | |||
ruleRepository = new RuleRepository(dbClient, dbSession, ruleFinder); | |||
} | |||
} | |||
@@ -129,7 +131,7 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert { | |||
return dto; | |||
} | |||
private ActiveRuleChange insertActiveRule(DbSession dbSession, RulesProfileDto rulesProfileDto, BuiltInQProfile.ActiveRule activeRule, long now) { | |||
private ActiveRuleChange insertActiveRule(DbSession dbSession, DbSession batchDbSession, RulesProfileDto rulesProfileDto, BuiltInQProfile.ActiveRule activeRule, long now) { | |||
RuleKey ruleKey = activeRule.getRuleKey(); | |||
RuleDefinitionDto ruleDefinitionDto = ruleRepository.getDefinition(ruleKey) | |||
.orElseThrow(() -> new IllegalStateException("RuleDefinition not found for key " + ruleKey)); | |||
@@ -141,7 +143,7 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert { | |||
dto.setSeverity(firstNonNull(activeRule.getSeverity(), ruleDefinitionDto.getSeverityString())); | |||
dto.setUpdatedAt(now); | |||
dto.setCreatedAt(now); | |||
dbClient.activeRuleDao().insert(dbSession, dto); | |||
dbClient.activeRuleDao().insert(batchDbSession, dto); | |||
List<ActiveRuleParamDto> paramDtos = insertActiveRuleParams(dbSession, activeRule, dto); | |||
@@ -151,13 +153,10 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert { | |||
return change; | |||
} | |||
private List<ActiveRuleParamDto> insertActiveRuleParams(DbSession session, BuiltInQProfile.ActiveRule activeRule, | |||
ActiveRuleDto activeRuleDto) { | |||
Map<String, String> valuesByParamKey = activeRule.getParams() | |||
.stream() | |||
private List<ActiveRuleParamDto> insertActiveRuleParams(DbSession session, BuiltInQProfile.ActiveRule activeRule, ActiveRuleDto activeRuleDto) { | |||
Map<String, String> valuesByParamKey = activeRule.getParams().stream() | |||
.collect(MoreCollectors.uniqueIndex(BuiltInQualityProfilesDefinition.OverriddenParam::key, BuiltInQualityProfilesDefinition.OverriddenParam::overriddenValue)); | |||
List<ActiveRuleParamDto> rules = ruleRepository.getRuleParams(activeRule.getRuleKey()) | |||
.stream() | |||
List<ActiveRuleParamDto> rules = ruleRepository.getRuleParams(activeRule.getRuleKey()).stream() | |||
.map(param -> createParamDto(param, Optional.ofNullable(valuesByParamKey.get(param.getName())).orElse(param.getDefaultValue()))) | |||
.filter(Objects::nonNull) | |||
.collect(Collectors.toList()); | |||
@@ -188,35 +187,29 @@ public class BuiltInQProfileInsertImpl implements BuiltInQProfileInsert { | |||
} | |||
private static class RuleRepository { | |||
private final Map<RuleKey, RuleDefinitionDto> definitions; | |||
private final Map<RuleKey, Set<RuleParamDto>> params; | |||
private final ServerRuleFinder ruleFinder; | |||
private RuleRepository(DbClient dbClient, DbSession session, ServerRuleFinder ruleFinder) { | |||
this.ruleFinder = ruleFinder; | |||
this.params = new HashMap<>(); | |||
for (RuleParamDto ruleParam : dbClient.ruleDao().selectAllRuleParams(session)) { | |||
Optional<RuleKey> ruleKey = ruleFinder.findDtoByUuid(ruleParam.getRuleUuid()) | |||
.map(r -> RuleKey.of(r.getRepositoryKey(), r.getRuleKey())); | |||
private RuleRepository(DbClient dbClient, DbSession session) { | |||
this.definitions = dbClient.ruleDao().selectAllDefinitions(session) | |||
.stream() | |||
.collect(Collectors.toMap(RuleDefinitionDto::getKey, Function.identity())); | |||
Map<String, RuleKey> ruleUuidsByKey = definitions.values() | |||
.stream() | |||
.collect(MoreCollectors.uniqueIndex(RuleDefinitionDto::getUuid, RuleDefinitionDto::getKey)); | |||
this.params = new HashMap<>(ruleUuidsByKey.size()); | |||
dbClient.ruleDao().selectRuleParamsByRuleKeys(session, definitions.keySet()) | |||
.forEach(ruleParam -> params.compute( | |||
ruleUuidsByKey.get(ruleParam.getRuleUuid()), | |||
(key, value) -> { | |||
if (value == null) { | |||
return ImmutableSet.of(ruleParam); | |||
} | |||
return ImmutableSet.copyOf(Sets.union(value, Collections.singleton(ruleParam))); | |||
})); | |||
if (ruleKey.isPresent()) { | |||
params.computeIfAbsent(ruleKey.get(), r -> new HashSet<>()).add(ruleParam); | |||
} | |||
} | |||
} | |||
private Optional<RuleDefinitionDto> getDefinition(RuleKey ruleKey) { | |||
return Optional.ofNullable(definitions.get(requireNonNull(ruleKey, "RuleKey can't be null"))); | |||
return ruleFinder.findDtoByKey(requireNonNull(ruleKey, "RuleKey can't be null")); | |||
} | |||
private Set<RuleParamDto> getRuleParams(RuleKey ruleKey) { | |||
Set<RuleParamDto> res = params.get(requireNonNull(ruleKey, "RuleKey can't be null")); | |||
return res == null ? Collections.emptySet() : res; | |||
return params.getOrDefault(requireNonNull(ruleKey, "RuleKey can't be null"), emptySet()); | |||
} | |||
} | |||
} |
@@ -46,6 +46,7 @@ import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.rule.DeprecatedRuleKeyDto; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.server.rule.ServerRuleFinder; | |||
import static com.google.common.base.Preconditions.checkState; | |||
@@ -54,6 +55,7 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository | |||
private static final String DEFAULT_PROFILE_NAME = "Sonar way"; | |||
private final DbClient dbClient; | |||
private final ServerRuleFinder ruleFinder; | |||
private final Languages languages; | |||
private final List<BuiltInQualityProfilesDefinition> definitions; | |||
private List<BuiltInQProfile> qProfiles; | |||
@@ -61,12 +63,13 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository | |||
/** | |||
* Requires for pico container when no {@link BuiltInQualityProfilesDefinition} is defined at all | |||
*/ | |||
public BuiltInQProfileRepositoryImpl(DbClient dbClient, Languages languages) { | |||
this(dbClient, languages, new BuiltInQualityProfilesDefinition[0]); | |||
public BuiltInQProfileRepositoryImpl(DbClient dbClient, ServerRuleFinder ruleFinder, Languages languages) { | |||
this(dbClient, ruleFinder, languages, new BuiltInQualityProfilesDefinition[0]); | |||
} | |||
public BuiltInQProfileRepositoryImpl(DbClient dbClient, Languages languages, BuiltInQualityProfilesDefinition... definitions) { | |||
public BuiltInQProfileRepositoryImpl(DbClient dbClient, ServerRuleFinder ruleFinder, Languages languages, BuiltInQualityProfilesDefinition... definitions) { | |||
this.dbClient = dbClient; | |||
this.ruleFinder = ruleFinder; | |||
this.languages = languages; | |||
this.definitions = ImmutableList.copyOf(definitions); | |||
} | |||
@@ -141,7 +144,7 @@ public class BuiltInQProfileRepositoryImpl implements BuiltInQProfileRepository | |||
private Map<RuleKey, RuleDefinitionDto> loadRuleDefinitionsByRuleKey() { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
List<RuleDefinitionDto> ruleDefinitions = dbClient.ruleDao().selectAllDefinitions(dbSession); | |||
Collection<RuleDefinitionDto> ruleDefinitions = ruleFinder.findAll(); | |||
Multimap<String, DeprecatedRuleKeyDto> deprecatedRuleKeysByRuleId = dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbSession).stream() | |||
.collect(MoreCollectors.index(DeprecatedRuleKeyDto::getRuleUuid)); | |||
Map<RuleKey, RuleDefinitionDto> rulesByRuleKey = new HashMap<>(); |
@@ -52,11 +52,6 @@ public class DefaultAdminCredentialsVerifierImplTest { | |||
private final DefaultAdminCredentialsVerifierImpl underTest = new DefaultAdminCredentialsVerifierImpl(db.getDbClient(), localAuthentication, notificationManager); | |||
@After | |||
public void after() { | |||
underTest.stop(); | |||
} | |||
@Test | |||
public void correctly_detect_if_admin_account_is_used_with_default_credential() { | |||
UserDto admin = db.users().insertUser(u -> u.setLogin(ADMIN_LOGIN)); | |||
@@ -77,7 +72,7 @@ public class DefaultAdminCredentialsVerifierImplTest { | |||
UserDto admin = db.users().insertUser(u -> u.setLogin(ADMIN_LOGIN)); | |||
changePassword(admin, "admin"); | |||
underTest.start(); | |||
underTest.runAtStart(); | |||
assertThat(db.users().selectUserByLogin(admin.getLogin()).get().isResetPassword()).isTrue(); | |||
assertThat(logTester.logs(LoggerLevel.WARN)).contains("Default Administrator credentials are still being used. Make sure to change the password or deactivate the account."); | |||
@@ -92,7 +87,7 @@ public class DefaultAdminCredentialsVerifierImplTest { | |||
db.getDbClient().internalPropertiesDao().save(db.getSession(), DEFAULT_ADMIN_CREDENTIAL_USAGE_EMAIL, "true"); | |||
db.commit(); | |||
underTest.start(); | |||
underTest.runAtStart(); | |||
verifyNoMoreInteractions(notificationManager); | |||
} | |||
@@ -102,7 +97,7 @@ public class DefaultAdminCredentialsVerifierImplTest { | |||
UserDto admin = db.users().insertUser(u -> u.setLogin(ADMIN_LOGIN)); | |||
changePassword(admin, "something_else"); | |||
underTest.start(); | |||
underTest.runAtStart(); | |||
assertThat(db.users().selectUserByLogin(admin.getLogin()).get().isResetPassword()).isFalse(); | |||
assertThat(logTester.logs()).isEmpty(); | |||
@@ -114,7 +109,7 @@ public class DefaultAdminCredentialsVerifierImplTest { | |||
UserDto otherUser = db.users().insertUser(); | |||
changePassword(otherUser, "admin"); | |||
underTest.start(); | |||
underTest.runAtStart(); | |||
assertThat(db.users().selectUserByLogin(otherUser.getLogin()).get().isResetPassword()).isFalse(); | |||
assertThat(logTester.logs()).isEmpty(); | |||
@@ -126,7 +121,7 @@ public class DefaultAdminCredentialsVerifierImplTest { | |||
UserDto admin = db.users().insertUser(u -> u.setLogin(ADMIN_LOGIN).setActive(false)); | |||
changePassword(admin, "admin"); | |||
underTest.start(); | |||
underTest.runAtStart(); | |||
assertThat(db.users().selectUserByLogin(admin.getLogin()).get().isResetPassword()).isFalse(); | |||
assertThat(logTester.logs()).isEmpty(); |
@@ -19,11 +19,13 @@ | |||
*/ | |||
package org.sonar.server.qualityprofile; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import org.junit.After; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.PropertyType; | |||
import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; | |||
import org.sonar.api.rule.Severity; | |||
import org.sonar.api.server.profile.BuiltInQualityProfilesDefinition; | |||
@@ -40,10 +42,14 @@ import org.sonar.db.qualityprofile.QProfileChangeDto; | |||
import org.sonar.db.qualityprofile.QProfileChangeQuery; | |||
import org.sonar.db.qualityprofile.QProfileDto; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.db.rule.RuleParamDto; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; | |||
import org.sonar.server.rule.DefaultRuleFinder; | |||
import org.sonar.server.rule.ServerRuleFinder; | |||
import org.sonar.server.util.StringTypeValidation; | |||
import org.sonar.server.util.TypeValidations; | |||
import static java.util.Collections.emptyList; | |||
import static java.util.Collections.singletonList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
@@ -56,13 +62,14 @@ public class BuiltInQProfileInsertImplTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private System2 system2 = new AlwaysIncreasingSystem2(); | |||
private UuidFactory uuidFactory = new SequenceUuidFactory(); | |||
private TypeValidations typeValidations = new TypeValidations(emptyList()); | |||
private DbSession dbSession = db.getSession(); | |||
private DbSession batchDbSession = db.getDbClient().openSession(true); | |||
private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class); | |||
private BuiltInQProfileInsertImpl underTest = new BuiltInQProfileInsertImpl(db.getDbClient(), system2, uuidFactory, typeValidations, activeRuleIndexer); | |||
private final System2 system2 = new AlwaysIncreasingSystem2(); | |||
private final UuidFactory uuidFactory = new SequenceUuidFactory(); | |||
private final TypeValidations typeValidations = new TypeValidations(singletonList(new StringTypeValidation())); | |||
private final DbSession dbSession = db.getSession(); | |||
private final DbSession batchDbSession = db.getDbClient().openSession(true); | |||
private final ServerRuleFinder ruleFinder = new DefaultRuleFinder(db.getDbClient()); | |||
private final ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class); | |||
private final BuiltInQProfileInsertImpl underTest = new BuiltInQProfileInsertImpl(db.getDbClient(), ruleFinder, system2, uuidFactory, typeValidations, activeRuleIndexer); | |||
@After | |||
public void tearDown() { | |||
@@ -85,15 +92,63 @@ public class BuiltInQProfileInsertImplTest { | |||
call(builtIn); | |||
verifyTableSize("rules_profiles", 1); | |||
verifyTableSize("org_qprofiles", 1); | |||
verifyTableSize("active_rules", 2); | |||
verifyTableSize("active_rule_parameters", 0); | |||
verifyTableSize("qprofile_changes", 2); | |||
verifyTableSize("default_qprofiles", 0); | |||
QProfileDto profile = verifyProfileInDb(builtIn); | |||
verifyActiveRuleInDb(profile, rule1, Severity.CRITICAL); | |||
verifyActiveRuleInDb(profile, rule2, Severity.MAJOR); | |||
} | |||
@Test | |||
public void insert_default_qp() { | |||
BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context(); | |||
context.createBuiltInQualityProfile("the name", "xoo") | |||
.setDefault(true) | |||
.done(); | |||
BuiltInQProfile builtIn = builtInQProfileRepository.create(context.profile("xoo", "the name")); | |||
call(builtIn); | |||
verifyTableSize("rules_profiles", 1); | |||
verifyTableSize("org_qprofiles", 1); | |||
verifyTableSize("active_rules", 0); | |||
verifyTableSize("active_rule_parameters", 0); | |||
verifyTableSize("qprofile_changes", 0); | |||
verifyTableSize("default_qprofiles", 1); | |||
verifyProfileInDb(builtIn); | |||
} | |||
@Test | |||
public void insert_active_rules_with_params() { | |||
RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("xoo")); | |||
RuleParamDto param1 = db.rules().insertRuleParam(rule1, p -> p.setType(PropertyType.STRING.name())); | |||
RuleParamDto param2 = db.rules().insertRuleParam(rule1, p -> p.setType(PropertyType.STRING.name())); | |||
BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context(); | |||
NewBuiltInQualityProfile newQp = context.createBuiltInQualityProfile("the name", "xoo"); | |||
newQp.activateRule(rule1.getRepositoryKey(), rule1.getRuleKey()).overrideSeverity(Severity.CRITICAL); | |||
newQp.done(); | |||
BuiltInQProfile builtIn = builtInQProfileRepository.create(context.profile("xoo", "the name"), rule1); | |||
call(builtIn); | |||
verifyTableSize("rules_profiles", 1); | |||
verifyTableSize("org_qprofiles", 1); | |||
verifyTableSize("active_rules", 1); | |||
verifyTableSize("active_rule_parameters", 2); | |||
verifyTableSize("qprofile_changes", 1); | |||
QProfileDto profile = verifyProfileInDb(builtIn); | |||
verifyActiveRuleInDb(profile, rule1, Severity.CRITICAL, param1, param2); | |||
} | |||
@Test | |||
public void flag_profile_as_default_if_declared_as_default_by_api() { | |||
BuiltInQualityProfilesDefinition.Context context = new BuiltInQualityProfilesDefinition.Context(); | |||
@@ -123,6 +178,7 @@ public class BuiltInQProfileInsertImplTest { | |||
QProfileDto defaultProfile = db.getDbClient().qualityProfileDao().selectDefaultProfile(dbSession, "xoo"); | |||
assertThat(defaultProfile.getKee()).isEqualTo(currentDefault.getKee()); | |||
verifyTableSize("rules_profiles", 2); | |||
} | |||
@Test | |||
@@ -138,10 +194,9 @@ public class BuiltInQProfileInsertImplTest { | |||
assertThat(defaultProfile).isNull(); | |||
} | |||
// TODO test params | |||
// TODO test lot of active_rules, params, orgas | |||
private void verifyActiveRuleInDb(QProfileDto profile, RuleDefinitionDto rule, String expectedSeverity) { | |||
private void verifyActiveRuleInDb(QProfileDto profile, RuleDefinitionDto rule, String expectedSeverity, RuleParamDto... paramDtos) { | |||
ActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByKey(dbSession, ActiveRuleKey.of(profile, rule.getKey())).get(); | |||
assertThat(activeRule.getUuid()).isNotNull(); | |||
assertThat(activeRule.getInheritance()).isNull(); | |||
@@ -153,7 +208,7 @@ public class BuiltInQProfileInsertImplTest { | |||
assertThat(activeRule.getUpdatedAt()).isPositive(); | |||
List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleUuid(dbSession, activeRule.getUuid()); | |||
assertThat(params).isEmpty(); | |||
assertThat(params).extracting(ActiveRuleParamDto::getKey).containsOnly(Arrays.stream(paramDtos).map(RuleParamDto::getName).toArray(String[]::new)); | |||
QProfileChangeQuery changeQuery = new QProfileChangeQuery(profile.getKee()); | |||
QProfileChangeDto change = db.getDbClient().qProfileChangeDao().selectByQuery(dbSession, changeQuery).stream() |
@@ -19,7 +19,6 @@ | |||
*/ | |||
package org.sonar.server.qualityprofile; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
@@ -32,6 +31,8 @@ import org.sonar.db.DbClient; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.server.language.LanguageTesting; | |||
import org.sonar.server.rule.DefaultRuleFinder; | |||
import org.sonar.server.rule.ServerRuleFinder; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.emptyList; | |||
@@ -51,16 +52,16 @@ public class BuiltInQProfileRepositoryImplTest { | |||
@Rule | |||
public DbTester db = DbTester.create(); | |||
private DbClient dbClient = db.getDbClient(); | |||
private final DbClient dbClient = db.getDbClient(); | |||
private final ServerRuleFinder ruleFinder = new DefaultRuleFinder(dbClient); | |||
@Test | |||
public void create_qprofile_with_rule() { | |||
RuleDefinitionDto rule1 = db.rules().insert(); | |||
RuleDefinitionDto rule2 = db.rules().insert(); | |||
db.rules().insert(); | |||
List<DummyProfileDefinition> definitions = singletonList(new DummyProfileDefinition("foo", "foo", false, | |||
asList(rule1.getKey(), rule2.getKey()))); | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), definitions.toArray(new BuiltInQualityProfilesDefinition[0])); | |||
DummyProfileDefinition definition = new DummyProfileDefinition("foo", "foo", false, asList(rule1.getKey(), rule2.getKey())); | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE), definition); | |||
underTest.initialize(); | |||
@@ -76,7 +77,8 @@ public class BuiltInQProfileRepositoryImplTest { | |||
@Test | |||
public void make_single_profile_of_a_language_default_even_if_not_flagged_as_so() { | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "foo1", false)); | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE), | |||
new DummyProfileDefinition("foo", "foo1", false)); | |||
underTest.initialize(); | |||
@@ -87,7 +89,8 @@ public class BuiltInQProfileRepositoryImplTest { | |||
@Test | |||
public void make_single_profile_of_a_language_default_even_if_flagged_as_so() { | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), new DummyProfileDefinition("foo", "foo1", true)); | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE), | |||
new DummyProfileDefinition("foo", "foo1", true)); | |||
underTest.initialize(); | |||
@@ -98,11 +101,10 @@ public class BuiltInQProfileRepositoryImplTest { | |||
@Test | |||
public void make_first_profile_of_a_language_default_when_none_flagged_as_so() { | |||
List<DummyProfileDefinition> definitions = new ArrayList<>( | |||
asList(new DummyProfileDefinition("foo", "foo1", false), new DummyProfileDefinition("foo", "foo2", false))); | |||
String firstName = definitions.get(0).getName(); | |||
String secondName = definitions.get(1).getName(); | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), definitions.toArray(new BuiltInQualityProfilesDefinition[0])); | |||
DummyProfileDefinition[] definitions = new DummyProfileDefinition[] {new DummyProfileDefinition("foo", "foo1", false), new DummyProfileDefinition("foo", "foo2", false)}; | |||
String firstName = definitions[0].getName(); | |||
String secondName = definitions[1].getName(); | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE), definitions); | |||
underTest.initialize(); | |||
@@ -114,7 +116,7 @@ public class BuiltInQProfileRepositoryImplTest { | |||
@Test | |||
public void create_profile_Sonar_Way_as_default_if_none_other_is_defined_default_for_a_given_language() { | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl( | |||
dbClient, new Languages(FOO_LANGUAGE), | |||
dbClient, ruleFinder, new Languages(FOO_LANGUAGE), | |||
new DummyProfileDefinition("foo", "doh", false), new DummyProfileDefinition("foo", "boo", false), | |||
new DummyProfileDefinition("foo", SONAR_WAY_QP_NAME, false), new DummyProfileDefinition("foo", "goo", false)); | |||
@@ -130,7 +132,7 @@ public class BuiltInQProfileRepositoryImplTest { | |||
@Test | |||
public void do_not_create_Sonar_Way_as_default_if_other_profile_is_defined_as_default() { | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl( | |||
dbClient, new Languages(FOO_LANGUAGE), | |||
dbClient, ruleFinder, new Languages(FOO_LANGUAGE), | |||
new DummyProfileDefinition("foo", SONAR_WAY_QP_NAME, false), new DummyProfileDefinition("foo", "goo", true)); | |||
underTest.initialize(); | |||
@@ -146,7 +148,7 @@ public class BuiltInQProfileRepositoryImplTest { | |||
public void match_Sonar_Way_default_with_case_sensitivity() { | |||
String sonarWayInOtherCase = SONAR_WAY_QP_NAME.toUpperCase(); | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl( | |||
dbClient, new Languages(FOO_LANGUAGE), | |||
dbClient, ruleFinder, new Languages(FOO_LANGUAGE), | |||
new DummyProfileDefinition("foo", "goo", false), new DummyProfileDefinition("foo", sonarWayInOtherCase, false)); | |||
underTest.initialize(); | |||
@@ -160,7 +162,8 @@ public class BuiltInQProfileRepositoryImplTest { | |||
@Test | |||
public void create_no_BuiltInQProfile_when_all_definitions_apply_to_non_defined_languages() { | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages(), new DummyProfileDefinition("foo", "P1", false)); | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), ruleFinder, new Languages(), | |||
new DummyProfileDefinition("foo", "P1", false)); | |||
underTest.initialize(); | |||
@@ -172,9 +175,9 @@ public class BuiltInQProfileRepositoryImplTest { | |||
RuleDefinitionDto rule1 = db.rules().insert(); | |||
db.rules().insertDeprecatedKey(d -> d.setRuleUuid(rule1.getUuid()).setOldRepositoryKey("oldRepo").setOldRuleKey("oldKey")); | |||
RuleDefinitionDto rule2 = db.rules().insert(); | |||
List<DummyProfileDefinition> definitions = singletonList(new DummyProfileDefinition("foo", "foo", false, | |||
asList(RuleKey.of("oldRepo", "oldKey"), rule2.getKey()))); | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), definitions.toArray(new BuiltInQualityProfilesDefinition[0])); | |||
DummyProfileDefinition definition = new DummyProfileDefinition("foo", "foo", false, | |||
asList(RuleKey.of("oldRepo", "oldKey"), rule2.getKey())); | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE), definition); | |||
underTest.initialize(); | |||
@@ -190,8 +193,8 @@ public class BuiltInQProfileRepositoryImplTest { | |||
@Test | |||
public void fail_with_ISE_when_rule_does_not_exist() { | |||
List<DummyProfileDefinition> definitions = singletonList(new DummyProfileDefinition("foo", "foo", false, singletonList(EXTERNAL_XOO))); | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), definitions.toArray(new BuiltInQualityProfilesDefinition[0])); | |||
DummyProfileDefinition[] definitions = new DummyProfileDefinition[] {new DummyProfileDefinition("foo", "foo", false, singletonList(EXTERNAL_XOO))}; | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE), definitions); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage(String.format("Rule with key '%s' not found", EXTERNAL_XOO.toString())); | |||
@@ -201,9 +204,8 @@ public class BuiltInQProfileRepositoryImplTest { | |||
@Test | |||
public void fail_with_ISE_when_two_profiles_with_different_name_are_default_for_the_same_language() { | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, new Languages(FOO_LANGUAGE), | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(dbClient, ruleFinder, new Languages(FOO_LANGUAGE), | |||
new DummyProfileDefinition("foo", "foo1", true), new DummyProfileDefinition("foo", "foo2", true)); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("Several Quality profiles are flagged as default for the language foo: [foo1, foo2]"); | |||
@@ -212,7 +214,7 @@ public class BuiltInQProfileRepositoryImplTest { | |||
@Test | |||
public void get_throws_ISE_if_called_before_initialize() { | |||
BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages()); | |||
BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), ruleFinder, new Languages()); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("initialize must be called first"); | |||
@@ -222,7 +224,7 @@ public class BuiltInQProfileRepositoryImplTest { | |||
@Test | |||
public void initialize_throws_ISE_if_called_twice() { | |||
BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages()); | |||
BuiltInQProfileRepositoryImpl underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), ruleFinder, new Languages()); | |||
underTest.initialize(); | |||
expectedException.expect(IllegalStateException.class); | |||
@@ -233,7 +235,7 @@ public class BuiltInQProfileRepositoryImplTest { | |||
@Test | |||
public void initialize_throws_ISE_if_language_has_no_builtin_qp() { | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), new Languages(FOO_LANGUAGE)); | |||
BuiltInQProfileRepository underTest = new BuiltInQProfileRepositoryImpl(mock(DbClient.class), ruleFinder, new Languages(FOO_LANGUAGE)); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("The following languages have no built-in quality profiles: foo"); |
@@ -26,6 +26,7 @@ import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.LinkedHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
@@ -35,7 +36,6 @@ import java.util.function.Supplier; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.Stream; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.lang.ObjectUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.picocontainer.Startable; | |||
import org.sonar.api.resources.Languages; | |||
@@ -72,7 +72,9 @@ import static com.google.common.base.Preconditions.checkState; | |||
import static com.google.common.collect.Sets.difference; | |||
import static com.google.common.collect.Sets.intersection; | |||
import static java.lang.String.format; | |||
import static java.util.Collections.emptyList; | |||
import static java.util.Collections.emptySet; | |||
import static java.util.Collections.unmodifiableMap; | |||
import static org.sonar.core.util.stream.MoreCollectors.toList; | |||
import static org.sonar.core.util.stream.MoreCollectors.toSet; | |||
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; | |||
@@ -113,7 +115,7 @@ public class RegisterRules implements Startable { | |||
@Override | |||
public void start() { | |||
Profiler profiler = Profiler.create(LOG).startInfo("Register rules"); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
try (DbSession dbSession = dbClient.openSession(true)) { | |||
RulesDefinition.Context ruleDefinitionContext = defLoader.load(); | |||
List<RulesDefinition.Repository> repositories = ruleDefinitionContext.repositories(); | |||
RegisterRulesContext registerRulesContext = createRegisterRulesContext(dbSession); | |||
@@ -122,9 +124,7 @@ public class RegisterRules implements Startable { | |||
for (RulesDefinition.ExtendedRepository repoDef : repositories) { | |||
if (languages.get(repoDef.language()) != null) { | |||
for (RulesDefinition.Rule ruleDef : repoDef.rules()) { | |||
registerRule(registerRulesContext, ruleDef, dbSession); | |||
} | |||
registerRules(registerRulesContext, repoDef.rules(), dbSession); | |||
dbSession.commit(); | |||
} | |||
} | |||
@@ -153,7 +153,13 @@ public class RegisterRules implements Startable { | |||
Map<RuleKey, RuleDefinitionDto> allRules = dbClient.ruleDao().selectAllDefinitions(dbSession).stream() | |||
.collect(uniqueIndex(RuleDefinitionDto::getKey)); | |||
Map<String, Set<SingleDeprecatedRuleKey>> existingDeprecatedKeysById = loadDeprecatedRuleKeys(dbSession); | |||
return new RegisterRulesContext(allRules, existingDeprecatedKeysById); | |||
Map<String, List<RuleParamDto>> ruleParamsByRuleUuid = loadAllRuleParameters(dbSession); | |||
return new RegisterRulesContext(allRules, existingDeprecatedKeysById, ruleParamsByRuleUuid); | |||
} | |||
private Map<String, List<RuleParamDto>> loadAllRuleParameters(DbSession dbSession) { | |||
return dbClient.ruleDao().selectAllRuleParams(dbSession).stream() | |||
.collect(Collectors.groupingBy(RuleParamDto::getRuleUuid)); | |||
} | |||
private Map<String, Set<SingleDeprecatedRuleKey>> loadDeprecatedRuleKeys(DbSession dbSession) { | |||
@@ -167,6 +173,7 @@ public class RegisterRules implements Startable { | |||
private final Map<RuleKey, RuleDefinitionDto> dbRules; | |||
private final Set<RuleDefinitionDto> known; | |||
private final Map<String, Set<SingleDeprecatedRuleKey>> dbDeprecatedKeysByUuid; | |||
private final Map<String, List<RuleParamDto>> ruleParamsByRuleUuid; | |||
private final Map<RuleKey, RuleDefinitionDto> dbRulesByDbDeprecatedKey; | |||
// mutable data | |||
private final Set<RuleDefinitionDto> created = new HashSet<>(); | |||
@@ -175,10 +182,12 @@ public class RegisterRules implements Startable { | |||
private final Set<RuleDefinitionDto> unchanged = new HashSet<>(); | |||
private final Set<RuleDefinitionDto> removed = new HashSet<>(); | |||
private RegisterRulesContext(Map<RuleKey, RuleDefinitionDto> dbRules, Map<String, Set<SingleDeprecatedRuleKey>> dbDeprecatedKeysByUuid) { | |||
private RegisterRulesContext(Map<RuleKey, RuleDefinitionDto> dbRules, Map<String, Set<SingleDeprecatedRuleKey>> dbDeprecatedKeysByUuid, | |||
Map<String, List<RuleParamDto>> ruleParamsByRuleUuid) { | |||
this.dbRules = ImmutableMap.copyOf(dbRules); | |||
this.known = ImmutableSet.copyOf(dbRules.values()); | |||
this.dbDeprecatedKeysByUuid = dbDeprecatedKeysByUuid; | |||
this.ruleParamsByRuleUuid = ruleParamsByRuleUuid; | |||
this.dbRulesByDbDeprecatedKey = buildDbRulesByDbDeprecatedKey(dbDeprecatedKeysByUuid, dbRules); | |||
} | |||
@@ -187,19 +196,19 @@ public class RegisterRules implements Startable { | |||
Map<String, RuleDefinitionDto> dbRulesByRuleUuid = dbRules.values().stream() | |||
.collect(uniqueIndex(RuleDefinitionDto::getUuid)); | |||
ImmutableMap.Builder<RuleKey, RuleDefinitionDto> builder = ImmutableMap.builder(); | |||
Map<RuleKey, RuleDefinitionDto> rulesByKey = new LinkedHashMap<>(); | |||
for (Map.Entry<String, Set<SingleDeprecatedRuleKey>> entry : dbDeprecatedKeysByUuid.entrySet()) { | |||
String ruleUuid = entry.getKey(); | |||
RuleDefinitionDto rule = dbRulesByRuleUuid.get(ruleUuid); | |||
if (rule == null) { | |||
LOG.warn("Could not retrieve rule with uuid %s referenced by a deprecated rule key. " + | |||
"The following deprecated rule keys seem to be referencing a non-existing rule", | |||
"The following deprecated rule keys seem to be referencing a non-existing rule", | |||
ruleUuid, entry.getValue()); | |||
} else { | |||
entry.getValue().forEach(d -> builder.put(d.getOldRuleKeyAsRuleKey(), rule)); | |||
entry.getValue().forEach(d -> rulesByKey.put(d.getOldRuleKeyAsRuleKey(), rule)); | |||
} | |||
} | |||
return builder.build(); | |||
return unmodifiableMap(rulesByKey); | |||
} | |||
private boolean hasDbRules() { | |||
@@ -219,7 +228,7 @@ public class RegisterRules implements Startable { | |||
return res; | |||
} | |||
private ImmutableMap<RuleKey, SingleDeprecatedRuleKey> getDbDeprecatedKeysByOldRuleKey() { | |||
private Map<RuleKey, SingleDeprecatedRuleKey> getDbDeprecatedKeysByOldRuleKey() { | |||
return dbDeprecatedKeysByUuid.values().stream() | |||
.flatMap(Collection::stream) | |||
.collect(uniqueIndex(SingleDeprecatedRuleKey::getOldRuleKeyAsRuleKey)); | |||
@@ -229,6 +238,10 @@ public class RegisterRules implements Startable { | |||
return dbDeprecatedKeysByUuid.getOrDefault(rule.getUuid(), emptySet()); | |||
} | |||
private List<RuleParamDto> getRuleParametersFor(String ruleUuid) { | |||
return ruleParamsByRuleUuid.getOrDefault(ruleUuid, emptyList()); | |||
} | |||
private Stream<RuleDefinitionDto> getRemaining() { | |||
Set<RuleDefinitionDto> res = new HashSet<>(dbRules.values()); | |||
res.removeAll(unchanged); | |||
@@ -298,8 +311,7 @@ public class RegisterRules implements Startable { | |||
} | |||
private void persistRepositories(DbSession dbSession, List<RulesDefinition.Repository> repositories) { | |||
List<RuleRepositoryDto> dtos = repositories | |||
.stream() | |||
List<RuleRepositoryDto> dtos = repositories.stream() | |||
.map(r -> new RuleRepositoryDto(r.key(), r.language(), r.name())) | |||
.collect(toList(repositories.size())); | |||
List<String> keys = dtos.stream().map(RuleRepositoryDto::getKey).collect(toList(repositories.size())); | |||
@@ -313,46 +325,53 @@ public class RegisterRules implements Startable { | |||
// nothing | |||
} | |||
private void registerRule(RegisterRulesContext context, RulesDefinition.Rule ruleDef, DbSession session) { | |||
RuleKey ruleKey = RuleKey.of(ruleDef.repository().key(), ruleDef.key()); | |||
private void registerRules(RegisterRulesContext context, List<RulesDefinition.Rule> ruleDefs, DbSession session) { | |||
Map<RulesDefinition.Rule, RuleDefinitionDto> dtos = new LinkedHashMap<>(ruleDefs.size()); | |||
RuleDefinitionDto ruleDefinitionDto = context.getDbRuleFor(ruleDef) | |||
.orElseGet(() -> { | |||
RuleDefinitionDto newRule = createRuleDto(ruleDef, session); | |||
context.created(newRule); | |||
return newRule; | |||
}); | |||
for (RulesDefinition.Rule ruleDef : ruleDefs) { | |||
RuleKey ruleKey = RuleKey.of(ruleDef.repository().key(), ruleDef.key()); | |||
// we must detect renaming __before__ we modify the DTO | |||
if (!ruleDefinitionDto.getKey().equals(ruleKey)) { | |||
context.renamed(ruleDefinitionDto); | |||
ruleDefinitionDto.setRuleKey(ruleKey); | |||
} | |||
RuleDefinitionDto ruleDefinitionDto = context.getDbRuleFor(ruleDef) | |||
.orElseGet(() -> { | |||
RuleDefinitionDto newRule = createRuleDto(ruleDef, session); | |||
context.created(newRule); | |||
return newRule; | |||
}); | |||
dtos.put(ruleDef, ruleDefinitionDto); | |||
// we must detect renaming __before__ we modify the DTO | |||
if (!ruleDefinitionDto.getKey().equals(ruleKey)) { | |||
context.renamed(ruleDefinitionDto); | |||
ruleDefinitionDto.setRuleKey(ruleKey); | |||
} | |||
if (mergeRule(ruleDef, ruleDefinitionDto)) { | |||
context.updated(ruleDefinitionDto); | |||
} | |||
if (mergeRule(ruleDef, ruleDefinitionDto)) { | |||
context.updated(ruleDefinitionDto); | |||
} | |||
if (mergeDebtDefinitions(ruleDef, ruleDefinitionDto)) { | |||
context.updated(ruleDefinitionDto); | |||
} | |||
if (mergeDebtDefinitions(ruleDef, ruleDefinitionDto)) { | |||
context.updated(ruleDefinitionDto); | |||
} | |||
if (mergeTags(ruleDef, ruleDefinitionDto)) { | |||
context.updated(ruleDefinitionDto); | |||
} | |||
if (mergeTags(ruleDef, ruleDefinitionDto)) { | |||
context.updated(ruleDefinitionDto); | |||
} | |||
if (mergeSecurityStandards(ruleDef, ruleDefinitionDto)) { | |||
context.updated(ruleDefinitionDto); | |||
} | |||
if (mergeSecurityStandards(ruleDef, ruleDefinitionDto)) { | |||
context.updated(ruleDefinitionDto); | |||
} | |||
if (context.isUpdated(ruleDefinitionDto) || context.isRenamed(ruleDefinitionDto)) { | |||
update(session, ruleDefinitionDto); | |||
} else if (!context.isCreated(ruleDefinitionDto)) { | |||
context.unchanged(ruleDefinitionDto); | |||
if (context.isUpdated(ruleDefinitionDto) || context.isRenamed(ruleDefinitionDto)) { | |||
update(session, ruleDefinitionDto); | |||
} else if (!context.isCreated(ruleDefinitionDto)) { | |||
context.unchanged(ruleDefinitionDto); | |||
} | |||
} | |||
mergeParams(ruleDef, ruleDefinitionDto, session); | |||
updateDeprecatedKeys(context, ruleDef, ruleDefinitionDto, session); | |||
for (Map.Entry<RulesDefinition.Rule, RuleDefinitionDto> e : dtos.entrySet()) { | |||
mergeParams(context, e.getKey(), e.getValue(), session); | |||
updateDeprecatedKeys(context, e.getKey(), e.getValue(), session); | |||
} | |||
} | |||
private RuleDefinitionDto createRuleDto(RulesDefinition.Rule ruleDef, DbSession session) { | |||
@@ -409,23 +428,23 @@ public class RegisterRules implements Startable { | |||
private static boolean mergeRule(RulesDefinition.Rule def, RuleDefinitionDto dto) { | |||
boolean changed = false; | |||
if (!StringUtils.equals(dto.getName(), def.name())) { | |||
if (!Objects.equals(dto.getName(), def.name())) { | |||
dto.setName(def.name()); | |||
changed = true; | |||
} | |||
if (mergeDescription(def, dto)) { | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(dto.getPluginKey(), def.pluginKey())) { | |||
if (!Objects.equals(dto.getPluginKey(), def.pluginKey())) { | |||
dto.setPluginKey(def.pluginKey()); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(dto.getConfigKey(), def.internalKey())) { | |||
if (!Objects.equals(dto.getConfigKey(), def.internalKey())) { | |||
dto.setConfigKey(def.internalKey()); | |||
changed = true; | |||
} | |||
String severity = def.severity(); | |||
if (!ObjectUtils.equals(dto.getSeverityString(), severity)) { | |||
if (!Objects.equals(dto.getSeverityString(), severity)) { | |||
dto.setSeverity(severity); | |||
changed = true; | |||
} | |||
@@ -438,16 +457,16 @@ public class RegisterRules implements Startable { | |||
dto.setStatus(def.status()); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(dto.getScope().name(), def.scope().name())) { | |||
if (!Objects.equals(dto.getScope().name(), def.scope().name())) { | |||
dto.setScope(toDtoScope(def.scope())); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(dto.getLanguage(), def.repository().language())) { | |||
if (!Objects.equals(dto.getLanguage(), def.repository().language())) { | |||
dto.setLanguage(def.repository().language()); | |||
changed = true; | |||
} | |||
RuleType type = RuleType.valueOf(def.type().name()); | |||
if (!ObjectUtils.equals(dto.getType(), type.getDbConstant())) { | |||
if (!Objects.equals(dto.getType(), type.getDbConstant())) { | |||
dto.setType(type); | |||
changed = true; | |||
} | |||
@@ -460,11 +479,11 @@ public class RegisterRules implements Startable { | |||
private static boolean mergeDescription(RulesDefinition.Rule def, RuleDefinitionDto dto) { | |||
boolean changed = false; | |||
if (def.htmlDescription() != null && !StringUtils.equals(dto.getDescription(), def.htmlDescription())) { | |||
if (def.htmlDescription() != null && !Objects.equals(dto.getDescription(), def.htmlDescription())) { | |||
dto.setDescription(def.htmlDescription()); | |||
dto.setDescriptionFormat(Format.HTML); | |||
changed = true; | |||
} else if (def.markdownDescription() != null && !StringUtils.equals(dto.getDescription(), def.markdownDescription())) { | |||
} else if (def.markdownDescription() != null && !Objects.equals(dto.getDescription(), def.markdownDescription())) { | |||
dto.setDescription(def.markdownDescription()); | |||
dto.setDescriptionFormat(Format.MARKDOWN); | |||
changed = true; | |||
@@ -490,27 +509,27 @@ public class RegisterRules implements Startable { | |||
@Nullable String remediationCoefficient, @Nullable String remediationOffset, @Nullable String effortToFixDescription) { | |||
boolean changed = false; | |||
if (!StringUtils.equals(dto.getDefRemediationFunction(), remediationFunction)) { | |||
if (!Objects.equals(dto.getDefRemediationFunction(), remediationFunction)) { | |||
dto.setDefRemediationFunction(remediationFunction); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(dto.getDefRemediationGapMultiplier(), remediationCoefficient)) { | |||
if (!Objects.equals(dto.getDefRemediationGapMultiplier(), remediationCoefficient)) { | |||
dto.setDefRemediationGapMultiplier(remediationCoefficient); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(dto.getDefRemediationBaseEffort(), remediationOffset)) { | |||
if (!Objects.equals(dto.getDefRemediationBaseEffort(), remediationOffset)) { | |||
dto.setDefRemediationBaseEffort(remediationOffset); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(dto.getGapDescription(), effortToFixDescription)) { | |||
if (!Objects.equals(dto.getGapDescription(), effortToFixDescription)) { | |||
dto.setGapDescription(effortToFixDescription); | |||
changed = true; | |||
} | |||
return changed; | |||
} | |||
private void mergeParams(RulesDefinition.Rule ruleDef, RuleDefinitionDto rule, DbSession session) { | |||
List<RuleParamDto> paramDtos = dbClient.ruleDao().selectRuleParamsByRuleKey(session, rule.getKey()); | |||
private void mergeParams(RegisterRulesContext context, RulesDefinition.Rule ruleDef, RuleDefinitionDto rule, DbSession session) { | |||
List<RuleParamDto> paramDtos = context.getRuleParametersFor(rule.getUuid()); | |||
Map<String, RuleParamDto> existingParamsByName = new HashMap<>(); | |||
Profiler profiler = Profiler.create(Loggers.get(getClass())); | |||
@@ -556,23 +575,22 @@ public class RegisterRules implements Startable { | |||
private static boolean mergeParam(RuleParamDto paramDto, RulesDefinition.Param paramDef) { | |||
boolean changed = false; | |||
if (!StringUtils.equals(paramDto.getType(), paramDef.type().toString())) { | |||
if (!Objects.equals(paramDto.getType(), paramDef.type().toString())) { | |||
paramDto.setType(paramDef.type().toString()); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(paramDto.getDefaultValue(), paramDef.defaultValue())) { | |||
if (!Objects.equals(paramDto.getDefaultValue(), paramDef.defaultValue())) { | |||
paramDto.setDefaultValue(paramDef.defaultValue()); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(paramDto.getDescription(), paramDef.description())) { | |||
if (!Objects.equals(paramDto.getDescription(), paramDef.description())) { | |||
paramDto.setDescription(paramDef.description()); | |||
changed = true; | |||
} | |||
return changed; | |||
} | |||
private void updateDeprecatedKeys(RegisterRulesContext context, RulesDefinition.Rule ruleDef, RuleDefinitionDto rule, | |||
DbSession dbSession) { | |||
private void updateDeprecatedKeys(RegisterRulesContext context, RulesDefinition.Rule ruleDef, RuleDefinitionDto rule, DbSession dbSession) { | |||
Set<SingleDeprecatedRuleKey> deprecatedRuleKeysFromDefinition = SingleDeprecatedRuleKey.from(ruleDef); | |||
Set<SingleDeprecatedRuleKey> deprecatedRuleKeysFromDB = context.getDBDeprecatedKeysFor(rule); | |||
@@ -604,9 +622,9 @@ public class RegisterRules implements Startable { | |||
changed = true; | |||
} else if (dto.getSystemTags().size() != ruleDef.tags().size() || | |||
!dto.getSystemTags().containsAll(ruleDef.tags())) { | |||
dto.setSystemTags(ruleDef.tags()); | |||
changed = true; | |||
} | |||
dto.setSystemTags(ruleDef.tags()); | |||
changed = true; | |||
} | |||
return changed; | |||
} | |||
@@ -618,9 +636,9 @@ public class RegisterRules implements Startable { | |||
changed = true; | |||
} else if (dto.getSecurityStandards().size() != ruleDef.securityStandards().size() || | |||
!dto.getSecurityStandards().containsAll(ruleDef.securityStandards())) { | |||
dto.setSecurityStandards(ruleDef.securityStandards()); | |||
changed = true; | |||
} | |||
dto.setSecurityStandards(ruleDef.securityStandards()); | |||
changed = true; | |||
} | |||
return changed; | |||
} | |||
@@ -669,31 +687,31 @@ public class RegisterRules implements Startable { | |||
private static boolean updateCustomRuleFromTemplateRule(RuleDefinitionDto customRule, RuleDefinitionDto templateRule) { | |||
boolean changed = false; | |||
if (!StringUtils.equals(customRule.getLanguage(), templateRule.getLanguage())) { | |||
if (!Objects.equals(customRule.getLanguage(), templateRule.getLanguage())) { | |||
customRule.setLanguage(templateRule.getLanguage()); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(customRule.getConfigKey(), templateRule.getConfigKey())) { | |||
if (!Objects.equals(customRule.getConfigKey(), templateRule.getConfigKey())) { | |||
customRule.setConfigKey(templateRule.getConfigKey()); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(customRule.getPluginKey(), templateRule.getPluginKey())) { | |||
if (!Objects.equals(customRule.getPluginKey(), templateRule.getPluginKey())) { | |||
customRule.setPluginKey(templateRule.getPluginKey()); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(customRule.getDefRemediationFunction(), templateRule.getDefRemediationFunction())) { | |||
if (!Objects.equals(customRule.getDefRemediationFunction(), templateRule.getDefRemediationFunction())) { | |||
customRule.setDefRemediationFunction(templateRule.getDefRemediationFunction()); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(customRule.getDefRemediationGapMultiplier(), templateRule.getDefRemediationGapMultiplier())) { | |||
if (!Objects.equals(customRule.getDefRemediationGapMultiplier(), templateRule.getDefRemediationGapMultiplier())) { | |||
customRule.setDefRemediationGapMultiplier(templateRule.getDefRemediationGapMultiplier()); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(customRule.getDefRemediationBaseEffort(), templateRule.getDefRemediationBaseEffort())) { | |||
if (!Objects.equals(customRule.getDefRemediationBaseEffort(), templateRule.getDefRemediationBaseEffort())) { | |||
customRule.setDefRemediationBaseEffort(templateRule.getDefRemediationBaseEffort()); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(customRule.getGapDescription(), templateRule.getGapDescription())) { | |||
if (!Objects.equals(customRule.getGapDescription(), templateRule.getGapDescription())) { | |||
customRule.setGapDescription(templateRule.getGapDescription()); | |||
changed = true; | |||
} | |||
@@ -701,11 +719,11 @@ public class RegisterRules implements Startable { | |||
customRule.setStatus(templateRule.getStatus()); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(customRule.getSeverityString(), templateRule.getSeverityString())) { | |||
if (!Objects.equals(customRule.getSeverityString(), templateRule.getSeverityString())) { | |||
customRule.setSeverity(templateRule.getSeverityString()); | |||
changed = true; | |||
} | |||
if (!StringUtils.equals(customRule.getRepositoryKey(), templateRule.getRepositoryKey())) { | |||
if (!Objects.equals(customRule.getRepositoryKey(), templateRule.getRepositoryKey())) { | |||
customRule.setRepositoryKey(templateRule.getRepositoryKey()); | |||
changed = true; | |||
} | |||
@@ -771,7 +789,7 @@ public class RegisterRules implements Startable { | |||
lazyToString(() -> intersection.stream().map(RuleKey::toString).collect(Collectors.joining(",")))); | |||
// Find incorrect usage of deprecated keys | |||
ImmutableMap<RuleKey, SingleDeprecatedRuleKey> dbDeprecatedRuleKeysByOldRuleKey = registerRulesContext.getDbDeprecatedKeysByOldRuleKey(); | |||
Map<RuleKey, SingleDeprecatedRuleKey> dbDeprecatedRuleKeysByOldRuleKey = registerRulesContext.getDbDeprecatedKeysByOldRuleKey(); | |||
Set<String> incorrectRuleKeyMessage = definedRules.stream() | |||
.flatMap(r -> filterInvalidDeprecatedRuleKeys(dbDeprecatedRuleKeysByOldRuleKey, r)) |
@@ -19,9 +19,6 @@ | |||
*/ | |||
package org.sonar.server.startup; | |||
import static com.google.common.collect.FluentIterable.concat; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
@@ -39,6 +36,9 @@ import org.sonar.db.DbSession; | |||
import org.sonar.db.metric.MetricDto; | |||
import org.sonar.server.metric.MetricToDto; | |||
import static com.google.common.collect.FluentIterable.concat; | |||
import static com.google.common.collect.Lists.newArrayList; | |||
public class RegisterMetrics implements Startable { | |||
private static final Logger LOG = Loggers.get(RegisterMetrics.class); | |||
@@ -72,7 +72,7 @@ public class RegisterMetrics implements Startable { | |||
void register(Iterable<Metric> metrics) { | |||
Profiler profiler = Profiler.create(LOG).startInfo("Register metrics"); | |||
try (DbSession session = dbClient.openSession(false)) { | |||
try (DbSession session = dbClient.openSession(true)) { | |||
save(session, metrics); | |||
sanitizeQualityGates(session); | |||
session.commit(); |
@@ -95,6 +95,7 @@ public class CachingRuleFinderTest { | |||
verify(dbClient).openSession(anyBoolean()); | |||
verify(ruleDao).selectAllDefinitions(dbSession); | |||
verify(ruleDao).selectAllRuleParams(dbSession); | |||
verifyNoMoreInteractions(ruleDao); | |||
} | |||
@@ -110,7 +111,7 @@ public class CachingRuleFinderTest { | |||
new CachingRuleFinder(dbClient); | |||
verify(ruleDao).selectRuleParamsByRuleKeys(dbSession, ImmutableSet.copyOf(ruleKeys)); | |||
verify(ruleDao).selectAllRuleParams(dbSession); | |||
} | |||
@Test |
@@ -102,7 +102,7 @@ public class RegisterRulesTest { | |||
private static final RuleKey RULE_KEY3 = RuleKey.of("fake", "rule3"); | |||
private static final RuleKey HOTSPOT_RULE_KEY = RuleKey.of("fake", "hotspot"); | |||
private TestSystem2 system = new TestSystem2().setNow(DATE1.getTime()); | |||
private final TestSystem2 system = new TestSystem2().setNow(DATE1.getTime()); | |||
@org.junit.Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@@ -113,14 +113,16 @@ public class RegisterRulesTest { | |||
@org.junit.Rule | |||
public LogTester logTester = new LogTester(); | |||
private QProfileRules qProfileRules = mock(QProfileRules.class); | |||
private WebServerRuleFinder webServerRuleFinder = mock(WebServerRuleFinder.class); | |||
private DbClient dbClient = db.getDbClient(); | |||
private final QProfileRules qProfileRules = mock(QProfileRules.class); | |||
private final WebServerRuleFinder webServerRuleFinder = mock(WebServerRuleFinder.class); | |||
private final DbClient dbClient = db.getDbClient(); | |||
private final MetadataIndex metadataIndex = mock(MetadataIndex.class); | |||
private final UuidFactory uuidFactory = UuidFactoryFast.getInstance(); | |||
private RuleIndexer ruleIndexer; | |||
private ActiveRuleIndexer activeRuleIndexer; | |||
private RuleIndex ruleIndex; | |||
private MetadataIndex metadataIndex = mock(MetadataIndex.class); | |||
private UuidFactory uuidFactory = UuidFactoryFast.getInstance(); | |||
@Before | |||
public void before() { | |||
@@ -996,7 +998,7 @@ public class RegisterRulesTest { | |||
} | |||
@SafeVarargs | |||
private final void createRule(RulesDefinition.Context context, String language, String repositoryKey, String ruleKey, Consumer<NewRule>... consumers) { | |||
private void createRule(RulesDefinition.Context context, String language, String repositoryKey, String ruleKey, Consumer<NewRule>... consumers) { | |||
NewRepository repo = context.createRepository(repositoryKey, language); | |||
NewRule newRule = repo.createRule(ruleKey) | |||
.setName(ruleKey) |
@@ -45,8 +45,9 @@ public class RegisterMetricsTest { | |||
@Rule | |||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
private UuidFactory uuidFactory = new SequenceUuidFactory(); | |||
private DbClient dbClient = dbTester.getDbClient(); | |||
private final UuidFactory uuidFactory = new SequenceUuidFactory(); | |||
private final DbClient dbClient = dbTester.getDbClient(); | |||
private final RegisterMetrics register = new RegisterMetrics(dbClient, uuidFactory); | |||
/** | |||
* Insert new metrics, including custom metrics | |||
@@ -65,7 +66,6 @@ public class RegisterMetricsTest { | |||
.setUserManaged(true) | |||
.create(); | |||
RegisterMetrics register = new RegisterMetrics(dbClient, uuidFactory); | |||
register.register(asList(m1, custom)); | |||
Map<String, MetricDto> metricsByKey = selectAllMetrics(); | |||
@@ -91,7 +91,6 @@ public class RegisterMetricsTest { | |||
.setDirection(1) | |||
.setHidden(false)); | |||
RegisterMetrics register = new RegisterMetrics(dbClient, uuidFactory); | |||
Metric m1 = new Metric.Builder("m1", "New name", Metric.ValueType.FLOAT) | |||
.setDescription("new description") | |||
.setDirection(-1) | |||
@@ -115,7 +114,6 @@ public class RegisterMetricsTest { | |||
IntStream.range(0, count) | |||
.forEach(t -> dbTester.measures().insertMetric(m -> m.setEnabled(random.nextBoolean()))); | |||
RegisterMetrics register = new RegisterMetrics(dbClient, uuidFactory); | |||
register.register(Collections.emptyList()); | |||
assertThat(selectAllMetrics().values().stream()) | |||
@@ -128,7 +126,6 @@ public class RegisterMetricsTest { | |||
MetricDto enabledMetric = dbTester.measures().insertMetric(t -> t.setEnabled(true)); | |||
MetricDto disabledMetric = dbTester.measures().insertMetric(t -> t.setEnabled(false)); | |||
RegisterMetrics register = new RegisterMetrics(dbClient, uuidFactory); | |||
register.register(asList(builderOf(enabledMetric).create(), builderOf(disabledMetric).create())); | |||
assertThat(selectAllMetrics().values()) | |||
@@ -138,7 +135,6 @@ public class RegisterMetricsTest { | |||
@Test | |||
public void insert_core_metrics() { | |||
RegisterMetrics register = new RegisterMetrics(dbClient, uuidFactory); | |||
register.start(); | |||
assertThat(dbTester.countRowsOfTable("metrics")).isEqualTo(CoreMetrics.getMetrics().size()); |
@@ -73,8 +73,7 @@ public class RegisterQualityGates implements Startable { | |||
private final UuidFactory uuidFactory; | |||
private final System2 system2; | |||
public RegisterQualityGates(DbClient dbClient, | |||
QualityGateConditionsUpdater qualityGateConditionsUpdater, UuidFactory uuidFactory, System2 system2) { | |||
public RegisterQualityGates(DbClient dbClient, QualityGateConditionsUpdater qualityGateConditionsUpdater, UuidFactory uuidFactory, System2 system2) { | |||
this.dbClient = dbClient; | |||
this.qualityGateConditionsUpdater = qualityGateConditionsUpdater; | |||
this.qualityGateDao = dbClient.qualityGateDao(); | |||
@@ -212,7 +211,7 @@ public class RegisterQualityGates implements Startable { | |||
.setQualityGateUuid(qualityGateUuid); | |||
} | |||
// id does not belongs to equals to be able to be compared with builtin | |||
// id does not belong to equals to be able to be compared with builtin | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
@@ -227,7 +226,7 @@ public class RegisterQualityGates implements Startable { | |||
Objects.equals(errorThreshold, that.errorThreshold); | |||
} | |||
// id does not belongs to hashcode to be able to be compared with builtin | |||
// id does not belong to hashcode to be able to be compared with builtin | |||
@Override | |||
public int hashCode() { | |||
return Objects.hash(metricKey, operator, errorThreshold); |
@@ -47,6 +47,8 @@ import org.sonar.db.qualityprofile.QProfileDto; | |||
import org.sonar.db.qualityprofile.RulesProfileDto; | |||
import org.sonar.db.rule.RuleDefinitionDto; | |||
import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; | |||
import org.sonar.server.rule.DefaultRuleFinder; | |||
import org.sonar.server.rule.ServerRuleFinder; | |||
import org.sonar.server.rule.index.RuleIndex; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import org.sonar.server.util.TypeValidations; | |||
@@ -62,6 +64,7 @@ import static org.mockito.ArgumentMatchers.anyLong; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoInteractions; | |||
import static org.mockito.Mockito.verifyZeroInteractions; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.api.rules.RulePriority.MAJOR; | |||
@@ -90,7 +93,9 @@ public class RegisterQualityProfilesNotificationTest { | |||
private DbClient dbClient = db.getDbClient(); | |||
private TypeValidations typeValidations = mock(TypeValidations.class); | |||
private ActiveRuleIndexer activeRuleIndexer = mock(ActiveRuleIndexer.class); | |||
private BuiltInQProfileInsert builtInQProfileInsert = new BuiltInQProfileInsertImpl(dbClient, system2, UuidFactoryFast.getInstance(), typeValidations, activeRuleIndexer); | |||
private ServerRuleFinder ruleFinder = new DefaultRuleFinder(dbClient); | |||
private BuiltInQProfileInsert builtInQProfileInsert = new BuiltInQProfileInsertImpl(dbClient, ruleFinder, system2, UuidFactoryFast.getInstance(), | |||
typeValidations, activeRuleIndexer); | |||
private RuleActivator ruleActivator = new RuleActivator(system2, dbClient, typeValidations, userSessionRule); | |||
private QProfileRules qProfileRules = new QProfileRulesImpl(dbClient, ruleActivator, mock(RuleIndex.class), activeRuleIndexer); | |||
private BuiltInQProfileUpdate builtInQProfileUpdate = new BuiltInQProfileUpdateImpl(dbClient, ruleActivator, activeRuleIndexer); | |||
@@ -120,7 +125,7 @@ public class RegisterQualityProfilesNotificationTest { | |||
underTest.start(); | |||
verifyZeroInteractions(builtInQualityProfilesNotification); | |||
verifyNoInteractions(builtInQualityProfilesNotification); | |||
} | |||
@Test |
@@ -170,15 +170,15 @@ public abstract class PlatformLevel { | |||
return addIfStandalone; | |||
} | |||
private WebServer getWebServer() { | |||
protected WebServer getWebServer() { | |||
return getOptional(WebServer.class) | |||
.orElseThrow(() -> new IllegalStateException("WebServer not available in Pico yet")); | |||
} | |||
private abstract class AddIf { | |||
protected abstract class AddIf { | |||
private final boolean condition; | |||
private AddIf(boolean condition) { | |||
protected AddIf(boolean condition) { | |||
this.condition = condition; | |||
} | |||
@@ -29,6 +29,7 @@ import org.sonar.server.platform.StartupMetadataPersister; | |||
import org.sonar.server.platform.WebCoreExtensionsInstaller; | |||
import org.sonar.server.platform.db.migration.NoopDatabaseMigrationImpl; | |||
import org.sonar.server.platform.serverid.ServerIdModule; | |||
import org.sonar.server.plugins.DetectPluginChange; | |||
import org.sonar.server.setting.DatabaseSettingLoader; | |||
import org.sonar.server.setting.DatabaseSettingsEnabler; | |||
@@ -42,7 +43,9 @@ public class PlatformLevel3 extends PlatformLevel { | |||
@Override | |||
protected void configureLevel() { | |||
addIfStartupLeader(StartupMetadataPersister.class); | |||
addIfStartupLeader( | |||
StartupMetadataPersister.class, | |||
DetectPluginChange.class); | |||
add( | |||
NoopDatabaseMigrationImpl.class, | |||
ServerIdModule.class, |
@@ -23,10 +23,12 @@ import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.core.platform.EditionProvider; | |||
import org.sonar.core.platform.PlatformEditionProvider; | |||
import org.sonar.server.app.ProcessCommandWrapper; | |||
import org.sonar.server.authentication.DefaultAdminCredentialsVerifierImpl; | |||
import org.sonar.server.ce.queue.CeQueueCleaner; | |||
import org.sonar.server.es.IndexerStartupTask; | |||
import org.sonar.server.platform.ServerLifecycleNotifier; | |||
import org.sonar.server.platform.web.RegisterServletFilters; | |||
import org.sonar.server.plugins.DetectPluginChange; | |||
import org.sonar.server.plugins.PluginConsentVerifier; | |||
import org.sonar.server.qualitygate.ProjectsInWarningDaemon; | |||
import org.sonar.server.qualitygate.RegisterQualityGates; | |||
@@ -47,6 +49,8 @@ import org.sonar.server.user.DoPrivileged; | |||
import org.sonar.server.user.ThreadLocalUserSession; | |||
public class PlatformLevelStartup extends PlatformLevel { | |||
private AddIfStartupLeaderAndPluginsChanged addIfPluginsChanged; | |||
public PlatformLevelStartup(PlatformLevel parent) { | |||
super("startup tasks", parent); | |||
} | |||
@@ -54,29 +58,57 @@ public class PlatformLevelStartup extends PlatformLevel { | |||
@Override | |||
protected void configureLevel() { | |||
add(GeneratePluginIndex.class, | |||
RegisterPlugins.class, | |||
ServerLifecycleNotifier.class); | |||
addIfStartupLeader( | |||
IndexerStartupTask.class, | |||
IndexerStartupTask.class); | |||
addIfStartupLeaderAndPluginsChanged( | |||
RegisterMetrics.class, | |||
RegisterQualityGates.class, | |||
RegisterRules.class); | |||
add(BuiltInQProfileLoader.class); | |||
RegisterRules.class, | |||
BuiltInQProfileLoader.class); | |||
addIfStartupLeader( | |||
BuiltInQualityProfilesUpdateListener.class, | |||
BuiltInQProfileUpdateImpl.class); | |||
addIfStartupLeaderAndPluginsChanged( | |||
BuiltInQProfileInsertImpl.class, | |||
BuiltInQProfileUpdateImpl.class, | |||
RegisterQualityProfiles.class, | |||
RegisterQualityProfiles.class); | |||
addIfStartupLeader( | |||
RegisterPermissionTemplates.class, | |||
RenameDeprecatedPropertyKeys.class, | |||
CeQueueCleaner.class, | |||
UpgradeSuggestionsCleaner.class, | |||
PluginConsentVerifier.class); | |||
add(RegisterPlugins.class, | |||
// RegisterServletFilters makes the WebService engine of Level4 served by the MasterServletFilter, therefore it | |||
// must be started after all the other startup tasks | |||
RegisterServletFilters.class | |||
); | |||
} | |||
/** | |||
* Add a component to container only if plugins have changed since last start. | |||
* | |||
* @throws IllegalStateException if called from PlatformLevel3 or below, plugin info is loaded yet | |||
*/ | |||
AddIfStartupLeaderAndPluginsChanged addIfStartupLeaderAndPluginsChanged(Object... objects) { | |||
if (addIfPluginsChanged == null) { | |||
this.addIfPluginsChanged = new AddIfStartupLeaderAndPluginsChanged(getWebServer().isStartupLeader() && anyPluginChanged()); | |||
} | |||
addIfPluginsChanged.ifAdd(objects); | |||
return addIfPluginsChanged; | |||
} | |||
private boolean anyPluginChanged() { | |||
return getOptional(DetectPluginChange.class) | |||
.map(DetectPluginChange::anyPluginChanged) | |||
.orElseThrow(() -> new IllegalStateException("DetectPluginChange not available in Pico yet")); | |||
} | |||
// RegisterServletFilters makes the WebService engine of Level4 served by the MasterServletFilter, therefore it | |||
// must be started after all the other startup tasks | |||
add(RegisterServletFilters.class); | |||
public final class AddIfStartupLeaderAndPluginsChanged extends AddIf { | |||
private AddIfStartupLeaderAndPluginsChanged(boolean condition) { | |||
super(condition); | |||
} | |||
} | |||
@Override | |||
@@ -93,6 +125,7 @@ public class PlatformLevelStartup extends PlatformLevel { | |||
get(WebServerRuleFinder.class).stopCaching(); | |||
Loggers.get(PlatformLevelStartup.class) | |||
.info("Running {} Edition", get(PlatformEditionProvider.class).get().map(EditionProvider.Edition::getLabel).orElse("")); | |||
get(DefaultAdminCredentialsVerifierImpl.class).runAtStart(); | |||
} | |||
}); | |||