@@ -19,6 +19,7 @@ | |||
*/ | |||
package org.sonar.server.component.ws; | |||
import com.google.common.collect.ImmutableSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
@@ -51,6 +52,10 @@ import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.util.Objects.requireNonNull; | |||
import static java.util.Optional.ofNullable; | |||
import static java.util.stream.Collectors.toMap; | |||
import static org.sonar.api.resources.Qualifiers.APP; | |||
import static org.sonar.api.resources.Qualifiers.PROJECT; | |||
import static org.sonar.api.resources.Qualifiers.SUBVIEW; | |||
import static org.sonar.api.resources.Qualifiers.VIEW; | |||
import static org.sonar.core.util.stream.MoreCollectors.toHashSet; | |||
import static org.sonar.server.es.SearchOptions.MAX_LIMIT; | |||
import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter; | |||
@@ -61,6 +66,9 @@ import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORG | |||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS; | |||
public class SearchAction implements ComponentsWsAction { | |||
private static final ImmutableSet<String> VALID_QUALIFIERS = ImmutableSet.<String>builder() | |||
.add(APP, PROJECT, VIEW, SUBVIEW) | |||
.build(); | |||
private final ComponentIndex componentIndex; | |||
private final DbClient dbClient; | |||
private final ResourceTypes resourceTypes; | |||
@@ -105,7 +113,7 @@ public class SearchAction implements ComponentsWsAction { | |||
.setExampleValue("my-org") | |||
.setSince("6.3"); | |||
createQualifiersParameter(action, newQualifierParameterContext(i18n, resourceTypes)) | |||
createQualifiersParameter(action, newQualifierParameterContext(i18n, resourceTypes), VALID_QUALIFIERS) | |||
.setRequired(true); | |||
} | |||
@@ -58,15 +58,14 @@ import static java.util.Collections.singletonList; | |||
import static java.util.Optional.ofNullable; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.sonar.api.resources.Qualifiers.APP; | |||
import static org.sonar.api.resources.Qualifiers.DIRECTORY; | |||
import static org.sonar.api.resources.Qualifiers.FILE; | |||
import static org.sonar.api.resources.Qualifiers.MODULE; | |||
import static org.sonar.api.resources.Qualifiers.PROJECT; | |||
import static org.sonar.api.server.ws.WebService.Param.PAGE; | |||
import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE; | |||
import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY; | |||
import static org.sonar.db.component.ComponentTesting.newDirectory; | |||
import static org.sonar.db.component.ComponentTesting.newFileDto; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; | |||
import static org.sonar.db.component.ComponentTesting.newView; | |||
@@ -97,7 +96,7 @@ public class SearchActionTest { | |||
@Before | |||
public void setUp() { | |||
resourceTypes.setAllQualifiers(PROJECT, MODULE, DIRECTORY, FILE); | |||
resourceTypes.setAllQualifiers(APP, PROJECT, DIRECTORY, FILE); | |||
ws = new WsActionTester(new SearchAction(index, db.getDbClient(), resourceTypes, i18n, defaultOrganizationProvider)); | |||
user = db.users().insertUser("john"); | |||
@@ -150,19 +149,6 @@ public class SearchActionTest { | |||
assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly("project-_%-key"); | |||
} | |||
@Test | |||
public void returns_empty_result_when_search_for_files() { | |||
ComponentDto project = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()); | |||
ComponentDto file1 = newFileDto(project).setDbKey("file1"); | |||
ComponentDto file2 = newFileDto(project).setDbKey("file2"); | |||
db.components().insertComponents(project, file1, file2); | |||
setBrowsePermissionOnUserAndIndex(project); | |||
SearchWsResponse response = call(new SearchRequest().setQuery(file1.getDbKey()).setQualifiers(singletonList(FILE))); | |||
assertThat(response.getComponentsList()).isEmpty(); | |||
} | |||
@Test | |||
public void search_with_pagination() { | |||
OrganizationDto organizationDto = db.organizations().insert(); | |||
@@ -203,7 +189,7 @@ public class SearchActionTest { | |||
db.components().insertComponents(project, module, dir1, dir2, dir3); | |||
setBrowsePermissionOnUserAndIndex(project); | |||
SearchWsResponse response = call(new SearchRequest().setQualifiers(asList(PROJECT, MODULE, DIRECTORY))); | |||
SearchWsResponse response = call(new SearchRequest().setQualifiers(asList(PROJECT, APP))); | |||
assertThat(response.getComponentsList()).extracting(Component::getKey, Component::getProject) | |||
.containsOnly(tuple(project.getDbKey(), project.getDbKey())); | |||
@@ -215,7 +201,7 @@ public class SearchActionTest { | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
setBrowsePermissionOnUserAndIndex(project, branch); | |||
SearchWsResponse response = call(new SearchRequest().setQualifiers(asList(PROJECT, MODULE, FILE))); | |||
SearchWsResponse response = call(new SearchRequest().setQualifiers(asList(PROJECT))); | |||
assertThat(response.getComponentsList()).extracting(Component::getKey) | |||
.containsOnly(project.getDbKey()); | |||
@@ -224,7 +210,7 @@ public class SearchActionTest { | |||
@Test | |||
public void fail_if_unknown_qualifier_provided() { | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Value of parameter 'qualifiers' (Unknown-Qualifier) must be one of: [BRC, DIR, FIL, TRK]"); | |||
expectedException.expectMessage("Value of parameter 'qualifiers' (Unknown-Qualifier) must be one of: [APP, TRK]"); | |||
call(new SearchRequest().setQualifiers(singletonList("Unknown-Qualifier"))); | |||
} | |||
@@ -251,7 +237,7 @@ public class SearchActionTest { | |||
String response = ws.newRequest() | |||
.setMediaType(MediaTypes.JSON) | |||
.setParam(PARAM_ORGANIZATION, organizationDto.getKey()) | |||
.setParam(PARAM_QUALIFIERS, Joiner.on(",").join(PROJECT, DIRECTORY)) | |||
.setParam(PARAM_QUALIFIERS, PROJECT) | |||
.execute().getInput(); | |||
assertJson(response).isSimilarTo(ws.getDef().responseExampleAsString()); | |||
} |
@@ -58,10 +58,17 @@ public class WsParameterBuilder { | |||
} | |||
public static WebService.NewParam createQualifiersParameter(WebService.NewAction action, QualifierParameterContext context) { | |||
return createQualifiersParameter(action, context, getAllQualifiers(context.getResourceTypes())); | |||
} | |||
public static WebService.NewParam createQualifiersParameter(WebService.NewAction action, QualifierParameterContext context, Set<String> availableQualifiers) { | |||
Set<String> filteredQualifiers = getAllQualifiers(context.getResourceTypes()).stream().filter(availableQualifiers::contains) | |||
.collect(Collectors.toSet()); | |||
return action.createParam(PARAM_QUALIFIERS) | |||
.setDescription( | |||
"Comma-separated list of component qualifiers. Filter the results with the specified qualifiers. Possible values are:" + buildAllQualifiersDescription(context)) | |||
.setPossibleValues(getAllQualifiers(context.getResourceTypes())); | |||
"Comma-separated list of component qualifiers. Filter the results with the specified qualifiers. Possible values are:" | |||
+ buildQualifiersDescription(context, filteredQualifiers)) | |||
.setPossibleValues(filteredQualifiers); | |||
} | |||
private static Set<String> getRootQualifiers(ResourceTypes resourceTypes) { | |||
@@ -90,10 +97,6 @@ public class WsParameterBuilder { | |||
return buildQualifiersDescription(context, getRootQualifiers(context.getResourceTypes())); | |||
} | |||
private static String buildAllQualifiersDescription(QualifierParameterContext context) { | |||
return buildQualifiersDescription(context, getAllQualifiers(context.getResourceTypes())); | |||
} | |||
private static String buildQualifiersDescription(QualifierParameterContext context, Set<String> qualifiers) { | |||
StringBuilder description = new StringBuilder(); | |||
description.append("<ul>"); |
@@ -0,0 +1,125 @@ | |||
/* | |||
* 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.ws; | |||
import com.google.common.collect.Sets; | |||
import java.util.Collection; | |||
import org.junit.Test; | |||
import org.sonar.api.resources.ResourceType; | |||
import org.sonar.api.resources.ResourceTypes; | |||
import org.sonar.api.server.ws.WebService.NewAction; | |||
import org.sonar.api.server.ws.WebService.NewParam; | |||
import org.sonar.core.i18n.I18n; | |||
import static java.util.Arrays.asList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.startsWith; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext; | |||
import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS; | |||
import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_QUALIFIER; | |||
public class WsParameterBuilderTest { | |||
private ResourceTypes resourceTypes = mock(ResourceTypes.class); | |||
private static final ResourceType Q1 = ResourceType.builder("Q1").build(); | |||
private static final ResourceType Q2 = ResourceType.builder("Q2").build(); | |||
private I18n i18n = mock(I18n.class); | |||
private NewAction newAction = mock(NewAction.class); | |||
private NewParam newParam = mock(NewParam.class); | |||
@Test | |||
public void test_createRootQualifierParameter() { | |||
when(resourceTypes.getRoots()).thenReturn(asList(Q1, Q2)); | |||
when(newAction.createParam(PARAM_QUALIFIER)).thenReturn(newParam); | |||
when(newParam.setDescription(startsWith("Project qualifier. Filter the results with the specified qualifier. " | |||
+ "Possible values are:" | |||
+ "<ul><li>Q1 - null</li>" | |||
+ "<li>Q2 - null</li></ul>"))).thenReturn(newParam); | |||
when(newParam.setPossibleValues(any(Collection.class))).thenReturn(newParam); | |||
NewParam newParam = WsParameterBuilder | |||
.createRootQualifierParameter(newAction, newQualifierParameterContext(i18n, resourceTypes)); | |||
assertThat(newParam).isNotNull(); | |||
} | |||
@Test | |||
public void test_createRootQualifiersParameter() { | |||
when(resourceTypes.getRoots()).thenReturn(asList(Q1, Q2)); | |||
when(newAction.createParam(PARAM_QUALIFIERS)).thenReturn(newParam); | |||
when(newParam.setDescription(startsWith("Comma-separated list of component qualifiers. Filter the results with the specified qualifiers. " + | |||
"Possible values are:" | |||
+ "<ul><li>Q1 - null</li>" | |||
+ "<li>Q2 - null</li></ul>"))).thenReturn(newParam); | |||
when(newParam.setPossibleValues(any(Collection.class))).thenReturn(newParam); | |||
NewParam newParam = WsParameterBuilder | |||
.createRootQualifiersParameter(newAction, newQualifierParameterContext(i18n, resourceTypes)); | |||
assertThat(newParam).isNotNull(); | |||
} | |||
@Test | |||
public void test_createDefaultTemplateQualifierParameter() { | |||
when(resourceTypes.getRoots()).thenReturn(asList(Q1, Q2)); | |||
when(newAction.createParam(PARAM_QUALIFIER)).thenReturn(newParam); | |||
when(newParam.setDescription(startsWith("Project qualifier. Filter the results with the specified qualifier. " | |||
+ "Possible values are:" | |||
+ "<ul><li>Q1 - null</li>" | |||
+ "<li>Q2 - null</li></ul>"))).thenReturn(newParam); | |||
when(newParam.setPossibleValues(any(Collection.class))).thenReturn(newParam); | |||
NewParam newParam = WsParameterBuilder | |||
.createDefaultTemplateQualifierParameter(newAction, newQualifierParameterContext(i18n, resourceTypes)); | |||
assertThat(newParam).isNotNull(); | |||
} | |||
@Test | |||
public void test_createQualifiersParameter() { | |||
when(resourceTypes.getAll()).thenReturn(asList(Q1, Q2)); | |||
when(newAction.createParam(PARAM_QUALIFIERS)).thenReturn(newParam); | |||
when(newParam.setDescription(startsWith("Comma-separated list of component qualifiers. Filter the results with the specified qualifiers. " | |||
+ "Possible values are:" | |||
+ "<ul><li>Q1 - null</li>" | |||
+ "<li>Q2 - null</li></ul>"))).thenReturn(newParam); | |||
when(newParam.setPossibleValues(any(Collection.class))).thenReturn(newParam); | |||
NewParam newParam = WsParameterBuilder | |||
.createQualifiersParameter(newAction, newQualifierParameterContext(i18n, resourceTypes)); | |||
assertThat(newParam).isNotNull(); | |||
} | |||
@Test | |||
public void test_createQualifiersParameter_with_filter() { | |||
when(resourceTypes.getAll()).thenReturn(asList(Q1, Q2)); | |||
when(newAction.createParam(PARAM_QUALIFIERS)).thenReturn(newParam); | |||
when(newParam.setDescription(startsWith("Comma-separated list of component qualifiers. Filter the results with the specified qualifiers. " | |||
+ "Possible values are:" | |||
+ "<ul><li>Q1 - null</li></ul>"))).thenReturn(newParam); | |||
when(newParam.setPossibleValues(any(Collection.class))).thenReturn(newParam); | |||
NewParam newParam = WsParameterBuilder | |||
.createQualifiersParameter(newAction, newQualifierParameterContext(i18n, resourceTypes), Sets.newHashSet(Q1.getQualifier())); | |||
assertThat(newParam).isNotNull(); | |||
} | |||
} |