]> source.dussan.org Git - sonarqube.git/blob
843e0b091d4edce42ad131bcfdd6a4cd5615afc6
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2024 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.server.v2.api.rule.controller;
21
22 import com.google.gson.Gson;
23 import com.google.gson.GsonBuilder;
24 import java.util.List;
25 import javax.annotation.Nullable;
26 import org.junit.Before;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.mockito.junit.MockitoJUnitRunner;
31 import org.sonar.api.resources.Languages;
32 import org.sonar.api.rule.RuleKey;
33 import org.sonar.db.rule.RuleDescriptionSectionDto;
34 import org.sonar.db.rule.RuleDto;
35 import org.sonar.db.rule.RuleTesting;
36 import org.sonar.server.common.rule.ReactivationException;
37 import org.sonar.server.common.rule.service.RuleInformation;
38 import org.sonar.server.common.rule.service.RuleService;
39 import org.sonar.server.common.text.MacroInterpreter;
40 import org.sonar.server.language.LanguageTesting;
41 import org.sonar.server.rule.RuleDescriptionFormatter;
42 import org.sonar.server.tester.UserSessionRule;
43 import org.sonar.server.v2.api.ControllerTester;
44 import org.sonar.server.v2.api.rule.converter.RuleRestResponseGenerator;
45 import org.sonar.server.v2.api.rule.enums.CleanCodeAttributeRestEnum;
46 import org.sonar.server.v2.api.rule.enums.ImpactSeverityRestEnum;
47 import org.sonar.server.v2.api.rule.enums.RuleStatusRestEnum;
48 import org.sonar.server.v2.api.rule.enums.SoftwareQualityRestEnum;
49 import org.sonar.server.v2.api.rule.request.RuleCreateRestRequest;
50 import org.sonar.server.v2.api.rule.resource.Impact;
51 import org.sonar.server.v2.api.rule.resource.Parameter;
52 import org.sonar.server.v2.api.rule.response.RuleRestResponse;
53 import org.springframework.http.MediaType;
54 import org.springframework.test.web.servlet.MockMvc;
55 import org.springframework.test.web.servlet.MvcResult;
56
57 import static org.assertj.core.api.Assertions.assertThat;
58 import static org.mockito.ArgumentMatchers.any;
59 import static org.mockito.ArgumentMatchers.anyString;
60 import static org.mockito.Mockito.mock;
61 import static org.mockito.Mockito.when;
62 import static org.sonar.db.permission.GlobalPermission.ADMINISTER_QUALITY_PROFILES;
63 import static org.sonar.server.v2.WebApiEndpoints.RULES_ENDPOINT;
64 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
65 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
66 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
67
68 @RunWith(MockitoJUnitRunner.class)
69 public class DefaultRuleControllerTest {
70
71   @Rule
72   public UserSessionRule userSession = UserSessionRule.standalone();
73
74   private final RuleService ruleService = mock(RuleService.class);
75   private final Languages languages = mock(Languages.class);
76   private final MacroInterpreter macroInterpreter = mock(MacroInterpreter.class);
77   private final RuleDescriptionFormatter ruleDescriptionFormatter = mock(RuleDescriptionFormatter.class);
78   private final RuleRestResponseGenerator ruleRestResponseGenerator = new RuleRestResponseGenerator(languages, macroInterpreter,
79     ruleDescriptionFormatter);
80
81   private final MockMvc mockMvc = ControllerTester.getMockMvc(new DefaultRuleController(userSession, ruleService,
82     ruleRestResponseGenerator));
83   private static final Gson gson = new GsonBuilder().create();
84
85   @Before
86   public void setUp() {
87     when(macroInterpreter.interpret(anyString())).thenAnswer(invocation -> "interpreted" + invocation.getArgument(0));
88     when(ruleDescriptionFormatter.toHtml(any(), any())).thenAnswer(invocation -> "html" + ((RuleDescriptionSectionDto) invocation.getArgument(1)).getContent());
89     when(languages.get(anyString())).thenAnswer(invocation -> LanguageTesting.newLanguage(invocation.getArgument(0, String.class),
90       "languageName"));
91   }
92
93   @Test
94   public void create_shouldReturnRule() throws Exception {
95     userSession.logIn().addPermission(ADMINISTER_QUALITY_PROFILES);
96
97     RuleInformation ruleInformation = generateRuleInformation();
98     when(ruleService.createCustomRule(any())).thenReturn(ruleInformation);
99
100     MvcResult mvcResult = mockMvc.perform(
101         post(RULES_ENDPOINT)
102           .contentType(MediaType.APPLICATION_JSON_VALUE)
103           .content(gson.toJson(newRequest())))
104       .andExpect(status().isOk())
105       .andReturn();
106
107     RuleRestResponse response = gson.fromJson(mvcResult.getResponse().getContentAsString(), RuleRestResponse.class);
108     assertThat(response).isEqualTo(ruleRestResponseGenerator.toRuleRestResponse(ruleInformation));
109   }
110
111   @Test
112   public void create_whenNotLoggedIn_shouldFailWithUnauthorized() throws Exception {
113     mockMvc.perform(
114         post(RULES_ENDPOINT)
115           .contentType(MediaType.APPLICATION_JSON_VALUE)
116           .content(gson.toJson(newRequest())))
117       .andExpectAll(status().isUnauthorized(), content().json("{message:'Authentication is required'}"));
118   }
119
120   @Test
121   public void create_whenNoPermission_shouldFailWithForbidden() throws Exception {
122     userSession.logIn();
123
124     mockMvc.perform(
125         post(RULES_ENDPOINT)
126           .contentType(MediaType.APPLICATION_JSON_VALUE)
127           .content(gson.toJson(newRequest())))
128       .andExpectAll(status().isForbidden(), content().json("{message:'Insufficient privileges'}"));
129   }
130
131   @Test
132   public void create_whenReactivationExceptionThrown_shouldFailWithConflict() throws Exception {
133     userSession.logIn().addPermission(ADMINISTER_QUALITY_PROFILES);
134
135     String errorMessage = "reactivation_exception";
136     when(ruleService.createCustomRule(any())).thenThrow(new ReactivationException(errorMessage, null));
137
138     mockMvc.perform(
139         post(RULES_ENDPOINT)
140           .contentType(MediaType.APPLICATION_JSON_VALUE)
141           .content(gson.toJson(newRequest())))
142       .andExpectAll(status().isConflict(), content().json(String.format("{message:'%s'}", errorMessage)));
143   }
144
145   @Test
146   public void create_whenMissingBodyField_shouldFailWithBadRequest() throws Exception {
147     userSession.logIn().addPermission(ADMINISTER_QUALITY_PROFILES);
148
149     RuleCreateRestRequest request = newRequest(null);
150
151     mockMvc.perform(
152         post(RULES_ENDPOINT)
153           .contentType(MediaType.APPLICATION_JSON_VALUE)
154           .content(gson.toJson(request)))
155       .andExpectAll(status().isBadRequest(), content().json("{message:'Value {} for field name was rejected. Error: must not be null.'}"));
156   }
157
158   @Test
159   public void create_whenInvalidParam_shouldFailWithBadRequest() throws Exception {
160     userSession.logIn().addPermission(ADMINISTER_QUALITY_PROFILES);
161
162     RuleCreateRestRequest request = newRequest("a".repeat(201));
163
164     mockMvc.perform(
165         post(RULES_ENDPOINT)
166           .contentType(MediaType.APPLICATION_JSON_VALUE)
167           .content(gson.toJson(request)))
168       .andExpectAll(status().isBadRequest(),
169         content().json(String.format("{message:'Value %s for field name was rejected. Error: size must be between 0 and 200.'}",
170           request.name())));
171   }
172
173   private static RuleCreateRestRequest newRequest() {
174     return newRequest("custom rule name");
175   }
176
177   private static RuleCreateRestRequest newRequest(@Nullable String name) {
178     return new RuleCreateRestRequest(
179       "java:custom_rule",
180       "java:template_rule",
181       name,
182       "some desc",
183       RuleStatusRestEnum.BETA,
184       List.of(new Parameter("key1", "desc", "value1", "text")),
185       CleanCodeAttributeRestEnum.MODULAR,
186       List.of(new Impact(SoftwareQualityRestEnum.MAINTAINABILITY, ImpactSeverityRestEnum.LOW)));
187   }
188
189   private RuleInformation generateRuleInformation() {
190     RuleDto ruleDto = RuleTesting.newCustomRule(RuleTesting.newTemplateRule(RuleKey.parse("java:template_rule")));
191     RuleTesting.newRuleParam(ruleDto);
192     return new RuleInformation(ruleDto, List.of(RuleTesting.newRuleParam(ruleDto), RuleTesting.newRuleParam(ruleDto)));
193   }
194 }