瀏覽代碼

SONAR-12723 remove hotspots from issues API

tags/8.2.0.32929
Jacek 4 年之前
父節點
當前提交
c890861887

+ 5
- 1
server/sonar-db-dao/src/main/java/org/sonar/db/issue/IssueTesting.java 查看文件

@@ -19,7 +19,9 @@
*/
package org.sonar.db.issue;

import java.util.Arrays;
import java.util.Date;
import java.util.Random;
import org.apache.commons.lang.math.RandomUtils;
import org.sonar.api.issue.Issue;
import org.sonar.api.resources.Qualifiers;
@@ -40,6 +42,8 @@ import static org.apache.commons.lang.math.RandomUtils.nextInt;
import static org.apache.commons.lang.math.RandomUtils.nextLong;

public class IssueTesting {
private static final RuleType[] RULE_TYPES_EXCEPT_HOTSPOTS = Arrays.stream(RuleType.values())
.filter(ruleType -> RuleType.SECURITY_HOTSPOT != ruleType).toArray(RuleType[]::new);

private IssueTesting() {
// only statics
@@ -52,7 +56,7 @@ public class IssueTesting {
return new IssueDto()
.setKee("uuid_" + randomAlphabetic(5))
.setRule(rule)
.setType(RuleType.values()[nextInt(RuleType.values().length)])
.setType(RULE_TYPES_EXCEPT_HOTSPOTS[new Random().nextInt(RULE_TYPES_EXCEPT_HOTSPOTS.length)])
.setProject(project)
.setComponent(file)
.setStatus(Issue.STATUS_OPEN)

+ 8
- 0
server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/IssueFinder.java 查看文件

@@ -19,6 +19,7 @@
*/
package org.sonar.server.issue;

import org.sonar.api.rules.RuleType;
import org.sonar.api.web.UserRole;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
@@ -28,6 +29,7 @@ import org.sonar.server.user.UserSession;

import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;

public class IssueFinder {

@@ -41,6 +43,12 @@ public class IssueFinder {

public IssueDto getByKey(DbSession session, String issueKey) {
IssueDto issue = dbClient.issueDao().selectByKey(session, issueKey).orElseThrow(() -> new NotFoundException(format("Issue with key '%s' does not exist", issueKey)));

RuleType ruleType = RuleType.valueOfNullable(issue.getType());
if (SECURITY_HOTSPOT.equals(ruleType)) {
throw new NotFoundException(format("Issue with key '%s' does not exist", issueKey));
}

userSession.checkComponentUuidPermission(UserRole.USER, requireNonNull(issue.getProjectUuid()));
return issue;
}

+ 34
- 50
server/sonar-webserver-webapi/src/main/java/org/sonar/server/issue/ws/SearchAction.java 查看文件

@@ -19,7 +19,6 @@
*/
package org.sonar.server.issue.ws;

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.util.ArrayList;
@@ -27,14 +26,11 @@ import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.SearchHit;
import org.sonar.api.Startable;
import org.sonar.api.config.Configuration;
import org.sonar.api.rule.Severity;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ws.Change;
@@ -47,7 +43,6 @@ import org.sonar.api.utils.System2;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.es.Facets;
import org.sonar.server.es.SearchOptions;
@@ -81,7 +76,6 @@ import static org.sonar.api.issue.Issue.STATUS_TO_REVIEW;
import static org.sonar.api.server.ws.WebService.Param.FACETS;
import static org.sonar.api.utils.Paging.forPageIndex;
import static org.sonar.core.util.stream.MoreCollectors.toSet;
import static org.sonar.process.ProcessProperties.Property.SONARCLOUD_ENABLED;
import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
import static org.sonar.server.issue.index.IssueIndex.FACET_ASSIGNED_TO_ME;
import static org.sonar.server.issue.index.IssueIndex.FACET_PROJECTS;
@@ -135,9 +129,10 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_STATUSES;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_TAGS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_TYPES;

public class SearchAction implements IssuesWsAction, Startable {
public class SearchAction implements IssuesWsAction {

private static final String LOGIN_MYSELF = "__me__";
private static final EnumSet<RuleType> ALL_RULE_TYPES_EXCEPT_SECURITY_HOTSPOTS = EnumSet.complementOf(EnumSet.of(RuleType.SECURITY_HOTSPOT));

static final List<String> SUPPORTED_FACETS = ImmutableList.of(
FACET_PROJECTS,
@@ -163,26 +158,22 @@ public class SearchAction implements IssuesWsAction, Startable {

private static final String INTERNAL_PARAMETER_DISCLAIMER = "This parameter is mostly used by the Issues page, please prefer usage of the componentKeys parameter. ";
private static final Set<String> FACETS_REQUIRING_PROJECT_OR_ORGANIZATION = newHashSet(PARAM_MODULE_UUIDS, PARAM_FILE_UUIDS, PARAM_DIRECTORIES);
private static final Joiner COMA_JOINER = Joiner.on(",");

private final UserSession userSession;
private final IssueIndex issueIndex;
private final IssueQueryFactory issueQueryFactory;
private final SearchResponseLoader searchResponseLoader;
private final SearchResponseFormat searchResponseFormat;
private final Configuration config;
private final System2 system2;
private final DbClient dbClient;
private boolean isOnSonarCloud;

public SearchAction(UserSession userSession, IssueIndex issueIndex, IssueQueryFactory issueQueryFactory, SearchResponseLoader searchResponseLoader,
SearchResponseFormat searchResponseFormat, Configuration config, System2 system2, DbClient dbClient) {
SearchResponseFormat searchResponseFormat, System2 system2, DbClient dbClient) {
this.userSession = userSession;
this.issueIndex = issueIndex;
this.issueQueryFactory = issueQueryFactory;
this.searchResponseLoader = searchResponseLoader;
this.searchResponseFormat = searchResponseFormat;
this.config = config;
this.system2 = system2;
this.dbClient = dbClient;
}
@@ -199,8 +190,10 @@ public class SearchAction implements IssuesWsAction, Startable {
PARAM_COMPONENT_KEYS, PARAM_COMPONENT_UUIDS)
.setSince("3.6")
.setChangelog(
new Change("8.1", "response field 'fromHotspot' has been deprecated and is no more populated"),
new Change("8.1", format("Status %s for Security Hotspots has been deprecated", STATUS_IN_REVIEW)),
new Change("8.2", "'REVIEWED', 'TO_REVIEW' status param values are no longer supported"),
new Change("8.2", "Security hotspots are no longer returned"),
new Change("8.2", "response field 'fromHotspot' has been deprecated and is no more populated"),
new Change("8.2", format("Status %s for Security Hotspots has been deprecated", STATUS_IN_REVIEW)),
new Change("7.8", format("added new Security Hotspots statuses : %s, %s and %s", STATUS_TO_REVIEW, STATUS_IN_REVIEW, STATUS_REVIEWED)),
new Change("7.8", "Security hotspots are returned by default"),
new Change("7.7", format("Value '%s' in parameter '%s' is deprecated, please use '%s' instead", DEPRECATED_PARAM_AUTHORS, FACETS, PARAM_AUTHOR)),
@@ -261,7 +254,7 @@ public class SearchAction implements IssuesWsAction, Startable {
action.createParam(PARAM_TYPES)
.setDescription("Comma-separated list of types.")
.setSince("5.5")
.setPossibleValues(RuleType.values())
.setPossibleValues(ALL_RULE_TYPES_EXCEPT_SECURITY_HOTSPOTS)
.setExampleValue(format("%s,%s", RuleType.CODE_SMELL, RuleType.BUG));
action.createParam(PARAM_OWASP_TOP_10)
.setDescription("Comma-separated list of OWASP Top 10 lowercase categories.")
@@ -391,14 +384,14 @@ public class SearchAction implements IssuesWsAction, Startable {
public final void handle(Request request, Response response) {
try (DbSession dbSession = dbClient.openSession(false)) {
SearchRequest searchRequest = toSearchWsRequest(dbSession, request);
SearchWsResponse searchWsResponse = doHandle(dbSession, searchRequest);
SearchWsResponse searchWsResponse = doHandle(searchRequest);
writeProtobuf(searchWsResponse, request, response);
}
}

private SearchWsResponse doHandle(DbSession dbSession, SearchRequest request) {
private SearchWsResponse doHandle(SearchRequest request) {
// prepare the Elasticsearch request
SearchOptions options = createSearchOptionsFromRequest(dbSession, request);
SearchOptions options = createSearchOptionsFromRequest(request);
EnumSet<SearchAdditionalField> additionalFields = SearchAdditionalField.getFromRequest(request);
IssueQuery query = issueQueryFactory.create(request);

@@ -407,7 +400,7 @@ public class SearchAction implements IssuesWsAction, Startable {
.collect(toSet());
checkArgument(facetsRequiringProjectOrOrganizationParameter.isEmpty() ||
(!query.projectUuids().isEmpty()) || query.organizationUuid() != null, "Facet(s) '%s' require to also filter by project or organization",
COMA_JOINER.join(facetsRequiringProjectOrOrganizationParameter));
String.join(",", facetsRequiringProjectOrOrganizationParameter));

// execute request
SearchResponse result = issueIndex.search(query, options);
@@ -436,7 +429,7 @@ public class SearchAction implements IssuesWsAction, Startable {
return searchResponseFormat.formatSearch(additionalFields, data, paging, facets);
}

private SearchOptions createSearchOptionsFromRequest(DbSession dbSession, SearchRequest request) {
private SearchOptions createSearchOptionsFromRequest(SearchRequest request) {
SearchOptions options = new SearchOptions();
options.setPage(request.getPage(), request.getPageSize());

@@ -446,29 +439,13 @@ public class SearchAction implements IssuesWsAction, Startable {
return options;
}

List<String> requestedFacets = new ArrayList<>(facets);
if (isOnSonarCloud) {
Optional<OrganizationDto> organizationDto = Optional.empty();
String organizationKey = request.getOrganization();
if (organizationKey != null) {
organizationDto = dbClient.organizationDao().selectByKey(dbSession, organizationKey);
}

if (!organizationDto.isPresent() || !userSession.hasMembership(organizationDto.get())) {
// In order to display the authors facet, the organization parameter must be set and the user
// must be member of this organization
requestedFacets.remove(PARAM_AUTHOR);
requestedFacets.remove(DEPRECATED_PARAM_AUTHORS);
}
}

options.addFacets(requestedFacets);
options.addFacets(facets);
return options;
}

private void completeFacets(Facets facets, SearchRequest request, IssueQuery query) {
addMandatoryValuesToFacet(facets, PARAM_SEVERITIES, Severity.ALL);
addMandatoryValuesToFacet(facets, PARAM_STATUSES, STATUSES);
addMandatoryValuesToFacet(facets, PARAM_STATUSES, STATUSES.stream().filter(s -> !STATUS_TO_REVIEW.equals(s)).filter(s -> !STATUS_REVIEWED.equals(s)).collect(toList()));
addMandatoryValuesToFacet(facets, PARAM_RESOLUTIONS, concat(singletonList(""), RESOLUTIONS));
addMandatoryValuesToFacet(facets, FACET_PROJECTS, query.projectUuids());
addMandatoryValuesToFacet(facets, PARAM_MODULE_UUIDS, query.moduleUuids());
@@ -486,13 +463,23 @@ public class SearchAction implements IssuesWsAction, Startable {
addMandatoryValuesToFacet(facets, PARAM_RULES, query.rules().stream().map(IssueDoc::formatRuleId).collect(toList()));
addMandatoryValuesToFacet(facets, PARAM_LANGUAGES, request.getLanguages());
addMandatoryValuesToFacet(facets, PARAM_TAGS, request.getTags());
addMandatoryValuesToFacet(facets, PARAM_TYPES, RuleType.names());

setTypesFacet(facets);

addMandatoryValuesToFacet(facets, PARAM_OWASP_TOP_10, request.getOwaspTop10());
addMandatoryValuesToFacet(facets, PARAM_SANS_TOP_25, request.getSansTop25());
addMandatoryValuesToFacet(facets, PARAM_CWE, request.getCwe());
addMandatoryValuesToFacet(facets, PARAM_SONARSOURCE_SECURITY, request.getSonarsourceSecurity());
}

private void setTypesFacet(Facets facets) {
Map<String, Long> typeFacet = facets.get(PARAM_TYPES);
if (typeFacet != null) {
typeFacet.remove(RuleType.SECURITY_HOTSPOT.name());
}
addMandatoryValuesToFacet(facets, PARAM_TYPES, ALL_RULE_TYPES_EXCEPT_SECURITY_HOTSPOTS.stream().map(Enum::name).collect(Collectors.toList()));
}

private static void addMandatoryValuesToFacet(Facets facets, String facetName, @Nullable Iterable<String> mandatoryValues) {
Map<String, Long> buckets = facets.get(facetName);
if (buckets != null && mandatoryValues != null) {
@@ -562,13 +549,20 @@ public class SearchAction implements IssuesWsAction, Startable {
.setSeverities(request.paramAsStrings(PARAM_SEVERITIES))
.setStatuses(request.paramAsStrings(PARAM_STATUSES))
.setTags(request.paramAsStrings(PARAM_TAGS))
.setTypes(request.paramAsStrings(PARAM_TYPES))
.setTypes(allRuleTypesExceptHotspotsIfEmpty(request.paramAsStrings(PARAM_TYPES)))
.setOwaspTop10(request.paramAsStrings(PARAM_OWASP_TOP_10))
.setSansTop25(request.paramAsStrings(PARAM_SANS_TOP_25))
.setCwe(request.paramAsStrings(PARAM_CWE))
.setSonarsourceSecurity(request.paramAsStrings(PARAM_SONARSOURCE_SECURITY));
}

private List<String> allRuleTypesExceptHotspotsIfEmpty(@Nullable List<String> types) {
if (types == null || types.isEmpty()) {
return ALL_RULE_TYPES_EXCEPT_SECURITY_HOTSPOTS.stream().map(Enum::name).collect(toList());
}
return types;
}

private List<String> getLogins(DbSession dbSession, @Nullable List<String> assigneeLogins) {
List<String> userLogins = new ArrayList<>();

@@ -592,14 +586,4 @@ public class SearchAction implements IssuesWsAction, Startable {
}
return assigneeUuid;
}

@Override
public void start() {
this.isOnSonarCloud = config.getBoolean(SONARCLOUD_ENABLED.getKey()).orElse(false);
}

@Override
public void stop() {
// Nothing to do
}
}

+ 27
- 6
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/EditCommentActionTest.java 查看文件

@@ -19,12 +19,15 @@
*/
package org.sonar.server.issue.ws;

import java.util.Arrays;
import java.util.Random;
import javax.annotation.Nullable;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.ArgumentCaptor;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
@@ -57,6 +60,8 @@ import static org.sonar.api.web.UserRole.USER;
public class EditCommentActionTest {

private static final long NOW = 10_000_000_000L;
private static final RuleType[] RULE_TYPES_EXCEPT_HOTSPOTS = Arrays.stream(RuleType.values())
.filter(ruleType -> RuleType.SECURITY_HOTSPOT != ruleType).toArray(RuleType[]::new);

@Rule
public ExpectedException expectedException = ExpectedException.none();
@@ -81,7 +86,7 @@ public class EditCommentActionTest {

@Test
public void edit_comment() {
IssueDto issueDto = issueDbTester.insertIssue();
IssueDto issueDto = newIssue();
UserDto user = dbTester.users().insertUser();
IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, user, "please fix it");
loginWithBrowsePermission(user, USER, issueDto);
@@ -98,7 +103,7 @@ public class EditCommentActionTest {

@Test
public void edit_comment_using_deprecated_key_parameter() {
IssueDto issueDto = issueDbTester.insertIssue();
IssueDto issueDto = newIssue();
UserDto user = dbTester.users().insertUser();
IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, user, "please fix it");
loginWithBrowsePermission(user, USER, issueDto);
@@ -115,7 +120,7 @@ public class EditCommentActionTest {

@Test
public void fail_when_comment_does_not_belong_to_current_user() {
IssueDto issueDto = issueDbTester.insertIssue();
IssueDto issueDto = newIssue();
UserDto user = dbTester.users().insertUser();
IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, user, "please fix it");
UserDto another = dbTester.users().insertUser();
@@ -128,7 +133,7 @@ public class EditCommentActionTest {

@Test
public void fail_when_comment_has_not_user() {
IssueDto issueDto = issueDbTester.insertIssue();
IssueDto issueDto = newIssue();
UserDto user = dbTester.users().insertUser();
IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, null, "please fix it");
loginWithBrowsePermission(user, USER, issueDto);
@@ -164,7 +169,7 @@ public class EditCommentActionTest {

@Test
public void fail_when_empty_comment_text() {
IssueDto issueDto = issueDbTester.insertIssue();
IssueDto issueDto = newIssue();
UserDto user = dbTester.users().insertUser();
IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, user, "please fix it");
loginWithBrowsePermission(user, USER, issueDto);
@@ -181,7 +186,7 @@ public class EditCommentActionTest {

@Test
public void fail_when_not_enough_permission() {
IssueDto issueDto = issueDbTester.insertIssue();
IssueDto issueDto = newIssue();
UserDto user = dbTester.users().insertUser();
IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, user, "please fix it");
loginWithBrowsePermission(user, CODEVIEWER, issueDto);
@@ -190,6 +195,18 @@ public class EditCommentActionTest {
call(commentDto.getKey(), "please have a look");
}

@Test
public void fail_NFE_if_security_hotspots() {
IssueDto issueDto = issueDbTester.insertIssue(i -> i.setType(RuleType.SECURITY_HOTSPOT));
UserDto user = dbTester.users().insertUser();
IssueChangeDto commentDto = issueDbTester.insertComment(issueDto, user, "please fix it");
loginWithBrowsePermission(user, CODEVIEWER, issueDto);

expectedException.expect(NotFoundException.class);
expectedException.expectMessage(String.format("Issue with key '%s' does not exist", issueDto.getKey()));
call(commentDto.getKey(), "please have a look");
}

@Test
public void test_definition() {
WebService.Action action = tester.getDef();
@@ -207,6 +224,10 @@ public class EditCommentActionTest {
return request.execute();
}

private IssueDto newIssue() {
return issueDbTester.insertIssue(i -> i.setType(RULE_TYPES_EXCEPT_HOTSPOTS[new Random().nextInt(RULE_TYPES_EXCEPT_HOTSPOTS.length)]));
}

private void loginWithBrowsePermission(UserDto user, String permission, IssueDto issueDto) {
userSession.logIn(user).addProjectPermission(permission,
dbClient.componentDao().selectByUuid(dbTester.getSession(), issueDto.getProjectUuid()).get(),

+ 18
- 19
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsTest.java 查看文件

@@ -25,7 +25,6 @@ import java.util.Date;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.resources.Languages;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.rule.RuleKey;
@@ -110,7 +109,7 @@ public class SearchActionComponentsTest {
private PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer);

private WsActionTester ws = new WsActionTester(new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat,
new MapSettings().asConfig(), System2.INSTANCE, dbClient));
System2.INSTANCE, dbClient));

@Test
public void search_all_issues_when_no_parameter() {
@@ -169,12 +168,12 @@ public class SearchActionComponentsTest {
assertThat(ws.newRequest()
.setParam(PARAM_COMPONENT_KEYS, module1.getKey())
.executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey)
.containsExactlyInAnyOrder(issue1.getKey());
.containsExactlyInAnyOrder(issue1.getKey());

assertThat(ws.newRequest()
.setParam(PARAM_MODULE_UUIDS, module1.uuid())
.executeProtobuf(SearchWsResponse.class).getIssuesList()).extracting(Issue::getKey)
.containsExactlyInAnyOrder(issue1.getKey());
.containsExactlyInAnyOrder(issue1.getKey());
}

@Test
@@ -482,11 +481,11 @@ public class SearchActionComponentsTest {
.setParam(PARAM_COMPONENT_KEYS, applicationBranch1.getKey())
.setParam(PARAM_BRANCH, applicationBranch1.getBranch())
.executeProtobuf(SearchWsResponse.class).getIssuesList())
.extracting(Issue::getKey, Issue::getComponent, Issue::getProject, Issue::getBranch, Issue::hasBranch)
.containsExactlyInAnyOrder(
tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
tuple(issueOnProject2.getKey(), project2.getKey(), project2.getKey(), "", false));
.extracting(Issue::getKey, Issue::getComponent, Issue::getProject, Issue::getBranch, Issue::hasBranch)
.containsExactlyInAnyOrder(
tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch(), true),
tuple(issueOnProject2.getKey(), project2.getKey(), project2.getKey(), "", false));

// Issues on project1Branch1
assertThat(ws.newRequest()
@@ -494,10 +493,10 @@ public class SearchActionComponentsTest {
.setParam(PARAM_PROJECTS, project1.getKey())
.setParam(PARAM_BRANCH, applicationBranch1.getBranch())
.executeProtobuf(SearchWsResponse.class).getIssuesList())
.extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
.containsExactlyInAnyOrder(
tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch()),
tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getBranch()));
.extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
.containsExactlyInAnyOrder(
tuple(issueOnProject1Branch1.getKey(), project1Branch1.getKey(), project1Branch1.getBranch()),
tuple(issueOnFileOnProject1Branch1.getKey(), fileOnProject1Branch1.getKey(), project1Branch1.getBranch()));
}

@Test
@@ -668,24 +667,24 @@ public class SearchActionComponentsTest {
.setParam(PARAM_COMPONENT_KEYS, project.getKey())
.setParam(PARAM_BRANCH, branch.getBranch())
.executeProtobuf(SearchWsResponse.class).getIssuesList())
.extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
.containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
.extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
.containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));

// On project key + branch
assertThat(ws.newRequest()
.setParam(PARAM_PROJECT_KEYS, project.getKey())
.setParam(PARAM_BRANCH, branch.getBranch())
.executeProtobuf(SearchWsResponse.class).getIssuesList())
.extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
.containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
.extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
.containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));

// On file key + branch
assertThat(ws.newRequest()
.setParam(PARAM_COMPONENT_KEYS, branchFile.getKey())
.setParam(PARAM_BRANCH, branch.getBranch())
.executeProtobuf(SearchWsResponse.class).getIssuesList())
.extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
.containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
.extracting(Issue::getKey, Issue::getComponent, Issue::getBranch)
.containsExactlyInAnyOrder(tuple(branchIssue.getKey(), branchFile.getKey(), branchFile.getBranch()));
}

@Test

+ 38
- 14
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionFacetsTest.java 查看文件

@@ -21,12 +21,14 @@ package org.sonar.server.issue.ws;

import com.google.common.collect.ImmutableMap;
import java.time.Clock;
import java.util.Arrays;
import java.util.Map;
import java.util.Random;
import java.util.stream.IntStream;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.issue.Issue;
import org.sonar.api.resources.Languages;
import org.sonar.api.rules.RuleType;
import org.sonar.api.server.ws.WebService;
@@ -73,6 +75,10 @@ import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECTS;

public class SearchActionFacetsTest {

private static final RuleType[] RULE_TYPES_EXCEPT_HOTSPOT = Arrays.stream(RuleType.values()).filter(ruleType -> RuleType.SECURITY_HOTSPOT != ruleType).toArray(RuleType[]::new);
private static final String[] ISSUE_STATUSES = Issue.STATUSES.stream().filter(s -> !Issue.STATUS_TO_REVIEW.equals(s)).filter(s -> !Issue.STATUS_REVIEWED.equals(s))
.toArray(String[]::new);

@Rule
public UserSessionRule userSession = standalone();
@Rule
@@ -92,8 +98,7 @@ public class SearchActionFacetsTest {
private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);

private WsActionTester ws = new WsActionTester(
new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat,
new MapSettings().asConfig(), System2.INSTANCE, db.getDbClient()));
new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat, System2.INSTANCE, db.getDbClient()));

@Test
public void display_all_facets() {
@@ -117,7 +122,7 @@ public class SearchActionFacetsTest {
.executeProtobuf(SearchWsResponse.class);

Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 1L).put("CONFIRMED", 0L)
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("TO_REVIEW", 0L).put("REVIEWED", 0L).build();
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).build();

assertThat(response.getFacets().getFacetsList())
.extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount)))
@@ -126,7 +131,7 @@ public class SearchActionFacetsTest {
tuple("statuses", expectedStatuses),
tuple("resolutions", of("", 1L, "FALSE-POSITIVE", 0L, "FIXED", 0L, "REMOVED", 0L, "WONTFIX", 0L)),
tuple("rules", of(rule.getKey().toString(), 1L)),
tuple("types", of("CODE_SMELL", 1L, "BUG", 0L, "VULNERABILITY", 0L, "SECURITY_HOTSPOT", 0L)),
tuple("types", of("CODE_SMELL", 1L, "BUG", 0L, "VULNERABILITY", 0L)),
tuple("languages", of(rule.getLanguage(), 1L)),
tuple("projects", of(project.getKey(), 1L)),
tuple("moduleUuids", of(module.uuid(), 1L)),
@@ -155,7 +160,7 @@ public class SearchActionFacetsTest {
.executeProtobuf(SearchWsResponse.class);

Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 10L).put("CONFIRMED", 0L)
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("TO_REVIEW", 0L).put("REVIEWED", 0L).build();
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).build();

assertThat(response.getFacets().getFacetsList())
.extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount)))
@@ -164,7 +169,7 @@ public class SearchActionFacetsTest {
tuple("statuses", expectedStatuses),
tuple("resolutions", of("", 10L, "FALSE-POSITIVE", 0L, "FIXED", 0L, "REMOVED", 0L, "WONTFIX", 0L)),
tuple("rules", of(rule.getKey().toString(), 10L)),
tuple("types", of("CODE_SMELL", 10L, "BUG", 0L, "VULNERABILITY", 0L, "SECURITY_HOTSPOT", 0L)),
tuple("types", of("CODE_SMELL", 10L, "BUG", 0L, "VULNERABILITY", 0L)),
tuple("languages", of(rule.getLanguage(), 10L)),
tuple("projects", of(project.getKey(), 10L)),
tuple("fileUuids", of(file.uuid(), 10L)),
@@ -420,17 +425,36 @@ public class SearchActionFacetsTest {
}

@Test
public void check_facets_max_size() {
public void check_facets_max_size_for_issues() {
ComponentDto project = db.components().insertPublicProject();
Random random = new Random();
IntStream.rangeClosed(1, 110)
.forEach(index -> {
RuleDefinitionDto rule = db.rules().insert();
UserDto user = db.users().insertUser();
ComponentDto module = db.components().insertComponent(newModuleDto(project));
ComponentDto directory = db.components().insertComponent(newDirectory(module, "dir" + index));
ComponentDto file = db.components().insertComponent(newFileDto(directory));
db.issues().insert(rule, project, file, i -> i.setAssigneeUuid(user.getUuid()));

RuleDefinitionDto rule = db.rules().insert(ruleDefinitionDto -> ruleDefinitionDto.setType(RULE_TYPES_EXCEPT_HOTSPOT[random.nextInt(RULE_TYPES_EXCEPT_HOTSPOT.length)]));
db.issues().insert(rule, project, file, i -> i.setAssigneeUuid(user.getUuid())
.setStatus(ISSUE_STATUSES[random.nextInt(ISSUE_STATUSES.length)])
.setType(rule.getType()));
});

// insert some hotspots which should be filtered by default
IntStream.rangeClosed(1, 30)
.forEach(index -> {
UserDto user = db.users().insertUser();
ComponentDto module = db.components().insertComponent(newModuleDto(project));
ComponentDto directory = db.components().insertComponent(newDirectory(module, "dir" + index));
ComponentDto file = db.components().insertComponent(newFileDto(directory));

RuleDefinitionDto rule = db.rules().insert(ruleDefinitionDto -> ruleDefinitionDto.setType(RuleType.SECURITY_HOTSPOT));
db.issues().insert(rule, project, file, i -> i.setAssigneeUuid(user.getUuid())
.setStatus(random.nextBoolean() ? Issue.STATUS_TO_REVIEW : Issue.STATUS_REVIEWED)
.setType(rule.getType()));
});

indexPermissions();
indexIssues();

@@ -450,10 +474,10 @@ public class SearchActionFacetsTest {
// Assignees contains one additional element : it's the empty string that will return number of unassigned issues
tuple("assignees", 101),
// Following facets returned fixed number of elements
tuple("statuses", 7),
tuple("statuses", 5),
tuple("resolutions", 5),
tuple("severities", 5),
tuple("types", 4));
tuple("types", 3));
}

@Test
@@ -509,7 +533,7 @@ public class SearchActionFacetsTest {
.executeProtobuf(SearchWsResponse.class);

Map<String, Number> expectedStatuses = ImmutableMap.<String, Number>builder().put("OPEN", 1L).put("CONFIRMED", 0L)
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).put("TO_REVIEW", 0L).put("REVIEWED", 0L).build();
.put("REOPENED", 0L).put("RESOLVED", 0L).put("CLOSED", 0L).build();

assertThat(response.getFacets().getFacetsList())
.extracting(Common.Facet::getProperty, facet -> facet.getValuesList().stream().collect(toMap(FacetValue::getVal, FacetValue::getCount)))
@@ -518,7 +542,7 @@ public class SearchActionFacetsTest {
tuple("statuses", expectedStatuses),
tuple("resolutions", of("", 1L, "FALSE-POSITIVE", 0L, "FIXED", 0L, "REMOVED", 0L, "WONTFIX", 0L)),
tuple("rules", of(rule1.getKey().toString(), 1L, rule2.getKey().toString(), 0L)),
tuple("types", of("CODE_SMELL", 1L, "BUG", 0L, "VULNERABILITY", 0L, "SECURITY_HOTSPOT", 0L)),
tuple("types", of("CODE_SMELL", 1L, "BUG", 0L, "VULNERABILITY", 0L)),
tuple("languages", of(rule1.getLanguage(), 1L, rule2.getLanguage(), 0L)),
tuple("projects", of(project1.getKey(), 1L, project2.getKey(), 0L)),
tuple("moduleUuids", of(module1.uuid(), 1L, module2.uuid(), 0L)),

+ 11
- 39
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTest.java 查看文件

@@ -28,7 +28,6 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.RuleType;
@@ -51,12 +50,12 @@ import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.db.rule.RuleTesting;
import org.sonar.db.user.UserDto;
import org.sonar.server.issue.TextRangeResponseFormatter;
import org.sonar.server.es.EsTester;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.es.StartupIndexer;
import org.sonar.server.issue.AvatarResolverImpl;
import org.sonar.server.issue.IssueFieldsSetter;
import org.sonar.server.issue.TextRangeResponseFormatter;
import org.sonar.server.issue.TransitionService;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.issue.index.IssueIndexer;
@@ -92,7 +91,6 @@ import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.issue.IssueTesting.newDto;
import static org.sonar.server.tester.UserSessionRule.standalone;
import static org.sonarqube.ws.Common.RuleType.BUG;
import static org.sonarqube.ws.Common.RuleType.SECURITY_HOTSPOT;
import static org.sonarqube.ws.Common.RuleType.VULNERABILITY;
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ADDITIONAL_FIELDS;
@@ -123,8 +121,8 @@ public class SearchActionTest {
private Languages languages = new Languages();
private UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);
private WsActionTester ws = new WsActionTester(new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat,
new MapSettings().asConfig(), System2.INSTANCE, dbClient));
private WsActionTester ws = new WsActionTester(
new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat, System2.INSTANCE, dbClient));
private StartupIndexer permissionIndexer = new PermissionIndexer(dbClient, es.client(), issueIndexer);

@Before
@@ -682,7 +680,7 @@ public class SearchActionTest {
}

@Test
public void security_hotspots_are_returned_by_default() {
public void security_hotspots_are_not_returned_by_default() {
ComponentDto project = db.components().insertPublicProject();
ComponentDto file = db.components().insertComponent(newFileDto(project));
RuleDefinitionDto rule = db.rules().insert();
@@ -697,11 +695,11 @@ public class SearchActionTest {

assertThat(result.getIssuesList())
.extracting(Issue::getType)
.containsExactlyInAnyOrder(BUG, VULNERABILITY, Common.RuleType.CODE_SMELL, SECURITY_HOTSPOT);
.containsExactlyInAnyOrder(BUG, VULNERABILITY, Common.RuleType.CODE_SMELL);
}

@Test
public void security_hotspot_type_included_when_explicitly_selected() {
public void fail_if_trying_to_filter_issues_by_hotspots() {
ComponentDto project = db.components().insertPublicProject();
ComponentDto file = db.components().insertComponent(newFileDto(project));
RuleDefinitionDto rule = newRule().getDefinition();
@@ -712,17 +710,12 @@ public class SearchActionTest {
indexPermissions();
indexIssues();

assertThat(ws.newRequest()
.setParam("types", RuleType.SECURITY_HOTSPOT.toString())
.executeProtobuf(SearchWsResponse.class).getIssuesList())
.extracting(Issue::getType)
.containsExactlyInAnyOrder(SECURITY_HOTSPOT);
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Value of parameter 'types' (SECURITY_HOTSPOT) must be one of: [CODE_SMELL, BUG, VULNERABILITY]");

assertThat(ws.newRequest()
.setParam("types", String.format("%s,%s", RuleType.BUG, RuleType.SECURITY_HOTSPOT))
.executeProtobuf(SearchWsResponse.class).getIssuesList())
.extracting(Issue::getType)
.containsExactlyInAnyOrder(BUG, SECURITY_HOTSPOT);
ws.newRequest()
.setParam("types", RuleType.SECURITY_HOTSPOT.toString())
.execute();
}

@Test
@@ -750,27 +743,6 @@ public class SearchActionTest {
.containsExactlyInAnyOrder(tuple("MAJOR", 3L), tuple("INFO", 0L), tuple("MINOR", 0L), tuple("CRITICAL", 0L), tuple("BLOCKER", 0L));
}

@Test
public void do_not_return_severity_on_security_hotspots() {
ComponentDto project = db.components().insertPublicProject();
ComponentDto file = db.components().insertComponent(newFileDto(project));
RuleDefinitionDto rule = db.rules().insert();
db.issues().insert(rule, project, file, i -> i.setType(RuleType.BUG).setSeverity(Severity.MAJOR.name()));
db.issues().insert(rule, project, file, i -> i.setType(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.MAJOR.name()));
indexPermissions();
indexIssues();

SearchWsResponse result = ws.newRequest()
.setParam("types", String.format("%s,%s", RuleType.BUG, RuleType.SECURITY_HOTSPOT))
.executeProtobuf(SearchWsResponse.class);

assertThat(result.getIssuesList())
.extracting(Issue::getType, Issue::hasSeverity)
.containsExactlyInAnyOrder(
tuple(BUG, true),
tuple(SECURITY_HOTSPOT, false));
}

@Test
public void return_total_effort() {
UserDto john = db.users().insertUser();

+ 0
- 170
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SearchActionTestOnSonarCloud.java 查看文件

@@ -1,170 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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.issue.ws;

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import java.time.Clock;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.Durations;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.user.UserDto;
import org.sonar.server.issue.TextRangeResponseFormatter;
import org.sonar.server.es.EsTester;
import org.sonar.server.issue.AvatarResolverImpl;
import org.sonar.server.issue.IssueFieldsSetter;
import org.sonar.server.issue.TransitionService;
import org.sonar.server.issue.index.IssueIndex;
import org.sonar.server.issue.index.IssueIndexer;
import org.sonar.server.issue.index.IssueIteratorFactory;
import org.sonar.server.issue.index.IssueQueryFactory;
import org.sonar.server.issue.workflow.FunctionExecutor;
import org.sonar.server.issue.workflow.IssueWorkflow;
import org.sonar.server.permission.index.PermissionIndexerTester;
import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsActionTester;
import org.sonar.test.JsonAssert;

import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.server.ws.WebService.Param.FACETS;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS;
import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_ORGANIZATION;

public class SearchActionTestOnSonarCloud {
@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public DbTester db = DbTester.create();
@Rule
public EsTester es = EsTester.create();

private MapSettings mapSettings = new MapSettings().setProperty("sonar.sonarcloud.enabled", true);

private DbClient dbClient = db.getDbClient();
private IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSession, new WebAuthorizationTypeSupport(userSession));
private IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient));
private IssueQueryFactory issueQueryFactory = new IssueQueryFactory(dbClient, Clock.systemUTC(), userSession);
private IssueFieldsSetter issueFieldsSetter = new IssueFieldsSetter();
private IssueWorkflow issueWorkflow = new IssueWorkflow(new FunctionExecutor(issueFieldsSetter), issueFieldsSetter);
private SearchResponseLoader searchResponseLoader = new SearchResponseLoader(userSession, dbClient, new TransitionService(userSession, issueWorkflow));
private Languages languages = new Languages();
private UserResponseFormatter userFormatter = new UserResponseFormatter(new AvatarResolverImpl());
private SearchResponseFormat searchResponseFormat = new SearchResponseFormat(new Durations(), languages, new TextRangeResponseFormatter(), userFormatter);
private PermissionIndexerTester permissionIndexer = new PermissionIndexerTester(es, issueIndexer);

private SearchAction underTest = new SearchAction(userSession, issueIndex, issueQueryFactory, searchResponseLoader, searchResponseFormat,
mapSettings.asConfig(), System2.INSTANCE, dbClient);
private WsActionTester ws = new WsActionTester(underTest);

private OrganizationDto organization;
private UserDto user;
private ComponentDto project;

@Before
public void setup() {
underTest.start();
organization = db.organizations().insert(o -> o.setKey("org-1"));
user = db.users().insertUser();

project = db.components().insertPublicProject(organization, p -> p.setDbKey("PK1"));
ComponentDto file = db.components().insertComponent(newFileDto(project, null, "F1").setDbKey("FK1"));
RuleDefinitionDto rule = db.rules().insert(r -> r.setRuleKey(RuleKey.of("xoo", "x1")));
db.issues().insert(rule, project, file, i -> i.setAuthorLogin("leia").setKee("2bd4eac2-b650-4037-80bc-7b112bd4eac2"));
db.issues().insert(rule, project, file, i -> i.setAuthorLogin("luke@skywalker.name").setKee("82fd47d4-b650-4037-80bc-7b1182fd47d4"));
db.commit();
allowAnyoneOnProjects(project);
indexIssues();
}

@Test
public void authors_facet_is_hidden_if_organization_is_not_set() {
db.organizations().addMember(organization, user);
userSession
.logIn(user)
.addMembership(organization);

String input = ws.newRequest()
.setParam(PARAM_COMPONENT_KEYS, project.getKey())
.setParam(FACETS, "authors")
.execute()
.getInput();

JsonAssert.assertJson(input).isSimilarTo(this.getClass().getResource(this.getClass().getSimpleName() + "/no_authors_facet.json"));

JsonElement gson = new JsonParser().parse(input);
assertThat(gson.getAsJsonObject().get("facets").getAsJsonArray()).isEmpty();
}

@Test
public void authors_facet_is_hidden_if_user_is_not_a_member_of_the_organization() {
userSession
.logIn(user);

String input = ws.newRequest()
.setParam(PARAM_COMPONENT_KEYS, project.getKey())
.setParam(FACETS, "authors")
.execute()
.getInput();

JsonAssert.assertJson(input).isSimilarTo(this.getClass().getResource(this.getClass().getSimpleName() + "/no_author_and_no_authors_facet.json"));

JsonElement gson = new JsonParser().parse(input);
assertThat(gson.getAsJsonObject().get("facets").getAsJsonArray()).isEmpty();

}

@Test
public void authors_facet_is_shown_if_organization_is_set_and_user_is_member_of_the_organization() {
db.organizations().addMember(organization, user);

userSession
.logIn(user)
.addMembership(organization);

ws.newRequest()
.setParam(PARAM_COMPONENT_KEYS, project.getKey())
.setParam(FACETS, "authors")
.setParam(PARAM_ORGANIZATION, organization.getKey())
.execute()
.assertJson(this.getClass(), "with_authors_facet.json");
}

private void indexIssues() {
issueIndexer.indexOnStartup(null);
}

private void allowAnyoneOnProjects(ComponentDto... projects) {
userSession.registerComponents(projects);
Arrays.stream(projects).forEach(p -> permissionIndexer.allowOnlyAnyone(p));
}
}

+ 4
- 2
server/sonar-webserver-webapi/src/test/java/org/sonar/server/issue/ws/SetTypeActionTest.java 查看文件

@@ -48,6 +48,7 @@ import org.sonar.db.rule.RuleDefinitionDto;
import org.sonar.db.rule.RuleDto;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.exceptions.UnauthorizedException;
import org.sonar.server.issue.IssueFieldsSetter;
import org.sonar.server.issue.IssueFinder;
@@ -189,13 +190,14 @@ public class SetTypeActionTest {

@Test
@UseDataProvider("allTypesExceptSecurityHotspot")
public void fail_if_trying_to_change_type_of_a_hotspot(RuleType type) {
public void fail_NFE_if_trying_to_change_type_of_a_hotspot(RuleType type) {
long now = 1_999_777_234L;
when(system2.now()).thenReturn(now);
IssueDto issueDto = issueDbTester.insertHotspot();
setUserWithBrowseAndAdministerIssuePermission(issueDto);

expectedException.expect(IllegalArgumentException.class);
expectedException.expect(NotFoundException.class);
expectedException.expectMessage(String.format("Issue with key '%s' does not exist", issueDto.getKey()));
call(issueDto.getKey(), type.name());
}


Loading…
取消
儲存