From: Guillaume Jambet Date: Tue, 10 Apr 2018 12:01:46 +0000 (+0200) Subject: SONAR-10544 save externally defined Rules if needed X-Git-Tag: 7.5~1326 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=a4f510d4548b71357412fcd0b6cac70ca1ec4277;p=sonarqube.git SONAR-10544 save externally defined Rules if needed --- diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java index 65f78d58d9f..ebf033b8316 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDao.java @@ -25,6 +25,7 @@ import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import javax.annotation.Nullable; + import org.apache.ibatis.session.ResultHandler; import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.RuleQuery; @@ -49,6 +50,11 @@ public class RuleDao implements Dao { return ofNullable(res); } + public RuleDto selectOrFailByKey(DbSession session, RuleKey key) { + RuleDefinitionDto ruleDefinitionDto = selectOrFailDefinitionByKey(session, key); + return new RuleDto(ruleDefinitionDto, new RuleMetadataDto()); + } + public Optional selectDefinitionByKey(DbSession session, RuleKey key) { return ofNullable(mapper(session).selectDefinitionByKey(key)); } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDefinitionDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDefinitionDto.java index 1b072c46594..c4180028480 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDefinitionDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/rule/RuleDefinitionDto.java @@ -122,11 +122,12 @@ public class RuleDefinitionDto { return this; } + @CheckForNull public String getDescriptionURL() { return descriptionURL; } - public RuleDefinitionDto setDescriptionURL(String descriptionURL) { + public RuleDefinitionDto setDescriptionURL(@Nullable String descriptionURL) { this.descriptionURL = descriptionURL; return this; } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/AddRuleExternalTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/AddRuleExternalTest.java index 850bf0c7610..c8ce8263fc7 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/AddRuleExternalTest.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v72/AddRuleExternalTest.java @@ -42,7 +42,11 @@ public class AddRuleExternalTest { @Test public void column_are_added_to_table() throws SQLException { + dbTester.assertColumnDoesNotExist("rules", "is_external"); + dbTester.assertColumnDoesNotExist("rules", "description_url"); + underTest.execute(); + dbTester.assertColumnDefinition("rules", "is_external", BOOLEAN, null, true); dbTester.assertColumnDefinition("rules", "description_url", VARCHAR, 256, true); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/NewExternalRule.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/NewExternalRule.java index a74632d02ff..1196c807e71 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/NewExternalRule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/NewExternalRule.java @@ -36,6 +36,7 @@ public class NewExternalRule implements Rule { private final String descriptionUrl; private final String severity; private final RuleType type; + private final String pluginKey; private NewExternalRule(Builder builder) { this.key = checkNotNull(builder.key, "key"); @@ -43,6 +44,7 @@ public class NewExternalRule implements Rule { this.descriptionUrl = builder.descriptionUrl; this.severity = checkNotEmpty(builder.severity, "severity"); this.type = checkNotNull(builder.type, "type"); + this.pluginKey = builder.pluginKey; } private static String checkNotEmpty(String str, String name) { @@ -110,7 +112,7 @@ public class NewExternalRule implements Rule { @Override public String getPluginKey() { - return null; + return pluginKey; } public static class Builder { @@ -119,6 +121,7 @@ public class NewExternalRule implements Rule { private String descriptionUrl; private String severity; private RuleType type; + private String pluginKey; public Builder setKey(RuleKey key) { this.key = key; @@ -164,5 +167,10 @@ public class NewExternalRule implements Rule { public NewExternalRule build() { return new NewExternalRule(this); } + + public Builder setPluginKey(String pluginKey) { + this.pluginKey = pluginKey; + return this; + } } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepository.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepository.java index 347638cddc4..adb1dd8d18e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepository.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepository.java @@ -22,6 +22,7 @@ package org.sonar.server.computation.task.projectanalysis.issue; import java.util.Optional; import java.util.function.Supplier; import org.sonar.api.rule.RuleKey; +import org.sonar.db.DbSession; /** * Repository of every rule in DB (including manual rules) whichever their status. @@ -45,6 +46,9 @@ public interface RuleRepository { Optional findByKey(RuleKey key); Optional findById(int id); - + void insertNewExternalRuleIfAbsent(RuleKey ruleKey, Supplier ruleSupplier); + + void persistNewExternalRules(DbSession dbSession); + } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepositoryImpl.java index e7f3cd61d80..32fbac077f6 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepositoryImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepositoryImpl.java @@ -19,13 +19,7 @@ */ package org.sonar.server.computation.task.projectanalysis.issue; -import com.google.common.collect.ImmutableMap; import com.google.common.collect.Multimap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Optional; -import java.util.function.Supplier; -import javax.annotation.CheckForNull; import org.sonar.api.rule.RuleKey; import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; @@ -33,6 +27,13 @@ import org.sonar.db.DbSession; import org.sonar.db.rule.DeprecatedRuleKeyDto; import org.sonar.db.rule.RuleDto; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; +import org.sonar.server.rule.RuleCreator; + +import javax.annotation.CheckForNull; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Supplier; import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; @@ -43,23 +44,39 @@ public class RuleRepositoryImpl implements RuleRepository { private Map rulesByKey; @CheckForNull private Map rulesById; - @CheckForNull - private Map newExternalRulesByKey; + private final RuleCreator creator; private final DbClient dbClient; private final AnalysisMetadataHolder analysisMetadataHolder; - public RuleRepositoryImpl(DbClient dbClient, AnalysisMetadataHolder analysisMetadataHolder) { + public RuleRepositoryImpl(RuleCreator creator, DbClient dbClient, AnalysisMetadataHolder analysisMetadataHolder) { + this.creator = creator; this.dbClient = dbClient; this.analysisMetadataHolder = analysisMetadataHolder; } public void insertNewExternalRuleIfAbsent(RuleKey ruleKey, Supplier ruleSupplier) { + ensureInitialized(); + if (!rulesByKey.containsKey(ruleKey)) { - newExternalRulesByKey.computeIfAbsent(ruleKey, s -> ruleSupplier.get()); + rulesByKey.computeIfAbsent(ruleKey, s -> ruleSupplier.get()); } } + @Override public void persistNewExternalRules(DbSession dbSession) { + ensureInitialized(); + + rulesByKey.values().stream() + .filter(NewExternalRule.class::isInstance) + .forEach(extRule -> persistAndIndex(dbSession, (NewExternalRule) extRule)); + } + + private void persistAndIndex(DbSession dbSession, NewExternalRule external) { + Rule rule = creator.create(dbSession, external); + rulesById.put(rule.getId(), rule); + rulesByKey.put(external.getKey(), rule); + } + @Override public Rule getByKey(RuleKey key) { verifyKeyArgument(key); @@ -109,20 +126,17 @@ public class RuleRepositoryImpl implements RuleRepository { } private void loadRulesFromDb(DbSession dbSession) { - ImmutableMap.Builder rulesByKeyBuilder = ImmutableMap.builder(); - ImmutableMap.Builder rulesByIdBuilder = ImmutableMap.builder(); + this.rulesByKey = new HashMap<>(); + this.rulesById = new HashMap<>(); String organizationUuid = analysisMetadataHolder.getOrganization().getUuid(); Multimap deprecatedRuleKeysByRuleId = dbClient.ruleDao().selectAllDeprecatedRuleKeys(dbSession).stream() .collect(MoreCollectors.index(DeprecatedRuleKeyDto::getRuleId)); for (RuleDto ruleDto : dbClient.ruleDao().selectAll(dbSession, organizationUuid)) { Rule rule = new RuleImpl(ruleDto); - rulesByKeyBuilder.put(ruleDto.getKey(), rule); - rulesByIdBuilder.put(ruleDto.getId(), rule); - deprecatedRuleKeysByRuleId.get(ruleDto.getId()).forEach(t -> rulesByKeyBuilder.put(RuleKey.of(t.getOldRepositoryKey(), t.getOldRuleKey()), rule)); + rulesByKey.put(ruleDto.getKey(), rule); + rulesById.put(ruleDto.getId(), rule); + deprecatedRuleKeysByRuleId.get(ruleDto.getId()).forEach(t -> rulesByKey.put(RuleKey.of(t.getOldRepositoryKey(), t.getOldRuleKey()), rule)); } - this.rulesByKey = rulesByKeyBuilder.build(); - this.rulesById = rulesByIdBuilder.build(); - this.newExternalRulesByKey = new LinkedHashMap<>(); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistExternalRulesStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistExternalRulesStep.java new file mode 100644 index 00000000000..aac5e714eeb --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/PersistExternalRulesStep.java @@ -0,0 +1,53 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.computation.task.projectanalysis.step; + +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.server.computation.task.projectanalysis.issue.RuleRepository; +import org.sonar.server.computation.task.step.ComputationStep; + +public class PersistExternalRulesStep implements ComputationStep { + + private final DbClient dbClient; + private final RuleRepository ruleRepository; + + public PersistExternalRulesStep(DbClient dbClient, RuleRepository ruleRepository) { + this.dbClient = dbClient; + this.ruleRepository = ruleRepository; + } + + @Override + public void execute() { + + try (DbSession dbSession = dbClient.openSession(true)) { + ruleRepository.persistNewExternalRules(dbSession); + dbSession.flushStatements(); + dbSession.commit(); + } + + } + + @Override + public String getDescription() { + return "Persist new externally defined Rules"; + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java index 9c9aa5116ea..8cb71963b0b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/step/ReportComputationSteps.java @@ -89,6 +89,7 @@ public class ReportComputationSteps extends AbstractComputationSteps { PersistAnalysisPropertiesStep.class, PersistMeasuresStep.class, PersistLiveMeasuresStep.class, + PersistExternalRulesStep.class, PersistIssuesStep.class, PersistProjectLinksStep.class, PersistEventsStep.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java b/server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java index b6823f0e3ef..73ab988cade 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/RuleCreator.java @@ -36,11 +36,14 @@ import org.sonar.api.utils.System2; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.organization.OrganizationDto; +import org.sonar.db.rule.RuleDao; import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.db.rule.RuleDto; import org.sonar.db.rule.RuleDto.Format; import org.sonar.db.rule.RuleMetadataDto; import org.sonar.db.rule.RuleParamDto; +import org.sonar.server.computation.task.projectanalysis.issue.NewExternalRule; +import org.sonar.server.computation.task.projectanalysis.issue.RuleImpl; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.rule.index.RuleIndexer; @@ -49,6 +52,7 @@ import org.sonar.server.util.TypeValidations; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.Lists.newArrayList; import static java.lang.String.format; +import static org.sonar.db.rule.RuleDto.Scope.ALL; import static org.sonar.server.ws.WsUtils.checkRequest; @ServerSide @@ -89,6 +93,20 @@ public class RuleCreator { return customRuleKey; } + public org.sonar.server.computation.task.projectanalysis.issue.Rule create(DbSession dbSession, NewExternalRule external) { + RuleDao dao = dbClient.ruleDao(); + dao.insert(dbSession, new RuleDefinitionDto() + .setRuleKey(external.getKey()) + .setPluginKey(external.getPluginKey()) + .setIsExternal(true) + .setName(external.getName()) + .setDescriptionURL(external.getDescriptionUrl()) + .setType(external.getType()) + .setScope(ALL) + .setSeverity(external.getSeverity())); + return new RuleImpl(dao.selectOrFailByKey(dbSession, external.getKey())); + } + private void validateCustomRule(NewCustomRule newRule, DbSession dbSession, RuleKey templateKey) { List errors = new ArrayList<>(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/NewExternalRuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/NewExternalRuleTest.java index 4b5f1944350..dd8b0978c21 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/NewExternalRuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/NewExternalRuleTest.java @@ -35,6 +35,7 @@ public class NewExternalRuleTest { NewExternalRule.Builder builder = new NewExternalRule.Builder() .setDescriptionUrl("url") .setKey(RuleKey.of("repo", "rule")) + .setPluginKey("repo") .setName("name") .setSeverity("MAJOR") .setType(RuleType.BUG); @@ -49,7 +50,7 @@ public class NewExternalRuleTest { assertThat(rule.getDescriptionUrl()).isEqualTo("url"); assertThat(rule.getName()).isEqualTo("name"); - assertThat(rule.getPluginKey()).isNull(); + assertThat(rule.getPluginKey()).isEqualTo("repo"); assertThat(rule.getSeverity()).isEqualTo("MAJOR"); assertThat(rule.getType()).isEqualTo(RuleType.BUG); assertThat(rule.getDescriptionUrl()).isEqualTo("url"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepositoryImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepositoryImplTest.java index 6dd3eee57a0..24400902b3d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepositoryImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepositoryImplTest.java @@ -21,21 +21,35 @@ package org.sonar.server.computation.task.projectanalysis.issue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; + import java.util.Optional; + import org.junit.Before; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.api.config.internal.MapSettings; import org.sonar.api.rule.RuleKey; import org.sonar.api.rule.RuleStatus; +import org.sonar.api.rule.Severity; import org.sonar.api.rules.RuleType; +import org.sonar.api.utils.System2; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.db.DbTester; import org.sonar.db.rule.DeprecatedRuleKeyDto; import org.sonar.db.rule.RuleDao; +import org.sonar.db.rule.RuleDefinitionDto; import org.sonar.db.rule.RuleDto; import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; +import org.sonar.server.es.EsTester; +import org.sonar.server.organization.TestDefaultOrganizationProvider; +import org.sonar.server.rule.RuleCreator; +import org.sonar.server.rule.index.RuleIndexDefinition; +import org.sonar.server.rule.index.RuleIndexer; +import org.sonar.server.util.TypeValidationsTesting; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; @@ -45,6 +59,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static org.mockito.internal.verification.VerificationModeFactory.times; +import static org.sonar.api.rule.Severity.BLOCKER; +import static org.sonar.api.rules.RuleType.BUG; +import static org.sonar.server.organization.TestDefaultOrganizationProvider.from; +import static org.sonar.server.util.TypeValidationsTesting.newFullTypeValidations; public class RuleRepositoryImplTest { @@ -64,11 +82,19 @@ public class RuleRepositoryImplTest { public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule() .setOrganizationUuid(ORGANIZATION_UUID, QUALITY_GATE_UUID); + @org.junit.Rule + public DbTester db = DbTester.create(System2.INSTANCE); + @org.junit.Rule + public EsTester es = new EsTester(new RuleIndexDefinition(new MapSettings().asConfig())); + + private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient()); + private RuleCreator creator = new RuleCreator(System2.INSTANCE, ruleIndexer, db.getDbClient(), newFullTypeValidations(), from(db)); + private DbClient dbClient = mock(DbClient.class); private DbSession dbSession = mock(DbSession.class); private RuleDao ruleDao = mock(RuleDao.class); - private RuleRepositoryImpl underTest = new RuleRepositoryImpl(dbClient, analysisMetadataHolder); + private RuleRepositoryImpl underTest = new RuleRepositoryImpl(creator, dbClient, analysisMetadataHolder); @Before public void setUp() throws Exception { @@ -255,6 +281,64 @@ public class RuleRepositoryImplTest { assertIsABRule(rule.get()); } + @Test + public void accept_new_externally_defined_Rules() { + DbClient dbClient = db.getDbClient(); + underTest = new RuleRepositoryImpl(creator, dbClient, analysisMetadataHolder); + + RuleKey ruleKey = RuleKey.of("eslint", "no-cond-assign"); + + underTest.insertNewExternalRuleIfAbsent(ruleKey, () -> new NewExternalRule.Builder() + .setKey(ruleKey) + .setPluginKey("eslint") + .setName("disallow assignment operators in conditional statements (no-cond-assign)") + .setDescriptionUrl("https://eslint.org/docs/rules/no-cond-assign") + .setSeverity(BLOCKER) + .setType(BUG) + .build()); + + + assertThat(underTest.getByKey(ruleKey)).isNotNull(); + assertThat(underTest.getByKey(ruleKey).getPluginKey()).isEqualTo("eslint"); + assertThat(underTest.getByKey(ruleKey).getName()).isEqualTo("disallow assignment operators in conditional statements (no-cond-assign)"); + assertThat(underTest.getByKey(ruleKey).getType()).isEqualTo(BUG); + + RuleDao ruleDao = dbClient.ruleDao(); + Optional ruleDefinitionDto = ruleDao.selectDefinitionByKey(dbClient.openSession(false), ruleKey); + assertThat(ruleDefinitionDto).isNotPresent(); + } + + @Test + public void persist_new_externally_defined_Rules() { + DbClient dbClient = db.getDbClient(); + DbSession dbSession = dbClient.openSession(false); + underTest = new RuleRepositoryImpl(creator, dbClient, analysisMetadataHolder); + + RuleKey ruleKey = RuleKey.of("eslint", "no-cond-assign"); + underTest.insertNewExternalRuleIfAbsent(ruleKey, () -> new NewExternalRule.Builder() + .setKey(ruleKey) + .setPluginKey("eslint") + .setName("disallow assignment operators in conditional statements (no-cond-assign)") + .setDescriptionUrl("https://eslint.org/docs/rules/no-cond-assign") + .setSeverity(BLOCKER) + .setType(BUG) + .build()); + + + underTest.persistNewExternalRules(dbSession); + + dbSession.commit(); + + RuleDao ruleDao = dbClient.ruleDao(); + Optional ruleDefinitionDto = ruleDao.selectDefinitionByKey(dbClient.openSession(false), ruleKey); + assertThat(ruleDefinitionDto).isPresent(); + + Rule rule = underTest.getByKey(ruleKey); + assertThat(rule).isNotNull(); + + assertThat(underTest.getById(ruleDefinitionDto.get().getId())).isNotNull(); + } + private void expectNullRuleKeyNPE() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("RuleKey can not be null"); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepositoryRule.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepositoryRule.java index 698954885aa..57300aca811 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepositoryRule.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/RuleRepositoryRule.java @@ -23,8 +23,10 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.function.Supplier; + import org.junit.rules.ExternalResource; import org.sonar.api.rule.RuleKey; +import org.sonar.db.DbSession; import static com.google.common.base.Preconditions.checkArgument; import static java.util.Objects.requireNonNull; @@ -65,6 +67,10 @@ public class RuleRepositoryRule extends ExternalResource implements RuleReposito return Optional.ofNullable(rulesById.get(id)); } + @Override public void persistNewExternalRules(DbSession dbSession) { + throw new UnsupportedOperationException(); + } + public DumbRule add(RuleKey key) { DumbRule rule = new DumbRule(key); rule.setId(key.hashCode()); diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistExternalRulesStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistExternalRulesStepTest.java new file mode 100644 index 00000000000..a9f0fdaf553 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistExternalRulesStepTest.java @@ -0,0 +1,114 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.computation.task.projectanalysis.step; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.utils.System2; +import org.sonar.db.DbClient; +import org.sonar.db.DbTester; +import org.sonar.db.rule.RuleDao; +import org.sonar.db.rule.RuleDefinitionDto; +import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; +import org.sonar.server.computation.task.projectanalysis.issue.NewExternalRule; +import org.sonar.server.computation.task.projectanalysis.issue.RuleRepositoryImpl; +import org.sonar.server.computation.task.step.ComputationStep; +import org.sonar.server.es.EsTester; +import org.sonar.server.rule.RuleCreator; +import org.sonar.server.rule.index.RuleIndexDefinition; +import org.sonar.server.rule.index.RuleIndexer; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.api.rule.Severity.BLOCKER; +import static org.sonar.api.rules.RuleType.BUG; +import static org.sonar.server.organization.TestDefaultOrganizationProvider.from; +import static org.sonar.server.util.TypeValidationsTesting.newFullTypeValidations; + +public class PersistExternalRulesStepTest extends BaseStepTest { + + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + @Rule + public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule() + .setOrganizationUuid("org-1", "qg-uuid-1"); + + private DbClient dbClient = db.getDbClient(); + private System2 system2 = System2.INSTANCE; + + private ComputationStep underTest; + private RuleRepositoryImpl ruleRepository; + + @org.junit.Rule + public EsTester es = new EsTester(new RuleIndexDefinition(new MapSettings().asConfig())); + + private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient()); + private RuleCreator creator = new RuleCreator(System2.INSTANCE, ruleIndexer, db.getDbClient(), newFullTypeValidations(), from(db)); + + + @Override + protected ComputationStep step() { + return underTest; + } + + @Before + public void setup() { + ruleRepository = new RuleRepositoryImpl(creator, dbClient, analysisMetadataHolder); + underTest = new PersistExternalRulesStep(dbClient, ruleRepository); + } + + @Test + public void persist_new_external_rules() { + + RuleKey ruleKey = RuleKey.of("eslint", "no-cond-assign"); + ruleRepository.insertNewExternalRuleIfAbsent(ruleKey, () -> new NewExternalRule.Builder() + .setKey(ruleKey) + .setPluginKey("eslint") + .setName("disallow assignment operators in conditional statements (no-cond-assign)") + .setDescriptionUrl("https://eslint.org/docs/rules/no-cond-assign") + .setSeverity(BLOCKER) + .setType(BUG) + .build()); + + underTest.execute(); + + RuleDao ruleDao = dbClient.ruleDao(); + Optional ruleDefinitionDtoOptional = ruleDao.selectDefinitionByKey(dbClient.openSession(false), ruleKey); + assertThat(ruleDefinitionDtoOptional).isPresent(); + + RuleDefinitionDto reloaded = ruleDefinitionDtoOptional.get(); + assertThat(reloaded.getRuleKey()).isEqualTo("no-cond-assign"); + assertThat(reloaded.getRepositoryKey()).isEqualTo("eslint"); + assertThat(reloaded.isExternal()).isTrue(); + assertThat(reloaded.getType()).isEqualTo(2); + assertThat(reloaded.getSeverity()).isEqualTo(4); + assertThat(reloaded.getDescriptionURL()).isEqualTo("https://eslint.org/docs/rules/no-cond-assign"); + assertThat(reloaded.getName()).isEqualTo("disallow assignment operators in conditional statements (no-cond-assign)"); + assertThat(reloaded.getPluginKey()).isEqualTo("eslint"); + + + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistIssuesStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistIssuesStepTest.java index 684ad94b3b4..2d3590b42fb 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistIssuesStepTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/step/PersistIssuesStepTest.java @@ -27,6 +27,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.sonar.api.config.internal.MapSettings; import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.RuleType; import org.sonar.api.utils.System2; @@ -50,6 +51,10 @@ import org.sonar.server.computation.task.projectanalysis.issue.IssueCache; import org.sonar.server.computation.task.projectanalysis.issue.RuleRepositoryImpl; import org.sonar.server.computation.task.projectanalysis.issue.UpdateConflictResolver; import org.sonar.server.computation.task.step.ComputationStep; +import org.sonar.server.es.EsTester; +import org.sonar.server.rule.RuleCreator; +import org.sonar.server.rule.index.RuleIndexDefinition; +import org.sonar.server.rule.index.RuleIndexer; import org.sonar.server.util.cache.DiskCache; import static java.util.Collections.singletonList; @@ -61,6 +66,8 @@ import static org.sonar.api.issue.Issue.STATUS_CLOSED; import static org.sonar.api.issue.Issue.STATUS_OPEN; import static org.sonar.api.rule.Severity.BLOCKER; import static org.sonar.db.component.ComponentTesting.newFileDto; +import static org.sonar.server.organization.TestDefaultOrganizationProvider.from; +import static org.sonar.server.util.TypeValidationsTesting.newFullTypeValidations; public class PersistIssuesStepTest extends BaseStepTest { @@ -82,6 +89,12 @@ public class PersistIssuesStepTest extends BaseStepTest { private IssueCache issueCache; private ComputationStep step; + @org.junit.Rule + public EsTester es = new EsTester(new RuleIndexDefinition(new MapSettings().asConfig())); + + private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), db.getDbClient()); + private RuleCreator creator = new RuleCreator(System2.INSTANCE, ruleIndexer, db.getDbClient(), newFullTypeValidations(), from(db)); + @Override protected ComputationStep step() { return step; @@ -94,7 +107,7 @@ public class PersistIssuesStepTest extends BaseStepTest { when(system2.now()).thenReturn(NOW); reportReader.setMetadata(ScannerReport.Metadata.getDefaultInstance()); - step = new PersistIssuesStep(dbClient, system2, new UpdateConflictResolver(), new RuleRepositoryImpl(dbClient, analysisMetadataHolder), issueCache); + step = new PersistIssuesStep(dbClient, system2, new UpdateConflictResolver(), new RuleRepositoryImpl(creator, dbClient, analysisMetadataHolder), issueCache); } @After