From: Sébastien Lesaint Date: Fri, 27 Jan 2017 08:28:59 +0000 (+0100) Subject: SONAR-8648 add organization parameter to api/components/search X-Git-Tag: 6.3-RC1~344 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=1667ff43142ce1dedcf716f62734bf64264349d1;p=sonarqube.git SONAR-8648 add organization parameter to api/components/search --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java index 3538aaca55d..25427abe3da 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java @@ -19,12 +19,11 @@ */ package org.sonar.server.component.ws; -import com.google.common.base.Function; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; -import javax.annotation.Nonnull; import org.sonar.api.i18n.I18n; import org.sonar.api.resources.Languages; import org.sonar.api.resources.ResourceTypes; @@ -39,12 +38,14 @@ import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentQuery; import org.sonar.db.organization.OrganizationDto; +import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.user.UserSession; +import org.sonar.server.ws.WsUtils; import org.sonarqube.ws.WsComponents; import org.sonarqube.ws.WsComponents.SearchWsResponse; import org.sonarqube.ws.client.component.SearchWsRequest; -import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkArgument; import static org.sonar.api.web.UserRole.USER; import static org.sonar.core.util.Protobuf.setNullable; import static org.sonar.core.util.stream.Collectors.uniqueIndex; @@ -55,6 +56,7 @@ import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.n import static org.sonar.server.ws.WsUtils.writeProtobuf; import static org.sonarqube.ws.client.component.ComponentsWsParameters.ACTION_SEARCH; import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_LANGUAGE; +import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION; import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS; public class SearchAction implements ComponentsWsAction { @@ -63,13 +65,16 @@ public class SearchAction implements ComponentsWsAction { private final I18n i18n; private final UserSession userSession; private final Languages languages; + private final DefaultOrganizationProvider defaultOrganizationProvider; - public SearchAction(DbClient dbClient, ResourceTypes resourceTypes, I18n i18n, UserSession userSession, Languages languages) { + public SearchAction(DbClient dbClient, ResourceTypes resourceTypes, I18n i18n, UserSession userSession, + Languages languages, DefaultOrganizationProvider defaultOrganizationProvider) { this.dbClient = dbClient; this.resourceTypes = resourceTypes; this.i18n = i18n; this.userSession = userSession; this.languages = languages; + this.defaultOrganizationProvider = defaultOrganizationProvider; } @Override @@ -81,6 +86,13 @@ public class SearchAction implements ComponentsWsAction { .addSearchQuery("sona", "component names", "component keys") .setResponseExample(getClass().getResource("search-components-example.json")) .setHandler(this); + action + .createParam(PARAM_ORGANIZATION) + .setDescription("Organization key") + .setRequired(false) + .setInternal(true) + .setExampleValue("my-org") + .setSince("6.3"); action .createParam(PARAM_LANGUAGE) .setDescription("Language key. If provided, only components for the given language are returned.") @@ -96,24 +108,9 @@ public class SearchAction implements ComponentsWsAction { writeProtobuf(searchWsResponse, wsRequest, wsResponse); } - private SearchWsResponse doHandle(SearchWsRequest request) { - try (DbSession dbSession = dbClient.openSession(false)) { - ComponentQuery query = buildQuery(request); - Paging paging = buildPaging(dbSession, request, query); - List components = searchComponents(dbSession, query, paging); - - Set organizationUuids = components.stream() - .map(ComponentDto::getOrganizationUuid) - .collect(Collectors.toSet()); - Map organizationsByUuid = dbClient.organizationDao().selectByUuids(dbSession, organizationUuids) - .stream() - .collect(Collectors.uniqueIndex(OrganizationDto::getUuid)); - return buildResponse(components, organizationsByUuid, paging); - } - } - private static SearchWsRequest toSearchWsRequest(Request request) { return new SearchWsRequest() + .setOrganization(request.param(PARAM_ORGANIZATION)) .setQualifiers(request.mandatoryParamAsStrings(PARAM_QUALIFIERS)) .setLanguage(request.param(PARAM_LANGUAGE)) .setQuery(request.param(Param.TEXT_QUERY)) @@ -121,8 +118,43 @@ public class SearchAction implements ComponentsWsAction { .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE)); } - private List searchComponents(DbSession dbSession, ComponentQuery query, Paging paging) { - List componentDtos = dbClient.componentDao().selectByQuery(dbSession, query, paging.offset(), paging.pageSize()); + private SearchWsResponse doHandle(SearchWsRequest request) { + try (DbSession dbSession = dbClient.openSession(false)) { + ComponentQuery query = buildQuery(request); + OrganizationDto organization = getOrganization(dbSession, request); + Paging paging = buildPaging(dbSession, request, organization, query); + List components = searchComponents(dbSession, organization, query, paging); + + return buildResponse(components, organization, paging); + } + } + + private static ComponentQuery buildQuery(SearchWsRequest request) { + List qualifiers = request.getQualifiers(); + return ComponentQuery.builder() + .setNameOrKeyQuery(request.getQuery()) + .setLanguage(request.getLanguage()) + .setQualifiers(qualifiers.toArray(new String[qualifiers.size()])) + .build(); + } + + private OrganizationDto getOrganization(DbSession dbSession, SearchWsRequest request) { + String organizationKey = Optional.ofNullable(request.getOrganization()) + .orElseGet(defaultOrganizationProvider.get()::getKey); + return WsUtils.checkFoundWithOptional( + dbClient.organizationDao().selectByKey(dbSession, organizationKey), + "No organizationDto with key '%s'", organizationKey); + } + + private Paging buildPaging(DbSession dbSession, SearchWsRequest request, OrganizationDto organization, ComponentQuery query) { + int total = dbClient.componentDao().countByQuery(dbSession, organization.getUuid(), query); + return Paging.forPageIndex(request.getPage()) + .withPageSize(request.getPageSize()) + .andTotal(total); + } + + private List searchComponents(DbSession dbSession, OrganizationDto organization, ComponentQuery query, Paging paging) { + List componentDtos = dbClient.componentDao().selectByQuery(dbSession, organization.getUuid(), query, paging.offset(), paging.pageSize()); return filterAuthorizedComponents(dbSession, componentDtos); } @@ -136,7 +168,7 @@ public class SearchAction implements ComponentsWsAction { .collect(Collectors.toList()); } - private static SearchWsResponse buildResponse(List components, Map organizationsByUuid, Paging paging) { + private static SearchWsResponse buildResponse(List components, OrganizationDto organization, Paging paging) { SearchWsResponse.Builder responseBuilder = SearchWsResponse.newBuilder(); responseBuilder.getPagingBuilder() .setPageIndex(paging.pageIndex()) @@ -145,50 +177,26 @@ public class SearchAction implements ComponentsWsAction { .build(); components.stream() - .map(new ComponentDToComponentResponseFunction(organizationsByUuid)::apply) + .map(dto -> dtoToComponent(organization, dto)) .forEach(responseBuilder::addComponents); return responseBuilder.build(); } - private Paging buildPaging(DbSession dbSession, SearchWsRequest request, ComponentQuery query) { - int total = dbClient.componentDao().countByQuery(dbSession, query); - return Paging.forPageIndex(request.getPage()) - .withPageSize(request.getPageSize()) - .andTotal(total); + private static WsComponents.Component dtoToComponent(OrganizationDto organization, ComponentDto dto) { + checkArgument( + organization.getUuid().equals(dto.getOrganizationUuid()), + "No Organization found for uuid '%s'", + dto.getOrganizationUuid()); + + WsComponents.Component.Builder builder = WsComponents.Component.newBuilder() + .setOrganization(organization.getKey()) + .setId(dto.uuid()) + .setKey(dto.key()) + .setName(dto.name()) + .setQualifier(dto.qualifier()); + setNullable(dto.language(), builder::setLanguage); + return builder.build(); } - private static ComponentQuery buildQuery(SearchWsRequest request) { - List qualifiers = request.getQualifiers(); - return ComponentQuery.builder() - .setNameOrKeyQuery(request.getQuery()) - .setLanguage(request.getLanguage()) - .setQualifiers(qualifiers.toArray(new String[qualifiers.size()])) - .build(); - } - - private static class ComponentDToComponentResponseFunction implements Function { - private final Map organizationsByUuid; - - private ComponentDToComponentResponseFunction(Map organizationsByUuid) { - this.organizationsByUuid = organizationsByUuid; - } - - @Override - public WsComponents.Component apply(@Nonnull ComponentDto dto) { - OrganizationDto organization = checkNotNull( - organizationsByUuid.get(dto.getOrganizationUuid()), - "No Organization found for uuid '%s'", - dto.getOrganizationUuid()); - - WsComponents.Component.Builder builder = WsComponents.Component.newBuilder() - .setOrganization(organization.getKey()) - .setId(dto.uuid()) - .setKey(dto.key()) - .setName(dto.name()) - .setQualifier(dto.qualifier()); - setNullable(dto.language(), builder::setLanguage); - return builder.build(); - } - } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java index 8e937c36ffe..b93c6051c37 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/ComponentsWsTest.java @@ -30,6 +30,7 @@ import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.server.component.ComponentFinder; import org.sonar.server.component.index.ComponentIndex; +import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsTester; @@ -52,7 +53,7 @@ public class ComponentsWsTest { WsTester tester = new WsTester(new ComponentsWs( new AppAction(mock(DbClient.class), userSessionRule, mock(ComponentFinder.class)), new SuggestionsAction(mock(DbClient.class), mock(ComponentIndex.class)), - new SearchAction(mock(DbClient.class), mock(ResourceTypes.class), mock(I18n.class), userSessionRule, languages))); + new SearchAction(mock(DbClient.class), mock(ResourceTypes.class), mock(I18n.class), userSessionRule, languages, TestDefaultOrganizationProvider.fromUuid("foo")))); controller = tester.controller("api/components"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchActionTest.java index 24ee4f44ea0..064ed90b921 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ws/SearchActionTest.java @@ -40,6 +40,7 @@ import org.sonar.db.component.ResourceTypesRule; import org.sonar.db.organization.OrganizationDto; import org.sonar.db.user.UserDto; import org.sonar.server.i18n.I18nRule; +import org.sonar.server.organization.TestDefaultOrganizationProvider; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; @@ -68,6 +69,7 @@ import static org.sonar.test.JsonAssert.assertJson; import static org.sonarqube.ws.MediaTypes.PROTOBUF; import static org.sonarqube.ws.WsComponents.Component; import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_LANGUAGE; +import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_ORGANIZATION; import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_QUALIFIERS; public class SearchActionTest { @@ -80,6 +82,7 @@ public class SearchActionTest { private I18nRule i18n = new I18nRule(); + private TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db); private ResourceTypesRule resourceTypes = new ResourceTypesRule(); private Languages languages = mock(Languages.class); private UserDto user; @@ -90,12 +93,35 @@ public class SearchActionTest { public void setUp() { resourceTypes.setAllQualifiers(PROJECT, MODULE, DIRECTORY, FILE); when(languages.all()).thenReturn(javaLanguage()); - ws = new WsActionTester(new SearchAction(db.getDbClient(), resourceTypes, i18n, userSession, languages)); + ws = new WsActionTester(new SearchAction(db.getDbClient(), resourceTypes, i18n, userSession, languages, defaultOrganizationProvider)); user = db.users().insertUser("john"); userSession.login(user); } + @Test + public void verify_definition() { + WebService.Action action = ws.getDef(); + + assertThat(action.description()).isEqualTo("Search for components"); + assertThat(action.since()).isEqualTo("6.3"); + assertThat(action.isPost()).isFalse(); + assertThat(action.isInternal()).isFalse(); + assertThat(action.responseExampleAsString()).isNotEmpty(); + + assertThat(action.params()).hasSize(6); + + WebService.Param qualifiers = action.param("qualifiers"); + assertThat(qualifiers.isRequired()).isTrue(); + + WebService.Param organization = action.param("organization"); + assertThat(organization.isRequired()).isFalse(); + assertThat(organization.description()).isEqualTo("Organization key"); + assertThat(organization.isInternal()).isTrue(); + assertThat(organization.exampleValue()).isEqualTo("my-org"); + assertThat(organization.since()).isEqualTo("6.3"); + } + @Test public void search_by_key_query() throws IOException { insertProjectsAuthorizedForUser( @@ -129,7 +155,7 @@ public class SearchActionTest { } insertProjectsAuthorizedForUser(componentDtoList.toArray(new ComponentDto[] {})); - SearchWsResponse response = call(new SearchWsRequest().setPage(2).setPageSize(3).setQualifiers(singletonList(PROJECT))); + SearchWsResponse response = call(new SearchWsRequest().setOrganization(organizationDto.getKey()).setPage(2).setPageSize(3).setQualifiers(singletonList(PROJECT))); assertThat(response.getComponentsList()).extracting(Component::getKey).containsExactly("project-key-4", "project-key-5", "project-key-6"); } @@ -141,7 +167,7 @@ public class SearchActionTest { newProjectDto(organizationDto).setKey("java-project").setLanguage("java"), newProjectDto(organizationDto).setKey("cpp-project").setLanguage("cpp")); - SearchWsResponse response = call(new SearchWsRequest().setLanguage("java").setQualifiers(singletonList(PROJECT))); + SearchWsResponse response = call(new SearchWsRequest().setOrganization(organizationDto.getKey()).setLanguage("java").setQualifiers(singletonList(PROJECT))); assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly("java-project"); } @@ -190,24 +216,12 @@ public class SearchActionTest { String response = ws.newRequest() .setMediaType(MediaTypes.JSON) + .setParam(PARAM_ORGANIZATION, organizationDto.getKey()) .setParam(PARAM_QUALIFIERS, Joiner.on(",").join(PROJECT, MODULE, DIRECTORY, FILE)) .execute().getInput(); assertJson(response).isSimilarTo(ws.getDef().responseExampleAsString()); } - @Test - public void test_definition() { - WebService.Action action = ws.getDef(); - - assertThat(action).isNotNull(); - assertThat(action.param("qualifiers").isRequired()).isTrue(); - assertThat(action.responseExampleAsString()).isNotEmpty(); - assertThat(action.description()).isNotEmpty(); - assertThat(action.isInternal()).isFalse(); - assertThat(action.isPost()).isFalse(); - assertThat(action.since()).isEqualTo("6.3"); - } - private void insertProjectsAuthorizedForUser(ComponentDto... projects) { db.components().insertComponents(projects); setBrowsePermissionOnUser(projects); @@ -222,6 +236,7 @@ public class SearchActionTest { private SearchWsResponse call(SearchWsRequest wsRequest) { TestRequest request = ws.newRequest() .setMediaType(PROTOBUF); + setNullable(wsRequest.getOrganization(), p -> request.setParam(PARAM_ORGANIZATION, p)); setNullable(wsRequest.getLanguage(), p -> request.setParam(PARAM_LANGUAGE, p)); setNullable(wsRequest.getQualifiers(), p -> request.setParam(PARAM_QUALIFIERS, Joiner.on(",").join(p))); setNullable(wsRequest.getQuery(), p -> request.setParam(TEXT_QUERY, p)); diff --git a/sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java b/sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java index 9880e51467f..d475e9ead20 100644 --- a/sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java +++ b/sonar-db/src/main/java/org/sonar/db/component/ComponentDao.java @@ -77,17 +77,37 @@ public class ComponentDao implements Dao { } public List selectByQuery(DbSession session, ComponentQuery query, int offset, int limit) { - if (query.getComponentIds() != null && query.getComponentIds().isEmpty()) { + return selectByQueryImpl(session, null, query, offset, limit); + } + + public List selectByQuery(DbSession dbSession, String organizationUuid, ComponentQuery query, int offset, int limit) { + requireNonNull(organizationUuid, "organizationUuid can't be null"); + return selectByQueryImpl(dbSession, organizationUuid, query, offset, limit); + } + + private static List selectByQueryImpl(DbSession session, @Nullable String organizationUuid, ComponentQuery query, int offset, int limit) { + Set componentIds = query.getComponentIds(); + if (componentIds != null && componentIds.isEmpty()) { return emptyList(); } - return mapper(session).selectByQuery(query, new RowBounds(offset, limit)); + return mapper(session).selectByQuery(organizationUuid, query, new RowBounds(offset, limit)); } public int countByQuery(DbSession session, ComponentQuery query) { - if (query.getComponentIds() != null && query.getComponentIds().isEmpty()) { + return countByQueryImpl(session, null, query); + } + + public int countByQuery(DbSession session, String organizationUuid, ComponentQuery query) { + requireNonNull(organizationUuid, "organizationUuid can't be null"); + return countByQueryImpl(session, organizationUuid, query); + } + + private static int countByQueryImpl(DbSession session, @Nullable String organizationUuid, ComponentQuery query) { + Set componentIds = query.getComponentIds(); + if (componentIds != null && componentIds.isEmpty()) { return 0; } - return mapper(session).countByQuery(query); + return mapper(session).countByQuery(organizationUuid, query); } public List selectSubProjectsByComponentUuids(DbSession session, Collection keys) { @@ -342,5 +362,4 @@ public class ComponentDao implements Dao { private static ComponentMapper mapper(DbSession session) { return session.getMapper(ComponentMapper.class); } - } diff --git a/sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java b/sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java index 9c3bb96b7e5..2cddadffbd4 100644 --- a/sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java +++ b/sonar-db/src/main/java/org/sonar/db/component/ComponentMapper.java @@ -65,9 +65,9 @@ public interface ComponentMapper { */ int countComponentByOrganizationAndId(@Param("organizationUuid") String organizationUuid, @Param("componentId") long componentId); - List selectByQuery(@Param("query") ComponentQuery query, RowBounds rowBounds); + List selectByQuery(@Nullable @Param("organizationUuid") String organizationUuid, @Param("query") ComponentQuery query, RowBounds rowBounds); - int countByQuery(@Param("query") ComponentQuery query); + int countByQuery(@Nullable @Param("organizationUuid") String organizationUuid, @Param("query") ComponentQuery query); List selectDescendants(@Param("query") ComponentTreeQuery query, @Param("baseUuid") String baseUuid, @Param("baseUuidPath") String baseUuidPath); diff --git a/sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml b/sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml index a9e91ccca50..b8a97b3df49 100644 --- a/sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml +++ b/sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml @@ -251,6 +251,9 @@ where p.enabled=${_true} AND p.copy_component_uuid is null + + and p.organization_uuid=#{organizationUuid,jdbcType=VARCHAR} + AND p.qualifier in diff --git a/sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java b/sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java index 632d98a3d8f..646a54be31a 100644 --- a/sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java +++ b/sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java @@ -66,9 +66,10 @@ public class ComponentDaoTest { private static final String FILE_2_UUID = "file-2-uuid"; private static final String FILE_3_UUID = "file-3-uuid"; private static final String A_VIEW_UUID = "view-uuid"; + private static final ComponentQuery ALL_PROJECTS_COMPONENT_QUERY = ComponentQuery.builder().setQualifiers("TRK").build(); @Rule - public ExpectedException thrown = ExpectedException.none(); + public ExpectedException expectedException = ExpectedException.none(); @Rule public DbTester db = DbTester.create(System2.INSTANCE); @@ -144,7 +145,7 @@ public class ComponentDaoTest { @Test public void selectOrFailByUuid_fails_when_component_not_found() { - thrown.expect(RowNotFoundException.class); + expectedException.expect(RowNotFoundException.class); db.prepareDbUnit(getClass(), "shared.xml"); @@ -175,7 +176,7 @@ public class ComponentDaoTest { @Test public void selectOrFailByKey_fails_when_component_not_found() { - thrown.expect(RowNotFoundException.class); + expectedException.expect(RowNotFoundException.class); db.prepareDbUnit(getClass(), "shared.xml"); @@ -345,8 +346,8 @@ public class ComponentDaoTest { @Test public void fail_with_IAE_select_component_keys_by_qualifiers_on_empty_qualifier() throws Exception { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("Qualifiers cannot be empty"); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Qualifiers cannot be empty"); db.prepareDbUnit(getClass(), "shared.xml"); underTest.selectComponentsByQualifiers(dbSession, Collections.emptySet()); @@ -807,7 +808,23 @@ public class ComponentDaoTest { } @Test - public void select_by_query_with_paging_query_and_qualifiers() { + public void selectByQuery_with_organization_throws_NPE_of_organizationUuid_is_null() { + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("organizationUuid can't be null"); + + underTest.selectByQuery(dbSession, null, ALL_PROJECTS_COMPONENT_QUERY, 1, 1); + } + + @Test + public void countByQuery_with_organization_throws_NPE_of_organizationUuid_is_null() { + expectedException.expect(NullPointerException.class); + expectedException.expectMessage("organizationUuid can't be null"); + + underTest.countByQuery(dbSession, null, ALL_PROJECTS_COMPONENT_QUERY); + } + + @Test + public void selectByQuery_with_paging_query_and_qualifiers() { OrganizationDto organizationDto = db.organizations().insert(); componentDb.insertProjectAndSnapshot(newProjectDto(organizationDto).setName("aaaa-name")); componentDb.insertProjectAndSnapshot(newView(organizationDto)); @@ -827,7 +844,44 @@ public class ComponentDaoTest { } @Test - public void select_by_query_name_with_special_characters() { + public void selectByQuery_with_organization_filters_on_specified_organization() { + OrganizationDto organization1 = db.organizations().insert(); + OrganizationDto organization2 = db.organizations().insert(); + ComponentDto project1 = componentDb.insertProject(organization1); + ComponentDto project2 = componentDb.insertProject(organization2); + + assertThat(underTest.selectByQuery(dbSession, ALL_PROJECTS_COMPONENT_QUERY, 0, 2)) + .extracting(ComponentDto::uuid) + .containsOnly(project1.uuid(), project2.uuid()); + assertThat(underTest.selectByQuery(dbSession, organization1.getUuid(), ALL_PROJECTS_COMPONENT_QUERY, 0, 2)) + .extracting(ComponentDto::uuid) + .containsOnly(project1.uuid()); + assertThat(underTest.selectByQuery(dbSession, organization2.getUuid(), ALL_PROJECTS_COMPONENT_QUERY, 0, 2)) + .extracting(ComponentDto::uuid) + .containsOnly(project2.uuid()); + assertThat(underTest.selectByQuery(dbSession, "non existent organization uuid", ALL_PROJECTS_COMPONENT_QUERY, 0, 2)) + .isEmpty(); + } + + @Test + public void countByQuery_with_organization_filters_on_specified_organization() { + OrganizationDto organization1 = db.organizations().insert(); + OrganizationDto organization2 = db.organizations().insert(); + ComponentDto project1 = componentDb.insertProject(organization1); + ComponentDto project2 = componentDb.insertProject(organization2); + + assertThat(underTest.countByQuery(dbSession, ALL_PROJECTS_COMPONENT_QUERY)) + .isEqualTo(2); + assertThat(underTest.countByQuery(dbSession, organization1.getUuid(), ALL_PROJECTS_COMPONENT_QUERY)) + .isEqualTo(1); + assertThat(underTest.countByQuery(dbSession, organization2.getUuid(), ALL_PROJECTS_COMPONENT_QUERY)) + .isEqualTo(1); + assertThat(underTest.countByQuery(dbSession, "non existent organization uuid", ALL_PROJECTS_COMPONENT_QUERY)) + .isEqualTo(0); + } + + @Test + public void selectByQuery_name_with_special_characters() { componentDb.insertProjectAndSnapshot(newProjectDto(db.getDefaultOrganization()).setName("project-\\_%/-name")); ComponentQuery query = ComponentQuery.builder().setNameOrKeyQuery("-\\_%/-").setQualifiers(Qualifiers.PROJECT).build(); @@ -838,7 +892,7 @@ public class ComponentDaoTest { } @Test - public void select_by_query_key_with_special_characters() { + public void selectByQuery_key_with_special_characters() { componentDb.insertProjectAndSnapshot(newProjectDto(db.organizations().insert()).setKey("project-_%-key")); ComponentQuery query = ComponentQuery.builder().setNameOrKeyQuery("project-_%-key").setQualifiers(Qualifiers.PROJECT).build(); @@ -849,7 +903,7 @@ public class ComponentDaoTest { } @Test - public void select_by_query_filter_on_language() { + public void selectByQuery_filter_on_language() { componentDb.insertComponent(newProjectDto(db.getDefaultOrganization()).setKey("java-project-key").setLanguage("java")); componentDb.insertComponent(newProjectDto(db.getDefaultOrganization()).setKey("cpp-project-key").setLanguage("cpp")); @@ -861,7 +915,7 @@ public class ComponentDaoTest { } @Test - public void select_by_query_on_empty_list_of_component_id() { + public void selectByQuery_on_empty_list_of_component_id() { ComponentQuery dbQuery = ComponentQuery.builder().setQualifiers(Qualifiers.PROJECT).setComponentIds(emptySet()).build(); List result = underTest.selectByQuery(dbSession, dbQuery, 0, 10); int count = underTest.countByQuery(dbSession, dbQuery); @@ -871,7 +925,7 @@ public class ComponentDaoTest { } @Test - public void select_by_query_on_component_ids() { + public void selectByQuery_on_component_ids() { OrganizationDto organizationDto = db.organizations().insert(); ComponentDto sonarqube = componentDb.insertComponent(newProjectDto(organizationDto)); ComponentDto jdk8 = componentDb.insertComponent(newProjectDto(organizationDto)); diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/component/SearchWsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/component/SearchWsRequest.java index 80d5acb65cb..00910b0366d 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/component/SearchWsRequest.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/component/SearchWsRequest.java @@ -26,12 +26,22 @@ import javax.annotation.Nullable; import static java.util.Objects.requireNonNull; public class SearchWsRequest { + private String organization; private List qualifiers; private Integer page; private Integer pageSize; private String query; private String language; + public String getOrganization() { + return organization; + } + + public SearchWsRequest setOrganization(String organization) { + this.organization = organization; + return this; + } + public List getQualifiers() { return qualifiers; }