From: Simon Brandhof Date: Mon, 13 Nov 2017 23:01:28 +0000 (+0100) Subject: Add category "project" to integration tests X-Git-Tag: 7.0-RC1~315 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=6dc1fa4a8673780f948c1f6e4917637467b35b47;p=sonarqube.git Add category "project" to integration tests --- diff --git a/cix.sh b/cix.sh index 073f4b76a52..6acdae1ff4e 100755 --- a/cix.sh +++ b/cix.sh @@ -30,7 +30,7 @@ case "$RUN_ACTIVITY" in ;; Category3) - CATEGORY="Category3" + CATEGORY="Category3|component|project" ;; Category4) diff --git a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java index b9770335aad..25fc6937c8e 100644 --- a/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java +++ b/server/sonar-qa-util/src/main/java/org/sonarqube/qa/util/pageobjects/Navigation.java @@ -187,6 +187,13 @@ public class Navigation { return open("/projects_admin", ProjectsManagementPage.class); } + /** + * Should be replaced by an intermediary OrganizationPage + */ + public ProjectsManagementPage openProjectsManagement(String orgKey) { + return open("/organizations/" + orgKey + "/projects_management", ProjectsManagementPage.class); + } + public LoginPage openLogin() { return open("/sessions/login", LoginPage.class); } diff --git a/tests/src/test/java/org/sonarqube/tests/Category1Suite.java b/tests/src/test/java/org/sonarqube/tests/Category1Suite.java index 2393e681879..34afd54d11b 100644 --- a/tests/src/test/java/org/sonarqube/tests/Category1Suite.java +++ b/tests/src/test/java/org/sonarqube/tests/Category1Suite.java @@ -23,12 +23,8 @@ import com.sonar.orchestrator.Orchestrator; import org.junit.ClassRule; import org.junit.runner.RunWith; import org.junit.runners.Suite; -import org.sonarqube.tests.projectAdministration.BackgroundTasksTest; +import org.sonarqube.tests.ce.BackgroundTasksTest; import org.sonarqube.tests.projectAdministration.ProjectAdministrationTest; -import org.sonarqube.tests.projectAdministration.ProjectBulkDeletionPageTest; -import org.sonarqube.tests.projectAdministration.ProjectLinksPageTest; -import org.sonarqube.tests.projectAdministration.ProjectVisibilityPageTest; -import org.sonarqube.tests.projectSearch.ProjectsPageTest; import org.sonarqube.tests.settings.DeprecatedPropertiesWsTest; import org.sonarqube.tests.settings.EmailsTest; import org.sonarqube.tests.settings.PropertySetsTest; @@ -45,21 +41,13 @@ import static util.ItUtils.xooPlugin; @Deprecated @RunWith(Suite.class) @Suite.SuiteClasses({ - // administration UsersPageTest.class, - ProjectVisibilityPageTest.class, - // project administration - ProjectBulkDeletionPageTest.class, ProjectAdministrationTest.class, - ProjectLinksPageTest.class, BackgroundTasksTest.class, - // settings DeprecatedPropertiesWsTest.class, EmailsTest.class, PropertySetsTest.class, - SettingsTest.class, - // measure - ProjectsPageTest.class + SettingsTest.class }) public class Category1Suite { diff --git a/tests/src/test/java/org/sonarqube/tests/Category2Suite.java b/tests/src/test/java/org/sonarqube/tests/Category2Suite.java index 03fd21935d7..619aa95106b 100644 --- a/tests/src/test/java/org/sonarqube/tests/Category2Suite.java +++ b/tests/src/test/java/org/sonarqube/tests/Category2Suite.java @@ -23,7 +23,7 @@ import com.sonar.orchestrator.Orchestrator; import org.junit.ClassRule; import org.junit.runner.RunWith; import org.junit.runners.Suite; -import org.sonarqube.tests.branch.BranchTest; +import org.sonarqube.tests.component.BranchTest; import org.sonarqube.tests.issue.AutoAssignTest; import org.sonarqube.tests.issue.CommonRulesTest; import org.sonarqube.tests.issue.CustomRulesTest; diff --git a/tests/src/test/java/org/sonarqube/tests/Category4Suite.java b/tests/src/test/java/org/sonarqube/tests/Category4Suite.java index 6c2d14ae4ba..94d9a43693a 100644 --- a/tests/src/test/java/org/sonarqube/tests/Category4Suite.java +++ b/tests/src/test/java/org/sonarqube/tests/Category4Suite.java @@ -27,9 +27,6 @@ import org.sonarqube.tests.analysis.FileExclusionsTest; import org.sonarqube.tests.analysis.IssueExclusionsTest; import org.sonarqube.tests.ce.CeTempDirTest; import org.sonarqube.tests.ce.CeWsTest; -import org.sonarqube.tests.component.ComponentsWsTest; -import org.sonarqube.tests.component.ProjectsWsTest; -import org.sonarqube.tests.projectEvent.ProjectActivityPageTest; import org.sonarqube.tests.qualityProfile.QualityProfilesUiTest; import org.sonarqube.tests.serverSystem.HttpHeadersTest; import org.sonarqube.tests.serverSystem.LogsTest; @@ -72,14 +69,9 @@ import static util.ItUtils.xooPlugin; LocalAuthenticationTest.class, BaseIdentityProviderTest.class, OAuth2IdentityProviderTest.class, - // component search - ProjectsWsTest.class, - ComponentsWsTest.class, // analysis exclusion FileExclusionsTest.class, IssueExclusionsTest.class, - // db cleaner - ProjectActivityPageTest.class, // http HttpHeadersTest.class, // ui diff --git a/tests/src/test/java/org/sonarqube/tests/Category6Suite.java b/tests/src/test/java/org/sonarqube/tests/Category6Suite.java index 87ebf3ac247..9cb93ba6474 100644 --- a/tests/src/test/java/org/sonarqube/tests/Category6Suite.java +++ b/tests/src/test/java/org/sonarqube/tests/Category6Suite.java @@ -31,12 +31,6 @@ import org.sonarqube.tests.issue.IssueNotificationsTest; import org.sonarqube.tests.issue.IssueTagsTest; import org.sonarqube.tests.issue.OrganizationIssueAssignTest; import org.sonarqube.tests.issue.OrganizationIssuesPageTest; -import org.sonarqube.tests.projectAdministration.ProjectDeleteTest; -import org.sonarqube.tests.projectAdministration.ProjectKeyUpdateTest; -import org.sonarqube.tests.projectAdministration.ProjectProvisioningTest; -import org.sonarqube.tests.projectAdministration.ProjectSearchTest; -import org.sonarqube.tests.projectSearch.LeakProjectsPageTest; -import org.sonarqube.tests.projectSearch.SearchProjectsTest; import org.sonarqube.tests.qualityProfile.BuiltInQualityProfilesTest; import org.sonarqube.tests.qualityProfile.CustomQualityProfilesTest; import org.sonarqube.tests.qualityProfile.QualityProfilesEditTest; @@ -64,13 +58,7 @@ import static util.ItUtils.xooPlugin; QualityProfilesWsTest.class, CustomQualityProfilesTest.class, IssueTagsTest.class, - LeakProjectsPageTest.class, - SearchProjectsTest.class, RulesWsTest.class, - ProjectDeleteTest.class, - ProjectProvisioningTest.class, - ProjectKeyUpdateTest.class, - ProjectSearchTest.class, PermissionTemplateTest.class, ReportFailureNotificationTest.class, IssueNotificationsTest.class diff --git a/tests/src/test/java/org/sonarqube/tests/branch/BranchTest.java b/tests/src/test/java/org/sonarqube/tests/branch/BranchTest.java deleted file mode 100644 index aef3ab0696a..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/branch/BranchTest.java +++ /dev/null @@ -1,66 +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 org.sonarqube.tests.branch; - -import com.sonar.orchestrator.Orchestrator; -import java.util.Map; -import org.assertj.core.groups.Tuple; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.sonarqube.tests.Category2Suite; -import org.sonarqube.qa.util.Tester; -import org.sonarqube.ws.Common; -import org.sonarqube.ws.WsBranches; -import org.sonarqube.ws.client.GetRequest; -import org.sonarqube.ws.client.WsResponse; -import util.ItUtils; - -import static org.assertj.core.api.Java6Assertions.assertThat; -import static util.ItUtils.runProjectAnalysis; - -public class BranchTest { - - @ClassRule - public static Orchestrator orchestrator = Category2Suite.ORCHESTRATOR; - - @Rule - public Tester tester = new Tester(orchestrator).disableOrganizations(); - - @Test - public void list_branches_contains_main_branch() { - runProjectAnalysis(orchestrator, "shared/xoo-sample"); - - WsBranches.ListWsResponse result = tester.wsClient().projectBranches().list("sample"); - - assertThat(result.getBranchesList()) - .extracting(WsBranches.Branch::getName, WsBranches.Branch::getType, WsBranches.Branch::getIsMain) - .containsExactlyInAnyOrder(Tuple.tuple("master", Common.BranchType.LONG, true)); - } - - @Test - public void navigation_global_return_branches_support_to_false() { - WsResponse status = tester.wsClient().wsConnector().call(new GetRequest("api/navigation/global")); - Map statusMap = ItUtils.jsonToMap(status.content()); - - assertThat(statusMap.get("branchesEnabled")).isEqualTo(false); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/ce/BackgroundTasksTest.java b/tests/src/test/java/org/sonarqube/tests/ce/BackgroundTasksTest.java new file mode 100644 index 00000000000..059bfa26b32 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/ce/BackgroundTasksTest.java @@ -0,0 +1,115 @@ +/* + * 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.tests.ce; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import org.sonarqube.tests.Category1Suite; +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.qa.util.pageobjects.BackgroundTaskItem; +import org.sonarqube.qa.util.pageobjects.BackgroundTasksPage; +import org.sonarqube.qa.util.pageobjects.Navigation; +import util.user.UserRule; + +import static com.codeborne.selenide.CollectionCondition.sizeGreaterThan; +import static util.ItUtils.projectDir; +import static util.selenium.Selenese.runSelenese; + +public class BackgroundTasksTest { + + private static final String ADMIN_USER_LOGIN = "admin-user"; + + @ClassRule + public static Orchestrator ORCHESTRATOR = Category1Suite.ORCHESTRATOR; + + @Rule + public UserRule userRule = UserRule.from(ORCHESTRATOR); + + private Navigation nav = Navigation.create(ORCHESTRATOR); + + @BeforeClass + public static void beforeClass() { + executeBuild("test-project", "Test Project"); + executeBuild("test-project-2", "Another Test Project"); + } + + @Before + public void before() { + userRule.createAdminUser(ADMIN_USER_LOGIN, ADMIN_USER_LOGIN); + } + + @After + public void deleteAdminUser() { + userRule.resetUsers(); + } + + @Test + public void should_not_display_failing_and_search_and_filter_elements_on_project_level_page() throws Exception { + runSelenese(ORCHESTRATOR, "/projectAdministration/BackgroundTasksTest/should_not_display_failing_and_search_and_filter_elements_on_project_level_page.html"); + } + + @Test + public void display_scanner_context() { + nav.logIn().submitCredentials(ADMIN_USER_LOGIN); + BackgroundTasksPage page = nav.openBackgroundTasksPage(); + + page.getTasks().shouldHave(sizeGreaterThan(0)); + BackgroundTaskItem task = page.getTasksAsItems().get(0); + task.openActions() + .openScannerContext() + .assertScannerContextContains("SonarQube plugins:") + .assertScannerContextContains("Global properties:"); + } + + @Test + public void display_error_stacktrace() { + Navigation nav = Navigation.create(ORCHESTRATOR); + executeBuild("test-project", "Test Project", "2010-01-01"); + + nav.logIn().submitCredentials(ADMIN_USER_LOGIN); + BackgroundTasksPage page = nav.openBackgroundTasksPage(); + + page.getTasks().shouldHave(sizeGreaterThan(0)); + BackgroundTaskItem task = page.getTasksAsItems().get(0); + task.openActions() + .openErrorStacktrace() + .assertErrorStacktraceContains("Date of analysis cannot be older than the date of the last known analysis"); + } + + private static void executeBuild(String projectKey, String projectName) { + ORCHESTRATOR.executeBuild( + SonarScanner.create(projectDir("shared/xoo-sample")) + .setProjectKey(projectKey) + .setProjectName(projectName)); + } + + private static void executeBuild(String projectKey, String projectName, String date) { + ORCHESTRATOR.executeBuild( + SonarScanner.create(projectDir("shared/xoo-sample")) + .setProjectKey(projectKey) + .setProjectName(projectName) + .setProperty("sonar.projectDate", date)); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/component/BranchTest.java b/tests/src/test/java/org/sonarqube/tests/component/BranchTest.java new file mode 100644 index 00000000000..feb667dce65 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/component/BranchTest.java @@ -0,0 +1,64 @@ +/* + * 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.tests.component; + +import com.sonar.orchestrator.Orchestrator; +import java.util.Map; +import org.assertj.core.groups.Tuple; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.ws.Common; +import org.sonarqube.ws.WsBranches; +import org.sonarqube.ws.client.GetRequest; +import org.sonarqube.ws.client.WsResponse; +import util.ItUtils; + +import static org.assertj.core.api.Java6Assertions.assertThat; +import static util.ItUtils.runProjectAnalysis; + +public class BranchTest { + + @ClassRule + public static Orchestrator orchestrator = ComponentSuite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator); + + @Test + public void list_branches_contains_main_branch() { + runProjectAnalysis(orchestrator, "shared/xoo-sample"); + + WsBranches.ListWsResponse result = tester.wsClient().projectBranches().list("sample"); + + assertThat(result.getBranchesList()) + .extracting(WsBranches.Branch::getName, WsBranches.Branch::getType, WsBranches.Branch::getIsMain) + .containsExactlyInAnyOrder(Tuple.tuple("master", Common.BranchType.LONG, true)); + } + + @Test + public void navigation_global_return_branches_support_to_false() { + WsResponse status = tester.wsClient().wsConnector().call(new GetRequest("api/navigation/global")); + Map statusMap = ItUtils.jsonToMap(status.content()); + + assertThat(statusMap.get("branchesEnabled")).isEqualTo(false); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/component/CodePageTest.java b/tests/src/test/java/org/sonarqube/tests/component/CodePageTest.java new file mode 100644 index 00000000000..1f1b33f5ae6 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/component/CodePageTest.java @@ -0,0 +1,85 @@ +/* + * 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.tests.component; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.ws.WsProjects.CreateWsResponse.Project; + +import static util.ItUtils.projectDir; + +public class CodePageTest { + + @ClassRule + public static Orchestrator orchestrator = ComponentSuite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator); + + @Test + public void code_page() { + Project project = tester.projects().generate(null); + executeAnalysis(project); + + tester.openBrowser().openCode(project.getKey()) + .shouldHaveComponent("src/main/xoo/sample") + .openFirstComponent() + .shouldHaveComponent("Sample.xoo") + .openFirstComponent() + .shouldHaveCode("public class Sample") + .shouldHaveBreadcrumbs(project.getName(), "src/main/xoo/sample", "Sample.xoo"); + + // search + tester.openBrowser().openCode(project.getKey()) + .shouldHaveComponent(project.getName()) + .search("xoo") + .shouldSearchResult("Sample.xoo"); + + // permalink + tester.openBrowser().openCode(project.getKey(), project.getKey() + ":src/main/xoo/sample/Sample.xoo") + .shouldHaveCode("public class Sample") + .shouldHaveBreadcrumbs(project.getName(), "src/main/xoo/sample", "Sample.xoo"); + } + + @Test + public void expand_root_dir() { + Project project = tester.projects().generate(null); + executeAnalysis(project, "shared/xoo-sample-with-root-dir"); + + tester.openBrowser().openCode(project.getKey()) + .shouldHaveComponent("Hello.xoo") + .shouldHaveComponent("src/main/xoo/sample"); + } + + private void executeAnalysis(Project project, String path) { + orchestrator.executeBuild( + SonarScanner.create(projectDir(path)) + .setProjectKey(project.getKey()) + .setProjectName(project.getName())); + } + + private void executeAnalysis(Project project) { + executeAnalysis(project, "shared/xoo-sample"); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/component/ComponentSuite.java b/tests/src/test/java/org/sonarqube/tests/component/ComponentSuite.java new file mode 100644 index 00000000000..3662490b224 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/component/ComponentSuite.java @@ -0,0 +1,46 @@ +/* + * 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.tests.component; + +import com.sonar.orchestrator.Orchestrator; +import org.junit.ClassRule; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +import static util.ItUtils.xooPlugin; + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + BranchTest.class, + CodePageTest.class, + ComponentsWsTest.class +}) +public class ComponentSuite { + + @ClassRule + public static final Orchestrator ORCHESTRATOR = Orchestrator.builderEnv() + // reduce memory for Elasticsearch + .setServerProperty("sonar.search.javaOpts", "-Xms128m -Xmx128m") + + .addPlugin(xooPlugin()) + + .build(); + +} diff --git a/tests/src/test/java/org/sonarqube/tests/component/ComponentsWsTest.java b/tests/src/test/java/org/sonarqube/tests/component/ComponentsWsTest.java index 69cae2a8d34..2e9ccdd7819 100644 --- a/tests/src/test/java/org/sonarqube/tests/component/ComponentsWsTest.java +++ b/tests/src/test/java/org/sonarqube/tests/component/ComponentsWsTest.java @@ -21,43 +21,39 @@ package org.sonarqube.tests.component; import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.SonarScanner; -import org.sonarqube.tests.Category4Suite; -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.junit.rules.RuleChain; +import org.sonarqube.qa.util.Tester; import org.sonarqube.ws.WsComponents; -import org.sonarqube.ws.client.WsClient; import org.sonarqube.ws.client.component.SearchWsRequest; import org.sonarqube.ws.client.component.ShowWsRequest; -import util.ItUtils; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static util.ItUtils.projectDir; public class ComponentsWsTest { - @ClassRule - public static final Orchestrator orchestrator = Category4Suite.ORCHESTRATOR; + private static final String FILE_KEY = "sample:src/main/xoo/sample/Sample.xoo"; - @Rule - public ExpectedException expectedException = ExpectedException.none(); + @ClassRule + public static final Orchestrator orchestrator = ComponentSuite.ORCHESTRATOR; + + private static Tester tester = new Tester(orchestrator); - WsClient wsClient; + @ClassRule + public static RuleChain ruleChain = RuleChain.outerRule(orchestrator).around(tester); - @Before - public void inspectProject() { - orchestrator.resetData(); + @BeforeClass + public static void setUp() { orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample"))); - - wsClient = ItUtils.newAdminWsClient(orchestrator); } @Test public void show() { - WsComponents.ShowWsResponse response = wsClient.components().show(new ShowWsRequest().setKey(FILE_KEY)); + WsComponents.ShowWsResponse response = tester.wsClient().components().show(new ShowWsRequest().setKey(FILE_KEY)); assertThat(response).isNotNull(); assertThat(response.getComponent().getKey()).isEqualTo(FILE_KEY); @@ -66,7 +62,7 @@ public class ComponentsWsTest { @Test public void search() { - WsComponents.SearchWsResponse response = wsClient.components().search(new SearchWsRequest() + WsComponents.SearchWsResponse response = tester.wsClient().components().search(new SearchWsRequest() .setQualifiers(singletonList("FIL"))); assertThat(response).isNotNull(); diff --git a/tests/src/test/java/org/sonarqube/tests/component/ProjectsWsTest.java b/tests/src/test/java/org/sonarqube/tests/component/ProjectsWsTest.java deleted file mode 100644 index 75d5f5bae16..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/component/ProjectsWsTest.java +++ /dev/null @@ -1,125 +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 org.sonarqube.tests.component; - -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.build.SonarScanner; -import org.sonarqube.tests.Category4Suite; -import java.io.IOException; -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.util.EntityUtils; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonarqube.ws.WsComponents; -import org.sonarqube.ws.WsProjects.BulkUpdateKeyWsResponse; -import org.sonarqube.ws.WsProjects.BulkUpdateKeyWsResponse.Key; -import org.sonarqube.ws.client.WsClient; -import org.sonarqube.ws.client.component.ShowWsRequest; -import org.sonarqube.ws.client.project.BulkUpdateKeyWsRequest; -import org.sonarqube.ws.client.project.UpdateKeyWsRequest; -import util.ItUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.projectDir; - -public class ProjectsWsTest { - - @ClassRule - public static final Orchestrator orchestrator = Category4Suite.ORCHESTRATOR; - private static final String PROJECT_KEY = "sample"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private WsClient wsClient; - - @Before - public void inspectProject() { - orchestrator.resetData(); - orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample"))); - - wsClient = ItUtils.newAdminWsClient(orchestrator); - } - - /** - * SONAR-3105 - */ - @Test - public void projects_web_service() throws IOException { - SonarScanner build = SonarScanner.create(projectDir("shared/xoo-sample")); - orchestrator.executeBuild(build); - - String url = orchestrator.getServer().getUrl() + "/api/projects/index?key=sample&versions=true"; - HttpClient httpclient = new DefaultHttpClient(); - try { - HttpGet get = new HttpGet(url); - HttpResponse response = httpclient.execute(get); - - assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); - String content = IOUtils.toString(response.getEntity().getContent()); - assertThat(content).doesNotContain("error"); - assertThat(content).contains("sample"); - EntityUtils.consume(response.getEntity()); - - } finally { - httpclient.getConnectionManager().shutdown(); - } - } - - @Test - public void update_key() { - String newProjectKey = "another_project_key"; - WsComponents.Component project = wsClient.components().show(new ShowWsRequest().setKey(PROJECT_KEY)).getComponent(); - assertThat(project.getKey()).isEqualTo(PROJECT_KEY); - - wsClient.projects().updateKey(UpdateKeyWsRequest.builder() - .setKey(PROJECT_KEY) - .setNewKey(newProjectKey) - .build()); - - assertThat(wsClient.components().show(new ShowWsRequest().setId(project.getId())).getComponent().getKey()).isEqualTo(newProjectKey); - } - - @Test - public void bulk_update_key() { - String newProjectKey = "another_project_key"; - WsComponents.Component project = wsClient.components().show(new ShowWsRequest().setKey(PROJECT_KEY)).getComponent(); - assertThat(project.getKey()).isEqualTo(PROJECT_KEY); - - BulkUpdateKeyWsResponse result = wsClient.projects().bulkUpdateKey(BulkUpdateKeyWsRequest.builder() - .setKey(PROJECT_KEY) - .setFrom(PROJECT_KEY) - .setTo(newProjectKey) - .build()); - - assertThat(wsClient.components().show(new ShowWsRequest().setId(project.getId())).getComponent().getKey()).isEqualTo(newProjectKey); - assertThat(result.getKeysCount()).isEqualTo(1); - assertThat(result.getKeys(0)) - .extracting(Key::getKey, Key::getNewKey, Key::getDuplicate) - .containsOnlyOnce(PROJECT_KEY, newProjectKey, false); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/measure/MeasureSuite.java b/tests/src/test/java/org/sonarqube/tests/measure/MeasureSuite.java index ffc9325163f..25f8b8ac230 100644 --- a/tests/src/test/java/org/sonarqube/tests/measure/MeasureSuite.java +++ b/tests/src/test/java/org/sonarqube/tests/measure/MeasureSuite.java @@ -34,6 +34,7 @@ import static util.ItUtils.xooPlugin; DecimalScaleMetricTest.class, DifferentialPeriodsTest.class, MeasuresWsTest.class, + ProjectActivityPageTest.class, ProjectDashboardTest.class, ProjectMeasuresPageTest.class, SincePreviousVersionHistoryTest.class, diff --git a/tests/src/test/java/org/sonarqube/tests/measure/ProjectActivityPageTest.java b/tests/src/test/java/org/sonarqube/tests/measure/ProjectActivityPageTest.java new file mode 100644 index 00000000000..188c72841ce --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/measure/ProjectActivityPageTest.java @@ -0,0 +1,93 @@ +/* + * 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.tests.measure; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import java.util.List; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.qa.util.pageobjects.ProjectActivityPage; +import org.sonarqube.qa.util.pageobjects.ProjectAnalysisItem; + +import static util.ItUtils.projectDir; + +public class ProjectActivityPageTest { + + @ClassRule + public static Orchestrator orchestrator = MeasureSuite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator); + + @Test + public void should_list_snapshots() { + analyzeXooSample("shared/xoo-history-v1", "2014-10-19"); + analyzeXooSample("shared/xoo-history-v2", "2014-11-13"); + + ProjectActivityPage page = openPage(); + page.getAnalyses().shouldHaveSize(2); + + List analyses = page.getAnalysesAsItems(); + analyses.get(0) + .shouldHaveEventWithText("1.0-SNAPSHOT") + .shouldNotHaveDeleteButton(); + + analyses.get(1) + .shouldHaveEventWithText("0.9-SNAPSHOT") + .shouldHaveDeleteButton(); + } + + @Test + public void add_change_delete_custom_event() { + analyzeXooSample(); + openPage().getLastAnalysis() + .addCustomEvent("foo") + .changeFirstEvent("bar") + .deleteFirstEvent(); + } + + @Test + public void delete_analysis() { + analyzeXooSample(); + analyzeXooSample(); + ProjectActivityPage page = openPage(); + page.getAnalyses().shouldHaveSize(2); + page.getFirstAnalysis().delete(); + } + + private ProjectActivityPage openPage() { + String userAdmin = tester.users().generateAdministratorOnDefaultOrganization().getLogin(); + return tester.openBrowser() + .logIn() + .submitCredentials(userAdmin, userAdmin) + .openProjectActivity("sample"); + } + + private void analyzeXooSample() { + orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample"))); + } + + private void analyzeXooSample(String path, String date) { + orchestrator.executeBuild(SonarScanner.create(projectDir(path)).setProperties("sonar.projectDate", date)); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectBulkDeletionPageTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectBulkDeletionPageTest.java new file mode 100644 index 00000000000..a040b04d25d --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectBulkDeletionPageTest.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 org.sonarqube.tests.project; + +import com.sonar.orchestrator.Orchestrator; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.ws.WsProjects.CreateWsResponse.Project; +import org.sonarqube.ws.client.component.SearchProjectsRequest; + +import static com.codeborne.selenide.Condition.text; +import static com.codeborne.selenide.Condition.visible; +import static com.codeborne.selenide.Selenide.$; +import static org.assertj.core.api.Assertions.assertThat; + +public class ProjectBulkDeletionPageTest { + + @ClassRule + public static Orchestrator orchestrator = ProjectSuite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator); + + private String sysAdminLogin; + + @Before + public void setUp() { + sysAdminLogin = tester.users().generateAdministratorOnDefaultOrganization().getLogin(); + } + + /** + * SONAR-2614, SONAR-3805 + */ + @Test + public void bulk_deletion_on_selected_projects() throws Exception { + Project project1 = tester.projects().generate(null, t -> t.setName("Foo")); + Project project2 = tester.projects().generate(null, t -> t.setName("Bar")); + Project project3 = tester.projects().generate(null, t -> t.setName("FooQux")); + + tester.openBrowser().logIn().submitCredentials(sysAdminLogin).open("/organizations/default-organization/projects_management"); + $("#projects-management-page").shouldHave(text(project1.getName())).shouldHave(text(project2.getName())).shouldHave(text(project3.getName())); + + $("#projects-management-page .search-box-input").val("foo").pressEnter(); + $("#projects-management-page").shouldNotHave(text(project2.getName())).shouldHave(text(project1.getName())).shouldHave(text(project3.getName())); + + $("#projects-management-page .js-delete").click(); + $(".modal").shouldBe(visible); + $(".modal button").click(); + $("#projects-management-page").shouldNotHave(text(project1.getName())).shouldNotHave(text(project3.getName())); + + assertThat(tester.wsClient().components().searchProjects(SearchProjectsRequest.builder().build()) + .getComponentsCount()).isEqualTo(1); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectBulkDeletionTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectBulkDeletionTest.java new file mode 100644 index 00000000000..559589ffc58 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectBulkDeletionTest.java @@ -0,0 +1,86 @@ +/* + * 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.tests.project; + +import com.sonar.orchestrator.Orchestrator; +import java.util.List; +import java.util.stream.IntStream; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.ws.Organizations; +import org.sonarqube.ws.WsProjects.CreateWsResponse; +import org.sonarqube.ws.WsProjects.SearchWsResponse.Component; +import org.sonarqube.ws.client.project.SearchWsRequest; + +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.runProjectAnalysis; + +public class ProjectBulkDeletionTest { + + @ClassRule + public static Orchestrator orchestrator = ProjectSuite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator); + + @Test + public void delete_projects() { + Organizations.Organization organization = tester.organizations().generate(); + CreateWsResponse.Project firstProvisionedProject = tester.projects().generate(organization, p -> p.setKey("first-provisioned-project")); + CreateWsResponse.Project secondProvisionedProject = tester.projects().generate(organization, p -> p.setKey("second-provisioned-project")); + CreateWsResponse.Project analyzedProject = tester.projects().generate(organization); + + analyzeProject(analyzedProject.getKey(), organization.getKey()); + + tester.wsClient().projects().bulkDelete(SearchWsRequest.builder() + .setOrganization(organization.getKey()) + .setQuery("FIRST-PROVISIONED") + .setOnProvisionedOnly(true).build()); + + List projects = tester.wsClient().projects().search(SearchWsRequest.builder().setOrganization(organization.getKey()).build()).getComponentsList(); + assertThat(projects).extracting(Component::getKey) + .containsExactlyInAnyOrder(analyzedProject.getKey(), secondProvisionedProject.getKey()) + .doesNotContain(firstProvisionedProject.getKey()); + } + + @Test + public void delete_more_than_50_projects_at_the_same_time() { + Organizations.Organization organization = tester.organizations().generate(); + IntStream.range(0, 60).forEach(i -> tester.projects().generate(organization)); + SearchWsRequest request = SearchWsRequest.builder().setOrganization(organization.getKey()).build(); + assertThat(tester.wsClient().projects().search(request).getPaging().getTotal()).isEqualTo(60); + + tester.wsClient().projects().bulkDelete(request); + + assertThat(tester.wsClient().projects().search(request).getComponentsList()).isEmpty(); + assertThat(tester.wsClient().projects().search(request).getPaging().getTotal()).isEqualTo(0); + } + + private void analyzeProject(String projectKey, String organizationKey) { + runProjectAnalysis(orchestrator, "shared/xoo-sample", + "sonar.organization", organizationKey, + "sonar.projectKey", projectKey, + "sonar.login", "admin", + "sonar.password", "admin"); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectDeletionTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectDeletionTest.java new file mode 100644 index 00000000000..abd50a848cd --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectDeletionTest.java @@ -0,0 +1,234 @@ +/* + * 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.tests.project; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import java.util.Arrays; +import java.util.Collection; +import java.util.Map; +import java.util.stream.Collectors; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.DisableOnDebug; +import org.junit.rules.TestRule; +import org.junit.rules.Timeout; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.ws.Organizations; +import org.sonarqube.ws.WsComponents; +import org.sonarqube.ws.WsProjects; +import org.sonarqube.ws.WsProjects.CreateWsResponse.Project; +import org.sonarqube.ws.WsUsers; +import org.sonarqube.ws.client.GetRequest; +import org.sonarqube.ws.client.WsClient; +import org.sonarqube.ws.client.WsResponse; +import org.sonarqube.ws.client.component.SearchProjectsRequest; +import org.sonarqube.ws.client.project.CreateRequest; +import org.sonarqube.ws.client.project.DeleteRequest; +import org.sonarqube.ws.client.project.SearchWsRequest; +import util.ItUtils; + +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.getComponent; +import static util.ItUtils.projectDir; + +public class ProjectDeletionTest { + + @ClassRule + public static final Orchestrator orchestrator = ProjectSuite.ORCHESTRATOR; + + @Rule + public TestRule safeguard = new DisableOnDebug(Timeout.seconds(300)); + + @Rule + public Tester tester = new Tester(orchestrator).setElasticsearchHttpPort(ProjectSuite.SEARCH_HTTP_PORT); + + @Test + public void delete_project_by_web_service() { + String projectKey = "sample"; + String fileKey = "sample:src/main/xoo/sample/Sample.xoo"; + + analyzeXooSample(); + assertThat(getComponent(orchestrator, projectKey)).isNotNull(); + assertThat(getComponent(orchestrator, fileKey)).isNotNull(); + + // fail to delete a file + ItUtils.expectBadRequestError(() -> executeDeleteRequest(tester.wsClient(), fileKey)); + + // fail if anonymous + ItUtils.expectUnauthorizedError(() -> executeDeleteRequest(tester.asAnonymous().wsClient(), projectKey)); + + // fail if insufficient privilege + WsUsers.CreateWsResponse.User user = tester.users().generate(); + ItUtils.expectForbiddenError(() -> executeDeleteRequest(tester.as(user.getLogin()).wsClient(), projectKey)); + + // succeed to delete if administrator + executeDeleteRequest(tester.wsClient(), projectKey); + assertThat(getComponent(orchestrator, "sample")).isNull(); + assertThat(getComponent(orchestrator, "sample:src/main/xoo/sample/Sample.xoo")).isNull(); + } + + @Test + public void deletion_removes_project_from_search_engines() { + Organizations.Organization organization = tester.organizations().generate(); + Project project1 = createProject(organization, "one", "Foo"); + Project project2 = createProject(organization, "two", "Bar"); + assertThatProjectIsSearchable(organization, "Foo"); + assertThatProjectIsSearchable(organization, "Bar"); + + deleteProject(project1); + assertThatProjectIsNotSearchable(organization, project1.getName()); + assertThatProjectIsSearchable(organization, project2.getName()); + + deleteProject(project2); + assertThatProjectIsNotSearchable(organization, project1.getName()); + assertThatProjectIsNotSearchable(organization, project2.getName()); + } + + @Test + public void indexing_errors_are_recovered_asynchronously_when_deleting_project() throws Exception { + Organizations.Organization organization = tester.organizations().generate(); + Project project = createProject(organization, "one", "Foo"); + + tester.elasticsearch().lockWrites("components"); + tester.elasticsearch().lockWrites("projectmeasures"); + deleteProject(project); + // WS reloads from database the results returned by Elasticsearch. That's + // why the project does not appear in search engine. + // However this test is still useful to verify that WS do not + // fail during this Elasticsearch inconsistency. + assertThatProjectIsNotSearchable(organization, project.getName()); + + tester.elasticsearch().unlockWrites("components"); + tester.elasticsearch().unlockWrites("projectmeasures"); + // TODO verify that recovery daemon successfully updated indices + } + + @Test + public void bulk_deletion_removes_projects_from_search_engines() { + Organizations.Organization organization = tester.organizations().generate(); + Project project1 = createProject(organization, "one", "Foo"); + Project project2 = createProject(organization, "two", "Bar"); + Project project3 = createProject(organization, "three", "Baz"); + + bulkDeleteProjects(organization, project1, project3); + assertThatProjectIsNotSearchable(organization, project1.getName()); + assertThatProjectIsSearchable(organization, project2.getName()); + assertThatProjectIsNotSearchable(organization, project3.getName()); + } + + @Test + public void indexing_errors_are_recovered_asynchronously_when_bulk_deleting_projects() throws Exception { + Organizations.Organization organization = tester.organizations().generate(); + Project project1 = createProject(organization, "one", "Foo"); + Project project2 = createProject(organization, "two", "Bar"); + Project project3 = createProject(organization, "three", "Baz"); + + tester.elasticsearch().lockWrites("components"); + tester.elasticsearch().lockWrites("projectmeasures"); + bulkDeleteProjects(organization, project1, project3); + + // WS reloads from database the results returned by Elasticsearch. That's + // why the project does not appear in search engine. + // However this test is still useful to verify that WS do not + // fail during this Elasticsearch inconsistency. + assertThatProjectIsNotSearchable(organization, project1.getName()); + assertThatProjectIsSearchable(organization, project2.getName()); + assertThatProjectIsNotSearchable(organization, project3.getName()); + + tester.elasticsearch().unlockWrites("components"); + tester.elasticsearch().unlockWrites("projectmeasures"); + // TODO verify that recovery daemon successfully updated indices + } + + private void deleteProject(Project project) { + tester.wsClient().projects().delete(DeleteRequest.builder().setKey(project.getKey()).build()); + } + + private void bulkDeleteProjects(Organizations.Organization organization, Project... projects) { + SearchWsRequest request = SearchWsRequest.builder() + .setOrganization(organization.getKey()) + .setProjects(Arrays.stream(projects).map(Project::getKey).collect(Collectors.toList())) + .build(); + tester.wsClient().projects().bulkDelete(request); + } + + private Project createProject(Organizations.Organization organization, String key, String name) { + CreateRequest createRequest = CreateRequest.builder().setKey(key).setName(name).setOrganization(organization.getKey()).build(); + return tester.wsClient().projects().create(createRequest).getProject(); + } + + private void assertThatProjectIsSearchable(Organizations.Organization organization, String name) { + assertThat(isInProjectsSearch(organization, name)).isTrue(); + assertThat(isInComponentSearchProjects(name)).isTrue(); + assertThat(isInComponentSuggestions(name)).isTrue(); + } + + private void assertThatProjectIsNotSearchable(Organizations.Organization organization, String name) { + assertThat(isInProjectsSearch(organization, name)).isFalse(); + assertThat(isInComponentSearchProjects(name)).isFalse(); + assertThat(isInComponentSuggestions(name)).isFalse(); + } + + /** + * Projects administration page - uses database + */ + private boolean isInProjectsSearch(Organizations.Organization organization, String name) { + WsProjects.SearchWsResponse response = tester.wsClient().projects().search( + SearchWsRequest.builder().setOrganization(organization.getKey()).setQuery(name).setQualifiers(singletonList("TRK")).build()); + return response.getComponentsCount() > 0; + } + + /** + * Projects page - api/components/search_projects - uses ES + DB + */ + private boolean isInComponentSearchProjects(String name) { + WsComponents.SearchProjectsWsResponse response = tester.wsClient().components().searchProjects( + SearchProjectsRequest.builder().setFilter("query=\"" + name + "\"").build()); + return response.getComponentsCount() > 0; + } + + /** + * Top-right search engine - api/components/suggestions - uses ES + DB + */ + private boolean isInComponentSuggestions(String name) { + GetRequest request = new GetRequest("api/components/suggestions").setParam("s", name); + WsResponse response = tester.wsClient().wsConnector().call(request); + Map json = ItUtils.jsonToMap(response.content()); + Collection> results = (Collection>) json.get("results"); + Collection items = results.stream() + .filter(map -> "TRK".equals(map.get("q"))) + .map(map -> (Collection) map.get("items")) + .findFirst() + .orElseThrow(() -> new IllegalStateException("missing field results/[q=TRK]")); + return !items.isEmpty(); + } + + private void analyzeXooSample() { + SonarScanner build = SonarScanner.create(projectDir("shared/xoo-sample")); + orchestrator.executeBuild(build); + } + + private static void executeDeleteRequest(WsClient wsClient, String key) { + wsClient.projects().delete(DeleteRequest.builder().setKey(key).build()); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectFilterTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectFilterTest.java new file mode 100644 index 00000000000..69913864a08 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectFilterTest.java @@ -0,0 +1,304 @@ +/* + * 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.tests.project; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.assertj.core.groups.Tuple; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.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.project.CreateRequest; + +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.newProjectKey; +import static util.ItUtils.projectDir; +import static util.ItUtils.restoreProfile; +import static util.ItUtils.sanitizeTimezones; + +/** + * Tests WS api/components/search_projects + */ +public class ProjectFilterTest { + + @ClassRule + public static Orchestrator orchestrator = ProjectSuite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator); + + private Organization organization; + + @Before + public void setUp() { + organization = tester.organizations().generate(); + restoreProfile(orchestrator, ProjectFilterTest.class.getResource("/projectSearch/SearchProjectsTest/with-many-rules.xml"), organization.getKey()); + } + + @Test + public void filter_projects_by_measure_values() throws Exception { + String projectKey = newProjectKey(); + analyzeProject(projectKey, "shared/xoo-sample"); + + verifyFilterMatches(projectKey, "ncloc > 1"); + verifyFilterMatches(projectKey, "ncloc > 1 and duplicated_lines_density <= 100"); + verifyFilterDoesNotMatch("ncloc <= 1"); + } + + @Test + public void find_projects_with_no_data() throws Exception { + String projectKey = newProjectKey(); + analyzeProject(projectKey, "shared/xoo-sample"); + + verifyFilterMatches(projectKey, "coverage = NO_DATA"); + verifyFilterDoesNotMatch("ncloc = NO_DATA"); + } + + @Test + public void provisioned_projects_should_be_included_to_results() throws Exception { + String projectKey = newProjectKey(); + tester.wsClient().projects().create(CreateRequest.builder().setKey(projectKey).setName(projectKey).setOrganization(organization.getKey()).build()); + + SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organization.getKey()).build()); + + assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly(projectKey); + } + + @Test + public void return_leak_period_date() throws Exception { + tester.settings().setGlobalSettings("sonar.leak.period", "previous_version"); + // This project has a leak period + String projectKey1 = newProjectKey(); + analyzeProject(projectKey1, "shared/xoo-sample", "sonar.projectDate", "2016-12-31"); + analyzeProject(projectKey1, "shared/xoo-sample"); + // This project has only one analysis, so no leak period + String projectKey2 = newProjectKey(); + analyzeProject(projectKey2, "shared/xoo-sample"); + // This project is provisioned, so has no leak period + String projectKey3 = newProjectKey(); + tester.wsClient().projects().create(CreateRequest.builder().setKey(projectKey3).setName(projectKey3).setOrganization(organization.getKey()).build()); + + SearchProjectsWsResponse response = searchProjects( + SearchProjectsRequest.builder().setAdditionalFields(singletonList("leakPeriodDate")).setOrganization(organization.getKey()).build()); + + assertThat(response.getComponentsList()).extracting(Component::getKey, Component::hasLeakPeriodDate) + .containsOnly( + tuple(projectKey1, true), + tuple(projectKey2, false), + tuple(projectKey3, false)); + Component project1 = response.getComponentsList().stream().filter(component -> component.getKey().equals(projectKey1)).findFirst() + .orElseThrow(() -> new IllegalStateException("Project1 is not found")); + assertThat(sanitizeTimezones(project1.getLeakPeriodDate())).isEqualTo("2016-12-31T00:00:00+0000"); + } + + @Test + public void filter_by_text_query() throws IOException { + analyzeProject("project1", "shared/xoo-sample", "sonar.projectName", "apachee"); + analyzeProject("project2", "shared/xoo-sample", "sonar.projectName", "Apache"); + analyzeProject("project3", "shared/xoo-multi-modules-sample", "sonar.projectName", "Apache Foundation"); + analyzeProject("project4", "shared/xoo-multi-modules-sample", "sonar.projectName", "Windows"); + + // Search only by text query + assertThat(searchProjects("query = \"apache\"").getComponentsList()).extracting(Component::getKey).containsExactly("project2", "project3", "project1"); + assertThat(searchProjects("query = \"pAch\"").getComponentsList()).extracting(Component::getKey).containsExactly("project2", "project3", "project1"); + assertThat(searchProjects("query = \"hee\"").getComponentsList()).extracting(Component::getKey).containsExactly("project1"); + assertThat(searchProjects("query = \"project1\"").getComponentsList()).extracting(Component::getKey).containsExactly("project1"); + assertThat(searchProjects("query = \"unknown\"").getComponentsList()).isEmpty(); + + // Search by metric criteria and text query + assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"pAch\" AND ncloc > 50").build()).getComponentsList()) + .extracting(Component::getKey).containsExactly("project3"); + assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"nd\" AND ncloc > 50").build()).getComponentsList()) + .extracting(Component::getKey).containsExactly("project3", "project4"); + assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"unknown\" AND ncloc > 50").build()).getComponentsList()).isEmpty(); + ; + + // Check facets + assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"apache\"").setFacets(singletonList("ncloc")).build()).getFacets().getFacets(0).getValuesList()) + .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount) + .containsOnly(tuple("*-1000.0", 3L), tuple("1000.0-10000.0", 0L), tuple("10000.0-100000.0", 0L), tuple("100000.0-500000.0", 0L), tuple("500000.0-*", 0L)); + assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"unknown\"").setFacets(singletonList("ncloc")).build()).getFacets().getFacets(0) + .getValuesList()).extracting(Common.FacetValue::getVal, Common.FacetValue::getCount) + .containsOnly(tuple("*-1000.0", 0L), tuple("1000.0-10000.0", 0L), tuple("10000.0-100000.0", 0L), tuple("100000.0-500000.0", 0L), tuple("500000.0-*", 0L)); + } + + @Test + public void should_return_facets() throws Exception { + analyzeProject(newProjectKey(), "shared/xoo-sample"); + analyzeProject(newProjectKey(), "shared/xoo-multi-modules-sample"); + + SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organization.getKey()).setFacets(asList( + "alert_status", + "coverage", + "duplicated_lines_density", + "languages", + "ncloc", + "reliability_rating", + "security_rating", + "sqale_rating", + "tags")).build()); + + checkFacet(response, "alert_status", + tuple("OK", 2L), + tuple("WARN", 0L), + tuple("ERROR", 0L)); + checkFacet(response, "coverage", + tuple("NO_DATA", 2L), + tuple("*-30.0", 0L), + tuple("30.0-50.0", 0L), + tuple("50.0-70.0", 0L), + tuple("70.0-80.0", 0L), + tuple("80.0-*", 0L)); + checkFacet(response, "duplicated_lines_density", + tuple("NO_DATA", 0L), + tuple("*-3.0", 2L), + tuple("3.0-5.0", 0L), + tuple("5.0-10.0", 0L), + tuple("10.0-20.0", 0L), + tuple("20.0-*", 0L)); + checkFacet(response, "languages", + tuple("xoo", 2L)); + checkFacet(response, "ncloc", + tuple("*-1000.0", 2L), + tuple("1000.0-10000.0", 0L), + tuple("10000.0-100000.0", 0L), + tuple("100000.0-500000.0", 0L), + tuple("500000.0-*", 0L)); + checkFacet(response, "reliability_rating", + tuple("1", 2L), + tuple("2", 0L), + tuple("3", 0L), + tuple("4", 0L), + tuple("5", 0L)); + checkFacet(response, "security_rating", + tuple("1", 2L), + tuple("2", 0L), + tuple("3", 0L), + tuple("4", 0L), + tuple("5", 0L)); + checkFacet(response, "sqale_rating", + tuple("1", 0L), + tuple("2", 0L), + tuple("3", 0L), + tuple("4", 2L), + tuple("5", 0L)); + checkFacet(response, "tags"); + } + + @Test + public void should_return_facets_on_leak() throws Exception { + tester.settings().setGlobalSettings("sonar.leak.period", "previous_version"); + // This project has no duplication on new code + String projectKey1 = newProjectKey(); + analyzeProject(projectKey1, "shared/xoo-sample", "sonar.projectDate", "2016-12-31"); + analyzeProject(projectKey1, "shared/xoo-sample"); + // This project has 0% duplication on new code + String projectKey2 = newProjectKey(); + analyzeProject(projectKey2, "projectSearch/xoo-history-v1", "sonar.projectDate", "2016-12-31"); + analyzeProject(projectKey2, "projectSearch/xoo-history-v2"); + + 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", + tuple("1", 2L), + tuple("2", 0L), + tuple("3", 0L), + tuple("4", 0L), + tuple("5", 0L)); + checkFacet(response, "new_security_rating", + tuple("1", 2L), + tuple("2", 0L), + tuple("3", 0L), + tuple("4", 0L), + tuple("5", 0L)); + checkFacet(response, "new_maintainability_rating", + tuple("1", 2L), + tuple("2", 0L), + tuple("3", 0L), + tuple("4", 0L), + tuple("5", 0L)); + checkFacet(response, "new_coverage", + tuple("NO_DATA", 2L), + tuple("*-30.0", 0L), + tuple("30.0-50.0", 0L), + tuple("50.0-70.0", 0L), + tuple("70.0-80.0", 0L), + tuple("80.0-*", 0L)); + checkFacet(response, "new_duplicated_lines_density", + tuple("NO_DATA", 1L), + tuple("*-3.0", 1L), + tuple("3.0-5.0", 0L), + tuple("5.0-10.0", 0L), + tuple("10.0-20.0", 0L), + tuple("20.0-*", 0L)); + checkFacet(response, "new_lines", + tuple("*-1000.0", 1L), + tuple("1000.0-10000.0", 0L), + tuple("10000.0-100000.0", 0L), + tuple("100000.0-500000.0", 0L), + tuple("500000.0-*", 0L)); + } + + private void checkFacet(SearchProjectsWsResponse response, String facetKey, Tuple... values) { + Common.Facet facet = response.getFacets().getFacetsList().stream().filter(f -> f.getProperty().equals(facetKey)).findAny().get(); + assertThat(facet.getValuesList()).extracting(Common.FacetValue::getVal, Common.FacetValue::getCount).containsExactlyInAnyOrder(values); + } + + private void analyzeProject(String projectKey, String relativePath, String... properties) { + List keyValueProperties = new ArrayList<>(asList( + "sonar.projectKey", projectKey, + "sonar.organization", organization.getKey(), + "sonar.profile", "with-many-rules", + "sonar.login", "admin", "sonar.password", "admin", + "sonar.scm.disabled", "false")); + orchestrator.executeBuild(SonarScanner.create(projectDir(relativePath), concat(keyValueProperties.toArray(new String[0]), properties))); + } + + private SearchProjectsWsResponse searchProjects(String filter) throws IOException { + return searchProjects(SearchProjectsRequest.builder().setOrganization(organization.getKey()).setFilter(filter).build()); + } + + private SearchProjectsWsResponse searchProjects(SearchProjectsRequest request) throws IOException { + return tester.wsClient().components().searchProjects(request); + } + + private void verifyFilterMatches(String projectKey, String filter) throws IOException { + assertThat(searchProjects(filter).getComponentsList()).extracting(Component::getKey).containsOnly(projectKey); + } + + private void verifyFilterDoesNotMatch(String filter) throws IOException { + assertThat(searchProjects(filter).getComponentsCount()).isZero(); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectKeyUpdateTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectKeyUpdateTest.java new file mode 100644 index 00000000000..8a2c14f3806 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectKeyUpdateTest.java @@ -0,0 +1,284 @@ +/* + * 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.tests.project; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import javax.annotation.CheckForNull; +import org.junit.After; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.DisableOnDebug; +import org.junit.rules.TestRule; +import org.junit.rules.Timeout; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.ws.Organizations; +import org.sonarqube.ws.WsComponents; +import org.sonarqube.ws.WsProjects; +import org.sonarqube.ws.client.GetRequest; +import org.sonarqube.ws.client.WsResponse; +import org.sonarqube.ws.client.component.SearchProjectsRequest; +import org.sonarqube.ws.client.component.ShowWsRequest; +import org.sonarqube.ws.client.project.BulkUpdateKeyWsRequest; +import org.sonarqube.ws.client.project.CreateRequest; +import org.sonarqube.ws.client.project.UpdateKeyWsRequest; +import util.ItUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.projectDir; + +public class ProjectKeyUpdateTest { + + private static final String PROJECT_KEY = "sample"; + + @ClassRule + public static final Orchestrator orchestrator = ProjectSuite.ORCHESTRATOR; + + @Rule + public TestRule safeguard = new DisableOnDebug(Timeout.seconds(300)); + + @Rule + public Tester tester = new Tester(orchestrator).setElasticsearchHttpPort(ProjectSuite.SEARCH_HTTP_PORT); + + @After + public void tearDown() throws Exception { + unlockWritesOnProjectIndices(); + } + + @Test + public void update_key() { + analyzeXooSample(); + String newProjectKey = "another_project_key"; + WsComponents.Component project = tester.wsClient().components().show(new ShowWsRequest().setKey(PROJECT_KEY)).getComponent(); + assertThat(project.getKey()).isEqualTo(PROJECT_KEY); + + tester.wsClient().projects().updateKey(UpdateKeyWsRequest.builder() + .setKey(PROJECT_KEY) + .setNewKey(newProjectKey) + .build()); + + assertThat(tester.wsClient().components().show(new ShowWsRequest().setId(project.getId())).getComponent().getKey()).isEqualTo(newProjectKey); + } + + @Test + public void bulk_update_key() { + analyzeXooSample(); + String newProjectKey = "another_project_key"; + WsComponents.Component project = tester.wsClient().components().show(new ShowWsRequest().setKey(PROJECT_KEY)).getComponent(); + assertThat(project.getKey()).isEqualTo(PROJECT_KEY); + + WsProjects.BulkUpdateKeyWsResponse result = tester.wsClient().projects().bulkUpdateKey(BulkUpdateKeyWsRequest.builder() + .setKey(PROJECT_KEY) + .setFrom(PROJECT_KEY) + .setTo(newProjectKey) + .build()); + + assertThat(tester.wsClient().components().show(new ShowWsRequest().setId(project.getId())).getComponent().getKey()).isEqualTo(newProjectKey); + assertThat(result.getKeysCount()).isEqualTo(1); + assertThat(result.getKeys(0)) + .extracting(WsProjects.BulkUpdateKeyWsResponse.Key::getKey, WsProjects.BulkUpdateKeyWsResponse.Key::getNewKey, WsProjects.BulkUpdateKeyWsResponse.Key::getDuplicate) + .containsOnlyOnce(PROJECT_KEY, newProjectKey, false); + } + + @Test + public void update_key_of_provisioned_project() { + Organizations.Organization organization = tester.organizations().generate(); + WsProjects.CreateWsResponse.Project project = createProject(organization, "one", "Foo"); + + updateKey(project, "two"); + + assertThat(isProjectInDatabase("one")).isFalse(); + assertThat(isProjectInDatabase("two")).isTrue(); + assertThat(isComponentInDatabase("one")).isFalse(); + assertThat(isComponentInDatabase("two")).isTrue(); + assertThat(keyInComponentSearchProjects("Foo")).isEqualTo("two"); + assertThat(keysInComponentSuggestions("Foo")).containsExactly("two"); + } + + @Test + public void recover_indexing_errors_when_updating_key_of_provisioned_project() throws Exception { + Organizations.Organization organization = tester.organizations().generate(); + WsProjects.CreateWsResponse.Project project = createProject(organization, "one", "Foo"); + + lockWritesOnProjectIndices(); + + updateKey(project, "two"); + + assertThat(isProjectInDatabase("one")).isFalse(); + + // WS gets the list of projects from ES then reloads projects from db. + // That's why keys in WS responses are correct. + assertThat(isProjectInDatabase("one")).isFalse(); + assertThat(isProjectInDatabase("two")).isTrue(); + assertThat(keyInComponentSearchProjects("Foo")).isEqualTo("two"); + assertThat(keysInComponentSuggestions("Foo")).containsExactly("two"); + + // however searching by key is inconsistent + assertThat(keyInComponentSearchProjects("one")).isEqualTo("two"); + assertThat(keysInComponentSuggestions("one")).containsExactly("two"); + assertThat(keyInComponentSearchProjects("two")).isNull(); + assertThat(keysInComponentSuggestions("two")).isEmpty(); + + unlockWritesOnProjectIndices(); + + boolean recovered = false; + while (!recovered) { + // recovery daemon runs every second, see Category6Suite + Thread.sleep(1_000L); + recovered = keyInComponentSearchProjects("one") == null && + keysInComponentSuggestions("one").isEmpty() && + "two".equals(keyInComponentSearchProjects("two")) && + keysInComponentSuggestions("two").contains("two"); + } + } + + @Test + public void update_key_of_module() { + Organizations.Organization organization = tester.organizations().generate(); + orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-multi-modules-sample"), + "sonar.organization", organization.getKey(), + "sonar.login", "admin", "sonar.password", "admin")); + + String initialKey = "com.sonarsource.it.samples:multi-modules-sample:module_a"; + String newKey = "com.sonarsource.it.samples:multi-modules-sample:module_c"; + + updateKey(initialKey, newKey); + + assertThat(isComponentInDatabase(initialKey)).isFalse(); + assertThat(isComponentInDatabase(newKey)).isTrue(); + // suggestions engine ignores one-character words, so we can't search for "Module A" + assertThat(keysInComponentSuggestions("Module")) + .contains(newKey) + .doesNotContain(initialKey); + assertThat(keysInComponentSuggestions(newKey)) + .contains(newKey) + .doesNotContain(initialKey); + assertThat(keysInComponentSuggestions(initialKey)).isEmpty(); + + } + + @Test + public void recover_indexing_errors_when_updating_key_of_module() throws Exception { + Organizations.Organization organization = tester.organizations().generate(); + orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-multi-modules-sample"), + "sonar.organization", organization.getKey(), + "sonar.login", "admin", "sonar.password", "admin")); + + String initialKey = "com.sonarsource.it.samples:multi-modules-sample:module_a"; + String newKey = "com.sonarsource.it.samples:multi-modules-sample:module_c"; + + lockWritesOnProjectIndices(); + updateKey(initialKey, newKey); + + // api/components/search loads keys from db, so results are consistent + assertThat(isComponentInDatabase(initialKey)).isFalse(); + assertThat(isComponentInDatabase(newKey)).isTrue(); + + // key in result of suggestion engine is loaded from db, so results are ok when searching for unchanged name + assertThat(keysInComponentSuggestions("Module")) + .contains(newKey) + .doesNotContain(initialKey); + + // but searching for new key does not work + assertThat(keysInComponentSuggestions(newKey)).isEmpty(); + assertThat(keysInComponentSuggestions(initialKey)) + .isNotEmpty() + .contains(newKey /* the returned key is loaded from db, so it's correct */); + + unlockWritesOnProjectIndices(); + + boolean recovered = false; + while (!recovered) { + // recovery daemon runs every second, see Category6Suite + Thread.sleep(1_000L); + recovered = keysInComponentSuggestions(newKey).contains(newKey) && keysInComponentSuggestions(initialKey).isEmpty(); + } + + } + + private void lockWritesOnProjectIndices() throws Exception { + tester.elasticsearch().lockWrites("components"); + tester.elasticsearch().lockWrites("projectmeasures"); + } + + private void unlockWritesOnProjectIndices() throws Exception { + tester.elasticsearch().unlockWrites("components"); + tester.elasticsearch().unlockWrites("projectmeasures"); + } + + private void updateKey(WsProjects.CreateWsResponse.Project project, String newKey) { + tester.wsClient().projects().updateKey(UpdateKeyWsRequest.builder().setKey(project.getKey()).setNewKey(newKey).build()); + } + + private void updateKey(String initialKey, String newKey) { + tester.wsClient().projects().updateKey(UpdateKeyWsRequest.builder().setKey(initialKey).setNewKey(newKey).build()); + } + + private WsProjects.CreateWsResponse.Project createProject(Organizations.Organization organization, String key, String name) { + CreateRequest createRequest = CreateRequest.builder().setKey(key).setName(name).setOrganization(organization.getKey()).build(); + return tester.wsClient().projects().create(createRequest).getProject(); + } + + private boolean isProjectInDatabase(String projectKey) { + return orchestrator.getDatabase().countSql(String.format("select count(id) from projects where qualifier='TRK' and kee='%s'", projectKey)) == 1L; + } + + private boolean isComponentInDatabase(String componentKey) { + return orchestrator.getDatabase().countSql(String.format("select count(id) from projects where kee='%s'", componentKey)) == 1L; + } + + /** + * Projects page - api/components/search_projects - uses ES + DB + */ + @CheckForNull + private String keyInComponentSearchProjects(String name) { + WsComponents.SearchProjectsWsResponse response = tester.wsClient().components().searchProjects( + SearchProjectsRequest.builder().setFilter("query=\"" + name + "\"").build()); + if (response.getComponentsCount() > 0) { + return response.getComponents(0).getKey(); + } + return null; + } + + /** + * Top-right search engine - api/components/suggestions - uses ES + DB + */ + private List keysInComponentSuggestions(String name) { + GetRequest request = new GetRequest("api/components/suggestions").setParam("s", name); + WsResponse response = tester.wsClient().wsConnector().call(request); + Map json = ItUtils.jsonToMap(response.content()); + Collection> results = (Collection>) json.get("results"); + return results.stream() + .filter(map -> "TRK".equals(map.get("q")) || "BRC".equals(map.get("q"))) + .flatMap(map -> ((Collection>) map.get("items")).stream()) + .map(map -> (String) map.get("key")) + .collect(Collectors.toList()); + } + + private void analyzeXooSample() { + SonarScanner build = SonarScanner.create(projectDir("shared/xoo-sample")); + orchestrator.executeBuild(build); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectLeakPageTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectLeakPageTest.java new file mode 100644 index 00000000000..1b0e145accd --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectLeakPageTest.java @@ -0,0 +1,105 @@ +/* + * 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.tests.project; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.qa.util.pageobjects.projects.ProjectsPage; +import org.sonarqube.ws.Organizations.Organization; + +import static com.codeborne.selenide.WebDriverRunner.url; +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.newProjectKey; +import static util.ItUtils.projectDir; +import static util.ItUtils.restoreProfile; + +public class ProjectLeakPageTest { + + @ClassRule + public static Orchestrator orchestrator = ProjectSuite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator); + + private Organization organization; + + @Before + public void setUp() { + tester.settings().setGlobalSettings("sonar.leak.period", "previous_version"); + organization = tester.organizations().generate(); + restoreProfile(orchestrator, ProjectLeakPageTest.class.getResource("/projectSearch/SearchProjectsTest/with-many-rules.xml"), organization.getKey()); + } + + @Test + public void should_display_leak_information() { + // This project has 0% duplication on new code + String projectKey2 = newProjectKey(); + analyzeProject(projectKey2, "projectSearch/xoo-history-v1", "2016-12-31"); + analyzeProject(projectKey2, "projectSearch/xoo-history-v2", null); + + // This project has no duplication on new code + String projectKey1 = newProjectKey(); + analyzeProject(projectKey1, "shared/xoo-sample", "2016-12-31"); + analyzeProject(projectKey1, "shared/xoo-sample", null); + + // Check the facets and project cards + ProjectsPage page = tester.openBrowser().openProjects(organization.getKey()); + page.changePerspective("Leak"); + assertThat(url()).endsWith("/projects?view=leak"); + page.shouldHaveTotal(2); + page.getProjectByKey(projectKey2) + .shouldHaveMeasure("new_reliability_rating", "0A") + .shouldHaveMeasure("new_security_rating", "0A") + .shouldHaveMeasure("new_maintainability_rating", "17A") + .shouldHaveMeasure("new_coverage", "–") + .shouldHaveMeasure("new_duplicated_lines_density", "0.0%") + .shouldHaveMeasure("new_lines", "17"); + page.getFacetByProperty("new_duplications") + .shouldHaveValue("1", "1") + .shouldHaveValue("2", "0") + .shouldHaveValue("3", "0") + .shouldHaveValue("4", "0") + .shouldHaveValue("5", "0") + .shouldHaveValue("6", "1"); + } + + private void analyzeProject(String projectKey, String relativePath, @Nullable String analysisDate) { + List keyValueProperties = new ArrayList<>(asList( + "sonar.projectKey", projectKey, + "sonar.organization", organization.getKey(), + "sonar.profile", "with-many-rules", + "sonar.login", "admin", "sonar.password", "admin", + "sonar.scm.disabled", "false")); + if (analysisDate != null) { + keyValueProperties.add("sonar.projectDate"); + keyValueProperties.add(analysisDate); + } + orchestrator.executeBuild(SonarScanner.create(projectDir(relativePath), keyValueProperties.toArray(new String[0]))); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectLinksTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectLinksTest.java new file mode 100644 index 00000000000..4efc15da144 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectLinksTest.java @@ -0,0 +1,155 @@ +/* + * 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.tests.project; + +import com.codeborne.selenide.Condition; +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import java.util.List; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.qa.util.pageobjects.ProjectLinkItem; +import org.sonarqube.qa.util.pageobjects.ProjectLinksPage; +import org.sonarqube.ws.WsProjectLinks.CreateWsResponse; +import org.sonarqube.ws.client.projectlinks.CreateWsRequest; +import org.sonarqube.ws.client.projectlinks.DeleteWsRequest; + +import static com.codeborne.selenide.Condition.text; +import static com.codeborne.selenide.Selenide.$; +import static util.ItUtils.projectDir; + +public class ProjectLinksTest { + + @ClassRule + public static Orchestrator orchestrator = ProjectSuite.ORCHESTRATOR; + + private static Tester tester = new Tester(orchestrator); + + @ClassRule + public static RuleChain ruleChain = RuleChain.outerRule(orchestrator).around(tester); + + private long customLinkId; + private String adminUser; + + @BeforeClass + public static void setUp() { + orchestrator.executeBuild( + SonarScanner.create(projectDir("shared/xoo-sample")) + .setProperty("sonar.links.homepage", "http://example.com")); + } + + @Before + public void prepare() { + customLinkId = Long.parseLong(createCustomLink().getLink().getId()); + adminUser = tester.users().generateAdministratorOnDefaultOrganization().getLogin(); + } + + @After + public void clean() { + deleteLink(customLinkId); + } + + @Test + public void should_list_links() { + ProjectLinksPage page = openLinksPage(); + + page.getLinks().shouldHaveSize(2); + + List links = page.getLinksAsItems(); + ProjectLinkItem homepageLink = links.get(0); + ProjectLinkItem customLink = links.get(1); + + homepageLink.getName().should(text("Home")); + homepageLink.getType().should(text("sonar.links.homepage")); + homepageLink.getUrl().should(text("http://example.com")); + homepageLink.getDeleteButton().shouldNot(Condition.exist); + + customLink.getName().should(text("Custom")); + customLink.getType().shouldNot(Condition.exist); + customLink.getUrl().should(text("http://example.org/custom")); + customLink.getDeleteButton().shouldBe(Condition.visible); + } + + @Test + public void should_create_link() { + ProjectLinksPage page = openLinksPage(); + + page.getLinks().shouldHaveSize(2); + + $("#create-project-link").click(); + $("#create-link-name").setValue("Test"); + $("#create-link-url").setValue("http://example.com/test"); + $("#create-link-confirm").click(); + + page.getLinks().shouldHaveSize(3); + + ProjectLinkItem testLink = page.getLinksAsItems().get(2); + + testLink.getName().should(text("Test")); + testLink.getType().shouldNot(Condition.exist); + testLink.getUrl().should(text("http://example.com/test")); + testLink.getDeleteButton().shouldBe(Condition.visible); + } + + @Test + public void should_delete_link() { + ProjectLinksPage page = openLinksPage(); + + page.getLinks().shouldHaveSize(2); + + List links = page.getLinksAsItems(); + ProjectLinkItem customLink = links.get(1); + + customLink.getDeleteButton().click(); + $("#delete-link-confirm") + .shouldBe(Condition.visible) + .click(); + + page.getLinks().shouldHaveSize(1); + } + + private CreateWsResponse createCustomLink() { + return tester.wsClient().projectLinks().create(new CreateWsRequest() + .setProjectKey("sample") + .setName("Custom") + .setUrl("http://example.org/custom")); + } + + private void deleteLink(long id) { + try { + tester.wsClient().projectLinks().delete(new DeleteWsRequest().setId(id)); + } catch (Exception e) { + // fail silently + } + } + + private ProjectLinksPage openLinksPage() { + return tester + .openBrowser() + .logIn() + .submitCredentials(adminUser, adminUser) + .openProjectLinks("sample"); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectListTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectListTest.java new file mode 100644 index 00000000000..55b1e4ee580 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectListTest.java @@ -0,0 +1,57 @@ +/* + * 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.tests.project; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import java.io.IOException; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.ws.client.GetRequest; + +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.projectDir; + +public class ProjectListTest { + + @ClassRule + public static final Orchestrator orchestrator = ProjectSuite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator); + + /** + * SONAR-3105 + */ + @Test + public void test_projects_index_ws() throws IOException { + SonarScanner build = SonarScanner.create(projectDir("shared/xoo-sample")); + orchestrator.executeBuild(build); + + String json = tester.wsClient().wsConnector().call(new GetRequest("/api/projects/index?key=sample&versions=true")).content(); + + assertThat(json).doesNotContain("error"); + assertThat(json).contains("sample"); + } + + +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectProvisioningTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectProvisioningTest.java new file mode 100644 index 00000000000..9f9b1a8b7a4 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectProvisioningTest.java @@ -0,0 +1,132 @@ +/* + * 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.tests.project; + +import com.sonar.orchestrator.Orchestrator; +import java.util.Collection; +import java.util.Map; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.DisableOnDebug; +import org.junit.rules.TestRule; +import org.junit.rules.Timeout; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.ws.Organizations; +import org.sonarqube.ws.WsComponents; +import org.sonarqube.ws.WsProjects; +import org.sonarqube.ws.WsProjects.CreateWsResponse.Project; +import org.sonarqube.ws.client.GetRequest; +import org.sonarqube.ws.client.WsResponse; +import org.sonarqube.ws.client.component.SearchProjectsRequest; +import org.sonarqube.ws.client.project.CreateRequest; +import org.sonarqube.ws.client.project.SearchWsRequest; +import util.ItUtils; + +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; + +public class ProjectProvisioningTest { + + @ClassRule + public static final Orchestrator orchestrator = ProjectSuite.ORCHESTRATOR; + + @Rule + public TestRule safeguard = new DisableOnDebug(Timeout.seconds(300)); + + @Rule + public Tester tester = new Tester(orchestrator).setElasticsearchHttpPort(ProjectSuite.SEARCH_HTTP_PORT); + + @Test + public void provisioned_project_is_available_in_search_engines() { + Organizations.Organization organization = tester.organizations().generate(); + + createProject(organization, "one", "Foo"); + + assertThat(isInProjectsSearch(organization, "Foo")).isTrue(); + assertThat(isInComponentSearchProjects("Foo")).isTrue(); + assertThat(isInComponentSuggestions("Foo")).isTrue(); + } + + @Test + public void indexing_errors_are_recovered_asynchronously_when_provisioning_project() throws Exception { + tester.elasticsearch().lockWrites("components"); + tester.elasticsearch().lockWrites("projectmeasures"); + + Organizations.Organization organization = tester.organizations().generate(); + Project project = createProject(organization, "one", "Foo"); + + // no ES requests but only DB + assertThat(isInProjectsSearch(organization, project.getName())).isTrue(); + + // these WS use ES so they are temporarily inconsistent + assertThat(isInComponentSearchProjects(project.getName())).isFalse(); + assertThat(isInComponentSuggestions(project.getName())).isFalse(); + + tester.elasticsearch().unlockWrites("components"); + tester.elasticsearch().unlockWrites("projectmeasures"); + + boolean found = false; + while (!found) { + // recovery daemon runs every second (see Category6Suite) + Thread.sleep(1_000L); + found = isInComponentSearchProjects(project.getName()) && isInComponentSuggestions(project.getName()); + } + } + + private Project createProject(Organizations.Organization organization, String key, String name) { + CreateRequest createRequest = CreateRequest.builder().setKey(key).setName(name).setOrganization(organization.getKey()).build(); + return tester.wsClient().projects().create(createRequest).getProject(); + } + + /** + * Projects administration page - uses database + */ + private boolean isInProjectsSearch(Organizations.Organization organization, String name) { + WsProjects.SearchWsResponse response = tester.wsClient().projects().search( + SearchWsRequest.builder().setOrganization(organization.getKey()).setQuery(name).setQualifiers(singletonList("TRK")).build()); + return response.getComponentsCount() > 0; + } + + /** + * Projects page - api/components/search_projects - uses ES + DB + */ + private boolean isInComponentSearchProjects(String name) { + WsComponents.SearchProjectsWsResponse response = tester.wsClient().components().searchProjects( + SearchProjectsRequest.builder().setFilter("query=\"" + name + "\"").build()); + return response.getComponentsCount() > 0; + } + + /** + * Top-right search engine - api/components/suggestions - uses ES + DB + */ + private boolean isInComponentSuggestions(String name) { + GetRequest request = new GetRequest("api/components/suggestions").setParam("s", name); + WsResponse response = tester.wsClient().wsConnector().call(request); + Map json = ItUtils.jsonToMap(response.content()); + Collection> results = (Collection>) json.get("results"); + Collection items = results.stream() + .filter(map -> "TRK".equals(map.get("q"))) + .map(map -> (Collection) map.get("items")) + .findFirst() + .orElseThrow(() -> new IllegalStateException("missing field results/[q=TRK]")); + return !items.isEmpty(); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectSearchTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectSearchTest.java new file mode 100644 index 00000000000..69cc1a69cfd --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectSearchTest.java @@ -0,0 +1,127 @@ +/* + * 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.tests.project; + +import com.sonar.orchestrator.Orchestrator; +import java.util.Date; +import org.apache.commons.lang.time.DateUtils; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.ws.Organizations; +import org.sonarqube.ws.WsProjects.CreateWsResponse; +import org.sonarqube.ws.WsProjects.SearchWsResponse; +import org.sonarqube.ws.WsProjects.SearchWsResponse.Component; +import org.sonarqube.ws.client.GetRequest; +import org.sonarqube.ws.client.project.SearchWsRequest; + +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.formatDate; +import static util.ItUtils.runProjectAnalysis; + +public class ProjectSearchTest { + + @ClassRule + public static Orchestrator orchestrator = ProjectSuite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator); + + @Test + public void search_old_projects() { + Organizations.Organization organization = tester.organizations().generate(); + CreateWsResponse.Project oldProject = tester.projects().generate(organization); + CreateWsResponse.Project recentProject = tester.projects().generate(organization); + Date now = new Date(); + Date oneYearAgo = DateUtils.addDays(now, -365); + Date moreThanOneYearAgo = DateUtils.addDays(now, -366); + + analyzeProject(oldProject.getKey(), moreThanOneYearAgo, organization.getKey()); + analyzeProject(recentProject.getKey(), now, organization.getKey()); + + SearchWsResponse result = tester.wsClient().projects().search(SearchWsRequest.builder() + .setOrganization(organization.getKey()) + .setQualifiers(singletonList("TRK")) + .setAnalyzedBefore(formatDate(oneYearAgo)).build()); + + assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(oldProject.getKey()); + } + + @Test + public void search_on_key_query_partial_match_case_insensitive() { + Organizations.Organization organization = tester.organizations().generate(); + CreateWsResponse.Project lowerCaseProject = tester.projects().generate(organization, p -> p.setKey("project-key")); + CreateWsResponse.Project upperCaseProject = tester.projects().generate(organization, p -> p.setKey("PROJECT-KEY")); + CreateWsResponse.Project anotherProject = tester.projects().generate(organization, p -> p.setKey("another-project")); + + analyzeProject(lowerCaseProject.getKey(), organization.getKey()); + analyzeProject(upperCaseProject.getKey(), organization.getKey()); + analyzeProject(anotherProject.getKey(), organization.getKey()); + + SearchWsResponse result = tester.wsClient().projects().search(SearchWsRequest.builder() + .setOrganization(organization.getKey()) + .setQualifiers(singletonList("TRK")) + .setQuery("JeCt-K") + .build()); + + assertThat(result.getComponentsList()).extracting(Component::getKey) + .containsExactlyInAnyOrder(lowerCaseProject.getKey(), upperCaseProject.getKey()) + .doesNotContain(anotherProject.getKey()); + } + + @Test + public void search_provisioned_projects() { + Organizations.Organization organization = tester.organizations().generate(); + CreateWsResponse.Project firstProvisionedProject = tester.projects().generate(organization); + CreateWsResponse.Project secondProvisionedProject = tester.projects().generate(organization); + CreateWsResponse.Project analyzedProject = tester.projects().generate(organization); + + analyzeProject(analyzedProject.getKey(), organization.getKey()); + + String result = tester.wsClient().wsConnector().call(new GetRequest("api/projects/provisioned") + .setParam("organization", organization.getKey())) + .failIfNotSuccessful().content(); + SearchWsResponse searchResult = tester.wsClient().projects().search(SearchWsRequest.builder() + .setQualifiers(singletonList("TRK")) + .setOrganization(organization.getKey()) + .setOnProvisionedOnly(true).build()); + + assertThat(result).contains(firstProvisionedProject.getKey(), secondProvisionedProject.getKey()).doesNotContain(analyzedProject.getKey()); + assertThat(searchResult.getComponentsList()).extracting(Component::getKey) + .containsOnly(firstProvisionedProject.getKey(), secondProvisionedProject.getKey()) + .doesNotContain(analyzedProject.getKey()); + } + + private void analyzeProject(String projectKey, Date analysisDate, String organizationKey) { + runProjectAnalysis(orchestrator, "shared/xoo-sample", + "sonar.organization", organizationKey, + "sonar.projectKey", projectKey, + "sonar.projectDate", formatDate(analysisDate), + "sonar.login", "admin", + "sonar.password", "admin"); + } + + private void analyzeProject(String projectKey, String organizationKey) { + analyzeProject(projectKey, new Date(), organizationKey); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectSuite.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectSuite.java new file mode 100644 index 00000000000..58dd29c9289 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectSuite.java @@ -0,0 +1,63 @@ +/* + * 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.tests.project; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.util.NetworkUtils; +import java.net.InetAddress; +import org.junit.ClassRule; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +import static util.ItUtils.xooPlugin; + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + ProjectBulkDeletionTest.class, + ProjectBulkDeletionPageTest.class, + ProjectDeletionTest.class, + ProjectFilterTest.class, + ProjectKeyUpdateTest.class, + ProjectLeakPageTest.class, + ProjectLinksTest.class, + ProjectListTest.class, + ProjectsPageTest.class, + ProjectProvisioningTest.class, + ProjectSearchTest.class, + ProjectVisibilityPageTest.class +}) +public class ProjectSuite { + public static final int SEARCH_HTTP_PORT = NetworkUtils.getNextAvailablePort(InetAddress.getLoopbackAddress()); + + @ClassRule + public static final Orchestrator ORCHESTRATOR = Orchestrator.builderEnv() + // reduce memory for Elasticsearch + .setServerProperty("sonar.search.javaOpts", "-Xms128m -Xmx128m") + // for ES resiliency tests + .setServerProperty("sonar.search.httpPort", "" + SEARCH_HTTP_PORT) + .setServerProperty("sonar.search.recovery.delayInMs", "1000") + .setServerProperty("sonar.search.recovery.minAgeInMs", "3000") + .setServerProperty("sonar.notifications.delay", "1") + + .addPlugin(xooPlugin()) + + .build(); + +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectVisibilityPageTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectVisibilityPageTest.java new file mode 100644 index 00000000000..0c2c745f9f6 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectVisibilityPageTest.java @@ -0,0 +1,95 @@ +/* + * 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.tests.project; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.qa.util.pageobjects.ProjectsManagementPage; +import org.sonarqube.ws.WsComponents; +import org.sonarqube.ws.client.component.SearchProjectsRequest; +import org.sonarqube.ws.client.permission.RemoveGroupWsRequest; +import org.sonarqube.ws.client.project.UpdateVisibilityRequest; + +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.newAdminWsClient; +import static util.ItUtils.projectDir; + +public class ProjectVisibilityPageTest { + + @ClassRule + public static Orchestrator orchestrator = ProjectSuite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator); + + private String adminUser; + + @Before + public void setUp() { + adminUser = tester.users().generateAdministratorOnDefaultOrganization().getLogin(); + } + + @Test + public void return_all_projects_even_when_no_permission() throws Exception { + orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample")).setProperties("sonar.projectKey", "sample1")); + orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample")).setProperties("sonar.projectKey", "sample2")); + tester.wsClient().projects().updateVisibility(UpdateVisibilityRequest.builder().setProject("sample2").setVisibility("private").build()); + // Remove 'Admin' permission for admin group on project 2 -> No one can access or admin this project, expect System Admin + tester.wsClient().permissions().removeGroup(new RemoveGroupWsRequest().setProjectKey("sample2").setGroupName("sonar-administrators").setPermission("admin")); + + tester.openBrowser().logIn().submitCredentials(adminUser) + .openProjectsManagement("default-organization") + .shouldHaveProject("sample1") + .shouldHaveProject("sample2"); + } + + @Test + public void create_public_project() { + createProjectAndVerify("public"); + } + + @Test + public void create_private_project() { + createProjectAndVerify("private"); + } + + private void createProjectAndVerify(String visibility) { + ProjectsManagementPage page = tester.openBrowser().logIn() + .submitCredentials(adminUser, adminUser) + .openProjectsManagement("default-organization"); + page + .shouldHaveProjectsCount(0) + .createProject("foo", "foo", visibility) + .shouldHaveProjectsCount(1); + + WsComponents.SearchProjectsWsResponse response = newAdminWsClient(orchestrator).components().searchProjects( + SearchProjectsRequest.builder().build()); + assertThat(response.getComponentsCount()).isEqualTo(1); + assertThat(response.getComponents(0).getKey()).isEqualTo("foo"); + assertThat(response.getComponents(0).getName()).isEqualTo("foo"); + assertThat(response.getComponents(0).getVisibility()).isEqualTo(visibility); + } + +} diff --git a/tests/src/test/java/org/sonarqube/tests/project/ProjectsPageTest.java b/tests/src/test/java/org/sonarqube/tests/project/ProjectsPageTest.java new file mode 100644 index 00000000000..d0008cc0bd6 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/project/ProjectsPageTest.java @@ -0,0 +1,209 @@ +/* + * 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.tests.project; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.qa.util.pageobjects.Navigation; +import org.sonarqube.qa.util.pageobjects.projects.ProjectsPage; +import org.sonarqube.ws.WsUsers; +import org.sonarqube.ws.client.PostRequest; +import org.sonarqube.ws.client.WsClient; + +import static com.codeborne.selenide.Selenide.clearBrowserLocalStorage; +import static com.codeborne.selenide.WebDriverRunner.url; +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.projectDir; + +public class ProjectsPageTest { + + private static final String PROJECT_KEY = "key-foo"; + + @ClassRule + public static Orchestrator orchestrator = ProjectSuite.ORCHESTRATOR; + + private static Tester tester = new Tester(orchestrator); + + @ClassRule + public static RuleChain ruleChain = RuleChain.outerRule(orchestrator).around(tester); + + @BeforeClass + public static void setUp() { + orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample")).setProjectKey(PROJECT_KEY)); + orchestrator.executeBuild(SonarScanner.create(projectDir("duplications/file-duplications")).setProjectKey("key-bar")); + } + + @Before + public void before() { + clearBrowserLocalStorage(); + } + + @Test + public void should_display_projects() { + ProjectsPage page = tester.openBrowser().openProjects(); + page.shouldHaveTotal(2); + page.getProjectByKey(PROJECT_KEY) + .shouldHaveMeasure("reliability_rating", "A") + .shouldHaveMeasure("security_rating", "A") + .shouldHaveMeasure("sqale_rating", "A") + .shouldHaveMeasure("duplicated_lines_density", "0.0%") + .shouldHaveMeasure("ncloc", "13") + .shouldHaveMeasure("ncloc", "Xoo"); + } + + @Test + public void should_display_facets() { + ProjectsPage page = tester.openBrowser().openProjects(); + page.getFacetByProperty("duplications") + .shouldHaveValue("1", "1") + .shouldHaveValue("2", "1") + .shouldHaveValue("3", "1") + .shouldHaveValue("4", "1") + .shouldHaveValue("5", "1") + .shouldHaveValue("6", "0"); + } + + @Test + public void should_filter_using_facet() { + ProjectsPage page = tester.openBrowser().openProjects(); + page.shouldHaveTotal(2); + page.getFacetByProperty("duplications").selectValue("3"); + page.shouldHaveTotal(1); + } + + @Test + public void should_open_default_page() { + // default page can be "All Projects" or "Favorite Projects" depending on your last choice + Navigation nav = tester.openBrowser(); + ProjectsPage page = nav.openProjects(); + + // all projects for anonymous user with default sorting to analysis date + page.shouldHaveTotal(2).shouldDisplayAllProjectsWidthSort("-analysis_date"); + + // all projects by default for logged in user + WsUsers.CreateWsResponse.User administrator = tester.users().generateAdministratorOnDefaultOrganization(); + page = nav.logIn().submitCredentials(administrator.getLogin()).openProjects(); + page.shouldHaveTotal(2).shouldDisplayAllProjects(); + + // favorite one project + WsClient administratorWsClient = tester.as(administrator.getLogin()).wsClient(); + administratorWsClient.favorites().add(PROJECT_KEY); + page = nav.openProjects(); + page.shouldHaveTotal(1).shouldDisplayFavoriteProjects(); + + // un-favorite this project + administratorWsClient.favorites().remove(PROJECT_KEY); + page = nav.openProjects(); + page.shouldHaveTotal(2).shouldDisplayAllProjects(); + + // select favorite + page.selectFavoriteProjects(); + page = nav.openProjects(); + page.shouldHaveTotal(0).shouldDisplayFavoriteProjects(); + + // select all + page.selectAllProjects(); + page = nav.openProjects(); + page.shouldHaveTotal(2).shouldDisplayAllProjects(); + } + + @Test + public void should_add_language_to_facet() { + ProjectsPage page = tester.openBrowser().openProjects(); + page.getFacetByProperty("languages") + .selectOptionItem("xoo2") + .shouldHaveValue("xoo2", "0"); + } + + @Test + public void should_add_tag_to_facet() { + // Add some tags to this project + tester.wsClient().wsConnector().call( + new PostRequest("api/project_tags/set") + .setParam("project", PROJECT_KEY) + .setParam("tags", "aa,bb,cc,dd,ee,ff,gg,hh,ii,jj,zz")); + + ProjectsPage page = tester.openBrowser().openProjects(); + page.getFacetByProperty("tags") + .shouldHaveValue("aa", "1") + .shouldHaveValue("ii", "1") + .selectOptionItem("zz") + .shouldHaveValue("zz", "1"); + } + + @Test + public void should_switch_between_perspectives() { + WsUsers.CreateWsResponse.User administrator = tester.users().generateAdministratorOnDefaultOrganization(); + ProjectsPage page = tester.openBrowser() + .logIn().submitCredentials(administrator.getLogin()) + .openProjects(); + page.changePerspective("Risk"); + assertThat(url()).endsWith("/projects?view=visualizations&visualization=risk"); + page.changePerspective("Leak"); + assertThat(url()).endsWith("/projects?view=leak"); + } + + @Test + public void should_sort_by_facet() { + ProjectsPage page = tester.openBrowser().openProjects(); + page.sortProjects("Duplications"); + page.getProjectByIdx(0).shouldHaveMeasure("duplicated_lines_density", "63.7%"); + page.invertSorting(); + page.getProjectByIdx(0).shouldHaveMeasure("duplicated_lines_density", "0.0%"); + } + + @Test + public void should_search_for_project() { + ProjectsPage page = tester.openBrowser().openProjects(); + page.searchProject("s").shouldHaveTotal(2); + page.searchProject("sam").shouldHaveTotal(1); + } + + @Test + public void should_search_for_project_and_keep_other_filters() { + ProjectsPage page = tester.openBrowser().openProjects(); + page.shouldHaveTotal(2); + page.getFacetByProperty("duplications").selectValue("3"); + page.shouldHaveTotal(1); + page.searchProject("sample").shouldHaveTotal(0); + } + + @Test + public void should_open_permalink() { + String user = tester.users().generate().getLogin(); + Navigation nav = tester.openBrowser().logIn().submitCredentials(user); + + // make a search, so its parameters saved to local storage + nav.openProjects().changePerspective("Leak"); + + // change a page + nav.openHome(); + + // open a permalink to a particular visualization, it must be kept + nav.openProjectsWithQuery("view=visualizations&visualization=coverage"); + assertThat(url()).contains("view=visualizations&visualization=coverage"); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/projectAdministration/BackgroundTasksTest.java b/tests/src/test/java/org/sonarqube/tests/projectAdministration/BackgroundTasksTest.java deleted file mode 100644 index 0e7eee2e783..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectAdministration/BackgroundTasksTest.java +++ /dev/null @@ -1,115 +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 org.sonarqube.tests.projectAdministration; - -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.build.SonarScanner; -import org.sonarqube.tests.Category1Suite; -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.qa.util.pageobjects.BackgroundTaskItem; -import org.sonarqube.qa.util.pageobjects.BackgroundTasksPage; -import org.sonarqube.qa.util.pageobjects.Navigation; -import util.user.UserRule; - -import static com.codeborne.selenide.CollectionCondition.sizeGreaterThan; -import static util.ItUtils.projectDir; -import static util.selenium.Selenese.runSelenese; - -public class BackgroundTasksTest { - - private static final String ADMIN_USER_LOGIN = "admin-user"; - - @ClassRule - public static Orchestrator ORCHESTRATOR = Category1Suite.ORCHESTRATOR; - - @Rule - public UserRule userRule = UserRule.from(ORCHESTRATOR); - - private Navigation nav = Navigation.create(ORCHESTRATOR); - - @BeforeClass - public static void beforeClass() { - executeBuild("test-project", "Test Project"); - executeBuild("test-project-2", "Another Test Project"); - } - - @Before - public void before() { - userRule.createAdminUser(ADMIN_USER_LOGIN, ADMIN_USER_LOGIN); - } - - @After - public void deleteAdminUser() { - userRule.resetUsers(); - } - - @Test - public void should_not_display_failing_and_search_and_filter_elements_on_project_level_page() throws Exception { - runSelenese(ORCHESTRATOR, "/projectAdministration/BackgroundTasksTest/should_not_display_failing_and_search_and_filter_elements_on_project_level_page.html"); - } - - @Test - public void display_scanner_context() { - nav.logIn().submitCredentials(ADMIN_USER_LOGIN); - BackgroundTasksPage page = nav.openBackgroundTasksPage(); - - page.getTasks().shouldHave(sizeGreaterThan(0)); - BackgroundTaskItem task = page.getTasksAsItems().get(0); - task.openActions() - .openScannerContext() - .assertScannerContextContains("SonarQube plugins:") - .assertScannerContextContains("Global properties:"); - } - - @Test - public void display_error_stacktrace() { - Navigation nav = Navigation.create(ORCHESTRATOR); - executeBuild("test-project", "Test Project", "2010-01-01"); - - nav.logIn().submitCredentials(ADMIN_USER_LOGIN); - BackgroundTasksPage page = nav.openBackgroundTasksPage(); - - page.getTasks().shouldHave(sizeGreaterThan(0)); - BackgroundTaskItem task = page.getTasksAsItems().get(0); - task.openActions() - .openErrorStacktrace() - .assertErrorStacktraceContains("Date of analysis cannot be older than the date of the last known analysis"); - } - - private static void executeBuild(String projectKey, String projectName) { - ORCHESTRATOR.executeBuild( - SonarScanner.create(projectDir("shared/xoo-sample")) - .setProjectKey(projectKey) - .setProjectName(projectName)); - } - - private static void executeBuild(String projectKey, String projectName, String date) { - ORCHESTRATOR.executeBuild( - SonarScanner.create(projectDir("shared/xoo-sample")) - .setProjectKey(projectKey) - .setProjectName(projectName) - .setProperty("sonar.projectDate", date)); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectAdministrationTest.java b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectAdministrationTest.java index b97d71f9e46..92fac69dda2 100644 --- a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectAdministrationTest.java +++ b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectAdministrationTest.java @@ -23,18 +23,13 @@ import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.SonarScanner; import java.io.UnsupportedEncodingException; import java.sql.SQLException; -import java.util.Date; import javax.annotation.Nullable; -import org.apache.commons.lang.time.DateFormatUtils; import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.openqa.selenium.By; -import org.sonar.wsclient.SonarClient; -import org.sonar.wsclient.base.HttpException; -import org.sonar.wsclient.user.UserParameters; import org.sonarqube.qa.util.Tester; import org.sonarqube.qa.util.pageobjects.Navigation; import org.sonarqube.qa.util.pageobjects.ProjectsManagementPage; @@ -44,21 +39,12 @@ import org.sonarqube.ws.WsPermissions; import org.sonarqube.ws.client.permission.AddUserToTemplateWsRequest; import org.sonarqube.ws.client.permission.CreateTemplateWsRequest; import org.sonarqube.ws.client.permission.UsersWsRequest; -import org.sonarqube.ws.client.project.SearchWsRequest; import static com.codeborne.selenide.Selenide.$; -import static java.util.Collections.singletonList; -import static org.apache.commons.lang.time.DateUtils.addDays; import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.getComponent; import static util.ItUtils.projectDir; -import static util.selenium.Selenese.runSelenese; public class ProjectAdministrationTest { - private static final String DELETE_WS_ENDPOINT = "api/projects/bulk_delete"; - - // take some day in the past - private static final String ANALYSIS_DATE = DateFormatUtils.ISO_DATE_FORMAT.format(addDays(new Date(), -1)); @ClassRule public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR; @@ -71,8 +57,6 @@ public class ProjectAdministrationTest { private Navigation nav = Navigation.create(orchestrator); - private static final String PROJECT_KEY = "sample"; - private static final String FILE_KEY = "sample:src/main/xoo/sample/Sample.xoo"; private String adminUser; @Before @@ -81,69 +65,6 @@ public class ProjectAdministrationTest { adminUser = tester.users().generateAdministrator().getLogin(); } - @Test - public void delete_project_by_web_service() { - scanSampleWithDate(ANALYSIS_DATE); - - assertThat(getComponent(orchestrator, PROJECT_KEY)).isNotNull(); - assertThat(getComponent(orchestrator, FILE_KEY)).isNotNull(); - - orchestrator.getServer().adminWsClient().post(DELETE_WS_ENDPOINT, "keys", PROJECT_KEY); - - assertThat(getComponent(orchestrator, PROJECT_KEY)).isNull(); - assertThat(getComponent(orchestrator, FILE_KEY)).isNull(); - } - - @Test - public void fail_when_trying_to_delete_a_file() { - scanSampleWithDate(ANALYSIS_DATE); - assertThat(getComponent(orchestrator, PROJECT_KEY)).isNotNull(); - assertThat(getComponent(orchestrator, FILE_KEY)).isNotNull(); - - expectedException.expect(org.sonarqube.ws.client.HttpException.class); - - tester.wsClient().projects().bulkDelete(SearchWsRequest.builder() - .setQualifiers(singletonList("FIL")) - .setProjects(singletonList(FILE_KEY)).build()); - } - - @Test - public void fail_when_insufficient_privilege() { - expectedException.expect(HttpException.class); - scanSampleWithDate(ANALYSIS_DATE); - - assertThat(getComponent(orchestrator, PROJECT_KEY)).isNotNull(); - - // use wsClient() instead of adminWsClient() - orchestrator.getServer().wsClient().post(DELETE_WS_ENDPOINT, "keys", PROJECT_KEY); - } - - /** - * Test updated for SONAR-3570 and SONAR-5923 - */ - @Test - public void project_deletion() { - String projectAdminUser = "project-deletion-with-admin-permission-on-project"; - SonarClient wsClient = orchestrator.getServer().adminWsClient(); - try { - SonarScanner scan = SonarScanner.create(projectDir("shared/xoo-sample")); - orchestrator.executeBuild(scan); - - // Create user having admin permission on previously analysed project - wsClient.userClient().create( - UserParameters.create().login(projectAdminUser).name(projectAdminUser).password("password").passwordConfirmation("password")); - - wsClient.post("api/permissions/add_user", - "login", projectAdminUser, - "projectKey", "sample", - "permission", "admin"); - - runSelenese(orchestrator, "/projectAdministration/ProjectAdministrationTest/project-deletion/project-deletion.html"); - } finally { - wsClient.userClient().deactivate(projectAdminUser); - } - } - @Test public void display_project_settings() throws UnsupportedEncodingException { scanSample(null, null); @@ -214,10 +135,6 @@ public class ProjectAdministrationTest { assertThat(usersResponse.getUsers(0).getLogin()).isEqualTo(user); } - private void scanSampleWithDate(String date) { - scanSample(date, null); - } - private void scanSample(@Nullable String date, @Nullable String profile) { SonarScanner scan = SonarScanner.create(projectDir("shared/xoo-sample")) .setProperty("sonar.cpd.exclusions", "**/*"); @@ -229,8 +146,4 @@ public class ProjectAdministrationTest { } orchestrator.executeBuild(scan); } - - private int count(String condition) { - return orchestrator.getDatabase().countSql("select count(1) from " + condition); - } } diff --git a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectBulkDeleteTest.java b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectBulkDeleteTest.java deleted file mode 100644 index 71ac12d965c..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectBulkDeleteTest.java +++ /dev/null @@ -1,86 +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 org.sonarqube.tests.projectAdministration; - -import com.sonar.orchestrator.Orchestrator; -import java.util.List; -import java.util.stream.IntStream; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.sonarqube.tests.Category6Suite; -import org.sonarqube.qa.util.Tester; -import org.sonarqube.ws.Organizations; -import org.sonarqube.ws.WsProjects.CreateWsResponse; -import org.sonarqube.ws.WsProjects.SearchWsResponse.Component; -import org.sonarqube.ws.client.project.SearchWsRequest; - -import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.runProjectAnalysis; - -public class ProjectBulkDeleteTest { - - @ClassRule - public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - @Rule - public Tester tester = new Tester(orchestrator); - - @Test - public void delete_projects() { - Organizations.Organization organization = tester.organizations().generate(); - CreateWsResponse.Project firstProvisionedProject = tester.projects().generate(organization, p -> p.setKey("first-provisioned-project")); - CreateWsResponse.Project secondProvisionedProject = tester.projects().generate(organization, p -> p.setKey("second-provisioned-project")); - CreateWsResponse.Project analyzedProject = tester.projects().generate(organization); - - analyzeProject(analyzedProject.getKey(), organization.getKey()); - - tester.wsClient().projects().bulkDelete(SearchWsRequest.builder() - .setOrganization(organization.getKey()) - .setQuery("FIRST-PROVISIONED") - .setOnProvisionedOnly(true).build()); - - List projects = tester.wsClient().projects().search(SearchWsRequest.builder().setOrganization(organization.getKey()).build()).getComponentsList(); - assertThat(projects).extracting(Component::getKey) - .containsExactlyInAnyOrder(analyzedProject.getKey(), secondProvisionedProject.getKey()) - .doesNotContain(firstProvisionedProject.getKey()); - } - - @Test - public void delete_more_than_50_projects_at_the_same_time() { - Organizations.Organization organization = tester.organizations().generate(); - IntStream.range(0, 60).forEach(i -> tester.projects().generate(organization)); - SearchWsRequest request = SearchWsRequest.builder().setOrganization(organization.getKey()).build(); - assertThat(tester.wsClient().projects().search(request).getPaging().getTotal()).isEqualTo(60); - - tester.wsClient().projects().bulkDelete(request); - - assertThat(tester.wsClient().projects().search(request).getComponentsList()).isEmpty(); - assertThat(tester.wsClient().projects().search(request).getPaging().getTotal()).isEqualTo(0); - } - - private void analyzeProject(String projectKey, String organizationKey) { - runProjectAnalysis(orchestrator, "shared/xoo-sample", - "sonar.organization", organizationKey, - "sonar.projectKey", projectKey, - "sonar.login", "admin", - "sonar.password", "admin"); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectBulkDeletionPageTest.java b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectBulkDeletionPageTest.java deleted file mode 100644 index 988f37703f8..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectBulkDeletionPageTest.java +++ /dev/null @@ -1,76 +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 org.sonarqube.tests.projectAdministration; - -import com.sonar.orchestrator.Orchestrator; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.sonarqube.tests.Category1Suite; -import org.sonarqube.qa.util.Tester; -import org.sonarqube.ws.WsProjects.CreateWsResponse.Project; -import org.sonarqube.ws.client.component.SearchProjectsRequest; - -import static com.codeborne.selenide.Condition.text; -import static com.codeborne.selenide.Condition.visible; -import static com.codeborne.selenide.Selenide.$; -import static org.assertj.core.api.Assertions.assertThat; - -public class ProjectBulkDeletionPageTest { - - private String adminUser; - - @ClassRule - public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR; - - @Rule - public Tester tester = new Tester(orchestrator); - - @Before - public void deleteData() { - orchestrator.resetData(); - adminUser = tester.users().generateAdministrator().getLogin(); - } - - /** - * SONAR-2614, SONAR-3805 - */ - @Test - public void test_bulk_deletion_on_selected_projects() throws Exception { - Project project1 = tester.projects().generate(null, t -> t.setName("Foo")); - Project project2 = tester.projects().generate(null, t -> t.setName("Bar")); - Project project3 = tester.projects().generate(null, t -> t.setName("FooQux")); - - tester.openBrowser().logIn().submitCredentials(adminUser).open("/admin/projects_management"); - $("#projects-management-page").shouldHave(text(project1.getName())).shouldHave(text(project2.getName())).shouldHave(text(project3.getName())); - - $("#projects-management-page .search-box-input").val("foo").pressEnter(); - $("#projects-management-page").shouldNotHave(text(project2.getName())).shouldHave(text(project1.getName())).shouldHave(text(project3.getName())); - - $("#projects-management-page .js-delete").click(); - $(".modal").shouldBe(visible); - $(".modal button").click(); - $("#projects-management-page").shouldNotHave(text(project1.getName())).shouldNotHave(text(project3.getName())); - - assertThat(tester.wsClient().components().searchProjects(SearchProjectsRequest.builder().build()) - .getComponentsCount()).isEqualTo(1); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectDeleteTest.java b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectDeleteTest.java deleted file mode 100644 index 788a94dfbf3..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectDeleteTest.java +++ /dev/null @@ -1,196 +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 org.sonarqube.tests.projectAdministration; - -import com.sonar.orchestrator.Orchestrator; -import java.util.Arrays; -import java.util.Collection; -import java.util.Map; -import java.util.stream.Collectors; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.DisableOnDebug; -import org.junit.rules.TestRule; -import org.junit.rules.Timeout; -import org.sonarqube.tests.Category6Suite; -import org.sonarqube.qa.util.Tester; -import org.sonarqube.ws.Organizations; -import org.sonarqube.ws.WsComponents; -import org.sonarqube.ws.WsProjects; -import org.sonarqube.ws.WsProjects.CreateWsResponse.Project; -import org.sonarqube.ws.client.GetRequest; -import org.sonarqube.ws.client.WsResponse; -import org.sonarqube.ws.client.component.SearchProjectsRequest; -import org.sonarqube.ws.client.project.CreateRequest; -import org.sonarqube.ws.client.project.DeleteRequest; -import org.sonarqube.ws.client.project.SearchWsRequest; -import util.ItUtils; - -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; - -public class ProjectDeleteTest { - - @ClassRule - public static final Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - - @Rule - public TestRule safeguard = new DisableOnDebug(Timeout.seconds(300)); - @Rule - public Tester tester = new Tester(orchestrator) - .setElasticsearchHttpPort(Category6Suite.SEARCH_HTTP_PORT); - - @Test - public void deletion_removes_project_from_search_engines() { - Organizations.Organization organization = tester.organizations().generate(); - Project project1 = createProject(organization, "one", "Foo"); - Project project2 = createProject(organization, "two", "Bar"); - assertThatProjectIsSearchable(organization, "Foo"); - assertThatProjectIsSearchable(organization, "Bar"); - - deleteProject(project1); - assertThatProjectIsNotSearchable(organization, project1.getName()); - assertThatProjectIsSearchable(organization, project2.getName()); - - deleteProject(project2); - assertThatProjectIsNotSearchable(organization, project1.getName()); - assertThatProjectIsNotSearchable(organization, project2.getName()); - } - - @Test - public void indexing_errors_are_recovered_asynchronously_when_deleting_project() throws Exception { - Organizations.Organization organization = tester.organizations().generate(); - Project project = createProject(organization, "one", "Foo"); - - tester.elasticsearch().lockWrites("components"); - tester.elasticsearch().lockWrites("projectmeasures"); - deleteProject(project); - // WS reloads from database the results returned by Elasticsearch. That's - // why the project does not appear in search engine. - // However this test is still useful to verify that WS do not - // fail during this Elasticsearch inconsistency. - assertThatProjectIsNotSearchable(organization, project.getName()); - - tester.elasticsearch().unlockWrites("components"); - tester.elasticsearch().unlockWrites("projectmeasures"); - // TODO verify that recovery daemon successfully updated indices - } - - @Test - public void bulk_deletion_removes_projects_from_search_engines() { - Organizations.Organization organization = tester.organizations().generate(); - Project project1 = createProject(organization, "one", "Foo"); - Project project2 = createProject(organization, "two", "Bar"); - Project project3 = createProject(organization, "three", "Baz"); - - bulkDeleteProjects(organization, project1, project3); - assertThatProjectIsNotSearchable(organization, project1.getName()); - assertThatProjectIsSearchable(organization, project2.getName()); - assertThatProjectIsNotSearchable(organization, project3.getName()); - } - - @Test - public void indexing_errors_are_recovered_asynchronously_when_bulk_deleting_projects() throws Exception { - Organizations.Organization organization = tester.organizations().generate(); - Project project1 = createProject(organization, "one", "Foo"); - Project project2 = createProject(organization, "two", "Bar"); - Project project3 = createProject(organization, "three", "Baz"); - - tester.elasticsearch().lockWrites("components"); - tester.elasticsearch().lockWrites("projectmeasures"); - bulkDeleteProjects(organization, project1, project3); - - // WS reloads from database the results returned by Elasticsearch. That's - // why the project does not appear in search engine. - // However this test is still useful to verify that WS do not - // fail during this Elasticsearch inconsistency. - assertThatProjectIsNotSearchable(organization, project1.getName()); - assertThatProjectIsSearchable(organization, project2.getName()); - assertThatProjectIsNotSearchable(organization, project3.getName()); - - tester.elasticsearch().unlockWrites("components"); - tester.elasticsearch().unlockWrites("projectmeasures"); - // TODO verify that recovery daemon successfully updated indices - } - - private void deleteProject(Project project) { - tester.wsClient().projects().delete(DeleteRequest.builder().setKey(project.getKey()).build()); - } - - private void bulkDeleteProjects(Organizations.Organization organization, Project... projects) { - SearchWsRequest request = SearchWsRequest.builder() - .setOrganization(organization.getKey()) - .setProjects(Arrays.stream(projects).map(Project::getKey).collect(Collectors.toList())) - .build(); - tester.wsClient().projects().bulkDelete(request); - } - - private Project createProject(Organizations.Organization organization, String key, String name) { - CreateRequest createRequest = CreateRequest.builder().setKey(key).setName(name).setOrganization(organization.getKey()).build(); - return tester.wsClient().projects().create(createRequest).getProject(); - } - - private void assertThatProjectIsSearchable(Organizations.Organization organization, String name) { - assertThat(isInProjectsSearch(organization, name)).isTrue(); - assertThat(isInComponentSearchProjects(name)).isTrue(); - assertThat(isInComponentSuggestions(name)).isTrue(); - } - - private void assertThatProjectIsNotSearchable(Organizations.Organization organization, String name) { - assertThat(isInProjectsSearch(organization, name)).isFalse(); - assertThat(isInComponentSearchProjects(name)).isFalse(); - assertThat(isInComponentSuggestions(name)).isFalse(); - } - - /** - * Projects administration page - uses database - */ - private boolean isInProjectsSearch(Organizations.Organization organization, String name) { - WsProjects.SearchWsResponse response = tester.wsClient().projects().search( - SearchWsRequest.builder().setOrganization(organization.getKey()).setQuery(name).setQualifiers(singletonList("TRK")).build()); - return response.getComponentsCount() > 0; - } - - /** - * Projects page - api/components/search_projects - uses ES + DB - */ - private boolean isInComponentSearchProjects(String name) { - WsComponents.SearchProjectsWsResponse response = tester.wsClient().components().searchProjects( - SearchProjectsRequest.builder().setFilter("query=\"" + name + "\"").build()); - return response.getComponentsCount() > 0; - } - - /** - * Top-right search engine - api/components/suggestions - uses ES + DB - */ - private boolean isInComponentSuggestions(String name) { - GetRequest request = new GetRequest("api/components/suggestions").setParam("s", name); - WsResponse response = tester.wsClient().wsConnector().call(request); - Map json = ItUtils.jsonToMap(response.content()); - Collection> results = (Collection>) json.get("results"); - Collection items = results.stream() - .filter(map -> "TRK".equals(map.get("q"))) - .map(map -> (Collection) map.get("items")) - .findFirst() - .orElseThrow(() -> new IllegalStateException("missing field results/[q=TRK]")); - return !items.isEmpty(); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectKeyUpdateTest.java b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectKeyUpdateTest.java deleted file mode 100644 index f1e1ba47ce4..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectKeyUpdateTest.java +++ /dev/null @@ -1,241 +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 org.sonarqube.tests.projectAdministration; - -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.build.SonarScanner; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import javax.annotation.CheckForNull; -import org.junit.After; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.DisableOnDebug; -import org.junit.rules.TestRule; -import org.junit.rules.Timeout; -import org.sonarqube.tests.Category6Suite; -import org.sonarqube.qa.util.Tester; -import org.sonarqube.ws.Organizations; -import org.sonarqube.ws.WsComponents; -import org.sonarqube.ws.WsProjects; -import org.sonarqube.ws.client.GetRequest; -import org.sonarqube.ws.client.WsResponse; -import org.sonarqube.ws.client.component.SearchProjectsRequest; -import org.sonarqube.ws.client.project.CreateRequest; -import org.sonarqube.ws.client.project.UpdateKeyWsRequest; -import util.ItUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.projectDir; - -public class ProjectKeyUpdateTest { - - @ClassRule - public static final Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - - @Rule - public TestRule safeguard = new DisableOnDebug(Timeout.seconds(300)); - @Rule - public Tester tester = new Tester(orchestrator) - .setElasticsearchHttpPort(Category6Suite.SEARCH_HTTP_PORT); - - @After - public void tearDown() throws Exception { - unlockWritesOnProjectIndices(); - } - - @Test - public void update_key_of_provisioned_project() { - Organizations.Organization organization = tester.organizations().generate(); - WsProjects.CreateWsResponse.Project project = createProject(organization, "one", "Foo"); - - updateKey(project, "two"); - - assertThat(isProjectInDatabase("one")).isFalse(); - assertThat(isProjectInDatabase("two")).isTrue(); - assertThat(isComponentInDatabase("one")).isFalse(); - assertThat(isComponentInDatabase("two")).isTrue(); - assertThat(keyInComponentSearchProjects("Foo")).isEqualTo("two"); - assertThat(keysInComponentSuggestions("Foo")).containsExactly("two"); - } - - @Test - public void recover_indexing_errors_when_updating_key_of_provisioned_project() throws Exception { - Organizations.Organization organization = tester.organizations().generate(); - WsProjects.CreateWsResponse.Project project = createProject(organization, "one", "Foo"); - - lockWritesOnProjectIndices(); - - updateKey(project, "two"); - - assertThat(isProjectInDatabase("one")).isFalse(); - - // WS gets the list of projects from ES then reloads projects from db. - // That's why keys in WS responses are correct. - assertThat(isProjectInDatabase("one")).isFalse(); - assertThat(isProjectInDatabase("two")).isTrue(); - assertThat(keyInComponentSearchProjects("Foo")).isEqualTo("two"); - assertThat(keysInComponentSuggestions("Foo")).containsExactly("two"); - - // however searching by key is inconsistent - assertThat(keyInComponentSearchProjects("one")).isEqualTo("two"); - assertThat(keysInComponentSuggestions("one")).containsExactly("two"); - assertThat(keyInComponentSearchProjects("two")).isNull(); - assertThat(keysInComponentSuggestions("two")).isEmpty(); - - unlockWritesOnProjectIndices(); - - boolean recovered = false; - while (!recovered) { - // recovery daemon runs every second, see Category6Suite - Thread.sleep(1_000L); - recovered = keyInComponentSearchProjects("one") == null && - keysInComponentSuggestions("one").isEmpty() && - "two".equals(keyInComponentSearchProjects("two")) && - keysInComponentSuggestions("two").contains("two"); - } - } - - @Test - public void update_key_of_module() { - Organizations.Organization organization = tester.organizations().generate(); - orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-multi-modules-sample"), - "sonar.organization", organization.getKey(), - "sonar.login", "admin", "sonar.password", "admin")); - - String initialKey = "com.sonarsource.it.samples:multi-modules-sample:module_a"; - String newKey = "com.sonarsource.it.samples:multi-modules-sample:module_c"; - - updateKey(initialKey, newKey); - - assertThat(isComponentInDatabase(initialKey)).isFalse(); - assertThat(isComponentInDatabase(newKey)).isTrue(); - // suggestions engine ignores one-character words, so we can't search for "Module A" - assertThat(keysInComponentSuggestions("Module")) - .contains(newKey) - .doesNotContain(initialKey); - assertThat(keysInComponentSuggestions(newKey)) - .contains(newKey) - .doesNotContain(initialKey); - assertThat(keysInComponentSuggestions(initialKey)).isEmpty(); - - } - - @Test - public void recover_indexing_errors_when_updating_key_of_module() throws Exception { - Organizations.Organization organization = tester.organizations().generate(); - orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-multi-modules-sample"), - "sonar.organization", organization.getKey(), - "sonar.login", "admin", "sonar.password", "admin")); - - String initialKey = "com.sonarsource.it.samples:multi-modules-sample:module_a"; - String newKey = "com.sonarsource.it.samples:multi-modules-sample:module_c"; - - lockWritesOnProjectIndices(); - updateKey(initialKey, newKey); - - // api/components/search loads keys from db, so results are consistent - assertThat(isComponentInDatabase(initialKey)).isFalse(); - assertThat(isComponentInDatabase(newKey)).isTrue(); - - // key in result of suggestion engine is loaded from db, so results are ok when searching for unchanged name - assertThat(keysInComponentSuggestions("Module")) - .contains(newKey) - .doesNotContain(initialKey); - - // but searching for new key does not work - assertThat(keysInComponentSuggestions(newKey)).isEmpty(); - assertThat(keysInComponentSuggestions(initialKey)) - .isNotEmpty() - .contains(newKey /* the returned key is loaded from db, so it's correct */); - - unlockWritesOnProjectIndices(); - - boolean recovered = false; - while (!recovered) { - // recovery daemon runs every second, see Category6Suite - Thread.sleep(1_000L); - recovered = keysInComponentSuggestions(newKey).contains(newKey) && keysInComponentSuggestions(initialKey).isEmpty(); - } - - } - - private void lockWritesOnProjectIndices() throws Exception { - tester.elasticsearch().lockWrites("components"); - tester.elasticsearch().lockWrites("projectmeasures"); - } - - private void unlockWritesOnProjectIndices() throws Exception { - tester.elasticsearch().unlockWrites("components"); - tester.elasticsearch().unlockWrites("projectmeasures"); - } - - private void updateKey(WsProjects.CreateWsResponse.Project project, String newKey) { - tester.wsClient().projects().updateKey(UpdateKeyWsRequest.builder().setKey(project.getKey()).setNewKey(newKey).build()); - } - - private void updateKey(String initialKey, String newKey) { - tester.wsClient().projects().updateKey(UpdateKeyWsRequest.builder().setKey(initialKey).setNewKey(newKey).build()); - } - - private WsProjects.CreateWsResponse.Project createProject(Organizations.Organization organization, String key, String name) { - CreateRequest createRequest = CreateRequest.builder().setKey(key).setName(name).setOrganization(organization.getKey()).build(); - return tester.wsClient().projects().create(createRequest).getProject(); - } - - private boolean isProjectInDatabase(String projectKey) { - return orchestrator.getDatabase().countSql(String.format("select count(id) from projects where qualifier='TRK' and kee='%s'", projectKey)) == 1L; - } - - private boolean isComponentInDatabase(String componentKey) { - return orchestrator.getDatabase().countSql(String.format("select count(id) from projects where kee='%s'", componentKey)) == 1L; - } - - /** - * Projects page - api/components/search_projects - uses ES + DB - */ - @CheckForNull - private String keyInComponentSearchProjects(String name) { - WsComponents.SearchProjectsWsResponse response = tester.wsClient().components().searchProjects( - SearchProjectsRequest.builder().setFilter("query=\"" + name + "\"").build()); - if (response.getComponentsCount() > 0) { - return response.getComponents(0).getKey(); - } - return null; - } - - /** - * Top-right search engine - api/components/suggestions - uses ES + DB - */ - private List keysInComponentSuggestions(String name) { - GetRequest request = new GetRequest("api/components/suggestions").setParam("s", name); - WsResponse response = tester.wsClient().wsConnector().call(request); - Map json = ItUtils.jsonToMap(response.content()); - Collection> results = (Collection>) json.get("results"); - return results.stream() - .filter(map -> "TRK".equals(map.get("q")) || "BRC".equals(map.get("q"))) - .flatMap(map -> ((Collection>) map.get("items")).stream()) - .map(map -> (String) map.get("key")) - .collect(Collectors.toList()); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectLinksPageTest.java b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectLinksPageTest.java deleted file mode 100644 index b6ad18a16b5..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectLinksPageTest.java +++ /dev/null @@ -1,158 +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 org.sonarqube.tests.projectAdministration; - -import com.codeborne.selenide.Condition; -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.build.SonarScanner; -import org.sonarqube.tests.Category1Suite; -import java.util.List; -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.WsProjectLinks.CreateWsResponse; -import org.sonarqube.ws.client.WsClient; -import org.sonarqube.ws.client.projectlinks.CreateWsRequest; -import org.sonarqube.ws.client.projectlinks.DeleteWsRequest; -import org.sonarqube.qa.util.pageobjects.Navigation; -import org.sonarqube.qa.util.pageobjects.ProjectLinkItem; -import org.sonarqube.qa.util.pageobjects.ProjectLinksPage; -import util.user.UserRule; - -import static com.codeborne.selenide.Condition.hasText; -import static com.codeborne.selenide.Selenide.$; -import static util.ItUtils.newAdminWsClient; -import static util.ItUtils.projectDir; - -public class ProjectLinksPageTest { - - @ClassRule - public static Orchestrator ORCHESTRATOR = Category1Suite.ORCHESTRATOR; - - private Navigation nav = Navigation.create(ORCHESTRATOR); - - @Rule - public UserRule userRule = UserRule.from(ORCHESTRATOR); - - private static WsClient wsClient; - private long customLinkId; - private String adminUser; - - @BeforeClass - public static void setUp() { - wsClient = newAdminWsClient(ORCHESTRATOR); - - ORCHESTRATOR.resetData(); - ORCHESTRATOR.executeBuild( - SonarScanner.create(projectDir("shared/xoo-sample")) - .setProperty("sonar.links.homepage", "http://example.com")); - } - - @Before - public void prepare() { - customLinkId = Long.parseLong(createCustomLink().getLink().getId()); - adminUser = userRule.createAdminUser(); - } - - @After - public void clean() { - deleteLink(customLinkId); - } - - @Test - public void should_list_links() { - ProjectLinksPage page = openPage(); - - page.getLinks().shouldHaveSize(2); - - List links = page.getLinksAsItems(); - ProjectLinkItem homepageLink = links.get(0); - ProjectLinkItem customLink = links.get(1); - - homepageLink.getName().should(hasText("Home")); - homepageLink.getType().should(hasText("sonar.links.homepage")); - homepageLink.getUrl().should(hasText("http://example.com")); - homepageLink.getDeleteButton().shouldNot(Condition.present); - - customLink.getName().should(hasText("Custom")); - customLink.getType().shouldNot(Condition.present); - customLink.getUrl().should(hasText("http://example.org/custom")); - customLink.getDeleteButton().shouldBe(Condition.visible); - } - - @Test - public void should_create_link() { - ProjectLinksPage page = openPage(); - - page.getLinks().shouldHaveSize(2); - - $("#create-project-link").click(); - $("#create-link-name").setValue("Test"); - $("#create-link-url").setValue("http://example.com/test"); - $("#create-link-confirm").click(); - - page.getLinks().shouldHaveSize(3); - - ProjectLinkItem testLink = page.getLinksAsItems().get(2); - - testLink.getName().should(hasText("Test")); - testLink.getType().shouldNot(Condition.present); - testLink.getUrl().should(hasText("http://example.com/test")); - testLink.getDeleteButton().shouldBe(Condition.visible); - } - - @Test - public void should_delete_link() { - ProjectLinksPage page = openPage(); - - page.getLinks().shouldHaveSize(2); - - List links = page.getLinksAsItems(); - ProjectLinkItem customLink = links.get(1); - - customLink.getDeleteButton().click(); - $("#delete-link-confirm").click(); - - page.getLinks().shouldHaveSize(1); - } - - private CreateWsResponse createCustomLink() { - return wsClient.projectLinks().create(new CreateWsRequest() - .setProjectKey("sample") - .setName("Custom") - .setUrl("http://example.org/custom")); - } - - private void deleteLink(long id) { - try { - wsClient.projectLinks().delete(new DeleteWsRequest().setId(id)); - } catch (Exception e) { - // fail silently - } - } - - private ProjectLinksPage openPage() { - nav.logIn().submitCredentials(adminUser, adminUser); - return nav.openProjectLinks("sample"); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectProvisioningTest.java b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectProvisioningTest.java deleted file mode 100644 index 40140448b55..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectProvisioningTest.java +++ /dev/null @@ -1,133 +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 org.sonarqube.tests.projectAdministration; - -import com.sonar.orchestrator.Orchestrator; -import java.util.Collection; -import java.util.Map; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.DisableOnDebug; -import org.junit.rules.TestRule; -import org.junit.rules.Timeout; -import org.sonarqube.tests.Category6Suite; -import org.sonarqube.qa.util.Tester; -import org.sonarqube.ws.Organizations; -import org.sonarqube.ws.WsComponents; -import org.sonarqube.ws.WsProjects; -import org.sonarqube.ws.WsProjects.CreateWsResponse.Project; -import org.sonarqube.ws.client.GetRequest; -import org.sonarqube.ws.client.WsResponse; -import org.sonarqube.ws.client.component.SearchProjectsRequest; -import org.sonarqube.ws.client.project.CreateRequest; -import org.sonarqube.ws.client.project.SearchWsRequest; -import util.ItUtils; - -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; - -public class ProjectProvisioningTest { - - @ClassRule - public static final Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - - @Rule - public TestRule safeguard = new DisableOnDebug(Timeout.seconds(300)); - @Rule - public Tester tester = new Tester(orchestrator) - .setElasticsearchHttpPort(Category6Suite.SEARCH_HTTP_PORT); - - @Test - public void provisioned_project_is_available_in_search_engines() { - Organizations.Organization organization = tester.organizations().generate(); - - createProject(organization, "one", "Foo"); - - assertThat(isInProjectsSearch(organization, "Foo")).isTrue(); - assertThat(isInComponentSearchProjects("Foo")).isTrue(); - assertThat(isInComponentSuggestions("Foo")).isTrue(); - } - - @Test - public void indexing_errors_are_recovered_asynchronously_when_provisioning_project() throws Exception { - tester.elasticsearch().lockWrites("components"); - tester.elasticsearch().lockWrites("projectmeasures"); - - Organizations.Organization organization = tester.organizations().generate(); - Project project = createProject(organization, "one", "Foo"); - - // no ES requests but only DB - assertThat(isInProjectsSearch(organization, project.getName())).isTrue(); - - // these WS use ES so they are temporarily inconsistent - assertThat(isInComponentSearchProjects(project.getName())).isFalse(); - assertThat(isInComponentSuggestions(project.getName())).isFalse(); - - tester.elasticsearch().unlockWrites("components"); - tester.elasticsearch().unlockWrites("projectmeasures"); - - boolean found = false; - while (!found) { - // recovery daemon runs every second (see Category6Suite) - Thread.sleep(1_000L); - found = isInComponentSearchProjects(project.getName()) && isInComponentSuggestions(project.getName()); - } - } - - private Project createProject(Organizations.Organization organization, String key, String name) { - CreateRequest createRequest = CreateRequest.builder().setKey(key).setName(name).setOrganization(organization.getKey()).build(); - return tester.wsClient().projects().create(createRequest).getProject(); - } - - /** - * Projects administration page - uses database - */ - private boolean isInProjectsSearch(Organizations.Organization organization, String name) { - WsProjects.SearchWsResponse response = tester.wsClient().projects().search( - SearchWsRequest.builder().setOrganization(organization.getKey()).setQuery(name).setQualifiers(singletonList("TRK")).build()); - return response.getComponentsCount() > 0; - } - - /** - * Projects page - api/components/search_projects - uses ES + DB - */ - private boolean isInComponentSearchProjects(String name) { - WsComponents.SearchProjectsWsResponse response = tester.wsClient().components().searchProjects( - SearchProjectsRequest.builder().setFilter("query=\"" + name + "\"").build()); - return response.getComponentsCount() > 0; - } - - /** - * Top-right search engine - api/components/suggestions - uses ES + DB - */ - private boolean isInComponentSuggestions(String name) { - GetRequest request = new GetRequest("api/components/suggestions").setParam("s", name); - WsResponse response = tester.wsClient().wsConnector().call(request); - Map json = ItUtils.jsonToMap(response.content()); - Collection> results = (Collection>) json.get("results"); - Collection items = results.stream() - .filter(map -> "TRK".equals(map.get("q"))) - .map(map -> (Collection) map.get("items")) - .findFirst() - .orElseThrow(() -> new IllegalStateException("missing field results/[q=TRK]")); - return !items.isEmpty(); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectQualityGatePageTest.java b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectQualityGatePageTest.java deleted file mode 100644 index 43d726a78de..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectQualityGatePageTest.java +++ /dev/null @@ -1,158 +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 org.sonarqube.tests.projectAdministration; - -import com.codeborne.selenide.Condition; -import com.codeborne.selenide.Selenide; -import com.codeborne.selenide.SelenideElement; -import com.sonar.orchestrator.Orchestrator; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.openqa.selenium.Keys; -import org.sonar.wsclient.qualitygate.QualityGate; -import org.sonar.wsclient.qualitygate.QualityGateClient; -import org.sonarqube.qa.util.pageobjects.Navigation; -import org.sonarqube.qa.util.pageobjects.ProjectQualityGatePage; -import org.sonarqube.tests.Category1Suite; -import org.sonarqube.ws.client.PostRequest; -import org.sonarqube.ws.client.WsClient; -import org.sonarqube.ws.client.qualitygate.SelectWsRequest; - -import static util.ItUtils.newAdminWsClient; - -public class ProjectQualityGatePageTest { - - @ClassRule - public static Orchestrator ORCHESTRATOR = Category1Suite.ORCHESTRATOR; - - private Navigation nav = Navigation.create(ORCHESTRATOR); - - private static WsClient wsClient; - - @BeforeClass - public static void prepare() { - wsClient = newAdminWsClient(ORCHESTRATOR); - } - - @Before - public void setUp() { - ORCHESTRATOR.resetData(); - - wsClient.wsConnector().call(new PostRequest("api/projects/create") - .setParam("name", "Sample") - .setParam("key", "sample")); - } - - @Test - public void should_display_default() { - QualityGate customQualityGate = createCustomQualityGate("should_display_default"); - qualityGateClient().setDefault(customQualityGate.id()); - - try { - ProjectQualityGatePage page = openPage(); - SelenideElement selectedQualityGate = page.getSelectedQualityGate(); - selectedQualityGate.should(Condition.text("Default")); - selectedQualityGate.should(Condition.text(customQualityGate.name())); - } finally { - qualityGateClient().unsetDefault(); - qualityGateClient().destroy(customQualityGate.id()); - } - } - - @Test - public void should_display_custom() { - QualityGate customQualityGate = createCustomQualityGate("should_display_custom"); - associateWithQualityGate(customQualityGate); - - ProjectQualityGatePage page = openPage(); - SelenideElement selectedQualityGate = page.getSelectedQualityGate(); - selectedQualityGate.shouldNot(Condition.text("Default")); - selectedQualityGate.should(Condition.text(customQualityGate.name())); - } - - @Test - public void should_display_none() { - qualityGateClient().unsetDefault(); - - ProjectQualityGatePage page = openPage(); - page.assertNotSelected(); - } - - @Test - public void should_set_custom() { - QualityGate customQualityGate = createCustomQualityGate("should_set_custom"); - - ProjectQualityGatePage page = openPage(); - page.setQualityGate(customQualityGate.name()); - - SelenideElement selectedQualityGate = page.getSelectedQualityGate(); - selectedQualityGate.should(Condition.text(customQualityGate.name())); - } - - @Test - public void should_set_default() { - QualityGate customQualityGate = createCustomQualityGate("should_set_default"); - qualityGateClient().setDefault(customQualityGate.id()); - - try { - ProjectQualityGatePage page = openPage(); - page.setQualityGate(customQualityGate.name()); - - SelenideElement selectedQualityGate = page.getSelectedQualityGate(); - selectedQualityGate.should(Condition.text("Default")); - selectedQualityGate.should(Condition.text(customQualityGate.name())); - } finally { - qualityGateClient().unsetDefault(); - qualityGateClient().destroy(customQualityGate.id()); - } - } - - @Test - public void should_set_none() { - qualityGateClient().unsetDefault(); - QualityGate customQualityGate = createCustomQualityGate("should_set_none"); - associateWithQualityGate(customQualityGate); - - ProjectQualityGatePage page = openPage(); - Selenide.$(".Select-input input").sendKeys(Keys.UP, Keys.UP, Keys.UP, Keys.ENTER); - - page.assertNotSelected(); - } - - private ProjectQualityGatePage openPage() { - nav.logIn().submitCredentials("admin", "admin"); - Selenide.$(".js-skip.text-muted").pressEscape(); - return nav.openProjectQualityGate("sample"); - } - - private static QualityGate createCustomQualityGate(String name) { - return qualityGateClient().create(name); - } - - private void associateWithQualityGate(QualityGate qualityGate) { - wsClient.qualityGates().associateProject(new SelectWsRequest().setProjectKey("sample").setGateId(qualityGate.id())); - } - - private static QualityGateClient qualityGateClient() { - return ORCHESTRATOR.getServer().adminWsClient().qualityGateClient(); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectSearchTest.java b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectSearchTest.java deleted file mode 100644 index cd1c0107c8c..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectSearchTest.java +++ /dev/null @@ -1,127 +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 org.sonarqube.tests.projectAdministration; - -import com.sonar.orchestrator.Orchestrator; -import java.util.Date; -import org.apache.commons.lang.time.DateUtils; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.sonarqube.tests.Category6Suite; -import org.sonarqube.qa.util.Tester; -import org.sonarqube.ws.Organizations; -import org.sonarqube.ws.WsProjects.CreateWsResponse; -import org.sonarqube.ws.WsProjects.SearchWsResponse; -import org.sonarqube.ws.WsProjects.SearchWsResponse.Component; -import org.sonarqube.ws.client.GetRequest; -import org.sonarqube.ws.client.project.SearchWsRequest; - -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.formatDate; -import static util.ItUtils.runProjectAnalysis; - -public class ProjectSearchTest { - - @ClassRule - public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - @Rule - public Tester tester = new Tester(orchestrator); - - @Test - public void search_old_projects() { - Organizations.Organization organization = tester.organizations().generate(); - CreateWsResponse.Project oldProject = tester.projects().generate(organization); - CreateWsResponse.Project recentProject = tester.projects().generate(organization); - Date now = new Date(); - Date oneYearAgo = DateUtils.addDays(now, -365); - Date moreThanOneYearAgo = DateUtils.addDays(now, -366); - - analyzeProject(oldProject.getKey(), moreThanOneYearAgo, organization.getKey()); - analyzeProject(recentProject.getKey(), now, organization.getKey()); - - SearchWsResponse result = tester.wsClient().projects().search(SearchWsRequest.builder() - .setOrganization(organization.getKey()) - .setQualifiers(singletonList("TRK")) - .setAnalyzedBefore(formatDate(oneYearAgo)).build()); - - assertThat(result.getComponentsList()).extracting(Component::getKey).containsExactlyInAnyOrder(oldProject.getKey()); - } - - @Test - public void search_on_key_query_partial_match_case_insensitive() { - Organizations.Organization organization = tester.organizations().generate(); - CreateWsResponse.Project lowerCaseProject = tester.projects().generate(organization, p -> p.setKey("project-key")); - CreateWsResponse.Project upperCaseProject = tester.projects().generate(organization, p -> p.setKey("PROJECT-KEY")); - CreateWsResponse.Project anotherProject = tester.projects().generate(organization, p -> p.setKey("another-project")); - - analyzeProject(lowerCaseProject.getKey(), organization.getKey()); - analyzeProject(upperCaseProject.getKey(), organization.getKey()); - analyzeProject(anotherProject.getKey(), organization.getKey()); - - SearchWsResponse result = tester.wsClient().projects().search(SearchWsRequest.builder() - .setOrganization(organization.getKey()) - .setQualifiers(singletonList("TRK")) - .setQuery("JeCt-K") - .build()); - - assertThat(result.getComponentsList()).extracting(Component::getKey) - .containsExactlyInAnyOrder(lowerCaseProject.getKey(), upperCaseProject.getKey()) - .doesNotContain(anotherProject.getKey()); - } - - @Test - public void search_provisioned_projects() { - Organizations.Organization organization = tester.organizations().generate(); - CreateWsResponse.Project firstProvisionedProject = tester.projects().generate(organization); - CreateWsResponse.Project secondProvisionedProject = tester.projects().generate(organization); - CreateWsResponse.Project analyzedProject = tester.projects().generate(organization); - - analyzeProject(analyzedProject.getKey(), organization.getKey()); - - String result = tester.wsClient().wsConnector().call(new GetRequest("api/projects/provisioned") - .setParam("organization", organization.getKey())) - .failIfNotSuccessful().content(); - SearchWsResponse searchResult = tester.wsClient().projects().search(SearchWsRequest.builder() - .setQualifiers(singletonList("TRK")) - .setOrganization(organization.getKey()) - .setOnProvisionedOnly(true).build()); - - assertThat(result).contains(firstProvisionedProject.getKey(), secondProvisionedProject.getKey()).doesNotContain(analyzedProject.getKey()); - assertThat(searchResult.getComponentsList()).extracting(Component::getKey) - .containsOnly(firstProvisionedProject.getKey(), secondProvisionedProject.getKey()) - .doesNotContain(analyzedProject.getKey()); - } - - private void analyzeProject(String projectKey, Date analysisDate, String organizationKey) { - runProjectAnalysis(orchestrator, "shared/xoo-sample", - "sonar.organization", organizationKey, - "sonar.projectKey", projectKey, - "sonar.projectDate", formatDate(analysisDate), - "sonar.login", "admin", - "sonar.password", "admin"); - } - - private void analyzeProject(String projectKey, String organizationKey) { - analyzeProject(projectKey, new Date(), organizationKey); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectVisibilityPageTest.java b/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectVisibilityPageTest.java deleted file mode 100644 index d5b4b12baaf..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectAdministration/ProjectVisibilityPageTest.java +++ /dev/null @@ -1,98 +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 org.sonarqube.tests.projectAdministration; - -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.build.SonarScanner; -import org.sonarqube.tests.Category1Suite; -import java.sql.SQLException; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.sonarqube.ws.WsComponents; -import org.sonarqube.ws.client.component.SearchProjectsRequest; -import org.sonarqube.ws.client.permission.RemoveGroupWsRequest; -import org.sonarqube.ws.client.project.UpdateVisibilityRequest; -import org.sonarqube.qa.util.pageobjects.Navigation; -import org.sonarqube.qa.util.pageobjects.ProjectsManagementPage; -import util.user.UserRule; - -import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.newAdminWsClient; -import static util.ItUtils.projectDir; - -public class ProjectVisibilityPageTest { - - @ClassRule - public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR; - - @Rule - public UserRule userRule = UserRule.from(orchestrator); - - private Navigation nav = Navigation.create(orchestrator); - - private String adminUser; - - @Before - public void initData() throws SQLException { - orchestrator.resetData(); - adminUser = userRule.createAdminUser(); - } - - @Test - public void return_all_projects_even_when_no_permission() throws Exception { - orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample")).setProperties("sonar.projectKey", "sample1")); - orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample")).setProperties("sonar.projectKey", "sample2")); - newAdminWsClient(orchestrator).projects().updateVisibility(UpdateVisibilityRequest.builder().setProject("sample2").setVisibility("private").build()); - // Remove 'Admin' permission for admin group on project 2 -> No one can access or admin this project, expect System Admin - newAdminWsClient(orchestrator).permissions().removeGroup(new RemoveGroupWsRequest().setProjectKey("sample2").setGroupName("sonar-administrators").setPermission("admin")); - - nav.logIn().submitCredentials(adminUser).openProjectsManagement() - .shouldHaveProject("sample1") - .shouldHaveProject("sample2"); - } - - @Test - public void create_public_project() { - createProjectAndVerify("public"); - } - - @Test - public void create_private_project() { - createProjectAndVerify("private"); - } - - private void createProjectAndVerify(String visibility) { - ProjectsManagementPage page = nav.logIn().submitCredentials(adminUser, adminUser).openProjectsManagement(); - page - .shouldHaveProjectsCount(0) - .createProject("foo", "foo", visibility) - .shouldHaveProjectsCount(1); - - WsComponents.SearchProjectsWsResponse response = newAdminWsClient(orchestrator).components().searchProjects( - SearchProjectsRequest.builder().build()); - assertThat(response.getComponentsCount()).isEqualTo(1); - assertThat(response.getComponents(0).getKey()).isEqualTo("foo"); - assertThat(response.getComponents(0).getName()).isEqualTo("foo"); - assertThat(response.getComponents(0).getVisibility()).isEqualTo(visibility); - } - -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectEvent/ProjectActivityPageTest.java b/tests/src/test/java/org/sonarqube/tests/projectEvent/ProjectActivityPageTest.java deleted file mode 100644 index 7261e43d083..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectEvent/ProjectActivityPageTest.java +++ /dev/null @@ -1,101 +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 org.sonarqube.tests.projectEvent; - -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.build.SonarScanner; -import org.sonarqube.tests.Category4Suite; -import java.util.List; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.sonarqube.qa.util.pageobjects.Navigation; -import org.sonarqube.qa.util.pageobjects.ProjectActivityPage; -import org.sonarqube.qa.util.pageobjects.ProjectAnalysisItem; -import util.user.UserRule; - -import static util.ItUtils.projectDir; - -public class ProjectActivityPageTest { - - @ClassRule - public static Orchestrator ORCHESTRATOR = Category4Suite.ORCHESTRATOR; - - @Rule - public UserRule userRule = UserRule.from(ORCHESTRATOR); - - private Navigation nav = Navigation.create(ORCHESTRATOR); - - @Before - public void setUp() throws Exception { - ORCHESTRATOR.resetData(); - } - - @Test - public void should_list_snapshots() { - analyzeProject("shared/xoo-history-v1", "2014-10-19"); - analyzeProject("shared/xoo-history-v2", "2014-11-13"); - - ProjectActivityPage page = openPage(); - page.getAnalyses().shouldHaveSize(2); - - List analyses = page.getAnalysesAsItems(); - analyses.get(0) - .shouldHaveEventWithText("1.0-SNAPSHOT") - .shouldNotHaveDeleteButton(); - - analyses.get(1) - .shouldHaveEventWithText("0.9-SNAPSHOT") - .shouldHaveDeleteButton(); - } - - @Test - public void add_change_delete_custom_event() { - analyzeProject(); - openPage().getLastAnalysis() - .addCustomEvent("foo") - .changeFirstEvent("bar") - .deleteFirstEvent(); - } - - @Test - public void delete_analysis() { - analyzeProject(); - analyzeProject(); - ProjectActivityPage page = openPage(); - page.getAnalyses().shouldHaveSize(2); - page.getFirstAnalysis().delete(); - } - - private ProjectActivityPage openPage() { - String userAdmin = userRule.createAdminUser(); - nav.logIn().submitCredentials(userAdmin, userAdmin); - return nav.openProjectActivity("sample"); - } - - private static void analyzeProject() { - ORCHESTRATOR.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample"))); - } - - private static void analyzeProject(String path, String date) { - ORCHESTRATOR.executeBuild(SonarScanner.create(projectDir(path)).setProperties("sonar.projectDate", date)); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectSearch/LeakProjectsPageTest.java b/tests/src/test/java/org/sonarqube/tests/projectSearch/LeakProjectsPageTest.java deleted file mode 100644 index 54ff1ce9bf6..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectSearch/LeakProjectsPageTest.java +++ /dev/null @@ -1,119 +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 org.sonarqube.tests.projectSearch; - -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.build.SonarScanner; -import org.sonarqube.tests.Category6Suite; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nullable; -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.qa.util.Tester; -import org.sonarqube.ws.Organizations.Organization; -import org.sonarqube.qa.util.pageobjects.projects.ProjectsPage; - -import static com.codeborne.selenide.WebDriverRunner.url; -import static java.util.Arrays.asList; -import static org.assertj.core.api.Assertions.assertThat; -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; - -public class LeakProjectsPageTest { - - @ClassRule - public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - - @Rule - public Tester tester = new Tester(orchestrator); - - private Organization organization; - - @BeforeClass - public static void beforeClass() { - setServerProperty(orchestrator, "sonar.leak.period", "previous_version"); - } - - @AfterClass - public static void tearDown() { - resetSettings(orchestrator, null, "sonar.leak.period"); - } - - @Before - public void setUp() { - organization = tester.organizations().generate(); - restoreProfile(orchestrator, SearchProjectsTest.class.getResource("/projectSearch/SearchProjectsTest/with-many-rules.xml"), organization.getKey()); - } - - @Test - public void should_display_leak_information() { - // This project has 0% duplication on new code - String projectKey2 = newProjectKey(); - analyzeProject(projectKey2, "projectSearch/xoo-history-v1", "2016-12-31"); - analyzeProject(projectKey2, "projectSearch/xoo-history-v2", null); - - // This project has no duplication on new code - String projectKey1 = newProjectKey(); - analyzeProject(projectKey1, "shared/xoo-sample", "2016-12-31"); - analyzeProject(projectKey1, "shared/xoo-sample", null); - - // Check the facets and project cards - ProjectsPage page = tester.openBrowser().openProjects(organization.getKey()); - page.changePerspective("Leak"); - assertThat(url()).endsWith("/projects?view=leak"); - page.shouldHaveTotal(2); - page.getProjectByKey(projectKey2) - .shouldHaveMeasure("new_reliability_rating", "0A") - .shouldHaveMeasure("new_security_rating", "0A") - .shouldHaveMeasure("new_maintainability_rating", "17A") - .shouldHaveMeasure("new_coverage", "–") - .shouldHaveMeasure("new_duplicated_lines_density", "0.0%") - .shouldHaveMeasure("new_lines", "17"); - page.getFacetByProperty("new_duplications") - .shouldHaveValue("1", "1") - .shouldHaveValue("2", "0") - .shouldHaveValue("3", "0") - .shouldHaveValue("4", "0") - .shouldHaveValue("5", "0") - .shouldHaveValue("6", "1"); - } - - private void analyzeProject(String projectKey, String relativePath, @Nullable String analysisDate) { - List keyValueProperties = new ArrayList<>(asList( - "sonar.projectKey", projectKey, - "sonar.organization", organization.getKey(), - "sonar.profile", "with-many-rules", - "sonar.login", "admin", "sonar.password", "admin", - "sonar.scm.disabled", "false")); - if (analysisDate != null) { - keyValueProperties.add("sonar.projectDate"); - keyValueProperties.add(analysisDate); - } - orchestrator.executeBuild(SonarScanner.create(projectDir(relativePath), keyValueProperties.toArray(new String[0]))); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectSearch/ProjectsPageTest.java b/tests/src/test/java/org/sonarqube/tests/projectSearch/ProjectsPageTest.java deleted file mode 100644 index 2843898a886..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectSearch/ProjectsPageTest.java +++ /dev/null @@ -1,219 +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 org.sonarqube.tests.projectSearch; - -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.build.SonarScanner; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.rules.RuleChain; -import org.sonarqube.qa.util.pageobjects.Navigation; -import org.sonarqube.qa.util.pageobjects.projects.ProjectsPage; -import org.sonarqube.tests.Category1Suite; -import org.sonarqube.qa.util.Tester; -import org.sonarqube.ws.WsUsers; -import org.sonarqube.ws.client.PostRequest; -import org.sonarqube.ws.client.WsClient; -import org.sonarqube.ws.client.project.DeleteRequest; - -import static com.codeborne.selenide.Selenide.clearBrowserLocalStorage; -import static com.codeborne.selenide.WebDriverRunner.url; -import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.projectDir; - -public class ProjectsPageTest { - - @ClassRule - public static Orchestrator orchestrator = Category1Suite.ORCHESTRATOR; - - private static final String PROJECT_KEY = "key-foo"; - private static Tester tester = new Tester(orchestrator).disableOrganizations(); - - @ClassRule - public static RuleChain ruleChain = RuleChain.outerRule(orchestrator) - .around(tester); - - @BeforeClass - public static void setUp() { - orchestrator.resetData(); - orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample")).setProjectKey(PROJECT_KEY)); - orchestrator.executeBuild(SonarScanner.create(projectDir("duplications/file-duplications")).setProjectKey("key-bar")); - } - - @AfterClass - public static void tearDown() { - tester.wsClient().projects().delete(DeleteRequest.builder().setKey(PROJECT_KEY).build()); - tester.wsClient().projects().delete(DeleteRequest.builder().setKey("key-bar").build()); - } - - @Before - public void before() { - clearBrowserLocalStorage(); - } - - @Test - public void should_display_projects() { - ProjectsPage page = tester.openBrowser().openProjects(); - page.shouldHaveTotal(2); - page.getProjectByKey(PROJECT_KEY) - .shouldHaveMeasure("reliability_rating", "A") - .shouldHaveMeasure("security_rating", "A") - .shouldHaveMeasure("sqale_rating", "A") - .shouldHaveMeasure("duplicated_lines_density", "0.0%") - .shouldHaveMeasure("ncloc", "13") - .shouldHaveMeasure("ncloc", "Xoo"); - } - - @Test - public void should_display_facets() { - ProjectsPage page = tester.openBrowser().openProjects(); - page.getFacetByProperty("duplications") - .shouldHaveValue("1", "1") - .shouldHaveValue("2", "1") - .shouldHaveValue("3", "1") - .shouldHaveValue("4", "1") - .shouldHaveValue("5", "1") - .shouldHaveValue("6", "0"); - } - - @Test - public void should_filter_using_facet() { - ProjectsPage page = tester.openBrowser().openProjects(); - page.shouldHaveTotal(2); - page.getFacetByProperty("duplications").selectValue("3"); - page.shouldHaveTotal(1); - } - - @Test - public void should_open_default_page() { - // default page can be "All Projects" or "Favorite Projects" depending on your last choice - Navigation nav = tester.openBrowser(); - ProjectsPage page = nav.openProjects(); - - // all projects for anonymous user with default sorting to analysis date - page.shouldHaveTotal(2).shouldDisplayAllProjectsWidthSort("-analysis_date"); - - // all projects by default for logged in user - WsUsers.CreateWsResponse.User administrator = tester.users().generateAdministrator(); - page = nav.logIn().submitCredentials(administrator.getLogin()).openProjects(); - page.shouldHaveTotal(2).shouldDisplayAllProjects(); - - // favorite one project - WsClient administratorWsClient = tester.as(administrator.getLogin()).wsClient(); - administratorWsClient.favorites().add(PROJECT_KEY); - page = nav.openProjects(); - page.shouldHaveTotal(1).shouldDisplayFavoriteProjects(); - - // un-favorite this project - administratorWsClient.favorites().remove(PROJECT_KEY); - page = nav.openProjects(); - page.shouldHaveTotal(2).shouldDisplayAllProjects(); - - // select favorite - page.selectFavoriteProjects(); - page = nav.openProjects(); - page.shouldHaveTotal(0).shouldDisplayFavoriteProjects(); - - // select all - page.selectAllProjects(); - page = nav.openProjects(); - page.shouldHaveTotal(2).shouldDisplayAllProjects(); - } - - @Test - public void should_add_language_to_facet() { - ProjectsPage page = tester.openBrowser().openProjects(); - page.getFacetByProperty("languages") - .selectOptionItem("xoo2") - .shouldHaveValue("xoo2", "0"); - } - - @Test - public void should_add_tag_to_facet() { - // Add some tags to this project - tester.wsClient().wsConnector().call( - new PostRequest("api/project_tags/set") - .setParam("project", PROJECT_KEY) - .setParam("tags", "aa,bb,cc,dd,ee,ff,gg,hh,ii,jj,zz")); - - ProjectsPage page = tester.openBrowser().openProjects(); - page.getFacetByProperty("tags") - .shouldHaveValue("aa", "1") - .shouldHaveValue("ii", "1") - .selectOptionItem("zz") - .shouldHaveValue("zz", "1"); - } - - @Test - public void should_switch_between_perspectives() { - WsUsers.CreateWsResponse.User administrator = tester.users().generateAdministrator(); - ProjectsPage page = tester.openBrowser() - .logIn().submitCredentials(administrator.getLogin()) - .openProjects(); - page.changePerspective("Risk"); - assertThat(url()).endsWith("/projects?view=visualizations&visualization=risk"); - page.changePerspective("Leak"); - assertThat(url()).endsWith("/projects?view=leak"); - } - - @Test - public void should_sort_by_facet() { - ProjectsPage page = tester.openBrowser().openProjects(); - page.sortProjects("Duplications"); - page.getProjectByIdx(0).shouldHaveMeasure("duplicated_lines_density", "63.7%"); - page.invertSorting(); - page.getProjectByIdx(0).shouldHaveMeasure("duplicated_lines_density", "0.0%"); - } - - @Test - public void should_search_for_project() { - ProjectsPage page = tester.openBrowser().openProjects(); - page.searchProject("s").shouldHaveTotal(2); - page.searchProject("sam").shouldHaveTotal(1); - } - - @Test - public void should_search_for_project_and_keep_other_filters() { - ProjectsPage page = tester.openBrowser().openProjects(); - page.shouldHaveTotal(2); - page.getFacetByProperty("duplications").selectValue("3"); - page.shouldHaveTotal(1); - page.searchProject("sample").shouldHaveTotal(0); - } - - @Test - public void should_open_permalink() { - String user = tester.users().generate().getLogin(); - Navigation nav = tester.openBrowser().logIn().submitCredentials(user); - - // make a search, so its parameters saved to local storage - nav.openProjects().changePerspective("Leak"); - - // change a page - nav.openHome(); - - // open a permalink to a particular visualization, it must be kept - nav.openProjectsWithQuery("view=visualizations&visualization=coverage"); - assertThat(url()).contains("view=visualizations&visualization=coverage"); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/projectSearch/SearchProjectsTest.java b/tests/src/test/java/org/sonarqube/tests/projectSearch/SearchProjectsTest.java deleted file mode 100644 index 2e4e6f159c2..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/projectSearch/SearchProjectsTest.java +++ /dev/null @@ -1,306 +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 org.sonarqube.tests.projectSearch; - -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.build.SonarScanner; -import org.sonarqube.tests.Category6Suite; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.assertj.core.groups.Tuple; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.sonarqube.qa.util.Tester; -import org.sonarqube.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.project.CreateRequest; - -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.newProjectKey; -import static util.ItUtils.projectDir; -import static util.ItUtils.restoreProfile; -import static util.ItUtils.sanitizeTimezones; -import static util.ItUtils.setServerProperty; - -/** - * Tests WS api/components/search_projects - */ -public class SearchProjectsTest { - - @ClassRule - public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR; - - @Rule - public Tester tester = new Tester(orchestrator); - - private Organization organization; - - @Before - public void setUp() { - organization = tester.organizations().generate(); - restoreProfile(orchestrator, SearchProjectsTest.class.getResource("/projectSearch/SearchProjectsTest/with-many-rules.xml"), organization.getKey()); - } - - @Test - public void filter_projects_by_measure_values() throws Exception { - String projectKey = newProjectKey(); - analyzeProject(projectKey, "shared/xoo-sample"); - - verifyFilterMatches(projectKey, "ncloc > 1"); - verifyFilterMatches(projectKey, "ncloc > 1 and duplicated_lines_density <= 100"); - verifyFilterDoesNotMatch("ncloc <= 1"); - } - - @Test - public void find_projects_with_no_data() throws Exception { - String projectKey = newProjectKey(); - analyzeProject(projectKey, "shared/xoo-sample"); - - verifyFilterMatches(projectKey, "coverage = NO_DATA"); - verifyFilterDoesNotMatch("ncloc = NO_DATA"); - } - - @Test - public void provisioned_projects_should_be_included_to_results() throws Exception { - String projectKey = newProjectKey(); - tester.wsClient().projects().create(CreateRequest.builder().setKey(projectKey).setName(projectKey).setOrganization(organization.getKey()).build()); - - SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organization.getKey()).build()); - - assertThat(response.getComponentsList()).extracting(Component::getKey).containsOnly(projectKey); - } - - @Test - public void return_leak_period_date() throws Exception { - setServerProperty(orchestrator, "sonar.leak.period", "previous_version"); - // This project has a leak period - String projectKey1 = newProjectKey(); - analyzeProject(projectKey1, "shared/xoo-sample", "sonar.projectDate", "2016-12-31"); - analyzeProject(projectKey1, "shared/xoo-sample"); - // This project has only one analysis, so no leak period - String projectKey2 = newProjectKey(); - analyzeProject(projectKey2, "shared/xoo-sample"); - // This project is provisioned, so has no leak period - String projectKey3 = newProjectKey(); - tester.wsClient().projects().create(CreateRequest.builder().setKey(projectKey3).setName(projectKey3).setOrganization(organization.getKey()).build()); - - SearchProjectsWsResponse response = searchProjects( - SearchProjectsRequest.builder().setAdditionalFields(singletonList("leakPeriodDate")).setOrganization(organization.getKey()).build()); - - assertThat(response.getComponentsList()).extracting(Component::getKey, Component::hasLeakPeriodDate) - .containsOnly( - tuple(projectKey1, true), - tuple(projectKey2, false), - tuple(projectKey3, false)); - Component project1 = response.getComponentsList().stream().filter(component -> component.getKey().equals(projectKey1)).findFirst() - .orElseThrow(() -> new IllegalStateException("Project1 is not found")); - assertThat(sanitizeTimezones(project1.getLeakPeriodDate())).isEqualTo("2016-12-31T00:00:00+0000"); - } - - @Test - public void filter_by_text_query() throws IOException { - analyzeProject("project1", "shared/xoo-sample", "sonar.projectName", "apachee"); - analyzeProject("project2", "shared/xoo-sample", "sonar.projectName", "Apache"); - analyzeProject("project3", "shared/xoo-multi-modules-sample", "sonar.projectName", "Apache Foundation"); - analyzeProject("project4", "shared/xoo-multi-modules-sample", "sonar.projectName", "Windows"); - - // Search only by text query - assertThat(searchProjects("query = \"apache\"").getComponentsList()).extracting(Component::getKey).containsExactly("project2", "project3", "project1"); - assertThat(searchProjects("query = \"pAch\"").getComponentsList()).extracting(Component::getKey).containsExactly("project2", "project3", "project1"); - assertThat(searchProjects("query = \"hee\"").getComponentsList()).extracting(Component::getKey).containsExactly("project1"); - assertThat(searchProjects("query = \"project1\"").getComponentsList()).extracting(Component::getKey).containsExactly("project1"); - assertThat(searchProjects("query = \"unknown\"").getComponentsList()).isEmpty(); - - // Search by metric criteria and text query - assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"pAch\" AND ncloc > 50").build()).getComponentsList()) - .extracting(Component::getKey).containsExactly("project3"); - assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"nd\" AND ncloc > 50").build()).getComponentsList()) - .extracting(Component::getKey).containsExactly("project3", "project4"); - assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"unknown\" AND ncloc > 50").build()).getComponentsList()).isEmpty(); - ; - - // Check facets - assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"apache\"").setFacets(singletonList("ncloc")).build()).getFacets().getFacets(0).getValuesList()) - .extracting(Common.FacetValue::getVal, Common.FacetValue::getCount) - .containsOnly(tuple("*-1000.0", 3L), tuple("1000.0-10000.0", 0L), tuple("10000.0-100000.0", 0L), tuple("100000.0-500000.0", 0L), tuple("500000.0-*", 0L)); - assertThat(searchProjects(SearchProjectsRequest.builder().setFilter("query = \"unknown\"").setFacets(singletonList("ncloc")).build()).getFacets().getFacets(0) - .getValuesList()).extracting(Common.FacetValue::getVal, Common.FacetValue::getCount) - .containsOnly(tuple("*-1000.0", 0L), tuple("1000.0-10000.0", 0L), tuple("10000.0-100000.0", 0L), tuple("100000.0-500000.0", 0L), tuple("500000.0-*", 0L)); - } - - @Test - public void should_return_facets() throws Exception { - analyzeProject(newProjectKey(), "shared/xoo-sample"); - analyzeProject(newProjectKey(), "shared/xoo-multi-modules-sample"); - - SearchProjectsWsResponse response = searchProjects(SearchProjectsRequest.builder().setOrganization(organization.getKey()).setFacets(asList( - "alert_status", - "coverage", - "duplicated_lines_density", - "languages", - "ncloc", - "reliability_rating", - "security_rating", - "sqale_rating", - "tags")).build()); - - checkFacet(response, "alert_status", - tuple("OK", 2L), - tuple("WARN", 0L), - tuple("ERROR", 0L)); - checkFacet(response, "coverage", - tuple("NO_DATA", 2L), - tuple("*-30.0", 0L), - tuple("30.0-50.0", 0L), - tuple("50.0-70.0", 0L), - tuple("70.0-80.0", 0L), - tuple("80.0-*", 0L)); - checkFacet(response, "duplicated_lines_density", - tuple("NO_DATA", 0L), - tuple("*-3.0", 2L), - tuple("3.0-5.0", 0L), - tuple("5.0-10.0", 0L), - tuple("10.0-20.0", 0L), - tuple("20.0-*", 0L)); - checkFacet(response, "languages", - tuple("xoo", 2L)); - checkFacet(response, "ncloc", - tuple("*-1000.0", 2L), - tuple("1000.0-10000.0", 0L), - tuple("10000.0-100000.0", 0L), - tuple("100000.0-500000.0", 0L), - tuple("500000.0-*", 0L)); - checkFacet(response, "reliability_rating", - tuple("1", 2L), - tuple("2", 0L), - tuple("3", 0L), - tuple("4", 0L), - tuple("5", 0L)); - checkFacet(response, "security_rating", - tuple("1", 2L), - tuple("2", 0L), - tuple("3", 0L), - tuple("4", 0L), - tuple("5", 0L)); - checkFacet(response, "sqale_rating", - tuple("1", 0L), - tuple("2", 0L), - tuple("3", 0L), - tuple("4", 2L), - tuple("5", 0L)); - checkFacet(response, "tags"); - } - - @Test - public void should_return_facets_on_leak() throws Exception { - setServerProperty(orchestrator, "sonar.leak.period", "previous_version"); - // This project has no duplication on new code - String projectKey1 = newProjectKey(); - analyzeProject(projectKey1, "shared/xoo-sample", "sonar.projectDate", "2016-12-31"); - analyzeProject(projectKey1, "shared/xoo-sample"); - // This project has 0% duplication on new code - String projectKey2 = newProjectKey(); - analyzeProject(projectKey2, "projectSearch/xoo-history-v1", "sonar.projectDate", "2016-12-31"); - analyzeProject(projectKey2, "projectSearch/xoo-history-v2"); - - 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", - tuple("1", 2L), - tuple("2", 0L), - tuple("3", 0L), - tuple("4", 0L), - tuple("5", 0L)); - checkFacet(response, "new_security_rating", - tuple("1", 2L), - tuple("2", 0L), - tuple("3", 0L), - tuple("4", 0L), - tuple("5", 0L)); - checkFacet(response, "new_maintainability_rating", - tuple("1", 2L), - tuple("2", 0L), - tuple("3", 0L), - tuple("4", 0L), - tuple("5", 0L)); - checkFacet(response, "new_coverage", - tuple("NO_DATA", 2L), - tuple("*-30.0", 0L), - tuple("30.0-50.0", 0L), - tuple("50.0-70.0", 0L), - tuple("70.0-80.0", 0L), - tuple("80.0-*", 0L)); - checkFacet(response, "new_duplicated_lines_density", - tuple("NO_DATA", 1L), - tuple("*-3.0", 1L), - tuple("3.0-5.0", 0L), - tuple("5.0-10.0", 0L), - tuple("10.0-20.0", 0L), - tuple("20.0-*", 0L)); - checkFacet(response, "new_lines", - tuple("*-1000.0", 1L), - tuple("1000.0-10000.0", 0L), - tuple("10000.0-100000.0", 0L), - tuple("100000.0-500000.0", 0L), - tuple("500000.0-*", 0L)); - } - - private void checkFacet(SearchProjectsWsResponse response, String facetKey, Tuple... values) { - Common.Facet facet = response.getFacets().getFacetsList().stream().filter(f -> f.getProperty().equals(facetKey)).findAny().get(); - assertThat(facet.getValuesList()).extracting(Common.FacetValue::getVal, Common.FacetValue::getCount).containsExactlyInAnyOrder(values); - } - - private void analyzeProject(String projectKey, String relativePath, String... properties) { - List keyValueProperties = new ArrayList<>(asList( - "sonar.projectKey", projectKey, - "sonar.organization", organization.getKey(), - "sonar.profile", "with-many-rules", - "sonar.login", "admin", "sonar.password", "admin", - "sonar.scm.disabled", "false")); - orchestrator.executeBuild(SonarScanner.create(projectDir(relativePath), concat(keyValueProperties.toArray(new String[0]), properties))); - } - - private SearchProjectsWsResponse searchProjects(String filter) throws IOException { - return searchProjects(SearchProjectsRequest.builder().setOrganization(organization.getKey()).setFilter(filter).build()); - } - - private SearchProjectsWsResponse searchProjects(SearchProjectsRequest request) throws IOException { - return tester.wsClient().components().searchProjects(request); - } - - private void verifyFilterMatches(String projectKey, String filter) throws IOException { - assertThat(searchProjects(filter).getComponentsList()).extracting(Component::getKey).containsOnly(projectKey); - } - - private void verifyFilterDoesNotMatch(String filter) throws IOException { - assertThat(searchProjects(filter).getComponentsCount()).isZero(); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/qualityGate/ProjectQualityGatePageTest.java b/tests/src/test/java/org/sonarqube/tests/qualityGate/ProjectQualityGatePageTest.java new file mode 100644 index 00000000000..d47377fd3c4 --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/qualityGate/ProjectQualityGatePageTest.java @@ -0,0 +1,162 @@ +/* + * 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.tests.qualityGate; + +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.Selenide; +import com.codeborne.selenide.SelenideElement; +import com.sonar.orchestrator.Orchestrator; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.openqa.selenium.Keys; +import org.sonar.wsclient.qualitygate.QualityGate; +import org.sonar.wsclient.qualitygate.QualityGateClient; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.qa.util.pageobjects.Navigation; +import org.sonarqube.qa.util.pageobjects.ProjectQualityGatePage; +import org.sonarqube.ws.client.PostRequest; +import org.sonarqube.ws.client.qualitygate.SelectWsRequest; + +public class ProjectQualityGatePageTest { + + @ClassRule + public static Orchestrator orchestrator = QualityGateSuite.ORCHESTRATOR; + + @Rule + public Tester tester = new Tester(orchestrator) + // all the tests of QualityGateSuite must disable organizations + .disableOrganizations(); + + @Before + public void setUp() { + tester.wsClient().wsConnector().call(new PostRequest("api/projects/create") + .setParam("name", "Sample") + .setParam("key", "sample")); + defaultGate = qualityGateClient().list().defaultGate(); + } + + private QualityGate defaultGate; + + @After + public void tearDown() { + if (defaultGate != null) { + qualityGateClient().setDefault(defaultGate.id()); + } + } + + @Test + public void should_display_default() { + QualityGate customQualityGate = createCustomQualityGate("should_display_default"); + qualityGateClient().setDefault(customQualityGate.id()); + + try { + ProjectQualityGatePage page = openPage(); + SelenideElement selectedQualityGate = page.getSelectedQualityGate(); + selectedQualityGate.should(Condition.text("Default")); + selectedQualityGate.should(Condition.text(customQualityGate.name())); + } finally { + qualityGateClient().unsetDefault(); + qualityGateClient().destroy(customQualityGate.id()); + } + } + + @Test + public void should_display_custom() { + QualityGate customQualityGate = createCustomQualityGate("should_display_custom"); + associateWithQualityGate(customQualityGate); + + ProjectQualityGatePage page = openPage(); + SelenideElement selectedQualityGate = page.getSelectedQualityGate(); + selectedQualityGate.shouldNot(Condition.text("Default")); + selectedQualityGate.should(Condition.text(customQualityGate.name())); + } + + @Test + public void should_display_none() { + qualityGateClient().unsetDefault(); + + ProjectQualityGatePage page = openPage(); + page.assertNotSelected(); + } + + @Test + public void should_set_custom() { + QualityGate customQualityGate = createCustomQualityGate("should_set_custom"); + + ProjectQualityGatePage page = openPage(); + page.setQualityGate(customQualityGate.name()); + + SelenideElement selectedQualityGate = page.getSelectedQualityGate(); + selectedQualityGate.should(Condition.text(customQualityGate.name())); + } + + @Test + public void should_set_default() { + QualityGate customQualityGate = createCustomQualityGate("should_set_default"); + qualityGateClient().setDefault(customQualityGate.id()); + + try { + ProjectQualityGatePage page = openPage(); + page.setQualityGate(customQualityGate.name()); + + SelenideElement selectedQualityGate = page.getSelectedQualityGate(); + selectedQualityGate.should(Condition.text("Default")); + selectedQualityGate.should(Condition.text(customQualityGate.name())); + } finally { + qualityGateClient().unsetDefault(); + qualityGateClient().destroy(customQualityGate.id()); + } + } + + @Test + @Ignore + public void should_set_none() { + qualityGateClient().unsetDefault(); + QualityGate customQualityGate = createCustomQualityGate("should_set_none"); + associateWithQualityGate(customQualityGate); + + ProjectQualityGatePage page = openPage(); + Selenide.$(".Select-input input").sendKeys(Keys.UP, Keys.UP, Keys.UP, Keys.ENTER); + + page.assertNotSelected(); + } + + private ProjectQualityGatePage openPage() { + tester.wsClient().users().skipOnboardingTutorial(); + Navigation navigation = tester.openBrowser().logIn().submitCredentials("admin"); + return navigation.openProjectQualityGate("sample"); + } + + private QualityGate createCustomQualityGate(String name) { + return qualityGateClient().create(name); + } + + private void associateWithQualityGate(QualityGate qualityGate) { + tester.wsClient().qualityGates().associateProject(new SelectWsRequest().setProjectKey("sample").setGateId(qualityGate.id())); + } + + private QualityGateClient qualityGateClient() { + return orchestrator.getServer().adminWsClient().qualityGateClient(); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/qualityGate/QualityGateSuite.java b/tests/src/test/java/org/sonarqube/tests/qualityGate/QualityGateSuite.java index ce4632b235a..616f9bf35ac 100644 --- a/tests/src/test/java/org/sonarqube/tests/qualityGate/QualityGateSuite.java +++ b/tests/src/test/java/org/sonarqube/tests/qualityGate/QualityGateSuite.java @@ -29,6 +29,7 @@ import static util.ItUtils.xooPlugin; @RunWith(Suite.class) @Suite.SuiteClasses({ + ProjectQualityGatePageTest.class, QualityGateTest.class, QualityGateUiTest.class, QualityGateNotificationTest.class, diff --git a/tests/src/test/java/org/sonarqube/tests/source/ProjectCodeTest.java b/tests/src/test/java/org/sonarqube/tests/source/ProjectCodeTest.java deleted file mode 100644 index 974ea41abf3..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/source/ProjectCodeTest.java +++ /dev/null @@ -1,95 +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 org.sonarqube.tests.source; - -import com.sonar.orchestrator.Orchestrator; -import com.sonar.orchestrator.build.SonarScanner; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.sonarqube.qa.util.Tester; -import org.sonarqube.ws.WsProjects.CreateWsResponse.Project; - -import static util.ItUtils.projectDir; - -public class ProjectCodeTest { - - @ClassRule - public static Orchestrator orchestrator = SourceSuite.ORCHESTRATOR; - - @Rule - public Tester tester = new Tester(orchestrator); - - @Test - public void browse() { - Project project = tester.projects().generate(null); - executeAnalysis(project); - - tester.openBrowser().openCode(project.getKey()) - .shouldHaveComponent("src/main/xoo/sample") - .openFirstComponent() - .shouldHaveComponent("Sample.xoo") - .openFirstComponent() - .shouldHaveCode("public class Sample") - .shouldHaveBreadcrumbs(project.getName(), "src/main/xoo/sample", "Sample.xoo"); - } - - @Test - public void search() { - Project project = tester.projects().generate(null); - executeAnalysis(project); - - tester.openBrowser().openCode(project.getKey()) - .shouldHaveComponent(project.getName()) - .search("xoo") - .shouldSearchResult("Sample.xoo"); - } - - @Test - public void permalink() { - Project project = tester.projects().generate(null); - executeAnalysis(project); - - tester.openBrowser().openCode(project.getKey(), project.getKey() + "%3Asrc%2Fmain%2Fxoo%2Fsample%2FSample.xoo") - .shouldHaveCode("public class Sample") - .shouldHaveBreadcrumbs(project.getName(), "src/main/xoo/sample", "Sample.xoo"); - } - - @Test - public void expand_root_dir() { - Project project = tester.projects().generate(null); - executeAnalysis(project, "shared/xoo-sample-with-root-dir"); - - tester.openBrowser().openCode(project.getKey()) - .shouldHaveComponent("Hello.xoo") - .shouldHaveComponent("src/main/xoo/sample"); - } - - private void executeAnalysis(Project project, String path) { - orchestrator.executeBuild( - SonarScanner.create(projectDir(path)) - .setProjectKey(project.getKey()) - .setProjectName(project.getName())); - } - - private void executeAnalysis(Project project) { - executeAnalysis(project, "shared/xoo-sample"); - } -} diff --git a/tests/src/test/java/org/sonarqube/tests/source/SourceSuite.java b/tests/src/test/java/org/sonarqube/tests/source/SourceSuite.java index 90fb2a72988..a46823621c3 100644 --- a/tests/src/test/java/org/sonarqube/tests/source/SourceSuite.java +++ b/tests/src/test/java/org/sonarqube/tests/source/SourceSuite.java @@ -29,7 +29,6 @@ import static util.ItUtils.xooPlugin; @RunWith(Suite.class) @Suite.SuiteClasses({ EncodingTest.class, - ProjectCodeTest.class, ScmTest.class, SourceViewerTest.class }) diff --git a/tests/src/test/java/org/sonarqube/tests/ui/UiTest.java b/tests/src/test/java/org/sonarqube/tests/ui/UiTest.java index 050960d843f..85e25b9e29c 100644 --- a/tests/src/test/java/org/sonarqube/tests/ui/UiTest.java +++ b/tests/src/test/java/org/sonarqube/tests/ui/UiTest.java @@ -21,19 +21,18 @@ package org.sonarqube.tests.ui; import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.SonarScanner; -import org.sonarqube.tests.Category4Suite; import java.util.Map; -import org.junit.After; -import org.junit.Before; import org.junit.ClassRule; +import org.junit.Rule; import org.junit.Test; +import org.sonarqube.qa.util.Tester; +import org.sonarqube.qa.util.pageobjects.Navigation; +import org.sonarqube.tests.Category4Suite; import org.sonarqube.ws.client.GetRequest; import org.sonarqube.ws.client.WsResponse; -import org.sonarqube.qa.util.pageobjects.Navigation; import util.ItUtils; import static com.codeborne.selenide.Condition.exist; -import static com.codeborne.selenide.Condition.hasText; import static com.codeborne.selenide.Condition.text; import static com.codeborne.selenide.Condition.visible; import static com.codeborne.selenide.Selenide.$; @@ -41,60 +40,56 @@ import static com.codeborne.selenide.Selenide.$$; import static com.codeborne.selenide.WebDriverRunner.url; import static org.assertj.core.api.Assertions.assertThat; import static util.ItUtils.projectDir; -import static util.ItUtils.resetSettings; -import static util.ItUtils.setServerProperty; public class UiTest { @ClassRule - public static final Orchestrator ORCHESTRATOR = Category4Suite.ORCHESTRATOR; - - private Navigation nav = Navigation.create(ORCHESTRATOR); + public static final Orchestrator orchestrator = Category4Suite.ORCHESTRATOR; - @Before - @After - public void resetData() throws Exception { - resetSettings(ORCHESTRATOR, null, "sonar.forceAuthentication"); - } + @Rule + public Tester tester = new Tester(orchestrator).disableOrganizations(); @Test public void footer_contains_information() { - nav.getFooter() - .should(hasText("Documentation")) - .should(hasText("SonarSource SA")); + tester.openBrowser().getFooter() + .should(text("Documentation")) + .should(text("SonarSource SA")); } @Test public void footer_contains_version() { - WsResponse status = ItUtils.newAdminWsClient(ORCHESTRATOR).wsConnector().call(new GetRequest("api/navigation/global")); + WsResponse status = tester.wsClient().wsConnector().call(new GetRequest("api/navigation/global")); Map statusMap = ItUtils.jsonToMap(status.content()); - nav.getFooter().should(hasText((String) statusMap.get("version"))); + tester.openBrowser().getFooter() + .should(text((String) statusMap.get("version"))); } @Test public void footer_doesnt_contains_version_on_login_page() { - WsResponse status = ItUtils.newAdminWsClient(ORCHESTRATOR).wsConnector().call(new GetRequest("api/navigation/global")); + WsResponse status = tester.wsClient().wsConnector().call(new GetRequest("api/navigation/global")); Map statusMap = ItUtils.jsonToMap(status.content()); - nav.openLogin(); - nav.getFooter().shouldNot(hasText((String) statusMap.get("version"))); + Navigation navigation = tester.openBrowser(); + navigation.openLogin(); + navigation.getFooter().shouldNot(text((String) statusMap.get("version"))); } @Test public void footer_doesnt_contains_about_when_not_logged_in() { - setServerProperty(ORCHESTRATOR, "sonar.forceAuthentication", "true"); - nav.openLogin(); - nav.getFooter() - .shouldNot(hasText("About")) - .shouldNot(hasText("Web API")); + tester.settings().setGlobalSettings("sonar.forceAuthentication", "true"); + Navigation navigation = tester.openBrowser(); + navigation.openLogin(); + navigation.getFooter() + .shouldNot(text("About")) + .shouldNot(text("Web API")); } @Test public void many_page_transitions() { - analyzeSampleProject(); + analyzeXooSample(); - nav.open("/about"); + tester.openBrowser().open("/about"); // on about page $(".about-page-projects-link") @@ -145,13 +140,13 @@ public class UiTest { public void markdown_help() { String tags[] = {"strong", "a", "ul", "ol", "h1", "code", "pre", "blockquote"}; - nav.open("/markdown/help"); + tester.openBrowser().open("/markdown/help"); for (String tag : tags) { $(tag).shouldBe(visible); } } - private static void analyzeSampleProject() { - ORCHESTRATOR.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample"))); + private static void analyzeXooSample() { + orchestrator.executeBuild(SonarScanner.create(projectDir("shared/xoo-sample"))); } }