From e1be2686b59c2fc63f83bd91aa91a784ee3a8632 Mon Sep 17 00:00:00 2001 From: Pierre Date: Tue, 10 May 2022 11:05:35 +0200 Subject: [PATCH] SONAR-16303 QP import/export should use a flat description, and not sections, as they are not supported for custom rules --- .../db/qualityprofile/ExportRuleDto.java | 26 +- .../QualityProfileExportMapper.xml | 15 +- .../QualityProfileExportDaoTest.java | 8 +- .../server/rule/index/RuleIndexerTest.java | 13 +- .../server/qualityprofile/ImportedRule.java | 13 +- .../qualityprofile/QProfileBackuperImpl.java | 7 +- .../server/qualityprofile/QProfileParser.java | 42 +- .../org/sonar/server/rule/NewCustomRule.java | 15 - .../rule/NewRuleDescriptionSection.java | 39 - .../org/sonar/server/rule/RuleCreator.java | 32 +- .../QProfileBackuperImplTest.java | 40 +- .../qualityprofile/QProfileParserTest.java | 32 +- .../sonar/server/rule/RuleCreatorTest.java | 1100 +++++++++-------- 13 files changed, 622 insertions(+), 760 deletions(-) delete mode 100644 server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/NewRuleDescriptionSection.java diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ExportRuleDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ExportRuleDto.java index 3795c115eb7..a823e188961 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ExportRuleDto.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/qualityprofile/ExportRuleDto.java @@ -21,18 +21,14 @@ package org.sonar.db.qualityprofile; import java.util.LinkedList; import java.util.List; -import java.util.Optional; -import java.util.Set; +import java.util.Objects; import org.sonar.api.rule.RuleKey; import org.sonar.api.rules.RuleType; -import org.sonar.db.rule.RuleDescriptionSectionDto; import org.sonar.db.rule.SeverityUtil; -import static java.util.Optional.ofNullable; -import static org.sonar.db.rule.RuleDescriptionSectionDto.DEFAULT_KEY; - public class ExportRuleDto { private String activeRuleUuid = null; + private String description = null; private String repository = null; private String rule = null; private String name = null; @@ -44,8 +40,6 @@ public class ExportRuleDto { private List params = null; - private Set ruleDescriptionSectionDtos = null; - public boolean isCustomRule() { return template != null; } @@ -82,6 +76,10 @@ public class ExportRuleDto { return name; } + public String getDescriptionOrThrow() { + return Objects.requireNonNull(description, "description is expected to be set but it is null"); + } + public List getParams() { if (params == null) { params = new LinkedList<>(); @@ -93,16 +91,4 @@ public class ExportRuleDto { this.params = params; } - public Set getRuleDescriptionSections() { - return ruleDescriptionSectionDtos; - } - - public Optional getDefaultRuleDescriptionSectionDto() { - return findExistingSectionWithSameKey(DEFAULT_KEY); - } - - private Optional findExistingSectionWithSameKey(String ruleDescriptionSectionKey) { - return ofNullable(ruleDescriptionSectionDtos).flatMap(sections -> - sections.stream().filter(section -> section.getKey().equals(ruleDescriptionSectionKey)).findAny()); - } } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileExportMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileExportMapper.xml index d323a166cf0..57d80943f23 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileExportMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/qualityprofile/QualityProfileExportMapper.xml @@ -9,9 +9,10 @@ rds.content as "rds_content", - + left outer join rule_desc_sections rds on rds.rule_uuid = r.uuid + and rds.kee = 'default' @@ -26,7 +27,8 @@ r.rule_type as "type", rt.plugin_rule_key as "template", rm.note_data as "extendedDescription", - rm.tags + rm.tags, + rds.content as "description" @@ -46,12 +48,7 @@ - - - - - - + @@ -64,7 +61,7 @@ inner join rules r on r.uuid = a.rule_uuid and r.status != 'REMOVED' left join rules rt on rt.uuid = r.template_uuid left join rules_metadata rm on rm.rule_uuid = r.uuid - + where oqp.uuid = #{id, jdbcType=VARCHAR} diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileExportDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileExportDaoTest.java index 9c1f9c09261..0c446f4f76d 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileExportDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/qualityprofile/QualityProfileExportDaoTest.java @@ -46,8 +46,8 @@ public class QualityProfileExportDaoTest { @Rule public DbTester db = DbTester.create(new AlwaysIncreasingSystem2()); - private DbSession dbSession = db.getSession(); - private QualityProfileExportDao underTest = db.getDbClient().qualityProfileExportDao(); + private final DbSession dbSession = db.getSession(); + private final QualityProfileExportDao underTest = db.getDbClient().qualityProfileExportDao(); @Test public void selectRulesByProfile_ready_rules_only() { @@ -96,7 +96,7 @@ public class QualityProfileExportDaoTest { assertThat(exportCustomRuleDto).isNotNull(); assertThat(exportCustomRuleDto.isCustomRule()).isTrue(); assertThat(exportCustomRuleDto.getParams()).isEmpty(); - assertThat(exportCustomRuleDto.getRuleDescriptionSections().iterator().next().getContent()).isEqualTo(customRuleContent); + assertThat(exportCustomRuleDto.getDescriptionOrThrow()).isEqualTo(customRuleContent); assertThat(exportCustomRuleDto.getExtendedDescription()).isEqualTo(customRuleMetadata.getNoteData()); assertThat(exportCustomRuleDto.getName()).isEqualTo(customRule.getName()); assertThat(exportCustomRuleDto.getRuleKey()).isEqualTo(customRule.getKey()); @@ -112,7 +112,7 @@ public class QualityProfileExportDaoTest { assertThat(exportRuleDto).isNotNull(); assertThat(exportRuleDto.isCustomRule()).isFalse(); assertThat(exportRuleDto.getParams()).isEmpty(); - assertThat(exportRuleDto.getRuleDescriptionSections().iterator().next().getContent()).isEqualTo(ruleContent); + assertThat(exportRuleDto.getDescriptionOrThrow()).isEqualTo(ruleContent); assertThat(exportRuleDto.getExtendedDescription()).isEqualTo(ruleMetadata.getNoteData()); assertThat(exportRuleDto.getName()).isEqualTo(rule.getName()); assertThat(exportRuleDto.getRuleKey()).isEqualTo(rule.getKey()); diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexerTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexerTest.java index fbe76eebf31..c47c8ab560c 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexerTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/rule/index/RuleIndexerTest.java @@ -23,12 +23,6 @@ import com.google.common.collect.ImmutableSet; import com.tngtech.java.junit.dataprovider.DataProvider; import com.tngtech.java.junit.dataprovider.DataProviderRunner; import com.tngtech.java.junit.dataprovider.UseDataProvider; -import java.util.EnumSet; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.stream.IntStream; -import java.util.stream.Stream; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -49,6 +43,13 @@ import org.sonar.server.es.EsTester; import org.sonar.server.security.SecurityStandards; import org.sonar.server.security.SecurityStandards.SQCategory; +import java.util.EnumSet; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.stream.IntStream; +import java.util.stream.Stream; + import static com.google.common.collect.Sets.newHashSet; import static java.lang.String.format; import static java.util.Collections.emptyList; diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ImportedRule.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ImportedRule.java index a9d2e60c01e..ee5d2d0b081 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ImportedRule.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/ImportedRule.java @@ -19,11 +19,9 @@ */ package org.sonar.server.qualityprofile; -import java.util.HashSet; import java.util.Map; -import java.util.Set; + import org.sonar.api.rule.RuleKey; -import org.sonar.server.rule.NewRuleDescriptionSection; class ImportedRule { private String key = null; @@ -36,7 +34,6 @@ class ImportedRule { private String severity = null; private String description = null; private Map parameters = null; - private Set ruleDescriptionSections = new HashSet<>(); public Map getParameters() { return parameters; } @@ -94,14 +91,6 @@ class ImportedRule { return template != null; } - public Set getRuleDescriptionSections() { - return ruleDescriptionSections; - } - - public void addRuleDescriptionSection(NewRuleDescriptionSection ruleDescriptionSection) { - this.ruleDescriptionSections.add(ruleDescriptionSection); - } - public void setRepository(String repository) { this.repository = repository; } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java index 742e09c4d22..99f173b8625 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileBackuperImpl.java @@ -45,7 +45,6 @@ import org.sonar.db.rule.DeprecatedRuleKeyDto; import org.sonar.db.rule.RuleDto; import org.sonar.server.qualityprofile.builtin.QProfileName; import org.sonar.server.rule.NewCustomRule; -import org.sonar.server.rule.NewRuleDescriptionSection; import org.sonar.server.rule.RuleCreator; import static com.google.common.base.Preconditions.checkArgument; @@ -98,12 +97,9 @@ public class QProfileBackuperImpl implements QProfileBackuper { importedRule.setSeverity(exportRuleDto.getSeverityString()); if (importedRule.isCustomRule()) { importedRule.setTemplate(exportRuleDto.getTemplateRuleKey().rule()); + importedRule.setDescription(exportRuleDto.getDescriptionOrThrow()); } importedRule.setType(exportRuleDto.getRuleType().name()); - exportRuleDto.getRuleDescriptionSections() - .stream() - .map(r -> new NewRuleDescriptionSection(r.getKey(), r.getContent())) - .forEach(importedRule::addRuleDescriptionSection); importedRule.setParameters(exportRuleDto.getParams().stream().collect(Collectors.toMap(ExportRuleParamDto::getKey, ExportRuleParamDto::getValue))); importedRules.add(importedRule); } @@ -221,7 +217,6 @@ public class QProfileBackuperImpl implements QProfileBackuper { .setPreventReactivation(true) .setType(RuleType.valueOf(r.getType())) .setMarkdownDescription(r.getDescription()) - .setRuleDescriptionSections(r.getRuleDescriptionSections()) .setParameters(r.getParameters()); } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileParser.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileParser.java index ec4db716e3c..171368bfc82 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileParser.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualityprofile/QProfileParser.java @@ -42,8 +42,6 @@ import org.sonar.api.utils.text.XmlWriter; import org.sonar.db.qualityprofile.ExportRuleDto; import org.sonar.db.qualityprofile.ExportRuleParamDto; import org.sonar.db.qualityprofile.QProfileDto; -import org.sonar.db.rule.RuleDescriptionSectionDto; -import org.sonar.server.rule.NewRuleDescriptionSection; @ServerSide public class QProfileParser { @@ -52,10 +50,6 @@ public class QProfileParser { private static final String ATTRIBUTE_LANGUAGE = "language"; private static final String ATTRIBUTE_RULES = "rules"; private static final String ATTRIBUTE_RULE = "rule"; - private static final String ATTRIBUTE_DESCRIPTION_SECTIONS = "descriptionSections"; - private static final String ATTRIBUTE_DESCRIPTION_SECTION = "descriptionSection"; - private static final String ATTRIBUTE_DESCRIPTION_SECTION_KEY = "key"; - private static final String ATTRIBUTE_DESCRIPTION_SECTION_CONTENT = "content"; private static final String ATTRIBUTE_REPOSITORY_KEY = "repositoryKey"; private static final String ATTRIBUTE_KEY = "key"; private static final String ATTRIBUTE_PRIORITY = "priority"; @@ -85,19 +79,7 @@ public class QProfileParser { if (ruleToExport.isCustomRule()) { xml.prop(ATTRIBUTE_NAME, ruleToExport.getName()); xml.prop(ATTRIBUTE_TEMPLATE_KEY, ruleToExport.getTemplateRuleKey().rule()); - if (!ruleToExport.getRuleDescriptionSections().isEmpty()) { - ruleToExport.getDefaultRuleDescriptionSectionDto() - .map(RuleDescriptionSectionDto::getContent) - .ifPresent(desc -> xml.prop(ATTRIBUTE_DESCRIPTION, desc)); - } - xml.begin(ATTRIBUTE_DESCRIPTION_SECTIONS); - for (RuleDescriptionSectionDto ruleDescriptionSection : ruleToExport.getRuleDescriptionSections()) { - xml.begin(ATTRIBUTE_DESCRIPTION_SECTION) - .prop(ATTRIBUTE_DESCRIPTION_SECTION_KEY, ruleDescriptionSection.getKey()) - .prop(ATTRIBUTE_DESCRIPTION_SECTION_CONTENT, ruleDescriptionSection.getContent()) - .end(); - } - xml.end(ATTRIBUTE_DESCRIPTION_SECTIONS); + xml.prop(ATTRIBUTE_DESCRIPTION, ruleToExport.getDescriptionOrThrow()); } xml.begin(ATTRIBUTE_PARAMETERS); @@ -199,9 +181,6 @@ public class QProfileParser { SMInputCursor propsCursor = ruleCursor.childElementCursor(ATTRIBUTE_PARAMETER); readParameters(propsCursor, parameters); rule.setParameters(parameters); - } else if (StringUtils.equals(ATTRIBUTE_DESCRIPTION_SECTIONS, nodeName)) { - SMInputCursor propsCursor = ruleCursor.childElementCursor(ATTRIBUTE_DESCRIPTION_SECTION); - readDescriptionSections(propsCursor, rule); } } } @@ -224,23 +203,4 @@ public class QProfileParser { } } } - - private static void readDescriptionSections(SMInputCursor propsCursor, ImportedRule importedRule) throws XMLStreamException { - while (propsCursor.getNext() != null) { - SMInputCursor propCursor = propsCursor.childElementCursor(); - String key = null; - String description = null; - while (propCursor.getNext() != null) { - String nodeName = propCursor.getLocalName(); - if (StringUtils.equals(ATTRIBUTE_DESCRIPTION_SECTION_KEY, nodeName)) { - key = StringUtils.trim(propCursor.collectDescendantText(false)); - } else if (StringUtils.equals(ATTRIBUTE_DESCRIPTION_SECTION_CONTENT, nodeName)) { - description = StringUtils.trim(propCursor.collectDescendantText(false)); - } - } - if (key != null && description != null) { - importedRule.addRuleDescriptionSection(new NewRuleDescriptionSection(key, description)); - } - } - } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/NewCustomRule.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/NewCustomRule.java index d824eb92769..baa19e4f31d 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/NewCustomRule.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/NewCustomRule.java @@ -21,11 +21,8 @@ package org.sonar.server.rule; import com.google.common.base.Preconditions; import com.google.common.base.Strings; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.api.rule.RuleKey; @@ -43,8 +40,6 @@ public class NewCustomRule { private RuleType type; private Map parameters = new HashMap<>(); - private Set ruleDescriptionSections = new HashSet<>(); - private boolean preventReactivation = false; private NewCustomRule() { @@ -55,7 +50,6 @@ public class NewCustomRule { return ruleKey; } - @CheckForNull public RuleKey templateKey() { return templateKey; } @@ -120,15 +114,6 @@ public class NewCustomRule { return this; } - public Set getRuleDescriptionSections() { - return Collections.unmodifiableSet(ruleDescriptionSections); - } - - public NewCustomRule setRuleDescriptionSections(Set sections) { - this.ruleDescriptionSections = sections; - return this; - } - public boolean isPreventReactivation() { return preventReactivation; } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/NewRuleDescriptionSection.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/NewRuleDescriptionSection.java deleted file mode 100644 index 7ab1ed79522..00000000000 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/NewRuleDescriptionSection.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2022 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.rule; - -public class NewRuleDescriptionSection { - private final String key; - - private final String content; - - public NewRuleDescriptionSection(String key, String content) { - this.key = key; - this.content = content; - } - - public String getKey() { - return key; - } - - public String getContent() { - return content; - } -} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleCreator.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleCreator.java index c3d82ccdd91..0a90a400c03 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleCreator.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/rule/RuleCreator.java @@ -49,6 +49,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 java.util.Objects.requireNonNull; import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection; import static org.sonar.server.exceptions.BadRequestException.checkRequest; @@ -72,7 +73,6 @@ public class RuleCreator { public RuleKey create(DbSession dbSession, NewCustomRule newRule) { RuleKey templateKey = newRule.templateKey(); - checkArgument(templateKey != null, "Rule template key should not be null"); RuleDto templateRule = dbClient.ruleDao().selectByKey(dbSession, templateKey) .orElseThrow(() -> new IllegalArgumentException(format(TEMPLATE_KEY_NOT_EXIST_FORMAT, templateKey))); checkArgument(templateRule.isTemplate(), "This rule is not a template rule: %s", templateKey.toString()); @@ -166,18 +166,11 @@ public class RuleCreator { } private static void validateDescription(List errors, NewCustomRule newRule) { - boolean missingDescription = newRule.getRuleDescriptionSections().isEmpty() ? - Strings.isNullOrEmpty(newRule.markdownDescription()) : - noDescriptionSectionHasContent(newRule); - if (missingDescription) { + if (Strings.isNullOrEmpty(newRule.markdownDescription())) { errors.add("The description is missing"); } } - private static boolean noDescriptionSectionHasContent(NewCustomRule newRule) { - return newRule.getRuleDescriptionSections().stream().map(NewRuleDescriptionSection::getContent).allMatch(Strings::isNullOrEmpty); - } - private static void validateRuleKey(List errors, String ruleKey) { if (!ruleKey.matches("^[\\w]+$")) { errors.add(format("The rule key \"%s\" is invalid, it should only contain: a-z, 0-9, \"_\"", ruleKey)); @@ -189,6 +182,7 @@ public class RuleCreator { } private String createCustomRule(RuleKey ruleKey, NewCustomRule newRule, RuleDto templateRuleDto, DbSession dbSession) { + RuleDescriptionSectionDto ruleDescriptionSectionDto = createDefaultRuleDescriptionSection(uuidFactory.create(), requireNonNull(newRule.markdownDescription())); RuleDto ruleDto = new RuleDto() .setUuid(uuidFactory.create()) .setRuleKey(ruleKey) @@ -210,23 +204,9 @@ public class RuleCreator { .setIsExternal(false) .setIsAdHoc(false) .setCreatedAt(system2.now()) - .setUpdatedAt(system2.now()); - - ruleDto.setDescriptionFormat(Format.MARKDOWN); - - if (newRule.getRuleDescriptionSections().isEmpty() && newRule.markdownDescription() != null) { - RuleDescriptionSectionDto ruleDescriptionSectionDto = createDefaultRuleDescriptionSection(uuidFactory.create(), newRule.markdownDescription()); - ruleDto.addRuleDescriptionSectionDto(ruleDescriptionSectionDto); - } else { - for (NewRuleDescriptionSection ruleDescriptionSection : newRule.getRuleDescriptionSections()) { - RuleDescriptionSectionDto ruleDescriptionSectionDto = RuleDescriptionSectionDto.builder() - .uuid(uuidFactory.create()) - .key(ruleDescriptionSection.getKey()) - .content(ruleDescriptionSection.getContent()) - .build(); - ruleDto.addRuleDescriptionSectionDto(ruleDescriptionSectionDto); - } - } + .setUpdatedAt(system2.now()) + .setDescriptionFormat(Format.MARKDOWN) + .addRuleDescriptionSectionDto(ruleDescriptionSectionDto); Set tags = templateRuleDto.getTags(); if (!tags.isEmpty()) { diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java index 522938b2261..52f573821d4 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileBackuperImplTest.java @@ -20,14 +20,6 @@ package org.sonar.server.qualityprofile; import com.google.common.io.Resources; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nullable; import org.junit.Rule; import org.junit.Test; import org.sonar.api.impl.utils.AlwaysIncreasingSystem2; @@ -47,6 +39,15 @@ import org.sonar.db.rule.RuleParamDto; import org.sonar.server.qualityprofile.builtin.QProfileName; import org.sonar.server.rule.RuleCreator; +import javax.annotation.Nullable; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -167,7 +168,6 @@ public class QProfileBackuperImplTest { "" + rule.getName() + "" + "" + templateRule.getKey().rule() + "" + "" + rule.getDefaultRuleDescriptionSection().getContent() + "" + - "default" + rule.getDefaultRuleDescriptionSection().getContent() + "" + "" + "" + param.getName() + "" + "20" + @@ -399,6 +399,28 @@ public class QProfileBackuperImplTest { assertThat(reset.calledProfile).isEqualTo(to); } + @Test + public void copy_profile_with_custom_rule() { + RuleDto templateRule = db.rules().insert(ruleDefinitionDto -> ruleDefinitionDto + .setIsTemplate(true)); + RuleDto rule = db.rules().insert(ruleDefinitionDto -> ruleDefinitionDto + .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(UuidFactoryFast.getInstance().create(), "custom rule description")) + .setName("custom rule name") + .setStatus(RuleStatus.READY) + .setTemplateUuid(templateRule.getUuid())); + + RuleParamDto param = db.rules().insertRuleParam(rule); + QProfileDto from = createProfile(rule.getLanguage()); + ActiveRuleDto activeRule = activate(from, rule, param); + + QProfileDto to = createProfile(rule.getLanguage()); + underTest.copy(db.getSession(), from, to); + + assertThat(reset.calledActivations).extracting(RuleActivation::getRuleUuid).containsOnly(activeRule.getRuleUuid()); + assertThat(reset.calledActivations.get(0).getParameter(param.getName())).isEqualTo("20"); + assertThat(reset.calledProfile).isEqualTo(to); + } + @Test public void fail_to_restore_if_bad_xml_format() { DbSession session = db.getSession(); diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileParserTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileParserTest.java index f832b5fdce4..263ae3d2394 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileParserTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/qualityprofile/QProfileParserTest.java @@ -28,7 +28,7 @@ import static org.assertj.core.api.Assertions.assertThat; public class QProfileParserTest { @Test - public void readOlderVersionXml() { + public void readXml() { Reader backup = new StringReader("" + "" + "custom rule" + @@ -53,34 +53,4 @@ public class QProfileParserTest { var importedRule = importedQProfile.getRules().get(0); assertThat(importedRule.getDescription()).isEqualTo("custom rule description"); } - - @Test - public void readNewVersionXml() { - Reader backup = new StringReader("" + - "" + - "custom rule" + - "js" + - "" + - "sonarjs" + - "s001" + - "CODE_SMELL" + - "CRITICAL" + - "custom rule name" + - "rule_mc8" + - "defaultcustom rule section content" + - "" + - "bar" + - "baz" + - "" + - "" + - ""); - var parser = new QProfileParser(); - var importedQProfile = parser.readXml(backup); - assertThat(importedQProfile.getRules()).hasSize(1); - var importedRule = importedQProfile.getRules().get(0); - assertThat(importedRule.getRuleDescriptionSections()).hasSize(1); - var section = importedRule.getRuleDescriptionSections().iterator().next(); - assertThat(section.getKey()).isEqualTo("default"); - assertThat(section.getContent()).isEqualTo("custom rule section content"); - } } diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleCreatorTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleCreatorTest.java index 7516b80edd5..46d27094d6d 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleCreatorTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/rule/RuleCreatorTest.java @@ -23,10 +23,8 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import java.time.Instant; import java.util.Arrays; -import java.util.Collections; import java.util.Date; import java.util.List; -import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import org.assertj.core.api.Fail; import org.junit.Rule; @@ -52,7 +50,9 @@ import org.sonar.server.rule.index.RuleIndex; import org.sonar.server.rule.index.RuleIndexer; import org.sonar.server.rule.index.RuleQuery; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.Assert.fail; import static org.sonar.db.rule.RuleDescriptionSectionDto.createDefaultRuleDescriptionSection; @@ -61,547 +61,563 @@ import static org.sonar.server.util.TypeValidationsTesting.newFullTypeValidation public class RuleCreatorTest { - private System2 system2 = new TestSystem2().setNow(Instant.now().toEpochMilli()); - - @Rule - public DbTester dbTester = DbTester.create(system2); - - @Rule - public EsTester es = EsTester.create(); - - private RuleIndex ruleIndex = new RuleIndex(es.client(), system2); - private RuleIndexer ruleIndexer = new RuleIndexer(es.client(), dbTester.getDbClient()); - private DbSession dbSession = dbTester.getSession(); - private UuidFactory uuidFactory = new SequenceUuidFactory(); - - private RuleCreator underTest = new RuleCreator(system2, new RuleIndexer(es.client(), dbTester.getDbClient()), dbTester.getDbClient(), newFullTypeValidations(), uuidFactory); - - @Test - public void create_custom_rule() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - // Create custom rule - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setMarkdownDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - RuleKey customRuleKey = underTest.create(dbSession, newRule); - - RuleDto rule = dbTester.getDbClient().ruleDao().selectOrFailByKey(dbSession, customRuleKey); - assertThat(rule).isNotNull(); - assertThat(rule.getKey()).isEqualTo(RuleKey.of("java", "CUSTOM_RULE")); - assertThat(rule.getPluginKey()).isEqualTo("sonarjava"); - assertThat(rule.getTemplateUuid()).isEqualTo(templateRule.getUuid()); - assertThat(rule.getName()).isEqualTo("My custom"); - assertThat(rule.getDefaultRuleDescriptionSection().getContent()).isEqualTo("Some description"); - assertThat(rule.getSeverityString()).isEqualTo("MAJOR"); - assertThat(rule.getStatus()).isEqualTo(RuleStatus.READY); - assertThat(rule.getLanguage()).isEqualTo("java"); - assertThat(rule.getConfigKey()).isEqualTo("S001"); - assertThat(rule.getDefRemediationFunction()).isEqualTo("LINEAR_OFFSET"); - assertThat(rule.getDefRemediationGapMultiplier()).isEqualTo("1h"); - assertThat(rule.getDefRemediationBaseEffort()).isEqualTo("5min"); - assertThat(rule.getGapDescription()).isEqualTo("desc"); - assertThat(rule.getTags()).containsOnly("usertag1", "usertag2"); - assertThat(rule.getSystemTags()).containsOnly("tag1", "tag4"); - assertThat(rule.getSecurityStandards()).containsOnly("owaspTop10:a1", "cwe:123"); - assertThat(rule.isExternal()).isFalse(); - assertThat(rule.isAdHoc()).isFalse(); - - List params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); - assertThat(params).hasSize(1); - - RuleParamDto param = params.get(0); - // From template rule - assertThat(param.getName()).isEqualTo("regex"); - assertThat(param.getDescription()).isEqualTo("Reg ex"); - assertThat(param.getType()).isEqualTo("STRING"); - // From user - assertThat(param.getDefaultValue()).isEqualTo("a.*"); - - assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getUuids()).containsOnly(rule.getUuid(), templateRule.getUuid()); - } - - @Test - public void create_custom_rule_with_both_markdown_description_and_description_sections() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - // Create custom rule - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setMarkdownDescription("Markdown description") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "new description section"))) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY); - RuleKey customRuleKey = underTest.create(dbSession, newRule); - - RuleDto rule = dbTester.getDbClient().ruleDao().selectOrFailByKey(dbSession, customRuleKey); - assertThat(rule).isNotNull(); - assertThat(rule.getKey()).isEqualTo(RuleKey.of("java", "CUSTOM_RULE")); - assertThat(rule.getPluginKey()).isEqualTo("sonarjava"); - assertThat(rule.getTemplateUuid()).isEqualTo(templateRule.getUuid()); - assertThat(rule.getName()).isEqualTo("My custom"); - assertThat(rule.getDefaultRuleDescriptionSection().getContent()).isEqualTo("new description section"); - assertThat(rule.getSeverityString()).isEqualTo("MAJOR"); - assertThat(rule.getStatus()).isEqualTo(RuleStatus.READY); - assertThat(rule.getLanguage()).isEqualTo("java"); - assertThat(rule.getConfigKey()).isEqualTo("S001"); - assertThat(rule.getDefRemediationFunction()).isEqualTo("LINEAR_OFFSET"); - assertThat(rule.getDefRemediationGapMultiplier()).isEqualTo("1h"); - assertThat(rule.getDefRemediationBaseEffort()).isEqualTo("5min"); - assertThat(rule.getGapDescription()).isEqualTo("desc"); - assertThat(rule.getTags()).containsOnly("usertag1", "usertag2"); - assertThat(rule.getSystemTags()).containsOnly("tag1", "tag4"); - assertThat(rule.getSecurityStandards()).containsOnly("owaspTop10:a1", "cwe:123"); - assertThat(rule.isExternal()).isFalse(); - assertThat(rule.isAdHoc()).isFalse(); - } - - @Test - public void create_custom_rule_with_empty_parameter_value() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - NewRuleDescriptionSection defaultSection = new NewRuleDescriptionSection("default", "some description"); - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setRuleDescriptionSections(Set.of(defaultSection)) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "")); - - RuleKey customRuleKey = underTest.create(dbSession, newRule); - - List params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); - assertThat(params).hasSize(1); - RuleParamDto param = params.get(0); - assertThat(param.getName()).isEqualTo("regex"); - assertThat(param.getDescription()).isEqualTo("Reg ex"); - assertThat(param.getType()).isEqualTo("STRING"); - assertThat(param.getDefaultValue()).isNull(); - } - - @Test - public void create_custom_rule_with_no_parameter_value() { - // insert template rule - RuleDto templateRule = createTemplateRuleWithIntArrayParam(); - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY); - - RuleKey customRuleKey = underTest.create(dbSession, newRule); - - List params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); - assertThat(params).hasSize(1); - RuleParamDto param = params.get(0); - assertThat(param.getName()).isEqualTo("myIntegers"); - assertThat(param.getDescription()).isEqualTo("My Integers"); - assertThat(param.getType()).isEqualTo("INTEGER,multiple=true,values=1;2;3"); - assertThat(param.getDefaultValue()).isNull(); - } - - @Test - public void create_custom_rule_with_multiple_parameter_values() { - // insert template rule - RuleDto templateRule = createTemplateRuleWithIntArrayParam(); - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("myIntegers", "1,3")); - - RuleKey customRuleKey = underTest.create(dbSession, newRule); - - List params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); - assertThat(params).hasSize(1); - RuleParamDto param = params.get(0); - assertThat(param.getName()).isEqualTo("myIntegers"); - assertThat(param.getDescription()).isEqualTo("My Integers"); - assertThat(param.getType()).isEqualTo("INTEGER,multiple=true,values=1;2;3"); - assertThat(param.getDefaultValue()).isEqualTo("1,3"); - } - - @Test - public void batch_create_custom_rules() { - // insert template rule - RuleDto templateRule = createTemplateRuleWithIntArrayParam(); - - NewCustomRule firstRule = NewCustomRule.createForCustomRule("CUSTOM_RULE_1", templateRule.getKey()) - .setName("My custom") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY); - - NewCustomRule secondRule = NewCustomRule.createForCustomRule("CUSTOM_RULE_2", templateRule.getKey()) - .setName("My custom") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY); - - List customRuleKeys = underTest.create(dbSession, Arrays.asList(firstRule, secondRule)); - - List rules = dbTester.getDbClient().ruleDao().selectByKeys(dbSession, customRuleKeys); - - assertThat(rules).hasSize(2); - assertThat(rules).asList() - .extracting("ruleKey") - .containsOnly("CUSTOM_RULE_1", "CUSTOM_RULE_2"); - } - - @Test - public void fail_to_create_custom_rules_when_wrong_rule_template() { - // insert rule - RuleDto rule = newRule(RuleKey.of("java", "S001")).setIsTemplate(false); - dbTester.rules().insert(rule); - dbSession.commit(); - - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", rule.getKey()) - .setName("My custom") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - - assertThatThrownBy(() -> underTest.create(dbSession, Collections.singletonList(newRule))) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("This rule is not a template rule: java:S001"); - } - - @Test - public void fail_to_create_custom_rule_with_invalid_parameter() { - // insert template rule - RuleDto templateRule = createTemplateRuleWithIntArrayParam(); - - assertThatThrownBy(() -> { - // Create custom rule - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setMarkdownDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("myIntegers", "1,polop,2")); - underTest.create(dbSession, newRule); - }) - .isInstanceOf(BadRequestException.class) - .hasMessage("Value 'polop' must be an integer."); - } - - @Test - public void fail_to_create_custom_rule_with_invalid_parameters() { - // insert template rule - RuleDto templateRule = createTemplateRuleWithTwoIntParams(); - - // Create custom rule - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setMarkdownDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("first", "polop", "second", "palap")); - try { - underTest.create(dbSession, newRule); - Fail.failBecauseExceptionWasNotThrown(BadRequestException.class); - } catch (BadRequestException badRequest) { - assertThat(badRequest.errors().toString()).contains("palap").contains("polop"); + private final System2 system2 = new TestSystem2().setNow(Instant.now().toEpochMilli()); + + @Rule + public DbTester dbTester = DbTester.create(system2); + + @Rule + public EsTester es = EsTester.create(); + + private final RuleIndex ruleIndex = new RuleIndex(es.client(), system2); + private final RuleIndexer ruleIndexer = new RuleIndexer(es.client(), dbTester.getDbClient()); + private final DbSession dbSession = dbTester.getSession(); + private final UuidFactory uuidFactory = new SequenceUuidFactory(); + + private final RuleCreator underTest = new RuleCreator(system2, new RuleIndexer(es.client(), dbTester.getDbClient()), dbTester.getDbClient(), newFullTypeValidations(), uuidFactory); + + @Test + public void create_custom_rule() { + // insert template rule + RuleDto templateRule = createTemplateRule(); + // Create custom rule + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("Some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "a.*")); + RuleKey customRuleKey = underTest.create(dbSession, newRule); + + RuleDto rule = dbTester.getDbClient().ruleDao().selectOrFailByKey(dbSession, customRuleKey); + assertThat(rule).isNotNull(); + assertThat(rule.getKey()).isEqualTo(RuleKey.of("java", "CUSTOM_RULE")); + assertThat(rule.getPluginKey()).isEqualTo("sonarjava"); + assertThat(rule.getTemplateUuid()).isEqualTo(templateRule.getUuid()); + assertThat(rule.getName()).isEqualTo("My custom"); + assertThat(rule.getDefaultRuleDescriptionSection().getContent()).isEqualTo("Some description"); + assertThat(rule.getSeverityString()).isEqualTo("MAJOR"); + assertThat(rule.getStatus()).isEqualTo(RuleStatus.READY); + assertThat(rule.getLanguage()).isEqualTo("java"); + assertThat(rule.getConfigKey()).isEqualTo("S001"); + assertThat(rule.getDefRemediationFunction()).isEqualTo("LINEAR_OFFSET"); + assertThat(rule.getDefRemediationGapMultiplier()).isEqualTo("1h"); + assertThat(rule.getDefRemediationBaseEffort()).isEqualTo("5min"); + assertThat(rule.getGapDescription()).isEqualTo("desc"); + assertThat(rule.getTags()).containsOnly("usertag1", "usertag2"); + assertThat(rule.getSystemTags()).containsOnly("tag1", "tag4"); + assertThat(rule.getSecurityStandards()).containsOnly("owaspTop10:a1", "cwe:123"); + assertThat(rule.isExternal()).isFalse(); + assertThat(rule.isAdHoc()).isFalse(); + + List params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); + assertThat(params).hasSize(1); + + RuleParamDto param = params.get(0); + // From template rule + assertThat(param.getName()).isEqualTo("regex"); + assertThat(param.getDescription()).isEqualTo("Reg ex"); + assertThat(param.getType()).isEqualTo("STRING"); + // From user + assertThat(param.getDefaultValue()).isEqualTo("a.*"); + + assertThat(ruleIndex.search(new RuleQuery(), new SearchOptions()).getUuids()).containsOnly(rule.getUuid(), templateRule.getUuid()); } - } - - @Test - public void reactivate_custom_rule_if_already_exists_in_removed_status() { - String key = "CUSTOM_RULE"; - - // insert template rule - RuleDto templateRule = createTemplateRule(); - - // insert a removed rule - RuleDto rule = RuleTesting.newCustomRule(templateRule) - .setRuleKey(key) - .setStatus(RuleStatus.REMOVED) - .setName("Old name") - .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(uuidFactory.create(), "Old description")) - .setDescriptionFormat(Format.MARKDOWN) - .setSeverity(Severity.INFO); - dbTester.rules().insert(rule); - dbTester.rules().insertRuleParam(rule, param -> param.setDefaultValue("a.*")); - dbSession.commit(); - - // Create custom rule with same key, but with different values - NewCustomRule newRule = NewCustomRule.createForCustomRule(key, templateRule.getKey()) - .setName("New name") - .setMarkdownDescription("New description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "c.*")); - RuleKey customRuleKey = underTest.create(dbSession, newRule); - - RuleDto result = dbTester.getDbClient().ruleDao().selectOrFailByKey(dbSession, customRuleKey); - assertThat(result.getKey()).isEqualTo(RuleKey.of("java", key)); - assertThat(result.getStatus()).isEqualTo(RuleStatus.READY); - - // These values should be the same than before - assertThat(result.getName()).isEqualTo("Old name"); - assertThat(result.getDefaultRuleDescriptionSection().getContent()).isEqualTo("Old description"); - assertThat(result.getSeverityString()).isEqualTo(Severity.INFO); - - List params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); - assertThat(params).hasSize(1); - assertThat(params.get(0).getDefaultValue()).isEqualTo("a.*"); - } - - @Test - public void generate_reactivation_exception_when_rule_exists_in_removed_status_and_prevent_reactivation_parameter_is_true() { - String key = "CUSTOM_RULE"; - // insert template rule - RuleDto templateRule = createTemplateRule(); - // insert a removed rule - RuleDto rule = RuleTesting.newCustomRule(templateRule) - .setRuleKey(key) - .setStatus(RuleStatus.REMOVED) - .setName("Old name") - .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(uuidFactory.create(), "Old description")) - .setSeverity(Severity.INFO); - dbTester.rules().insert(rule); - dbTester.rules().insertRuleParam(rule, param -> param.setDefaultValue("a.*")); - dbSession.commit(); - - // Create custom rule with same key, but with different values - NewCustomRule newRule = NewCustomRule.createForCustomRule(key, templateRule.getKey()) - .setName("New name") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "c.*")) - .setPreventReactivation(true); - - try { - underTest.create(dbSession, newRule); - fail(); - } catch (Exception e) { - assertThat(e).isInstanceOf(ReactivationException.class); - ReactivationException reactivationException = (ReactivationException) e; - assertThat(reactivationException.ruleKey()).isEqualTo(rule.getKey()); + + @Test + public void create_custom_rule_with_empty_parameter_value() { + // insert template rule + RuleDto templateRule = createTemplateRule(); + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "")); + + RuleKey customRuleKey = underTest.create(dbSession, newRule); + + List params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); + assertThat(params).hasSize(1); + RuleParamDto param = params.get(0); + assertThat(param.getName()).isEqualTo("regex"); + assertThat(param.getDescription()).isEqualTo("Reg ex"); + assertThat(param.getType()).isEqualTo("STRING"); + assertThat(param.getDefaultValue()).isNull(); + } + + @Test + public void create_custom_rule_with_no_parameter_value() { + // insert template rule + RuleDto templateRule = createTemplateRuleWithIntArrayParam(); + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY); + + RuleKey customRuleKey = underTest.create(dbSession, newRule); + + List params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); + assertThat(params).hasSize(1); + RuleParamDto param = params.get(0); + assertThat(param.getName()).isEqualTo("myIntegers"); + assertThat(param.getDescription()).isEqualTo("My Integers"); + assertThat(param.getType()).isEqualTo("INTEGER,multiple=true,values=1;2;3"); + assertThat(param.getDefaultValue()).isNull(); + } + + @Test + public void create_custom_rule_with_multiple_parameter_values() { + // insert template rule + RuleDto templateRule = createTemplateRuleWithIntArrayParam(); + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("myIntegers", "1,3")); + + RuleKey customRuleKey = underTest.create(dbSession, newRule); + + List params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); + assertThat(params).hasSize(1); + RuleParamDto param = params.get(0); + assertThat(param.getName()).isEqualTo("myIntegers"); + assertThat(param.getDescription()).isEqualTo("My Integers"); + assertThat(param.getType()).isEqualTo("INTEGER,multiple=true,values=1;2;3"); + assertThat(param.getDefaultValue()).isEqualTo("1,3"); + } + + @Test + public void batch_create_custom_rules() { + // insert template rule + RuleDto templateRule = createTemplateRuleWithIntArrayParam(); + + NewCustomRule firstRule = NewCustomRule.createForCustomRule("CUSTOM_RULE_1", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY); + + NewCustomRule secondRule = NewCustomRule.createForCustomRule("CUSTOM_RULE_2", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY); + + List customRuleKeys = underTest.create(dbSession, Arrays.asList(firstRule, secondRule)); + + List rules = dbTester.getDbClient().ruleDao().selectByKeys(dbSession, customRuleKeys); + + assertThat(rules).hasSize(2); + assertThat(rules).asList() + .extracting("ruleKey") + .containsOnly("CUSTOM_RULE_1", "CUSTOM_RULE_2"); + } + + @Test + public void fail_to_create_custom_rules_when_wrong_rule_template() { + // insert rule + RuleDto rule = newRule(RuleKey.of("java", "S001")).setIsTemplate(false); + dbTester.rules().insert(rule); + dbSession.commit(); + + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", rule.getKey()) + .setName("My custom") + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "a.*")); + + assertThatThrownBy(() -> underTest.create(dbSession, singletonList(newRule))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("This rule is not a template rule: java:S001"); + } + + @Test + public void fail_to_create_custom_rules_when_removed_rule_template() { + // insert rule + RuleDto rule = createTemplateRule(); newRule(RuleKey.of("java", "S001")).setIsTemplate(false); + rule.setStatus(RuleStatus.REMOVED); + dbTester.rules().update(rule); + dbSession.commit(); + + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", rule.getKey()) + .setName("My custom") + .setMarkdownDescription("Some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY); + + List newRules = singletonList(newRule); + assertThatThrownBy(() -> underTest.create(dbSession, newRules)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("The template key doesn't exist: java:S001"); + } + + @Test + public void fail_to_create_custom_rule_with_invalid_parameter() { + // insert template rule + RuleDto templateRule = createTemplateRuleWithIntArrayParam(); + + assertThatThrownBy(() -> { + // Create custom rule + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("Some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("myIntegers", "1,polop,2")); + underTest.create(dbSession, newRule); + }) + .isInstanceOf(BadRequestException.class) + .hasMessage("Value 'polop' must be an integer."); + } + + @Test + public void fail_to_create_custom_rule_with_invalid_parameters() { + // insert template rule + RuleDto templateRule = createTemplateRuleWithTwoIntParams(); + + // Create custom rule + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("Some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("first", "polop", "second", "palap")); + try { + underTest.create(dbSession, newRule); + Fail.failBecauseExceptionWasNotThrown(BadRequestException.class); + } catch (BadRequestException badRequest) { + assertThat(badRequest.errors().toString()).contains("palap").contains("polop"); + } + } + + @Test + public void fail_to_create_custom_rule_with_empty_description() { + // insert template rule + RuleDto templateRule = createTemplateRuleWithTwoIntParams(); + + // Create custom rule + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("Some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setMarkdownDescription(""); + assertThatExceptionOfType(BadRequestException.class) + .isThrownBy(() -> underTest.create(dbSession, newRule)) + .withMessage("The description is missing"); + } + + @Test + public void reactivate_custom_rule_if_already_exists_in_removed_status() { + String key = "CUSTOM_RULE"; + + // insert template rule + RuleDto templateRule = createTemplateRule(); + + // insert a removed rule + RuleDto rule = RuleTesting.newCustomRule(templateRule) + .setRuleKey(key) + .setStatus(RuleStatus.REMOVED) + .setName("Old name") + .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(uuidFactory.create(), "Old description")) + .setDescriptionFormat(Format.MARKDOWN) + .setSeverity(Severity.INFO); + dbTester.rules().insert(rule); + dbTester.rules().insertRuleParam(rule, param -> param.setDefaultValue("a.*")); + dbSession.commit(); + + // Create custom rule with same key, but with different values + NewCustomRule newRule = NewCustomRule.createForCustomRule(key, templateRule.getKey()) + .setName("New name") + .setMarkdownDescription("New description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "c.*")); + RuleKey customRuleKey = underTest.create(dbSession, newRule); + + RuleDto result = dbTester.getDbClient().ruleDao().selectOrFailByKey(dbSession, customRuleKey); + assertThat(result.getKey()).isEqualTo(RuleKey.of("java", key)); + assertThat(result.getStatus()).isEqualTo(RuleStatus.READY); + + // These values should be the same than before + assertThat(result.getName()).isEqualTo("Old name"); + assertThat(result.getDefaultRuleDescriptionSection().getContent()).isEqualTo("Old description"); + assertThat(result.getSeverityString()).isEqualTo(Severity.INFO); + + List params = dbTester.getDbClient().ruleDao().selectRuleParamsByRuleKey(dbSession, customRuleKey); + assertThat(params).hasSize(1); + assertThat(params.get(0).getDefaultValue()).isEqualTo("a.*"); + } + + @Test + public void generate_reactivation_exception_when_rule_exists_in_removed_status_and_prevent_reactivation_parameter_is_true() { + String key = "CUSTOM_RULE"; + // insert template rule + RuleDto templateRule = createTemplateRule(); + // insert a removed rule + RuleDto rule = RuleTesting.newCustomRule(templateRule) + .setRuleKey(key) + .setStatus(RuleStatus.REMOVED) + .setName("Old name") + .addOrReplaceRuleDescriptionSectionDto(createDefaultRuleDescriptionSection(uuidFactory.create(), "Old description")) + .setSeverity(Severity.INFO); + dbTester.rules().insert(rule); + dbTester.rules().insertRuleParam(rule, param -> param.setDefaultValue("a.*")); + dbSession.commit(); + + // Create custom rule with same key, but with different values + NewCustomRule newRule = NewCustomRule.createForCustomRule(key, templateRule.getKey()) + .setName("New name") + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "c.*")) + .setPreventReactivation(true); + + try { + underTest.create(dbSession, newRule); + fail(); + } catch (Exception e) { + assertThat(e).isInstanceOf(ReactivationException.class); + ReactivationException reactivationException = (ReactivationException) e; + assertThat(reactivationException.ruleKey()).isEqualTo(rule.getKey()); + } + } + + @Test + public void fail_to_create_custom_rule_when_invalid_key() { + // insert template rule + RuleDto templateRule = createTemplateRule(); + + NewCustomRule newRule = NewCustomRule.createForCustomRule("*INVALID*", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "a.*")); + + assertThatThrownBy(() -> underTest.create(dbSession, newRule)) + .isInstanceOf(BadRequestException.class) + .hasMessage("The rule key \"*INVALID*\" is invalid, it should only contain: a-z, 0-9, \"_\""); + } + + @Test + public void fail_to_create_custom_rule_when_rule_key_already_exists() { + // insert template rule + RuleDto templateRule = createTemplateRule(); + // Create a custom rule + AtomicReference newRule = new AtomicReference<>(NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "a.*"))); + underTest.create(dbSession, newRule.get()); + + // Create another custom rule having same key + newRule.set(NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My another custom") + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "a.*"))); + + assertThatThrownBy(() -> underTest.create(dbSession, newRule.get())) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("A rule with the key 'CUSTOM_RULE' already exists"); + } + + @Test + public void fail_to_create_custom_rule_when_missing_name() { + // insert template rule + RuleDto templateRule = createTemplateRule(); + + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "a.*")); + + assertThatThrownBy(() -> underTest.create(dbSession, newRule)) + .isInstanceOf(BadRequestException.class) + .hasMessage("The name is missing"); + } + + @Test + public void fail_to_create_custom_rule_when_missing_description() { + // insert template rule + RuleDto templateRule = createTemplateRule(); + + assertThatThrownBy(() -> { + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My custom") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "a.*")); + underTest.create(dbSession, newRule); + }) + .isInstanceOf(BadRequestException.class) + .hasMessage("The description is missing"); + } + + @Test + public void fail_to_create_custom_rule_when_missing_severity() { + // insert template rule + RuleDto templateRule = createTemplateRule(); + + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("some description") + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "a.*")); + + assertThatThrownBy(() -> underTest.create(dbSession, newRule)) + .isInstanceOf(BadRequestException.class) + .hasMessage("The severity is missing"); + } + + @Test + public void fail_to_create_custom_rule_when_invalid_severity() { + // insert template rule + RuleDto templateRule = createTemplateRule(); + + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("some description") + .setSeverity("INVALID") + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "a.*")); + + assertThatThrownBy(() -> underTest.create(dbSession, newRule)) + .isInstanceOf(BadRequestException.class) + .hasMessage("Severity \"INVALID\" is invalid"); + } + + @Test + public void fail_to_create_custom_rule_when_missing_status() { + // insert template rule + RuleDto templateRule = createTemplateRule(); + + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) + .setName("My custom") + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setParameters(ImmutableMap.of("regex", "a.*")); + + assertThatThrownBy(() -> underTest.create(dbSession, newRule)) + .isInstanceOf(BadRequestException.class) + .hasMessage("The status is missing"); + } + + @Test + public void fail_to_create_custom_rule_when_wrong_rule_template() { + // insert rule + RuleDto rule = newRule(RuleKey.of("java", "S001")).setIsTemplate(false); + dbTester.rules().insert(rule); + dbSession.commit(); + + // Create custom rule with unknown template rule + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", rule.getKey()) + .setName("My custom") + .setMarkdownDescription("some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY) + .setParameters(ImmutableMap.of("regex", "a.*")); + + assertThatThrownBy(() -> underTest.create(dbSession, newRule)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("This rule is not a template rule: java:S001"); + } + + @Test + public void fail_to_create_custom_rule_when_null_template() { + assertThatThrownBy(() -> { + // Create custom rule + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", null) + .setName("My custom") + .setMarkdownDescription("Some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY); + underTest.create(dbSession, newRule); + }) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Template key should be set"); + } + + @Test + public void fail_to_create_custom_rule_when_unknown_template() { + assertThatThrownBy(() -> { + // Create custom rule + NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", RuleKey.of("java", "S001")) + .setName("My custom") + .setMarkdownDescription("Some description") + .setSeverity(Severity.MAJOR) + .setStatus(RuleStatus.READY); + underTest.create(dbSession, newRule); + }) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("The template key doesn't exist: java:S001"); + } + + private RuleDto createTemplateRule() { + RuleDto templateRule = RuleTesting.newDto(RuleKey.of("java", "S001")) + .setIsTemplate(true) + .setLanguage("java") + .setPluginKey("sonarjava") + .setConfigKey("S001") + .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name()) + .setDefRemediationGapMultiplier("1h") + .setDefRemediationBaseEffort("5min") + .setGapDescription("desc") + .setTags(Sets.newHashSet("usertag1", "usertag2")) + .setSystemTags(Sets.newHashSet("tag1", "tag4")) + .setSecurityStandards(Sets.newHashSet("owaspTop10:a1", "cwe:123")) + .setCreatedAt(new Date().getTime()) + .setUpdatedAt(new Date().getTime()); + dbTester.rules().insert(templateRule); + dbTester.rules().insertOrUpdateMetadata(templateRule.getMetadata().setRuleUuid(templateRule.getUuid())); + dbTester.rules().insertRuleParam(templateRule, param -> param.setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(".*")); + ruleIndexer.commitAndIndex(dbTester.getSession(), templateRule.getUuid()); + return templateRule; + } + + private RuleDto createTemplateRuleWithIntArrayParam() { + RuleDto templateRule = newRule(RuleKey.of("java", "S002")) + .setIsTemplate(true) + .setLanguage("java") + .setConfigKey("S002") + .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name()) + .setDefRemediationGapMultiplier("1h") + .setDefRemediationBaseEffort("5min") + .setGapDescription("desc") + .setCreatedAt(new Date().getTime()) + .setUpdatedAt(new Date().getTime()); + dbTester.rules().insert(templateRule); + dbTester.rules().insertRuleParam(templateRule, + param -> param.setName("myIntegers").setType("INTEGER,multiple=true,values=1;2;3").setDescription("My Integers").setDefaultValue("1")); + ruleIndexer.commitAndIndex(dbTester.getSession(), templateRule.getUuid()); + return templateRule; + } + + private RuleDto createTemplateRuleWithTwoIntParams() { + RuleDto templateRule = newRule(RuleKey.of("java", "S003")) + .setIsTemplate(true) + .setLanguage("java") + .setConfigKey("S003") + .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name()) + .setDefRemediationGapMultiplier("1h") + .setDefRemediationBaseEffort("5min") + .setGapDescription("desc") + .setCreatedAt(new Date().getTime()) + .setUpdatedAt(new Date().getTime()); + dbTester.rules().insert(templateRule); + dbTester.rules().insertRuleParam(templateRule, param -> param.setName("first").setType("INTEGER").setDescription("First integer").setDefaultValue("0")); + dbTester.rules().insertRuleParam(templateRule, param -> param.setName("second").setType("INTEGER").setDescription("Second integer").setDefaultValue("0")); + return templateRule; } - } - - @Test - public void fail_to_create_custom_rule_when_invalid_key() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - - NewCustomRule newRule = NewCustomRule.createForCustomRule("*INVALID*", templateRule.getKey()) - .setName("My custom") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - - assertThatThrownBy(() -> underTest.create(dbSession, newRule)) - .isInstanceOf(BadRequestException.class) - .hasMessage("The rule key \"*INVALID*\" is invalid, it should only contain: a-z, 0-9, \"_\""); - } - - @Test - public void fail_to_create_custom_rule_when_rule_key_already_exists() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - // Create a custom rule - AtomicReference newRule = new AtomicReference<>(NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*"))); - underTest.create(dbSession, newRule.get()); - - // Create another custom rule having same key - newRule.set(NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My another custom") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*"))); - - assertThatThrownBy(() -> underTest.create(dbSession, newRule.get())) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("A rule with the key 'CUSTOM_RULE' already exists"); - } - - @Test - public void fail_to_create_custom_rule_when_missing_name() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - - assertThatThrownBy(() -> underTest.create(dbSession, newRule)) - .isInstanceOf(BadRequestException.class) - .hasMessage("The name is missing"); - } - - @Test - public void fail_to_create_custom_rule_when_missing_description() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - - assertThatThrownBy(() -> { - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - underTest.create(dbSession, newRule); - }) - .isInstanceOf(BadRequestException.class) - .hasMessage("The description is missing"); - } - - @Test - public void fail_to_create_custom_rule_when_missing_severity() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - - assertThatThrownBy(() -> underTest.create(dbSession, newRule)) - .isInstanceOf(BadRequestException.class) - .hasMessage("The severity is missing"); - } - - @Test - public void fail_to_create_custom_rule_when_invalid_severity() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity("INVALID") - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - - assertThatThrownBy(() -> underTest.create(dbSession, newRule)) - .isInstanceOf(BadRequestException.class) - .hasMessage("Severity \"INVALID\" is invalid"); - } - - @Test - public void fail_to_create_custom_rule_when_missing_status() { - // insert template rule - RuleDto templateRule = createTemplateRule(); - - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", templateRule.getKey()) - .setName("My custom") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity(Severity.MAJOR) - .setParameters(ImmutableMap.of("regex", "a.*")); - - assertThatThrownBy(() -> underTest.create(dbSession, newRule)) - .isInstanceOf(BadRequestException.class) - .hasMessage("The status is missing"); - } - - @Test - public void fail_to_create_custom_rule_when_wrong_rule_template() { - // insert rule - RuleDto rule = newRule(RuleKey.of("java", "S001")).setIsTemplate(false); - dbTester.rules().insert(rule); - dbSession.commit(); - - // Create custom rule with unknown template rule - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", rule.getKey()) - .setName("My custom") - .setRuleDescriptionSections(Set.of(new NewRuleDescriptionSection("default", "some description"))) - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY) - .setParameters(ImmutableMap.of("regex", "a.*")); - - assertThatThrownBy(() -> underTest.create(dbSession, newRule)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("This rule is not a template rule: java:S001"); - } - - @Test - public void fail_to_create_custom_rule_when_unknown_template() { - assertThatThrownBy(() -> { - // Create custom rule - NewCustomRule newRule = NewCustomRule.createForCustomRule("CUSTOM_RULE", RuleKey.of("java", "S001")) - .setName("My custom") - .setMarkdownDescription("Some description") - .setSeverity(Severity.MAJOR) - .setStatus(RuleStatus.READY); - underTest.create(dbSession, newRule); - }) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("The template key doesn't exist: java:S001"); - } - - private RuleDto createTemplateRule() { - RuleDto templateRule = RuleTesting.newDto(RuleKey.of("java", "S001")) - .setIsTemplate(true) - .setLanguage("java") - .setPluginKey("sonarjava") - .setConfigKey("S001") - .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name()) - .setDefRemediationGapMultiplier("1h") - .setDefRemediationBaseEffort("5min") - .setGapDescription("desc") - .setTags(Sets.newHashSet("usertag1", "usertag2")) - .setSystemTags(Sets.newHashSet("tag1", "tag4")) - .setSecurityStandards(Sets.newHashSet("owaspTop10:a1", "cwe:123")) - .setCreatedAt(new Date().getTime()) - .setUpdatedAt(new Date().getTime()); - dbTester.rules().insert(templateRule); - dbTester.rules().insertOrUpdateMetadata(templateRule.getMetadata().setRuleUuid(templateRule.getUuid())); - dbTester.rules().insertRuleParam(templateRule, param -> param.setName("regex").setType("STRING").setDescription("Reg ex").setDefaultValue(".*")); - ruleIndexer.commitAndIndex(dbTester.getSession(), templateRule.getUuid()); - return templateRule; - } - - private RuleDto createTemplateRuleWithIntArrayParam() { - RuleDto templateRule = newRule(RuleKey.of("java", "S002")) - .setIsTemplate(true) - .setLanguage("java") - .setConfigKey("S002") - .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name()) - .setDefRemediationGapMultiplier("1h") - .setDefRemediationBaseEffort("5min") - .setGapDescription("desc") - .setCreatedAt(new Date().getTime()) - .setUpdatedAt(new Date().getTime()); - dbTester.rules().insert(templateRule); - dbTester.rules().insertRuleParam(templateRule, - param -> param.setName("myIntegers").setType("INTEGER,multiple=true,values=1;2;3").setDescription("My Integers").setDefaultValue("1")); - ruleIndexer.commitAndIndex(dbTester.getSession(), templateRule.getUuid()); - return templateRule; - } - - private RuleDto createTemplateRuleWithTwoIntParams() { - RuleDto templateRule = newRule(RuleKey.of("java", "S003")) - .setIsTemplate(true) - .setLanguage("java") - .setConfigKey("S003") - .setDefRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.name()) - .setDefRemediationGapMultiplier("1h") - .setDefRemediationBaseEffort("5min") - .setGapDescription("desc") - .setCreatedAt(new Date().getTime()) - .setUpdatedAt(new Date().getTime()); - dbTester.rules().insert(templateRule); - dbTester.rules().insertRuleParam(templateRule, param -> param.setName("first").setType("INTEGER").setDescription("First integer").setDefaultValue("0")); - dbTester.rules().insertRuleParam(templateRule, param -> param.setName("second").setType("INTEGER").setDescription("Second integer").setDefaultValue("0")); - return templateRule; - } } -- 2.39.5