]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10813 Define project branches in an application
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Wed, 13 Jun 2018 16:49:50 +0000 (18:49 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 29 Jun 2018 07:10:15 +0000 (09:10 +0200)
16 files changed:
server/sonar-server/src/main/java/org/sonar/server/branch/ws/DeleteAction.java
server/sonar-server/src/main/java/org/sonar/server/component/ws/TreeAction.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
server/sonar-server/src/main/java/org/sonar/server/measure/ws/ComponentTreeAction.java
server/sonar-server/src/main/java/org/sonar/server/project/ProjectLifeCycleListener.java
server/sonar-server/src/main/java/org/sonar/server/project/ProjectLifeCycleListeners.java
server/sonar-server/src/main/java/org/sonar/server/project/ProjectLifeCycleListenersImpl.java
server/sonar-server/src/test/java/org/sonar/server/branch/ws/DeleteActionTest.java
server/sonar-server/src/test/java/org/sonar/server/component/ws/TreeActionTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionComponentsTest.java
server/sonar-server/src/test/java/org/sonar/server/measure/ws/ComponentTreeActionTest.java
server/sonar-server/src/test/java/org/sonar/server/project/ProjectLifeCycleListenersImplTest.java
server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/BaseRequest.java
sonar-ws/src/test/java/org/sonarqube/ws/client/BaseRequestTest.java

index cde6921b059603392308c3752fc9c40c1b0b07b2..1da2eb87f33eb6705bab82751899f5922cf886f8 100644 (file)
@@ -30,13 +30,16 @@ import org.sonar.db.component.BranchDto;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.server.component.ComponentCleanerService;
 import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.project.ProjectLifeCycleListeners;
 import org.sonar.server.user.UserSession;
 
+import static java.util.Collections.singleton;
 import static org.sonar.server.branch.ws.BranchesWs.addBranchParam;
 import static org.sonar.server.branch.ws.BranchesWs.addProjectParam;
 import static org.sonar.server.branch.ws.ProjectBranchesParameters.ACTION_DELETE;
 import static org.sonar.server.branch.ws.ProjectBranchesParameters.PARAM_BRANCH;
 import static org.sonar.server.branch.ws.ProjectBranchesParameters.PARAM_PROJECT;
+import static org.sonar.server.project.Project.from;
 import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
 
 public class DeleteAction implements BranchWsAction {
@@ -44,12 +47,15 @@ public class DeleteAction implements BranchWsAction {
   private final UserSession userSession;
   private final ComponentCleanerService componentCleanerService;
   private final ComponentFinder componentFinder;
+  private final ProjectLifeCycleListeners projectLifeCycleListeners;
 
-  public DeleteAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, ComponentCleanerService componentCleanerService) {
+  public DeleteAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, ComponentCleanerService componentCleanerService,
+    ProjectLifeCycleListeners projectLifeCycleListeners) {
     this.dbClient = dbClient;
     this.componentFinder = componentFinder;
     this.userSession = userSession;
     this.componentCleanerService = componentCleanerService;
+    this.projectLifeCycleListeners = projectLifeCycleListeners;
   }
 
   @Override
@@ -84,6 +90,7 @@ public class DeleteAction implements BranchWsAction {
       }
       ComponentDto branchComponent = componentFinder.getByKeyAndBranch(dbSession, projectKey, branchKey);
       componentCleanerService.deleteBranch(dbSession, branchComponent);
+      projectLifeCycleListeners.onProjectBranchesDeleted(singleton(from(project)));
       response.noContent();
     }
   }
index ef86ba3c9c77a8f48fb5bc2b9e1f40238fbc164f..558ac7d492a11bf2a08eedaa42892464c8734485 100644 (file)
@@ -67,8 +67,8 @@ import static org.sonar.server.component.ws.ComponentDtoToWsComponent.componentD
 import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001;
 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
 import static org.sonar.server.ws.KeyExamples.KEY_PULL_REQUEST_EXAMPLE_001;
-import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
 import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter;
+import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
 import static org.sonar.server.ws.WsUtils.checkRequest;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 import static org.sonarqube.ws.client.component.ComponentsWsParameters.ACTION_TREE;
@@ -252,7 +252,7 @@ public class TreeAction implements ComponentsWsAction {
     ComponentDto referenceComponent = referenceComponentsByUuid.get(component.getCopyResourceUuid());
     if (referenceComponent != null) {
       wsComponent.setRefId(referenceComponent.uuid());
-      wsComponent.setRefKey(referenceComponent.getDbKey());
+      wsComponent.setRefKey(referenceComponent.getKey());
     }
 
     return wsComponent;
index 29e881db26ba1ef08f90bb9834478f238c3770dc..7e5c5c1ca5126f8edf36482b57839472de71e563 100644 (file)
@@ -316,6 +316,7 @@ public class IssueIndex {
     if (onApplicationBranch) {
       filters.put("__view", createViewFilter(singletonList(query.branchUuid())));
     } else {
+      filters.put("__is_main_branch", createTermFilter(IssueIndexDefinition.FIELD_ISSUE_IS_MAIN_BRANCH, Boolean.toString(true)));
       filters.put("__view", createViewFilter(viewUuids));
     }
   }
@@ -328,7 +329,7 @@ public class IssueIndex {
 
     BoolQueryBuilder viewsFilter = boolQuery();
     for (String viewUuid : viewUuids) {
-      viewsFilter.should(QueryBuilders.termsLookupQuery(IssueIndexDefinition.FIELD_ISSUE_PROJECT_UUID,
+      viewsFilter.should(QueryBuilders.termsLookupQuery(IssueIndexDefinition.FIELD_ISSUE_BRANCH_UUID,
         new TermsLookup(
           ViewIndexDefinition.INDEX_TYPE_VIEW.getIndex(),
           ViewIndexDefinition.INDEX_TYPE_VIEW.getType(),
index 3adddc099656e1c745783e2077d390ebd119669c..2f1ffe9ac6e12c767641abcd14aca40fa3ec9088 100644 (file)
@@ -111,8 +111,8 @@ import static org.sonar.server.measure.ws.SnapshotDtoToWsPeriods.snapshotToWsPer
 import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001;
 import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
 import static org.sonar.server.ws.KeyExamples.KEY_PULL_REQUEST_EXAMPLE_001;
-import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
 import static org.sonar.server.ws.WsParameterBuilder.createQualifiersParameter;
+import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
 import static org.sonar.server.ws.WsUtils.checkRequest;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
 
@@ -388,7 +388,7 @@ public class ComponentTreeAction implements MeasuresWsAction {
     ComponentDto referenceComponent = referenceComponentsByUuid.get(component.getCopyResourceUuid());
     if (referenceComponent != null) {
       wsComponent.setRefId(referenceComponent.uuid());
-      wsComponent.setRefKey(referenceComponent.getDbKey());
+      wsComponent.setRefKey(referenceComponent.getKey());
     }
     Measures.Measure.Builder measureBuilder = Measures.Measure.newBuilder();
     for (Map.Entry<MetricDto, ComponentTreeData.Measure> entry : measures.entrySet()) {
index 9b3c092b3db3fcc6026fb57d7f49127c521ff200..05630721431a5ea924e0b7610ddc7043f0c41124 100644 (file)
@@ -29,6 +29,11 @@ public interface ProjectLifeCycleListener {
    */
   void onProjectsDeleted(Set<Project> projects);
 
+  /**
+   * This method is called after the specified projects have been deleted.
+   */
+  void onProjectBranchesDeleted(Set<Project> projects);
+
   /**
    * This method is called after the specified projects' keys have been modified.
    */
index 9b2c7b76d5999ca387d45d097251115b1a685d8d..86158036742a29ffdb0a9feb7ce98ac65ecd5b0c 100644 (file)
@@ -32,6 +32,16 @@ public interface ProjectLifeCycleListeners {
    */
   void onProjectsDeleted(Set<Project> projects);
 
+  /**
+   * This method is called after the specified project branches have been deleted and will call method
+   * {@link ProjectLifeCycleListener#onProjectBranchesDeleted(Set)} of all known
+   * {@link ProjectLifeCycleListener} implementations.
+   * <p>
+   * This method ensures all {@link ProjectLifeCycleListener} implementations are called, even if one or more of
+   * them fail with an exception.
+   */
+  void onProjectBranchesDeleted(Set<Project> projects);
+
   /**
    * This method is called after the specified project's key has been changed and will call method
    * {@link ProjectLifeCycleListener#onProjectsRekeyed(Set) onProjectsRekeyed(Set)} of all known
index 0ca49891b2ee1f58af549196cc30ab13f39fc6cd..f2665ea67a55bf47f64ffa20a7aa4534cc8c4beb 100644 (file)
@@ -57,6 +57,17 @@ public class ProjectLifeCycleListenersImpl implements ProjectLifeCycleListeners
       .forEach(safelyCallListener(listener -> listener.onProjectsDeleted(projects)));
   }
 
+  @Override
+  public void onProjectBranchesDeleted(Set<Project> projects) {
+    checkNotNull(projects, "projects can't be null");
+    if (projects.isEmpty()) {
+      return;
+    }
+
+    Arrays.stream(listeners)
+      .forEach(safelyCallListener(listener -> listener.onProjectBranchesDeleted(projects)));
+  }
+
   @Override
   public void onProjectsRekeyed(Set<RekeyedProject> rekeyedProjects) {
     checkNotNull(rekeyedProjects, "rekeyedProjects can't be null");
index 691087c4690b5d31f269e87ff6528eff03d5e361..7797be99415abd3696aec04a48550770b7b892f9 100644 (file)
@@ -34,9 +34,12 @@ import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.component.TestComponentFinder;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.project.Project;
+import org.sonar.server.project.ProjectLifeCycleListeners;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.WsActionTester;
 
+import static java.util.Collections.singleton;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
@@ -51,20 +54,26 @@ public class DeleteActionTest {
 
   private ComponentCleanerService componentCleanerService = mock(ComponentCleanerService.class);
   private ComponentFinder componentFinder = TestComponentFinder.from(db);
+  private ProjectLifeCycleListeners projectLifeCycleListeners = mock(ProjectLifeCycleListeners.class);
 
   @Rule
   public UserSessionRule userSession = UserSessionRule.standalone();
 
-  public WsActionTester tester = new WsActionTester(new DeleteAction(db.getDbClient(), componentFinder, userSession, componentCleanerService));
+  public WsActionTester tester = new WsActionTester(new DeleteAction(db.getDbClient(), componentFinder, userSession, componentCleanerService, projectLifeCycleListeners));
 
   @Test
-  public void test_definition() {
-    WebService.Action definition = tester.getDef();
-    assertThat(definition.key()).isEqualTo("delete");
-    assertThat(definition.isPost()).isTrue();
-    assertThat(definition.isInternal()).isFalse();
-    assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("project", "branch");
-    assertThat(definition.since()).isEqualTo("6.6");
+  public void delete_branch() {
+    ComponentDto project = db.components().insertMainBranch();
+    ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch1"));
+    userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
+
+    tester.newRequest()
+      .setParam("project", project.getKey())
+      .setParam("branch", "branch1")
+      .execute();
+
+    verifyDeletedKey(branch.getDbKey());
+    verify(projectLifeCycleListeners).onProjectBranchesDeleted(singleton(Project.from(project)));
   }
 
   @Test
@@ -139,16 +148,13 @@ public class DeleteActionTest {
   }
 
   @Test
-  public void delete_branch() {
-    ComponentDto project = db.components().insertMainBranch();
-    ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch1"));
-    userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
-
-    tester.newRequest()
-      .setParam("project", project.getKey())
-      .setParam("branch", "branch1")
-      .execute();
-    verifyDeletedKey(branch.getDbKey());
+  public void definition() {
+    WebService.Action definition = tester.getDef();
+    assertThat(definition.key()).isEqualTo("delete");
+    assertThat(definition.isPost()).isTrue();
+    assertThat(definition.isInternal()).isFalse();
+    assertThat(definition.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("project", "branch");
+    assertThat(definition.since()).isEqualTo("6.6");
   }
 
   private void verifyDeletedKey(String key) {
index 4452efaa621b741f6fea08e150aa5b4ae4031841..d3c21cd19b02c1a8d4092efb9487e43a302d2431 100644 (file)
@@ -40,7 +40,6 @@ import org.sonar.api.utils.System2;
 import org.sonar.api.web.UserRole;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbTester;
-import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ComponentTesting;
 import org.sonar.db.component.ResourceTypesRule;
@@ -53,11 +52,13 @@ import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.WsActionTester;
 import org.sonar.test.JsonAssert;
 import org.sonarqube.ws.Components;
+import org.sonarqube.ws.Components.Component;
 import org.sonarqube.ws.Components.TreeWsResponse;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 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.FILE;
 import static org.sonar.api.resources.Qualifiers.PROJECT;
 import static org.sonar.api.resources.Qualifiers.UNIT_TEST_FILE;
@@ -87,7 +88,6 @@ public class TreeActionTest {
   private ResourceTypesRule resourceTypes = new ResourceTypesRule()
     .setRootQualifiers(PROJECT)
     .setLeavesQualifiers(FILE, UNIT_TEST_FILE);
-  private ComponentDbTester componentDb = new ComponentDbTester(db);
   private DbClient dbClient = db.getDbClient();
 
   private WsActionTester ws = new WsActionTester(new TreeAction(dbClient, new ComponentFinder(dbClient, resourceTypes), resourceTypes, userSession, Mockito.mock(I18n.class)));
@@ -142,16 +142,16 @@ public class TreeActionTest {
   @Test
   public void return_children() {
     ComponentDto project = newPrivateProjectDto(db.organizations().insert(), "project-uuid");
-    componentDb.insertProjectAndSnapshot(project);
+    db.components().insertProjectAndSnapshot(project);
     ComponentDto module = newModuleDto("module-uuid-1", project);
-    componentDb.insertComponent(module);
-    componentDb.insertComponent(newFileDto(project, 1));
+    db.components().insertComponent(module);
+    db.components().insertComponent(newFileDto(project, 1));
     for (int i = 2; i <= 9; i++) {
-      componentDb.insertComponent(newFileDto(module, i));
+      db.components().insertComponent(newFileDto(module, i));
     }
     ComponentDto directory = newDirectory(module, "directory-path-1");
-    componentDb.insertComponent(directory);
-    componentDb.insertComponent(newFileDto(module, directory, 10));
+    db.components().insertComponent(directory);
+    db.components().insertComponent(newFileDto(module, directory, 10));
     db.commit();
     logInWithBrowsePermission(project);
 
@@ -172,16 +172,16 @@ public class TreeActionTest {
   @Test
   public void return_descendants() {
     ComponentDto project = newPrivateProjectDto(db.getDefaultOrganization(), "project-uuid");
-    SnapshotDto projectSnapshot = componentDb.insertProjectAndSnapshot(project);
+    SnapshotDto projectSnapshot = db.components().insertProjectAndSnapshot(project);
     ComponentDto module = newModuleDto("module-uuid-1", project);
-    componentDb.insertComponent(module);
-    componentDb.insertComponent(newFileDto(project, 10));
+    db.components().insertComponent(module);
+    db.components().insertComponent(newFileDto(project, 10));
     for (int i = 2; i <= 9; i++) {
-      componentDb.insertComponent(newFileDto(module, i));
+      db.components().insertComponent(newFileDto(module, i));
     }
     ComponentDto directory = newDirectory(module, "directory-path-1");
-    componentDb.insertComponent(directory);
-    componentDb.insertComponent(newFileDto(module, directory, 1));
+    db.components().insertComponent(directory);
+    db.components().insertComponent(newFileDto(module, directory, 1));
     db.commit();
     logInWithBrowsePermission(project);
 
@@ -202,10 +202,10 @@ public class TreeActionTest {
   @Test
   public void filter_descendants_by_qualifier() {
     ComponentDto project = newPrivateProjectDto(db.organizations().insert(), "project-uuid");
-    componentDb.insertProjectAndSnapshot(project);
-    componentDb.insertComponent(newFileDto(project, 1));
-    componentDb.insertComponent(newFileDto(project, 2));
-    componentDb.insertComponent(newModuleDto("module-uuid-1", project));
+    db.components().insertProjectAndSnapshot(project);
+    db.components().insertComponent(newFileDto(project, 1));
+    db.components().insertComponent(newFileDto(project, 2));
+    db.components().insertComponent(newModuleDto("module-uuid-1", project));
     db.commit();
     logInWithBrowsePermission(project);
 
@@ -220,14 +220,14 @@ public class TreeActionTest {
   @Test
   public void return_leaves() {
     ComponentDto project = newPrivateProjectDto(db.getDefaultOrganization(), "project-uuid");
-    componentDb.insertProjectAndSnapshot(project);
+    db.components().insertProjectAndSnapshot(project);
     ComponentDto module = newModuleDto("module-uuid-1", project);
-    componentDb.insertComponent(module);
-    componentDb.insertComponent(newFileDto(project, 1));
-    componentDb.insertComponent(newFileDto(module, 2));
+    db.components().insertComponent(module);
+    db.components().insertComponent(newFileDto(project, 1));
+    db.components().insertComponent(newFileDto(module, 2));
     ComponentDto directory = newDirectory(project, "directory-path-1");
-    componentDb.insertComponent(directory);
-    componentDb.insertComponent(newFileDto(module, directory, 3));
+    db.components().insertComponent(directory);
+    db.components().insertComponent(newFileDto(module, directory, 3));
     db.commit();
     logInWithBrowsePermission(project);
 
@@ -244,12 +244,12 @@ public class TreeActionTest {
   @Test
   public void sort_descendants_by_qualifier() {
     ComponentDto project = newPrivateProjectDto(db.organizations().insert(), "project-uuid");
-    componentDb.insertProjectAndSnapshot(project);
-    componentDb.insertComponent(newFileDto(project, 1));
-    componentDb.insertComponent(newFileDto(project, 2));
+    db.components().insertProjectAndSnapshot(project);
+    db.components().insertComponent(newFileDto(project, 1));
+    db.components().insertComponent(newFileDto(project, 2));
     ComponentDto module = newModuleDto("module-uuid-1", project);
-    componentDb.insertComponent(module);
-    componentDb.insertComponent(newDirectory(project, "path/directory/", "directory-uuid-1"));
+    db.components().insertComponent(module);
+    db.components().insertComponent(newDirectory(project, "path/directory/", "directory-uuid-1"));
     db.commit();
     logInWithBrowsePermission(project);
 
@@ -262,14 +262,14 @@ public class TreeActionTest {
   }
 
   @Test
-  public void return_children_of_a_view() {
+  public void project_reference_from_portfolio() {
     OrganizationDto organizationDto = db.organizations().insert();
     ComponentDto view = newView(organizationDto, "view-uuid");
-    componentDb.insertViewAndSnapshot(view);
+    db.components().insertViewAndSnapshot(view);
     ComponentDto project = newPrivateProjectDto(organizationDto, "project-uuid-1").setName("project-name").setDbKey("project-key-1");
-    componentDb.insertProjectAndSnapshot(project);
-    componentDb.insertComponent(newProjectCopy("project-uuid-1-copy", project, view));
-    componentDb.insertComponent(newSubView(view, "sub-view-uuid", "sub-view-key").setName("sub-view-name"));
+    db.components().insertProjectAndSnapshot(project);
+    db.components().insertComponent(newProjectCopy("project-uuid-1-copy", project, view));
+    db.components().insertComponent(newSubView(view, "sub-view-uuid", "sub-view-key").setName("sub-view-name"));
     db.commit();
     userSession.logIn()
       .registerComponents(view, project);
@@ -284,9 +284,32 @@ public class TreeActionTest {
     assertThat(response.getComponentsList()).extracting("refKey").containsExactly("project-key-1", "");
   }
 
+  @Test
+  public void project_branch_reference_from_application_branch() {
+    ComponentDto application = db.components().insertMainBranch(c -> c.setQualifier(APP).setDbKey("app-key"));
+    ComponentDto applicationBranch = db.components().insertProjectBranch(application, a -> a.setKey("app-branch"));
+    ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey("project-key"));
+    ComponentDto projectBranch = db.components().insertProjectBranch(project, b -> b.setKey("project-branch"));
+    ComponentDto techProjectBranch = db.components().insertComponent(newProjectCopy(projectBranch, applicationBranch)
+      .setDbKey(applicationBranch.getKey() + applicationBranch.getBranch() + projectBranch.getDbKey()));
+    logInWithBrowsePermission(application);
+
+    TreeWsResponse result = ws.newRequest()
+      .setParam(MeasuresWsParameters.PARAM_COMPONENT, applicationBranch.getKey())
+      .setParam(MeasuresWsParameters.PARAM_BRANCH, applicationBranch.getBranch())
+      .executeProtobuf(TreeWsResponse.class);
+
+    assertThat(result.getBaseComponent())
+      .extracting(Component::getKey, Component::getBranch)
+      .containsExactlyInAnyOrder(applicationBranch.getKey(), applicationBranch.getBranch());
+    assertThat(result.getComponentsList())
+      .extracting(Component::getKey, Component::getBranch, Component::getRefId, Component::getRefKey)
+      .containsExactlyInAnyOrder(tuple(techProjectBranch.getKey(), projectBranch.getBranch(), projectBranch.uuid(), project.getKey()));
+  }
+
   @Test
   public void response_is_empty_on_provisioned_projects() {
-    ComponentDto project = componentDb.insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), "project-uuid"));
+    ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), "project-uuid"));
     logInWithBrowsePermission(project);
 
     TreeWsResponse response = ws.newRequest()
@@ -302,10 +325,10 @@ public class TreeActionTest {
   @Test
   public void return_projects_composing_a_view() {
     ComponentDto project = newPrivateProjectDto(db.organizations().insert(), "project-uuid");
-    componentDb.insertProjectAndSnapshot(project);
+    db.components().insertProjectAndSnapshot(project);
     ComponentDto view = newView(db.getDefaultOrganization(), "view-uuid");
-    componentDb.insertViewAndSnapshot(view);
-    componentDb.insertComponent(newProjectCopy("project-copy-uuid", project, view));
+    db.components().insertViewAndSnapshot(view);
+    db.components().insertComponent(newProjectCopy("project-copy-uuid", project, view));
     userSession.logIn()
       .registerComponents(project, view);
 
@@ -332,9 +355,9 @@ public class TreeActionTest {
       .setParam(PARAM_BRANCH, branchKey)
       .executeProtobuf(TreeWsResponse.class);
 
-    assertThat(response.getBaseComponent()).extracting(Components.Component::getKey, Components.Component::getBranch)
+    assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getBranch)
       .containsExactlyInAnyOrder(module.getKey(), branchKey);
-    assertThat(response.getComponentsList()).extracting(Components.Component::getKey, Components.Component::getBranch)
+    assertThat(response.getComponentsList()).extracting(Component::getKey, Component::getBranch)
       .containsExactlyInAnyOrder(
         tuple(directory.getKey(), branchKey),
         tuple(file.getKey(), branchKey));
@@ -355,9 +378,9 @@ public class TreeActionTest {
       .setParam(PARAM_PULL_REQUEST, pullRequestId)
       .executeProtobuf(TreeWsResponse.class);
 
-    assertThat(response.getBaseComponent()).extracting(Components.Component::getKey, Components.Component::getPullRequest)
+    assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getPullRequest)
       .containsExactlyInAnyOrder(module.getKey(), pullRequestId);
-    assertThat(response.getComponentsList()).extracting(Components.Component::getKey, Components.Component::getPullRequest)
+    assertThat(response.getComponentsList()).extracting(Component::getKey, Component::getPullRequest)
       .containsExactlyInAnyOrder(
         tuple(directory.getKey(), pullRequestId),
         tuple(file.getKey(), pullRequestId));
@@ -393,7 +416,7 @@ public class TreeActionTest {
 
   @Test
   public void fail_when_not_enough_privileges() {
-    ComponentDto project = componentDb.insertComponent(newPrivateProjectDto(db.organizations().insert(), "project-uuid"));
+    ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.organizations().insert(), "project-uuid"));
     userSession.logIn()
       .addProjectPermission(UserRole.CODEVIEWER, project);
     db.commit();
@@ -409,7 +432,7 @@ public class TreeActionTest {
   public void fail_when_page_size_above_500() {
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("'ps' value (501) must be less than 500");
-    componentDb.insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), "project-uuid"));
+    db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), "project-uuid"));
     db.commit();
 
     ws.newRequest()
@@ -422,7 +445,7 @@ public class TreeActionTest {
   public void fail_when_search_query_has_less_than_3_characters() {
     expectedException.expect(IllegalArgumentException.class);
     expectedException.expectMessage("'q' length (2) is shorter than the minimum authorized (3)");
-    componentDb.insertComponent(newPrivateProjectDto(db.organizations().insert(), "project-uuid"));
+    db.components().insertComponent(newPrivateProjectDto(db.organizations().insert(), "project-uuid"));
     db.commit();
 
     ws.newRequest()
@@ -434,7 +457,7 @@ public class TreeActionTest {
   @Test
   public void fail_when_sort_is_unknown() {
     expectedException.expect(IllegalArgumentException.class);
-    componentDb.insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), "project-uuid"));
+    db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization(), "project-uuid"));
     db.commit();
 
     ws.newRequest()
@@ -446,7 +469,7 @@ public class TreeActionTest {
   @Test
   public void fail_when_strategy_is_unknown() {
     expectedException.expect(IllegalArgumentException.class);
-    componentDb.insertComponent(newPrivateProjectDto(db.organizations().insert(), "project-uuid"));
+    db.components().insertComponent(newPrivateProjectDto(db.organizations().insert(), "project-uuid"));
     db.commit();
 
     ws.newRequest()
@@ -466,8 +489,8 @@ public class TreeActionTest {
 
   @Test
   public void fail_when_base_component_is_removed() {
-    ComponentDto project = componentDb.insertComponent(newPrivateProjectDto(db.getDefaultOrganization()));
-    componentDb.insertComponent(ComponentTesting.newFileDto(project).setDbKey("file-key").setEnabled(false));
+    ComponentDto project = db.components().insertComponent(newPrivateProjectDto(db.getDefaultOrganization()));
+    db.components().insertComponent(ComponentTesting.newFileDto(project).setDbKey("file-key").setEnabled(false));
     logInWithBrowsePermission(project);
 
     expectedException.expect(NotFoundException.class);
@@ -532,7 +555,7 @@ public class TreeActionTest {
     ComponentDto project = newPrivateProjectDto(organizationDto, "MY_PROJECT_ID")
       .setDbKey("MY_PROJECT_KEY")
       .setName("Project Name");
-    componentDb.insertProjectAndSnapshot(project);
+    db.components().insertProjectAndSnapshot(project);
     Date now = new Date();
     JsonParser jsonParser = new JsonParser();
     JsonElement jsonTree = jsonParser.parse(IOUtils.toString(getClass().getResource("tree-example.json"), UTF_8));
@@ -540,7 +563,7 @@ public class TreeActionTest {
     for (JsonElement componentAsJsonElement : components) {
       JsonObject componentAsJsonObject = componentAsJsonElement.getAsJsonObject();
       String uuid = getJsonField(componentAsJsonObject, "id");
-      componentDb.insertComponent(newChildComponent(uuid, project, project)
+      db.components().insertComponent(newChildComponent(uuid, project, project)
         .setDbKey(getJsonField(componentAsJsonObject, "key"))
         .setName(getJsonField(componentAsJsonObject, "name"))
         .setLanguage(getJsonField(componentAsJsonObject, "language"))
index b02ac50d17ded7434556ecd5d490e30f3c9b83de..db95f8711dcbd7367046b44d956029900e5d63e1 100644 (file)
@@ -306,6 +306,25 @@ public class IssueIndexTest {
     assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(view1)));
   }
 
+  @Test
+  public void do_not_return_issues_from_project_branch_when_filtering_by_portfolios() {
+    ComponentDto portfolio = db.components().insertPrivateApplication(db.getDefaultOrganization());
+    ComponentDto project = db.components().insertMainBranch();
+    ComponentDto projectBranch = db.components().insertProjectBranch(project);
+    ComponentDto fileOnProjectBranch = db.components().insertComponent(newFileDto(projectBranch));
+    indexView(portfolio.uuid(), singletonList(project.uuid()));
+
+    IssueDoc issueOnProject = newDoc(project);
+    IssueDoc issueOnProjectBranch = newDoc(projectBranch);
+    IssueDoc issueOnFileOnProjectBranch = newDoc(fileOnProjectBranch);
+    indexIssues(issueOnProject, issueOnFileOnProjectBranch, issueOnProjectBranch);
+
+    assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(portfolio.uuid())), issueOnProject.key());
+    assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(portfolio.uuid())).projectUuids(singletonList(project.uuid())),
+      issueOnProject.key());
+    assertThatSearchReturnsEmpty(IssueQuery.builder().viewUuids(singletonList(portfolio.uuid())).projectUuids(singletonList(projectBranch.uuid())));
+  }
+
   @Test
   public void filter_one_issue_by_project_and_branch() {
     ComponentDto project = db.components().insertPrivateProject();
@@ -379,20 +398,19 @@ public class IssueIndexTest {
   }
 
   @Test
-  public void filter_by_application() {
+  public void filter_by_main_application() {
     ComponentDto application1 = db.components().insertPrivateApplication(db.getDefaultOrganization());
     ComponentDto application2 = db.components().insertPrivateApplication(db.getDefaultOrganization());
     ComponentDto project1 = db.components().insertPrivateProject();
     ComponentDto file = db.components().insertComponent(newFileDto(project1));
     ComponentDto project2 = db.components().insertPrivateProject();
+    indexView(application1.uuid(), singletonList(project1.uuid()));
+    indexView(application2.uuid(), singletonList(project2.uuid()));
 
     IssueDoc issueOnProject1 = newDoc(project1);
     IssueDoc issueOnFile = newDoc(file);
     IssueDoc issueOnProject2 = newDoc(project2);
-
     indexIssues(issueOnProject1, issueOnFile, issueOnProject2);
-    indexView(application1.uuid(), singletonList(project1.uuid()));
-    indexView(application2.uuid(), singletonList(project2.uuid()));
 
     assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(application1.uuid())), issueOnProject1.key(), issueOnFile.key());
     assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(application2.uuid())), issueOnProject2.key());
@@ -404,24 +422,23 @@ public class IssueIndexTest {
   }
 
   @Test
-  public void filter_by_application_and_branch() {
+  public void filter_by_application_branch() {
     ComponentDto application = db.components().insertMainBranch(c -> c.setQualifier(APP));
     ComponentDto branch1 = db.components().insertProjectBranch(application);
     ComponentDto branch2 = db.components().insertProjectBranch(application);
     ComponentDto project1 = db.components().insertPrivateProject();
     ComponentDto file = db.components().insertComponent(newFileDto(project1));
     ComponentDto project2 = db.components().insertPrivateProject();
+    indexView(branch1.uuid(), singletonList(project1.uuid()));
+    indexView(branch2.uuid(), singletonList(project2.uuid()));
 
     IssueDoc issueOnProject1 = newDoc(project1);
     IssueDoc issueOnFile = newDoc(file);
     IssueDoc issueOnProject2 = newDoc(project2);
     indexIssues(issueOnProject1, issueOnFile, issueOnProject2);
 
-    indexView(branch1.uuid(), singletonList(project1.uuid()));
-    indexView(branch2.uuid(), singletonList(project2.uuid()));
-
-    assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(branch1.uuid())).branchUuid(branch1.uuid()).mainBranch(false), issueOnProject1.key(),
-      issueOnFile.key());
+    assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(branch1.uuid())).branchUuid(branch1.uuid()).mainBranch(false),
+      issueOnProject1.key(), issueOnFile.key());
     assertThatSearchReturnsOnly(
       IssueQuery.builder().viewUuids(singletonList(branch1.uuid())).projectUuids(singletonList(project1.uuid())).branchUuid(branch1.uuid()).mainBranch(false),
       issueOnProject1.key(), issueOnFile.key());
@@ -430,6 +447,39 @@ public class IssueIndexTest {
     assertThatSearchReturnsEmpty(IssueQuery.builder().branchUuid("unknown"));
   }
 
+  @Test
+  public void filter_by_application_branch_having_project_branches() {
+    ComponentDto application = db.components().insertMainBranch(c -> c.setQualifier(APP).setDbKey("app"));
+    ComponentDto applicationBranch1 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch1"));
+    ComponentDto applicationBranch2 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch2"));
+    ComponentDto project1 = db.components().insertPrivateProject(p -> p.setDbKey("prj1"));
+    ComponentDto project1Branch1 = db.components().insertProjectBranch(project1);
+    ComponentDto fileOnProject1Branch1 = db.components().insertComponent(newFileDto(project1Branch1));
+    ComponentDto project1Branch2 = db.components().insertProjectBranch(project1);
+    ComponentDto project2 = db.components().insertPrivateProject(p -> p.setDbKey("prj2"));
+    indexView(applicationBranch1.uuid(), asList(project1Branch1.uuid(), project2.uuid()));
+    indexView(applicationBranch2.uuid(), singletonList(project1Branch2.uuid()));
+
+    IssueDoc issueOnProject1 = newDoc(project1);
+    IssueDoc issueOnProject1Branch1 = newDoc(project1Branch1);
+    IssueDoc issueOnFileOnProject1Branch1 = newDoc(fileOnProject1Branch1);
+    IssueDoc issueOnProject1Branch2 = newDoc(project1Branch2);
+    IssueDoc issueOnProject2 = newDoc(project2);
+    indexIssues(issueOnProject1, issueOnProject1Branch1, issueOnFileOnProject1Branch1, issueOnProject1Branch2, issueOnProject2);
+
+    assertThatSearchReturnsOnly(IssueQuery.builder().viewUuids(singletonList(applicationBranch1.uuid())).branchUuid(applicationBranch1.uuid()).mainBranch(false),
+      issueOnProject1Branch1.key(), issueOnFileOnProject1Branch1.key(), issueOnProject2.key());
+    assertThatSearchReturnsOnly(
+      IssueQuery.builder().viewUuids(singletonList(applicationBranch1.uuid())).projectUuids(singletonList(project1.uuid())).branchUuid(applicationBranch1.uuid()).mainBranch(false),
+      issueOnProject1Branch1.key(), issueOnFileOnProject1Branch1.key());
+    assertThatSearchReturnsOnly(
+      IssueQuery.builder().viewUuids(singletonList(applicationBranch1.uuid())).fileUuids(singletonList(fileOnProject1Branch1.uuid())).branchUuid(applicationBranch1.uuid())
+        .mainBranch(false),
+      issueOnFileOnProject1Branch1.key());
+    assertThatSearchReturnsEmpty(
+      IssueQuery.builder().viewUuids(singletonList(applicationBranch1.uuid())).projectUuids(singletonList("unknown")).branchUuid(applicationBranch1.uuid()).mainBranch(false));
+  }
+
   @Test
   public void filter_by_created_after_by_projects() {
     Date now = new Date();
index d5298d243693c89dd32677fc25790566891c81a0..2a601ec3767b428275fde6f8acdd39d6dd0dfbac 100644 (file)
@@ -78,6 +78,7 @@ import static org.sonar.db.issue.IssueTesting.newIssue;
 import static org.sonarqube.ws.client.component.ComponentsWsParameters.PARAM_BRANCH;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_COMPONENT_KEYS;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_KEYS;
+import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PROJECT_UUIDS;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_PULL_REQUEST;
 import static org.sonarqube.ws.client.issue.IssuesWsParameters.PARAM_SINCE_LEAK_PERIOD;
 
@@ -688,26 +689,49 @@ public class SearchActionComponentsTest {
 
   @Test
   public void search_by_application_key_and_branch() {
-    ComponentDto application = db.components().insertMainBranch(c -> c.setQualifier(APP));
-    ComponentDto applicationBranch = db.components().insertProjectBranch(application);
-    ComponentDto project1 = db.components().insertPrivateProject();
-    ComponentDto project2 = db.components().insertPrivateProject();
-    db.components().insertComponents(newProjectCopy(project1, applicationBranch));
-    db.components().insertComponents(newProjectCopy(project2, applicationBranch));
+    ComponentDto application = db.components().insertMainBranch(c -> c.setQualifier(APP).setDbKey("app"));
+    ComponentDto applicationBranch1 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch1"));
+    ComponentDto applicationBranch2 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch2"));
+    ComponentDto project1 = db.components().insertPrivateProject(p -> p.setDbKey("prj1"));
+    ComponentDto project1Branch1 = db.components().insertProjectBranch(project1);
+    ComponentDto fileOnProject1Branch1 = db.components().insertComponent(newFileDto(project1Branch1));
+    ComponentDto project1Branch2 = db.components().insertProjectBranch(project1);
+    ComponentDto project2 = db.components().insertPrivateProject(p -> p.setDbKey("prj2"));
+    db.components().insertComponents(newProjectCopy(project1Branch1, applicationBranch1));
+    db.components().insertComponents(newProjectCopy(project2, applicationBranch1));
+    db.components().insertComponents(newProjectCopy(project1Branch2, applicationBranch2));
+
     RuleDefinitionDto rule = db.rules().insert();
-    IssueDto issue1 = db.issues().insert(rule, project1, project1);
-    IssueDto issue2 = db.issues().insert(rule, project2, project2);
+    IssueDto issueOnProject1 = db.issues().insert(rule, project1, project1);
+    IssueDto issueOnProject1Branch1 = db.issues().insert(rule, project1Branch1, project1Branch1);
+    IssueDto issueOnFileOnProject1Branch1 = db.issues().insert(rule, project1Branch1, fileOnProject1Branch1);
+    IssueDto issueOnProject1Branch2 = db.issues().insert(rule, project1Branch2, project1Branch2);
+    IssueDto issueOnProject2 = db.issues().insert(rule, project2, project2);
     allowAnyoneOnProjects(project1, project2, application);
     userSession.addProjectPermission(USER, application);
     indexIssuesAndViews();
 
-    SearchWsResponse result = ws.newRequest()
-      .setParam(PARAM_COMPONENT_KEYS, applicationBranch.getKey())
-      .setParam(PARAM_BRANCH, applicationBranch.getBranch())
-      .executeProtobuf(SearchWsResponse.class);
-
-    assertThat(result.getIssuesList()).extracting(Issue::getKey)
-      .containsExactlyInAnyOrder(issue1.getKey(), issue2.getKey());
+    // All issues on applicationBranch1
+    assertThat(ws.newRequest()
+      .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));
+
+    // Issues on project1Branch1
+    assertThat(ws.newRequest()
+      .setParam(PARAM_COMPONENT_KEYS, applicationBranch1.getKey())
+      .setParam(PARAM_PROJECT_UUIDS, project1.uuid())
+      .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()));
   }
 
   @Test
index 424c2607084fbada77203340846fea8c8563ca50..49af088982ed4641201e51fff5f868cefc472431 100644 (file)
@@ -33,7 +33,6 @@ import org.sonar.core.util.stream.MoreCollectors;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
-import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.ResourceTypesRule;
 import org.sonar.db.component.SnapshotDto;
@@ -49,7 +48,6 @@ import org.sonar.server.i18n.I18nRule;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.WsActionTester;
 import org.sonarqube.ws.Common;
-import org.sonarqube.ws.Measures;
 import org.sonarqube.ws.Measures.ComponentTreeWsResponse;
 import org.sonarqube.ws.Measures.PeriodValue;
 
@@ -63,6 +61,7 @@ import static org.sonar.api.measures.Metric.ValueType.DISTRIB;
 import static org.sonar.api.measures.Metric.ValueType.FLOAT;
 import static org.sonar.api.measures.Metric.ValueType.INT;
 import static org.sonar.api.measures.Metric.ValueType.RATING;
+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.PROJECT;
@@ -94,6 +93,8 @@ import static org.sonar.server.measure.ws.ComponentTreeAction.METRIC_SORT;
 import static org.sonar.server.measure.ws.ComponentTreeAction.NAME_SORT;
 import static org.sonar.server.measure.ws.ComponentTreeAction.WITH_MEASURES_ONLY_METRIC_SORT_FILTER;
 import static org.sonar.test.JsonAssert.assertJson;
+import static org.sonarqube.ws.Measures.Component;
+import static org.sonarqube.ws.Measures.Measure;
 
 public class ComponentTreeActionTest {
   @Rule
@@ -107,7 +108,6 @@ public class ComponentTreeActionTest {
   private ResourceTypesRule resourceTypes = new ResourceTypesRule()
     .setRootQualifiers(PROJECT)
     .setLeavesQualifiers(FILE, UNIT_TEST_FILE);
-  private ComponentDbTester componentDb = new ComponentDbTester(db);
   private DbClient dbClient = db.getDbClient();
   private DbSession dbSession = db.getSession();
 
@@ -123,21 +123,21 @@ public class ComponentTreeActionTest {
     SnapshotDto analysis = db.components().insertSnapshot(project, s -> s.setPeriodDate(parseDateTime("2016-01-11T10:49:50+0100").getTime())
       .setPeriodMode("previous_version")
       .setPeriodParam("1.0-SNAPSHOT"));
-    ComponentDto file1 = componentDb.insertComponent(newFileDto(project, null)
+    ComponentDto file1 = db.components().insertComponent(newFileDto(project, null)
       .setUuid("AVIwDXE-bJbJqrw6wFv5")
       .setDbKey("com.sonarsource:java-markdown:src/main/java/com/sonarsource/markdown/impl/ElementImpl.java")
       .setName("ElementImpl.java")
       .setLanguage("java")
       .setQualifier(FILE)
       .setPath("src/main/java/com/sonarsource/markdown/impl/ElementImpl.java"));
-    ComponentDto file2 = componentDb.insertComponent(newFileDto(project, null)
+    ComponentDto file2 = db.components().insertComponent(newFileDto(project, null)
       .setUuid("AVIwDXE_bJbJqrw6wFwJ")
       .setDbKey("com.sonarsource:java-markdown:src/test/java/com/sonarsource/markdown/impl/ElementImplTest.java")
       .setName("ElementImplTest.java")
       .setLanguage("java")
       .setQualifier(UNIT_TEST_FILE)
       .setPath("src/test/java/com/sonarsource/markdown/impl/ElementImplTest.java"));
-    ComponentDto dir = componentDb.insertComponent(newDirectory(project, "src/main/java/com/sonarsource/markdown/impl")
+    ComponentDto dir = db.components().insertComponent(newDirectory(project, "src/main/java/com/sonarsource/markdown/impl")
       .setUuid("AVIwDXE-bJbJqrw6wFv8")
       .setDbKey("com.sonarsource:java-markdown:src/main/java/com/sonarsource/markdown/impl")
       .setQualifier(DIRECTORY));
@@ -194,9 +194,9 @@ public class ComponentTreeActionTest {
         .setPeriodDate(System.currentTimeMillis()));
     userSession.anonymous().addProjectPermission(UserRole.USER, project);
     ComponentDto directory = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1");
-    componentDb.insertComponent(directory);
+    db.components().insertComponent(directory);
     ComponentDto file = newFileDto(directory, null, "file-uuid").setName("file-1");
-    componentDb.insertComponent(file);
+    db.components().insertComponent(file);
     MetricDto ncloc = insertNclocMetric();
     MetricDto coverage = insertCoverageMetric();
     db.commit();
@@ -212,7 +212,7 @@ public class ComponentTreeActionTest {
 
     assertThat(response.getComponentsList().get(0).getMeasuresList()).extracting("metric").containsOnly("coverage");
     // file measures
-    List<Measures.Measure> fileMeasures = response.getComponentsList().get(1).getMeasuresList();
+    List<Measure> fileMeasures = response.getComponentsList().get(1).getMeasuresList();
     assertThat(fileMeasures).extracting("metric").containsOnly("ncloc", "coverage");
     assertThat(fileMeasures).extracting("value").containsOnly("5", "15.5");
     assertThat(response.getPeriods().getPeriodsList()).extracting("mode").containsOnly("last_version");
@@ -224,9 +224,9 @@ public class ComponentTreeActionTest {
     SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
     userSession.anonymous().addProjectPermission(UserRole.USER, project);
     ComponentDto directory = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1");
-    componentDb.insertComponent(directory);
+    db.components().insertComponent(directory);
     ComponentDto file = newFileDto(directory, null, "file-uuid").setName("file-1");
-    componentDb.insertComponent(file);
+    db.components().insertComponent(file);
     MetricDto coverage = insertCoverageMetric();
     dbClient.metricDao().insert(dbSession, MetricTesting.newMetricDto()
       .setKey("ncloc")
@@ -252,9 +252,9 @@ public class ComponentTreeActionTest {
     // directory measures
     assertThat(response.getComponentsList().get(0).getMeasuresList()).extracting("metric").containsOnly("coverage");
     // file measures
-    List<Measures.Measure> fileMeasures = response.getComponentsList().get(1).getMeasuresList();
+    List<Measure> fileMeasures = response.getComponentsList().get(1).getMeasuresList();
     assertThat(fileMeasures)
-      .extracting(Measures.Measure::getMetric, Measures.Measure::getValue, Measures.Measure::getBestValue, Measures.Measure::hasBestValue)
+      .extracting(Measure::getMetric, Measure::getValue, Measure::getBestValue, Measure::hasBestValue)
       .containsExactlyInAnyOrder(tuple("ncloc", "100", true, true),
         tuple("coverage", "15.5", false, false),
         tuple("new_violations", "", false, false));
@@ -294,9 +294,9 @@ public class ComponentTreeActionTest {
       .executeProtobuf(ComponentTreeWsResponse.class);
 
     // file measures
-    List<Measures.Measure> fileMeasures = response.getComponentsList().get(0).getMeasuresList();
+    List<Measure> fileMeasures = response.getComponentsList().get(0).getMeasuresList();
     assertThat(fileMeasures)
-      .extracting(Measures.Measure::getMetric, m -> m.getPeriods().getPeriodsValueList())
+      .extracting(Measure::getMetric, m -> m.getPeriods().getPeriodsValueList())
       .containsExactlyInAnyOrder(
         tuple(matchingBestValue.getKey(), singletonList(PeriodValue.newBuilder().setIndex(1).setValue("100").setBestValue(true).build())),
         tuple(doesNotMatchBestValue.getKey(), singletonList(PeriodValue.newBuilder().setIndex(1).setValue("10").setBestValue(false).build())),
@@ -312,9 +312,9 @@ public class ComponentTreeActionTest {
       .setPeriodMode("previous_version")
       .setPeriodParam("1.0-SNAPSHOT"));
     ComponentDto directory = newDirectory(project, "directory-uuid", "path/to/directory").setName("directory-1");
-    componentDb.insertComponent(directory);
+    db.components().insertComponent(directory);
     ComponentDto file = newFileDto(directory, null, "file-uuid").setName("file-1");
-    componentDb.insertComponent(file);
+    db.components().insertComponent(file);
     MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
       .setKey(NEW_SECURITY_RATING_KEY)
       .setOptimizedBestValue(true)
@@ -339,15 +339,15 @@ public class ComponentTreeActionTest {
   public void load_measures_multi_sort_with_metric_key_and_paginated() {
     ComponentDto project = db.components().insertPrivateProject();
     SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
-    ComponentDto file9 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-9").setName("file-1"));
-    ComponentDto file8 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-8").setName("file-1"));
-    ComponentDto file7 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-7").setName("file-1"));
-    ComponentDto file6 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-6").setName("file-1"));
-    ComponentDto file5 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-5").setName("file-1"));
-    ComponentDto file4 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-4").setName("file-1"));
-    ComponentDto file3 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-3").setName("file-1"));
-    ComponentDto file2 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-2").setName("file-1"));
-    ComponentDto file1 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-1").setName("file-1"));
+    ComponentDto file9 = db.components().insertComponent(newFileDto(project, null, "file-uuid-9").setName("file-1"));
+    ComponentDto file8 = db.components().insertComponent(newFileDto(project, null, "file-uuid-8").setName("file-1"));
+    ComponentDto file7 = db.components().insertComponent(newFileDto(project, null, "file-uuid-7").setName("file-1"));
+    ComponentDto file6 = db.components().insertComponent(newFileDto(project, null, "file-uuid-6").setName("file-1"));
+    ComponentDto file5 = db.components().insertComponent(newFileDto(project, null, "file-uuid-5").setName("file-1"));
+    ComponentDto file4 = db.components().insertComponent(newFileDto(project, null, "file-uuid-4").setName("file-1"));
+    ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "file-uuid-3").setName("file-1"));
+    ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "file-uuid-2").setName("file-1"));
+    ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "file-uuid-1").setName("file-1"));
     MetricDto coverage = insertCoverageMetric();
     db.commit();
     db.measures().insertLiveMeasure(file1, coverage, m -> m.setValue(1.0d));
@@ -381,10 +381,10 @@ public class ComponentTreeActionTest {
   public void sort_by_metric_value() {
     ComponentDto project = db.components().insertPrivateProject();
     SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
-    ComponentDto file4 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-4"));
-    ComponentDto file3 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-3"));
-    ComponentDto file1 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-1"));
-    ComponentDto file2 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-2"));
+    ComponentDto file4 = db.components().insertComponent(newFileDto(project, null, "file-uuid-4"));
+    ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "file-uuid-3"));
+    ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "file-uuid-1"));
+    ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "file-uuid-2"));
     MetricDto ncloc = newMetricDto().setKey("ncloc").setValueType(INT.name()).setDirection(1);
     dbClient.metricDao().insert(dbSession, ncloc);
     db.commit();
@@ -411,10 +411,10 @@ public class ComponentTreeActionTest {
     ComponentDto file2 = newFileDto(project, null, "file-uuid-2");
     ComponentDto file3 = newFileDto(project, null, "file-uuid-3");
     ComponentDto file4 = newFileDto(project, null, "file-uuid-4");
-    componentDb.insertComponent(file1);
-    componentDb.insertComponent(file2);
-    componentDb.insertComponent(file3);
-    componentDb.insertComponent(file4);
+    db.components().insertComponent(file1);
+    db.components().insertComponent(file2);
+    db.components().insertComponent(file3);
+    db.components().insertComponent(file4);
     MetricDto ncloc = newMetricDto().setKey("ncloc").setValueType(INT.name()).setDirection(1);
     dbClient.metricDao().insert(dbSession, ncloc);
     db.measures().insertLiveMeasure(file1, ncloc, m -> m.setData((String) null).setValue(1.0d).setVariation(null));
@@ -442,9 +442,9 @@ public class ComponentTreeActionTest {
   public void sort_by_metric_period() {
     ComponentDto project = db.components().insertPrivateProject();
     SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
-    ComponentDto file3 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-3"));
-    ComponentDto file1 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-1"));
-    ComponentDto file2 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-2"));
+    ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "file-uuid-3"));
+    ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "file-uuid-1"));
+    ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "file-uuid-2"));
     MetricDto ncloc = newMetricDto().setKey("ncloc").setValueType(INT.name()).setDirection(1);
     dbClient.metricDao().insert(dbSession, ncloc);
     db.commit();
@@ -467,10 +467,10 @@ public class ComponentTreeActionTest {
   public void remove_components_without_measure_on_the_metric_period_sort() {
     ComponentDto project = db.components().insertPrivateProject();
     SnapshotDto projectSnapshot = db.components().insertSnapshot(project);
-    ComponentDto file4 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-4"));
-    ComponentDto file3 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-3"));
-    ComponentDto file2 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-2"));
-    ComponentDto file1 = componentDb.insertComponent(newFileDto(project, null, "file-uuid-1"));
+    ComponentDto file4 = db.components().insertComponent(newFileDto(project, null, "file-uuid-4"));
+    ComponentDto file3 = db.components().insertComponent(newFileDto(project, null, "file-uuid-3"));
+    ComponentDto file2 = db.components().insertComponent(newFileDto(project, null, "file-uuid-2"));
+    ComponentDto file1 = db.components().insertComponent(newFileDto(project, null, "file-uuid-1"));
     MetricDto ncloc = newMetricDto().setKey("new_ncloc").setValueType(INT.name()).setDirection(1);
     dbClient.metricDao().insert(dbSession, ncloc);
     db.measures().insertLiveMeasure(file1, ncloc, m -> m.setData((String) null).setValue(null).setVariation(1.0d));
@@ -499,7 +499,7 @@ public class ComponentTreeActionTest {
     resourceTypes.setLeavesQualifiers();
     ComponentDto project = db.components().insertPrivateProject();
     db.components().insertSnapshot(project);
-    componentDb.insertComponent(newFileDto(project, null));
+    db.components().insertComponent(newFileDto(project, null));
     insertNclocMetric();
 
     ComponentTreeWsResponse result = ws.newRequest()
@@ -526,12 +526,12 @@ public class ComponentTreeActionTest {
       .setParam(PARAM_COMPONENT, file.getKey())
       .setParam(PARAM_BRANCH, file.getBranch())
       .setParam(PARAM_METRIC_KEYS, complexity.getKey())
-      .executeProtobuf(Measures.ComponentTreeWsResponse.class);
+      .executeProtobuf(ComponentTreeWsResponse.class);
 
-    assertThat(response.getBaseComponent()).extracting(Measures.Component::getKey, Measures.Component::getBranch)
+    assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getBranch)
       .containsExactlyInAnyOrder(file.getKey(), file.getBranch());
     assertThat(response.getBaseComponent().getMeasuresList())
-      .extracting(Measures.Measure::getMetric, m -> parseDouble(m.getValue()))
+      .extracting(Measure::getMetric, m -> parseDouble(m.getValue()))
       .containsExactlyInAnyOrder(tuple(complexity.getKey(), measure.getValue()));
   }
 
@@ -549,12 +549,12 @@ public class ComponentTreeActionTest {
       .setParam(PARAM_COMPONENT, file.getKey())
       .setParam(PARAM_PULL_REQUEST, "pr-123")
       .setParam(PARAM_METRIC_KEYS, complexity.getKey())
-      .executeProtobuf(Measures.ComponentTreeWsResponse.class);
+      .executeProtobuf(ComponentTreeWsResponse.class);
 
-    assertThat(response.getBaseComponent()).extracting(Measures.Component::getKey, Measures.Component::getPullRequest)
+    assertThat(response.getBaseComponent()).extracting(Component::getKey, Component::getPullRequest)
       .containsExactlyInAnyOrder(file.getKey(), "pr-123");
     assertThat(response.getBaseComponent().getMeasuresList())
-      .extracting(Measures.Measure::getMetric, m -> parseDouble(m.getValue()))
+      .extracting(Measure::getMetric, m -> parseDouble(m.getValue()))
       .containsExactlyInAnyOrder(tuple(complexity.getKey(), measure.getValue()));
   }
 
@@ -562,7 +562,7 @@ public class ComponentTreeActionTest {
   public void return_deprecated_id_in_the_response() {
     ComponentDto project = db.components().insertPrivateProject();
     SnapshotDto analysis = db.components().insertSnapshot(project);
-    ComponentDto file = componentDb.insertComponent(newFileDto(project));
+    ComponentDto file = db.components().insertComponent(newFileDto(project));
     MetricDto ncloc = insertNclocMetric();
     db.measures().insertLiveMeasure(file, ncloc, m -> m.setValue(2d));
 
@@ -572,7 +572,7 @@ public class ComponentTreeActionTest {
       .executeProtobuf(ComponentTreeWsResponse.class);
 
     assertThat(response.getBaseComponent().getId()).isEqualTo(project.uuid());
-    assertThat(response.getComponentsList()).extracting(Measures.Component::getId)
+    assertThat(response.getComponentsList()).extracting(Component::getId)
       .containsExactlyInAnyOrder(file.uuid());
   }
 
@@ -626,7 +626,7 @@ public class ComponentTreeActionTest {
   }
 
   @Test
-  public void reference_component() {
+  public void project_reference_from_portfolio() {
     ComponentDto project = db.components().insertPrivateProject();
     ComponentDto view = db.components().insertPrivatePortfolio(db.getDefaultOrganization());
     SnapshotDto viewAnalysis = db.components().insertSnapshot(view);
@@ -640,10 +640,37 @@ public class ComponentTreeActionTest {
       .executeProtobuf(ComponentTreeWsResponse.class);
 
     assertThat(result.getComponentsList())
-      .extracting(Measures.Component::getKey, Measures.Component::getRefId, Measures.Component::getRefKey)
+      .extracting(Component::getKey, Component::getRefId, Component::getRefKey)
       .containsExactlyInAnyOrder(tuple(projectCopy.getKey(), project.uuid(), project.getKey()));
   }
 
+  @Test
+  public void project_branch_reference_from_application_branch() {
+    MetricDto ncloc = insertNclocMetric();
+    ComponentDto application = db.components().insertMainBranch(c -> c.setQualifier(APP).setDbKey("app-key"));
+    ComponentDto applicationBranch = db.components().insertProjectBranch(application, a -> a.setKey("app-branch"));
+    ComponentDto project = db.components().insertPrivateProject(p -> p.setDbKey("project-key"));
+    ComponentDto projectBranch = db.components().insertProjectBranch(project, b -> b.setKey("project-branch"));
+    ComponentDto techProjectBranch = db.components().insertComponent(newProjectCopy(projectBranch, applicationBranch)
+      .setDbKey(applicationBranch.getKey() + applicationBranch.getBranch() + projectBranch.getDbKey()));
+    SnapshotDto applicationBranchAnalysis = db.components().insertSnapshot(applicationBranch);
+    db.measures().insertLiveMeasure(applicationBranch, ncloc, m -> m.setValue(5d));
+    db.measures().insertLiveMeasure(techProjectBranch, ncloc, m -> m.setValue(1d));
+
+    ComponentTreeWsResponse result = ws.newRequest()
+      .setParam(PARAM_COMPONENT, applicationBranch.getKey())
+      .setParam(PARAM_BRANCH, applicationBranch.getBranch())
+      .setParam(PARAM_METRIC_KEYS, ncloc.getKey())
+      .executeProtobuf(ComponentTreeWsResponse.class);
+
+    assertThat(result.getBaseComponent())
+      .extracting(Component::getKey, Component::getBranch)
+      .containsExactlyInAnyOrder(applicationBranch.getKey(), applicationBranch.getBranch());
+    assertThat(result.getComponentsList())
+      .extracting(Component::getKey, Component::getBranch, Component::getRefId, Component::getRefKey)
+      .containsExactlyInAnyOrder(tuple(techProjectBranch.getKey(), projectBranch.getBranch(), projectBranch.uuid(), project.getKey()));
+  }
+
   @Test
   public void fail_when_metric_keys_parameter_is_empty() {
     ComponentDto project = db.components().insertPrivateProject();
@@ -854,7 +881,7 @@ public class ComponentTreeActionTest {
   public void fail_when_component_is_removed() {
     ComponentDto project = db.components().insertPrivateProject();
     db.components().insertSnapshot(project);
-    ComponentDto file = componentDb.insertComponent(newFileDto(project).setDbKey("file-key").setEnabled(false));
+    ComponentDto file = db.components().insertComponent(newFileDto(project).setDbKey("file-key").setEnabled(false));
     userSession.anonymous().addProjectPermission(UserRole.USER, project);
     insertNclocMetric();
 
index 933e9a3ddc1953390711d26789e4a81d436cf3b9..c1bf5acf7fa3903194f825201929ca1686cc505a 100644 (file)
@@ -128,6 +128,82 @@ public class ProjectLifeCycleListenersImplTest {
     inOrder.verifyNoMoreInteractions();
   }
 
+  @Test
+  public void onProjectBranchesDeleted_throws_NPE_if_set_is_null() {
+    expectedException.expect(NullPointerException.class);
+    expectedException.expectMessage("projects can't be null");
+
+    underTestWithListeners.onProjectBranchesDeleted(null);
+  }
+
+  @Test
+  public void onProjectBranchesDeleted_throws_NPE_if_set_is_null_even_if_no_listeners() {
+    expectedException.expect(NullPointerException.class);
+    expectedException.expectMessage("projects can't be null");
+
+    underTestNoListeners.onProjectBranchesDeleted(null);
+  }
+
+  @Test
+  public void onProjectBranchesDeleted_has_no_effect_if_set_is_empty() {
+    underTestNoListeners.onProjectBranchesDeleted(Collections.emptySet());
+
+    underTestWithListeners.onProjectBranchesDeleted(Collections.emptySet());
+    verifyZeroInteractions(listener1, listener2, listener3);
+  }
+
+  @Test
+  @UseDataProvider("oneOrManyProjects")
+  public void onProjectBranchesDeleted_does_not_fail_if_there_is_no_listener(Set<Project> projects) {
+    underTestNoListeners.onProjectBranchesDeleted(projects);
+  }
+
+  @Test
+  @UseDataProvider("oneOrManyProjects")
+  public void onProjectBranchesDeleted_calls_all_listeners_in_order_of_addition_to_constructor(Set<Project> projects) {
+    InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
+
+    underTestWithListeners.onProjectBranchesDeleted(projects);
+
+    inOrder.verify(listener1).onProjectBranchesDeleted(same(projects));
+    inOrder.verify(listener2).onProjectBranchesDeleted(same(projects));
+    inOrder.verify(listener3).onProjectBranchesDeleted(same(projects));
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  @UseDataProvider("oneOrManyProjects")
+  public void onProjectBranchesDeleted_calls_all_listeners_even_if_one_throws_an_Exception(Set<Project> projects) {
+    InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
+    doThrow(new RuntimeException("Faking listener2 throwing an exception"))
+      .when(listener2)
+      .onProjectBranchesDeleted(any());
+
+    underTestWithListeners.onProjectBranchesDeleted(projects);
+
+    inOrder.verify(listener1).onProjectBranchesDeleted(same(projects));
+    inOrder.verify(listener2).onProjectBranchesDeleted(same(projects));
+    inOrder.verify(listener3).onProjectBranchesDeleted(same(projects));
+    inOrder.verifyNoMoreInteractions();
+  }
+
+  @Test
+  @UseDataProvider("oneOrManyProjects")
+  public void onProjectBranchesDeleted_calls_all_listeners_even_if_one_throws_an_Error(Set<Project> projects) {
+    InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
+    doThrow(new Error("Faking listener2 throwing an Error"))
+      .when(listener2)
+      .onProjectBranchesDeleted(any());
+
+    underTestWithListeners.onProjectBranchesDeleted(projects);
+
+    inOrder.verify(listener1).onProjectBranchesDeleted(same(projects));
+    inOrder.verify(listener2).onProjectBranchesDeleted(same(projects));
+    inOrder.verify(listener3).onProjectBranchesDeleted(same(projects));
+    inOrder.verifyNoMoreInteractions();
+  }
+
+
   @DataProvider
   public static Object[][] oneOrManyProjects() {
     return new Object[][] {
index 4b5b12b437d7464c8c19653d91bdcca291824901..a36042baf764c50f0074cde60ce0d390c1ed6a48 100644 (file)
@@ -56,6 +56,8 @@ import static com.google.common.collect.Lists.newArrayList;
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptySet;
 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.db.component.ComponentTesting.newProjectCopy;
 import static org.sonar.server.view.index.ViewIndexDefinition.INDEX_TYPE_VIEW;
 
@@ -65,18 +67,15 @@ public class ViewIndexerTest {
 
   @Rule
   public TestRule safeguardTimeout = new DisableOnDebug(Timeout.seconds(60));
-
   @Rule
-  public DbTester dbTester = DbTester.create(system2);
-
+  public DbTester db = DbTester.create();
   @Rule
   public EsTester es = EsTester.create();
-
   @Rule
   public UserSessionRule userSessionRule = UserSessionRule.standalone();
 
-  private DbClient dbClient = dbTester.getDbClient();
-  private DbSession dbSession = dbTester.getSession();
+  private DbClient dbClient = db.getDbClient();
+  private DbSession dbSession = db.getSession();
   private IssueIndexer issueIndexer = new IssueIndexer(es.client(), dbClient, new IssueIteratorFactory(dbClient));
   private PermissionIndexer permissionIndexer = new PermissionIndexer(dbClient, es.client(), issueIndexer);
   private ViewIndexer underTest = new ViewIndexer(dbClient, es.client());
@@ -89,7 +88,7 @@ public class ViewIndexerTest {
 
   @Test
   public void index_on_startup() {
-    dbTester.prepareDbUnit(getClass(), "index.xml");
+    db.prepareDbUnit(getClass(), "index.xml");
 
     underTest.indexOnStartup(emptySet());
 
@@ -106,7 +105,7 @@ public class ViewIndexerTest {
 
   @Test
   public void index_root_view() {
-    dbTester.prepareDbUnit(getClass(), "index.xml");
+    db.prepareDbUnit(getClass(), "index.xml");
 
     underTest.index("EFGH");
 
@@ -133,9 +132,9 @@ public class ViewIndexerTest {
 
   @Test
   public void index_application() {
-    ComponentDto application = dbTester.components().insertApplication(dbTester.getDefaultOrganization());
-    ComponentDto project = dbTester.components().insertPrivateProject();
-    dbTester.components().insertComponent(newProjectCopy("PC1", project, application));
+    ComponentDto application = db.components().insertApplication(db.getDefaultOrganization());
+    ComponentDto project = db.components().insertPrivateProject();
+    db.components().insertComponent(newProjectCopy("PC1", project, application));
 
     underTest.index(application.uuid());
     List<ViewDoc> result = es.getDocuments(ViewIndexDefinition.INDEX_TYPE_VIEW, ViewDoc.class);
@@ -148,9 +147,9 @@ public class ViewIndexerTest {
 
   @Test
   public void index_application_on_startup() {
-    ComponentDto application = dbTester.components().insertApplication(dbTester.getDefaultOrganization());
-    ComponentDto project = dbTester.components().insertPrivateProject();
-    dbTester.components().insertComponent(newProjectCopy("PC1", project, application));
+    ComponentDto application = db.components().insertApplication(db.getDefaultOrganization());
+    ComponentDto project = db.components().insertPrivateProject();
+    db.components().insertComponent(newProjectCopy("PC1", project, application));
 
     underTest.indexOnStartup(emptySet());
     List<ViewDoc> result = es.getDocuments(ViewIndexDefinition.INDEX_TYPE_VIEW, ViewDoc.class);
@@ -161,6 +160,31 @@ public class ViewIndexerTest {
     assertThat(resultApp.projects()).containsExactlyInAnyOrder(project.uuid());
   }
 
+  @Test
+  public void index_application_branch() {
+    ComponentDto application = db.components().insertMainBranch(c -> c.setQualifier(APP).setDbKey("app"));
+    ComponentDto applicationBranch1 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch1"));
+    ComponentDto applicationBranch2 = db.components().insertProjectBranch(application, a -> a.setKey("app-branch2"));
+    ComponentDto project1 = db.components().insertPrivateProject(p -> p.setDbKey("prj1"));
+    ComponentDto project1Branch = db.components().insertProjectBranch(project1);
+    ComponentDto project2 = db.components().insertPrivateProject(p -> p.setDbKey("prj2"));
+    ComponentDto project2Branch = db.components().insertProjectBranch(project2);
+    ComponentDto project3 = db.components().insertPrivateProject(p -> p.setDbKey("prj3"));
+    ComponentDto project3Branch = db.components().insertProjectBranch(project3);
+    db.components().insertComponent(newProjectCopy(project1Branch, applicationBranch1));
+    db.components().insertComponent(newProjectCopy(project2Branch, applicationBranch1));
+    // Technical project of applicationBranch2 should be ignored
+    db.components().insertComponent(newProjectCopy(project3Branch, applicationBranch2));
+
+    underTest.index(applicationBranch1.uuid());
+
+    List<ViewDoc> result = es.getDocuments(ViewIndexDefinition.INDEX_TYPE_VIEW, ViewDoc.class);
+    assertThat(result)
+      .extracting(ViewDoc::uuid, ViewDoc::projects)
+      .containsExactlyInAnyOrder(
+        tuple(applicationBranch1.uuid(), asList(project1Branch.uuid(), project2Branch.uuid())));
+  }
+
   @Test
   public void clear_views_lookup_cache_on_index_view_uuid() {
     IssueIndex issueIndex = new IssueIndex(es.client(), System2.INSTANCE, userSessionRule, new AuthorizationTypeSupport(userSessionRule));
@@ -170,11 +194,11 @@ public class ViewIndexerTest {
 
     RuleDto rule = RuleTesting.newXooX1();
     dbClient.ruleDao().insert(dbSession, rule.getDefinition());
-    ComponentDto project1 = addProjectWithIssue(rule, dbTester.organizations().insert());
+    ComponentDto project1 = addProjectWithIssue(rule, db.organizations().insert());
     issueIndexer.indexOnStartup(issueIndexer.getIndexTypes());
     permissionIndexer.indexOnStartup(permissionIndexer.getIndexTypes());
 
-    OrganizationDto organizationDto = dbTester.organizations().insert();
+    OrganizationDto organizationDto = db.organizations().insert();
     ComponentDto view = ComponentTesting.newView(organizationDto, "ABCD");
     ComponentDto techProject1 = newProjectCopy("CDEF", project1, view);
     dbClient.componentDao().insert(dbSession, view, techProject1);
@@ -250,7 +274,7 @@ public class ViewIndexerTest {
   private ComponentDto addProjectWithIssue(RuleDto rule, OrganizationDto org) {
     ComponentDto project = ComponentTesting.newPublicProjectDto(org);
     ComponentDto file = ComponentTesting.newFileDto(project, null);
-    dbTester.components().insertComponents(project, file);
+    db.components().insertComponents(project, file);
 
     IssueDto issue = IssueTesting.newDto(rule, file, project);
     dbClient.issueDao().insert(dbSession, issue);
index 8f76a4f1ecb1b671d9c2313a168a2c76487b30ef..c0a308c3578a54576edaf6cb0043a9caafe9098d 100644 (file)
@@ -115,7 +115,6 @@ abstract class BaseRequest<SELF extends BaseRequest> implements WsRequest {
     parameters.setValues(key, values.stream()
       .filter(Objects::nonNull)
       .map(Object::toString)
-      .filter(value -> !value.isEmpty())
       .collect(Collectors.toList()));
 
     return (SELF) this;
index 6c0b67735e8b0e1bc77791811438f7a398a78ad9..87e09cfd7e0ac8a7af8f524b348fb632ef7b51ba 100644 (file)
@@ -29,6 +29,7 @@ import org.junit.rules.ExpectedException;
 import org.sonarqube.ws.MediaTypes;
 
 import static com.google.common.collect.Lists.newArrayList;
+import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.data.MapEntry.entry;
@@ -79,8 +80,9 @@ public class BaseRequestTest {
 
   @Test
   public void skip_null_value_in_multi_param() {
-    underTest.setParam("key", newArrayList("v1", null, "v3"));
+    underTest.setParam("key", newArrayList("v1", null, "", "v3"));
 
+    assertMultiValueParameters(entry("key", asList("v1", "", "v3")));
   }
 
   @Test