]> source.dussan.org Git - sonarqube.git/blob
0490a7dd965bb698290cee03b186e3e5f6065120
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2023 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.ce.task.projectexport.rule;
21
22 import com.google.common.collect.ImmutableList;
23 import com.sonarsource.governance.projectdump.protobuf.ProjectDump;
24 import java.util.Date;
25 import java.util.List;
26 import org.apache.commons.lang.RandomStringUtils;
27 import org.junit.Before;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.slf4j.event.Level;
31 import org.sonar.api.rule.RuleKey;
32 import org.sonar.api.rule.RuleStatus;
33 import org.sonar.api.rule.Severity;
34 import org.sonar.api.rules.RuleType;
35 import org.sonar.api.testfixtures.log.LogTester;
36 import org.sonar.api.utils.System2;
37 import org.sonar.ce.task.projectexport.steps.DumpElement;
38 import org.sonar.ce.task.projectexport.steps.FakeDumpWriter;
39 import org.sonar.ce.task.projectexport.steps.ProjectHolder;
40 import org.sonar.ce.task.step.TestComputationStepContext;
41 import org.sonar.db.DbTester;
42 import org.sonar.db.component.BranchDto;
43 import org.sonar.db.component.BranchType;
44 import org.sonar.db.component.ComponentDto;
45 import org.sonar.db.component.ProjectData;
46 import org.sonar.db.issue.IssueDto;
47 import org.sonar.db.project.ProjectDto;
48 import org.sonar.db.rule.RuleDto;
49
50 import static org.assertj.core.api.Assertions.assertThat;
51 import static org.assertj.core.api.Assertions.assertThatThrownBy;
52 import static org.mockito.Mockito.mock;
53 import static org.mockito.Mockito.when;
54
55 public class ExportAdHocRulesStepIT {
56   private static final String PROJECT_UUID = "some-uuid";
57   private static final List<BranchDto> BRANCHES = ImmutableList.of(
58     new BranchDto().setBranchType(BranchType.PULL_REQUEST).setProjectUuid(PROJECT_UUID).setKey("pr-1").setUuid("pr-1-uuid").setMergeBranchUuid("master").setIsMain(false),
59     new BranchDto().setBranchType(BranchType.BRANCH).setProjectUuid(PROJECT_UUID).setKey("branch-2").setUuid("branch-2-uuid").setMergeBranchUuid("master")
60       .setExcludeFromPurge(true).setIsMain(false),
61     new BranchDto().setBranchType(BranchType.BRANCH).setProjectUuid(PROJECT_UUID).setKey("branch-3").setUuid("branch-3-uuid").setMergeBranchUuid("master")
62       .setExcludeFromPurge(false).setIsMain(false));
63
64   @Rule
65   public LogTester logTester = new LogTester();
66   @Rule
67   public DbTester dbTester = DbTester.create(System2.INSTANCE);
68
69   private int issueUuidGenerator = 1;
70   private ComponentDto mainBranch;
71   private final FakeDumpWriter dumpWriter = new FakeDumpWriter();
72   private final ProjectHolder projectHolder = mock(ProjectHolder.class);
73   private final ExportAdHocRulesStep underTest = new ExportAdHocRulesStep(dbTester.getDbClient(), projectHolder, dumpWriter);
74
75   @Before
76   public void setup() {
77     logTester.setLevel(Level.DEBUG);
78     ProjectDto project = createProject();
79     when(projectHolder.projectDto()).thenReturn(project);
80   }
81
82   @Test
83   public void export_zero_ad_hoc_rules() {
84     underTest.execute(new TestComputationStepContext());
85
86     List<ProjectDump.AdHocRule> exportedRules = dumpWriter.getWrittenMessagesOf(DumpElement.AD_HOC_RULES);
87     assertThat(exportedRules).isEmpty();
88     assertThat(logTester.logs(Level.DEBUG)).contains("0 ad-hoc rules exported");
89   }
90
91   @Test
92   public void execute_only_exports_ad_hoc_rules_that_reference_project_issue() {
93     String differentProject = "diff-proj-uuid";
94     RuleDto rule1 = insertAddHocRule( "rule-1");
95     RuleDto rule2 = insertAddHocRule( "rule-2");
96     insertAddHocRule( "rule-3");
97     insertIssue(rule1, differentProject, differentProject);
98     insertIssue(rule2, mainBranch.uuid(), mainBranch.uuid());
99
100     underTest.execute(new TestComputationStepContext());
101
102     List<ProjectDump.AdHocRule> exportedRules = dumpWriter.getWrittenMessagesOf(DumpElement.AD_HOC_RULES);
103     assertThat(exportedRules).hasSize(1);
104     assertProtobufAdHocRuleIsCorrectlyBuilt(exportedRules.iterator().next(), rule2);
105     assertThat(logTester.logs(Level.DEBUG)).contains("1 ad-hoc rules exported");
106   }
107
108   @Test
109   public void execute_only_exports_rules_that_are_ad_hoc() {
110     RuleDto rule1 = insertStandardRule("rule-1");
111     RuleDto rule2 = insertExternalRule("rule-2");
112     RuleDto rule3 = insertAddHocRule("rule-3");
113     insertIssue(rule1, mainBranch.uuid(), mainBranch.uuid());
114     insertIssue(rule2, mainBranch.uuid(), mainBranch.uuid());
115     insertIssue(rule3, mainBranch.uuid(), mainBranch.uuid());
116
117     underTest.execute(new TestComputationStepContext());
118
119     List<ProjectDump.AdHocRule> exportedRules = dumpWriter.getWrittenMessagesOf(DumpElement.AD_HOC_RULES);
120     assertThat(exportedRules).hasSize(1);
121     assertProtobufAdHocRuleIsCorrectlyBuilt(exportedRules.iterator().next(), rule3);
122     assertThat(logTester.logs(Level.DEBUG)).contains("1 ad-hoc rules exported");
123   }
124
125   @Test
126   public void execute_exports_ad_hoc_rules_that_are_referenced_by_issues_on_branches_excluded_from_purge() {
127     when(projectHolder.branches()).thenReturn(BRANCHES);
128     RuleDto rule1 = insertAddHocRule("rule-1");
129     RuleDto rule2 = insertAddHocRule("rule-2");
130     RuleDto rule3 = insertAddHocRule("rule-3");
131     insertIssue(rule1, "branch-1-uuid", "branch-1-uuid");
132     insertIssue(rule2, "branch-2-uuid", "branch-2-uuid");
133     insertIssue(rule3, "branch-3-uuid", "branch-3-uuid");
134
135     underTest.execute(new TestComputationStepContext());
136
137     List<ProjectDump.AdHocRule> exportedRules = dumpWriter.getWrittenMessagesOf(DumpElement.AD_HOC_RULES);
138     assertThat(exportedRules).hasSize(1);
139     assertProtobufAdHocRuleIsCorrectlyBuilt(exportedRules.iterator().next(), rule2);
140     assertThat(logTester.logs(Level.DEBUG)).contains("1 ad-hoc rules exported");
141   }
142
143   @Test
144   public void execute_throws_ISE_with_number_of_successful_exports_before_failure() {
145     RuleDto rule1 = insertAddHocRule("rule-1");
146     RuleDto rule2 = insertAddHocRule("rule-2");
147     RuleDto rule3 = insertAddHocRule("rule-3");
148     insertIssue(rule1, mainBranch.uuid(), mainBranch.uuid());
149     insertIssue(rule2, mainBranch.uuid(), mainBranch.uuid());
150     insertIssue(rule3, mainBranch.uuid(), mainBranch.uuid());
151     dumpWriter.failIfMoreThan(2, DumpElement.AD_HOC_RULES);
152
153     assertThatThrownBy(() -> underTest.execute(new TestComputationStepContext()))
154       .isInstanceOf(IllegalStateException.class)
155       .hasMessage("Ad-hoc rules export failed after processing 2 rules successfully");
156   }
157
158   @Test
159   public void getDescription() {
160     assertThat(underTest.getDescription()).isEqualTo("Export ad-hoc rules");
161   }
162
163   private ProjectDto createProject() {
164     Date createdAt = new Date();
165     ProjectData projectData = dbTester.components().insertPublicProject(PROJECT_UUID);
166     mainBranch = projectData.getMainBranchComponent();
167     BRANCHES.forEach(branch -> dbTester.components().insertProjectBranch(projectData.getProjectDto(), branch).setCreatedAt(createdAt));
168     dbTester.commit();
169     return projectData.getProjectDto();
170   }
171
172   private void insertIssue(RuleDto ruleDto, String branchUuid, String componentUuid) {
173     IssueDto dto = createBaseIssueDto(ruleDto, branchUuid, componentUuid);
174     insertIssue(dto);
175   }
176
177   private void insertIssue(IssueDto dto) {
178     dbTester.getDbClient().issueDao().insert(dbTester.getSession(), dto);
179     dbTester.commit();
180   }
181
182   private IssueDto createBaseIssueDto(RuleDto ruleDto, String branchUuid, String componentUuid) {
183     return new IssueDto()
184       .setKee("issue_uuid_" + issueUuidGenerator++)
185       .setComponentUuid(componentUuid)
186       .setProjectUuid(branchUuid)
187       .setRuleUuid(ruleDto.getUuid())
188       .setStatus("OPEN");
189   }
190
191   private RuleDto insertExternalRule(String ruleName) {
192     RuleDto ruleDto = new RuleDto()
193       .setIsExternal(true)
194       .setIsAdHoc(false);
195     return insertRule(ruleName, ruleDto);
196   }
197
198   private RuleDto insertAddHocRule(String ruleName) {
199     RuleDto ruleDto = new RuleDto()
200       .setIsExternal(false)
201       .setIsAdHoc(true)
202       .setAdHocName("ad_hoc_rule" + RandomStringUtils.randomAlphabetic(10))
203       .setAdHocType(RuleType.VULNERABILITY)
204       .setAdHocSeverity(Severity.CRITICAL)
205       .setAdHocDescription("ad hoc description: " + RandomStringUtils.randomAlphanumeric(100));
206     return insertRule(ruleName, ruleDto);
207   }
208
209   private RuleDto insertStandardRule(String ruleName) {
210     RuleDto ruleDto = new RuleDto()
211       .setIsExternal(false)
212       .setIsAdHoc(false);
213     return insertRule(ruleName, ruleDto);
214   }
215
216   private RuleDto insertRule(String ruleName, RuleDto partiallyInitRuleDto) {
217     RuleKey ruleKey = RuleKey.of("plugin1", ruleName);
218     partiallyInitRuleDto
219       .setName("ruleName" + RandomStringUtils.randomAlphanumeric(10))
220       .setRuleKey(ruleKey)
221       .setPluginKey("pluginKey" + RandomStringUtils.randomAlphanumeric(10))
222       .setStatus(RuleStatus.READY)
223       .setScope(RuleDto.Scope.ALL);
224
225     dbTester.rules().insert(partiallyInitRuleDto);
226     dbTester.commit();
227     return dbTester.getDbClient().ruleDao().selectByKey(dbTester.getSession(), ruleKey)
228       .orElseThrow(() -> new RuntimeException("insertAdHocRule failed"));
229   }
230
231   private static void assertProtobufAdHocRuleIsCorrectlyBuilt(ProjectDump.AdHocRule protobufAdHocRule, RuleDto source) {
232     assertThat(protobufAdHocRule.getName()).isEqualTo(source.getName());
233     assertThat(protobufAdHocRule.getRef()).isEqualTo(source.getUuid());
234     assertThat(protobufAdHocRule.getPluginKey()).isEqualTo(source.getPluginKey());
235     assertThat(protobufAdHocRule.getPluginRuleKey()).isEqualTo(source.getRuleKey());
236     assertThat(protobufAdHocRule.getPluginName()).isEqualTo(source.getRepositoryKey());
237     assertThat(protobufAdHocRule.getName()).isEqualTo(source.getName());
238     assertThat(protobufAdHocRule.getStatus()).isEqualTo(source.getStatus().name());
239     assertThat(protobufAdHocRule.getType()).isEqualTo(source.getType());
240     assertThat(protobufAdHocRule.getScope()).isEqualTo(source.getScope().name());
241     assertProtobufAdHocRuleIsCorrectlyBuilt(protobufAdHocRule.getMetadata(), source);
242   }
243
244   private static void assertProtobufAdHocRuleIsCorrectlyBuilt(ProjectDump.AdHocRule.RuleMetadata metadata, RuleDto expected) {
245     assertThat(metadata.getAdHocName()).isEqualTo(expected.getAdHocName());
246     assertThat(metadata.getAdHocDescription()).isEqualTo(expected.getAdHocDescription());
247     assertThat(metadata.getAdHocSeverity()).isEqualTo(expected.getAdHocSeverity());
248     assertThat(metadata.getAdHocType()).isEqualTo(expected.getAdHocType());
249   }
250
251 }