]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9084 auto issue assignment should deal with case sensitivity
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Fri, 5 May 2017 15:12:17 +0000 (17:12 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Tue, 9 May 2017 09:55:58 +0000 (11:55 +0200)
- login is case sensitive
- email and scm accounts match whatever the case

it/it-projects/issue/AutoAssignTest/sonar-project.properties [new file with mode: 0644]
it/it-projects/issue/AutoAssignTest/src/sample.xoo [new file with mode: 0644]
it/it-projects/issue/AutoAssignTest/src/sample.xoo.measures [new file with mode: 0644]
it/it-projects/issue/AutoAssignTest/src/sample.xoo.scm [new file with mode: 0644]
it/it-tests/src/test/java/it/issue/AutoAssignTest.java
server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndex.java
server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexDefinition.java
server/sonar-server/src/test/java/org/sonar/server/user/index/UserIndexTest.java

diff --git a/it/it-projects/issue/AutoAssignTest/sonar-project.properties b/it/it-projects/issue/AutoAssignTest/sonar-project.properties
new file mode 100644 (file)
index 0000000..3a14309
--- /dev/null
@@ -0,0 +1,4 @@
+sonar.projectKey=AutoAssignTest
+sonar.projectName=AutoAssignTest
+sonar.projectVersion=1.0-SNAPSHOT
+sonar.sources=src
diff --git a/it/it-projects/issue/AutoAssignTest/src/sample.xoo b/it/it-projects/issue/AutoAssignTest/src/sample.xoo
new file mode 100644 (file)
index 0000000..8357280
--- /dev/null
@@ -0,0 +1,8 @@
+line
+line
+line
+line
+line
+line
+line
+line
diff --git a/it/it-projects/issue/AutoAssignTest/src/sample.xoo.measures b/it/it-projects/issue/AutoAssignTest/src/sample.xoo.measures
new file mode 100644 (file)
index 0000000..7bb5f43
--- /dev/null
@@ -0,0 +1 @@
+ncloc:8
diff --git a/it/it-projects/issue/AutoAssignTest/src/sample.xoo.scm b/it/it-projects/issue/AutoAssignTest/src/sample.xoo.scm
new file mode 100644 (file)
index 0000000..d469fe0
--- /dev/null
@@ -0,0 +1,9 @@
+1,user1,2011-12-04
+2,user2,2011-12-04
+3,user3Name,2011-12-04
+4,user4Name,2011-12-04
+5,user5@email.com,2015-12-04
+6,user6@email.com,2015-12-04
+7,user7ScmAccount,2015-12-04
+8,user8ScmAccount,2015-12-04
+9,user8ScmAccount,2015-12-04
index d4293c551eea358440f91acd077e106389730fbd..6110c02f245f5cf63832f421ea0c93f2d1741ea5 100644 (file)
  */
 package it.issue;
 
+import java.util.Arrays;
 import java.util.List;
+import javax.annotation.Nullable;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.sonar.wsclient.issue.Issue;
 import org.sonar.wsclient.issue.IssueQuery;
+import org.sonarqube.ws.WsUsers;
 import org.sonarqube.ws.client.PostRequest;
-import org.sonarqube.ws.client.WsResponse;
+import org.sonarqube.ws.client.WsClient;
+import org.sonarqube.ws.client.user.CreateRequest;
+import org.sonarqube.ws.client.user.SearchRequest;
 import util.ProjectAnalysis;
 import util.ProjectAnalysisRule;
 
@@ -37,8 +42,6 @@ import static util.ItUtils.setServerProperty;
 
 public class AutoAssignTest extends AbstractIssueTest {
 
-  static final String SIMON_USER = "simon";
-
   @Rule
   public final ProjectAnalysisRule projectAnalysisRule = ProjectAnalysisRule.from(ORCHESTRATOR);
 
@@ -46,10 +49,8 @@ public class AutoAssignTest extends AbstractIssueTest {
 
   @Before
   public void setup() {
-    ORCHESTRATOR.resetData();
-
     String qualityProfileKey = projectAnalysisRule.registerProfile("/issue/IssueActionTest/xoo-one-issue-per-line-profile.xml");
-    String projectKey = projectAnalysisRule.registerProject("issue/xoo-with-scm");
+    String projectKey = projectAnalysisRule.registerProject("issue/AutoAssignTest");
     projectAnalysis = projectAnalysisRule.newProjectAnalysis(projectKey)
       .withQualityProfile(qualityProfileKey)
       .withProperties("sonar.scm.disabled", "false", "sonar.scm.provider", "xoo");
@@ -57,10 +58,8 @@ public class AutoAssignTest extends AbstractIssueTest {
 
   @After
   public void resetData() throws Exception {
-    // Remove user simon
-    newAdminWsClient(ORCHESTRATOR).wsConnector().call(
-      new PostRequest("api/users/deactivate")
-        .setParam("login", SIMON_USER));
+    newAdminWsClient(ORCHESTRATOR).wsConnector().call(new PostRequest("api/projects/delete").setParam("project", "AutoAssignTest"));
+    deleteAllUsers();
 
     // Reset default assignee
     setServerProperty(ORCHESTRATOR, "sonar.issues.defaultAssigneeLogin", null);
@@ -68,23 +67,50 @@ public class AutoAssignTest extends AbstractIssueTest {
 
   @Test
   public void auto_assign_issues_to_user() throws Exception {
-    createUser(SIMON_USER, SIMON_USER);
+    // verify that login matches, case-sensitive
+    createUser("user1", "User 1", "user1@email.com");
+    createUser("USER2", "User 2", "user2@email.com");
+    // verify that name is not used to match, whatever the case
+    createUser("user3", "User 3", "user3@email.com");
+    createUser("user4", "USER 4", "user4@email.com");
+    // verify that email matches, case-insensitive
+    createUser("user5", "User 5", "user5@email.com");
+    createUser("user6", "User 6", "USER6@email.COM");
+    // verify that SCM account matches, case-insensitive
+    createUser("user7", "User 7", "user7@email.com", "user7ScmAccount");
+    createUser("user8", "User 8", "user8@email.com", "user8SCMaccOUNT");
+
     projectAnalysis.run();
 
-    // Simon has 3 issues
-    assertThat(search(IssueQuery.create().assignees(SIMON_USER)).list()).hasSize(3);
-    // Other issues are not assigned as no user have been created on their author
-    assertThat(search(IssueQuery.create().assigned(false)).list()).hasSize(10);
+    List<Issue> issues = search(IssueQuery.create().components("AutoAssignTest:src/sample.xoo").sort("FILE_LINE")).list();
+    // login match, case-sensitive
+    verifyIssueAssignee(issues, 1, "user1");
+    verifyIssueAssignee(issues, 2, null);
+    // user name is not used to match
+    verifyIssueAssignee(issues, 3, null);
+    verifyIssueAssignee(issues, 4, null);
+    // email match, case-insensitive
+    verifyIssueAssignee(issues, 5, "user5");
+    verifyIssueAssignee(issues, 6, "user6");
+    // SCM account match, case-insensitive
+    verifyIssueAssignee(issues, 7, "user7");
+    verifyIssueAssignee(issues, 8, "user8");
+  }
+
+  private static void verifyIssueAssignee(List<Issue> issues, int line, @Nullable String expectedAssignee) {
+    assertThat(issues.get(line - 1).assignee()).isEqualTo(expectedAssignee);
   }
 
   @Test
   public void auto_assign_issues_to_default_assignee() throws Exception {
-    createUser(SIMON_USER, SIMON_USER);
-    setServerProperty(ORCHESTRATOR, "sonar.issues.defaultAssigneeLogin", SIMON_USER);
+    createUser("user1", "User 1", "user1@email.com");
+    createUser("user2", "User 2", "user2@email.com");
+    setServerProperty(ORCHESTRATOR, "sonar.issues.defaultAssigneeLogin", "user2");
     projectAnalysis.run();
 
-    // Simon has all issues
-    assertThat(search(IssueQuery.create().assignees(SIMON_USER)).list()).hasSize(13);
+    // user1 is assigned to his issues. All other issues are assigned to the default assignee.
+    assertThat(search(IssueQuery.create().assignees("user1")).list()).hasSize(1);
+    assertThat(search(IssueQuery.create().assignees("user2")).list()).hasSize(8);
     // No unassigned issues
     assertThat(search(IssueQuery.create().assigned(false)).list()).isEmpty();
   }
@@ -99,7 +125,7 @@ public class AutoAssignTest extends AbstractIssueTest {
    */
   @Test
   public void update_author_and_assignee_when_scm_is_activated() {
-    createUser(SIMON_USER, SIMON_USER);
+    createUser("user1", "User 1", "user1@email.com");
 
     // Run a first analysis without SCM
     projectAnalysis.withProperties("sonar.scm.disabled", "true").run();
@@ -121,15 +147,25 @@ public class AutoAssignTest extends AbstractIssueTest {
     for (Issue issue : issues) {
       assertThat(issue.author()).isNotEmpty();
     }
-    assertThat(search(IssueQuery.create().assignees(SIMON_USER)).list()).hasSize(3);
+    assertThat(search(IssueQuery.create().assignees("user1")).list()).hasSize(1);
+  }
+
+  private static void createUser(String login, String name, String email, String... scmAccounts) {
+    newAdminWsClient(ORCHESTRATOR).users().create(
+      CreateRequest.builder()
+        .setLogin(login)
+        .setName(name)
+        .setEmail(email)
+        .setPassword("xxxxxxx")
+        .setScmAccounts(Arrays.asList(scmAccounts))
+        .build());
   }
 
-  private void createUser(String login, String password) {
-    WsResponse response = newAdminWsClient(ORCHESTRATOR).wsConnector().call(
-      new PostRequest("api/users/create")
-        .setParam("login", login)
-        .setParam("name", login)
-        .setParam("password", password));
-    assertThat(response.code()).isEqualTo(200);
+  private static void deleteAllUsers() {
+    WsClient wsClient = newAdminWsClient(ORCHESTRATOR);
+    WsUsers.SearchWsResponse searchResponse = wsClient.users().search(SearchRequest.builder().build());
+    searchResponse.getUsersList().forEach(user -> {
+      wsClient.wsConnector().call(new PostRequest("api/users/deactivate").setParam("login", user.getLogin()));
+    });
   }
 }
index 517e6a7e4639975898a445bbd9056c492cbedcfd..9b0613059ab5ecd674c86ca7dfbb9d68f9c89a16 100644 (file)
@@ -47,8 +47,10 @@ import org.sonar.server.es.SearchResult;
 
 import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
 import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
+import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
 import static org.elasticsearch.index.query.QueryBuilders.termQuery;
 import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
+import static org.sonar.server.es.DefaultIndexSettingsElement.SORTABLE_ANALYZER;
 import static org.sonar.server.es.DefaultIndexSettingsElement.USER_SEARCH_GRAMS_ANALYZER;
 import static org.sonar.server.user.index.UserIndexDefinition.FIELD_ACTIVE;
 import static org.sonar.server.user.index.UserIndexDefinition.FIELD_EMAIL;
@@ -91,8 +93,8 @@ public class UserIndex {
           boolQuery()
             .must(termQuery(FIELD_ACTIVE, true))
             .should(termQuery(FIELD_LOGIN, scmAccount))
-            .should(termQuery(FIELD_EMAIL, scmAccount))
-            .should(termQuery(FIELD_SCM_ACCOUNTS, scmAccount))))
+            .should(matchQuery(SORTABLE_ANALYZER.subField(FIELD_EMAIL), scmAccount))
+            .should(matchQuery(SORTABLE_ANALYZER.subField(FIELD_SCM_ACCOUNTS), scmAccount))))
         .setSize(3);
       for (SearchHit hit : request.get().getHits().getHits()) {
         result.add(new UserDoc(hit.sourceAsMap()));
index ace94fdfac948edd509d83f2681ae8c320237257..2270ccff34b49eafa7c31ec0c94e6c89738aef55 100644 (file)
@@ -62,7 +62,7 @@ public class UserIndexDefinition implements IndexDefinition {
     mapping.createDateTimeField(FIELD_CREATED_AT);
     mapping.createDateTimeField(FIELD_UPDATED_AT);
     mapping.createBooleanField(FIELD_ACTIVE);
-    mapping.stringFieldBuilder(FIELD_SCM_ACCOUNTS).disableNorms().build();
+    mapping.stringFieldBuilder(FIELD_SCM_ACCOUNTS).disableNorms().addSubFields(SORTABLE_ANALYZER).build();
     mapping.stringFieldBuilder(FIELD_ORGANIZATION_UUIDS).disableNorms().build();
   }
 }
index 5a8a731e6be4d2cd82af1ec192514efb9cc30804..9a572262c1b16093dd08c2b7b046ff2f82e6d1bd 100644 (file)
@@ -138,22 +138,24 @@ public class UserIndexTest {
   }
 
   @Test
-  public void getAtMostThreeActiveUsersForScmAccount_is_case_sensitive_for_email()  {
+  public void getAtMostThreeActiveUsersForScmAccount_is_case_insensitive_for_email()  {
     UserDoc user = newUser("the_login", "the_EMAIL@corp.com", asList("John.Smith"));
     esTester.putDocuments(INDEX_TYPE_USER, user);
 
     assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("the_EMAIL@corp.com")).hasSize(1);
-    assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("the_email@corp.com")).isEmpty();
+    assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("the_email@corp.com")).hasSize(1);
+    assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("email")).isEmpty();
   }
 
   @Test
-  public void getAtMostThreeActiveUsersForScmAccount_is_case_sensitive_for_scm_account()  {
+  public void getAtMostThreeActiveUsersForScmAccount_is_case_insensitive_for_scm_account()  {
     UserDoc user = newUser("the_login", asList("John.Smith"));
     esTester.putDocuments(INDEX_TYPE_USER, user);
 
     assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("John.Smith")).hasSize(1);
-    assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("JOHN.SMIth")).isEmpty();
-    assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("JOHN.SMITH")).isEmpty();
+    assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("JOHN.SMIth")).hasSize(1);
+    assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("JOHN.SMITH")).hasSize(1);
+    assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("JOHN")).isEmpty();
   }
 
   @Test