diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-05-05 17:12:17 +0200 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-05-09 11:55:58 +0200 |
commit | 68acdc5ba2456d2a7b871a1c8f85eebf246f175d (patch) | |
tree | cd4203746bfb1e338c889ea239da54c99679babb | |
parent | f16448e9832492b7c9e9ba4c929d19af4994c6f0 (diff) | |
download | sonarqube-68acdc5ba2456d2a7b871a1c8f85eebf246f175d.tar.gz sonarqube-68acdc5ba2456d2a7b871a1c8f85eebf246f175d.zip |
SONAR-9084 auto issue assignment should deal with case sensitivity
- login is case sensitive
- email and scm accounts match whatever the case
8 files changed, 98 insertions, 36 deletions
diff --git a/it/it-projects/issue/AutoAssignTest/sonar-project.properties b/it/it-projects/issue/AutoAssignTest/sonar-project.properties new file mode 100644 index 00000000000..3a14309e6c2 --- /dev/null +++ b/it/it-projects/issue/AutoAssignTest/sonar-project.properties @@ -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 index 00000000000..83572801d71 --- /dev/null +++ b/it/it-projects/issue/AutoAssignTest/src/sample.xoo @@ -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 index 00000000000..7bb5f438500 --- /dev/null +++ b/it/it-projects/issue/AutoAssignTest/src/sample.xoo.measures @@ -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 index 00000000000..d469fe05994 --- /dev/null +++ b/it/it-projects/issue/AutoAssignTest/src/sample.xoo.scm @@ -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 diff --git a/it/it-tests/src/test/java/it/issue/AutoAssignTest.java b/it/it-tests/src/test/java/it/issue/AutoAssignTest.java index d4293c551ee..6110c02f245 100644 --- a/it/it-tests/src/test/java/it/issue/AutoAssignTest.java +++ b/it/it-tests/src/test/java/it/issue/AutoAssignTest.java @@ -19,15 +19,20 @@ */ 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())); + }); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndex.java b/server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndex.java index 517e6a7e463..9b0613059ab 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndex.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndex.java @@ -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())); diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexDefinition.java b/server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexDefinition.java index ace94fdfac9..2270ccff34b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexDefinition.java +++ b/server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexDefinition.java @@ -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(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/index/UserIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/index/UserIndexTest.java index 5a8a731e6be..9a572262c1b 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/user/index/UserIndexTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/user/index/UserIndexTest.java @@ -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 |