From: Julien Lancelot Date: Tue, 6 Feb 2018 12:58:34 +0000 (+0100) Subject: SONAR-10302 Auto issue assignment is now based on org membership X-Git-Tag: 7.5~1714 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=bb56ae4237f712cb6060dcff1b82edb549767ae0;p=sonarqube.git SONAR-10302 Auto issue assignment is now based on org membership --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/ScmAccountToUserLoader.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/ScmAccountToUserLoader.java index 44092180e59..aeb3e9dfa72 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/ScmAccountToUserLoader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/issue/ScmAccountToUserLoader.java @@ -27,6 +27,7 @@ import java.util.Map; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.core.util.stream.MoreCollectors; +import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolder; import org.sonar.server.user.index.UserDoc; import org.sonar.server.user.index.UserIndex; import org.sonar.server.util.cache.CacheLoader; @@ -37,15 +38,18 @@ import org.sonar.server.util.cache.CacheLoader; public class ScmAccountToUserLoader implements CacheLoader { private static final Logger LOGGER = Loggers.get(ScmAccountToUserLoader.class); + private final UserIndex index; + private final AnalysisMetadataHolder analysisMetadataHolder; - public ScmAccountToUserLoader(UserIndex index) { + public ScmAccountToUserLoader(UserIndex index, AnalysisMetadataHolder analysisMetadataHolder) { this.index = index; + this.analysisMetadataHolder = analysisMetadataHolder; } @Override public String load(String scmAccount) { - List users = index.getAtMostThreeActiveUsersForScmAccount(scmAccount); + List users = index.getAtMostThreeActiveUsersForScmAccount(scmAccount, analysisMetadataHolder.getOrganization().getUuid()); if (users.size() == 1) { return users.get(0).login(); } 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 15f59ce0f5c..c33452c9cd2 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 @@ -81,13 +81,14 @@ public class UserIndex { * Returns the active users (at most 3) who are associated to the given SCM account. This method can be used * to detect user conflicts. */ - public List getAtMostThreeActiveUsersForScmAccount(String scmAccount) { + public List getAtMostThreeActiveUsersForScmAccount(String scmAccount, String organizationUuid) { List result = new ArrayList<>(); if (!StringUtils.isEmpty(scmAccount)) { SearchRequestBuilder request = esClient.prepareSearch(UserIndexDefinition.INDEX_TYPE_USER) .setQuery(boolQuery().must(matchAllQuery()).filter( boolQuery() .must(termQuery(FIELD_ACTIVE, true)) + .must(termQuery(FIELD_ORGANIZATION_UUIDS, organizationUuid)) .should(termQuery(FIELD_LOGIN, scmAccount)) .should(matchQuery(SORTABLE_ANALYZER.subField(FIELD_EMAIL), scmAccount)) .should(matchQuery(SORTABLE_ANALYZER.subField(FIELD_SCM_ACCOUNTS), scmAccount)))) diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/ScmAccountToUserLoaderTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/ScmAccountToUserLoaderTest.java index 99523d36d41..c19b136fe43 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/ScmAccountToUserLoaderTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/issue/ScmAccountToUserLoaderTest.java @@ -20,28 +20,39 @@ package org.sonar.server.computation.task.projectanalysis.issue; import java.util.Collections; +import org.junit.Rule; import org.junit.Test; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.utils.System2; import org.sonar.api.utils.log.LogTester; import org.sonar.api.utils.log.LoggerLevel; +import org.sonar.db.organization.OrganizationDto; +import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule; +import org.sonar.server.computation.task.projectanalysis.analysis.Organization; import org.sonar.server.es.EsTester; import org.sonar.server.user.index.UserDoc; import org.sonar.server.user.index.UserIndex; import org.sonar.server.user.index.UserIndexDefinition; import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; public class ScmAccountToUserLoaderTest { - @org.junit.Rule + private static final String ORGANIZATION_UUID = "my-organization"; + + @Rule public EsTester esTester = new EsTester(new UserIndexDefinition(new MapSettings().asConfig())); - @org.junit.Rule + @Rule public LogTester logTester = new LogTester(); + @Rule + public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule() + .setOrganization(Organization.from(new OrganizationDto().setUuid(ORGANIZATION_UUID).setKey("Key").setName("Name").setDefaultQualityGateUuid("QGate"))); + @Test public void load_login_for_scm_account() { UserDoc user = new UserDoc() @@ -49,11 +60,12 @@ public class ScmAccountToUserLoaderTest { .setName("Charlie") .setEmail("charlie@hebdo.com") .setActive(true) - .setScmAccounts(asList("charlie", "jesuis@charlie.com")); + .setScmAccounts(asList("charlie", "jesuis@charlie.com")) + .setOrganizationUuids(singletonList(ORGANIZATION_UUID)); esTester.putDocuments(UserIndexDefinition.INDEX_TYPE_USER.getIndex(), UserIndexDefinition.INDEX_TYPE_USER.getType(), user); UserIndex index = new UserIndex(esTester.client(), System2.INSTANCE); - ScmAccountToUserLoader underTest = new ScmAccountToUserLoader(index); + ScmAccountToUserLoader underTest = new ScmAccountToUserLoader(index, analysisMetadataHolder); assertThat(underTest.load("missing")).isNull(); assertThat(underTest.load("jesuis@charlie.com")).isEqualTo("charlie"); @@ -66,18 +78,20 @@ public class ScmAccountToUserLoaderTest { .setName("Charlie") .setEmail("charlie@hebdo.com") .setActive(true) - .setScmAccounts(asList("charlie", "jesuis@charlie.com")); + .setScmAccounts(asList("charlie", "jesuis@charlie.com")) + .setOrganizationUuids(singletonList(ORGANIZATION_UUID)); esTester.putDocuments(UserIndexDefinition.INDEX_TYPE_USER.getIndex(), UserIndexDefinition.INDEX_TYPE_USER.getType(), user1); UserDoc user2 = new UserDoc() .setLogin("another.charlie") .setName("Another Charlie") .setActive(true) - .setScmAccounts(asList("charlie")); + .setScmAccounts(singletonList("charlie")) + .setOrganizationUuids(singletonList(ORGANIZATION_UUID)); esTester.putDocuments(UserIndexDefinition.INDEX_TYPE_USER.getIndex(), UserIndexDefinition.INDEX_TYPE_USER.getType(), user2); UserIndex index = new UserIndex(esTester.client(), System2.INSTANCE); - ScmAccountToUserLoader underTest = new ScmAccountToUserLoader(index); + ScmAccountToUserLoader underTest = new ScmAccountToUserLoader(index, analysisMetadataHolder); assertThat(underTest.load("charlie")).isNull(); assertThat(logTester.logs(LoggerLevel.WARN)).contains("Multiple users share the SCM account 'charlie': another.charlie, charlie"); @@ -86,7 +100,7 @@ public class ScmAccountToUserLoaderTest { @Test public void load_by_multiple_scm_accounts_is_not_supported_yet() { UserIndex index = new UserIndex(esTester.client(), System2.INSTANCE); - ScmAccountToUserLoader underTest = new ScmAccountToUserLoader(index); + ScmAccountToUserLoader underTest = new ScmAccountToUserLoader(index, analysisMetadataHolder); try { underTest.loadAll(Collections.emptyList()); fail(); 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 3ed10b6452a..45af16daf7b 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 @@ -33,11 +33,13 @@ import org.sonar.server.es.SearchOptions; import static com.google.common.collect.Lists.newArrayList; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.server.user.index.UserIndexDefinition.INDEX_TYPE_USER; public class UserIndexTest { + private static final String ORGANIZATION_UUID = "my-organization"; private static final String USER1_LOGIN = "user1"; private static final String USER2_LOGIN = "user2"; private static final long DATE_1 = 1_500_000_000_000L; @@ -91,24 +93,24 @@ public class UserIndexTest { esTester.putDocuments(INDEX_TYPE_USER, user2); esTester.putDocuments(INDEX_TYPE_USER, user3); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount(user1.scmAccounts().get(0))).extractingResultOf("login").containsOnly(user1.login()); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount(user1.login())).extractingResultOf("login").containsOnly(user1.login()); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount(user1.scmAccounts().get(0), ORGANIZATION_UUID)).extractingResultOf("login").containsOnly(user1.login()); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount(user1.login(), ORGANIZATION_UUID)).extractingResultOf("login").containsOnly(user1.login()); // both users share the same email - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount(user1.email())).extracting(UserDoc::login).containsOnly(user1.login(), user2.login()); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount(user1.email(), ORGANIZATION_UUID)).extracting(UserDoc::login).containsOnly(user1.login(), user2.login()); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("")).isEmpty(); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("unknown")).isEmpty(); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("", ORGANIZATION_UUID)).isEmpty(); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("unknown", ORGANIZATION_UUID)).isEmpty(); } @Test public void getAtMostThreeActiveUsersForScmAccount_ignores_inactive_user() { String scmAccount = "scmA"; - UserDoc user = newUser(USER1_LOGIN, asList(scmAccount)).setActive(false); + UserDoc user = newUser(USER1_LOGIN, singletonList(scmAccount)).setActive(false); esTester.putDocuments(INDEX_TYPE_USER, user); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount(user.login())).isEmpty(); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount(scmAccount)).isEmpty(); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount(user.login(), ORGANIZATION_UUID)).isEmpty(); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount(scmAccount, ORGANIZATION_UUID)).isEmpty(); } @Test @@ -124,37 +126,47 @@ public class UserIndexTest { esTester.putDocuments(INDEX_TYPE_USER, user4); // restrict results to 3 users - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount(email)).hasSize(3); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount(email, ORGANIZATION_UUID)).hasSize(3); } @Test public void getAtMostThreeActiveUsersForScmAccount_is_case_sensitive_for_login() { - UserDoc user = newUser("the_login", asList("John.Smith")); + UserDoc user = newUser("the_login", singletonList("John.Smith")); esTester.putDocuments(INDEX_TYPE_USER, user); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("the_login")).hasSize(1); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("the_Login")).isEmpty(); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("the_login", ORGANIZATION_UUID)).hasSize(1); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("the_Login", ORGANIZATION_UUID)).isEmpty(); } @Test public void getAtMostThreeActiveUsersForScmAccount_is_case_insensitive_for_email() { - UserDoc user = newUser("the_login", "the_EMAIL@corp.com", asList("John.Smith")); + UserDoc user = newUser("the_login", "the_EMAIL@corp.com", singletonList("John.Smith")); esTester.putDocuments(INDEX_TYPE_USER, user); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("the_EMAIL@corp.com")).hasSize(1); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("the_email@corp.com")).hasSize(1); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("email")).isEmpty(); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("the_EMAIL@corp.com", ORGANIZATION_UUID)).hasSize(1); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("the_email@corp.com", ORGANIZATION_UUID)).hasSize(1); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("email", ORGANIZATION_UUID)).isEmpty(); } @Test public void getAtMostThreeActiveUsersForScmAccount_is_case_insensitive_for_scm_account() { - UserDoc user = newUser("the_login", asList("John.Smith")); + UserDoc user = newUser("the_login", singletonList("John.Smith")); esTester.putDocuments(INDEX_TYPE_USER, user); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("John.Smith")).hasSize(1); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("JOHN.SMIth")).hasSize(1); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("JOHN.SMITH")).hasSize(1); - assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("JOHN")).isEmpty(); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("John.Smith", ORGANIZATION_UUID)).hasSize(1); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("JOHN.SMIth", ORGANIZATION_UUID)).hasSize(1); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("JOHN.SMITH", ORGANIZATION_UUID)).hasSize(1); + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("JOHN", ORGANIZATION_UUID)).isEmpty(); + } + + @Test + public void getAtMostThreeActiveUsersForScmAccount_search_only_user_within_given_organization() { + UserDoc user1 = newUser("user1", singletonList("same_scm")).setOrganizationUuids(singletonList(ORGANIZATION_UUID)); + UserDoc user2 = newUser("user2", singletonList("same_scm")).setOrganizationUuids(singletonList("another_organization")); + esTester.putDocuments(INDEX_TYPE_USER, user1); + esTester.putDocuments(INDEX_TYPE_USER, user2); + + assertThat(underTest.getAtMostThreeActiveUsersForScmAccount("same_scm", ORGANIZATION_UUID)).extractingResultOf("login").containsOnly(user1.login()); } @Test @@ -201,7 +213,8 @@ public class UserIndexTest { .setName(login.toUpperCase(Locale.ENGLISH)) .setEmail(login + "@mail.com") .setActive(true) - .setScmAccounts(scmAccounts); + .setScmAccounts(scmAccounts) + .setOrganizationUuids(singletonList(ORGANIZATION_UUID)); } private static UserDoc newUser(String login, String email, List scmAccounts) { @@ -210,6 +223,7 @@ public class UserIndexTest { .setName(login.toUpperCase(Locale.ENGLISH)) .setEmail(email) .setActive(true) - .setScmAccounts(scmAccounts); + .setScmAccounts(scmAccounts) + .setOrganizationUuids(singletonList(ORGANIZATION_UUID)); } } diff --git a/tests/src/test/java/org/sonarqube/tests/Category6Suite.java b/tests/src/test/java/org/sonarqube/tests/Category6Suite.java index 27db0db9d0d..dd8ecd2876b 100644 --- a/tests/src/test/java/org/sonarqube/tests/Category6Suite.java +++ b/tests/src/test/java/org/sonarqube/tests/Category6Suite.java @@ -29,7 +29,6 @@ import org.sonarqube.tests.authorization.PermissionTemplateTest; import org.sonarqube.tests.ce.ReportFailureNotificationTest; import org.sonarqube.tests.issue.IssueNotificationsTest; import org.sonarqube.tests.issue.IssueTagsTest; -import org.sonarqube.tests.issue.OrganizationIssueAssignTest; import org.sonarqube.tests.issue.OrganizationIssuesPageTest; import org.sonarqube.tests.qualityProfile.BuiltInQualityProfilesTest; import org.sonarqube.tests.qualityProfile.CustomQualityProfilesTest; @@ -53,7 +52,6 @@ import static util.ItUtils.xooPlugin; @RunWith(Suite.class) @Suite.SuiteClasses({ OrganizationIdentityProviderTest.class, - OrganizationIssueAssignTest.class, OrganizationIssuesPageTest.class, OrganizationQualityProfilesUiTest.class, BuiltInQualityProfilesTest.class, diff --git a/tests/src/test/java/org/sonarqube/tests/issue/OrganizationIssueAssignTest.java b/tests/src/test/java/org/sonarqube/tests/issue/OrganizationIssueAssignTest.java index 4e76ba14180..01e8e141431 100644 --- a/tests/src/test/java/org/sonarqube/tests/issue/OrganizationIssueAssignTest.java +++ b/tests/src/test/java/org/sonarqube/tests/issue/OrganizationIssueAssignTest.java @@ -21,24 +21,22 @@ package org.sonarqube.tests.issue; import com.sonar.orchestrator.Orchestrator; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; -import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.sonarqube.qa.util.Tester; import org.sonarqube.qa.util.pageobjects.issues.IssuesPage; -import org.sonarqube.tests.Category6Suite; import org.sonarqube.ws.Issues; import org.sonarqube.ws.Issues.Issue; -import org.sonarqube.ws.Organizations; +import org.sonarqube.ws.Organizations.Organization; +import org.sonarqube.ws.Projects.CreateWsResponse.Project; +import org.sonarqube.ws.Qualityprofiles.CreateWsResponse.QualityProfile; import org.sonarqube.ws.Users.CreateWsResponse.User; import org.sonarqube.ws.client.issues.AssignRequest; import org.sonarqube.ws.client.issues.BulkChangeRequest; import org.sonarqube.ws.client.issues.SearchRequest; -import org.sonarqube.ws.client.qualityprofiles.AddProjectRequest; -import org.sonarqube.ws.client.projects.CreateRequest; -import util.issue.IssueRule; import static java.lang.String.format; import static java.util.Collections.singletonList; @@ -46,101 +44,120 @@ import static org.assertj.core.api.Assertions.assertThat; import static util.ItUtils.expectHttpError; import static util.ItUtils.restoreProfile; import static util.ItUtils.runProjectAnalysis; -import static util.ItUtils.setServerProperty; public class OrganizationIssueAssignTest { private final static String SAMPLE_PROJECT_KEY = "sample"; @ClassRule - public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; + public static Orchestrator orchestrator = OrganizationIssueSuite.ORCHESTRATOR; @Rule public Tester tester = new Tester(orchestrator); - @Rule - public IssueRule issueRule = IssueRule.from(orchestrator); - - private Organizations.Organization org1; - private Organizations.Organization org2; - private User user; - - @Before - public void setUp() { - org1 = tester.organizations().generate(); - org2 = tester.organizations().generate(); - user = tester.users().generate(); - restoreProfile(orchestrator, getClass().getResource("/organization/IssueAssignTest/one-issue-per-file-profile.xml"), org1.getKey()); - } - @Test - public void auto_assign_issues_to_user_if_default_assignee_is_member_of_project_organization() { - tester.organizations().addMember(org1, user); + public void auto_assign_issues_to_default_assignee_if_member_of_project_organization() { + Organization organization = tester.organizations().generate(); + User user = tester.users().generateMember(organization); + provisionProjectAndAssociateItToQProfile(SAMPLE_PROJECT_KEY, organization); + tester.settings().setProjectSetting("sample", "sonar.issues.defaultAssigneeLogin", user.getLogin()); - provisionProject(SAMPLE_PROJECT_KEY, org1.getKey()); - setServerProperty(orchestrator, "sample", "sonar.issues.defaultAssigneeLogin", user.getLogin()); + analyseProject(SAMPLE_PROJECT_KEY, organization); - analyseProject(SAMPLE_PROJECT_KEY, org1.getKey()); - - assertThat(issueRule.getRandomIssue().getAssignee()).isEqualTo(user.getLogin()); + assertThat(getRandomIssue().getAssignee()).isEqualTo(user.getLogin()); } @Test - public void does_not_auto_assign_issues_to_user_if_default_assignee_is_not_member_of_project_organization() { - tester.organizations().addMember(org2, user); - provisionProject(SAMPLE_PROJECT_KEY, org1.getKey()); - setServerProperty(orchestrator, "sample", "sonar.issues.defaultAssigneeLogin", user.getLogin()); + public void do_not_auto_assign_issues_to_default_assignee_if_not_member_of_project_organization() { + Organization organization1 = tester.organizations().generate(); + Organization organization2 = tester.organizations().generate(); + User user = tester.users().generateMember(organization2); + provisionProjectAndAssociateItToQProfile(SAMPLE_PROJECT_KEY, organization1); + tester.settings().setProjectSetting("sample", "sonar.issues.defaultAssigneeLogin", user.getLogin()); + + analyseProject(SAMPLE_PROJECT_KEY, organization1); - analyseProject(SAMPLE_PROJECT_KEY, org1.getKey()); + assertThat(getRandomIssue().hasAssignee()).isFalse(); + } - assertThat(issueRule.getRandomIssue().hasAssignee()).isFalse(); + /** + * SONAR-10302 + */ + @Test + public void do_not_auto_assign_issues_to_user_if_assignee_is_not_member_of_project_organization() { + Organization organization1 = tester.organizations().generate(); + Organization organization2 = tester.organizations().generate(); + User fabrice = tester.users().generateMember(organization1, u -> u.setScmAccount(singletonList("fabrice"))); + // Simon is not member of project's organization, no issue should be assigned to him + User simon = tester.users().generateMember(organization2, u -> u.setScmAccount(singletonList("simon"))); + provisionProjectAndAssociateItToQProfile(SAMPLE_PROJECT_KEY, organization1); + + analyseProject(SAMPLE_PROJECT_KEY, organization1); + + Set assignees = tester.wsClient().issues().search(new SearchRequest().setComponentKeys(singletonList(SAMPLE_PROJECT_KEY))).getIssuesList() + .stream() + .map(Issue::getAssignee) + .filter(s -> !s.isEmpty()) + .collect(Collectors.toSet()); + assertThat(assignees) + .containsOnly(fabrice.getLogin()) + .doesNotContain(simon.getLogin()); } @Test public void assign_issue_to_user_being_member_of_same_organization_as_project_issue_organization() { - tester.organizations().addMember(org1, user); - provisionAndAnalyseProject(SAMPLE_PROJECT_KEY, org1.getKey()); - Issue issue = issueRule.getRandomIssue(); + Organization organization = tester.organizations().generate(); + User user = tester.users().generateMember(organization); + provisionAndAnalyseProject(SAMPLE_PROJECT_KEY, organization); + Issue issue = getRandomIssue(); assignIssueTo(issue, user); - assertThat(issueRule.getByKey(issue.getKey()).getAssignee()).isEqualTo(user.getLogin()); + assertThat(getByKey(issue.getKey()).getAssignee()).isEqualTo(user.getLogin()); } @Test public void fail_to_assign_issue_to_user_not_being_member_of_same_organization_as_project_issue_organization() { - tester.organizations().addMember(org2, user); - provisionAndAnalyseProject(SAMPLE_PROJECT_KEY, org1.getKey()); - Issue issue = issueRule.getRandomIssue(); + Organization organization1 = tester.organizations().generate(); + Organization organization2 = tester.organizations().generate(); + User user = tester.users().generateMember(organization2); + provisionAndAnalyseProject(SAMPLE_PROJECT_KEY, organization1); + Issue issue = getRandomIssue(); expectHttpError(400, - format("User '%s' is not member of organization '%s'", user.getLogin(), org1.getKey()), + format("User '%s' is not member of organization '%s'", user.getLogin(), organization1.getKey()), () -> assignIssueTo(issue, user)); } @Test public void bulk_assign_issues_to_user_being_only_member_of_same_organization_as_project_issue_organization() { - restoreProfile(orchestrator, getClass().getResource("/organization/IssueAssignTest/one-issue-per-file-profile.xml"), org2.getKey()); + Organization organization1 = tester.organizations().generate(); + Organization organization2 = tester.organizations().generate(); // User is only member of org1, not of org2 - tester.organizations().addMember(org1, user); - provisionAndAnalyseProject(SAMPLE_PROJECT_KEY, org1.getKey()); - provisionAndAnalyseProject("sample2", org2.getKey()); - List issues = issueRule.search(new SearchRequest()).getIssuesList().stream().map(Issue::getKey).collect(Collectors.toList()); + User user = tester.users().generateMember(organization1); + + restoreProfile(orchestrator, getClass().getResource("/organization/IssueAssignTest/one-issue-per-file-profile.xml"), organization2.getKey()); + + provisionAndAnalyseProject(SAMPLE_PROJECT_KEY, organization1); + provisionAndAnalyseProject("sample2", organization2); + List issues = tester.wsClient().issues().search(new SearchRequest()).getIssuesList().stream().map(Issue::getKey).collect(Collectors.toList()); Issues.BulkChangeWsResponse response = tester.wsClient().issues() .bulkChange(new BulkChangeRequest().setIssues(issues).setAssign(singletonList(user.getLogin()))); assertThat(response.getIgnored()).isGreaterThan(0); - assertThat(issueRule.search(new SearchRequest().setProjects(singletonList("sample"))).getIssuesList()).extracting(Issue::getAssignee) + assertThat(tester.wsClient().issues().search(new SearchRequest().setProjects(singletonList("sample"))).getIssuesList()).extracting(Issue::getAssignee) .containsOnly(user.getLogin()); - assertThat(issueRule.search(new SearchRequest().setProjects(singletonList("sample2"))).getIssuesList()).extracting(Issue::hasAssignee) + assertThat(tester.wsClient().issues().search(new SearchRequest().setProjects(singletonList("sample2"))).getIssuesList()).extracting(Issue::hasAssignee) .containsOnly(false); } @Test public void single_assign_search_show_only_members_in_global_issues() { - tester.organizations().addMember(org1, user); + Organization organization = tester.organizations().generate(); + User user = tester.users().generateMember(organization); User otherUser = tester.users().generate(); - provisionAndAnalyseProject(SAMPLE_PROJECT_KEY, org1.getKey()); + provisionAndAnalyseProject(SAMPLE_PROJECT_KEY, organization); + IssuesPage page = tester.openBrowser().logIn().submitCredentials(user.getLogin()).openIssues(); page.getFirstIssue() .shouldAllowAssign() @@ -150,10 +167,11 @@ public class OrganizationIssueAssignTest { @Test public void bulk_assign_search_only_members_of_organization_in_project_issues() { - tester.organizations().addMember(org1, user); + Organization organization = tester.organizations().generate(); + User user = tester.users().generateMember(organization); User otherUser = tester.users().generate(); + provisionAndAnalyseProject(SAMPLE_PROJECT_KEY, organization); - provisionAndAnalyseProject(SAMPLE_PROJECT_KEY, org1.getKey()); IssuesPage page = tester.openBrowser() .logIn().submitCredentials(user.getLogin()) .openComponentIssues(SAMPLE_PROJECT_KEY); @@ -165,9 +183,10 @@ public class OrganizationIssueAssignTest { @Test public void bulk_assign_search_all_users_in_global_issues() { - tester.organizations().addMember(org1, user); + Organization organization = tester.organizations().generate(); + User user = tester.users().generateMember(organization); User otherUser = tester.users().generate(); - provisionAndAnalyseProject(SAMPLE_PROJECT_KEY, org1.getKey()); + provisionAndAnalyseProject(SAMPLE_PROJECT_KEY, organization); IssuesPage page = tester.openBrowser() .logIn().submitCredentials(user.getLogin()) .openIssues(); @@ -177,37 +196,44 @@ public class OrganizationIssueAssignTest { .bulkChangeAssigneeSearchCount(otherUser.getLogin(), 1); } - private void provisionAndAnalyseProject(String projectKey, String organization) { - provisionProject(projectKey, organization); + private void provisionAndAnalyseProject(String projectKey, Organization organization) { + provisionProjectAndAssociateItToQProfile(projectKey, organization); analyseProject(projectKey, organization); } - private void provisionProject(String projectKey, String organization) { - tester.wsClient().projects().create( - new CreateRequest() - .setProject(projectKey) - .setName(projectKey) - .setOrganization(organization)); + private void provisionProjectAndAssociateItToQProfile(String projectKey, Organization organization) { + Project project = tester.projects().provision(organization, p -> p.setProject(projectKey)); + QualityProfile profile = tester.qProfiles().createXooProfile(organization); + tester.qProfiles() + .activateRule(profile, "xoo:OneIssuePerLine") + .assignQProfileToProject(profile, project); } - private void analyseProject(String projectKey, String organization) { - addQualityProfileToProject(organization, projectKey); + private void analyseProject(String projectKey, Organization organization) { runProjectAnalysis(orchestrator, "issue/xoo-with-scm", "sonar.projectKey", projectKey, - "sonar.organization", organization, + "sonar.organization", organization.getKey(), "sonar.login", "admin", "sonar.password", "admin", "sonar.scm.disabled", "false", "sonar.scm.provider", "xoo"); } - private void addQualityProfileToProject(String organization, String projectKey) { - tester.wsClient().qualityprofiles().addProject( - new AddProjectRequest() - .setProject(projectKey) - .setOrganization(organization) - .setLanguage("xoo") - .setQualityProfile("one-issue-per-file-profile")); + private Issues.Issue getByKey(String issueKey) { + return tester.wsClient().issues().search( + new SearchRequest() + .setComponentKeys(singletonList(SAMPLE_PROJECT_KEY)) + .setIssues(singletonList(issueKey))) + .getIssuesList() + .get(0); + } + + private Issues.Issue getRandomIssue() { + return tester.wsClient().issues().search( + new SearchRequest() + .setComponentKeys(singletonList(SAMPLE_PROJECT_KEY))) + .getIssuesList() + .get(0); } private Issues.AssignResponse assignIssueTo(Issue issue, User u) { diff --git a/tests/src/test/java/org/sonarqube/tests/issue/OrganizationIssueSuite.java b/tests/src/test/java/org/sonarqube/tests/issue/OrganizationIssueSuite.java new file mode 100644 index 00000000000..2babb0d1985 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/issue/OrganizationIssueSuite.java @@ -0,0 +1,44 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonarqube.tests.issue; + +import com.sonar.orchestrator.Orchestrator; +import org.junit.ClassRule; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +import static util.ItUtils.xooPlugin; + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + OrganizationIssueAssignTest.class +}) +public class OrganizationIssueSuite { + + @ClassRule + public static final Orchestrator ORCHESTRATOR = Orchestrator.builderEnv() + .addPlugin(xooPlugin()) + + // reduce memory for Elasticsearch to 128M + .setServerProperty("sonar.search.javaOpts", "-Xms128m -Xmx128m") + + .build(); + +}