diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2017-06-09 17:12:01 +0200 |
---|---|---|
committer | Eric Hartmann <hartmann.eric@gmail.com> | 2017-06-14 15:43:13 +0200 |
commit | dd5713279b5b6beccdb5cc65681dbde25898f035 (patch) | |
tree | 916d99177aefa54a1da27afd9b317a7e182a53b6 | |
parent | 7a163414fe1eeb2be1754d87c9969c4a68105b5e (diff) | |
download | sonarqube-dd5713279b5b6beccdb5cc65681dbde25898f035.tar.gz sonarqube-dd5713279b5b6beccdb5cc65681dbde25898f035.zip |
SONAR-9304 add integration tests
71 files changed, 3008 insertions, 2003 deletions
diff --git a/it/it-tests/src/test/java/it/Category4Suite.java b/it/it-tests/src/test/java/it/Category4Suite.java index 9ab69253da6..cbb752d4a71 100644 --- a/it/it-tests/src/test/java/it/Category4Suite.java +++ b/it/it-tests/src/test/java/it/Category4Suite.java @@ -32,8 +32,7 @@ import it.duplication.NewDuplicationsTest; import it.organization.RootUserTest; import it.projectEvent.EventTest; import it.projectEvent.ProjectActivityPageTest; -import it.qualityProfile.QualityProfilesPageTest; -import it.qualityProfile.QualityProfilesRestoreAndSearchTest; +import it.qualityProfile.QualityProfilesUiTest; import it.serverSystem.HttpHeadersTest; import it.serverSystem.LogsTest; import it.serverSystem.PingTest; @@ -97,8 +96,7 @@ import static util.ItUtils.xooPlugin; WsLocalCallTest.class, WsTest.class, // quality profiles - QualityProfilesRestoreAndSearchTest.class, - QualityProfilesPageTest.class, + QualityProfilesUiTest.class, LogsTest.class }) public class Category4Suite { diff --git a/it/it-tests/src/test/java/it/Category6Suite.java b/it/it-tests/src/test/java/it/Category6Suite.java index edb69c482bf..cb9c6811313 100644 --- a/it/it-tests/src/test/java/it/Category6Suite.java +++ b/it/it-tests/src/test/java/it/Category6Suite.java @@ -20,20 +20,21 @@ package it; import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.http.HttpMethod; import it.issue.IssueTagsTest; import it.issue.OrganizationIssueAssignTest; import it.organization.BillingTest; import it.organization.OrganizationMembershipTest; +import it.organization.OrganizationMembershipUiTest; import it.organization.OrganizationTest; +import it.organization.PersonalOrganizationTest; +import it.organization.RootUserOnOrganizationTest; import it.projectSearch.LeakProjectsPageTest; import it.projectSearch.SearchProjectsTest; -import it.organization.RootUserOnOrganizationTest; -import it.qualityProfile.OrganizationQualityProfilesPageTest; -import it.qualityProfile.QualityProfilesBuiltInTest; +import it.qualityProfile.BuiltInQualityProfilesTest; +import it.qualityProfile.CustomQualityProfilesTest; +import it.qualityProfile.OrganizationQualityProfilesUiTest; import it.uiExtension.OrganizationUiExtensionsTest; import it.user.OrganizationIdentityProviderTest; -import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -49,11 +50,14 @@ import static util.ItUtils.xooPlugin; OrganizationIdentityProviderTest.class, OrganizationIssueAssignTest.class, OrganizationMembershipTest.class, - OrganizationQualityProfilesPageTest.class, + OrganizationMembershipUiTest.class, + OrganizationQualityProfilesUiTest.class, OrganizationTest.class, RootUserOnOrganizationTest.class, OrganizationUiExtensionsTest.class, - QualityProfilesBuiltInTest.class, + PersonalOrganizationTest.class, + BuiltInQualityProfilesTest.class, + CustomQualityProfilesTest.class, BillingTest.class, IssueTagsTest.class, LeakProjectsPageTest.class, @@ -68,17 +72,4 @@ public class Category6Suite { .addPlugin(pluginArtifact("fake-billing-plugin")) .addPlugin(pluginArtifact("ui-extensions-plugin")) .build(); - - @BeforeClass - public static void enableOrganizations() { - enableOrganizationsSupport(); - } - - public static void enableOrganizationsSupport() { - ORCHESTRATOR.getServer() - .newHttpCall("api/organizations/enable_support") - .setMethod(HttpMethod.POST) - .setAdminCredentials() - .execute(); - } } diff --git a/it/it-tests/src/test/java/it/analysis/ReportDumpTest.java b/it/it-tests/src/test/java/it/analysis/ReportDumpTest.java index 9f9a8ee9776..3a632def01a 100644 --- a/it/it-tests/src/test/java/it/analysis/ReportDumpTest.java +++ b/it/it-tests/src/test/java/it/analysis/ReportDumpTest.java @@ -21,13 +21,13 @@ package it.analysis; import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.SonarScanner; +import com.sonar.orchestrator.http.HttpResponse; import it.Category3Suite; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.nio.charset.StandardCharsets; import java.util.Properties; -import okhttp3.Response; import org.apache.commons.io.FileUtils; import org.junit.ClassRule; import org.junit.Test; @@ -64,9 +64,9 @@ public class ReportDumpTest { } private void verifyUrl(String url) throws IOException { - Response response = ItUtils.call(url); + HttpResponse response = orchestrator.getServer().newHttpCall(url).execute(); assertThat(response.isSuccessful()).as(url).isTrue(); - assertThat(response.body().string()).as(url).isNotEmpty(); + assertThat(response.getBodyAsString()).as(url).isNotEmpty(); } } diff --git a/it/it-tests/src/test/java/it/issue/AbstractIssueTest.java b/it/it-tests/src/test/java/it/issue/AbstractIssueTest.java index dc05293a31f..55ddc987572 100644 --- a/it/it-tests/src/test/java/it/issue/AbstractIssueTest.java +++ b/it/it-tests/src/test/java/it/issue/AbstractIssueTest.java @@ -54,30 +54,6 @@ public abstract class AbstractIssueTest { return issueClient().find(issueQuery); } - static Issue searchIssueByKey(String issueKey) { - List<Issue> issues = searchIssues(IssueQuery.create().issues(issueKey)); - assertThat(issues).hasSize(1); - return issues.get(0); - } - - static List<Issue> searchIssues(String... issueKeys) { - return searchIssues(issueKeys, false); - } - - static Issue searchIssue(String issueKey, boolean withComments) { - List<Issue> issues = searchIssues(new String[] {issueKey}, withComments); - assertThat(issues).hasSize(1); - return issues.iterator().next(); - } - - static List<Issue> searchIssues(String[] issueKeys, boolean withComments) { - IssueQuery query = IssueQuery.create().issues(issueKeys); - if (withComments) { - query.urlParams().put("additionalFields", "comments"); - } - return searchIssues(query); - } - static List<Issue> searchIssues() { return searchIssues(IssueQuery.create()); } diff --git a/it/it-tests/src/test/java/it/issue/IssueSearchTest.java b/it/it-tests/src/test/java/it/issue/IssueSearchTest.java index cc8f3f8031f..a0fd5dd81c3 100644 --- a/it/it-tests/src/test/java/it/issue/IssueSearchTest.java +++ b/it/it-tests/src/test/java/it/issue/IssueSearchTest.java @@ -25,6 +25,7 @@ import java.util.Date; import java.util.List; import org.apache.commons.lang.time.DateUtils; import org.assertj.core.api.Fail; +import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -40,13 +41,11 @@ import util.ItUtils; 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; import static org.sonarqube.ws.Issues.SearchWsResponse; import static util.ItUtils.newAdminWsClient; import static util.ItUtils.runProjectAnalysis; import static util.ItUtils.setServerProperty; import static util.ItUtils.toDate; -import static util.ItUtils.verifyHttpException; public class IssueSearchTest extends AbstractIssueTest { @@ -143,10 +142,10 @@ public class IssueSearchTest extends AbstractIssueTest { assertThat(search(IssueQuery.create().rules("xoo:OneIssuePerFile")).list()).hasSize(8); try { - assertThat(search(IssueQuery.create().rules("unknown")).list()).isEmpty(); - fail(); - } catch (Exception e) { - verifyHttpException(e, 400); + search(IssueQuery.create().rules("unknown")); + Assert.fail(); + } catch (org.sonar.wsclient.base.HttpException e) { + assertThat(e.status()).isEqualTo(400); } } diff --git a/it/it-tests/src/test/java/it/issue/IssueTagsTest.java b/it/it-tests/src/test/java/it/issue/IssueTagsTest.java index 09dd6c32823..d7559501931 100644 --- a/it/it-tests/src/test/java/it/issue/IssueTagsTest.java +++ b/it/it-tests/src/test/java/it/issue/IssueTagsTest.java @@ -26,17 +26,17 @@ import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; +import org.sonarqube.ws.Organizations; import org.sonarqube.ws.client.issue.SearchWsRequest; -import org.sonarqube.ws.client.organization.CreateWsRequest; import org.sonarqube.ws.client.permission.AddUserWsRequest; import org.sonarqube.ws.client.project.CreateRequest; import util.ItUtils; +import util.OrganizationRule; import util.user.UserRule; -import static it.Category6Suite.enableOrganizationsSupport; import static java.util.Arrays.asList; import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; import static org.assertj.core.api.Assertions.assertThat; @@ -53,33 +53,26 @@ public class IssueTagsTest { @ClassRule public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - @ClassRule - public static UserRule userRule = UserRule.from(orchestrator); - - private String organizationKey; + @Rule + public UserRule userRule = new UserRule(orchestrator); + @Rule + public OrganizationRule organizationRule = new OrganizationRule(orchestrator); - @BeforeClass - public static void beforeClass() throws Exception { - enableOrganizationsSupport(); - } + private Organizations.Organization organization; @Before - public void setUp() throws Exception { - organizationKey = ItUtils.newOrganizationKey(); - newAdminWsClient(orchestrator).organizations().create(CreateWsRequest.builder() - .setKey(organizationKey) - .setName(organizationKey) - .build()); + public void setUp() { + organization = organizationRule.create(); } @Test - public void getTags() throws Exception { - restoreProfile(orchestrator, IssueTagsTest.class.getResource("/issue/one-issue-per-line-profile.xml"), organizationKey); + public void getTags() { + restoreProfile(orchestrator, IssueTagsTest.class.getResource("/issue/one-issue-per-line-profile.xml"), organization.getKey()); String projectKey = newProjectKey(); ItUtils.newAdminWsClient(orchestrator).projects().create( CreateRequest.builder() .setKey(projectKey) - .setOrganization(organizationKey) + .setOrganization(organization.getKey()) .setName(randomAlphabetic(10)) .setVisibility("private") .build()); @@ -96,7 +89,7 @@ public class IssueTagsTest { { String anonymous = null; String anonymousPassword = null; - assertTags(anonymous, anonymousPassword, organizationKey, publicTags); + assertTags(anonymous, anonymousPassword, organization.getKey(), publicTags); assertTags(anonymous, anonymousPassword, defaultOrganization, publicTags); } @@ -105,7 +98,7 @@ public class IssueTagsTest { String stranger = randomAlphabetic(10).toLowerCase(); String strangerPassword = randomAlphabetic(8); userRule.createUser(stranger, strangerPassword); - assertTags(stranger, strangerPassword, organizationKey, publicTags); + assertTags(stranger, strangerPassword, organization.getKey(), publicTags); assertTags(stranger, strangerPassword, defaultOrganization, publicTags); } @@ -116,13 +109,13 @@ public class IssueTagsTest { userRule.createUser(member, memberPassword); addMember(member); grantUserPermission(projectKey, member); - assertTags(member, memberPassword, organizationKey, privateTags); + assertTags(member, memberPassword, organization.getKey(), privateTags); assertTags(member, memberPassword, defaultOrganization, publicTags); } } private void addMember(String member) { - newAdminWsClient(orchestrator).organizations().addMember(organizationKey, member); + newAdminWsClient(orchestrator).organizations().addMember(organization.getKey(), member); } private void grantUserPermission(String projectKey, String member) { @@ -147,7 +140,7 @@ public class IssueTagsTest { private void analyzeProject(String projectKey) { List<String> keyValueProperties = new ArrayList<>(asList( "sonar.projectKey", projectKey, - "sonar.organization", organizationKey, + "sonar.organization", organization.getKey(), "sonar.profile", "one-issue-per-line-profile", "sonar.login", "admin", "sonar.password", "admin", "sonar.scm.disabled", "false")); diff --git a/it/it-tests/src/test/java/it/issue/OrganizationIssueAssignTest.java b/it/it-tests/src/test/java/it/issue/OrganizationIssueAssignTest.java index af5b8e0b76b..61a85920f72 100644 --- a/it/it-tests/src/test/java/it/issue/OrganizationIssueAssignTest.java +++ b/it/it-tests/src/test/java/it/issue/OrganizationIssueAssignTest.java @@ -24,9 +24,7 @@ import com.sonar.orchestrator.Orchestrator; import it.Category6Suite; import java.util.List; import java.util.stream.Collectors; -import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; @@ -38,19 +36,17 @@ import org.sonarqube.ws.client.WsClient; import org.sonarqube.ws.client.issue.AssignRequest; import org.sonarqube.ws.client.issue.BulkChangeRequest; import org.sonarqube.ws.client.issue.SearchWsRequest; -import org.sonarqube.ws.client.organization.CreateWsRequest; import org.sonarqube.ws.client.project.CreateRequest; import org.sonarqube.ws.client.qualityprofile.AddProjectRequest; import pageobjects.Navigation; import pageobjects.issues.IssuesPage; +import util.OrganizationRule; import util.issue.IssueRule; import util.user.UserRule; -import static it.Category6Suite.enableOrganizationsSupport; import static java.lang.String.format; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.deleteOrganizations; import static util.ItUtils.newAdminWsClient; import static util.ItUtils.newOrganizationKey; import static util.ItUtils.restoreProfile; @@ -68,38 +64,26 @@ public class OrganizationIssueAssignTest { @Rule public ExpectedException expectedException = ExpectedException.none(); - @Rule - public Navigation nav = Navigation.get(orchestrator); - @ClassRule public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - @ClassRule - public static UserRule userRule = UserRule.from(orchestrator); - - @ClassRule - public static IssueRule issueRule = IssueRule.from(orchestrator); + @Rule + public OrganizationRule organizations = new OrganizationRule(orchestrator); + @Rule + public UserRule userRule = new UserRule(orchestrator); + @Rule + public IssueRule issueRule = IssueRule.from(orchestrator); + @Rule + public Navigation nav = Navigation.get(orchestrator); private WsClient adminClient = newAdminWsClient(orchestrator); - @BeforeClass - public static void enableOrganizations() throws Exception { - enableOrganizationsSupport(); - } - @Before public void setUp() throws Exception { - userRule.deactivateUsers(ASSIGNEE_LOGIN, OTHER_LOGIN); createOrganization(ORGANIZATION_KEY); restoreProfile(orchestrator, getClass().getResource("/organization/IssueAssignTest/one-issue-per-file-profile.xml"), ORGANIZATION_KEY); } - @After - public void tearDown() throws Exception { - userRule.deactivateUsers(ASSIGNEE_LOGIN, OTHER_LOGIN); - deleteOrganizations(orchestrator); - } - @Test public void auto_assign_issues_to_user_if_default_assignee_is_member_of_project_organization() throws Exception { userRule.createUser(ASSIGNEE_LOGIN, ASSIGNEE_LOGIN); @@ -212,7 +196,7 @@ public class OrganizationIssueAssignTest { } private void createOrganization(String organizationKey) { - adminClient.organizations().create(new CreateWsRequest.Builder().setKey(organizationKey).setName(organizationKey).build()).getOrganization(); + organizations.create(o -> o.setKey(organizationKey).setName(organizationKey)); } private void provisionAndAnalyseProject(String projectKey, String organization) { diff --git a/it/it-tests/src/test/java/it/organization/BillingTest.java b/it/it-tests/src/test/java/it/organization/BillingTest.java index 82af2341319..5396a836c39 100644 --- a/it/it-tests/src/test/java/it/organization/BillingTest.java +++ b/it/it-tests/src/test/java/it/organization/BillingTest.java @@ -23,7 +23,7 @@ import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.BuildResult; import com.sonar.orchestrator.build.SonarScanner; import it.Category6Suite; -import org.junit.AfterClass; +import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -40,9 +40,9 @@ import org.sonarqube.ws.client.project.CreateRequest; import org.sonarqube.ws.client.project.UpdateVisibilityRequest; import pageobjects.Navigation; import util.ItUtils; +import util.OrganizationRule; import util.user.UserRule; -import static it.Category6Suite.enableOrganizationsSupport; import static java.lang.String.format; import static org.assertj.core.api.Java6Assertions.assertThat; import static org.junit.Assert.fail; @@ -58,43 +58,37 @@ import static util.ItUtils.setServerProperty; public class BillingTest { private static final String USER_LOGIN = "USER_LOGIN"; + private static final String PROPERTY_PREVENT_ANALYSIS = "sonar.billing.preventProjectAnalysis"; @ClassRule public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - @ClassRule - public static UserRule userRule = UserRule.from(orchestrator); - + @Rule + public UserRule userRule = UserRule.from(orchestrator); + @Rule + public OrganizationRule organizationRule = new OrganizationRule(orchestrator); @Rule public ExpectedException expectedException = ExpectedException.none(); - @Rule public Navigation nav = Navigation.get(orchestrator); private static WsClient adminClient; @BeforeClass - public static void prepare() throws Exception { + public static void prepare() { adminClient = newAdminWsClient(orchestrator); - enableOrganizationsSupport(); } @Before - public void setUp() throws Exception { - userRule.deactivateUsers(USER_LOGIN); - resetSettings(orchestrator, null, "sonar.billing.preventProjectAnalysis", "sonar.billing.preventUpdatingProjectsVisibilityToPrivate"); - } - - @AfterClass - public static void tearDown() throws Exception { - resetSettings(orchestrator, null, "sonar.billing.preventProjectAnalysis", "sonar.billing.preventUpdatingProjectsVisibilityToPrivate"); - userRule.deactivateUsers(USER_LOGIN); + @After + public void reset() { + resetSettings(orchestrator, null, PROPERTY_PREVENT_ANALYSIS, "sonar.billing.preventUpdatingProjectsVisibilityToPrivate"); } @Test public void execute_successfully_ce_analysis_on_organization() { String organizationKey = createOrganization(); - setServerProperty(orchestrator, "sonar.billing.preventProjectAnalysis", "false"); + setServerProperty(orchestrator, PROPERTY_PREVENT_ANALYSIS, "false"); String taskUuid = executeAnalysis(organizationKey); @@ -105,7 +99,7 @@ public class BillingTest { @Test public void fail_to_execute_ce_analysis_on_organization() { String organizationKey = createOrganization(); - setServerProperty(orchestrator, "sonar.billing.preventProjectAnalysis", "true"); + setServerProperty(orchestrator, PROPERTY_PREVENT_ANALYSIS, "true"); String taskUuid = executeAnalysis(organizationKey); diff --git a/it/it-tests/src/test/java/it/organization/OrganizationMembershipTest.java b/it/it-tests/src/test/java/it/organization/OrganizationMembershipTest.java index c6096c4ee5a..a8f151e48b4 100644 --- a/it/it-tests/src/test/java/it/organization/OrganizationMembershipTest.java +++ b/it/it-tests/src/test/java/it/organization/OrganizationMembershipTest.java @@ -22,285 +22,124 @@ package it.organization; import com.sonar.orchestrator.Orchestrator; import it.Category6Suite; -import java.util.List; -import org.junit.After; +import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.sonarqube.ws.Organizations; -import org.sonarqube.ws.WsUsers; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; +import org.sonarqube.ws.Organizations.Organization; +import org.sonarqube.ws.WsUsers.CreateWsResponse.User; import org.sonarqube.ws.client.HttpException; import org.sonarqube.ws.client.WsClient; -import org.sonarqube.ws.client.organization.CreateWsRequest; -import org.sonarqube.ws.client.organization.SearchMembersWsRequest; import org.sonarqube.ws.client.permission.AddUserWsRequest; -import org.sonarqube.ws.client.user.GroupsRequest; -import pageobjects.Navigation; -import pageobjects.organization.MembersPage; +import util.OrganizationRule; import util.user.UserRule; -import static it.Category6Suite.enableOrganizationsSupport; -import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; -import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.deleteOrganizations; import static util.ItUtils.newAdminWsClient; -import static util.ItUtils.newOrganizationKey; -import static util.ItUtils.newUserWsClient; import static util.ItUtils.setServerProperty; public class OrganizationMembershipTest { - private static final String KEY = newOrganizationKey(); + private static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; + private static OrganizationRule organizations = new OrganizationRule(orchestrator); + private static UserRule users = new UserRule(orchestrator); @ClassRule - public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - - @ClassRule - public static UserRule userRule = UserRule.from(orchestrator); + public static TestRule chain = RuleChain.outerRule(orchestrator) + .around(users) + .around(organizations); @Rule public ExpectedException expectedException = ExpectedException.none(); - @Rule - public Navigation nav = Navigation.get(orchestrator); - - private static WsClient adminClient; + private static WsClient rootWsClient; @BeforeClass - public static void setUp() throws Exception { - adminClient = newAdminWsClient(orchestrator); - enableOrganizationsSupport(); + public static void setUp() { + rootWsClient = newAdminWsClient(orchestrator); setServerProperty(orchestrator, "sonar.organizations.anyoneCanCreate", "true"); - deleteOrganizations(orchestrator); } - @After - public void tearDown() throws Exception { - deleteOrganizations(orchestrator); + @AfterClass + public static void tearDown() { + setServerProperty(orchestrator, "sonar.organizations.anyoneCanCreate", null); } @Test - public void new_user_should_not_become_member_of_default_organization() throws Exception { - String login = createUser(); - verifyMembership(login, "default-organization", false); + public void new_user_should_not_become_member_of_default_organization() { + User user = users.createUser(); + organizations.assertThatNotMemberOf(null, user); } @Test - public void add_and_remove_member() throws Exception { - String organizationKey = createOrganization(); - String login = createUser(); - adminClient.organizations().addMember(organizationKey, login); - verifyMembership(login, organizationKey, true); + public void add_and_remove_member() { + Organization organization = organizations.create(); + User user = users.createUser(); - adminClient.organizations().removeMember(organizationKey, login); - verifyMembership(login, organizationKey, false); - } - - @Test - public void remove_organization_admin_member() throws Exception { - String organizationKey = createOrganization(); - String login = createUser(); - adminClient.organizations().addMember(organizationKey, login); - adminClient.permissions().addUser(new AddUserWsRequest().setLogin(login).setPermission("admin").setOrganization(organizationKey)); - verifyMembership(login, organizationKey, true); + addMembership(organization, user); + organizations.assertThatMemberOf(organization, user); - adminClient.organizations().removeMember(organizationKey, login); - verifyMembership(login, organizationKey, false); + removeMembership(organization, user); + organizations.assertThatNotMemberOf(organization, user); } @Test - public void fail_to_remove_organization_admin_member_when_last_admin() throws Exception { - String organizationKey = createOrganization(); - String login = createUser(); - adminClient.organizations().addMember(organizationKey, login); - adminClient.permissions().addUser(new AddUserWsRequest().setLogin(login).setPermission("admin").setOrganization(organizationKey)); - verifyMembership(login, organizationKey, true); - // Admin is the creator of the organization so he was granted with admin permission - adminClient.organizations().removeMember(organizationKey, "admin"); + public void remove_organization_admin_member() { + Organization organization = organizations.create(); + User user = users.createUser(); + addMembership(organization, user); - expectedException.expect(HttpException.class); - expectedException.expectMessage("The last administrator member cannot be removed"); + rootWsClient.permissions().addUser(new AddUserWsRequest().setLogin(user.getLogin()).setPermission("admin").setOrganization(organization.getKey())); + organizations.assertThatMemberOf(organization, user); - adminClient.organizations().removeMember(organizationKey, login); + removeMembership(organization, user); + organizations.assertThatNotMemberOf(organization, user); } @Test - public void remove_user_remove_its_membership() throws Exception { - String organizationKey = createOrganization(); - String login = createUser(); - adminClient.organizations().addMember(organizationKey, login); - verifyMembership(login, organizationKey, true); + public void fail_to_remove_organization_admin_member_when_last_admin() { + Organization organization = organizations.create(); + User user = users.createUser(); + addMembership(organization, user); - userRule.deactivateUsers(login); - verifyOrganizationMembership(login, organizationKey, false); - } - - @Test - public void user_creating_an_organization_becomes_member_of_this_organization() throws Exception { - String keyAndName = newOrganizationKey(); - String login = createUser(); - - newUserWsClient(orchestrator, login, login).organizations().create( - new CreateWsRequest.Builder().setKey(keyAndName).setName(keyAndName).build()).getOrganization(); - - verifyMembership(login, keyAndName, true); - } - - @Test - public void should_display_members_page() { - String orgKey = createOrganization(); - - String userFoo = createUser("foo"); - adminClient.organizations().addMember(orgKey, userFoo); - - String userBar = createUser("bar"); - adminClient.organizations().addMember(orgKey, userBar); - - createUser(); - - MembersPage page = nav.openOrganizationMembers(orgKey); - page - .canNotAddMember() - .shouldHaveTotal(3); - page.getMembersByIdx(0).shouldBeNamed("admin", "Administrator"); - page.getMembersByIdx(1).shouldBeNamed(userBar, userBar); - page.getMembersByIdx(2) - .shouldBeNamed(userFoo, userFoo) - .shouldNotHaveActions(); - } - - @Test - public void search_for_members() { - String orgKey = createOrganization(); - - String user1 = createUser(); - adminClient.organizations().addMember(orgKey, user1); - - String user2 = createUser("sameprefixuser"); - adminClient.organizations().addMember(orgKey, user2); - - // Created to verify that only the user part of the org is returned - createUser("sameprefixuser"); - - MembersPage page = nav.openOrganizationMembers(orgKey); - page - .searchForMember("sameprefixuser") - .shouldHaveTotal(1); - page.getMembersByIdx(0).shouldBeNamed(user2, user2); - page - .searchForMember(user1) - .shouldHaveTotal(1); - page.getMembersByIdx(0).shouldBeNamed(user1, user1); - } - - @Test - public void admin_can_add_members() { - String orgKey = createOrganization(); - String userFoo = createUser("foo"); - createUser(); - - MembersPage page = nav.logIn().asAdmin().openOrganizationMembers(orgKey); - page - .shouldHaveTotal(1) - .addMember(userFoo) - .shouldHaveTotal(2); - page.getMembersByIdx(0).shouldBeNamed("admin", "Administrator").shouldHaveGroups(2); - page.getMembersByIdx(1).shouldBeNamed(userFoo, userFoo).shouldHaveGroups(1); - } - - @Test - public void admin_can_remove_members() { - String orgKey = createOrganization(); - - String user1 = createUser(); - adminClient.organizations().addMember(orgKey, user1); - - String user2 = createUser(); - adminClient.organizations().addMember(orgKey, user2); + rootWsClient.permissions().addUser(new AddUserWsRequest().setLogin(user.getLogin()).setPermission("admin").setOrganization(organization.getKey())); + organizations.assertThatMemberOf(organization, user); + // Admin is the creator of the organization so he was granted with admin permission + rootWsClient.organizations().removeMember(organization.getKey(), "admin"); - MembersPage page = nav.logIn().asAdmin().openOrganizationMembers(orgKey); - page.shouldHaveTotal(3) - .getMembersByIdx(1).removeMembership(); - page.shouldHaveTotal(2); + expectedException.expect(HttpException.class); + expectedException.expectMessage("The last administrator member cannot be removed"); + removeMembership(organization, user); } @Test - public void admin_can_manage_groups() { - String orgKey = createOrganization(); - - String userFoo = createUser("foo"); - adminClient.organizations().addMember(orgKey, userFoo); + public void remove_user_remove_its_membership() { + Organization organization = organizations.create(); + User user = users.createUser(); + addMembership(organization, user); - MembersPage page = nav.logIn().asAdmin().openOrganizationMembers(orgKey); - // foo user - page.getMembersByIdx(1) - .manageGroupsOpen() - .manageGroupsSelect("owners") - .manageGroupsSave() - .shouldHaveGroups(2); - // admin user - page.getMembersByIdx(0) - .manageGroupsOpen() - .manageGroupsSelect("owners") - .manageGroupsSave() - .shouldHaveGroups(1); + users.deactivateUsers(user.getLogin()); + organizations.assertThatNotMemberOf(organization, user); } @Test - public void groups_count_should_be_updated_when_a_member_was_just_added() { - String orgKey = createOrganization(); - String userFoo = createUser("foo"); - - MembersPage page = nav.logIn().asAdmin().openOrganizationMembers(orgKey); - page - .addMember(userFoo) - .getMembersByIdx(1) - .shouldHaveGroups(1) - .manageGroupsOpen() - .manageGroupsSelect("owners") - .manageGroupsSave() - .shouldHaveGroups(2); - } - - private void verifyMembership(String login, String organizationKey, boolean isMember) { - verifyOrganizationMembership(login, organizationKey, isMember); - verifyMembersGroupMembership(login, organizationKey, isMember); - } + public void user_creating_an_organization_becomes_member_of_this_organization() { + String password = "aPassword"; + User user = users.createUser(p -> p.setPassword(password)); - private void verifyOrganizationMembership(String login, String organizationKey, boolean isMember) { - List<Organizations.User> users = adminClient.organizations().searchMembers(new SearchMembersWsRequest() - .setQuery(login) - .setSelected("selected") - .setOrganization(organizationKey)) - .getUsersList(); - assertThat(users).hasSize(isMember ? 1 : 0); - } - - private void verifyMembersGroupMembership(String login, String organizationKey, boolean isMember) { - List<WsUsers.GroupsWsResponse.Group> groups = adminClient.users().groups(GroupsRequest.builder() - .setLogin(login) - .setOrganization(organizationKey) - .setQuery("Members") - .setSelected("selected") - .build()) - .getGroupsList(); - assertThat(groups).hasSize(isMember ? 1 : 0); - } + Organization organization = organizations.as(user.getLogin(), password).create(); - private static String createOrganization() { - adminClient.organizations().create(new CreateWsRequest.Builder().setKey(KEY).setName(KEY).build()).getOrganization(); - return KEY; + organizations.assertThatMemberOf(organization, user); } - private static String createUser() { - return createUser(""); + private void addMembership(Organization organization, User user) { + rootWsClient.organizations().addMember(organization.getKey(), user.getLogin()); } - private static String createUser(String prefix) { - String login = prefix + randomAlphabetic(10).toLowerCase(); - userRule.createUser(login, login); - return login; + private void removeMembership(Organization organization, User user) { + rootWsClient.organizations().removeMember(organization.getKey(), user.getLogin()); } } diff --git a/it/it-tests/src/test/java/it/organization/OrganizationMembershipUiTest.java b/it/it-tests/src/test/java/it/organization/OrganizationMembershipUiTest.java new file mode 100644 index 00000000000..a03327d743b --- /dev/null +++ b/it/it-tests/src/test/java/it/organization/OrganizationMembershipUiTest.java @@ -0,0 +1,186 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 it.organization; + +import com.sonar.orchestrator.Orchestrator; +import it.Category6Suite; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; +import org.sonarqube.ws.Organizations.Organization; +import org.sonarqube.ws.WsUsers.CreateWsResponse.User; +import org.sonarqube.ws.client.WsClient; +import pageobjects.Navigation; +import pageobjects.organization.MembersPage; +import util.OrganizationRule; +import util.user.UserRule; + +import static util.ItUtils.newAdminWsClient; +import static util.ItUtils.setServerProperty; + +public class OrganizationMembershipUiTest { + + private static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; + private static OrganizationRule organizations = new OrganizationRule(orchestrator); + private static UserRule users = new UserRule(orchestrator); + + @ClassRule + public static TestRule chain = RuleChain.outerRule(orchestrator) + .around(users) + .around(organizations); + + @Rule + public Navigation nav = Navigation.get(orchestrator); + + private static WsClient rootWsClient; + + @BeforeClass + public static void setUp() { + rootWsClient = newAdminWsClient(orchestrator); + setServerProperty(orchestrator, "sonar.organizations.anyoneCanCreate", "true"); + } + + @AfterClass + public static void tearDown() { + setServerProperty(orchestrator, "sonar.organizations.anyoneCanCreate", null); + } + + @Test + public void should_display_members_page() { + Organization organization = organizations.create(); + User member1 = users.createUser(p -> p.setName("foo")); + addMembership(organization, member1); + User member2 = users.createUser(p -> p.setName("bar")); + addMembership(organization, member2); + User nonMember = users.createUser(); + + MembersPage page = nav.openOrganizationMembers(organization.getKey()); + page + .canNotAddMember() + .shouldHaveTotal(3); + page.getMembersByIdx(0).shouldBeNamed("admin", "Administrator"); + page.getMembersByIdx(1) + .shouldBeNamed(member2.getLogin(), member2.getName()); + page.getMembersByIdx(2) + .shouldBeNamed(member1.getLogin(), member1.getName()) + .shouldNotHaveActions(); + } + + @Test + public void search_for_members() { + Organization organization = organizations.create(); + User member1 = users.createUser(p -> p.setName("foo")); + addMembership(organization, member1); + User member2 = users.createUser(p -> p.setName("barGuy")); + addMembership(organization, member2); + // Created to verify that only the user part of the org is returned + User userWithSameNamePrefix = users.createUser(p -> p.setName(member2.getName() + "barOtherGuy")); + + MembersPage page = nav.openOrganizationMembers(organization.getKey()); + page + .searchForMember("bar") + .shouldHaveTotal(1); + page.getMembersByIdx(0) + .shouldBeNamed(member2.getLogin(), member2.getName()); + page + .searchForMember(member1.getName()) + .shouldHaveTotal(1); + page.getMembersByIdx(0) + .shouldBeNamed(member1.getLogin(), member1.getName()); + } + + @Test + public void admin_can_add_members() { + Organization organization = organizations.create(); + User user = users.createUser(); + + MembersPage page = nav.logIn().asAdmin().openOrganizationMembers(organization.getKey()); + page + .shouldHaveTotal(1) + .addMember(user.getLogin()) + .shouldHaveTotal(2); + page.getMembersByIdx(0) + .shouldBeNamed("admin", "Administrator") + .shouldHaveGroups(2); + page.getMembersByIdx(1) + .shouldBeNamed(user.getLogin(), user.getName()) + .shouldHaveGroups(1); + } + + @Test + public void admin_can_remove_members() { + Organization organization = organizations.create(); + User user1 = users.createUser(); + addMembership(organization, user1); + User user2 = users.createUser(); + addMembership(organization, user2); + + MembersPage page = nav.logIn().asAdmin().openOrganizationMembers(organization.getKey()); + page.shouldHaveTotal(3) + .getMembersByIdx(1).removeMembership(); + page.shouldHaveTotal(2); + } + + @Test + public void admin_can_manage_groups() { + Organization organization = organizations.create(); + User user = users.createUser(); + addMembership(organization, user); + + MembersPage page = nav.logIn().asAdmin().openOrganizationMembers(organization.getKey()); + // foo user + page.getMembersByIdx(1) + .manageGroupsOpen() + .manageGroupsSelect("owners") + .manageGroupsSave() + .shouldHaveGroups(2); + // admin user + page.getMembersByIdx(0) + .manageGroupsOpen() + .manageGroupsSelect("owners") + .manageGroupsSave() + .shouldHaveGroups(1); + } + + @Test + public void groups_count_should_be_updated_when_a_member_was_just_added() { + Organization organization = organizations.create(); + User user = users.createUser(); + + MembersPage page = nav.logIn().asAdmin().openOrganizationMembers(organization.getKey()); + page + .addMember(user.getLogin()) + .getMembersByIdx(1) + .shouldHaveGroups(1) + .manageGroupsOpen() + .manageGroupsSelect("owners") + .manageGroupsSave() + .shouldHaveGroups(2); + } + + private void addMembership(Organization organization, User user) { + rootWsClient.organizations().addMember(organization.getKey(), user.getLogin()); + } +} diff --git a/it/it-tests/src/test/java/it/organization/OrganizationTest.java b/it/it-tests/src/test/java/it/organization/OrganizationTest.java index 1a23e0f6262..4f6c15bf0a0 100644 --- a/it/it-tests/src/test/java/it/organization/OrganizationTest.java +++ b/it/it-tests/src/test/java/it/organization/OrganizationTest.java @@ -24,207 +24,139 @@ import com.sonar.orchestrator.build.BuildFailureException; import it.Category6Suite; import java.util.List; import java.util.Locale; -import java.util.function.Consumer; -import java.util.function.Function; import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonarqube.ws.Organizations; +import org.sonarqube.ws.Organizations.Organization; import org.sonarqube.ws.QualityProfiles; import org.sonarqube.ws.Rules; import org.sonarqube.ws.WsComponents; import org.sonarqube.ws.WsUsers; -import org.sonarqube.ws.client.HttpException; +import org.sonarqube.ws.WsUsers.CreateWsResponse.User; import org.sonarqube.ws.client.PostRequest; import org.sonarqube.ws.client.WsClient; import org.sonarqube.ws.client.component.ComponentsService; import org.sonarqube.ws.client.organization.CreateWsRequest; -import org.sonarqube.ws.client.organization.OrganizationService; import org.sonarqube.ws.client.organization.SearchWsRequest; import org.sonarqube.ws.client.organization.UpdateWsRequest; import org.sonarqube.ws.client.permission.AddUserWsRequest; import org.sonarqube.ws.client.permission.PermissionsService; import org.sonarqube.ws.client.user.GroupsRequest; +import util.OrganizationRule; +import util.OrganizationSupport; import util.user.GroupManagement; import util.user.Groups; import util.user.UserRule; -import static it.Category6Suite.enableOrganizationsSupport; import static java.util.Collections.singletonList; import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; -import static util.ItUtils.deleteOrganizations; +import static util.ItUtils.expectBadRequestError; +import static util.ItUtils.expectForbiddenError; +import static util.ItUtils.expectNotFoundError; +import static util.ItUtils.expectUnauthorizedError; import static util.ItUtils.newAdminWsClient; import static util.ItUtils.newUserWsClient; import static util.ItUtils.newWsClient; -import static util.ItUtils.resetSettings; import static util.ItUtils.runProjectAnalysis; import static util.ItUtils.setServerProperty; public class OrganizationTest { + + private static final String SETTING_ANYONE_CAN_CREATE_ORGANIZATIONS = "sonar.organizations.anyoneCanCreate"; private static final String DEFAULT_ORGANIZATION_KEY = "default-organization"; private static final String NAME = "Foo Company"; - private static final String KEY = "foo-company"; + // private static final String KEY = "foo-company"; private static final String DESCRIPTION = "the description of Foo company"; private static final String URL = "https://www.foo.fr"; private static final String AVATAR_URL = "https://www.foo.fr/corporate_logo.png"; - private static final String SETTING_ANYONE_CAN_CREATE_ORGANIZATIONS = "sonar.organizations.anyoneCanCreate"; private static final String USER_LOGIN = "foo"; @ClassRule public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - @ClassRule - public static UserRule userRule = UserRule.from(orchestrator); + @Rule + public OrganizationRule organizations = new OrganizationRule(orchestrator); + @Rule + public UserRule users = new UserRule(orchestrator); @Rule public ExpectedException expectedException = ExpectedException.none(); private WsClient adminClient = newAdminWsClient(orchestrator); - private OrganizationService anonymousOrganizationService = newWsClient(orchestrator).organizations(); - private OrganizationService adminOrganizationService = adminClient.organizations(); - @BeforeClass - public static void enableOrganizations() throws Exception { - enableOrganizationsSupport(); + @After + public void tearDown() { + setServerProperty(orchestrator, SETTING_ANYONE_CAN_CREATE_ORGANIZATIONS, null); } - @Before - public void setUp() throws Exception { - resetSettings(orchestrator, null, SETTING_ANYONE_CAN_CREATE_ORGANIZATIONS); - deleteOrganizations(orchestrator); - userRule.deactivateUsers(USER_LOGIN); + @Test + public void default_organization_should_exist() { + Organization defaultOrg = organizations.getWsService().search(SearchWsRequest.builder().build()) + .getOrganizationsList() + .stream() + .filter(Organization::getGuarded) + .findFirst() + .orElseThrow(IllegalStateException::new); + assertThat(defaultOrg.getKey().equals(DEFAULT_ORGANIZATION_KEY)); + assertThat(defaultOrg.getName().equals("Default Organization")); } - @After - public void tearDown() throws Exception { - deleteOrganizations(orchestrator); + @Test + public void default_organization_can_not_be_deleted() { + expectBadRequestError(() -> organizations.getWsService().delete(DEFAULT_ORGANIZATION_KEY)); } @Test - public void create_update_delete_organizations_and_check_security() { - assertThatOrganizationDoesNotExit(KEY); - - Organizations.Organization createdOrganization = adminOrganizationService.create(new CreateWsRequest.Builder() + public void create_update_and_delete_organizations() { + Organization org = organizations.create(o -> o .setName(NAME) - .setKey(KEY) .setDescription(DESCRIPTION) .setUrl(URL) .setAvatar(AVATAR_URL) - .build()) - .getOrganization(); - assertThat(createdOrganization.getName()).isEqualTo(NAME); - assertThat(createdOrganization.getKey()).isEqualTo(KEY); - assertThat(createdOrganization.getDescription()).isEqualTo(DESCRIPTION); - assertThat(createdOrganization.getUrl()).isEqualTo(URL); - assertThat(createdOrganization.getAvatar()).isEqualTo(AVATAR_URL); - - verifySingleSearchResult(createdOrganization, NAME, DESCRIPTION, URL, AVATAR_URL); - assertThatBuiltInQualityProfilesExist(createdOrganization.getKey()); - - // update by id - adminOrganizationService.update(new UpdateWsRequest.Builder() - .setKey(createdOrganization.getKey()) + .build()); + assertThat(org.getName()).isEqualTo(NAME); + assertThat(org.getDescription()).isEqualTo(DESCRIPTION); + assertThat(org.getUrl()).isEqualTo(URL); + assertThat(org.getAvatar()).isEqualTo(AVATAR_URL); + + verifyOrganization(org, NAME, DESCRIPTION, URL, AVATAR_URL); + assertThatBuiltInQualityProfilesExist(org); + + // update by key + organizations.getWsService().update(new UpdateWsRequest.Builder() + .setKey(org.getKey()) .setName("new name") .setDescription("new description") .setUrl("new url") .setAvatar("new avatar url") .build()); - verifySingleSearchResult(createdOrganization, "new name", "new description", "new url", "new avatar url"); - - // update by key - adminOrganizationService.update(new UpdateWsRequest.Builder() - .setKey(createdOrganization.getKey()) - .setName("new name 2") - .setDescription("new description 2") - .setUrl("new url 2") - .setAvatar("new avatar url 2") - .build()); - verifySingleSearchResult(createdOrganization, "new name 2", "new description 2", "new url 2", "new avatar url 2"); + verifyOrganization(org, "new name", "new description", "new url", "new avatar url"); // remove optional fields - adminOrganizationService.update(new UpdateWsRequest.Builder() - .setKey(createdOrganization.getKey()) - .setName("new name 3") + organizations.getWsService().update(new UpdateWsRequest.Builder() + .setKey(org.getKey()) + .setName("new name 2") .setDescription("") .setUrl("") .setAvatar("") .build()); - verifySingleSearchResult(createdOrganization, "new name 3", null, null, null); + verifyOrganization(org, "new name 2", null, null, null); // delete organization - adminOrganizationService.delete(createdOrganization.getKey()); - assertThatOrganizationDoesNotExit(createdOrganization.getKey()); - assertThatQualityProfilesDoNotExist(createdOrganization.getKey()); + organizations.delete(org); + assertThatOrganizationDoesNotExit(org); + assertThatQualityProfilesDoNotExist(org); - adminOrganizationService.create(new CreateWsRequest.Builder() + // create again + organizations.getWsService().create(new CreateWsRequest.Builder() .setName(NAME) - .setKey(KEY) + .setKey(org.getKey()) .build()) .getOrganization(); - verifySingleSearchResult(createdOrganization, NAME, null, null, null); - - // verify anonymous can't create update nor delete an organization by default - verifyAnonymousNotAuthorized(service -> service.create(new CreateWsRequest.Builder().setName("An org").build())); - assertThatUserNotAuthenticated(service -> service.update(new UpdateWsRequest.Builder().setKey(KEY).setName("new name").build())); - assertThatUserNotAuthenticated(service -> service.delete(KEY)); - - // verify logged in user without any permission can't create update nor delete an organization by default - userRule.createUser(USER_LOGIN, USER_LOGIN); - assertThatUserNotAuthorized(USER_LOGIN, USER_LOGIN, service -> service.create(new CreateWsRequest.Builder().setName("An org").build())); - assertThatUserNotAuthorized(USER_LOGIN, USER_LOGIN, service -> service.update(new UpdateWsRequest.Builder().setKey(KEY).setName("new name").build())); - assertThatUserNotAuthorized(USER_LOGIN, USER_LOGIN, service -> service.delete(KEY)); - - setServerProperty(orchestrator, SETTING_ANYONE_CAN_CREATE_ORGANIZATIONS, "true"); - // verify anonymous still can't create update nor delete an organization if property is true - assertThatUserNotAuthenticated(service -> service.create(new CreateWsRequest.Builder().setName("An org").build())); - assertThatUserNotAuthenticated(service -> service.update(new UpdateWsRequest.Builder().setKey(KEY).setName("new name").build())); - assertThatUserNotAuthenticated(service -> service.delete(KEY)); - - // verify logged in user without any permission can't create nor update nor delete an organization if property is true - assertThatUserNotAuthorized(USER_LOGIN, USER_LOGIN, service -> service.update(new UpdateWsRequest.Builder().setKey(KEY).setName("new name").build())); - assertThatUserNotAuthorized(USER_LOGIN, USER_LOGIN, service -> service.delete(KEY)); - // clean-up - adminOrganizationService.delete(KEY); - verifySingleSearchResult( - verifyUserAuthorized(USER_LOGIN, USER_LOGIN, service -> service.create(new CreateWsRequest.Builder().setName("An org").build())).getOrganization(), - "An org", null, null, null); - } - - private void verifyAnonymousNotAuthorized(Consumer<OrganizationService> consumer) { - try { - consumer.accept(anonymousOrganizationService); - fail("An HttpException should have been raised"); - } catch (HttpException e) { - assertThat(e.code()).isEqualTo(403); - } - } - - private void assertThatUserNotAuthenticated(Consumer<OrganizationService> consumer) { - try { - consumer.accept(anonymousOrganizationService); - fail("An HttpException should have been raised"); - } catch (HttpException e) { - assertThat(e.code()).isEqualTo(401); - } - } - - private void assertThatUserNotAuthorized(String login, String password, Consumer<OrganizationService> consumer) { - try { - OrganizationService organizationService = newUserWsClient(orchestrator, login, password).organizations(); - consumer.accept(organizationService); - fail("An HttpException should have been raised"); - } catch (HttpException e) { - assertThat(e.code()).isEqualTo(403); - } - } - - private <T> T verifyUserAuthorized(String login, String password, Function<OrganizationService, T> consumer) { - OrganizationService organizationService = newUserWsClient(orchestrator, login, password).organizations(); - return consumer.apply(organizationService); + verifyOrganization(org, NAME, null, null, null); } @Test @@ -232,105 +164,94 @@ public class OrganizationTest { // create organization without key String name = "Foo Company to keyize"; String expectedKey = "foo-company-to-keyize"; - Organizations.Organization createdOrganization = adminOrganizationService.create(new CreateWsRequest.Builder() + Organization createdOrganization = organizations.getWsService().create(new CreateWsRequest.Builder() .setName(name) .build()) .getOrganization(); assertThat(createdOrganization.getKey()).isEqualTo(expectedKey); - verifySingleSearchResult(createdOrganization, name, null, null, null); - - // clean-up - adminOrganizationService.delete(expectedKey); + verifyOrganization(createdOrganization, name, null, null, null); } @Test - public void default_organization_can_not_be_deleted() { - try { - adminOrganizationService.delete(DEFAULT_ORGANIZATION_KEY); - fail("a HttpException should have been raised"); - } catch (HttpException e) { - assertThat(e.code()).isEqualTo(400); - } + public void anonymous_user_cannot_administrate_organization() { + Organization org = organizations.create(); + OrganizationSupport anonymousOrganisations = organizations.asAnonymous(); + + expectForbiddenError(() -> anonymousOrganisations.create()); + expectUnauthorizedError(() -> anonymousOrganisations.getWsService().update(new UpdateWsRequest.Builder().setKey(org.getKey()).setName("new name").build())); + expectUnauthorizedError(() -> anonymousOrganisations.delete(org)); } @Test - public void create_fails_if_user_is_not_root() { - userRule.createUser(USER_LOGIN, USER_LOGIN); - - CreateWsRequest createWsRequest = new CreateWsRequest.Builder() - .setName("bla bla") - .build(); - OrganizationService fooUserOrganizationService = newUserWsClient(orchestrator, USER_LOGIN, USER_LOGIN).organizations(); + public void logged_in_user_cannot_administrate_organization() { + Organization org = organizations.create(); + String password = "aPassword"; + User user = users.createUser(p -> p.setPassword(password)); + OrganizationSupport userOrganisations = organizations.as(user.getLogin(), password); + + expectForbiddenError(() -> userOrganisations.create()); + expectForbiddenError(() -> userOrganisations.getWsService().update(new UpdateWsRequest.Builder().setKey(org.getKey()).setName("new name").build())); + expectForbiddenError(() -> userOrganisations.delete(org)); + } - expect403HttpError(() -> fooUserOrganizationService.create(createWsRequest)); + @Test + public void logged_in_user_can_administrate_organization_if_root() { + String password = "aPassword"; + User user = users.createUser(p -> p.setPassword(password)); + OrganizationSupport userOrganisations = organizations.as(user.getLogin(), password); - userRule.setRoot(USER_LOGIN); - assertThat(fooUserOrganizationService.create(createWsRequest).getOrganization().getKey()).isEqualTo("bla-bla"); + users.setRoot(user.getLogin()); + Organization org = userOrganisations.create(); // delete org, attempt recreate when no root anymore and ensure it can't anymore - fooUserOrganizationService.delete("bla-bla"); - userRule.unsetRoot(USER_LOGIN); - expect403HttpError(() -> fooUserOrganizationService.create(createWsRequest)); + userOrganisations.delete(org); + + users.unsetRoot(user.getLogin()); + expectForbiddenError(() -> userOrganisations.create()); } @Test public void an_organization_member_can_analyze_project() { + Organization organization = organizations.create(); - assertThatOrganizationDoesNotExit(KEY); - - Organizations.Organization createdOrganization = adminOrganizationService.create(new CreateWsRequest.Builder() - .setName(KEY) - .setKey(KEY) - .build()) - .getOrganization(); - verifySingleSearchResult(createdOrganization, KEY, null, null, null); - - userRule.createUser(USER_LOGIN, USER_LOGIN); - userRule.removeGroups("sonar-users"); - adminOrganizationService.addMember(KEY, USER_LOGIN); - addPermissionsToUser(KEY, USER_LOGIN, "provisioning", "scan"); + String password = "aPassword"; + User user = users.createUser(p -> p.setPassword(password)); + users.removeGroups("sonar-users"); + organizations.getWsService().addMember(organization.getKey(), user.getLogin()); + addPermissionsToUser(organization.getKey(), user.getLogin(), "provisioning", "scan"); runProjectAnalysis(orchestrator, "shared/xoo-sample", - "sonar.organization", KEY, "sonar.login", USER_LOGIN, "sonar.password", USER_LOGIN); - ComponentsService componentsService = newUserWsClient(orchestrator, USER_LOGIN, USER_LOGIN).components(); - assertThat(searchSampleProject(KEY, componentsService).getComponentsList()).hasSize(1); + "sonar.organization", organization.getKey(), + "sonar.login", user.getLogin(), + "sonar.password", password); + ComponentsService componentsService = newUserWsClient(orchestrator, user.getLogin(), password).components(); + assertThat(searchSampleProject(organization.getKey(), componentsService).getComponentsList()).hasSize(1); } @Test public void by_default_anonymous_cannot_analyse_project_on_organization() { - assertThatOrganizationDoesNotExit(KEY); - - Organizations.Organization createdOrganization = adminOrganizationService.create(new CreateWsRequest.Builder() - .setName(KEY) - .setKey(KEY) - .build()) - .getOrganization(); - verifySingleSearchResult(createdOrganization, KEY, null, null, null); + Organization organization = organizations.create(); try { runProjectAnalysis(orchestrator, "shared/xoo-sample", - "sonar.organization", KEY); + "sonar.organization", organization.getKey()); fail(); } catch (BuildFailureException e) { assertThat(e.getResult().getLogs()).contains("Insufficient privileges"); } ComponentsService componentsService = newAdminWsClient(orchestrator).components(); - assertThat(searchSampleProject(KEY, componentsService).getComponentsCount()).isEqualTo(0); + assertThat(searchSampleProject(organization.getKey(), componentsService).getComponentsCount()).isEqualTo(0); } @Test public void by_default_anonymous_can_browse_project_on_organization() { - adminOrganizationService.create(new CreateWsRequest.Builder() - .setName(KEY) - .setKey(KEY) - .build()) - .getOrganization(); + Organization organization = organizations.create(); - runProjectAnalysis(orchestrator, "shared/xoo-sample", "sonar.organization", KEY, "sonar.login", "admin", "sonar.password", "admin"); + runProjectAnalysis(orchestrator, "shared/xoo-sample", "sonar.organization", organization.getKey(), "sonar.login", "admin", "sonar.password", "admin"); ComponentsService componentsService = newWsClient(orchestrator).components(); - assertThat(searchSampleProject(KEY, componentsService).getComponentsList()).hasSize(1); + assertThat(searchSampleProject(organization.getKey(), componentsService).getComponentsList()).hasSize(1); } private void addPermissionsToUser(String orgKeyAndName, String login, String permission, String... otherPermissions) { @@ -342,61 +263,75 @@ public class OrganizationTest { } @Test - public void deleting_an_organization_also_deletes_projects_and_check_security() { - assertThatOrganizationDoesNotExit(KEY); + public void deleting_an_organization_also_deletes_projects() { + Organization organization = organizations.create(); - Organizations.Organization createdOrganization = adminOrganizationService.create(new CreateWsRequest.Builder() - .setName(KEY) - .setKey(KEY) - .build()) - .getOrganization(); - verifySingleSearchResult(createdOrganization, KEY, null, null, null); - - GroupManagement groupManagement = userRule.forOrganization(KEY); + GroupManagement groupManagement = users.forOrganization(organization.getKey()); - userRule.createUser(USER_LOGIN, USER_LOGIN); - adminOrganizationService.addMember(KEY, USER_LOGIN); + users.createUser(USER_LOGIN, USER_LOGIN); + organizations.getWsService().addMember(organization.getKey(), USER_LOGIN); groupManagement.createGroup("grp1"); groupManagement.createGroup("grp2"); groupManagement.associateGroupsToUser(USER_LOGIN, "grp1", "grp2"); assertThat(groupManagement.getUserGroups(USER_LOGIN).getGroups()) .extracting(Groups.Group::getName) .contains("grp1", "grp2"); - addPermissionsToUser(KEY, USER_LOGIN, "provisioning", "scan"); + addPermissionsToUser(organization.getKey(), USER_LOGIN, "provisioning", "scan"); runProjectAnalysis(orchestrator, "shared/xoo-sample", - "sonar.organization", KEY, "sonar.login", USER_LOGIN, "sonar.password", USER_LOGIN); + "sonar.organization", organization.getKey(), "sonar.login", USER_LOGIN, "sonar.password", USER_LOGIN); ComponentsService componentsService = newAdminWsClient(orchestrator).components(); - assertThat(searchSampleProject(KEY, componentsService).getComponentsList()).hasSize(1); + assertThat(searchSampleProject(organization.getKey(), componentsService).getComponentsList()).hasSize(1); - adminOrganizationService.delete(KEY); + organizations.delete(organization); - expect404HttpError(() -> searchSampleProject(KEY, componentsService)); - assertThatOrganizationDoesNotExit(KEY); + expectNotFoundError(() -> searchSampleProject(organization.getKey(), componentsService)); + assertThatOrganizationDoesNotExit(organization); } @Test public void return_groups_belonging_to_a_user_on_an_organization() throws Exception { String userLogin = randomAlphabetic(10); String groupName = randomAlphabetic(10); - adminClient.organizations().create(new CreateWsRequest.Builder().setKey(KEY).setName(KEY).build()).getOrganization(); - userRule.createUser(userLogin, userLogin); - adminOrganizationService.addMember(KEY, userLogin); + Organization organization = organizations.create(); + users.createUser(userLogin, userLogin); + organizations.getWsService().addMember(organization.getKey(), userLogin); adminClient.wsConnector().call(new PostRequest("api/user_groups/create") .setParam("name", groupName) .setParam("description", groupName) - .setParam("organization", KEY)).failIfNotSuccessful(); + .setParam("organization", organization.getKey())).failIfNotSuccessful(); adminClient.wsConnector().call(new PostRequest("api/user_groups/add_user") .setParam("login", userLogin) .setParam("name", groupName) - .setParam("organization", KEY)).failIfNotSuccessful(); + .setParam("organization", organization.getKey())).failIfNotSuccessful(); List<WsUsers.GroupsWsResponse.Group> result = adminClient.users().groups( - GroupsRequest.builder().setLogin(userLogin).setOrganization(KEY).build()).getGroupsList(); + GroupsRequest.builder().setLogin(userLogin).setOrganization(organization.getKey()).build()).getGroupsList(); assertThat(result).extracting(WsUsers.GroupsWsResponse.Group::getName).containsOnly(groupName, "Members"); } + @Test + public void anonymous_cannot_create_organizations_even_if_anyone_is_allowed_to() { + setServerProperty(orchestrator, SETTING_ANYONE_CAN_CREATE_ORGANIZATIONS, "true"); + + expectUnauthorizedError(() -> organizations.asAnonymous().create()); + } + + @Test + public void logged_in_user_can_create_organizations_if_anyone_is_allowed_to() { + setServerProperty(orchestrator, SETTING_ANYONE_CAN_CREATE_ORGANIZATIONS, "true"); + + String password = "aPassword"; + User user = users.createUser(p -> p.setPassword(password)); + OrganizationSupport userOrganisations = organizations.as(user.getLogin(), password); + Organizations.Organization org = userOrganisations.create(); + + assertThat(org.getName()).isNotEmpty(); + assertThat(org.getKey()).isNotEmpty(); + assertThat(org.getGuarded()).isFalse(); + } + private WsComponents.SearchWsResponse searchSampleProject(String organizationKey, ComponentsService componentsService) { return componentsService .search(new org.sonarqube.ws.client.component.SearchWsRequest() @@ -405,35 +340,17 @@ public class OrganizationTest { .setQuery("sample")); } - private void expect403HttpError(Runnable runnable) { - try { - runnable.run(); - fail("Ws call should have failed"); - } catch (HttpException e) { - assertThat(e.code()).isEqualTo(403); - } - } - - private void expect404HttpError(Runnable runnable) { - try { - runnable.run(); - fail("Ws call should have failed"); - } catch (HttpException e) { - assertThat(e.code()).isEqualTo(404); - } - } - - private void assertThatOrganizationDoesNotExit(String organizationKey) { - Organizations.SearchWsResponse searchWsResponse = anonymousOrganizationService.search(new SearchWsRequest.Builder().setOrganizations(organizationKey).build()); + private void assertThatOrganizationDoesNotExit(Organization org) { + Organizations.SearchWsResponse searchWsResponse = organizations.getWsService().search(new SearchWsRequest.Builder().setOrganizations(org.getKey()).build()); assertThat(searchWsResponse.getOrganizationsList()).isEmpty(); } - private void verifySingleSearchResult(Organizations.Organization createdOrganization, String name, String description, String url, + private void verifyOrganization(Organization createdOrganization, String name, String description, String url, String avatarUrl) { - List<Organizations.Organization> organizations = anonymousOrganizationService.search(new SearchWsRequest.Builder().setOrganizations(createdOrganization.getKey()) + List<Organization> result = organizations.getWsService().search(new SearchWsRequest.Builder().setOrganizations(createdOrganization.getKey()) .build()).getOrganizationsList(); - assertThat(organizations).hasSize(1); - Organizations.Organization searchedOrganization = organizations.get(0); + assertThat(result).hasSize(1); + Organization searchedOrganization = result.get(0); assertThat(searchedOrganization.getKey()).isEqualTo(createdOrganization.getKey()); assertThat(searchedOrganization.getName()).isEqualTo(name); if (description == null) { @@ -453,34 +370,30 @@ public class OrganizationTest { } } - private void assertThatBuiltInQualityProfilesExist(String organizationKey) { - org.sonarqube.ws.client.qualityprofile.SearchWsRequest profilesRequest = new org.sonarqube.ws.client.qualityprofile.SearchWsRequest().setOrganizationKey(organizationKey); + private void assertThatBuiltInQualityProfilesExist(Organization org) { + org.sonarqube.ws.client.qualityprofile.SearchWsRequest profilesRequest = new org.sonarqube.ws.client.qualityprofile.SearchWsRequest() + .setOrganizationKey(org.getKey()); QualityProfiles.SearchWsResponse response = adminClient.qualityProfiles().search(profilesRequest); assertThat(response.getProfilesCount()).isGreaterThan(0); - for (QualityProfiles.SearchWsResponse.QualityProfile profile : response.getProfilesList()) { - assertThat(profile.getIsInherited()).isFalse(); - assertThat(profile.getProjectCount()).isEqualTo(0); - assertThat(profile.getIsBuiltIn()).isTrue(); - if (profile.getName().toLowerCase(Locale.ENGLISH).contains("empty")) { - assertThat(profile.getActiveRuleCount()).isEqualTo(0); + + response.getProfilesList().forEach(p -> { + assertThat(p.getIsInherited()).isFalse(); + assertThat(p.getProjectCount()).isEqualTo(0); + assertThat(p.getIsBuiltIn()).isTrue(); + if (p.getName().toLowerCase(Locale.ENGLISH).contains("empty")) { + assertThat(p.getActiveRuleCount()).isEqualTo(0); } else { - assertThat(profile.getActiveRuleCount()).isGreaterThan(0); + assertThat(p.getActiveRuleCount()).isGreaterThan(0); // that allows to check the Elasticsearch index of active rules - Rules.SearchResponse activeRulesResponse = adminClient.rules().search(new org.sonarqube.ws.client.rule.SearchWsRequest().setActivation(true).setQProfile(profile.getKey())); - assertThat(activeRulesResponse.getTotal()).as("profile " + profile.getName()).isEqualTo(profile.getActiveRuleCount()); - assertThat(activeRulesResponse.getRulesCount()).isEqualTo((int)profile.getActiveRuleCount()); + Rules.SearchResponse activeRulesResponse = adminClient.rules().search(new org.sonarqube.ws.client.rule.SearchWsRequest().setActivation(true).setQProfile(p.getKey())); + assertThat(activeRulesResponse.getTotal()).as("profile " + p.getName()).isEqualTo(p.getActiveRuleCount()); + assertThat(activeRulesResponse.getRulesCount()).isEqualTo((int) p.getActiveRuleCount()); } - } + }); } - private void assertThatQualityProfilesDoNotExist(String organizationKey) { - org.sonarqube.ws.client.qualityprofile.SearchWsRequest profilesRequest = new org.sonarqube.ws.client.qualityprofile.SearchWsRequest().setOrganizationKey(organizationKey); - try { - adminClient.qualityProfiles().search(profilesRequest); - fail(); - } catch (HttpException e) { - assertThat(e.code()).isEqualTo(404); - assertThat(e.getMessage()).contains("No organization with key '" + organizationKey + "'"); - } + private void assertThatQualityProfilesDoNotExist(Organization org) { + expectNotFoundError(() -> adminClient.qualityProfiles().search( + new org.sonarqube.ws.client.qualityprofile.SearchWsRequest().setOrganizationKey(org.getKey()))); } } diff --git a/it/it-tests/src/test/java/it/organization/PersonalOrganizationTest.java b/it/it-tests/src/test/java/it/organization/PersonalOrganizationTest.java new file mode 100644 index 00000000000..3d349f95f2a --- /dev/null +++ b/it/it-tests/src/test/java/it/organization/PersonalOrganizationTest.java @@ -0,0 +1,77 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 it.organization; + +import com.sonar.orchestrator.Orchestrator; +import it.Category6Suite; +import java.util.List; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; +import org.sonarqube.ws.Organizations; +import org.sonarqube.ws.WsUsers; +import org.sonarqube.ws.client.organization.SearchWsRequest; +import util.OrganizationRule; +import util.user.UserRule; + +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.setServerProperty; + +public class PersonalOrganizationTest { + + private static final String SETTING_CREATE_PERSONAL_ORG = "sonar.organizations.createPersonalOrg"; + + private static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; + private static OrganizationRule organizations = new OrganizationRule(orchestrator); + private static UserRule users = new UserRule(orchestrator); + + @ClassRule + public static TestRule chain = RuleChain.outerRule(orchestrator) + .around(users) + .around(organizations); + + @BeforeClass + public static void setUp() { + setServerProperty(orchestrator, SETTING_CREATE_PERSONAL_ORG, "true"); + } + + @AfterClass + public static void tearDown() { + setServerProperty(orchestrator, SETTING_CREATE_PERSONAL_ORG, null); + } + + @Test + public void personal_organizations_are_created_for_new_users() { + WsUsers.CreateWsResponse.User user = users.createUser(); + + List<Organizations.Organization> existing = organizations.getWsService().search(SearchWsRequest.builder().build()).getOrganizationsList(); + assertThat(existing) + .filteredOn(o -> o.getGuarded()) + .filteredOn(o -> o.getKey().equals(user.getLogin())) + .hasSize(1) + .matches(l -> l.get(0).getName().equals(user.getName())); + + organizations.assertThatMemberOf(existing.get(0), user); + } +} diff --git a/it/it-tests/src/test/java/it/organization/RootUserOnOrganizationTest.java b/it/it-tests/src/test/java/it/organization/RootUserOnOrganizationTest.java index dbf4432593d..1e674c12f3e 100644 --- a/it/it-tests/src/test/java/it/organization/RootUserOnOrganizationTest.java +++ b/it/it-tests/src/test/java/it/organization/RootUserOnOrganizationTest.java @@ -22,57 +22,39 @@ package it.organization; import com.sonar.orchestrator.Orchestrator; import it.Category6Suite; import java.sql.SQLException; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; import org.sonarqube.ws.WsRoot; -import org.sonarqube.ws.client.HttpException; import org.sonarqube.ws.client.WsClient; -import org.sonarqube.ws.client.user.SearchRequest; -import org.sonarqube.ws.client.user.UsersService; +import util.OrganizationRule; import util.user.UserRule; -import static it.Category6Suite.enableOrganizationsSupport; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; +import static util.ItUtils.expectBadRequestError; +import static util.ItUtils.expectForbiddenError; import static util.ItUtils.newAdminWsClient; import static util.ItUtils.newUserWsClient; public class RootUserOnOrganizationTest { - @ClassRule - public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - - private static UserRule userRule; + private static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; + private static OrganizationRule organizationRule = new OrganizationRule(orchestrator); - @Before - public void start() { - userRule = UserRule.from(orchestrator); - } - - @After - public void tearDown() throws Exception { - UsersService service = newAdminWsClient(orchestrator).users(); - service.search(SearchRequest.builder().build()).getUsersList() - .stream() - .filter(u -> !u.getLogin().equals("admin")) - .forEach(u -> { - userRule.deactivateUsers(u.getLogin()); - }); - } + @ClassRule + public static TestRule chain = RuleChain.outerRule(orchestrator) + .around(organizationRule); - @BeforeClass - public static void enableOrganizations() throws Exception { - enableOrganizationsSupport(); - } + @Rule + public UserRule userRule = UserRule.from(orchestrator); @Test public void system_administrator_is_flagged_as_root_when_he_enables_organization_support() { assertThat(newAdminWsClient(orchestrator).rootService().search().getRootsList()) .extracting(WsRoot.Root::getLogin) - .containsOnly(UserRule.ADMIN_LOGIN); + .containsExactly(UserRule.ADMIN_LOGIN); } @Test @@ -87,7 +69,7 @@ public class RootUserOnOrganizationTest { @Test public void last_root_can_not_be_unset_root() throws SQLException { - verifyHttpError(() -> newAdminWsClient(orchestrator).rootService().unsetRoot(UserRule.ADMIN_LOGIN), 400); + expectBadRequestError(() -> newAdminWsClient(orchestrator).rootService().unsetRoot(UserRule.ADMIN_LOGIN)); } @Test @@ -98,11 +80,11 @@ public class RootUserOnOrganizationTest { WsClient root2WsClient = newUserWsClient(orchestrator, "root2", "bar"); // non root can not set or unset root another user not itself - verifyHttpError(() -> root1WsClient.rootService().setRoot("root2"), 403); - verifyHttpError(() -> root1WsClient.rootService().setRoot("root1"), 403); - verifyHttpError(() -> root1WsClient.rootService().unsetRoot("root1"), 403); - verifyHttpError(() -> root2WsClient.rootService().unsetRoot("root1"), 403); - verifyHttpError(() -> root2WsClient.rootService().unsetRoot("root2"), 403); + expectForbiddenError(() -> root1WsClient.rootService().setRoot("root2")); + expectForbiddenError(() -> root1WsClient.rootService().setRoot("root1")); + expectForbiddenError(() -> root1WsClient.rootService().unsetRoot("root1")); + expectForbiddenError(() -> root2WsClient.rootService().unsetRoot("root1")); + expectForbiddenError(() -> root2WsClient.rootService().unsetRoot("root2")); // admin (the first root) sets root1 as root newAdminWsClient(orchestrator).rootService().setRoot("root1"); // root1 can set root root2 @@ -112,13 +94,5 @@ public class RootUserOnOrganizationTest { // root2 can unset root itself as it's not the last root root2WsClient.rootService().unsetRoot("root2"); } - - private static void verifyHttpError(Runnable runnable, int expectedErrorCode) { - try { - runnable.run(); - fail("Ws Call should have failed with http code " + expectedErrorCode); - } catch (HttpException e) { - assertThat(e.code()).isEqualTo(expectedErrorCode); - } - } + } diff --git a/it/it-tests/src/test/java/it/organization/RootUserTest.java b/it/it-tests/src/test/java/it/organization/RootUserTest.java index 2692f7bd347..4e6c51eb1e3 100644 --- a/it/it-tests/src/test/java/it/organization/RootUserTest.java +++ b/it/it-tests/src/test/java/it/organization/RootUserTest.java @@ -23,10 +23,8 @@ import com.sonar.orchestrator.Orchestrator; import it.Category4Suite; import org.junit.ClassRule; import org.junit.Test; -import org.sonarqube.ws.client.HttpException; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; +import static util.ItUtils.expectForbiddenError; import static util.ItUtils.newAdminWsClient; import static util.ItUtils.newWsClient; @@ -36,20 +34,11 @@ public class RootUserTest { public static Orchestrator orchestrator = Category4Suite.ORCHESTRATOR; @Test - public void nobody_is_root_by_default() { + public void nobody_is_root_by_default_when_organizations_are_disabled() { // anonymous - verifyHttpError(() -> newWsClient(orchestrator).rootService().search(), 403); + expectForbiddenError(() -> newWsClient(orchestrator).rootService().search()); // admin - verifyHttpError(() -> newAdminWsClient(orchestrator).rootService().search(), 403); - } - - private static void verifyHttpError(Runnable runnable, int expectedErrorCode) { - try { - runnable.run(); - fail("Ws Call should have failed with http code " + expectedErrorCode); - } catch (HttpException e) { - assertThat(e.code()).isEqualTo(expectedErrorCode); - } + expectForbiddenError(() -> newAdminWsClient(orchestrator).rootService().search()); } } diff --git a/it/it-tests/src/test/java/it/projectSearch/LeakProjectsPageTest.java b/it/it-tests/src/test/java/it/projectSearch/LeakProjectsPageTest.java index 95e06a627cc..cfa30558bcb 100644 --- a/it/it-tests/src/test/java/it/projectSearch/LeakProjectsPageTest.java +++ b/it/it-tests/src/test/java/it/projectSearch/LeakProjectsPageTest.java @@ -25,25 +25,23 @@ import it.Category6Suite; import java.util.ArrayList; import java.util.List; import javax.annotation.Nullable; -import org.junit.After; +import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; -import org.sonarqube.ws.client.WsClient; -import org.sonarqube.ws.client.organization.CreateWsRequest; +import org.sonarqube.ws.Organizations.Organization; import pageobjects.Navigation; import pageobjects.projects.ProjectsPage; -import util.ItUtils; +import util.OrganizationRule; import static com.codeborne.selenide.WebDriverRunner.url; -import static it.Category6Suite.enableOrganizationsSupport; import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.newAdminWsClient; import static util.ItUtils.newProjectKey; import static util.ItUtils.projectDir; +import static util.ItUtils.resetSettings; import static util.ItUtils.restoreProfile; import static util.ItUtils.setServerProperty; @@ -53,32 +51,26 @@ public class LeakProjectsPageTest { public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; @Rule + public OrganizationRule organizationRule = new OrganizationRule(orchestrator); + @Rule public Navigation nav = Navigation.get(orchestrator); - private static WsClient wsClient; - - private String organizationKey; + private Organization organization; @BeforeClass - public static void beforeClass() throws Exception { - enableOrganizationsSupport(); + public static void beforeClass() { setServerProperty(orchestrator, "sonar.leak.period", "previous_analysis"); - wsClient = newAdminWsClient(orchestrator); } - @Before - public void setUp() throws Exception { - organizationKey = ItUtils.newOrganizationKey(); - wsClient.organizations().create(CreateWsRequest.builder() - .setKey(organizationKey) - .setName(organizationKey) - .build()); - restoreProfile(orchestrator, SearchProjectsTest.class.getResource("/projectSearch/SearchProjectsTest/with-many-rules.xml"), organizationKey); + @AfterClass + public static void tearDown() { + resetSettings(orchestrator, null, "sonar.leak.period"); } - @After - public void tearDown() { - wsClient.organizations().delete(organizationKey); + @Before + public void setUp() { + organization = organizationRule.create(); + restoreProfile(orchestrator, SearchProjectsTest.class.getResource("/projectSearch/SearchProjectsTest/with-many-rules.xml"), organization.getKey()); } @Test @@ -94,7 +86,7 @@ public class LeakProjectsPageTest { analyzeProject(projectKey1, "shared/xoo-sample", null); // Check the facets and project cards - ProjectsPage page = nav.logIn().asAdmin().openProjects(organizationKey); + ProjectsPage page = nav.logIn().asAdmin().openProjects(organization.getKey()); page.changePerspective("Leak"); assertThat(url()).endsWith("/projects?view=leak"); page.shouldHaveTotal(2); @@ -117,7 +109,7 @@ public class LeakProjectsPageTest { private void analyzeProject(String projectKey, String relativePath, @Nullable String analysisDate) { List<String> keyValueProperties = new ArrayList<>(asList( "sonar.projectKey", projectKey, - "sonar.organization", organizationKey, + "sonar.organization", organization.getKey(), "sonar.profile", "with-many-rules", "sonar.login", "admin", "sonar.password", "admin", "sonar.scm.disabled", "false")); diff --git a/it/it-tests/src/test/java/it/projectSearch/SearchProjectsTest.java b/it/it-tests/src/test/java/it/projectSearch/SearchProjectsTest.java index ec1bdc68de1..abfd79bf6de 100644 --- a/it/it-tests/src/test/java/it/projectSearch/SearchProjectsTest.java +++ b/it/it-tests/src/test/java/it/projectSearch/SearchProjectsTest.java @@ -26,26 +26,23 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.assertj.core.groups.Tuple; -import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; import org.sonarqube.ws.Common; +import org.sonarqube.ws.Organizations.Organization; import org.sonarqube.ws.WsComponents.Component; import org.sonarqube.ws.WsComponents.SearchProjectsWsResponse; import org.sonarqube.ws.client.component.SearchProjectsRequest; -import org.sonarqube.ws.client.organization.CreateWsRequest; import org.sonarqube.ws.client.project.CreateRequest; -import util.ItUtils; +import util.OrganizationRule; -import static it.Category6Suite.enableOrganizationsSupport; 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.groups.Tuple.tuple; import static util.ItUtils.concat; -import static util.ItUtils.deleteOrganizationsIfExists; import static util.ItUtils.newAdminWsClient; import static util.ItUtils.newProjectKey; import static util.ItUtils.projectDir; @@ -61,26 +58,15 @@ public class SearchProjectsTest { @ClassRule public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - private String organizationKey; + @Rule + public OrganizationRule organizations = new OrganizationRule(orchestrator); - @BeforeClass - public static void beforeClass() throws Exception { - enableOrganizationsSupport(); - } + private Organization organization; @Before - public void setUp() throws Exception { - organizationKey = ItUtils.newOrganizationKey(); - newAdminWsClient(orchestrator).organizations().create(CreateWsRequest.builder() - .setKey(organizationKey) - .setName(organizationKey) - .build()); - restoreProfile(orchestrator, SearchProjectsTest.class.getResource("/projectSearch/SearchProjectsTest/with-many-rules.xml"), organizationKey); - } - - @After - public void tearDown() throws Exception { - deleteOrganizationsIfExists(orchestrator, organizationKey); + public void setUp() { + organization = organizations.create(); + restoreProfile(orchestrator, SearchProjectsTest.class.getResource("/projectSearch/SearchProjectsTest/with-many-rules.xml"), organization.getKey()); } @Test @@ -105,9 +91,9 @@ public class SearchProjectsTest { @Test public void provisioned_projects_should_be_included_to_results() throws Exception { String projectKey = newProjectKey(); - newAdminWsClient(orchestrator).projects().create(CreateRequest.builder().setKey(projectKey).setName(projectKey).setOrganization(organizationKey).build()); + newAdminWsClient(orchestrator).projects().create(CreateRequest.builder().setKey(projectKey).setName(projectKey).setOrganization(organization.getKey()).build()); - SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organizationKey).build()); + SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organization.getKey()).build()); assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly(projectKey); } @@ -124,10 +110,10 @@ public class SearchProjectsTest { analyzeProject(projectKey2, "shared/xoo-sample"); // This project is provisioned, so has no leak period String projectKey3 = newProjectKey(); - newAdminWsClient(orchestrator).projects().create(CreateRequest.builder().setKey(projectKey3).setName(projectKey3).setOrganization(organizationKey).build()); + newAdminWsClient(orchestrator).projects().create(CreateRequest.builder().setKey(projectKey3).setName(projectKey3).setOrganization(organization.getKey()).build()); SearchProjectsWsResponse response = searchProjects( - SearchProjectsRequest.builder().setAdditionalFields(singletonList("leakPeriodDate")).setOrganization(organizationKey).build()); + SearchProjectsRequest.builder().setAdditionalFields(singletonList("leakPeriodDate")).setOrganization(organization.getKey()).build()); assertThat(response.getComponentsList()).extracting(Component::getKey, Component::hasLeakPeriodDate) .containsOnly( @@ -175,7 +161,7 @@ public class SearchProjectsTest { analyzeProject(newProjectKey(), "shared/xoo-sample"); analyzeProject(newProjectKey(), "shared/xoo-multi-modules-sample"); - SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organizationKey).setFacets(asList( + SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organization.getKey()).setFacets(asList( "alert_status", "coverage", "duplicated_lines_density", @@ -245,7 +231,7 @@ public class SearchProjectsTest { analyzeProject(projectKey2, "projectSearch/xoo-history-v1", "sonar.projectDate", "2016-12-31"); analyzeProject(projectKey2, "projectSearch/xoo-history-v2"); - SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organizationKey).setFacets(asList( + SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organization.getKey()).setFacets(asList( "new_reliability_rating", "new_security_rating", "new_maintainability_rating", "new_coverage", "new_duplicated_lines_density", "new_lines")).build()); checkFacet(response, "new_reliability_rating", @@ -296,7 +282,7 @@ public class SearchProjectsTest { private void analyzeProject(String projectKey, String relativePath, String... properties) { List<String> keyValueProperties = new ArrayList<>(asList( "sonar.projectKey", projectKey, - "sonar.organization", organizationKey, + "sonar.organization", organization.getKey(), "sonar.profile", "with-many-rules", "sonar.login", "admin", "sonar.password", "admin", "sonar.scm.disabled", "false")); @@ -304,7 +290,7 @@ public class SearchProjectsTest { } private SearchProjectsWsResponse searchProjects(String filter) throws IOException { - return searchProjects(SearchProjectsRequest.builder().setOrganization(organizationKey).setFilter(filter).build()); + return searchProjects(SearchProjectsRequest.builder().setOrganization(organization.getKey()).setFilter(filter).build()); } private SearchProjectsWsResponse searchProjects(SearchProjectsRequest request) throws IOException { diff --git a/it/it-tests/src/test/java/it/qualityProfile/BuiltInQualityProfilesTest.java b/it/it-tests/src/test/java/it/qualityProfile/BuiltInQualityProfilesTest.java new file mode 100644 index 00000000000..07ce9131de1 --- /dev/null +++ b/it/it-tests/src/test/java/it/qualityProfile/BuiltInQualityProfilesTest.java @@ -0,0 +1,166 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 it.qualityProfile; + +import com.sonar.orchestrator.Orchestrator; +import it.Category6Suite; +import java.util.function.Predicate; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; +import org.sonarqube.ws.Organizations.Organization; +import org.sonarqube.ws.QualityProfiles; +import org.sonarqube.ws.QualityProfiles.CreateWsResponse; +import org.sonarqube.ws.QualityProfiles.SearchWsResponse; +import org.sonarqube.ws.QualityProfiles.SearchWsResponse.QualityProfile; +import org.sonarqube.ws.WsUsers; +import org.sonarqube.ws.client.qualityprofile.ChangeParentRequest; +import org.sonarqube.ws.client.qualityprofile.CopyRequest; +import org.sonarqube.ws.client.qualityprofile.DeleteRequest; +import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; +import org.sonarqube.ws.client.qualityprofile.SetDefaultRequest; +import util.OrganizationRule; +import util.QualityProfileRule; +import util.QualityProfileSupport; +import util.user.UserRule; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static util.ItUtils.expectBadRequestError; + +public class BuiltInQualityProfilesTest { + private static final String RULE_ONE_BUG_PER_LINE = "xoo:OneBugIssuePerLine"; + public static final String A_PASSWORD = "aPassword"; + + private static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; + private static OrganizationRule organizations = new OrganizationRule(orchestrator); + private static QualityProfileRule profiles = new QualityProfileRule(orchestrator); + private static UserRule users = new UserRule(orchestrator); + + @ClassRule + public static TestRule chain = RuleChain.outerRule(orchestrator) + .around(organizations) + .around(profiles) + .around(users); + + @Test + public void built_in_profiles_are_available_in_new_organization() { + Organization org = organizations.create(); + SearchWsResponse result = profiles.getWsService().search(new SearchWsRequest().setOrganizationKey(org.getKey())); + + assertThat(result.getProfilesList()) + .extracting(QualityProfile::getName, QualityProfile::getLanguage, QualityProfile::getIsBuiltIn, QualityProfile::getIsDefault) + .containsExactlyInAnyOrder( + tuple("Basic", "xoo", true, true), + tuple("empty", "xoo", true, false), + tuple("Basic", "xoo2", true, true)); + } + + @Test + public void built_in_profiles_are_available_in_default_organization() { + SearchWsResponse result = profiles.getWsService().search(new SearchWsRequest().setOrganizationKey("default-organization")); + + assertThat(result.getProfilesList()) + .extracting(QualityProfile::getOrganization, QualityProfile::getName, QualityProfile::getLanguage, QualityProfile::getIsBuiltIn, QualityProfile::getIsDefault) + .containsExactlyInAnyOrder( + tuple("default-organization", "Basic", "xoo", true, true), + tuple("default-organization", "empty", "xoo", true, false), + tuple("default-organization", "Basic", "xoo2", true, true)); + } + + @Test + public void cannot_delete_built_in_profile_even_when_not_the_default_profile() { + Organization org = organizations.create(); + QualityProfile builtInProfile = getProfile(org, p -> p.getIsBuiltIn() && p.getIsDefault() && "Basic".equals(p.getName()) && "xoo".equals(p.getLanguage())); + + CreateWsResponse.QualityProfile profileInOrg = profiles.createXooProfile(org); + profiles.getWsService().setDefault(new SetDefaultRequest(profileInOrg.getKey())); + + expectBadRequestError(() -> + profiles.getWsService().delete(new DeleteRequest(builtInProfile.getKey()))); + } + + @Test + public void built_in_profile_cannot_be_modified() { + Organization org = organizations.create(); + QualityProfile builtInProfile = getProfile(org, p -> p.getIsBuiltIn() && p.getIsDefault() && "Basic".equals(p.getName()) && "xoo".equals(p.getLanguage())); + + expectBadRequestError(() -> profiles.activateRule(builtInProfile, RULE_ONE_BUG_PER_LINE)); + expectBadRequestError(() -> profiles.deactivateRule(builtInProfile, RULE_ONE_BUG_PER_LINE)); + expectBadRequestError(() -> profiles.delete(builtInProfile)); + } + + @Test + public void copy_built_in_profile_to_a_custom_profile() { + Organization org = organizations.create(); + WsUsers.CreateWsResponse.User administrator = users.createAdministrator(org, A_PASSWORD); + QualityProfile builtInProfile = getProfile(org, p -> p.getIsBuiltIn() && "Basic".equals(p.getName()) && "xoo".equals(p.getLanguage())); + QualityProfileSupport adminProfiles = profiles.as(administrator.getLogin(), A_PASSWORD); + + QualityProfiles.CopyWsResponse copyResponse = adminProfiles.getWsService().copy(new CopyRequest(builtInProfile.getKey(), "My copy")); + + assertThat(copyResponse.getIsDefault()).isFalse(); + assertThat(copyResponse.getKey()).isNotEmpty().isNotEqualTo(builtInProfile.getKey()); + assertThat(copyResponse.getLanguage()).isEqualTo(builtInProfile.getLanguage()); + assertThat(copyResponse.getName()).isEqualTo("My copy"); + assertThat(copyResponse.getIsInherited()).isFalse(); + + QualityProfile copy = getProfile(org, p -> "My copy".equals(p.getName()) && "xoo".equals(p.getLanguage())); + assertThat(copy.getIsBuiltIn()).isFalse(); + assertThat(copy.getIsDefault()).isFalse(); + assertThat(builtInProfile.getActiveRuleCount()).isGreaterThan(0); + adminProfiles.assertThatNumberOfActiveRulesEqualsTo(copy, (int)builtInProfile.getActiveRuleCount()); + } + + @Test + public void can_inherit_and_disinherit_from_built_in_profile_to_a_custom_profile() { + Organization org = organizations.create(); + WsUsers.CreateWsResponse.User administrator = users.createAdministrator(org, A_PASSWORD); + QualityProfile builtInProfile = getProfile(org, p -> p.getIsBuiltIn() && "Basic".equals(p.getName()) && "xoo".equals(p.getLanguage())); + QualityProfileSupport adminProfiles = profiles.as(administrator.getLogin(), A_PASSWORD); + + QualityProfiles.CopyWsResponse copyResponse = adminProfiles.getWsService().copy(new CopyRequest(builtInProfile.getKey(), "My copy")); + adminProfiles.getWsService().changeParent( + ChangeParentRequest.builder().setParentKey(builtInProfile.getKey()).setProfileKey(copyResponse.getKey()).build()); + + QualityProfile inheritedQualityPropfile = getProfile(org, p -> p.getKey().equals(copyResponse.getKey())); + + assertThat(inheritedQualityPropfile.getParentKey()).isEqualTo(builtInProfile.getKey()); + assertThat(inheritedQualityPropfile.getParentName()).isEqualTo(builtInProfile.getName()); + + // Remove inheritance + adminProfiles.getWsService().changeParent( + new ChangeParentRequest(ChangeParentRequest.builder().setProfileKey(inheritedQualityPropfile.getKey()))); + + inheritedQualityPropfile = getProfile(org, p -> p.getKey().equals(copyResponse.getKey())); + + assertThat(inheritedQualityPropfile.getParentKey()).isEmpty(); + assertThat(inheritedQualityPropfile.getParentName()).isEmpty(); + } + + private QualityProfile getProfile(Organization organization, Predicate<QualityProfile> filter) { + return profiles.getWsService().search(new SearchWsRequest() + .setOrganizationKey(organization.getKey())).getProfilesList() + .stream() + .filter(filter) + .findAny().orElseThrow(IllegalStateException::new); + } +} diff --git a/it/it-tests/src/test/java/it/qualityProfile/CustomQualityProfilesTest.java b/it/it-tests/src/test/java/it/qualityProfile/CustomQualityProfilesTest.java new file mode 100644 index 00000000000..2de56eaf33b --- /dev/null +++ b/it/it-tests/src/test/java/it/qualityProfile/CustomQualityProfilesTest.java @@ -0,0 +1,334 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 it.qualityProfile; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import com.sonar.orchestrator.http.HttpMethod; +import it.Category6Suite; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; +import org.sonarqube.ws.Organizations.Organization; +import org.sonarqube.ws.QualityProfiles; +import org.sonarqube.ws.QualityProfiles.CreateWsResponse.QualityProfile; +import org.sonarqube.ws.WsUsers.CreateWsResponse.User; +import org.sonarqube.ws.client.qualityprofile.AddProjectRequest; +import org.sonarqube.ws.client.qualityprofile.ChangeParentRequest; +import org.sonarqube.ws.client.qualityprofile.CopyRequest; +import org.sonarqube.ws.client.qualityprofile.CreateRequest; +import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; +import org.sonarqube.ws.client.qualityprofile.SetDefaultRequest; +import util.ItUtils; +import util.OrganizationRule; +import util.QualityProfileRule; +import util.QualityProfileSupport; +import util.user.UserRule; + +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.expectForbiddenError; +import static util.ItUtils.expectMissingError; +import static util.ItUtils.expectUnauthorizedError; +import static util.ItUtils.projectDir; + +public class CustomQualityProfilesTest { + + private static final String A_PASSWORD = "a_password"; + + private static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; + private static OrganizationRule organizations = new OrganizationRule(orchestrator); + private static QualityProfileRule profiles = new QualityProfileRule(orchestrator); + private static UserRule users = new UserRule(orchestrator); + + @ClassRule + public static TestRule chain = RuleChain.outerRule(orchestrator) + .around(organizations) + .around(profiles) + .around(users); + + @Test + public void activation_of_rules_is_isolated_among_organizations() { + // create two profiles with same names in two organizations + Organization org1 = organizations.create(); + Organization org2 = organizations.create(); + QualityProfile profileInOrg1 = profiles.createXooProfile(org1, p -> p.setProfileName("foo")); + QualityProfile profileInOrg2 = profiles.createXooProfile(org2, p -> p.setProfileName("foo")); + + profiles + .assertThatNumberOfActiveRulesEqualsTo(profileInOrg1, 0) + .assertThatNumberOfActiveRulesEqualsTo(profileInOrg2, 0); + + profiles + .activateRule(profileInOrg1, "xoo:OneIssuePerLine") + .assertThatNumberOfActiveRulesEqualsTo(profileInOrg1, 1) + .assertThatNumberOfActiveRulesEqualsTo(profileInOrg2, 0); + + profiles + .activateRule(profileInOrg1, "xoo:OneIssuePerFile") + .assertThatNumberOfActiveRulesEqualsTo(profileInOrg1, 2) + .assertThatNumberOfActiveRulesEqualsTo(profileInOrg2, 0); + + profiles + .deactivateRule(profileInOrg1, "xoo:OneIssuePerFile") + .assertThatNumberOfActiveRulesEqualsTo(profileInOrg1, 1) + .assertThatNumberOfActiveRulesEqualsTo(profileInOrg2, 0); + + profiles + .activateRule(profileInOrg2, "xoo:OneIssuePerFile") + .assertThatNumberOfActiveRulesEqualsTo(profileInOrg1, 1) + .assertThatNumberOfActiveRulesEqualsTo(profileInOrg2, 1); + + profiles + .delete(profileInOrg1) + .assertThatNumberOfActiveRulesEqualsTo(profileInOrg1, 0) + .assertThatNumberOfActiveRulesEqualsTo(profileInOrg2, 1); + } + + @Test + public void an_organization_administrator_can_manage_the_profiles_of_organization() { + Organization org = organizations.create(); + User user = users.createAdministrator(org, A_PASSWORD); + + QualityProfileSupport adminProfiles = profiles.as(user.getLogin(), A_PASSWORD); + QualityProfile profile = adminProfiles.createXooProfile(org); + adminProfiles.assertThatNumberOfActiveRulesEqualsTo(profile, 0); + + adminProfiles + .activateRule(profile, "xoo:OneIssuePerFile") + .assertThatNumberOfActiveRulesEqualsTo(profile, 1); + + adminProfiles + .delete(profile) + .assertThatNumberOfActiveRulesEqualsTo(profile, 0); + } + + @Test + public void deleting_an_organization_delete_all_profiles_on_this_organization() { + Organization org = organizations.create(); + User user = users.createAdministrator(org, A_PASSWORD); + + QualityProfileSupport adminProfiles = profiles.as(user.getLogin(), A_PASSWORD); + // Profile + QualityProfile parentProfile = adminProfiles.createXooProfile(org); + + // Copied profile + QualityProfiles.SearchWsResponse.QualityProfile builtInProfile = getProfile(org, p -> p.getIsBuiltIn() && "Basic".equals(p.getName()) && "xoo".equals(p.getLanguage())); + QualityProfiles.CopyWsResponse copyResponse = adminProfiles.getWsService().copy(new CopyRequest(builtInProfile.getKey(), "My copy")); + + // Inherited profile from custom + QualityProfile inheritedProfile1 = adminProfiles.getWsService().create( + CreateRequest.builder() + .setLanguage(parentProfile.getLanguage()) + .setOrganizationKey(org.getKey()) + .setProfileName("inherited_profile") + .build()).getProfile(); + + adminProfiles.getWsService().changeParent( + ChangeParentRequest.builder().setParentKey(parentProfile.getKey()).setProfileKey(inheritedProfile1.getKey()).build()); + + // Inherited profile from builtIn + QualityProfile inheritedProfile2 = adminProfiles.getWsService().create( + CreateRequest.builder() + .setLanguage(parentProfile.getLanguage()) + .setOrganizationKey(org.getKey()) + .setProfileName("inherited_profile2") + .build()).getProfile(); + + adminProfiles.getWsService().changeParent( + ChangeParentRequest.builder().setParentKey(builtInProfile.getKey()).setProfileKey(inheritedProfile2.getKey()).build()); + + organizations.delete(org); + + expectMissingError(() -> profiles.getWsService().search(new SearchWsRequest() + .setOrganizationKey(org.getKey())).getProfilesList()); + + profiles.getWsService().search(new SearchWsRequest()).getProfilesList().stream() + .forEach(p -> { + assertThat(p.getOrganization()).isNotEqualTo(org.getKey()); + assertThat(p.getKey()).isNotIn(parentProfile.getKey(), copyResponse.getKey(), inheritedProfile1.getKey(), inheritedProfile2.getKey()); + }); + } + + @Test + public void an_organization_administrator_cannot_manage_the_profiles_of_other_organizations() { + Organization org1 = organizations.create(); + Organization org2 = organizations.create(); + QualityProfile profileInOrg2 = profiles.createXooProfile(org2); + User adminOfOrg1 = users.createAdministrator(org1, A_PASSWORD); + + QualityProfileSupport adminProfiles = profiles.as(adminOfOrg1.getLogin(), A_PASSWORD); + + expectForbiddenError(() -> adminProfiles.createXooProfile(org2)); + expectForbiddenError(() -> adminProfiles.delete(profileInOrg2)); + expectForbiddenError(() -> adminProfiles.activateRule(profileInOrg2, "xoo:OneIssuePerFile")); + expectForbiddenError(() -> adminProfiles.deactivateRule(profileInOrg2, "xoo:OneIssuePerFile")); + } + + @Test + public void anonymous_cannot_manage_the_profiles_of_an_organization() { + Organization org = organizations.create(); + QualityProfile profile = profiles.createXooProfile(org); + + QualityProfileSupport anonymousProfiles = profiles.asAnonymous(); + + expectUnauthorizedError(() -> anonymousProfiles.createXooProfile(org)); + expectUnauthorizedError(() -> anonymousProfiles.delete(profile)); + expectUnauthorizedError(() -> anonymousProfiles.activateRule(profile, "xoo:OneIssuePerFile")); + expectUnauthorizedError(() -> anonymousProfiles.deactivateRule(profile, "xoo:OneIssuePerFile")); + } + + @Test + public void root_can_manage_the_profiles_of_any_organization() { + Organization org = organizations.create(); + + User orgAdmin = users.createAdministrator(org, A_PASSWORD); + QualityProfileSupport adminProfiles = profiles.as(orgAdmin.getLogin(), A_PASSWORD); + QualityProfile profile = adminProfiles.createXooProfile(org); + + // root can activate rule and delete the profile + profiles + .activateRule(profile, "xoo:OneIssuePerFile") + .assertThatNumberOfActiveRulesEqualsTo(profile, 1); + profiles + .delete(profile) + .assertThatNumberOfActiveRulesEqualsTo(profile, 0); + } + + @Test + public void can_inherit_and_disinherit_and__from_another_custom_profile() { + Organization org = organizations.create(); + User user = users.createAdministrator(org, A_PASSWORD); + + QualityProfileSupport adminProfiles = profiles.as(user.getLogin(), A_PASSWORD); + QualityProfile parentProfile = adminProfiles.createXooProfile(org); + QualityProfile inheritedProfile = adminProfiles.getWsService().create( + CreateRequest.builder() + .setLanguage(parentProfile.getLanguage()) + .setOrganizationKey(org.getKey()) + .setProfileName("inherited_profile") + .build()).getProfile(); + + adminProfiles.getWsService().changeParent( + ChangeParentRequest.builder().setParentKey(parentProfile.getKey()).setProfileKey(inheritedProfile.getKey()).build()); + + QualityProfiles.SearchWsResponse.QualityProfile inheritedQualityPropfile = getProfile(org, p -> p.getKey().equals(inheritedProfile.getKey())); + + assertThat(inheritedQualityPropfile.getParentKey()).isEqualTo(parentProfile.getKey()); + assertThat(inheritedQualityPropfile.getParentName()).isEqualTo(parentProfile.getName()); + + // Remove inheritance + adminProfiles.getWsService().changeParent( + new ChangeParentRequest(ChangeParentRequest.builder().setProfileKey(inheritedQualityPropfile.getKey()))); + + inheritedQualityPropfile = getProfile(org, p -> p.getKey().equals(inheritedProfile.getKey())); + + assertThat(inheritedQualityPropfile.getParentKey()).isEmpty(); + assertThat(inheritedQualityPropfile.getParentName()).isEmpty(); + } + + @Test + public void analysis_must_use_default_profile() { + Organization org = organizations.create(); + User user = users.createAdministrator(org, A_PASSWORD); + + QualityProfileSupport adminProfiles = profiles.as(user.getLogin(), A_PASSWORD); + + String projectKey = "test-project"; + orchestrator.executeBuild( + SonarScanner.create(projectDir("shared/xoo-sample"), + "sonar.login", user.getLogin(), + "sonar.password", A_PASSWORD, + "sonar.organization", org.getKey()) + .setProjectKey(projectKey) + .setProjectName("my-project") + ); + + QualityProfiles.SearchWsResponse.QualityProfile defaultProfile = getProfile(org, p -> "xoo".equals(p.getLanguage()) && p.getIsDefault()); + assertThatQualityProfileIsUsedFor(projectKey, defaultProfile.getKey()); + + QualityProfile newXooProfile = adminProfiles.createXooProfile(org); + profiles.getWsService().setDefault(new SetDefaultRequest(newXooProfile.getKey())); + + orchestrator.executeBuild( + SonarScanner.create(projectDir("shared/xoo-sample"), + "sonar.login", user.getLogin(), + "sonar.password", A_PASSWORD, + "sonar.organization", org.getKey()) + .setProjectKey(projectKey) + .setProjectName("my-project") + ); + + assertThatQualityProfileIsUsedFor(projectKey, newXooProfile.getKey()); + } + + @Test + public void analysis_must_use_associated_profile() { + Organization org = organizations.create(); + User user = users.createAdministrator(org, A_PASSWORD); + String projectKey = "test-project"; + String projectName = "my-project"; + QualityProfileSupport adminProfiles = profiles.as(user.getLogin(), A_PASSWORD); + QualityProfile newXooProfile = adminProfiles.createXooProfile(org); + + orchestrator.getServer().newHttpCall("api/projects/create") + .setCredentials(user.getLogin(), A_PASSWORD) + .setParam("project", projectKey) + .setParam("name", projectName) + .setParam("organization", org.getKey()) + .setMethod(HttpMethod.POST) + .execute(); + + adminProfiles.getWsService().addProject(AddProjectRequest.builder() + .setProfileKey(newXooProfile.getKey()) + .setProjectKey(projectKey) + .build()); + + orchestrator.executeBuild( + SonarScanner.create(projectDir("shared/xoo-sample"), + "sonar.login", user.getLogin(), + "sonar.password", A_PASSWORD, + "sonar.organization", org.getKey()) + .setProjectKey(projectKey) + .setProjectName(projectName) + ); + + assertThatQualityProfileIsUsedFor(projectKey, newXooProfile.getKey()); + } + + private static void assertThatQualityProfileIsUsedFor(String projectKey, String qualityProfileKey) { + Map components = ItUtils.jsonToMap(orchestrator.getServer().newHttpCall("api/navigation/component") + .setParam("componentKey", projectKey) + .execute().getBodyAsString()); + + assertThat(((Map) ((List) components.get("qualityProfiles")).get(0)).get("key")).isEqualTo(qualityProfileKey); + } + + private QualityProfiles.SearchWsResponse.QualityProfile getProfile(Organization organization, Predicate<QualityProfiles.SearchWsResponse.QualityProfile> filter) { + return profiles.getWsService().search(new SearchWsRequest() + .setOrganizationKey(organization.getKey())).getProfilesList() + .stream() + .filter(filter) + .findAny().orElseThrow(IllegalStateException::new); + } +} diff --git a/it/it-tests/src/test/java/it/qualityProfile/OrganizationQualityProfilesPageTest.java b/it/it-tests/src/test/java/it/qualityProfile/OrganizationQualityProfilesUiTest.java index 0c57d7b2782..f3eb040aebe 100644 --- a/it/it-tests/src/test/java/it/qualityProfile/OrganizationQualityProfilesPageTest.java +++ b/it/it-tests/src/test/java/it/qualityProfile/OrganizationQualityProfilesUiTest.java @@ -24,42 +24,39 @@ import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.SonarScanner; import it.Category6Suite; import org.junit.After; -import org.junit.AfterClass; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Ignore; +import org.junit.Rule; import org.junit.Test; +import org.sonarqube.ws.Organizations; import org.sonarqube.ws.client.PostRequest; import org.sonarqube.ws.client.WsClient; import org.sonarqube.ws.client.organization.CreateWsRequest; import pageobjects.Navigation; +import util.OrganizationRule; import static com.codeborne.selenide.Selenide.$; -import static it.Category6Suite.enableOrganizationsSupport; -import static util.ItUtils.deleteOrganizations; import static util.ItUtils.newAdminWsClient; import static util.ItUtils.projectDir; import static util.selenium.Selenese.runSelenese; -public class OrganizationQualityProfilesPageTest { +public class OrganizationQualityProfilesUiTest { private static WsClient adminWsClient; - private static final String ORGANIZATION = "test-org"; @ClassRule public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - @BeforeClass - public static void setUp() { - adminWsClient = newAdminWsClient(orchestrator); - enableOrganizationsSupport(); - createOrganization(); - } + @Rule + public OrganizationRule organizationRule = new OrganizationRule(orchestrator); + + private static Organizations.Organization organization; - @AfterClass - public static void tearDown() throws Exception { - deleteOrganizations(orchestrator); + @Before + public void setUp() { + adminWsClient = newAdminWsClient(orchestrator); + organization = adminWsClient.organizations().create(new CreateWsRequest.Builder().setKey("test-org").setName("test-org").build()).getOrganization(); } @Before @@ -87,72 +84,72 @@ public class OrganizationQualityProfilesPageTest { @Test public void testHomePage() throws Exception { runSelenese(orchestrator, - "/organization/OrganizationQualityProfilesPageTest/should_display_list.html", - "/organization/OrganizationQualityProfilesPageTest/should_open_from_list.html", - "/organization/OrganizationQualityProfilesPageTest/should_filter_by_language.html"); + "/organization/OrganizationQualityProfilesUiTest/should_display_list.html", + "/organization/OrganizationQualityProfilesUiTest/should_open_from_list.html", + "/organization/OrganizationQualityProfilesUiTest/should_filter_by_language.html"); } @Test public void testProfilePage() throws Exception { runSelenese(orchestrator, - "/organization/OrganizationQualityProfilesPageTest/should_display_profile_rules.html", - "/organization/OrganizationQualityProfilesPageTest/should_display_profile_inheritance.html", - "/organization/OrganizationQualityProfilesPageTest/should_display_profile_projects.html", - "/organization/OrganizationQualityProfilesPageTest/should_display_profile_exporters.html"); + "/organization/OrganizationQualityProfilesUiTest/should_display_profile_rules.html", + "/organization/OrganizationQualityProfilesUiTest/should_display_profile_inheritance.html", + "/organization/OrganizationQualityProfilesUiTest/should_display_profile_projects.html", + "/organization/OrganizationQualityProfilesUiTest/should_display_profile_exporters.html"); } @Test public void testNotFound() { Navigation nav = Navigation.get(orchestrator); - nav.open("/organizations/" + ORGANIZATION + "/quality_profiles/show?key=unknown"); + nav.open("/organizations/" + organization.getKey() + "/quality_profiles/show?key=unknown"); $(".quality-profile-not-found").should(Condition.visible); - nav.open("/organizations/" + ORGANIZATION + "/quality_profiles/show?language=xoo&name=unknown"); + nav.open("/organizations/" + organization.getKey() + "/quality_profiles/show?language=xoo&name=unknown"); $(".quality-profile-not-found").should(Condition.visible); } @Test public void testProfileChangelog() throws Exception { runSelenese(orchestrator, - "/organization/OrganizationQualityProfilesPageTest/should_display_changelog.html"); + "/organization/OrganizationQualityProfilesUiTest/should_display_changelog.html"); } @Ignore("find a way to know profile key inside selenium tests") @Test public void testComparison() throws Exception { - runSelenese(orchestrator, "/organization/OrganizationQualityProfilesPageTest/should_compare.html"); + runSelenese(orchestrator, "/organization/OrganizationQualityProfilesUiTest/should_compare.html"); } @Test public void testCreation() throws Exception { - runSelenese(orchestrator, "/organization/OrganizationQualityProfilesPageTest/should_create.html"); + runSelenese(orchestrator, "/organization/OrganizationQualityProfilesUiTest/should_create.html"); } @Test public void testDeletion() throws Exception { - runSelenese(orchestrator, "/organization/OrganizationQualityProfilesPageTest/should_delete.html"); + runSelenese(orchestrator, "/organization/OrganizationQualityProfilesUiTest/should_delete.html"); } @Test public void testCopying() throws Exception { - runSelenese(orchestrator, "/organization/OrganizationQualityProfilesPageTest/should_copy.html"); + runSelenese(orchestrator, "/organization/OrganizationQualityProfilesUiTest/should_copy.html"); } @Test public void testRenaming() throws Exception { - runSelenese(orchestrator, "/organization/OrganizationQualityProfilesPageTest/should_rename.html"); + runSelenese(orchestrator, "/organization/OrganizationQualityProfilesUiTest/should_rename.html"); } @Test public void testSettingDefault() throws Exception { - runSelenese(orchestrator, "/organization/OrganizationQualityProfilesPageTest/should_set_default.html"); + runSelenese(orchestrator, "/organization/OrganizationQualityProfilesUiTest/should_set_default.html"); } @Test public void testRestoration() throws Exception { deleteProfile("xoo", "empty"); - runSelenese(orchestrator, "/organization/OrganizationQualityProfilesPageTest/should_restore.html"); + runSelenese(orchestrator, "/organization/OrganizationQualityProfilesUiTest/should_restore.html"); } private static void createProfile(String language, String name) { @@ -160,7 +157,7 @@ public class OrganizationQualityProfilesPageTest { new PostRequest("api/qualityprofiles/create") .setParam("language", language) .setParam("name", name) - .setParam("organization", ORGANIZATION)); + .setParam("organization", organization.getKey())); } private static void inheritProfile(String language, String name, String parentName) { @@ -169,12 +166,12 @@ public class OrganizationQualityProfilesPageTest { .setParam("language", language) .setParam("profileName", name) .setParam("parentName", parentName) - .setParam("organization", ORGANIZATION)); + .setParam("organization", organization.getKey())); } private static void analyzeProject(String path) { orchestrator.executeBuild(SonarScanner.create(projectDir(path)).setProperties( - "sonar.organization", ORGANIZATION, + "sonar.organization", organization.getKey(), "sonar.login", "admin", "sonar.password", "admin")); } @@ -184,7 +181,7 @@ public class OrganizationQualityProfilesPageTest { new PostRequest("api/qualityprofiles/add_project") .setParam("language", language) .setParam("profileName", profileName) - .setParam("organization", ORGANIZATION) + .setParam("organization", organization.getKey()) .setParam("projectKey", projectKey)); } @@ -193,7 +190,7 @@ public class OrganizationQualityProfilesPageTest { new PostRequest("api/qualityprofiles/delete") .setParam("language", language) .setParam("profileName", name) - .setParam("organization", ORGANIZATION)); + .setParam("organization", organization.getKey())); } private static void setDefault(String language, String name) { @@ -201,10 +198,7 @@ public class OrganizationQualityProfilesPageTest { new PostRequest("api/qualityprofiles/set_default") .setParam("language", language) .setParam("profileName", name) - .setParam("organization", ORGANIZATION)); + .setParam("organization", organization.getKey())); } - private static void createOrganization() { - adminWsClient.organizations().create(new CreateWsRequest.Builder().setKey(ORGANIZATION).setName(ORGANIZATION).build()); - } } diff --git a/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesBuiltInTest.java b/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesBuiltInTest.java deleted file mode 100644 index 0d9c3bcb38c..00000000000 --- a/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesBuiltInTest.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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 it.qualityProfile; - -import com.sonar.orchestrator.Orchestrator; -import it.Category6Suite; -import java.util.function.Predicate; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.sonarqube.ws.QualityProfiles; -import org.sonarqube.ws.QualityProfiles.SearchWsResponse; -import org.sonarqube.ws.QualityProfiles.SearchWsResponse.QualityProfile; -import org.sonarqube.ws.client.HttpException; -import org.sonarqube.ws.client.WsClient; -import org.sonarqube.ws.client.organization.CreateWsRequest; -import org.sonarqube.ws.client.qualityprofile.ActivateRuleWsRequest; -import org.sonarqube.ws.client.qualityprofile.CopyRequest; -import org.sonarqube.ws.client.qualityprofile.DeleteRequest; -import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; -import org.sonarqube.ws.client.qualityprofile.SetDefaultRequest; - -import static it.Category6Suite.enableOrganizationsSupport; -import static java.net.HttpURLConnection.HTTP_BAD_REQUEST; -import static org.apache.commons.lang.RandomStringUtils.randomAscii; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; -import static org.junit.Assert.fail; -import static util.ItUtils.newAdminWsClient; -import static util.ItUtils.newOrganizationKey; - -public class QualityProfilesBuiltInTest { - - private static final String ORGANIZATION = newOrganizationKey(); - private static final String RULE_ONE_BUG_PER_LINE = "xoo:OneBugIssuePerLine"; - - @ClassRule - public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - - private static WsClient adminWsClient; - - @BeforeClass - public static void setUp() { - enableOrganizationsSupport(); - adminWsClient = newAdminWsClient(orchestrator); - adminWsClient.organizations().create(new CreateWsRequest.Builder() - .setKey(ORGANIZATION) - .setName(ORGANIZATION).build()); - } - - @AfterClass - public static void tearDown() { - adminWsClient.organizations().delete(ORGANIZATION); - } - - @Test - public void built_in_profiles_provided_copied_to_new_organization() { - SearchWsResponse result = adminWsClient.qualityProfiles().search(new SearchWsRequest().setOrganizationKey(ORGANIZATION)); - - assertThat(result.getProfilesList()) - .extracting(QualityProfile::getName, QualityProfile::getLanguage, QualityProfile::getIsBuiltIn, QualityProfile::getIsDefault) - .containsExactlyInAnyOrder( - tuple("Basic", "xoo", true, true), - tuple("empty", "xoo", true, false), - tuple("Basic", "xoo2", true, true)); - } - - @Test - public void built_in_profiles_provided_for_default_organization() { - SearchWsResponse result = adminWsClient.qualityProfiles().search(new SearchWsRequest().setOrganizationKey("default-organization")); - - assertThat(result.getProfilesList()) - .extracting(QualityProfile::getOrganization, QualityProfile::getName, QualityProfile::getLanguage, QualityProfile::getIsBuiltIn, QualityProfile::getIsDefault) - .containsExactlyInAnyOrder( - tuple("default-organization", "Basic", "xoo", true, true), - tuple("default-organization", "empty", "xoo", true, false), - tuple("default-organization", "Basic", "xoo2", true, true)); - } - - @Test - public void cannot_delete_built_in_profile_even_when_non_default() { - QualityProfile defaultBuiltInProfile = getProfile(p -> p.getIsBuiltIn() && p.getIsDefault() && "Basic".equals(p.getName()) && "xoo".equals(p.getLanguage())); - - QualityProfiles.CopyWsResponse copiedProfile = adminWsClient.qualityProfiles().copy(new CopyRequest(defaultBuiltInProfile.getKey(), randomAscii(20))); - adminWsClient.qualityProfiles().setDefault(new SetDefaultRequest(copiedProfile.getKey())); - - try { - adminWsClient.qualityProfiles().delete(new DeleteRequest(defaultBuiltInProfile.getKey())); - fail(); - } catch (HttpException e) { - assertThat(e.code()).isEqualTo(400); - assertThat(e.content()).contains("Operation forbidden for built-in Quality Profile 'Basic' with language 'xoo'"); - } finally { - adminWsClient.qualityProfiles().setDefault(new SetDefaultRequest(defaultBuiltInProfile.getKey())); - adminWsClient.qualityProfiles().delete(new DeleteRequest(copiedProfile.getKey())); - } - } - - @Test - public void fail_to_modify_built_in_quality_profile() { - QualityProfile profile = getProfile(p -> p.getIsBuiltIn() && "Basic".equals(p.getName()) && "xoo".equals(p.getLanguage())); - assertThat(profile.getIsBuiltIn()).isTrue(); - - try { - adminWsClient.qualityProfiles().activateRule(ActivateRuleWsRequest.builder() - .setOrganization(ORGANIZATION) - .setProfileKey(profile.getKey()) - .setRuleKey(RULE_ONE_BUG_PER_LINE) - .build()); - fail(); - } catch (HttpException e) { - assertThat(e.code()).isEqualTo(HTTP_BAD_REQUEST); - assertThat(e.content()).contains("Operation forbidden for built-in Quality Profile 'Basic' with language 'xoo'"); - } - } - - private QualityProfile getProfile(Predicate<QualityProfile> filter) { - return adminWsClient.qualityProfiles().search(new SearchWsRequest() - .setOrganizationKey(ORGANIZATION)).getProfilesList() - .stream() - .filter(filter) - .findAny().orElseThrow(IllegalStateException::new); - } -} diff --git a/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesRestoreAndSearchTest.java b/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesRestoreAndSearchTest.java deleted file mode 100644 index 887fd2fd14f..00000000000 --- a/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesRestoreAndSearchTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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 it.qualityProfile; - -import com.sonar.orchestrator.Orchestrator; -import it.Category4Suite; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.sonarqube.ws.QualityProfiles; -import org.sonarqube.ws.client.qualityprofile.SearchWsRequest; -import util.ItUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -public class QualityProfilesRestoreAndSearchTest { - - @ClassRule - public static Orchestrator orchestrator = Category4Suite.ORCHESTRATOR; - - @Before - public void init() { - orchestrator.resetData(); - } - - @Test - public void restore_and_search_in_default_organization() { - ItUtils.restoreProfile(orchestrator, getClass().getResource("/authorisation/one-issue-per-line-profile.xml")); - QualityProfiles.SearchWsResponse results = ItUtils.newAdminWsClient(orchestrator).qualityProfiles().search(new SearchWsRequest()); - assertThat(results.getProfilesList()) - .filteredOn(result -> "xoo".equals(result.getLanguage())) - .filteredOn(result -> "one-issue-per-line".equals(result.getName())) - .filteredOn(result -> "default-organization".equals(result.getOrganization())) - .hasSize(1); - } -} diff --git a/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesPageTest.java b/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesUiTest.java index 6c29b8e9b1e..b0406584fa3 100644 --- a/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesPageTest.java +++ b/it/it-tests/src/test/java/it/qualityProfile/QualityProfilesUiTest.java @@ -38,7 +38,7 @@ import static util.ItUtils.newAdminWsClient; import static util.ItUtils.projectDir; import static util.selenium.Selenese.runSelenese; -public class QualityProfilesPageTest { +public class QualityProfilesUiTest { @ClassRule public static Orchestrator orchestrator = Category4Suite.ORCHESTRATOR; @@ -68,18 +68,18 @@ public class QualityProfilesPageTest { @Test public void testHomePage() throws Exception { runSelenese(orchestrator, - "/qualityProfile/QualityProfilesPageTest/should_display_list.html", - "/qualityProfile/QualityProfilesPageTest/should_open_from_list.html", - "/qualityProfile/QualityProfilesPageTest/should_filter_by_language.html"); + "/qualityProfile/QualityProfilesUiTest/should_display_list.html", + "/qualityProfile/QualityProfilesUiTest/should_open_from_list.html", + "/qualityProfile/QualityProfilesUiTest/should_filter_by_language.html"); } @Test public void testProfilePage() throws Exception { runSelenese(orchestrator, - "/qualityProfile/QualityProfilesPageTest/should_display_profile_rules.html", - "/qualityProfile/QualityProfilesPageTest/should_display_profile_inheritance.html", - "/qualityProfile/QualityProfilesPageTest/should_display_profile_projects.html", - "/qualityProfile/QualityProfilesPageTest/should_display_profile_exporters.html"); + "/qualityProfile/QualityProfilesUiTest/should_display_profile_rules.html", + "/qualityProfile/QualityProfilesUiTest/should_display_profile_inheritance.html", + "/qualityProfile/QualityProfilesUiTest/should_display_profile_projects.html", + "/qualityProfile/QualityProfilesUiTest/should_display_profile_exporters.html"); } @Test @@ -96,45 +96,45 @@ public class QualityProfilesPageTest { @Test public void testProfileChangelog() throws Exception { runSelenese(orchestrator, - "/qualityProfile/QualityProfilesPageTest/should_display_changelog.html"); + "/qualityProfile/QualityProfilesUiTest/should_display_changelog.html"); } @Ignore("find a way to know profile key inside selenium tests") @Test public void testComparison() throws Exception { - runSelenese(orchestrator, "/qualityProfile/QualityProfilesPageTest/should_compare.html"); + runSelenese(orchestrator, "/qualityProfile/QualityProfilesUiTest/should_compare.html"); } @Test public void testCreation() throws Exception { - runSelenese(orchestrator, "/qualityProfile/QualityProfilesPageTest/should_create.html"); + runSelenese(orchestrator, "/qualityProfile/QualityProfilesUiTest/should_create.html"); } @Test public void testDeletion() throws Exception { - runSelenese(orchestrator, "/qualityProfile/QualityProfilesPageTest/should_delete.html"); + runSelenese(orchestrator, "/qualityProfile/QualityProfilesUiTest/should_delete.html"); } @Test public void testCopying() throws Exception { - runSelenese(orchestrator, "/qualityProfile/QualityProfilesPageTest/should_copy.html"); + runSelenese(orchestrator, "/qualityProfile/QualityProfilesUiTest/should_copy.html"); } @Test public void testRenaming() throws Exception { - runSelenese(orchestrator, "/qualityProfile/QualityProfilesPageTest/should_rename.html"); + runSelenese(orchestrator, "/qualityProfile/QualityProfilesUiTest/should_rename.html"); } @Test public void testSettingDefault() throws Exception { - runSelenese(orchestrator, "/qualityProfile/QualityProfilesPageTest/should_set_default.html"); + runSelenese(orchestrator, "/qualityProfile/QualityProfilesUiTest/should_set_default.html"); } @Test public void testRestoration() throws Exception { deleteProfile("xoo", "empty"); - runSelenese(orchestrator, "/qualityProfile/QualityProfilesPageTest/should_restore.html"); + runSelenese(orchestrator, "/qualityProfile/QualityProfilesUiTest/should_restore.html"); } private static void createProfile(String language, String name) { diff --git a/it/it-tests/src/test/java/it/rule/RuleTagsTest.java b/it/it-tests/src/test/java/it/rule/RuleTagsTest.java new file mode 100644 index 00000000000..80ba81eab69 --- /dev/null +++ b/it/it-tests/src/test/java/it/rule/RuleTagsTest.java @@ -0,0 +1,113 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 it.rule; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.http.HttpMethod; +import it.Category6Suite; +import java.util.List; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; +import org.sonarqube.ws.Organizations; +import util.ItUtils; +import util.OrganizationRule; + +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.newWsClient; + +public class RuleTagsTest { + + private static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; + private static OrganizationRule organizations = new OrganizationRule(orchestrator); + + @ClassRule + public static TestRule chain = RuleChain.outerRule(orchestrator) + .around(organizations); + + private static Organizations.Organization organization1; + private static Organizations.Organization organization2; + + @BeforeClass + public static void setUp() { + organization1 = organizations.create(); + organization2 = organizations.create(); + } + + @Test + public void should_not_show_tags_of_other_organization() { + updateTag("foo-tag", organization1); + updateTag("bar-tag", organization2); + assertThat(showRuleTags(organization1)).containsExactly("foo-tag"); + assertThat(showRuleTags(organization2)).containsExactly("bar-tag"); + } + + @Test + public void should_not_list_tags_of_other_organization() { + updateTag("foo-tag", organization1); + updateTag("bar-tag", organization2); + assertThat(listTags(organization1)) + .contains("foo-tag") + .doesNotContain("bar-tag"); + } + + @Test + public void should_not_show_removed_tags() { + updateTag("foo-tag", organization1); + assertThat(showRuleTags(organization1)).contains("foo-tag"); + + updateTag("", organization1); + assertThat(showRuleTags(organization1)).isEmpty(); + } + + @Test + public void should_not_list_removed_tags() { + updateTag("foo-tag", organization1); + assertThat(listTags(organization1)).contains("foo-tag"); + + updateTag("", organization1); + assertThat(listTags(organization1)).doesNotContain("foo-tag"); + } + + private List<String> listTags(Organizations.Organization organization) { + String json = orchestrator.getServer().newHttpCall("/api/rules/tags") + .setParam("organization", organization.getKey()) + .execute() + .getBodyAsString(); + return (List<String>) ItUtils.jsonToMap(json).get("tags"); + } + + private List<String> showRuleTags(Organizations.Organization organization) { + return newWsClient(orchestrator).rules().show(organization.getKey(), "xoo:OneIssuePerFile") + .getRule().getTags().getTagsList(); + } + + private void updateTag(String tag, Organizations.Organization organization) { + orchestrator.getServer().newHttpCall("/api/rules/update") + .setMethod(HttpMethod.POST) + .setAdminCredentials() + .setParam("organization", organization.getKey()) + .setParam("key", "xoo:OneIssuePerFile") + .setParam("tags", tag) + .execute(); + } +} diff --git a/it/it-tests/src/test/java/it/rule/RulesPerOrganizationTest.java b/it/it-tests/src/test/java/it/rule/RulesPerOrganizationTest.java deleted file mode 100644 index 8b642f2dc52..00000000000 --- a/it/it-tests/src/test/java/it/rule/RulesPerOrganizationTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 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 it.rule; - -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.http.HttpMethod; -import it.Category6Suite; -import java.util.List; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.sonarqube.ws.client.WsClient; -import org.sonarqube.ws.client.organization.CreateWsRequest; -import util.ItUtils; - -import static it.Category6Suite.enableOrganizationsSupport; -import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.deleteOrganizations; -import static util.ItUtils.newAdminWsClient; -import static util.ItUtils.newWsClient; - -public class RulesPerOrganizationTest { - - private static WsClient adminWsClient; - private static final String ORGANIZATION_FOO = "foo-org"; - private static final String ORGANIZATION_BAR = "bar-org"; - - @ClassRule - public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - - @BeforeClass - public static void setUp() { - adminWsClient = newAdminWsClient(orchestrator); - enableOrganizationsSupport(); - createOrganization(ORGANIZATION_FOO); - createOrganization(ORGANIZATION_BAR); - } - - @AfterClass - public static void tearDown() throws Exception { - deleteOrganizations(orchestrator); - } - - private static void createOrganization(String organization) { - adminWsClient.organizations().create(new CreateWsRequest.Builder().setKey(organization).setName(organization).build()); - } - - @Test - public void should_not_show_tags_of_other_org() { - updateTag("foo-tag", ORGANIZATION_FOO); - updateTag("bar-tag", ORGANIZATION_BAR); - assertThat(showRuleTags(ORGANIZATION_FOO)).containsExactly("foo-tag"); - assertThat(showRuleTags(ORGANIZATION_BAR)).containsExactly("bar-tag"); - } - - @Test - public void should_not_list_tags_of_other_org() { - updateTag("foo-tag", ORGANIZATION_FOO); - updateTag("bar-tag", ORGANIZATION_BAR); - assertThat(listTags(ORGANIZATION_FOO)) - .contains("foo-tag") - .doesNotContain("bar-tag"); - } - - @Test - public void should_not_show_removed_tags() { - updateTag("foo-tag", ORGANIZATION_FOO); - assertThat(showRuleTags(ORGANIZATION_FOO)).contains("foo-tag"); - - updateTag("", ORGANIZATION_FOO); - assertThat(showRuleTags(ORGANIZATION_FOO)).isEmpty(); - } - - @Test - public void should_not_list_removed_tags() { - updateTag("foo-tag", ORGANIZATION_FOO); - assertThat(listTags(ORGANIZATION_FOO)).contains("foo-tag"); - - updateTag("", ORGANIZATION_FOO); - assertThat(listTags(ORGANIZATION_FOO)).doesNotContain("foo-tag"); - } - - private List<String> listTags(String organization) { - String json = orchestrator.getServer().newHttpCall("/api/rules/tags") - .setParam("organization", organization) - .execute() - .getBodyAsString(); - return (List<String>) ItUtils.jsonToMap(json).get("tags"); - } - - private List<String> showRuleTags(String organization) { - return newWsClient(orchestrator).rules().show(organization, "xoo:OneIssuePerFile") - .getRule().getTags().getTagsList(); - } - - private void updateTag(String tag, String organization) { - orchestrator.getServer().newHttpCall("/api/rules/update") - .setMethod(HttpMethod.POST) - .setAdminCredentials() - .setParam("organization", organization) - .setParam("key", "xoo:OneIssuePerFile") - .setParam("tags", tag) - .execute(); - } -} diff --git a/it/it-tests/src/test/java/it/serverSystem/PingTest.java b/it/it-tests/src/test/java/it/serverSystem/PingTest.java index 602c7e3bf01..3be2e6c7132 100644 --- a/it/it-tests/src/test/java/it/serverSystem/PingTest.java +++ b/it/it-tests/src/test/java/it/serverSystem/PingTest.java @@ -20,11 +20,10 @@ package it.serverSystem; import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.http.HttpResponse; import it.Category4Suite; -import okhttp3.Response; import org.junit.ClassRule; import org.junit.Test; -import util.ItUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -35,9 +34,9 @@ public class PingTest { @Test public void ping_answers_pong() throws Exception { - Response response = ItUtils.call(orchestrator.getServer().getUrl() + "/api/system/ping"); + HttpResponse response = orchestrator.getServer().newHttpCall("/api/system/ping").execute(); - assertThat(response.body().string()).isEqualTo("pong"); - assertThat(response.header("Content-Type")).isEqualTo("text/plain"); + assertThat(response.getBodyAsString()).isEqualTo("pong"); + assertThat(response.getHeader("Content-Type")).isEqualTo("text/plain"); } } diff --git a/it/it-tests/src/test/java/it/uiExtension/OrganizationUiExtensionsTest.java b/it/it-tests/src/test/java/it/uiExtension/OrganizationUiExtensionsTest.java index 41150c6d192..7e1e8610130 100644 --- a/it/it-tests/src/test/java/it/uiExtension/OrganizationUiExtensionsTest.java +++ b/it/it-tests/src/test/java/it/uiExtension/OrganizationUiExtensionsTest.java @@ -22,43 +22,37 @@ package it.uiExtension; import com.codeborne.selenide.Condition; import com.sonar.orchestrator.Orchestrator; import it.Category6Suite; -import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; import org.openqa.selenium.By; -import org.sonarqube.ws.client.WsClient; -import org.sonarqube.ws.client.organization.CreateWsRequest; +import org.sonarqube.ws.Organizations.Organization; import pageobjects.Navigation; +import util.OrganizationRule; import static com.codeborne.selenide.Condition.text; import static com.codeborne.selenide.Selenide.$; import static com.codeborne.selenide.WebDriverRunner.url; -import static it.Category6Suite.enableOrganizationsSupport; import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.newAdminWsClient; -import static util.ItUtils.newOrganizationKey; public class OrganizationUiExtensionsTest { + private static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; + private static OrganizationRule organizations = new OrganizationRule(orchestrator); + @ClassRule - public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; + public static TestRule chain = RuleChain.outerRule(orchestrator) + .around(organizations); @Rule public Navigation nav = Navigation.get(orchestrator); - private static WsClient adminClient; - - @BeforeClass - public static void setUp() throws Exception { - adminClient = newAdminWsClient(orchestrator); - enableOrganizationsSupport(); - } - @Test public void organization_page() { - String orgKey = createOrganization(); - nav.open("/organizations/" + orgKey + "/projects"); + Organization organization = organizations.create(); + nav.open("/organizations/" + organization.getKey() + "/projects"); $("#organization-navigation-more").click(); $(By.linkText("Organization Page")).shouldBe(Condition.visible).click(); @@ -69,8 +63,8 @@ public class OrganizationUiExtensionsTest { @Test public void organization_admin_page() { - String orgKey = createOrganization(); - nav.logIn().asAdmin().open("/organizations/" + orgKey + "/projects"); + Organization organization = organizations.create(); + nav.logIn().asAdmin().open("/organizations/" + organization.getKey() + "/projects"); $("#context-navigation a.navbar-admin-link").click(); $(By.linkText("Organization Admin Page")).shouldBe(Condition.visible).click(); @@ -78,10 +72,4 @@ public class OrganizationUiExtensionsTest { assertThat(url()).contains("uiextensionsplugin/organization_admin_page"); $("body").shouldHave(text("uiextensionsplugin/organization_admin_page")); } - - private static String createOrganization() { - String keyAndName = newOrganizationKey(); - adminClient.organizations().create(new CreateWsRequest.Builder().setKey(keyAndName).setName(keyAndName).build()).getOrganization(); - return keyAndName; - } } diff --git a/it/it-tests/src/test/java/it/user/OrganizationIdentityProviderTest.java b/it/it-tests/src/test/java/it/user/OrganizationIdentityProviderTest.java index d62e6863a8e..95f3ce894b1 100644 --- a/it/it-tests/src/test/java/it/user/OrganizationIdentityProviderTest.java +++ b/it/it-tests/src/test/java/it/user/OrganizationIdentityProviderTest.java @@ -27,40 +27,36 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; import org.sonarqube.ws.client.GetRequest; import org.sonarqube.ws.client.WsClient; +import util.OrganizationRule; import util.user.UserRule; -import static it.Category6Suite.enableOrganizationsSupport; import static util.ItUtils.newAdminWsClient; import static util.ItUtils.resetSettings; import static util.ItUtils.setServerProperty; public class OrganizationIdentityProviderTest { - @ClassRule - public static Orchestrator ORCHESTRATOR = Category6Suite.ORCHESTRATOR; + private static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; + private static OrganizationRule organizations = new OrganizationRule(orchestrator); + private static UserRule users = new UserRule(orchestrator); @ClassRule - public static UserRule userRule = UserRule.from(ORCHESTRATOR); + public static TestRule chain = RuleChain.outerRule(orchestrator) + .around(users) + .around(organizations); private static String USER_LOGIN = "john"; - private static String GROUP = "group"; - private static WsClient adminWsClient; @BeforeClass - public static void enableOrganizations() { - enableOrganizationsSupport(); - adminWsClient = newAdminWsClient(ORCHESTRATOR); - setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.enabled", "true"); - } - - private static void purgeSettings(){ - resetSettings(ORCHESTRATOR, null, "sonar.auth.fake-base-id-provider.enabled", "sonar.auth.fake-base-id-provider.user", - "sonar.auth.fake-base-id-provider.throwUnauthorizedMessage", "sonar.auth.fake-base-id-provider.enabledGroupsSync", "sonar.auth.fake-base-id-provider.groups", - "sonar.auth.fake-base-id-provider.allowsUsersToSignUp"); + public static void before() { + adminWsClient = newAdminWsClient(orchestrator); + setServerProperty(orchestrator, "sonar.auth.fake-base-id-provider.enabled", "true"); } @AfterClass @@ -70,46 +66,52 @@ public class OrganizationIdentityProviderTest { @Before public void setUp() throws Exception { - userRule.deactivateUsers(USER_LOGIN); - userRule.removeGroups(GROUP); + users.deactivateUsers(USER_LOGIN); + users.removeGroups(GROUP); purgeSettings(); } + private static void purgeSettings() { + resetSettings(orchestrator, null, "sonar.auth.fake-base-id-provider.enabled", "sonar.auth.fake-base-id-provider.user", + "sonar.auth.fake-base-id-provider.throwUnauthorizedMessage", "sonar.auth.fake-base-id-provider.enabledGroupsSync", "sonar.auth.fake-base-id-provider.groups", + "sonar.auth.fake-base-id-provider.allowsUsersToSignUp"); + } + @Test public void default_group_is_not_added_for_new_user_when_organizations_are_enabled() throws Exception { enablePlugin(); - userRule.createGroup(GROUP); + users.createGroup(GROUP); enableUserCreationByAuthPlugin(); setGroupsReturnedByAuthPlugin(GROUP); authenticateWithFakeAuthProvider(); // No default group membership - userRule.verifyUserGroupMembership(USER_LOGIN, GROUP); + users.verifyUserGroupMembership(USER_LOGIN, GROUP); } @Test public void default_group_is_not_sync_for_existing_user_when_organizations_are_enabled() throws Exception { enablePlugin(); - userRule.createGroup(GROUP); - userRule.createUser(USER_LOGIN, "password"); + users.createGroup(GROUP); + users.createUser(USER_LOGIN, "password"); enableUserCreationByAuthPlugin(); setGroupsReturnedByAuthPlugin(GROUP); authenticateWithFakeAuthProvider(); // No default group membership - userRule.verifyUserGroupMembership(USER_LOGIN, GROUP); + users.verifyUserGroupMembership(USER_LOGIN, GROUP); } @Test public void remove_default_group_when_organizations_are_enabled() throws Exception { enablePlugin(); - userRule.createGroup(GROUP); - userRule.createUser(USER_LOGIN, "password"); + users.createGroup(GROUP); + users.createUser(USER_LOGIN, "password"); // Add user as member of default organization adminWsClient.organizations().addMember("default-organization", USER_LOGIN); - userRule.verifyUserGroupMembership(USER_LOGIN, "Members"); + users.verifyUserGroupMembership(USER_LOGIN, "Members"); enableUserCreationByAuthPlugin(); // No group is returned by the plugin setGroupsReturnedByAuthPlugin(); @@ -117,21 +119,21 @@ public class OrganizationIdentityProviderTest { authenticateWithFakeAuthProvider(); // No default group membership - userRule.verifyUserGroupMembership(USER_LOGIN); + users.verifyUserGroupMembership(USER_LOGIN); } private static void enablePlugin() { - setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.enabled", "true"); + setServerProperty(orchestrator, "sonar.auth.fake-base-id-provider.enabled", "true"); } private static void enableUserCreationByAuthPlugin() { - setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.user", USER_LOGIN + ",fake-john,John,john@email.com"); + setServerProperty(orchestrator, "sonar.auth.fake-base-id-provider.user", USER_LOGIN + ",fake-john,John,john@email.com"); } private static void setGroupsReturnedByAuthPlugin(String... groups) { - setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.enabledGroupsSync", "true"); + setServerProperty(orchestrator, "sonar.auth.fake-base-id-provider.enabledGroupsSync", "true"); if (groups.length > 0) { - setServerProperty(ORCHESTRATOR, "sonar.auth.fake-base-id-provider.groups", Joiner.on(",").join(groups)); + setServerProperty(orchestrator, "sonar.auth.fake-base-id-provider.groups", Joiner.on(",").join(groups)); } } diff --git a/it/it-tests/src/test/java/util/ItUtils.java b/it/it-tests/src/test/java/util/ItUtils.java index 526da26950f..1bbabd35fde 100644 --- a/it/it-tests/src/test/java/util/ItUtils.java +++ b/it/it-tests/src/test/java/util/ItUtils.java @@ -57,7 +57,7 @@ import org.apache.commons.io.FileUtils; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.JSONValue; -import org.sonar.wsclient.base.HttpException; +import org.junit.Assert; import org.sonar.wsclient.issue.Issue; import org.sonar.wsclient.issue.IssueClient; import org.sonar.wsclient.issue.IssueQuery; @@ -70,8 +70,6 @@ import org.sonarqube.ws.client.WsClient; import org.sonarqube.ws.client.WsClientFactories; import org.sonarqube.ws.client.component.ShowWsRequest; import org.sonarqube.ws.client.measure.ComponentWsRequest; -import org.sonarqube.ws.client.organization.OrganizationService; -import org.sonarqube.ws.client.organization.SearchWsRequest; import org.sonarqube.ws.client.qualityprofile.RestoreWsRequest; import org.sonarqube.ws.client.setting.ResetRequest; import org.sonarqube.ws.client.setting.SetRequest; @@ -372,14 +370,6 @@ public class ItUtils { return "key-" + randomAlphabetic(100); } - public static void deleteOrganizations(Orchestrator orchestrator) { - OrganizationService service = newAdminWsClient(orchestrator).organizations(); - service.search(SearchWsRequest.builder().build()).getOrganizationsList() - .stream() - .filter(o -> !o.getGuarded()) - .forEach(organization -> service.delete(organization.getKey())); - } - public static class ComponentNavigation { private String version; private String analysisDate; @@ -416,12 +406,6 @@ public class ItUtils { .toArray(String[]::new); } - public static void verifyHttpException(Exception e, int expectedCode) { - assertThat(e).isInstanceOf(HttpException.class); - HttpException exception = (HttpException) e; - assertThat(exception.status()).isEqualTo(expectedCode); - } - public static Date toDate(String sDate) { try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); @@ -451,7 +435,7 @@ public class ItUtils { return taskIds.iterator().next(); } - public static List<String> extractCeTaskIds(BuildResult buildResult) { + private static List<String> extractCeTaskIds(BuildResult buildResult) { String logs = buildResult.getLogs(); return StreamSupport.stream(LINE_SPLITTER.split(logs).spliterator(), false) .filter(s -> s.contains("More about the report processing at")) @@ -466,6 +450,10 @@ public class ItUtils { return gson.fromJson(json, type); } + /** + * @deprecated replaced by {@code orchestrator.getServer().newHttpCall()} + */ + @Deprecated public static Response call(String url, String... headers) { Request.Builder requestBuilder = new Request.Builder().get().url(url); for (int i = 0; i < headers.length; i += 2) { @@ -486,4 +474,38 @@ public class ItUtils { throw Throwables.propagate(e); } } + + public static void expectBadRequestError(Runnable runnable) { + expectHttpError(runnable, 400); + } + + public static void expectMissingError(Runnable runnable) { + expectHttpError(runnable, 404); + } + /** + * Missing permissions + */ + public static void expectForbiddenError(Runnable runnable) { + expectHttpError(runnable, 403); + } + + /** + * Not authenticated + */ + public static void expectUnauthorizedError(Runnable runnable) { + expectHttpError(runnable, 401); + } + + public static void expectNotFoundError(Runnable runnable) { + expectHttpError(runnable, 404); + } + + private static void expectHttpError(Runnable runnable, int expectedCode) { + try { + runnable.run(); + Assert.fail("Ws call should have failed"); + } catch (org.sonarqube.ws.client.HttpException e) { + assertThat(e.code()).isEqualTo(expectedCode); + } + } } diff --git a/it/it-tests/src/test/java/util/OrganizationRule.java b/it/it-tests/src/test/java/util/OrganizationRule.java new file mode 100644 index 00000000000..8034ffa5295 --- /dev/null +++ b/it/it-tests/src/test/java/util/OrganizationRule.java @@ -0,0 +1,177 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 util; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.http.HttpMethod; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; +import javax.annotation.Nullable; +import org.junit.rules.ExternalResource; +import org.sonarqube.ws.Organizations; +import org.sonarqube.ws.Organizations.Organization; +import org.sonarqube.ws.WsUsers; +import org.sonarqube.ws.client.HttpException; +import org.sonarqube.ws.client.WsClient; +import org.sonarqube.ws.client.organization.CreateWsRequest; +import org.sonarqube.ws.client.organization.OrganizationService; +import org.sonarqube.ws.client.organization.SearchMembersWsRequest; +import org.sonarqube.ws.client.organization.SearchWsRequest; +import org.sonarqube.ws.client.user.GroupsRequest; + +import static java.util.Arrays.stream; +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.newAdminWsClient; + +public class OrganizationRule extends ExternalResource implements OrganizationSupport { + + private final Orchestrator orchestrator; + private OrganizationSupport rootSupport; + + public OrganizationRule(Orchestrator orchestrator) { + this.orchestrator = orchestrator; + } + + @Override + protected void before() { + enableSupport(); + rootSupport = new OrganizationSupportImpl(newAdminWsClient(orchestrator)); + } + + @Override + protected void after() { + deleteOrganizations(); + } + + private void enableSupport() { + orchestrator.getServer() + .newHttpCall("api/organizations/enable_support") + .setMethod(HttpMethod.POST) + .setAdminCredentials() + .execute(); + } + + public void deleteOrganizations() { + rootSupport.getWsService().search(SearchWsRequest.builder().build()).getOrganizationsList() + .stream() + .filter(o -> !o.getKey().equals("default-organization")) + .forEach(organization -> rootSupport.getWsService().delete(organization.getKey())); + } + + public OrganizationSupport as(String login, String password) { + return new OrganizationSupportImpl(ItUtils.newUserWsClient(orchestrator, login, password)); + } + + public OrganizationSupport asAnonymous() { + return as(null, null); + } + + @Override + public OrganizationService getWsService() { + return rootSupport.getWsService(); + } + + @Override + public Organization create(Consumer<CreateWsRequest.Builder>... populators) { + return rootSupport.create(populators); + } + + @Override + public OrganizationSupport delete(Organization organization) { + return rootSupport.delete(organization); + } + + public OrganizationRule assertThatOrganizationDoesNotExist(String organizationKey) { + SearchWsRequest request = new SearchWsRequest.Builder().setOrganizations(organizationKey).build(); + Organizations.SearchWsResponse searchWsResponse = getWsService().search(request); + assertThat(searchWsResponse.getOrganizationsList()).isEmpty(); + return this; + } + + public OrganizationRule assertThatMemberOf(@Nullable Organization organization, WsUsers.CreateWsResponse.User user) { + verifyOrganizationMembership(organization, user, true); + verifyMembersGroupMembership(user, organization, true); + return this; + } + + public OrganizationRule assertThatNotMemberOf(@Nullable Organization organization, WsUsers.CreateWsResponse.User user) { + verifyOrganizationMembership(organization, user, false); + try { + verifyMembersGroupMembership(user, organization, false); + } catch (HttpException e) { + // do not fail if user does not exist + if (e.code() != 404) { + throw e; + } + } + return this; + } + + private void verifyOrganizationMembership(@Nullable Organization organization, WsUsers.CreateWsResponse.User user, boolean isMember) { + List<Organizations.User> users = getWsService().searchMembers(new SearchMembersWsRequest() + .setQuery(user.getLogin()) + .setSelected("selected") + .setOrganization(organization != null ? organization.getKey() : null)) + .getUsersList(); + assertThat(users).hasSize(isMember ? 1 : 0); + } + + private void verifyMembersGroupMembership(WsUsers.CreateWsResponse.User user, @Nullable Organization organization, boolean isMember) { + List<WsUsers.GroupsWsResponse.Group> groups = newAdminWsClient(orchestrator).users().groups(GroupsRequest.builder() + .setLogin(user.getLogin()) + .setOrganization(organization != null ? organization.getKey() : null) + .setQuery("Members") + .setSelected("selected") + .build()) + .getGroupsList(); + assertThat(groups).hasSize(isMember ? 1 : 0); + } + + private static class OrganizationSupportImpl implements OrganizationSupport { + private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); + private final WsClient wsClient; + + private OrganizationSupportImpl(WsClient wsClient) { + this.wsClient = wsClient; + } + + @Override + public OrganizationService getWsService() { + return wsClient.organizations(); + } + + @Override + public Organization create(Consumer<CreateWsRequest.Builder>... populators) { + int id = ID_GENERATOR.getAndIncrement(); + CreateWsRequest.Builder request = new CreateWsRequest.Builder() + .setKey("org" + id) + .setName("Org " + id); + stream(populators).forEach(p -> p.accept(request)); + return getWsService().create(request.build()).getOrganization(); + } + + @Override + public OrganizationSupport delete(Organization organization) { + getWsService().delete(organization.getKey()); + return this; + } + } +} diff --git a/it/it-tests/src/test/java/util/OrganizationSupport.java b/it/it-tests/src/test/java/util/OrganizationSupport.java new file mode 100644 index 00000000000..9b8a6e36edc --- /dev/null +++ b/it/it-tests/src/test/java/util/OrganizationSupport.java @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 util; + +import java.util.function.Consumer; +import org.sonarqube.ws.Organizations.Organization; +import org.sonarqube.ws.client.organization.CreateWsRequest; +import org.sonarqube.ws.client.organization.OrganizationService; + +public interface OrganizationSupport { + + OrganizationService getWsService(); + + /** + * Create organization with randomly generated key and name + */ + Organization create(Consumer<CreateWsRequest.Builder>... populators); + + OrganizationSupport delete(Organization organization); + +} diff --git a/it/it-tests/src/test/java/util/QualityProfileRule.java b/it/it-tests/src/test/java/util/QualityProfileRule.java new file mode 100644 index 00000000000..a8904f35cb3 --- /dev/null +++ b/it/it-tests/src/test/java/util/QualityProfileRule.java @@ -0,0 +1,178 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 util; + +import com.sonar.orchestrator.Orchestrator; +import java.util.List; +import java.util.function.Consumer; +import org.junit.rules.ExternalResource; +import org.sonarqube.ws.Common; +import org.sonarqube.ws.Organizations; +import org.sonarqube.ws.QualityProfiles.CreateWsResponse.QualityProfile; +import org.sonarqube.ws.Rules; +import org.sonarqube.ws.client.HttpException; +import org.sonarqube.ws.client.WsClient; +import org.sonarqube.ws.client.qualityprofile.ActivateRuleWsRequest; +import org.sonarqube.ws.client.qualityprofile.CreateRequest; +import org.sonarqube.ws.client.qualityprofile.DeleteRequest; +import org.sonarqube.ws.client.qualityprofile.QualityProfilesService; +import org.sonarqube.ws.client.rule.SearchWsRequest; + +import static java.util.Arrays.asList; +import static java.util.Arrays.stream; +import static java.util.Collections.singletonList; +import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.newUserWsClient; +import static util.ItUtils.newWsClient; + +public class QualityProfileRule extends ExternalResource implements QualityProfileSupport { + + private final Orchestrator orchestrator; + private QualityProfileSupport support; + + public QualityProfileRule(Orchestrator orchestrator) { + this.orchestrator = orchestrator; + } + + @Override + protected void before() throws Throwable { + support = new QualityProfileSupportImpl(ItUtils.newAdminWsClient(orchestrator)); + } + + public QualityProfileSupport as(String login, String password) { + return new QualityProfileSupportImpl(newUserWsClient(orchestrator, login, password)); + } + + public QualityProfileSupport asAnonymous() { + return new QualityProfileSupportImpl(newWsClient(orchestrator)); + } + + @Override + public QualityProfilesService getWsService() { + return support.getWsService(); + } + + @Override + public QualityProfile createXooProfile(Organizations.Organization organization, Consumer<CreateRequest.Builder>... populators) { + return support.createXooProfile(organization, populators); + } + + @Override + public QualityProfileSupport delete(String profileKey) { + return support.delete(profileKey); + } + + @Override + public QualityProfileSupport activateRule(String profileKey, String ruleKey) { + return support.activateRule(profileKey, ruleKey); + } + + @Override + public QualityProfileSupport deactivateRule(String profileKey, String ruleKey) { + return support.deactivateRule(profileKey, ruleKey); + } + + @Override + public QualityProfileSupport assertThatNumberOfActiveRulesEqualsTo(String profileKey, int expectedActiveRules) { + return support.assertThatNumberOfActiveRulesEqualsTo(profileKey, expectedActiveRules); + } + + private static class QualityProfileSupportImpl implements QualityProfileSupport { + + private final WsClient wsClient; + + private QualityProfileSupportImpl(WsClient wsClient) { + this.wsClient = wsClient; + } + + @Override + public QualityProfilesService getWsService() { + return wsClient.qualityProfiles(); + } + + @Override + public QualityProfile createXooProfile(Organizations.Organization organization, Consumer<CreateRequest.Builder>... populators) { + CreateRequest.Builder request = CreateRequest.builder() + .setOrganizationKey(organization.getKey()) + .setLanguage("xoo") + .setProfileName(randomAlphanumeric(10)); + stream(populators).forEach(p -> p.accept(request)); + return getWsService().create(request.build()).getProfile(); + } + + @Override + public QualityProfileSupport delete(String profileKey) { + getWsService().delete(new DeleteRequest(profileKey)); + return this; + } + + @Override + public QualityProfileSupport activateRule(String profileKey, String ruleKey) { + ActivateRuleWsRequest request = ActivateRuleWsRequest.builder() + .setProfileKey(profileKey) + .setRuleKey(ruleKey) + .build(); + getWsService().activateRule(request); + return this; + } + + @Override + public QualityProfileSupport deactivateRule(String profileKey, String ruleKey) { + getWsService().deactivateRule(profileKey, ruleKey); + return this; + } + + @Override + public QualityProfileSupport assertThatNumberOfActiveRulesEqualsTo(String profileKey, int expectedActiveRules) { + try { + List<String> facetIds = asList("active_severities", "repositories", "languages", "severities", "statuses", "types"); + SearchWsRequest request = new SearchWsRequest() + .setQProfile(profileKey) + .setActivation(true) + .setFacets(facetIds) + .setFields(singletonList("actives")); + Rules.SearchResponse response = wsClient.rules().search(request); + + // assume that expectedActiveRules fits in first page of results + assertThat(response.getRulesCount()).isEqualTo(expectedActiveRules); + assertThat(response.getTotal()).isEqualTo(expectedActiveRules); + assertThat(response.getActives().getActives()).as(response.toString()).hasSize(expectedActiveRules); + + // verify facets + assertThat(response.getFacets().getFacetsCount()).isEqualTo(facetIds.size()); + response.getFacets().getFacetsList().forEach(facet -> { + long total = facet.getValuesList().stream() + .mapToLong(Common.FacetValue::getCount) + .sum(); + assertThat(total).as("Facet " + facet.getProperty()).isEqualTo((long) expectedActiveRules); + }); + } catch (HttpException e) { + if (expectedActiveRules == 0 && e.code() == 404) { + // profile does not exist, do nothing + return this; + } + throw e; + } + return this; + } + + } +} diff --git a/it/it-tests/src/test/java/util/QualityProfileSupport.java b/it/it-tests/src/test/java/util/QualityProfileSupport.java new file mode 100644 index 00000000000..647d31409d1 --- /dev/null +++ b/it/it-tests/src/test/java/util/QualityProfileSupport.java @@ -0,0 +1,74 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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 util; + +import java.util.function.Consumer; +import org.sonarqube.ws.Organizations; +import org.sonarqube.ws.QualityProfiles; +import org.sonarqube.ws.QualityProfiles.CreateWsResponse.QualityProfile; +import org.sonarqube.ws.client.qualityprofile.CreateRequest; +import org.sonarqube.ws.client.qualityprofile.QualityProfilesService; + +public interface QualityProfileSupport { + + QualityProfilesService getWsService(); + + QualityProfile createXooProfile(Organizations.Organization organization, Consumer<CreateRequest.Builder>... populators); + + QualityProfileSupport delete(String profileKey); + + default QualityProfileSupport delete(QualityProfile profile) { + return delete(profile.getKey()); + } + + default QualityProfileSupport delete(QualityProfiles.SearchWsResponse.QualityProfile profile) { + return delete(profile.getKey()); + } + + QualityProfileSupport activateRule(String profileKey, String ruleKey); + + default QualityProfileSupport activateRule(QualityProfile profile, String ruleKey) { + return activateRule(profile.getKey(), ruleKey); + } + + default QualityProfileSupport activateRule(QualityProfiles.SearchWsResponse.QualityProfile profile, String ruleKey) { + return activateRule(profile.getKey(), ruleKey); + } + + QualityProfileSupport deactivateRule(String profileKey, String ruleKey); + + default QualityProfileSupport deactivateRule(QualityProfile profile, String ruleKey) { + return deactivateRule(profile.getKey(), ruleKey); + } + + default QualityProfileSupport deactivateRule(QualityProfiles.SearchWsResponse.QualityProfile profile, String ruleKey) { + return deactivateRule(profile.getKey(), ruleKey); + } + + QualityProfileSupport assertThatNumberOfActiveRulesEqualsTo(String profileKey, int expectedActiveRules); + + default QualityProfileSupport assertThatNumberOfActiveRulesEqualsTo(QualityProfile profile, int expectedActiveRules) { + return assertThatNumberOfActiveRulesEqualsTo(profile.getKey(), expectedActiveRules); + } + + default QualityProfileSupport assertThatNumberOfActiveRulesEqualsTo(QualityProfiles.SearchWsResponse.QualityProfile profile, int expectedActiveRules) { + return assertThatNumberOfActiveRulesEqualsTo(profile.getKey(), expectedActiveRules); + } +} diff --git a/it/it-tests/src/test/java/util/user/UserRule.java b/it/it-tests/src/test/java/util/user/UserRule.java index 06f6c874d65..370bb7892da 100644 --- a/it/it-tests/src/test/java/util/user/UserRule.java +++ b/it/it-tests/src/test/java/util/user/UserRule.java @@ -24,17 +24,25 @@ import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; import com.sonar.orchestrator.Orchestrator; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.junit.rules.ExternalResource; +import org.sonarqube.ws.Organizations; +import org.sonarqube.ws.WsUsers; import org.sonarqube.ws.client.GetRequest; import org.sonarqube.ws.client.PostRequest; import org.sonarqube.ws.client.WsClient; import org.sonarqube.ws.client.WsResponse; +import org.sonarqube.ws.client.user.CreateRequest; +import org.sonarqube.ws.client.user.SearchRequest; +import org.sonarqube.ws.client.user.UsersService; +import util.selenium.Consumer; import static java.util.Arrays.asList; +import static java.util.Arrays.stream; import static java.util.Objects.requireNonNull; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.guava.api.Assertions.assertThat; @@ -43,12 +51,13 @@ import static util.ItUtils.newAdminWsClient; public class UserRule extends ExternalResource implements GroupManagement { public static final String ADMIN_LOGIN = "admin"; + private static final AtomicInteger ID_GENERATOR = new AtomicInteger(); private final Orchestrator orchestrator; private WsClient adminWsClient; private final GroupManagement defaultOrganizationGroupManagement; - private UserRule(Orchestrator orchestrator) { + public UserRule(Orchestrator orchestrator) { this.orchestrator = orchestrator; this.defaultOrganizationGroupManagement = new GroupManagementImpl(null); } @@ -57,6 +66,12 @@ public class UserRule extends ExternalResource implements GroupManagement { return new UserRule(requireNonNull(orchestrator, "Orchestrator instance cannot be null")); } + @Override + protected void after() { + deactivateAllUsers(); + // TODO delete groups + } + // ***************** // Users // ***************** @@ -88,20 +103,40 @@ public class UserRule extends ExternalResource implements GroupManagement { assertThat(getUserByLogin(login)).as("Unexpected user with login '%s' has been found", login).isAbsent(); } - public void createUser(String login, String name, @Nullable String email, String password) { - adminWsClient().wsConnector().call( - new PostRequest("api/users/create") - .setParam("login", login) - .setParam("name", name) - .setParam("email", email) - .setParam("password", password)) - .failIfNotSuccessful(); + public WsUsers.CreateWsResponse.User createUser(String login, String name, @Nullable String email, String password) { + CreateRequest.Builder request = CreateRequest.builder() + .setLogin(login) + .setName(name) + .setEmail(email) + .setPassword(password); + return adminWsClient().users().create(request.build()).getUser(); + } + + /** + * Create user with randomly generated values + */ + public WsUsers.CreateWsResponse.User createUser(Consumer<CreateRequest.Builder>... populators) { + int id = ID_GENERATOR.getAndIncrement(); + CreateRequest.Builder request = CreateRequest.builder() + .setLogin("login" + id) + .setName("name" + id) + .setEmail(id + "@test.com") + .setPassword("password" + id); + stream(populators).forEach(p -> p.accept(request)); + return adminWsClient().users().create(request.build()).getUser(); } public void createUser(String login, String password) { createUser(login, login, null, password); } + public WsUsers.CreateWsResponse.User createAdministrator(Organizations.Organization organization, String password) { + WsUsers.CreateWsResponse.User user = createUser(p -> p.setPassword(password)); + adminWsClient.organizations().addMember(organization.getKey(), user.getLogin()); + forOrganization(organization.getKey()).associateGroupsToUser(user.getLogin(), "Owners"); + return user; + } + public void setRoot(String login) { adminWsClient().rootService().setRoot(login); } @@ -133,6 +168,16 @@ public class UserRule extends ExternalResource implements GroupManagement { deactivateUsers(asList(userLogins)); } + public void deactivateAllUsers() { + UsersService service = newAdminWsClient(orchestrator).users(); + List<String> logins = service.search(SearchRequest.builder().build()).getUsersList() + .stream() + .filter(u -> !u.getLogin().equals("admin")) + .map(u -> u.getLogin()) + .collect(Collectors.toList()); + deactivateUsers(logins); + } + // ***************** // User groups // ***************** @@ -164,15 +209,11 @@ public class UserRule extends ExternalResource implements GroupManagement { } private void addOrganizationParam(PostRequest request) { - if (organizationKey != null) { - request.setParam("organization", organizationKey); - } + request.setParam("organization", organizationKey); } private void addOrganizationParam(GetRequest request) { - if (organizationKey != null) { - request.setParam("organization", organizationKey); - } + request.setParam("organization", organizationKey); } @Override diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_compare.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_compare.html index b8ea98d1690..b8ea98d1690 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_compare.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_compare.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_copy.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_copy.html index e233ad8f005..e233ad8f005 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_copy.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_copy.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_create.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_create.html index 253880e05b4..253880e05b4 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_create.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_create.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_delete.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_delete.html index bdaab3efc06..bdaab3efc06 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_delete.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_delete.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_display_changelog.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_display_changelog.html index 12536be7cbf..12536be7cbf 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_display_changelog.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_display_changelog.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_display_list.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_display_list.html index 4d9242c77de..4d9242c77de 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_display_list.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_display_list.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_display_profile_exporters.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_display_profile_exporters.html index b26d162f2e7..b26d162f2e7 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_display_profile_exporters.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_display_profile_exporters.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_display_profile_inheritance.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_display_profile_inheritance.html index c403fbf5196..c403fbf5196 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_display_profile_inheritance.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_display_profile_inheritance.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_display_profile_projects.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_display_profile_projects.html index 062014eb239..062014eb239 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_display_profile_projects.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_display_profile_projects.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_display_profile_rules.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_display_profile_rules.html index 6b497fc7b58..6b497fc7b58 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_display_profile_rules.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_display_profile_rules.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_filter_by_language.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_filter_by_language.html index a913a70a34f..a913a70a34f 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_filter_by_language.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_filter_by_language.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_open_from_list.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_open_from_list.html index 2e753ba1cd7..2e753ba1cd7 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_open_from_list.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_open_from_list.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_rename.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_rename.html index c0c437e809f..c0c437e809f 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_rename.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_rename.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_restore.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_restore.html index 1debd02fcbb..1debd02fcbb 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_restore.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_restore.html diff --git a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_set_default.html b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_set_default.html index bb996462b3e..bb996462b3e 100644 --- a/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesPageTest/should_set_default.html +++ b/it/it-tests/src/test/resources/organization/OrganizationQualityProfilesUiTest/should_set_default.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_compare.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_compare.html index c2339d690f6..c2339d690f6 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_compare.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_compare.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_copy.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_copy.html index d8ff976d04d..d8ff976d04d 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_copy.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_copy.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_create.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_create.html index f2c5fae2aa8..f2c5fae2aa8 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_create.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_create.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_delete.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_delete.html index 69e80a57c98..69e80a57c98 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_delete.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_delete.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_changelog.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_display_changelog.html index 8614c2fdab9..8614c2fdab9 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_changelog.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_display_changelog.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_list.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_display_list.html index 66f83c9af47..66f83c9af47 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_list.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_display_list.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_exporters.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_display_profile_exporters.html index ea8b1d321f1..ea8b1d321f1 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_exporters.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_display_profile_exporters.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_inheritance.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_display_profile_inheritance.html index 501ae5b5df8..501ae5b5df8 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_inheritance.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_display_profile_inheritance.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_projects.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_display_profile_projects.html index ff38495e318..ff38495e318 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_projects.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_display_profile_projects.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_rules.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_display_profile_rules.html index eb5ccf3194b..eb5ccf3194b 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_display_profile_rules.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_display_profile_rules.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_filter_by_language.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_filter_by_language.html index cfe5321b816..cfe5321b816 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_filter_by_language.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_filter_by_language.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_open_from_list.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_open_from_list.html index de19c00a017..de19c00a017 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_open_from_list.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_open_from_list.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_rename.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_rename.html index 7f533d09f36..7f533d09f36 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_rename.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_rename.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_restore.html index 287d6f86067..287d6f86067 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_restore.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_restore.html diff --git a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_set_default.html b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_set_default.html index 3f1d0db80a4..3f1d0db80a4 100644 --- a/it/it-tests/src/test/resources/qualityProfile/QualityProfilesPageTest/should_set_default.html +++ b/it/it-tests/src/test/resources/qualityProfile/QualityProfilesUiTest/should_set_default.html diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/DbVersion65.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/DbVersion65.java index 1ebc80ab604..0f13d2d420a 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/DbVersion65.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/DbVersion65.java @@ -48,9 +48,9 @@ public class DbVersion65 implements DbVersion { .add(1719, "Create table default_qprofiles", CreateTableDefaultQProfiles.class) .add(1720, "Populate table default_qprofiles", PopulateTableDefaultQProfiles.class) .add(1721, "Drop rules_profiles.is_default", DropIsDefaultColumnFromRulesProfiles.class) - .add(1722, "Create table qprofiles", CreateTableQProfiles.class) - .add(1723, "Populate table qprofiles", PopulateQProfiles.class) - .add(1724, "Drop columns organization_uuid and parent_kee from rules_profiles", DropOrgUuidAndParentKeeFromRulesProfiles.class) + .add(1722, "Create table qprofiles", CreateTableOrgQProfiles.class) + .add(1723, "Populate table qprofiles", PopulateOrgQProfiles.class) + .add(1724, "Drop columns organization_uuid and parent_kee from rules_profiles", DropOrgColumnsFromRulesProfiles.class) .add(1725, "Mark rules_profiles.is_built_in to true for default organization", SetRulesProfilesIsBuiltInToTrueForDefaultOrganization.class) .add(1726, "Update OrgQProfiles to point to built-in profiles", UpdateOrgQProfilesToPointToBuiltInProfiles.class) .add(1727, "Delete orphans rules_profiles table and associated tables", DeleteOrphansFromRulesProfiles.class); diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java index c525b821737..ee553bdbd57 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/RuleActivator.java @@ -20,7 +20,6 @@ package org.sonar.server.qualityprofile; import com.google.common.base.Splitter; -import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -83,7 +82,7 @@ public class RuleActivator { private List<ActiveRuleChange> doActivate(DbSession dbSession, RuleActivation activation, RuleActivatorContext context) { context.verifyForActivation(); - List<ActiveRuleChange> changes = Lists.newArrayList(); + List<ActiveRuleChange> changes = new ArrayList<>(); ActiveRuleChange change; boolean stopPropagation = false; @@ -433,6 +432,11 @@ public class RuleActivator { } public List<ActiveRuleChange> setParent(DbSession dbSession, QProfileDto profile, @Nullable QProfileDto parent) { + checkRequest( + parent == null || profile.getLanguage().equals(parent.getLanguage()), + "Cannot set the profile '%s' as the parent of profile '%s' since their languages differ ('%s' != '%s')", + parent != null ? parent.getKee() : "", profile.getKee(), parent != null ? parent.getLanguage() : "", profile.getLanguage()); + List<ActiveRuleChange> changes = new ArrayList<>(); if (parent == null) { // unset if parent is defined, else nothing to do diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java index be62199bdb6..fbab477c55e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorMediumTest.java @@ -25,24 +25,6 @@ public class RuleActivatorMediumTest { // static final RuleKey TEMPLATE_RULE_KEY = RuleKey.of("xoo", "template1"); // static final RuleKey CUSTOM_RULE_KEY = RuleKey.of("xoo", "custom1"); // -// @ClassRule -// public static ServerTester tester = new ServerTester().withEsIndexes(); -// -// @Rule -// public UserSessionRule userSessionRule = UserSessionRule.forServerTester(tester); -// -// DbClient db; -// DbSession dbSession; -// -// RuleActivator ruleActivator; -// -// RuleIndexer ruleIndexer; -// -// ActiveRuleIndexer activeRuleIndexer; -// -// QProfileDto profileDto; -// private OrganizationDto organization; -// // @Before // public void before() { // tester.clearDbAndIndexes(); @@ -96,260 +78,15 @@ public class RuleActivatorMediumTest { // dbSession.close(); // } // -// @Test -// public void activate() { -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// activation.setParameter("min", "3"); -// List<ActiveRuleChange> changes = ruleActivator.activate(dbSession, activation, XOO_P1_KEY); -// dbSession.commit(); -// dbSession.clearCache(); -// -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), BLOCKER, null, -// ImmutableMap.of("max", "7", "min", "3")); -// assertThat(changes).hasSize(1); -// assertThat(changes.get(0).getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED); -// } -// -// @Test -// public void automatic_activation_does_not_update_intended_column() { -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// activation.setParameter("min", "3"); -// List<ActiveRuleChange> changes = ruleActivator.activate(dbSession, activation, XOO_P1_KEY); -// dbSession.commit(); -// dbSession.clearCache(); -// userSessionRule.anonymous(); -// -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), BLOCKER, null, -// ImmutableMap.of("max", "7", "min", "3")); -// assertThat(changes).hasSize(1); -// assertThat(changes.get(0).getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED); -// assertProfileHasBeenUpdatedAutomatically(XOO_P1_KEY); -// } -// -// @Test -// public void activate_with_profile_dto() { -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// activation.setParameter("min", "3"); -// userSessionRule.logIn().setRoot(); -// List<ActiveRuleChange> changes = ruleActivator.activate(dbSession, activation, profileDto); -// dbSession.commit(); -// dbSession.clearCache(); -// -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), BLOCKER, null, -// ImmutableMap.of("max", "7", "min", "3")); -// assertThat(changes).hasSize(1); -// assertThat(changes.get(0).getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED); -// assertProfileHasBeenUpdatedManually(profileDto.getKee()); -// } -// -// @Test -// public void activate_with_default_severity_and_parameter() { -// activate(new RuleActivation(XOO_X1), XOO_P1_KEY); -// -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), MINOR, null, -// ImmutableMap.of("max", "10")); -// } -// -// /** -// * SONAR-5841 -// */ -// @Test -// public void activate_with_empty_parameter_having_no_default_value() { -// activate(new RuleActivation(XOO_X1) -// .setParameter("min", ""), -// XOO_P1_KEY); -// -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), MINOR, null, -// // Max should be set to default value, min has no value it should be ignored -// ImmutableMap.of("max", "10")); -// } -// -// /** -// * SONAR-5841 -// */ -// @Test -// public void activate_with_empty_parameters() { -// activate(new RuleActivation(XOO_X1) -// .setParameters(ImmutableMap.of("max", "", "min", "")), -// XOO_P1_KEY); -// -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// // Max should be set to default value, min has not value it should be ignored -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), MINOR, null, -// ImmutableMap.of("max", "10")); -// } -// -// /** -// * SONAR-5840 -// */ -// @Test -// public void activate_rule_with_negative_integer_value_on_parameter_having_no_default_value() { -// activate(new RuleActivation(XOO_X1) -// .setParameter("min", "-10"), -// XOO_P1_KEY); -// -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// // Max should be set to default value, min should be set to -10 -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), MINOR, null, -// ImmutableMap.of("max", "10", "min", "-10")); -// } -// -// @Test -// public void activation_ignores_unsupported_parameters() { -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setParameter("xxx", "yyy"); -// activate(activation, XOO_P1_KEY); -// -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), MINOR, null, ImmutableMap.of("max", "10")); -// } -// -// @Test -// public void update_activation_severity_and_parameters() { -// // initial activation -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activate(activation, XOO_P1_KEY); -// -// // update -// RuleActivation update = new RuleActivation(XOO_X1); -// update.setSeverity(CRITICAL); -// update.setParameter("max", "42"); -// List<ActiveRuleChange> changes = activate(update, XOO_P1_KEY); -// -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), CRITICAL, null, ImmutableMap.of("max", "42")); -// assertThat(changes).hasSize(1); -// assertThat(changes.get(0).getType()).isEqualTo(ActiveRuleChange.Type.UPDATED); -// } -// -// @Test -// public void update_activation_with_parameter_without_default_value() { -// // initial activation -> param "max" has a default value -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activate(activation, XOO_P1_KEY); -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), BLOCKER, null, -// ImmutableMap.of("max", "10")); -// -// // update param "min", which has no default value -// RuleActivation update = new RuleActivation(XOO_X1); -// update.setParameter("min", "3"); -// List<ActiveRuleChange> changes = activate(update, XOO_P1_KEY); -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), BLOCKER, null, -// ImmutableMap.of("min", "3", "max", "10")); -// assertThat(changes).hasSize(1); -// assertThat(changes.get(0).getType()).isEqualTo(ActiveRuleChange.Type.UPDATED); -// } -// -// @Test -// public void update_activation_remove_parameter_value_having_default_value() { -// // initial activation -// activate(new RuleActivation(XOO_X1).setSeverity(BLOCKER).setParameter("max", "20"), XOO_P1_KEY); -// -// // update -// activate(new RuleActivation(XOO_X1).setParameter("max", null), XOO_P1_KEY); -// -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), BLOCKER, null, ImmutableMap.of("max", "10")); -// } -// -// @Test -// public void update_activation_remove_parameter_value_without_default_value() { -// // initial activation -> param "min" has a no default value -// activate(new RuleActivation(XOO_X1).setSeverity(BLOCKER).setParameter("min", "5"), XOO_P1_KEY); -// -// // update param "min" with empty value -// activate(new RuleActivation(XOO_X1).setParameter("min", null), XOO_P1_KEY); -// -// verifyHasActiveRuleInDb(ActiveRuleKey.of(XOO_P1_KEY, XOO_X1), BLOCKER, null, ImmutableMap.of("max", "10")); -// } -// -// @Test -// public void update_activation_but_new_parameter() { -// // initial activation -// ActiveRuleKey activeRuleKey = ActiveRuleKey.of(XOO_P1_KEY, XOO_X1); -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activate(activation, XOO_P1_KEY); -// -// assertThat(db.activeRuleDao().selectParamByKeyAndName(activeRuleKey, "max", dbSession)).isNotNull(); -// // FIXME db.activeRuleDao().deleteParamByKeyAndName(dbSession, activeRuleKey, "max"); -// dbSession.commit(); -// assertThat(db.activeRuleDao().selectParamByKeyAndName(activeRuleKey, "max", dbSession)).isNull(); -// dbSession.clearCache(); -// -// // update -// RuleActivation update = new RuleActivation(XOO_X1); -// update.setSeverity(CRITICAL); -// update.setParameter("max", "42"); -// // contrary to activerule, the param 'max' is supposed to be inserted but not updated -// activate(update, XOO_P1_KEY); // -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// verifyHasActiveRuleInDb(activeRuleKey, CRITICAL, null, ImmutableMap.of("max", "42")); -// } -// -// @Test -// public void ignore_activation_without_changes() { -// // initial activation -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activate(activation, XOO_P1_KEY); // -// // update with exactly the same severity and params -// RuleActivation update = new RuleActivation(XOO_X1); -// update.setSeverity(BLOCKER); -// List<ActiveRuleChange> changes = activate(update, XOO_P1_KEY); -// assertThat(changes).isEmpty(); -// } // -// @Test -// public void do_not_change_severity_and_params_if_unset_and_already_activated() { -// // initial activation -// ActiveRuleKey activeRuleKey = ActiveRuleKey.of(XOO_P1_KEY, XOO_X1); -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// activate(activation, XOO_P1_KEY); // -// // update without any severity or params => keep -// RuleActivation update = new RuleActivation(XOO_X1); -// activate(update, XOO_P1_KEY); // -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// verifyHasActiveRuleInDb(activeRuleKey, BLOCKER, null, ImmutableMap.of("max", "7")); -// } // -// @Test -// public void revert_activation_to_default_severity_and_parameters() { -// // initial activation -// ActiveRuleKey activeRuleKey = ActiveRuleKey.of(XOO_P1_KEY, XOO_X1); -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// activation.setParameter("min", "3"); -// activate(activation, XOO_P1_KEY); // -// // update without any severity or params = reset -// RuleActivation update = new RuleActivation(XOO_X1).setReset(true); -// activate(update, XOO_P1_KEY); -// assertThat(countActiveRules(XOO_P1_KEY)).isEqualTo(1); -// verifyHasActiveRuleInDb(activeRuleKey, MINOR, null, -// // only default values -// ImmutableMap.of("max", "10")); -// } + + // // @Test // public void ignore_parameters_when_activating_custom_rule() { @@ -367,126 +104,6 @@ public class RuleActivatorMediumTest { // verifyHasActiveRuleInDb(activeRuleKey, MINOR, null, ImmutableMap.of("format", "txt")); // } // -// @Test -// public void fail_to_activate_if_template() { -// RuleActivation activation = new RuleActivation(TEMPLATE_RULE_KEY); -// -// try { -// activate(activation, XOO_P1_KEY); -// fail(); -// } catch (BadRequestException e) { -// assertThat(e).hasMessage("Rule template can't be activated on a Quality profile: xoo:template1"); -// verifyZeroActiveRules(XOO_P1_KEY); -// } -// } -// -// @Test -// public void fail_to_activate_if_different_languages() { -// // profile and rule have different languages -// RuleActivation activation = new RuleActivation(RuleKey.of("squid", "j1")); -// -// try { -// activate(activation, XOO_P1_KEY); -// fail(); -// } catch (BadRequestException e) { -// assertThat(e).hasMessage("Rule squid:j1 and profile XOO_P1 have different languages"); -// verifyZeroActiveRules(XOO_P1_KEY); -// } -// } -// -// @Test -// public void fail_to_activate_if_unknown_rule() { -// // profile and rule have different languages -// RuleActivation activation = new RuleActivation(RuleKey.of("xoo", "x3")); -// -// try { -// activate(activation, XOO_P1_KEY); -// fail(); -// } catch (BadRequestException e) { -// assertThat(e).hasMessage("Rule not found: xoo:x3"); -// verifyZeroActiveRules(XOO_P1_KEY); -// } -// } -// -// @Test -// public void fail_to_activate_if_rule_with_removed_status() { -// RuleDefinitionDto ruleDto = db.ruleDao().selectOrFailDefinitionByKey(dbSession, XOO_X1); -// ruleDto.setStatus(RuleStatus.REMOVED); -// db.ruleDao().update(dbSession, ruleDto); -// dbSession.commit(); -// dbSession.clearCache(); -// -// RuleActivation activation = new RuleActivation(XOO_X1); -// -// try { -// activate(activation, XOO_P1_KEY); -// fail(); -// } catch (BadRequestException e) { -// assertThat(e).hasMessage("Rule was removed: xoo:x1"); -// verifyZeroActiveRules(XOO_P1_KEY); -// } -// } -// -// @Test -// public void fail_to_activate_if_unknown_profile() { -// try { -// activate(new RuleActivation(XOO_X1), "unknown"); -// fail(); -// } catch (BadRequestException e) { -// assertThat(e).hasMessage("Quality profile not found: unknown"); -// } -// } -// -// @Test -// public void fail_to_activate_if_invalid_parameter() { -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setParameter("max", "foo"); -// -// try { -// activate(activation, XOO_P1_KEY); -// fail(); -// } catch (BadRequestException e) { -// assertThat(e.getMessage()).isEqualTo("Value 'foo' must be an integer."); -// verifyZeroActiveRules(XOO_P1_KEY); -// } -// } -// -// @Test -// public void deactivate() { -// // activation -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// userSessionRule.logIn(); -// activate(activation, XOO_P1_KEY); -// -// // deactivation -// ruleActivator.deactivateAndUpdateIndex(dbSession, ActiveRuleKey.of(XOO_P1_KEY, XOO_X1)); -// -// verifyZeroActiveRules(XOO_P1_KEY); -// assertProfileHasBeenUpdatedManually(XOO_P1_KEY); -// } -// -// @Test -// public void ignore_deactivation_if_rule_not_activated() { -// // deactivation -// ActiveRuleKey key = ActiveRuleKey.of(XOO_P1_KEY, XOO_X1); -// ruleActivator.deactivateAndUpdateIndex(dbSession, key); -// -// verifyZeroActiveRules(XOO_P1_KEY); -// } -// -// @Test -// public void deactivation_fails_if_rule_not_found() { -// ActiveRuleKey key = ActiveRuleKey.of(XOO_P1_KEY, RuleKey.of("xoo", "x3")); -// try { -// ruleActivator.deactivateAndUpdateIndex(dbSession, key); -// fail(); -// } catch (BadRequestException e) { -// assertThat(e).hasMessage("Rule not found: xoo:x3"); -// verifyZeroActiveRules(XOO_P1_KEY); -// } -// } // // @Test // public void deactivation_fails_if_profile_not_found() { @@ -499,351 +116,6 @@ public class RuleActivatorMediumTest { // } // } // -// @Test -// public void allow_to_deactivate_removed_rule() { -// // activation -// RuleActivation activation = new RuleActivation(XOO_X1); -// activate(activation, XOO_P1_KEY); -// -// // set rule as removed -// RuleDefinitionDto rule = db.ruleDao().selectOrFailDefinitionByKey(dbSession, XOO_X1); -// rule.setStatus(RuleStatus.REMOVED); -// db.ruleDao().update(dbSession, rule); -// dbSession.commit(); -// dbSession.clearCache(); -// -// // deactivation -// ruleActivator.deactivateAndUpdateIndex(dbSession, ActiveRuleKey.of(XOO_P1_KEY, XOO_X1)); -// -// verifyZeroActiveRules(XOO_P1_KEY); -// } -// -// // INHERITANCE OF PROFILES -// @Test -// public void activate_on_child_profile_but_not_on_parent() { -// createChildProfiles(); -// -// // activate on child profile, but not on root -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// activate(activation, XOO_P2_KEY); -// -// verifyZeroActiveRules(XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// -// // update severity on child -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity(MINOR); -// activation.setParameter("max", "77"); -// activate(activation, XOO_P2_KEY); -// -// verifyZeroActiveRules(XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, MINOR, null, ImmutableMap.of("max", "77")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, MINOR, INHERITED, ImmutableMap.of("max", "77")); -// } -// -// @Test -// public void propagate_activation_on_child_profiles() { -// createChildProfiles(); -// -// // activate on root profile -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// List<ActiveRuleChange> changes = activate(activation, XOO_P1_KEY); -// -// assertThat(changes).hasSize(3); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// } -// -// @Test -// public void propagate_activation_update_on_child_profiles() { -// createChildProfiles(); -// userSessionRule.logIn(); -// -// // activate on root profile -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// activate(activation, XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// -// // update on parent -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity(INFO); -// activation.setParameter("max", "8"); -// activate(activation, XOO_P1_KEY); -// -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, INFO, null, ImmutableMap.of("max", "8")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, INFO, INHERITED, ImmutableMap.of("max", "8")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, INFO, INHERITED, ImmutableMap.of("max", "8")); -// -// // update on child -> propagate on grand child only -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity(MINOR); -// activation.setParameter("max", "9"); -// activate(activation, XOO_P2_KEY); -// -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, INFO, null, ImmutableMap.of("max", "8")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, MINOR, OVERRIDES, ImmutableMap.of("max", "9")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, MINOR, INHERITED, ImmutableMap.of("max", "9")); -// -// // update on grand child -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "10"); -// activate(activation, XOO_P3_KEY); -// -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, INFO, null, ImmutableMap.of("max", "8")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, MINOR, OVERRIDES, ImmutableMap.of("max", "9")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, OVERRIDES, ImmutableMap.of("max", "10")); -// -// assertProfileHasBeenUpdatedManually(XOO_P1_KEY); -// assertProfileHasBeenUpdatedManually(XOO_P2_KEY); -// assertProfileHasBeenUpdatedManually(XOO_P3_KEY); -// } -// -// @Test -// public void do_not_propagate_activation_update_on_child_overrides() { -// createChildProfiles(); -// -// // activate on root profile P1 -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(INFO); -// activation.setParameter("max", "7"); -// activate(activation, XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, INFO, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, INFO, INHERITED, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, INFO, INHERITED, ImmutableMap.of("max", "7")); -// -// // override on child P2 -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "8"); -// activate(activation, XOO_P2_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, INFO, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, OVERRIDES, ImmutableMap.of("max", "8")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "8")); -// -// // change on parent -> do not propagate on children because they're overriding values -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity(CRITICAL); -// activation.setParameter("max", "9"); -// activate(activation, XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, CRITICAL, null, ImmutableMap.of("max", "9")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, OVERRIDES, ImmutableMap.of("max", "8")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "8")); -// -// // reset on parent (use default severity and params) -> do not propagate on children because they're overriding values -// activation = new RuleActivation(XOO_X1).setReset(true); -// activate(activation, XOO_P1_KEY); -// -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, MINOR, null, ImmutableMap.of("max", "10")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, OVERRIDES, ImmutableMap.of("max", "8")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "8")); -// } -// -// @Test -// public void active_on_parent_a_rule_already_activated_on_child() { -// createChildProfiles(); -// -// // activate on child profile -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(INFO); -// activation.setParameter("max", "7"); -// activate(activation, XOO_P2_KEY); -// verifyZeroActiveRules(XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, INFO, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, INFO, INHERITED, ImmutableMap.of("max", "7")); -// -// // active the same rule on root profile -> mark the child profile as OVERRIDES -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity(MAJOR); -// activation.setParameter("max", "8"); -// activate(activation, XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, MAJOR, null, ImmutableMap.of("max", "8")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, INFO, OVERRIDES, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, INFO, INHERITED, ImmutableMap.of("max", "7")); -// } -// -// @Test -// public void do_not_override_on_child_if_same_values() { -// createChildProfiles(); -// -// // activate on root profile -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(INFO); -// activation.setParameter("max", "7"); -// activate(activation, XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, INFO, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, INFO, INHERITED, ImmutableMap.of("max", "7")); -// -// // override on child P2 with same severity and params -> do nothing (still INHERITED but not OVERRIDDEN) -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity(INFO); -// activation.setParameter("max", "7"); -// activate(activation, XOO_P2_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, INFO, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, INFO, INHERITED, ImmutableMap.of("max", "7")); -// } -// -// @Test -// public void propagate_deactivation_on_child_profiles() { -// createChildProfiles(); -// -// // activate on root profile -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// activate(activation, XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// -// // deactivate on root -// ruleActivator.deactivateAndUpdateIndex(dbSession, ActiveRuleKey.of(XOO_P1_KEY, XOO_X1)); -// -// verifyZeroActiveRules(XOO_P1_KEY); -// verifyZeroActiveRules(XOO_P2_KEY); -// verifyZeroActiveRules(XOO_P3_KEY); -// } -// -// @Test -// public void propagate_deactivation_even_on_child_overrides() { -// createChildProfiles(); -// -// // activate on root profile -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(INFO); -// activation.setParameter("max", "7"); -// activate(activation, XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, INFO, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, INFO, INHERITED, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, INFO, INHERITED, ImmutableMap.of("max", "7")); -// -// // override on child -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "8"); -// activate(activation, XOO_P2_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, INFO, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, OVERRIDES, ImmutableMap.of("max", "8")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "8")); -// -// // deactivate on parent -> do not propagate on children because they're overriding values -// ruleActivator.deactivateAndUpdateIndex(dbSession, ActiveRuleKey.of(XOO_P1_KEY, XOO_X1)); -// dbSession.clearCache(); -// verifyZeroActiveRules(XOO_P1_KEY); -// verifyZeroActiveRules(XOO_P2_KEY); -// verifyZeroActiveRules(XOO_P3_KEY); -// } -// -// @Test -// public void do_not_deactivate_inherited_or_overridden_rule() { -// createChildProfiles(); -// -// // activate on root profile -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// activate(activation, XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// -// // try to deactivate on child -// try { -// ruleActivator.deactivateAndUpdateIndex(dbSession, ActiveRuleKey.of(XOO_P2_KEY, XOO_X1)); -// fail(); -// } catch (BadRequestException e) { -// assertThat(e).hasMessage("Cannot deactivate inherited rule 'xoo:x1'"); -// } -// } -// -// @Test -// public void reset_child_profile() { -// createChildProfiles(); -// -// // activate on root profile -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// activate(activation, XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// -// // override -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity(INFO); -// activation.setParameter("max", "10"); -// activate(activation, XOO_P2_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, INFO, OVERRIDES, ImmutableMap.of("max", "10")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, INFO, INHERITED, ImmutableMap.of("max", "10")); -// -// // reset -> remove overridden values -// activation = new RuleActivation(XOO_X1).setReset(true); -// activate(activation, XOO_P2_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// } -// -// @Test -// public void reset_is_not_propagated_to_child_overrides() { -// createChildProfiles(); -// -// // activate on root profile -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity(BLOCKER); -// activation.setParameter("max", "7"); -// activate(activation, XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// -// // override on child -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity(INFO); -// activation.setParameter("max", "10"); -// activate(activation, XOO_P2_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, INFO, OVERRIDES, ImmutableMap.of("max", "10")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, INFO, INHERITED, ImmutableMap.of("max", "10")); -// -// // override on grand child -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity(MINOR); -// activation.setParameter("max", "20"); -// activate(activation, XOO_P3_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, INFO, OVERRIDES, ImmutableMap.of("max", "10")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, MINOR, OVERRIDES, ImmutableMap.of("max", "20")); -// -// // reset child P2 -> keep the overridden grand-child P3 -// activation = new RuleActivation(XOO_X1).setReset(true); -// activate(activation, XOO_P2_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, INHERITED, ImmutableMap.of("max", "7")); -// verifyOneActiveRuleInDb(XOO_P3_KEY, XOO_X1, MINOR, OVERRIDES, ImmutableMap.of("max", "20")); -// } -// -// @Test -// public void ignore_reset_if_not_activated() { -// createChildProfiles(); -// RuleActivation activation = new RuleActivation(XOO_X1).setReset(true); -// activate(activation, XOO_P1_KEY); -// -// verifyZeroActiveRules(XOO_P1_KEY); -// verifyZeroActiveRules(XOO_P2_KEY); -// } // // @Test // public void bulk_activation() { @@ -892,84 +164,6 @@ public class RuleActivatorMediumTest { // assertThat(result.countFailed()).isGreaterThan(0); // } // -// @Test -// public void set_and_unset_parent_profile() { -// // x1 is activated on the "future parent" P1 -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity("MAJOR"); -// activate(activation, XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, MAJOR, null, ImmutableMap.of("max", "10")); -// -// // create profile P2 with x2 -// db.qualityProfileDao().insert(dbSession, QProfileTesting.newXooP2("org-123")); -// activation = new RuleActivation(XOO_X2); -// activation.setSeverity("MAJOR"); -// activate(activation, XOO_P2_KEY); -// -// // set parent -> child profile inherits rule x1 and still has x2 -// ruleActivator.setParent(dbSession, selectProfile(XOO_P2_KEY), selectProfile(XOO_P1_KEY)); -// dbSession.clearCache(); -// assertThat(db.qualityProfileDao().selectByUuid(dbSession, XOO_P2_KEY).getParentKee()).isEqualTo(XOO_P1_KEY); -// -// verifyHasActiveRuleInDbAndIndex(ActiveRuleKey.of(XOO_P2_KEY, XOO_X1), MAJOR, INHERITED, ImmutableMap.of("max", "10")); -// verifyHasActiveRuleInDbAndIndex(ActiveRuleKey.of(XOO_P2_KEY, XOO_X2), MAJOR, null, Collections.emptyMap()); -// -// // unset parent -// dbSession.clearCache(); -// ruleActivator.setParent(dbSession, selectProfile(XOO_P2_KEY), null); -// assertThat(countActiveRules(XOO_P2_KEY)).isEqualTo(1); -// assertThat(db.qualityProfileDao().selectByUuid(dbSession, XOO_P2_KEY).getParentKee()).isNull(); -// verifyHasActiveRuleInDbAndIndex(ActiveRuleKey.of(XOO_P2_KEY, XOO_X2), MAJOR, null, Collections.emptyMap()); -// } -// -// @Test -// public void unset_no_parent_does_not_fail() { -// // P1 has no parent ! -// ruleActivator.setParent(dbSession, selectProfile(XOO_P1_KEY), null); -// assertThat(selectProfile(XOO_P1_KEY).getParentKee()).isNull(); -// } -// -// @Test -// public void fail_if_set_child_as_parent() { -// createChildProfiles(); -// -// try { -// ruleActivator.setParent(dbSession, selectProfile(XOO_P1_KEY), selectProfile(XOO_P3_KEY)); -// fail(); -// } catch (BadRequestException e) { -// assertThat(e).hasMessage("Descendant profile 'XOO_P3' can not be selected as parent of 'XOO_P1'"); -// } -// } -// -// @Test -// public void keep_overridden_rules_when_unsetting_parent() { -// // x1 is activated on the "future parent" -// RuleActivation activation = new RuleActivation(XOO_X1); -// activation.setSeverity("MAJOR"); -// activate(activation, XOO_P1_KEY); -// verifyOneActiveRuleInDb(XOO_P1_KEY, XOO_X1, MAJOR, null, ImmutableMap.of("max", "10")); -// -// // create empty profile P2 -// db.qualityProfileDao().insert(dbSession, QProfileTesting.newXooP2("org-123")); -// dbSession.commit(); -// dbSession.clearCache(); -// -// // set parent -> child profile inherits rule x1 -// ruleActivator.setParent(dbSession, selectProfile(XOO_P2_KEY), selectProfile(XOO_P1_KEY)); -// verifyOneActiveRuleInDbAndIndex(XOO_P2_KEY, XOO_X1, MAJOR, INHERITED, ImmutableMap.of("max", "10")); -// -// // override x1 -// activation = new RuleActivation(XOO_X1); -// activation.setSeverity("BLOCKER").setParameter("max", "333"); -// activate(activation, XOO_P2_KEY); -// verifyOneActiveRuleInDb(XOO_P2_KEY, XOO_X1, BLOCKER, OVERRIDES, ImmutableMap.of("max", "333")); -// -// // unset parent -> keep x1 -// ruleActivator.setParent(dbSession, selectProfile(XOO_P2_KEY), null); -// dbSession.clearCache(); -// assertThat(db.qualityProfileDao().selectByUuid(dbSession, XOO_P2_KEY).getParentKee()).isNull(); -// verifyOneActiveRuleInDbAndIndex(XOO_P2_KEY, XOO_X1, BLOCKER, null, ImmutableMap.of("max", "333")); -// } // // @Test // public void ignore_activation_errors_when_setting_parent() { diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorTest.java new file mode 100644 index 00000000000..021f0b53a06 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/qualityprofile/RuleActivatorTest.java @@ -0,0 +1,967 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.sonar.server.qualityprofile; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import javax.annotation.Nullable; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.PropertyType; +import org.sonar.api.config.MapSettings; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.rule.RuleStatus; +import org.sonar.api.rule.Severity; +import org.sonar.api.utils.System2; +import org.sonar.api.utils.internal.AlwaysIncreasingSystem2; +import org.sonar.db.DbTester; +import org.sonar.db.qualityprofile.ActiveRuleParamDto; +import org.sonar.db.qualityprofile.OrgActiveRuleDto; +import org.sonar.db.qualityprofile.QProfileDto; +import org.sonar.db.rule.RuleDefinitionDto; +import org.sonar.db.rule.RuleParamDto; +import org.sonar.server.es.EsTester; +import org.sonar.server.exceptions.BadRequestException; +import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; +import org.sonar.server.qualityprofile.index.ActiveRuleIteratorFactory; +import org.sonar.server.rule.index.RuleIndex; +import org.sonar.server.rule.index.RuleIndexDefinition; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.util.IntegerTypeValidation; +import org.sonar.server.util.StringTypeValidation; +import org.sonar.server.util.TypeValidations; + +import static com.google.common.collect.ImmutableMap.of; +import static java.util.Arrays.asList; +import static java.util.Collections.emptyMap; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; +import static org.sonar.api.rule.Severity.BLOCKER; +import static org.sonar.api.rule.Severity.CRITICAL; +import static org.sonar.api.rule.Severity.MAJOR; + +public class RuleActivatorTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private System2 system2 = new AlwaysIncreasingSystem2(); + @Rule + public DbTester db = DbTester.create(system2); + @Rule + public EsTester es = new EsTester(RuleIndexDefinition.createForTest(new MapSettings())); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + private RuleIndex ruleIndex = new RuleIndex(es.client()); + private RuleActivatorContextFactory contextFactory = new RuleActivatorContextFactory(db.getDbClient()); + private ActiveRuleIteratorFactory activeRuleIteratorFactory = new ActiveRuleIteratorFactory(db.getDbClient()); + private ActiveRuleIndexer activeRuleIndexer = new ActiveRuleIndexer(db.getDbClient(), es.client(), activeRuleIteratorFactory); + private TypeValidations typeValidations = new TypeValidations(asList(new StringTypeValidation(), new IntegerTypeValidation())); + + private RuleActivator underTest = new RuleActivator(system2, db.getDbClient(), ruleIndex, contextFactory, typeValidations, activeRuleIndexer, + userSession); + + @Test + public void system_activates_rule_without_parameters() { + RuleDefinitionDto rule = createRule(); + QProfileDto profile = createProfile(rule); + RuleActivation activation = new RuleActivation(rule.getKey()); + activation.setSeverity(BLOCKER); + List<ActiveRuleChange> changes = activate(profile, activation); + + assertThatRuleIsActivated(profile, rule, changes, BLOCKER, null, emptyMap()); + assertThatProfileIsUpdatedBySystem(profile); + } + + @Test + public void user_activates_rule_without_parameters() { + userSession.logIn(); + RuleDefinitionDto rule = createRule(); + QProfileDto profile = createProfile(rule); + RuleActivation activation = new RuleActivation(rule.getKey()); + activation.setSeverity(BLOCKER); + List<ActiveRuleChange> changes = activate(profile, activation); + + assertThatRuleIsActivated(profile, rule, changes, BLOCKER, null, emptyMap()); + assertThatProfileIsUpdatedByUser(profile); + } + + @Test + public void activate_rule_with_default_severity_and_parameters() { + RuleDefinitionDto rule = createRule(); + RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10")); + QProfileDto profile = createProfile(rule); + + RuleActivation activation = new RuleActivation(rule.getKey()); + List<ActiveRuleChange> changes = activate(profile, activation); + + assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "10")); + assertThatProfileIsUpdatedBySystem(profile); + } + + @Test + public void activate_rule_with_parameters() { + RuleDefinitionDto rule = createRule(); + RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10")); + QProfileDto profile = createProfile(rule); + + RuleActivation activation = new RuleActivation(rule.getKey()) + .setParameter(ruleParam.getName(), "15"); + List<ActiveRuleChange> changes = activate(profile, activation); + + assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "15")); + assertThatProfileIsUpdatedBySystem(profile); + } + + @Test + public void activate_rule_with_default_severity() { + RuleDefinitionDto rule = createRule(); + QProfileDto profile = createProfile(rule); + + RuleActivation activation = new RuleActivation(rule.getKey()); + List<ActiveRuleChange> changes = activate(profile, activation); + + assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap()); + assertThatProfileIsUpdatedBySystem(profile); + } + + /** + * SONAR-5841 + */ + @Test + public void activate_rule_with_empty_parameter_having_no_default_value() { + RuleDefinitionDto rule = createRule(); + RuleParamDto ruleParam = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue("10")); + QProfileDto profile = createProfile(rule); + + RuleActivation activation = new RuleActivation(rule.getKey()) + .setParameter("min", ""); + List<ActiveRuleChange> changes = activate(profile, activation); + + assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of("min", "10")); + assertThatProfileIsUpdatedBySystem(profile); + } + + /** + // * SONAR-5840 + // */ + @Test + public void activate_rule_with_negative_integer_value_on_parameter_having_no_default_value() { + RuleDefinitionDto rule = createRule(); + RuleParamDto paramWithoutDefault = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue(null)); + RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); + QProfileDto profile = createProfile(rule); + + RuleActivation activation = new RuleActivation(rule.getKey()) + .setParameter(paramWithoutDefault.getName(), "-10"); + List<ActiveRuleChange> changes = activate(profile, activation); + + assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, + of(paramWithoutDefault.getName(), "-10", paramWithDefault.getName(), paramWithDefault.getDefaultValue())); + assertThatProfileIsUpdatedBySystem(profile); + } + + @Test + public void activation_ignores_unsupported_parameters() { + RuleDefinitionDto rule = createRule(); + RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); + QProfileDto profile = createProfile(rule); + + RuleActivation activation = new RuleActivation(rule.getKey()) + .setParameter("xxx", "yyy"); + List<ActiveRuleChange> changes = activate(profile, activation); + + assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue())); + assertThatProfileIsUpdatedBySystem(profile); + } + + @Test + public void update_an_already_activated_rule() { + RuleDefinitionDto rule = createRule(); + RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); + QProfileDto profile = createProfile(rule); + + // initial activation + RuleActivation activation = new RuleActivation(rule.getKey()) + .setSeverity(MAJOR); + activate(profile, activation); + + // update + RuleActivation updateActivation = new RuleActivation(rule.getKey()) + .setSeverity(CRITICAL) + .setParameter(param.getName(), "20"); + List<ActiveRuleChange> changes = activate(profile, updateActivation); + + assertThatRuleIsUpdated(profile, rule, CRITICAL, null, of(param.getName(), "20")); + assertThatProfileIsUpdatedBySystem(profile); + } + + @Test + public void update_activation_with_parameter_without_default_value() { + RuleDefinitionDto rule = createRule(); + RuleParamDto paramWithoutDefault = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue(null)); + RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); + QProfileDto profile = createProfile(rule); + + // initial activation -> param "max" has a default value + RuleActivation activation = new RuleActivation(rule.getKey()); + activate(profile, activation); + + // update param "min", which has no default value + RuleActivation updateActivation = new RuleActivation(rule.getKey()) + .setSeverity(MAJOR) + .setParameter(paramWithoutDefault.getName(), "3"); + List<ActiveRuleChange> changes = activate(profile, updateActivation); + + assertThatRuleIsUpdated(profile, rule, MAJOR, null, of(paramWithDefault.getName(), "10", paramWithoutDefault.getName(), "3")); + assertThatProfileIsUpdatedBySystem(profile); + } + + @Test + public void reset_parameter_to_default_value() { + RuleDefinitionDto rule = createRule(); + RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); + QProfileDto profile = createProfile(rule); + + // initial activation -> param "max" has a default value + RuleActivation activation = new RuleActivation(rule.getKey()) + .setParameter(paramWithDefault.getName(), "20"); + activate(profile, activation); + + // reset to default_value + RuleActivation updateActivation = new RuleActivation(rule.getKey()) + .setParameter(paramWithDefault.getName(), null); + List<ActiveRuleChange> changes = activate(profile, updateActivation); + + assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(paramWithDefault.getName(), "10")); + assertThat(changes).hasSize(1); + } + + @Test + public void update_activation_removes_parameter_without_default_value() { + RuleDefinitionDto rule = createRule(); + RuleParamDto paramWithoutDefault = db.rules().insertRuleParam(rule, p -> p.setName("min").setDefaultValue(null)); + RuleParamDto paramWithDefault = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); + QProfileDto profile = createProfile(rule); + + // initial activation -> param "max" has a default value + RuleActivation activation = new RuleActivation(rule.getKey()) + .setParameter(paramWithoutDefault.getName(), "20"); + activate(profile, activation); + + // remove parameter + RuleActivation updateActivation = new RuleActivation(rule.getKey()) + .setParameter(paramWithoutDefault.getName(), null); + List<ActiveRuleChange> changes = activate(profile, updateActivation); + + assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(paramWithDefault.getName(), paramWithDefault.getDefaultValue())); + assertThat(changes).hasSize(1); + } + + @Test + public void update_activation_with_new_parameter() { + RuleDefinitionDto rule = createRule(); + RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); + QProfileDto profile = createProfile(rule); + + // initial activation -> param "max" has a default value + RuleActivation activation = new RuleActivation(rule.getKey()); + List<ActiveRuleChange> changes = activate(profile, activation); + db.getDbClient().activeRuleDao().deleteParametersByRuleProfileUuids(db.getSession(), asList(profile.getRulesProfileUuid())); + assertThatRuleIsActivated(profile, rule, changes, rule.getSeverityString(), null, emptyMap()); + + // contrary to activerule, the param is supposed to be inserted but not updated + RuleActivation updateActivation = new RuleActivation(rule.getKey()) + .setParameter(param.getName(), null); + changes = activate(profile, updateActivation); + + assertThatRuleIsUpdated(profile, rule, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue())); + assertThat(changes).hasSize(1); + } + + @Test + public void ignore_activation_without_changes() { + RuleDefinitionDto rule = createRule(); + QProfileDto profile = createProfile(rule); + + // initial activation + RuleActivation activation = new RuleActivation(rule.getKey()); + activate(profile, activation); + + // update with exactly the same severity and params + activation = new RuleActivation(rule.getKey()); + List<ActiveRuleChange> changes = activate(profile, activation); + + assertThat(changes).isEmpty(); + } + + @Test + public void do_not_change_severity_and_params_if_unset_and_already_activated() { + RuleDefinitionDto rule = createRule(); + RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10")); + QProfileDto profile = createProfile(rule); + + // initial activation -> param "max" has a default value + RuleActivation activation = new RuleActivation(rule.getKey()) + .setSeverity(BLOCKER) + .setParameter(param.getName(), "20"); + activate(profile, activation); + + // update without any severity or params => keep + RuleActivation update = new RuleActivation(rule.getKey()); + List<ActiveRuleChange> changes = activate(profile, update); + + assertThat(changes).isEmpty(); + } + + @Test + public void activation_fails_if_rule_does_not_exist() { + RuleDefinitionDto rule = createRule(); + QProfileDto profile = createProfile(rule); + RuleKey ruleKey = RuleKey.parse("unknown:xxx"); + RuleActivation activation = new RuleActivation(ruleKey); + + expectFailure("Rule not found: " + ruleKey, () -> activate(profile, activation)); + } + + @Test + public void fail_to_activate_rule_if_profile_is_on_different_languages() { + RuleDefinitionDto rule = createJavaRule(); + QProfileDto profile = db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage("js")); + RuleActivation activation = new RuleActivation(rule.getKey()); + + expectFailure("Rule " + rule.getKey() + " and profile " + profile.getKee() + " have different languages", () -> activate(profile, activation)); + } + + @Test + public void fail_to_activate_rule_if_rule_has_REMOVED_status() { + RuleDefinitionDto rule = db.rules().insert(r -> r.setStatus(RuleStatus.REMOVED)); + QProfileDto profile = createProfile(rule); + RuleActivation activation = new RuleActivation(rule.getKey()); + + expectFailure("Rule was removed: " + rule.getKey(), () -> activate(profile, activation)); + } + + @Test + public void fail_to_activate_if_template() { + RuleDefinitionDto rule = db.rules().insert(r -> r.setIsTemplate(true)); + QProfileDto profile = createProfile(rule); + RuleActivation activation = new RuleActivation(rule.getKey()); + + expectFailure("Rule template can't be activated on a Quality profile: " + rule.getKey(), () -> activate(profile, activation)); + } + + @Test + public void fail_to_activate_if_invalid_parameter() { + RuleDefinitionDto rule = createRule(); + RuleParamDto param = db.rules().insertRuleParam(rule, p -> p.setName("max").setDefaultValue("10").setType(PropertyType.INTEGER.name())); + QProfileDto profile = createProfile(rule); + + RuleActivation activation = new RuleActivation(rule.getKey()) + .setParameter(param.getName(), "foo"); + expectFailure("Value 'foo' must be an integer.", () -> activate(profile, activation)); + } + + @Test + public void user_deactivates_a_rule() { + userSession.logIn(); + RuleDefinitionDto rule = createRule(); + QProfileDto profile = createProfile(rule); + RuleActivation activation = new RuleActivation(rule.getKey()); + activate(profile, activation); + + List<ActiveRuleChange> changes = deactivate(profile, rule); + verifyNoActiveRules(); + assertThatProfileIsUpdatedByUser(profile); + assertThat(changes).hasSize(1); + assertThat(changes.get(0).getType()).isEqualTo(ActiveRuleChange.Type.DEACTIVATED); + } + + @Test + public void system_deactivates_a_rule() { + RuleDefinitionDto rule = createRule(); + QProfileDto profile = createProfile(rule); + RuleActivation activation = new RuleActivation(rule.getKey()); + activate(profile, activation); + + List<ActiveRuleChange> changes = deactivate(profile, rule); + verifyNoActiveRules(); + assertThatProfileIsUpdatedBySystem(profile); + assertThatChangeIsDeactivation(changes, rule); + } + + private void assertThatChangeIsDeactivation(List<ActiveRuleChange> changes, RuleDefinitionDto rule) { + assertThat(changes).hasSize(1); + ActiveRuleChange change = changes.get(0); + assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.DEACTIVATED); + assertThat(change.getKey().getRuleKey()).isEqualTo(rule.getKey()); + } + + @Test + public void ignore_deactivation_if_rule_is_not_activated() { + RuleDefinitionDto rule = createRule(); + QProfileDto profile = createProfile(rule); + + List<ActiveRuleChange> changes = deactivate(profile, rule); + verifyNoActiveRules(); + assertThat(changes).hasSize(0); + } + + @Test + public void deactivation_fails_if_rule_does_not_exist() { + RuleDefinitionDto rule = createRule(); + QProfileDto profile = createProfile(rule); + RuleKey ruleKey = RuleKey.parse("unknown:xxx"); + + expectFailure("Rule not found: " + ruleKey, () -> underTest.deactivate(db.getSession(), profile, ruleKey)); + } + + @Test + public void deactivate_rule_that_has_REMOVED_status() { + RuleDefinitionDto rule = createRule(); + QProfileDto profile = createProfile(rule); + RuleActivation activation = new RuleActivation(rule.getKey()); + activate(profile, activation); + + rule.setStatus(RuleStatus.REMOVED); + db.getDbClient().ruleDao().update(db.getSession(), rule); + + List<ActiveRuleChange> changes = deactivate(profile, rule); + verifyNoActiveRules(); + assertThatChangeIsDeactivation(changes, rule); + } + + @Test + public void activation_on_child_profile_is_propagated_to_descendants() { + RuleDefinitionDto rule = createRule(); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + QProfileDto grandChildProfile = createChildProfile(childProfile); + + List<ActiveRuleChange> changes = activate(childProfile, new RuleActivation(rule.getKey())); + assertThatProfileHasNoActiveRules(parentProfile); + assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), null, emptyMap()); + assertThatRuleIsActivated(grandChildProfile, rule, changes, rule.getSeverityString(), ActiveRule.Inheritance.INHERITED, emptyMap()); + } + + @Test + public void update_on_child_profile_is_propagated_to_descendants() { + RuleDefinitionDto rule = createRule(); + RuleParamDto param = db.rules().insertRuleParam(rule); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + QProfileDto grandChildProfile = createChildProfile(childProfile); + + RuleActivation initialActivation = new RuleActivation(rule.getKey()) + .setSeverity(MAJOR) + .setParameter(param.getName(), "foo"); + activate(childProfile, initialActivation); + + RuleActivation updateActivation = new RuleActivation(rule.getKey()) + .setSeverity(CRITICAL) + .setParameter(param.getName(), "bar"); + List<ActiveRuleChange> changes = activate(childProfile, updateActivation); + + assertThatProfileHasNoActiveRules(parentProfile); + assertThatRuleIsUpdated(childProfile, rule, CRITICAL, null, of(param.getName(), "bar")); + assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRule.Inheritance.INHERITED, of(param.getName(), "bar")); + assertThat(changes).hasSize(2); + } + + @Test + public void override_activation_of_inherited_profile() { + RuleDefinitionDto rule = createRule(); + RuleParamDto param = db.rules().insertRuleParam(rule); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + QProfileDto grandChildProfile = createChildProfile(childProfile); + + RuleActivation initialActivation = new RuleActivation(rule.getKey()) + .setSeverity(MAJOR) + .setParameter(param.getName(), "foo"); + activate(childProfile, initialActivation); + + RuleActivation overrideActivation = new RuleActivation(rule.getKey()) + .setSeverity(CRITICAL) + .setParameter(param.getName(), "bar"); + List<ActiveRuleChange> changes = activate(grandChildProfile, overrideActivation); + + assertThatProfileHasNoActiveRules(parentProfile); + assertThatRuleIsUpdated(childProfile, rule, MAJOR, null, of(param.getName(), "foo")); + assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRule.Inheritance.OVERRIDES, of(param.getName(), "bar")); + assertThat(changes).hasSize(1); + } + + @Test + public void updated_activation_on_parent_is_not_propagated_to_overridden_profiles() { + RuleDefinitionDto rule = createRule(); + RuleParamDto param = db.rules().insertRuleParam(rule); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + QProfileDto grandChildProfile = createChildProfile(childProfile); + + RuleActivation initialActivation = new RuleActivation(rule.getKey()) + .setSeverity(MAJOR) + .setParameter(param.getName(), "foo"); + activate(childProfile, initialActivation); + + RuleActivation overrideActivation = new RuleActivation(rule.getKey()) + .setSeverity(CRITICAL) + .setParameter(param.getName(), "bar"); + activate(grandChildProfile, overrideActivation); + + // update child --> do not touch grandChild + RuleActivation updateActivation = new RuleActivation(rule.getKey()) + .setSeverity(BLOCKER) + .setParameter(param.getName(), "baz"); + List<ActiveRuleChange> changes = activate(childProfile, updateActivation); + + assertThatProfileHasNoActiveRules(parentProfile); + assertThatRuleIsUpdated(childProfile, rule, BLOCKER, null, of(param.getName(), "baz")); + assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRule.Inheritance.OVERRIDES, of(param.getName(), "bar")); + assertThat(changes).hasSize(1); + } + + @Test + public void reset_on_parent_is_not_propagated_to_overridden_profiles() { + RuleDefinitionDto rule = createRule(); + RuleParamDto param = db.rules().insertRuleParam(rule); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + QProfileDto grandChildProfile = createChildProfile(childProfile); + + RuleActivation initialActivation = new RuleActivation(rule.getKey()) + .setSeverity(MAJOR) + .setParameter(param.getName(), "foo"); + activate(parentProfile, initialActivation); + + RuleActivation overrideActivation = new RuleActivation(rule.getKey()) + .setSeverity(CRITICAL) + .setParameter(param.getName(), "bar"); + activate(grandChildProfile, overrideActivation); + + // reset parent --> touch child but not grandChild + RuleActivation updateActivation = new RuleActivation(rule.getKey()) + .setReset(true); + List<ActiveRuleChange> changes = activate(parentProfile, updateActivation); + + assertThatRuleIsUpdated(parentProfile, rule, rule.getSeverityString(), null, of(param.getName(), param.getDefaultValue())); + assertThatRuleIsUpdated(childProfile, rule, rule.getSeverityString(), ActiveRule.Inheritance.INHERITED, of(param.getName(), param.getDefaultValue())); + assertThatRuleIsUpdated(grandChildProfile, rule, CRITICAL, ActiveRule.Inheritance.OVERRIDES, of(param.getName(), "bar")); + assertThat(changes).hasSize(2); + } + + @Test + public void active_on_parent_a_rule_already_activated_on_child() { + RuleDefinitionDto rule = createRule(); + RuleParamDto param = db.rules().insertRuleParam(rule); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + + RuleActivation childActivation = new RuleActivation(rule.getKey()) + .setSeverity(MAJOR) + .setParameter(param.getName(), "foo"); + activate(childProfile, childActivation); + + RuleActivation parentActivation = new RuleActivation(rule.getKey()) + .setSeverity(CRITICAL) + .setParameter(param.getName(), "bar"); + List<ActiveRuleChange> changes = activate(parentProfile, parentActivation); + + assertThatRuleIsUpdated(parentProfile, rule, CRITICAL, null, of(param.getName(), "bar")); + assertThatRuleIsUpdated(childProfile, rule, MAJOR, ActiveRule.Inheritance.OVERRIDES, of(param.getName(), "foo")); + assertThat(changes).hasSize(2); + } + + @Test + public void do_not_mark_as_overridden_if_same_values_than_parent() { + RuleDefinitionDto rule = createRule(); + RuleParamDto param = db.rules().insertRuleParam(rule); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + + RuleActivation parentActivation = new RuleActivation(rule.getKey()) + .setSeverity(MAJOR) + .setParameter(param.getName(), "foo"); + activate(parentProfile, parentActivation); + + RuleActivation overrideActivation = new RuleActivation(rule.getKey()) + .setSeverity(MAJOR) + .setParameter(param.getName(), "foo"); + List<ActiveRuleChange> changes = activate(childProfile, overrideActivation); + + assertThatRuleIsUpdated(childProfile, rule, MAJOR, ActiveRule.Inheritance.INHERITED, of(param.getName(), "foo")); + assertThat(changes).hasSize(0); + } + + @Test + public void propagate_deactivation_on_children() { + RuleDefinitionDto rule = createRule(); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + + RuleActivation activation = new RuleActivation(rule.getKey()); + List<ActiveRuleChange> changes = activate(parentProfile, activation); + assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap()); + assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), ActiveRule.Inheritance.INHERITED, emptyMap()); + + changes = deactivate(parentProfile, rule); + assertThatProfileHasNoActiveRules(parentProfile); + assertThatProfileHasNoActiveRules(childProfile); + assertThat(changes).hasSize(2); + } + + @Test + public void propagate_deactivation_on_children_even_when_overridden() { + RuleDefinitionDto rule = createRule(); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + + RuleActivation activation = new RuleActivation(rule.getKey()); + List<ActiveRuleChange> changes = activate(parentProfile, activation); + assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap()); + assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), ActiveRule.Inheritance.INHERITED, emptyMap()); + + activation = new RuleActivation(rule.getKey()) + .setSeverity(CRITICAL); + activate(childProfile, activation); + + changes = deactivate(parentProfile, rule); + assertThatProfileHasNoActiveRules(parentProfile); + assertThatProfileHasNoActiveRules(childProfile); + assertThat(changes).hasSize(2); + } + + @Test + public void cannot_deactivate_rule_inherited() { + RuleDefinitionDto rule = createRule(); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + + RuleActivation activation = new RuleActivation(rule.getKey()); + List<ActiveRuleChange> changes = activate(parentProfile, activation); + assertThatRuleIsActivated(parentProfile, rule, changes, rule.getSeverityString(), null, emptyMap()); + assertThatRuleIsActivated(childProfile, rule, changes, rule.getSeverityString(), ActiveRule.Inheritance.INHERITED, emptyMap()); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("Cannot deactivate inherited rule"); + deactivate(childProfile, rule); + } + + @Test + public void reset_child_profile_do_not_change_parent() { + RuleDefinitionDto rule = createRule(); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + + RuleActivation activation = new RuleActivation(rule.getKey()) + .setSeverity(CRITICAL); + List<ActiveRuleChange> changes = activate(parentProfile, activation); + assertThatRuleIsActivated(parentProfile, rule, changes, CRITICAL, null, emptyMap()); + assertThatRuleIsActivated(childProfile, rule, changes, CRITICAL, ActiveRule.Inheritance.INHERITED, emptyMap()); + assertThat(changes).hasSize(2); + + RuleActivation childActivation = new RuleActivation(rule.getKey()) + .setSeverity(BLOCKER); + changes = activate(childProfile, childActivation); + assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRule.Inheritance.OVERRIDES, emptyMap()); + assertThat(changes).hasSize(1); + + RuleActivation resetActivation = new RuleActivation(rule.getKey()).setReset(true); + changes = activate(childProfile, resetActivation); + assertThatRuleIsUpdated(childProfile, rule, CRITICAL, ActiveRule.Inheritance.INHERITED, emptyMap()); + assertThatRuleIsUpdated(parentProfile, rule, CRITICAL, null, emptyMap()); + assertThat(changes).hasSize(1); + } + + @Test + public void reset_parent_is_not_propagated_when_child_overrides() { + RuleDefinitionDto rule = createRule(); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + QProfileDto grandchildProfile = createChildProfile(childProfile); + + RuleActivation activation = new RuleActivation(rule.getKey()) + .setSeverity(CRITICAL); + List<ActiveRuleChange> changes = activate(parentProfile, activation); + assertThatRuleIsActivated(parentProfile, rule, changes, CRITICAL, null, emptyMap()); + assertThatRuleIsActivated(childProfile, rule, changes, CRITICAL, ActiveRule.Inheritance.INHERITED, emptyMap()); + assertThatRuleIsActivated(grandchildProfile, rule, changes, CRITICAL, ActiveRule.Inheritance.INHERITED, emptyMap()); + assertThat(changes).hasSize(3); + + RuleActivation childActivation = new RuleActivation(rule.getKey()) + .setSeverity(BLOCKER); + changes = activate(childProfile, childActivation); + assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRule.Inheritance.OVERRIDES, emptyMap()); + assertThatRuleIsUpdated(grandchildProfile, rule, BLOCKER, ActiveRule.Inheritance.INHERITED, emptyMap()); + assertThat(changes).hasSize(2); + + // Reset on parent do not change child nor grandchild + RuleActivation resetActivation = new RuleActivation(rule.getKey()).setReset(true); + changes = activate(parentProfile, resetActivation); + assertThatRuleIsUpdated(parentProfile, rule, rule.getSeverityString(), null, emptyMap()); + assertThatRuleIsUpdated(childProfile, rule, BLOCKER, ActiveRule.Inheritance.OVERRIDES, emptyMap()); + assertThatRuleIsUpdated(grandchildProfile, rule, BLOCKER, ActiveRule.Inheritance.INHERITED, emptyMap()); + assertThat(changes).hasSize(1); + + // Reset on child change grandchild + resetActivation = new RuleActivation(rule.getKey()).setReset(true); + changes = activate(childProfile, resetActivation); + assertThatRuleIsUpdated(parentProfile, rule, rule.getSeverityString(), null, emptyMap()); + assertThatRuleIsUpdated(childProfile, rule, rule.getSeverityString(), ActiveRule.Inheritance.INHERITED, emptyMap()); + assertThatRuleIsUpdated(grandchildProfile, rule, rule.getSeverityString(), ActiveRule.Inheritance.INHERITED, emptyMap()); + assertThat(changes).hasSize(2); + } + + @Test + public void ignore_reset_if_not_activated() { + RuleDefinitionDto rule = createRule(); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + + RuleActivation resetActivation = new RuleActivation(rule.getKey()).setReset(true); + List<ActiveRuleChange> changes = activate(parentProfile, resetActivation); + verifyNoActiveRules(); + assertThat(changes).hasSize(0); + } + + @Test + public void unset_parent_when_no_parent_does_not_fail() { + RuleDefinitionDto rule = createRule(); + QProfileDto profile = createProfile(rule); + underTest.setParent(db.getSession(), profile, null); + } + + @Test + public void set_itself_as_parent_fails() { + RuleDefinitionDto rule = createRule(); + QProfileDto profile = createProfile(rule); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage(" can not be selected as parent of "); + underTest.setParent(db.getSession(), profile, profile); + } + + @Test + public void set_child_as_parent_fails() { + RuleDefinitionDto rule = createRule(); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage(" can not be selected as parent of "); + underTest.setParent(db.getSession(), parentProfile, childProfile); + } + + @Test + public void set_grandchild_as_parent_fails() { + RuleDefinitionDto rule = createRule(); + QProfileDto parentProfile = createProfile(rule); + QProfileDto childProfile = createChildProfile(parentProfile); + QProfileDto grandchildProfile = createChildProfile(childProfile); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage(" can not be selected as parent of "); + underTest.setParent(db.getSession(), parentProfile, grandchildProfile); + } + + @Test + public void cannot_set_parent_if_language_is_different() { + RuleDefinitionDto rule1 = db.rules().insert(r -> r.setLanguage("foo")); + RuleDefinitionDto rule2 = db.rules().insert(r -> r.setLanguage("bar")); + + QProfileDto parentProfile = createProfile(rule1); + List<ActiveRuleChange> changes = activate(parentProfile, new RuleActivation(rule1.getKey())); + assertThat(changes).hasSize(1); + + QProfileDto childProfile = createProfile(rule2); + changes = activate(childProfile, new RuleActivation(rule2.getKey())); + assertThat(changes).hasSize(1); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("Cannot set the profile"); + + underTest.setParent(db.getSession(), childProfile, parentProfile); + } + + @Test + public void set_then_unset_parent() { + RuleDefinitionDto rule1 = createJavaRule(); + RuleDefinitionDto rule2 = createJavaRule(); + + QProfileDto profile1 = createProfile(rule1); + List<ActiveRuleChange> changes = activate(profile1, new RuleActivation(rule1.getKey())); + assertThat(changes).hasSize(1); + + QProfileDto profile2 = createProfile(rule2); + changes = activate(profile2, new RuleActivation(rule2.getKey())); + assertThat(changes).hasSize(1); + + changes = underTest.setParent(db.getSession(), profile2, profile1); + assertThat(changes).hasSize(1); + assertThatRuleIsActivated(profile2, rule1, changes, rule1.getSeverityString(), ActiveRule.Inheritance.INHERITED, emptyMap()); + assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); + + changes = underTest.setParent(db.getSession(), profile2, null); + assertThat(changes).hasSize(1); + assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); + assertThatRuleIsNotPresent(profile2, rule1); + } + + @Test + public void set_then_unset_parent_keep_overridden_rules() { + RuleDefinitionDto rule1 = createJavaRule(); + RuleDefinitionDto rule2 = createJavaRule(); + QProfileDto profile1 = createProfile(rule1); + List<ActiveRuleChange> changes = activate(profile1, new RuleActivation(rule1.getKey())); + assertThat(changes).hasSize(1); + + QProfileDto profile2 = createProfile(rule2); + changes = activate(profile2, new RuleActivation(rule2.getKey())); + assertThat(changes).hasSize(1); + + changes = underTest.setParent(db.getSession(), profile2, profile1); + assertThat(changes).hasSize(1); + assertThatRuleIsActivated(profile2, rule1, changes, rule1.getSeverityString(), ActiveRule.Inheritance.INHERITED, emptyMap()); + assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); + + RuleActivation activation = new RuleActivation(rule1.getKey()) + .setSeverity(BLOCKER); + changes = activate(profile2, activation); + assertThat(changes).hasSize(1); + assertThatRuleIsUpdated(profile2, rule1, BLOCKER, ActiveRule.Inheritance.OVERRIDES, emptyMap()); + assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); + + changes = underTest.setParent(db.getSession(), profile2, null); + assertThat(changes).hasSize(1); + // Not testing changes here since severity is not set in changelog + assertThatRuleIsActivated(profile2, rule1, null, BLOCKER, null, emptyMap()); + assertThatRuleIsActivated(profile2, rule2, null, rule2.getSeverityString(), null, emptyMap()); + } + + private void assertThatProfileHasNoActiveRules(QProfileDto profile) { + List<OrgActiveRuleDto> activeRules = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile); + assertThat(activeRules).isEmpty(); + } + + private List<ActiveRuleChange> deactivate(QProfileDto profile, RuleDefinitionDto rule) { + return underTest.deactivate(db.getSession(), profile, rule.getKey()); + } + + private List<ActiveRuleChange> activate(QProfileDto profile, RuleActivation activation) { + return underTest.activate(db.getSession(), activation, profile); + } + + private QProfileDto createProfile(RuleDefinitionDto rule) { + return db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(rule.getLanguage())); + } + + private QProfileDto createChildProfile(QProfileDto parent) { + return db.qualityProfiles().insert(db.getDefaultOrganization(), p -> p.setLanguage(parent.getLanguage()).setParentKee(parent.getKee())); + } + + private void assertThatProfileIsUpdatedByUser(QProfileDto profile) { + QProfileDto loaded = db.getDbClient().qualityProfileDao().selectByUuid(db.getSession(), profile.getKee()); + assertThat(loaded.getUserUpdatedAt()).isNotNull(); + assertThat(loaded.getRulesUpdatedAt()).isNotEmpty(); + } + + private void assertThatProfileIsUpdatedBySystem(QProfileDto profile) { + QProfileDto loaded = db.getDbClient().qualityProfileDao().selectByUuid(db.getSession(), profile.getKee()); + assertThat(loaded.getUserUpdatedAt()).isNull(); + assertThat(loaded.getRulesUpdatedAt()).isNotEmpty(); + } + + private void assertThatRuleIsActivated(QProfileDto profile, RuleDefinitionDto rule, @Nullable List<ActiveRuleChange> changes, + String expectedSeverity, @Nullable ActiveRule.Inheritance expectedInheritance, Map<String, String> expectedParams) { + OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile) + .stream() + .filter(ar -> ar.getRuleKey().equals(rule.getKey())) + .findFirst() + .orElseThrow(IllegalStateException::new); + + assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity); + assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null); + assertThat(activeRule.getCreatedAt()).isNotNull(); + assertThat(activeRule.getUpdatedAt()).isNotNull(); + + List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleId(db.getSession(), activeRule.getId()); + assertThat(params).hasSize(expectedParams.size()); + + if (changes != null) { + ActiveRuleChange change = changes.stream() + .filter(c -> c.getActiveRule().getId().equals(activeRule.getId())) + .findFirst().orElseThrow(IllegalStateException::new); + assertThat(change.getInheritance()).isEqualTo(expectedInheritance); + assertThat(change.getSeverity()).isEqualTo(expectedSeverity); + assertThat(change.getType()).isEqualTo(ActiveRuleChange.Type.ACTIVATED); + } + } + + private void assertThatRuleIsNotPresent(QProfileDto profile, RuleDefinitionDto rule) { + Optional<OrgActiveRuleDto> activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile) + .stream() + .filter(ar -> ar.getRuleKey().equals(rule.getKey())) + .findFirst(); + + assertThat(activeRule).isEmpty(); + } + + private void assertThatRuleIsUpdated(QProfileDto profile, RuleDefinitionDto rule, + String expectedSeverity, @Nullable ActiveRule.Inheritance expectedInheritance, Map<String, String> expectedParams) { + OrgActiveRuleDto activeRule = db.getDbClient().activeRuleDao().selectByProfile(db.getSession(), profile) + .stream() + .filter(ar -> ar.getRuleKey().equals(rule.getKey())) + .findFirst() + .orElseThrow(IllegalStateException::new); + + assertThat(activeRule.getSeverityString()).isEqualTo(expectedSeverity); + assertThat(activeRule.getInheritance()).isEqualTo(expectedInheritance != null ? expectedInheritance.name() : null); + assertThat(activeRule.getCreatedAt()).isNotNull(); + assertThat(activeRule.getUpdatedAt()).isNotNull(); + + List<ActiveRuleParamDto> params = db.getDbClient().activeRuleDao().selectParamsByActiveRuleId(db.getSession(), activeRule.getId()); + assertThat(params).hasSize(expectedParams.size()); + } + + private void expectFailure(String expectedMessage, Runnable runnable) { + try { + runnable.run(); + fail(); + } catch (BadRequestException e) { + assertThat(e.getMessage()).isEqualTo(expectedMessage); + } + verifyNoActiveRules(); + } + + private void verifyNoActiveRules() { + assertThat(db.countRowsOfTable(db.getSession(), "active_rules")).isEqualTo(0); + } + + private RuleDefinitionDto createRule() { + return db.rules().insert(r -> r.setSeverity(Severity.MAJOR)); + } + + private RuleDefinitionDto createJavaRule() { + return db.rules().insert(r -> r.setSeverity(Severity.MAJOR).setLanguage("java")); + } +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/ChangeParentRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/ChangeParentRequest.java new file mode 100644 index 00000000000..4ad8ec57ea5 --- /dev/null +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/ChangeParentRequest.java @@ -0,0 +1,104 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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.ws.client.qualityprofile; + +import javax.annotation.Nullable; + +public class ChangeParentRequest { + private final String language; + private final String parentKey; + private final String parentName; + private final String profileKey; + private final String profileName; + + public ChangeParentRequest(Builder builder) { + this.language = builder.language; + this.parentKey = builder.parentKey; + this.parentName = builder.parentName; + this.profileKey = builder.profileKey; + this.profileName = builder.profileName; + } + + public String getLanguage() { + return language; + } + + public String getParentKey() { + return parentKey; + } + + public String getParentName() { + return parentName; + } + + public String getProfileKey() { + return profileKey; + } + + public String getProfileName() { + return profileName; + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private String language; + private String parentKey; + private String parentName; + private String profileKey; + private String profileName; + + private Builder() { + // enforce factory method use + } + + public Builder setLanguage(@Nullable String language) { + this.language = language; + return this; + } + + public Builder setProfileName(@Nullable String profileName) { + this.profileName = profileName; + return this; + } + + public Builder setProfileKey(@Nullable String profileKey) { + this.profileKey = profileKey; + return this; + } + + public Builder setParentKey(@Nullable String parentKey) { + this.parentKey = parentKey; + return this; + } + + public Builder setParentName(@Nullable String parentName) { + this.parentName = parentName; + return this; + } + + public ChangeParentRequest build() { + return new ChangeParentRequest(this); + } + } +} diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfileWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfileWsParameters.java index c054f13eecc..7c3f36cd380 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfileWsParameters.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfileWsParameters.java @@ -43,6 +43,7 @@ public class QualityProfileWsParameters { public static final String ACTION_REMOVE_PROJECT = "remove_project"; public static final String ACTION_CREATE = "create"; public static final String ACTION_COPY = "copy"; + public static final String ACTION_CHANGE_PARENT = "change_parent"; public static final String ACTION_SET_DEFAULT = "set_default"; public static final String ACTION_DELETE = "delete"; @@ -55,6 +56,8 @@ public class QualityProfileWsParameters { public static final String PARAM_PROJECT_UUID = "projectUuid"; public static final String PARAM_FROM_KEY = "fromKey"; public static final String PARAM_TO_NAME = "toName"; + public static final String PARAM_PARENT_NAME = "parentName"; + public static final String PARAM_PARENT_KEY = "parentKey"; private QualityProfileWsParameters() { // Only static stuff diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesService.java index 5fe3a705b16..e885f51f101 100644 --- a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesService.java +++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesService.java @@ -30,8 +30,10 @@ import org.sonarqube.ws.client.WsConnector; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_ACTIVATE_RULE; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_ADD_PROJECT; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_CHANGE_PARENT; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_COPY; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_CREATE; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_DEACTIVATE_RULE; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_DELETE; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_REMOVE_PROJECT; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.ACTION_RESTORE; @@ -43,6 +45,8 @@ import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters. import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_FROM_KEY; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_LANGUAGE; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_ORGANIZATION; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PARENT_KEY; +import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PARENT_NAME; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_KEY; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROFILE_NAME; import static org.sonarqube.ws.client.qualityprofile.QualityProfileWsParameters.PARAM_PROJECT_KEY; @@ -67,6 +71,13 @@ public class QualityProfilesService extends BaseService { call(httpRequest); } + public void deactivateRule(String profileKey, String ruleKey) { + PostRequest httpRequest = new PostRequest(path(ACTION_DEACTIVATE_RULE)); + httpRequest.setParam(ActivateActionParameters.PARAM_PROFILE_KEY, profileKey); + httpRequest.setParam(ActivateActionParameters.PARAM_RULE_KEY, ruleKey); + call(httpRequest); + } + public void restoreProfile(RestoreWsRequest request) { PostRequest httpRequest = new PostRequest(path(ACTION_RESTORE)); httpRequest.setParam(PARAM_ORGANIZATION, request.getOrganization().orElse(null)); @@ -106,6 +117,7 @@ public class QualityProfilesService extends BaseService { public CreateWsResponse create(CreateRequest request) { PostRequest postRequest = new PostRequest(path(ACTION_CREATE)) + .setParam(PARAM_ORGANIZATION, request.getOrganizationKey()) .setParam(PARAM_LANGUAGE, request.getLanguage()) .setParam(PARAM_PROFILE_NAME, request.getProfileName()); return call(postRequest, CreateWsResponse.parser()); @@ -119,6 +131,15 @@ public class QualityProfilesService extends BaseService { return call(postRequest, CopyWsResponse.parser()); } + public void changeParent(ChangeParentRequest request) { + call(new PostRequest(path(ACTION_CHANGE_PARENT)) + .setParam(PARAM_LANGUAGE, request.getLanguage()) + .setParam(PARAM_PARENT_KEY, request.getParentKey()) + .setParam(PARAM_PARENT_NAME, request.getParentName()) + .setParam(PARAM_PROFILE_KEY, request.getProfileKey()) + .setParam(PARAM_PROFILE_NAME, request.getProfileName())); + } + public void setDefault(SetDefaultRequest request) { PostRequest postRequest = new PostRequest(path(ACTION_SET_DEFAULT)) .setParam(PARAM_PROFILE_KEY, request.getProfileKey()); diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesServiceTest.java index 411d4662779..ae1d3c9c0f3 100644 --- a/sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesServiceTest.java +++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/qualityprofile/QualityProfilesServiceTest.java @@ -23,6 +23,7 @@ import org.junit.Rule; import org.junit.Test; import org.sonarqube.ws.QualityProfiles; import org.sonarqube.ws.client.GetRequest; +import org.sonarqube.ws.client.PostRequest; import org.sonarqube.ws.client.ServiceTester; import org.sonarqube.ws.client.WsConnector; @@ -138,4 +139,16 @@ public class QualityProfilesServiceTest { .hasParam(PARAM_PROFILE_KEY, "sample") .andNoOtherParam(); } + + @Test + public void deactivate_rule() { + underTest.deactivateRule("P1", "R1"); + PostRequest request = serviceTester.getPostRequest(); + + serviceTester.assertThat(request) + .hasPath("deactivate_rule") + .hasParam(QualityProfileWsParameters.ActivateActionParameters.PARAM_PROFILE_KEY, "P1") + .hasParam(QualityProfileWsParameters.ActivateActionParameters.PARAM_RULE_KEY, "R1") + .andNoOtherParam(); + } } |