]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5559 Update Issue mapping to add a Issue Authorization parent (only created...
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 3 Sep 2014 08:26:25 +0000 (10:26 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 3 Sep 2014 08:26:25 +0000 (10:26 +0200)
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueNormalizer.java
server/sonar-server/src/main/java/org/sonar/server/search/IndexDefinition.java
server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest.java

index 92fd7aef6c793a7d45edc9d3049ad440e67b7ed0..b925f5e1e1e3177f3ed16ad7c61be5fe83ec9071 100644 (file)
@@ -60,6 +60,34 @@ public class IssueIndex extends BaseIndex<IssueDoc, IssueDto, String> {
     return mapping;
   }
 
+  @Override
+  protected Map mapDomain() {
+    Map<String, Object> mapping = new HashMap<String, Object>();
+    mapping.put("dynamic", false);
+    mapping.put("_id", mapKey());
+    mapping.put("_parent", mapParent());
+    mapping.put("_routing", mapRouting());
+    mapping.put("properties", mapProperties());
+    return mapping;
+  }
+
+  private Object mapParent() {
+    Map<String, Object> mapping = new HashMap<String, Object>();
+    mapping.put("type", getParentType());
+    return mapping;
+  }
+
+  private String getParentType() {
+    return IndexDefinition.ISSUES_AUTHENTICATION.getIndexType();
+  }
+
+  private Map mapRouting() {
+    Map<String, Object> mapping = new HashMap<String, Object>();
+    mapping.put("required", true);
+    mapping.put("path", IssueNormalizer.IssueField.PROJECT.field());
+    return mapping;
+  }
+
   @Override
   protected Map mapKey() {
     Map<String, Object> mapping = new HashMap<String, Object>();
index 38ae9d97635004c2d4516f3e94061b6f65d622da..30f7368c168f57e1d82690129452e77ba6bee54a 100644 (file)
@@ -29,11 +29,7 @@ import org.sonar.server.search.IndexField;
 import org.sonar.server.search.Indexable;
 
 import java.lang.reflect.Field;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 public class IssueNormalizer extends BaseNormalizer<IssueDto, String> {
 
@@ -53,6 +49,7 @@ public class IssueNormalizer extends BaseNormalizer<IssueDto, String> {
     public static final IndexField ISSUE_CREATED_AT = add(IndexField.Type.DATE, "issueCreatedAt");
     public static final IndexField ISSUE_UPDATED_AT = add(IndexField.Type.DATE, "issueUpdatedAt");
     public static final IndexField ISSUE_CLOSE_DATE = add(IndexField.Type.DATE, "issueClosedAt");
+    public static final IndexField PROJECT = add(IndexField.Type.STRING, "project");
     public static final IndexField COMPONENT = add(IndexField.Type.STRING, "component");
     public static final IndexField EFFORT = add(IndexField.Type.NUMERIC, "effort");
     public static final IndexField RESOLUTION = add(IndexField.Type.STRING, "resolution");
@@ -95,6 +92,7 @@ public class IssueNormalizer extends BaseNormalizer<IssueDto, String> {
   public List<UpdateRequest> normalize(IssueDto dto) {
     Map<String, Object> update = new HashMap<String, Object>();
 
+    update.put("_parent", dto.getRootComponentKey());
     update.put(IssueField.KEY.field(), dto.getKey());
     update.put(IssueField.UPDATED_AT.field(), dto.getUpdatedAt());
     update.put(IssueField.CREATED_AT.field(), dto.getCreatedAt());
@@ -103,6 +101,7 @@ public class IssueNormalizer extends BaseNormalizer<IssueDto, String> {
     update.put(IssueField.ASSIGNEE.field(), dto.getAssignee());
     update.put(IssueField.AUTHOR_LOGIN.field(), dto.getAuthorLogin());
     update.put(IssueField.ISSUE_CLOSE_DATE.field(), dto.getIssueCloseDate());
+    update.put(IssueField.PROJECT.field(), dto.getRootComponentKey());
     update.put(IssueField.COMPONENT.field(), dto.getComponentKey());
     update.put(IssueField.ISSUE_CREATED_AT.field(), dto.getIssueCreationDate());
     update.put(IssueField.ISSUE_UPDATED_AT.field(), dto.getIssueUpdateDate());
@@ -131,6 +130,8 @@ public class IssueNormalizer extends BaseNormalizer<IssueDto, String> {
     return ImmutableList.of(
       new UpdateRequest()
         .id(dto.getKey().toString())
+        .routing(dto.getRootComponentKey())
+        .parent(dto.getRootComponentKey())
         .doc(update)
         .upsert(upsert));
  }
index 0d16ff4b972186e3805d008b74a4f313bec9d4b6..94580d1b29d489f75d60dcc69af7723e983f0c48 100644 (file)
@@ -52,9 +52,14 @@ public class IndexDefinition {
 
   public static final IndexDefinition RULE = new IndexDefinition("rules", "rule");
   public static final IndexDefinition ACTIVE_RULE = new IndexDefinition("rules", "activeRule");
+  public static final IndexDefinition ISSUES_AUTHENTICATION = new IndexDefinition("issues", "issuesAuthorization");
   public static final IndexDefinition ISSUES = new IndexDefinition("issues", "issue");
   public static final IndexDefinition LOG = new IndexDefinition("logs", "sonarLog");
 
   @VisibleForTesting
   protected static IndexDefinition TEST = new IndexDefinition("test", "test");
+
+  public static IndexDefinition createFor(String indexName, String indexType) {
+    return new IndexDefinition(indexName, indexType);
+  }
 }
index d108c22e20197778a71843e77df77af2e6c0f015..5b68a40a0ec53c4d22c7d3fcf31f558800451e49 100644 (file)
  */
 package org.sonar.server.issue.db;
 
+import com.google.common.collect.ImmutableMap;
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.settings.ImmutableSettings;
+import org.elasticsearch.index.query.FilterBuilders;
+import org.elasticsearch.index.query.QueryBuilders;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.ClassRule;
@@ -35,11 +41,15 @@ import org.sonar.server.issue.index.IssueIndex;
 import org.sonar.server.platform.Platform;
 import org.sonar.server.rule.RuleTesting;
 import org.sonar.server.rule.db.RuleDao;
+import org.sonar.server.search.BaseIndex;
 import org.sonar.server.search.IndexClient;
+import org.sonar.server.search.IndexDefinition;
+import org.sonar.server.search.SearchClient;
 import org.sonar.server.tester.ServerTester;
 
-import java.util.Date;
-import java.util.UUID;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.*;
 
 import static org.fest.assertions.Assertions.assertThat;
 
@@ -75,14 +85,14 @@ public class IssueBackendMediumTest {
     tester.get(RuleDao.class).insert(dbSession, rule);
 
     ComponentDto project = new ComponentDto()
+      .setId(1L)
       .setKey("MyProject")
-  .setId(1L)
       .setProjectId(1L);
     tester.get(ComponentDao.class).insert(dbSession, project);
 
     ComponentDto resource = new ComponentDto()
-      .setKey("MyComponent")
       .setProjectId(1L)
+      .setKey("MyComponent")
       .setId(2L);
     tester.get(ComponentDao.class).insert(dbSession, resource);
 
@@ -137,18 +147,22 @@ public class IssueBackendMediumTest {
 
     ComponentDto project = new ComponentDto()
       .setId(1L)
+      .setKey("MyProject")
       .setProjectId(1L);
     tester.get(ComponentDao.class).insert(dbSession, project);
 
     ComponentDto resource = new ComponentDto()
-      .setProjectId(1L)
-      .setId(2L);
+      .setId(2L)
+      .setKey("MyComponent")
+      .setProjectId(1L);
     tester.get(ComponentDao.class).insert(dbSession, resource);
 
-    IssueDto issue = new IssueDto().setId(1L).setRuleId(50).setComponentId(123l).setRootComponentId(100l)
+    IssueDto issue = new IssueDto().setId(1L)
       .setRuleId(rule.getId())
       .setRootComponentId(project.getId())
+      .setRootComponentKey_unit_test_only(project.key())
       .setComponentId(resource.getId())
+      .setComponentKey_unit_test_only(resource.key())
       .setStatus("OPEN").setResolution("OPEN")
       .setKee(UUID.randomUUID().toString());
     dbClient.issueDao().insert(dbSession, issue);
@@ -169,6 +183,161 @@ public class IssueBackendMediumTest {
     assertThat(indexClient.get(IssueIndex.class).countAll()).isEqualTo(0);
     tester.get(Platform.class).executeStartupTasks();
     assertThat(indexClient.get(IssueIndex.class).countAll()).isEqualTo(1);
+  }
+
+  @Test
+  public void issue_authorization_on_group() throws Exception {
+    SearchClient searchClient = tester.get(SearchClient.class);
+    createIssueAuthorizationIndex(searchClient, IndexDefinition.ISSUES_AUTHENTICATION.getIndexName(), IndexDefinition.ISSUES_AUTHENTICATION.getIndexType());
+
+    RuleDto rule = RuleTesting.newXooX1();
+    tester.get(RuleDao.class).insert(dbSession, rule);
+
+    ComponentDto project = new ComponentDto()
+      .setId(1L)
+      .setProjectId(1L)
+      .setKey("SonarQube");
+    tester.get(ComponentDao.class).insert(dbSession, project);
+
+    ComponentDto resource = new ComponentDto()
+      .setProjectId(1L)
+      .setId(2L)
+      .setKey("IssueAction.java");
+    tester.get(ComponentDao.class).insert(dbSession, resource);
+
+    IssueDto issue = new IssueDto().setId(1L)
+      .setRuleId(rule.getId())
+      .setRootComponentKey_unit_test_only(project.key())
+      .setRootComponentId(project.getId())
+      .setComponentKey_unit_test_only(resource.key())
+      .setComponentId(resource.getId())
+      .setStatus("OPEN").setResolution("OPEN")
+      .setKee(UUID.randomUUID().toString());
+    dbClient.issueDao().insert(dbSession, issue);
+
+    dbSession.commit();
+
+    searchClient.prepareIndex(IndexDefinition.ISSUES_AUTHENTICATION.getIndexName(), IndexDefinition.ISSUES_AUTHENTICATION.getIndexType())
+      .setId(project.key())
+      .setSource(ImmutableMap.<String, Object>of("permission", "read", "project", project.key(), "group", "user"))
+      .setRefresh(true)
+      .get();
+
+    // The issue is only visible for group user
+    assertThat(searchIssueWithAuthorization(searchClient, "user", "").getHits().getTotalHits()).isEqualTo(1);
+    // The issue is not visible for group reviewer
+    assertThat(searchIssueWithAuthorization(searchClient, "reviewer", "").getHits().getTotalHits()).isEqualTo(0);
+  }
+
+  @Test
+  public void issue_authorization_on_user() throws Exception {
+    SearchClient searchClient = tester.get(SearchClient.class);
+    createIssueAuthorizationIndex(searchClient, IndexDefinition.ISSUES_AUTHENTICATION.getIndexName(), IndexDefinition.ISSUES_AUTHENTICATION.getIndexType());
+
+    RuleDto rule = RuleTesting.newXooX1();
+    tester.get(RuleDao.class).insert(dbSession, rule);
+
+    ComponentDto project = new ComponentDto()
+      .setId(1L)
+      .setProjectId(1L)
+      .setKey("SonarQube");
+    tester.get(ComponentDao.class).insert(dbSession, project);
+
+    ComponentDto resource = new ComponentDto()
+      .setProjectId(1L)
+      .setId(2L)
+      .setKey("IssueAction.java");
+    tester.get(ComponentDao.class).insert(dbSession, resource);
+
+    IssueDto issue = new IssueDto().setId(1L)
+      .setRuleId(rule.getId())
+      .setRootComponentKey_unit_test_only(project.key())
+      .setRootComponentId(project.getId())
+      .setComponentKey_unit_test_only(resource.key())
+      .setComponentId(resource.getId())
+      .setStatus("OPEN").setResolution("OPEN")
+      .setKee(UUID.randomUUID().toString());
+    dbClient.issueDao().insert(dbSession, issue);
+
+    dbSession.commit();
+
+    searchClient.prepareIndex(IndexDefinition.ISSUES_AUTHENTICATION.getIndexName(), IndexDefinition.ISSUES_AUTHENTICATION.getIndexType())
+      .setId(project.key())
+      .setSource(ImmutableMap.<String, Object>of("permission", "read", "project", project.key(), "user", "julien"))
+      .setRefresh(true)
+      .get();
+
+    // The issue is visible for user julien
+    assertThat(searchIssueWithAuthorization(searchClient, "", "julien").getHits().getTotalHits()).isEqualTo(1);
+    // The issue is not visible for user simon
+    assertThat(searchIssueWithAuthorization(searchClient, "", "simon").getHits().getTotalHits()).isEqualTo(0);
+  }
+
+  private SearchResponse searchIssueWithAuthorization(SearchClient searchClient, String group, String user){
+    SearchRequestBuilder request = searchClient.prepareSearch(IndexDefinition.ISSUES.getIndexName())
+      .setQuery(
+        QueryBuilders.filteredQuery(
+          QueryBuilders.matchAllQuery(),
+          FilterBuilders.hasParentFilter(
+            IndexDefinition.ISSUES_AUTHENTICATION.getIndexType(),
+            FilterBuilders.boolFilter().must(
+              FilterBuilders.termFilter("permission", "read"),
+              FilterBuilders.orFilter(
+                FilterBuilders.termFilter("group", group),
+                FilterBuilders.termFilter("user", user)
+              )
+            ).cache(true)
+          )
+        )
+      )
+      .setSize(Integer.MAX_VALUE);
+    return searchClient.execute(request);
+  }
+
+  private BaseIndex createIssueAuthorizationIndex(final SearchClient searchClient, String index, String type) {
+    BaseIndex baseIndex = new BaseIndex(
+      IndexDefinition.createFor(index, type),
+      null, searchClient) {
+      @Override
+      protected String getKeyValue(Serializable key) {
+        return null;
+      }
+
+      @Override
+      protected org.elasticsearch.common.settings.Settings getIndexSettings() throws IOException {
+        return ImmutableSettings.builder().build();
+      }
+
+      @Override
+      protected Map mapProperties() {
+        Map<String, Object> mapping = new HashMap<String, Object>();
+        mapping.put("permission", mapStringField());
+        mapping.put("project", mapStringField());
+        mapping.put("group", mapStringField());
+        mapping.put("user", mapStringField());
+        return mapping;
+      }
+
+      protected Map mapStringField() {
+        Map<String, Object> mapping = new HashMap<String, Object>();
+        mapping.put("type", "string");
+        mapping.put("index", "analyzed");
+        mapping.put("index_analyzer", "keyword");
+        mapping.put("search_analyzer", "whitespace");
+        return mapping;
+      }
+
+      @Override
+      protected Map mapKey() {
+        return Collections.emptyMap();
+      }
 
+      @Override
+      public Object toDoc(Map fields) {
+        return null;
+      }
+    };
+    baseIndex.start();
+    return baseIndex;
   }
 }