From: Julien Lancelot Date: Thu, 13 Sep 2018 13:10:42 +0000 (+0200) Subject: SONAR-11210 Display organization specific ad hoc rule info X-Git-Tag: 7.5~438 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=04963a43f10710b0992c1ef708183f05723c7025;p=sonarqube.git SONAR-11210 Display organization specific ad hoc rule info --- diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java index cc66f2d9c1d..25ee11d763e 100644 --- a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/XooPlugin.java @@ -49,7 +49,6 @@ import org.sonar.xoo.rule.OneBlockerIssuePerFileSensor; import org.sonar.xoo.rule.OneBugIssuePerLineSensor; import org.sonar.xoo.rule.OneDayDebtPerFileSensor; import org.sonar.xoo.rule.OneExternalIssuePerLineSensor; -import org.sonar.xoo.rule.OnePredefinedRuleExternalIssuePerLineSensor; import org.sonar.xoo.rule.OneIssueOnDirPerFileSensor; import org.sonar.xoo.rule.OneIssuePerDirectorySensor; import org.sonar.xoo.rule.OneIssuePerFileSensor; @@ -57,6 +56,8 @@ import org.sonar.xoo.rule.OneIssuePerLineSensor; import org.sonar.xoo.rule.OneIssuePerModuleSensor; import org.sonar.xoo.rule.OneIssuePerTestFileSensor; import org.sonar.xoo.rule.OneIssuePerUnknownFileSensor; +import org.sonar.xoo.rule.OnePredefinedAndAdHocRuleExternalIssuePerLineSensor; +import org.sonar.xoo.rule.OnePredefinedRuleExternalIssuePerLineSensor; import org.sonar.xoo.rule.OneVulnerabilityIssuePerModuleSensor; import org.sonar.xoo.rule.RandomAccessSensor; import org.sonar.xoo.rule.SaveDataTwiceSensor; @@ -169,6 +170,7 @@ public class XooPlugin implements Plugin { context.addExtensions( OneExternalIssuePerLineSensor.class, OnePredefinedRuleExternalIssuePerLineSensor.class, + OnePredefinedAndAdHocRuleExternalIssuePerLineSensor.class, SignificantCodeSensor.class); } if (context.getSonarQubeVersion().isGreaterThanOrEqual(Version.create(7, 3))) { diff --git a/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OnePredefinedAndAdHocRuleExternalIssuePerLineSensor.java b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OnePredefinedAndAdHocRuleExternalIssuePerLineSensor.java new file mode 100644 index 00000000000..b522c299f00 --- /dev/null +++ b/plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/rule/OnePredefinedAndAdHocRuleExternalIssuePerLineSensor.java @@ -0,0 +1,82 @@ +/* + * 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.xoo.rule; + +import org.sonar.api.batch.fs.FilePredicates; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.InputFile.Type; +import org.sonar.api.batch.rule.Severity; +import org.sonar.api.batch.sensor.Sensor; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.SensorDescriptor; +import org.sonar.api.batch.sensor.issue.NewExternalIssue; +import org.sonar.api.rules.RuleType; +import org.sonar.xoo.Xoo; + +public class OnePredefinedAndAdHocRuleExternalIssuePerLineSensor implements Sensor { + + public static final String ACTIVATE = "sonar.onePredefinedAndAdHocRuleExternalIssuePerLine.activate"; + private static final String NAME = "One External Issue Per Line With A Predefined And An AdHoc Rule"; + + @Override + public void describe(SensorDescriptor descriptor) { + descriptor + .name(NAME) + .onlyOnLanguages(Xoo.KEY) + .onlyWhenConfiguration(c -> c.getBoolean(ACTIVATE).orElse(false)); + } + + @Override + public void execute(SensorContext context) { + FileSystem fs = context.fileSystem(); + FilePredicates p = fs.predicates(); + for (InputFile file : fs.inputFiles(p.and(p.hasLanguages(Xoo.KEY), p.hasType(Type.MAIN)))) { + createIssues(file, context); + } + } + + private static void createIssues(InputFile file, SensorContext context) { + for (int line = 1; line <= file.lines(); line++) { + NewExternalIssue newIssue = context.newExternalIssue(); + newIssue + .engineId(OnePredefinedRuleExternalIssuePerLineSensor.ENGINE_ID) + .ruleId(OnePredefinedRuleExternalIssuePerLineSensor.RULE_ID) + .at(newIssue.newLocation() + .on(file) + .at(file.selectLine(line)) + .message("This issue is generated on each line and the rule is predefined")) + .severity(Severity.valueOf(OnePredefinedRuleExternalIssuePerLineSensor.SEVERITY)) + .remediationEffortMinutes(OnePredefinedRuleExternalIssuePerLineSensor.EFFORT) + .type(OnePredefinedRuleExternalIssuePerLineSensor.TYPE) + .save(); + + // Even if the issue is on a predefined rule, the sensor is declaring an adHoc rule => this info should be ignored + context.newAdHocRule() + .engineId(OnePredefinedRuleExternalIssuePerLineSensor.ENGINE_ID) + .ruleId(OnePredefinedRuleExternalIssuePerLineSensor.RULE_ID) + .name("An ad hoc rule") + .description("blah blah") + .severity(Severity.BLOCKER) + .type(RuleType.BUG) + .save(); + } + } +} diff --git a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java index fadb287de47..f515a6859f7 100644 --- a/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java +++ b/plugins/sonar-xoo-plugin/src/test/java/org/sonar/xoo/XooPluginTest.java @@ -60,7 +60,7 @@ public class XooPluginTest { Plugin.Context context = new PluginContextImpl.Builder().setSonarRuntime(runtime).build(); new XooPlugin().define(context); assertThat(getExtensions(context)) - .hasSize(52) + .hasSize(53) .contains(OneExternalIssuePerLineSensor.class); } @@ -70,7 +70,7 @@ public class XooPluginTest { Plugin.Context context = new PluginContextImpl.Builder().setSonarRuntime(runtime).build(); new XooPlugin().define(context); assertThat(getExtensions(context)) - .hasSize(53) + .hasSize(54) .contains(OneExternalIssuePerLineSensor.class); } 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 4d96f20ae23..3ada8d5a11f 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 @@ -40,12 +40,25 @@ public class RuleDefinitionDto { private Integer id; private String repositoryKey; private String ruleKey; + + /** + * Description can be null on external rule, otherwise it should never be null + */ private String description; + + /** + * Description format can be null on external rule, otherwise it should never be null + */ private RuleDto.Format descriptionFormat; private RuleStatus status; private String name; private String configKey; + + /** + * Severity can be null on external rule, otherwise it should never be null + */ private Integer severity; + private boolean isTemplate; /** @@ -128,20 +141,22 @@ public class RuleDefinitionDto { return this; } + @CheckForNull public String getDescription() { return description; } - public RuleDefinitionDto setDescription(String description) { + public RuleDefinitionDto setDescription(@Nullable String description) { this.description = description; return this; } + @CheckForNull public RuleDto.Format getDescriptionFormat() { return descriptionFormat; } - public RuleDefinitionDto setDescriptionFormat(RuleDto.Format descriptionFormat) { + public RuleDefinitionDto setDescriptionFormat(@Nullable RuleDto.Format descriptionFormat) { this.descriptionFormat = descriptionFormat; return this; } diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDbTester.java b/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDbTester.java index 3ab4a154a03..f494dc4d1bb 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDbTester.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/rule/RuleDbTester.java @@ -94,7 +94,8 @@ public class RuleDbTester { } public RuleParamDto insertRuleParam(RuleDefinitionDto rule) { - return insertRuleParam(rule, p -> {}); + return insertRuleParam(rule, p -> { + }); } @SafeVarargs @@ -116,15 +117,6 @@ public class RuleDbTester { return ruleDto; } - public RuleDto updateRule(RuleDto ruleDto) { - update(ruleDto.getDefinition()); - RuleMetadataDto metadata = ruleDto.getMetadata(); - if (metadata.getOrganizationUuid() != null) { - db.getDbClient().ruleDao().insertOrUpdate(db.getSession(), metadata.setRuleId(ruleDto.getId())); - db.commit(); - } - return ruleDto; - } /** * Create and persist a rule with random values. */ @@ -154,7 +146,6 @@ public class RuleDbTester { return deprecatedRuleKeyDto; } - public RuleParamDto insertRuleParam(RuleDto rule) { RuleParamDto param = new RuleParamDto(); param.setRuleId(rule.getId()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleMapper.java b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleMapper.java index ad20629b98f..88bef6aa0e3 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleMapper.java +++ b/server/sonar-server/src/main/java/org/sonar/server/rule/ws/RuleMapper.java @@ -20,7 +20,6 @@ package org.sonar.server.rule.ws; import com.google.common.base.Function; -import com.google.common.collect.FluentIterable; import java.util.List; import java.util.Locale; import java.util.Map; @@ -32,6 +31,7 @@ import org.sonar.api.resources.Languages; import org.sonar.api.server.debt.DebtRemediationFunction; import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction; import org.sonar.db.rule.RuleDefinitionDto; +import org.sonar.db.rule.RuleDto; import org.sonar.db.rule.RuleDto.Scope; import org.sonar.db.rule.RuleMetadataDto; import org.sonar.db.rule.RuleParamDto; @@ -45,6 +45,7 @@ import org.sonarqube.ws.Rules; import static java.lang.String.format; import static org.sonar.api.utils.DateUtils.formatDateTime; +import static org.sonar.core.util.stream.MoreCollectors.toList; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_CREATED_AT; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_DEBT_OVERLOADED; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_DEBT_REM_FUNCTION; @@ -73,7 +74,7 @@ import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_TAGS; import static org.sonar.server.rule.ws.RulesWsParameters.FIELD_TEMPLATE_KEY; /** - * Conversion of {@link org.sonar.db.rule.RuleDto} to {@link org.sonarqube.ws.Rules.Rule} + * Conversion of {@link RuleDto} to {@link Rules.Rule} */ public class RuleMapper { @@ -91,23 +92,23 @@ public class RuleMapper { return ruleResponse.build(); } - public Rules.Rule toWsRule(RuleDefinitionDto ruleDefinitionDto, SearchResult result, Set fieldsToReturn, RuleMetadataDto metadata, Map usersByUuid) { + public Rules.Rule toWsRule(RuleDefinitionDto ruleDefinition, SearchResult result, Set fieldsToReturn, RuleMetadataDto metadata, Map usersByUuid) { Rules.Rule.Builder ruleResponse = Rules.Rule.newBuilder(); - applyRuleDefinition(ruleResponse, ruleDefinitionDto, result, fieldsToReturn); - applyRuleMetadata(ruleResponse, metadata, usersByUuid, fieldsToReturn); - setDebtRemediationFunctionFields(ruleResponse, ruleDefinitionDto, metadata, fieldsToReturn); + applyRuleDefinition(ruleResponse, ruleDefinition, result, fieldsToReturn); + applyRuleMetadata(ruleResponse, ruleDefinition, metadata, usersByUuid, fieldsToReturn); + setDebtRemediationFunctionFields(ruleResponse, ruleDefinition, metadata, fieldsToReturn); return ruleResponse.build(); } - public Rules.Rule.Builder applyRuleDefinition(Rules.Rule.Builder ruleResponse, RuleDefinitionDto ruleDefinitionDto, SearchResult result, Set fieldsToReturn) { + private Rules.Rule.Builder applyRuleDefinition(Rules.Rule.Builder ruleResponse, RuleDefinitionDto ruleDefinitionDto, SearchResult result, Set fieldsToReturn) { // Mandatory fields ruleResponse.setKey(ruleDefinitionDto.getKey().toString()); ruleResponse.setType(Common.RuleType.forNumber(ruleDefinitionDto.getType())); // Optional fields - setRepository(ruleResponse, ruleDefinitionDto, fieldsToReturn); setName(ruleResponse, ruleDefinitionDto, fieldsToReturn); + setRepository(ruleResponse, ruleDefinitionDto, fieldsToReturn); setStatus(ruleResponse, ruleDefinitionDto, fieldsToReturn); setSysTags(ruleResponse, ruleDefinitionDto, fieldsToReturn); setParams(ruleResponse, ruleDefinitionDto, result, fieldsToReturn); @@ -126,10 +127,45 @@ public class RuleMapper { return ruleResponse; } - private void applyRuleMetadata(Rules.Rule.Builder ruleResponse, RuleMetadataDto metadata, Map usersByUuid, Set fieldsToReturn) { + private void applyRuleMetadata(Rules.Rule.Builder ruleResponse, RuleDefinitionDto ruleDefinition, RuleMetadataDto metadata, Map usersByUuid, + Set fieldsToReturn) { setTags(ruleResponse, metadata, fieldsToReturn); setNotesFields(ruleResponse, metadata, usersByUuid, fieldsToReturn); setIsRemediationFunctionOverloaded(ruleResponse, metadata, fieldsToReturn); + if (ruleDefinition.isAdHoc()) { + setAdHocName(ruleResponse, metadata, fieldsToReturn); + setAdHocDescription(ruleResponse, metadata, fieldsToReturn); + setAdHocSeverity(ruleResponse, metadata, fieldsToReturn); + setAdHocType(ruleResponse, metadata); + } + } + + private static void setAdHocName(Rules.Rule.Builder ruleResponse, RuleMetadataDto metadata, Set fieldsToReturn) { + String adHocName = metadata.getAdHocName(); + if (adHocName != null && shouldReturnField(fieldsToReturn, FIELD_NAME)) { + ruleResponse.setName(adHocName); + } + } + + private void setAdHocDescription(Rules.Rule.Builder ruleResponse, RuleMetadataDto metadata, Set fieldsToReturn) { + String adHocDescription = metadata.getAdHocDescription(); + if (adHocDescription != null && shouldReturnField(fieldsToReturn, FIELD_HTML_DESCRIPTION)) { + ruleResponse.setHtmlDesc(macroInterpreter.interpret(adHocDescription)); + } + } + + private static void setAdHocSeverity(Rules.Rule.Builder ruleResponse, RuleMetadataDto metadata, Set fieldsToReturn) { + String severity = metadata.getAdHocSeverity(); + if (shouldReturnField(fieldsToReturn, FIELD_SEVERITY) && severity != null) { + ruleResponse.setSeverity(severity); + } + } + + private static void setAdHocType(Rules.Rule.Builder ruleResponse, RuleMetadataDto metadata) { + Integer ruleType = metadata.getAdHocType(); + if (ruleType != null) { + ruleResponse.setType(Common.RuleType.forNumber(ruleType)); + } } private static void setRepository(Rules.Rule.Builder ruleResponse, RuleDefinitionDto ruleDto, Set fieldsToReturn) { @@ -158,10 +194,11 @@ public class RuleMapper { } private static void setEffortToFixDescription(Rules.Rule.Builder ruleResponse, RuleDefinitionDto ruleDto, Set fieldsToReturn) { + String gapDescription = ruleDto.getGapDescription(); if ((shouldReturnField(fieldsToReturn, FIELD_EFFORT_TO_FIX_DESCRIPTION) || shouldReturnField(fieldsToReturn, FIELD_GAP_DESCRIPTION)) - && ruleDto.getGapDescription() != null) { - ruleResponse.setEffortToFixDescription(ruleDto.getGapDescription()); - ruleResponse.setGapDescription(ruleDto.getGapDescription()); + && gapDescription != null) { + ruleResponse.setEffortToFixDescription(gapDescription); + ruleResponse.setGapDescription(gapDescription); } } @@ -250,9 +287,7 @@ public class RuleMapper { private static void setParams(Rules.Rule.Builder ruleResponse, RuleDefinitionDto ruleDto, SearchResult searchResult, Set fieldsToReturn) { if (shouldReturnField(fieldsToReturn, FIELD_PARAMS)) { List ruleParameters = searchResult.getRuleParamsByRuleId().get(ruleDto.getId()); - ruleResponse.getParamsBuilder().addAllParams(FluentIterable.from(ruleParameters) - .transform(RuleParamDtoToWsRuleParam.INSTANCE) - .toList()); + ruleResponse.getParamsBuilder().addAllParams(ruleParameters.stream().map(RuleParamDtoToWsRuleParam.INSTANCE::apply).collect(toList())); } } @@ -263,10 +298,11 @@ public class RuleMapper { } private void setDescriptionFields(Rules.Rule.Builder ruleResponse, RuleDefinitionDto ruleDto, Set fieldsToReturn) { + String description = ruleDto.getDescription(); if (shouldReturnField(fieldsToReturn, FIELD_HTML_DESCRIPTION)) { - String description = ruleDto.getDescription(); - if (description != null) { - switch (ruleDto.getDescriptionFormat()) { + RuleDto.Format descriptionFormat = ruleDto.getDescriptionFormat(); + if (description != null && descriptionFormat != null) { + switch (descriptionFormat) { case MARKDOWN: ruleResponse.setHtmlDesc(macroInterpreter.interpret(Markdown.convertToHtml(description))); break; @@ -274,13 +310,13 @@ public class RuleMapper { ruleResponse.setHtmlDesc(macroInterpreter.interpret(description)); break; default: - throw new IllegalStateException(format("Rule description format '%s' is unknown for key '%s'", ruleDto.getDescriptionFormat(), ruleDto.getKey().toString())); + throw new IllegalStateException(format("Rule description format '%s' is unknown for key '%s'", descriptionFormat, ruleDto.getKey().toString())); } } } - if (shouldReturnField(fieldsToReturn, FIELD_MARKDOWN_DESCRIPTION) && ruleDto.getDescription() != null) { - ruleResponse.setMdDesc(ruleDto.getDescription()); + if (shouldReturnField(fieldsToReturn, FIELD_MARKDOWN_DESCRIPTION) && description != null) { + ruleResponse.setMdDesc(description); } } @@ -319,8 +355,8 @@ public class RuleMapper { } private void setLanguageName(Rules.Rule.Builder ruleResponse, RuleDefinitionDto ruleDto, Set fieldsToReturn) { - if (shouldReturnField(fieldsToReturn, FIELD_LANGUAGE_NAME) && ruleDto.getLanguage() != null) { - String languageKey = ruleDto.getLanguage(); + String languageKey = ruleDto.getLanguage(); + if (shouldReturnField(fieldsToReturn, FIELD_LANGUAGE_NAME) && languageKey != null) { Language language = languages.get(languageKey); ruleResponse.setLangName(language == null ? languageKey : language.getName()); } @@ -331,7 +367,7 @@ public class RuleMapper { ruleResponse.setIsTemplate(ruleDto.isTemplate()); } } - + private static void setIsExternal(Rules.Rule.Builder ruleResponse, RuleDefinitionDto ruleDto, Set fieldsToReturn) { if (shouldReturnField(fieldsToReturn, FIELD_IS_EXTERNAL)) { ruleResponse.setIsExternal(ruleDto.isExternal()); diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java index 6b4b1bf5ceb..23a5f97e48e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/SearchActionTest.java @@ -628,6 +628,17 @@ public class SearchActionTest { assertThat(searchedRule.getTemplateKey()).isEqualTo(templateRule.getRepositoryKey() + ":" + templateRule.getRuleKey()); } + @Test + public void do_not_return_external_rule() { + db.rules().insert(r -> r.setIsExternal(true)); + indexRules(); + + SearchResponse result = ws.newRequest().executeProtobuf(SearchResponse.class); + + assertThat(result.getTotal()).isZero(); + assertThat(result.getRulesCount()).isZero(); + } + @Test public void search_all_active_rules() { OrganizationDto organization = db.organizations().insert(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java index a3f3d7b8797..bdbc2ce3e9b 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/rule/ws/ShowActionTest.java @@ -25,6 +25,8 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.resources.Languages; import org.sonar.api.rule.RuleKey; +import org.sonar.api.rule.Severity; +import org.sonar.api.rules.RuleType; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbTester; import org.sonar.db.organization.OrganizationDto; @@ -41,6 +43,7 @@ import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.text.MacroInterpreter; import org.sonar.server.ws.WsActionTester; +import org.sonarqube.ws.Common; import org.sonarqube.ws.Rules; import org.sonarqube.ws.Rules.Rule; import org.sonarqube.ws.Rules.ShowResponse; @@ -60,6 +63,8 @@ import static org.sonar.server.language.LanguageTesting.newLanguage; import static org.sonar.server.rule.ws.ShowAction.PARAM_ACTIVES; import static org.sonar.server.rule.ws.ShowAction.PARAM_KEY; import static org.sonar.server.rule.ws.ShowAction.PARAM_ORGANIZATION; +import static org.sonarqube.ws.Common.RuleType.UNKNOWN; +import static org.sonarqube.ws.Common.RuleType.VULNERABILITY; public class ShowActionTest { @@ -230,6 +235,7 @@ public class ShowActionTest { Rule resultRule = result.getRule(); assertThat(resultRule.getDefaultRemFnType()).isEqualTo("LINEAR_OFFSET"); + assertThat(resultRule.getDefaultRemFnType()).isEqualTo("LINEAR_OFFSET"); assertThat(resultRule.getDefaultRemFnGapMultiplier()).isEqualTo("5d"); assertThat(resultRule.getDefaultRemFnBaseEffort()).isEqualTo("10h"); assertThat(resultRule.getRemFnType()).isEqualTo("CONSTANT_ISSUE"); @@ -313,6 +319,99 @@ public class ShowActionTest { verify(macroInterpreter).interpret("<div>line1
line2</div>"); } + @Test + public void show_external_rule() { + RuleDefinitionDto externalRule = db.rules().insert(r -> r + .setIsExternal(true) + .setName("ext rule name")); + + ShowResponse result = ws.newRequest() + .setParam(PARAM_KEY, externalRule.getKey().toString()) + .executeProtobuf(ShowResponse.class); + + Rule resultRule = result.getRule(); + assertThat(resultRule.getName()).isEqualTo("ext rule name"); + } + + @Test + public void show_adhoc_rule() { + OrganizationDto organization = db.organizations().insert(); + RuleDefinitionDto externalRule = db.rules().insert(r -> r + .setIsExternal(true) + .setIsAdHoc(true)); + RuleMetadataDto metadata = db.rules().insertOrUpdateMetadata(externalRule, organization, m -> m + .setAdHocName("adhoc name") + .setAdHocDescription("
desc
") + .setAdHocSeverity(Severity.BLOCKER) + .setAdHocType(RuleType.VULNERABILITY) + .setNoteData(null) + .setNoteUserUuid(null)); + doReturn("<div>desc2</div>").when(macroInterpreter).interpret(metadata.getAdHocDescription()); + + ShowResponse result = ws.newRequest() + .setParam(PARAM_KEY, externalRule.getKey().toString()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .executeProtobuf(ShowResponse.class); + + Rule resultRule = result.getRule(); + assertThat(resultRule) + .extracting(Rule::getName, Rule::getHtmlDesc, Rule::getSeverity, Rule::getType) + .containsExactlyInAnyOrder("adhoc name", "<div>desc2</div>", Severity.BLOCKER, VULNERABILITY); + } + + @Test + public void ignore_predefined_info_on_adhoc_rule() { + OrganizationDto organization = db.organizations().insert(); + RuleDefinitionDto externalRule = db.rules().insert(r -> r + .setIsExternal(true) + .setIsAdHoc(true) + .setName("predefined name") + .setDescription("
predefined desc
") + .setSeverity(Severity.BLOCKER) + .setType(RuleType.VULNERABILITY)); + RuleMetadataDto metadata = db.rules().insertOrUpdateMetadata(externalRule, organization, m -> m + .setAdHocName("adhoc name") + .setAdHocDescription("
adhoc desc
") + .setAdHocSeverity(Severity.MAJOR) + .setAdHocType(RuleType.CODE_SMELL) + .setNoteData(null) + .setNoteUserUuid(null)); + doReturn("<div>adhoc desc</div>").when(macroInterpreter).interpret(metadata.getAdHocDescription()); + + ShowResponse result = ws.newRequest() + .setParam(PARAM_KEY, externalRule.getKey().toString()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .executeProtobuf(ShowResponse.class); + + Rule resultRule = result.getRule(); + assertThat(resultRule) + .extracting(Rule::getName, Rule::getHtmlDesc, Rule::getSeverity, Rule::getType) + .containsExactlyInAnyOrder("adhoc name", "<div>adhoc desc</div>", Severity.MAJOR, Common.RuleType.CODE_SMELL); + } + + @Test + public void adhoc_info_are_empty_when_no_metadata() { + OrganizationDto organization = db.organizations().insert(); + RuleDefinitionDto externalRule = db.rules().insert(r -> r + .setIsExternal(true) + .setIsAdHoc(true) + .setName(null) + .setDescription(null) + .setDescriptionFormat(null) + .setSeverity((String) null) + .setType(0)); + + ShowResponse result = ws.newRequest() + .setParam(PARAM_KEY, externalRule.getKey().toString()) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .executeProtobuf(ShowResponse.class); + + Rule resultRule = result.getRule(); + assertThat(resultRule) + .extracting(Rule::hasName, Rule::hasHtmlDesc, Rule::hasSeverity, Rule::getType) + .containsExactlyInAnyOrder(false, false, false, UNKNOWN); + } + @Test public void show_rule_with_activation() { OrganizationDto organization = db.organizations().insert();