Kaynağa Gözat

SONAR-12834 filter hotspots by current user

tags/8.2.0.32929
Jacek 4 yıl önce
ebeveyn
işleme
0cde042754

+ 32
- 5
server/sonar-webserver-webapi/src/main/java/org/sonar/server/hotspot/ws/SearchAction.java Dosyayı Görüntüle

@@ -22,6 +22,7 @@ package org.sonar.server.hotspot.ws;
import com.google.common.collect.ImmutableSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -90,6 +91,7 @@ public class SearchAction implements HotspotsWsAction {
private static final String PARAM_BRANCH = "branch";
private static final String PARAM_PULL_REQUEST = "pullRequest";
private static final String PARAM_SINCE_LEAK_PERIOD = "sinceLeakPeriod";
private static final String PARAM_ONLY_MINE = "onlyMine";

private final DbClient dbClient;
private final UserSession userSession;
@@ -146,6 +148,11 @@ public class SearchAction implements HotspotsWsAction {
.setDescription("If '%s' is provided, only Security Hotspots created since the leak period are returned.")
.setBooleanPossibleValues()
.setDefaultValue("false");
action.createParam(PARAM_ONLY_MINE)
.setDescription("If 'projectKey' is provided, returns only Security Hotspots assigned to the current user")
.setBooleanPossibleValues()
.setRequired(false);

// FIXME add response example and test it
// action.setResponseExample()
}
@@ -172,15 +179,15 @@ public class SearchAction implements HotspotsWsAction {
request.param(PARAM_PROJECT_KEY), request.param(PARAM_BRANCH), request.param(PARAM_PULL_REQUEST),
hotspotKeys,
request.param(PARAM_STATUS), request.param(PARAM_RESOLUTION),
request.paramAsBoolean(PARAM_SINCE_LEAK_PERIOD));
request.paramAsBoolean(PARAM_SINCE_LEAK_PERIOD),
request.paramAsBoolean(PARAM_ONLY_MINE));
}

private static void validateParameters(WsRequest wsRequest) {
private void validateParameters(WsRequest wsRequest) {
Optional<String> projectKey = wsRequest.getProjectKey();
Optional<String> branch = wsRequest.getBranch();
Optional<String> pullRequest = wsRequest.getPullRequest();
Set<String> hotspotKeys = wsRequest.getHotspotKeys();

checkArgument(
projectKey.isPresent() || !hotspotKeys.isEmpty(),
"A value must be provided for either parameter '%s' or parameter '%s'", PARAM_PROJECT_KEY, PARAM_HOTSPOTS);
@@ -206,6 +213,13 @@ public class SearchAction implements HotspotsWsAction {
r -> checkArgument(status.filter(STATUS_REVIEWED::equals).isPresent(),
"Value '%s' of parameter '%s' can only be provided if value of parameter '%s' is '%s'",
r, PARAM_RESOLUTION, PARAM_STATUS, STATUS_REVIEWED));

if (wsRequest.isOnlyMine()) {
checkArgument(userSession.isLoggedIn(),
"Parameter '%s' requires user to be logged in", PARAM_ONLY_MINE);
checkArgument(wsRequest.getProjectKey().isPresent(),
"Parameter '%s' can be used with parameter '%s' only", PARAM_ONLY_MINE, PARAM_PROJECT_KEY);
}
}

private Optional<ComponentDto> getAndValidateProject(DbSession dbSession, WsRequest wsRequest) {
@@ -276,6 +290,12 @@ public class SearchAction implements HotspotsWsAction {
if (!hotspotKeys.isEmpty()) {
builder.issueKeys(hotspotKeys);
}

if (wsRequest.isOnlyMine()) {
userSession.checkLoggedIn();
builder.assigneeUuids(Collections.singletonList(userSession.getUuid()));
}

wsRequest.getStatus().ifPresent(status -> builder.resolved(STATUS_REVIEWED.equals(status)));
wsRequest.getResolution().ifPresent(resolution -> builder.resolutions(singleton(resolution)));

@@ -380,11 +400,13 @@ public class SearchAction implements HotspotsWsAction {
private final String status;
private final String resolution;
private final boolean sinceLeakPeriod;
private final boolean onlyMine;

private WsRequest(int page, int index,
@Nullable String projectKey, @Nullable String branch, @Nullable String pullRequest,
Set<String> hotspotKeys,
@Nullable String status, @Nullable String resolution, @Nullable Boolean sinceLeakPeriod) {
@Nullable String status, @Nullable String resolution, @Nullable Boolean sinceLeakPeriod,
@Nullable Boolean onlyMine) {
this.page = page;
this.index = index;
this.projectKey = projectKey;
@@ -393,7 +415,8 @@ public class SearchAction implements HotspotsWsAction {
this.hotspotKeys = hotspotKeys;
this.status = status;
this.resolution = resolution;
this.sinceLeakPeriod = sinceLeakPeriod == null ? false : sinceLeakPeriod;
this.sinceLeakPeriod = sinceLeakPeriod != null && sinceLeakPeriod;
this.onlyMine = onlyMine != null && onlyMine;
}

int getPage() {
@@ -431,6 +454,10 @@ public class SearchAction implements HotspotsWsAction {
boolean isSinceLeakPeriod() {
return sinceLeakPeriod;
}

boolean isOnlyMine() {
return onlyMine;
}
}

private static final class SearchResponseData {

+ 88
- 1
server/sonar-webserver-webapi/src/test/java/org/sonar/server/hotspot/ws/SearchActionTest.java Dosyayı Görüntüle

@@ -71,6 +71,7 @@ import org.sonarqube.ws.Hotspots.Component;
import org.sonarqube.ws.Hotspots.SearchWsResponse;

import static java.util.Collections.singleton;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
@@ -111,8 +112,11 @@ public class SearchActionTest {
private WsActionTester actionTester = new WsActionTester(underTest);

@Test
public void ws_is_internal() {
public void verify_ws_def() {
assertThat(actionTester.getDef().isInternal()).isTrue();
assertThat(actionTester.getDef().param("onlyMine").isRequired()).isFalse();
assertThat(actionTester.getDef().param("onlyMine").possibleValues())
.containsExactlyInAnyOrder("yes", "no", "true", "false");
}

@Test
@@ -506,6 +510,85 @@ public class SearchActionTest {
.containsExactlyInAnyOrder(Arrays.stream(hotspotPR).map(IssueDto::getKey).toArray(String[]::new));
}

@Test
@UseDataProvider("onlyMineParamValues")
public void returns_hotspots_of_specified_project_assigned_to_current_user_if_only_mine_is_set(String onlyMineParameter, boolean shouldFilter) {
ComponentDto project1 = dbTester.components().insertPublicProject();
String assigneeUuid = this.userSessionRule.logIn().registerComponents(project1).getUuid();

indexPermissions();
ComponentDto file1 = dbTester.components().insertComponent(newFileDto(project1));
IssueDto[] assigneeHotspots = IntStream.range(0, 1 + RANDOM.nextInt(10))
.mapToObj(i -> {
RuleDefinitionDto rule = newRule(SECURITY_HOTSPOT);
insertHotspot(project1, file1, rule, randomAlphabetic(5));
return insertHotspot(project1, file1, rule, assigneeUuid);
})
.toArray(IssueDto[]::new);

indexIssues();

SearchWsResponse allHotspots = newRequest(project1)
.executeProtobuf(SearchWsResponse.class);

SearchWsResponse userHotspots = newRequest(project1, r -> r.setParam("onlyMine", onlyMineParameter))
.executeProtobuf(SearchWsResponse.class);

assertThat(allHotspots.getHotspotsList())
.extracting(SearchWsResponse.Hotspot::getKey)
.contains(Arrays.stream(assigneeHotspots).map(IssueDto::getKey).toArray(String[]::new))
.hasSizeGreaterThan(assigneeHotspots.length);

if (shouldFilter) {
assertThat(userHotspots.getHotspotsList())
.extracting(SearchWsResponse.Hotspot::getKey)
.containsOnly(Arrays.stream(assigneeHotspots).map(IssueDto::getKey).toArray(String[]::new));
} else {
assertThat(userHotspots.getHotspotsList())
.extracting(SearchWsResponse.Hotspot::getKey)
.containsOnly(allHotspots.getHotspotsList().stream().map(SearchWsResponse.Hotspot::getKey).toArray(String[]::new));
}
}

@DataProvider
public static Object[][] onlyMineParamValues() {
return new Object[][] {
{"yes", true},
{"true", true},
{"no", false},
{"false", false}
};
}

@Test
public void fail_if_hotspots_provided_with_onlyMine_param() {
ComponentDto project = dbTester.components().insertPrivateProject();

userSessionRule.registerComponents(project);
userSessionRule.logIn().addProjectPermission(UserRole.USER, project);

assertThatThrownBy(() -> actionTester.newRequest()
.setParam("hotspots", IntStream.range(2, 10).mapToObj(String::valueOf).collect(joining(",")))
.setParam("onlyMine", "true")
.execute())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Parameter 'onlyMine' can be used with parameter 'projectKey' only");
}

@Test
public void fail_if_user_not_authenticated_with_onlyMine_param() {
ComponentDto project = dbTester.components().insertPublicProject();

userSessionRule.anonymous();

assertThatThrownBy(() -> actionTester.newRequest()
.setParam("projectKey", project.getKey())
.setParam("onlyMine", "true")
.execute())
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("Parameter 'onlyMine' requires user to be logged in");
}

@Test
public void returns_hotpots_with_any_status_if_no_status_nor_resolution_parameter() {
ComponentDto project = dbTester.components().insertPublicProject();
@@ -1127,6 +1210,10 @@ public class SearchActionTest {
return dbTester.issues().insert(rule, project, file, t -> t.setType(SECURITY_HOTSPOT));
}

private IssueDto insertHotspot(ComponentDto project, ComponentDto file, RuleDefinitionDto rule, String assigneeUuid) {
return dbTester.issues().insert(rule, project, file, t -> t.setType(SECURITY_HOTSPOT).setAssigneeUuid(assigneeUuid));
}

private TestRequest newRequest(ComponentDto project) {
return newRequest(project, null, null);
}

Loading…
İptal
Kaydet