;;
Category3)
- CATEGORY="Category3"
+ CATEGORY="Category3|component|project"
;;
Category4)
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);
}
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;
@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 {
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;
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;
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
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;
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
+++ /dev/null
-/*
- * 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<String, Object> statusMap = ItUtils.jsonToMap(status.content());
-
- assertThat(statusMap.get("branchesEnabled")).isEqualTo(false);
- }
-}
--- /dev/null
+/*
+ * 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));
+ }
+}
--- /dev/null
+/*
+ * 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<String, Object> statusMap = ItUtils.jsonToMap(status.content());
+
+ assertThat(statusMap.get("branchesEnabled")).isEqualTo(false);
+ }
+}
--- /dev/null
+/*
+ * 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");
+ }
+}
--- /dev/null
+/*
+ * 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();
+
+}
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);
@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();
+++ /dev/null
-/*
- * 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);
- }
-}
DecimalScaleMetricTest.class,
DifferentialPeriodsTest.class,
MeasuresWsTest.class,
+ ProjectActivityPageTest.class,
ProjectDashboardTest.class,
ProjectMeasuresPageTest.class,
SincePreviousVersionHistoryTest.class,
--- /dev/null
+/*
+ * 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<ProjectAnalysisItem> 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));
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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<Component> 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");
+ }
+}
--- /dev/null
+/*
+ * 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<String, Object> json = ItUtils.jsonToMap(response.content());
+ Collection<Map<String, Object>> results = (Collection<Map<String, Object>>) 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());
+ }
+}
--- /dev/null
+/*
+ * 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<String> 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();
+ }
+}
--- /dev/null
+/*
+ * 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<String> keysInComponentSuggestions(String name) {
+ GetRequest request = new GetRequest("api/components/suggestions").setParam("s", name);
+ WsResponse response = tester.wsClient().wsConnector().call(request);
+ Map<String, Object> json = ItUtils.jsonToMap(response.content());
+ Collection<Map<String, Object>> results = (Collection<Map<String, Object>>) json.get("results");
+ return results.stream()
+ .filter(map -> "TRK".equals(map.get("q")) || "BRC".equals(map.get("q")))
+ .flatMap(map -> ((Collection<Map<String, Object>>) 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);
+ }
+}
--- /dev/null
+/*
+ * 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<String> 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])));
+ }
+}
--- /dev/null
+/*
+ * 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<ProjectLinkItem> 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<ProjectLinkItem> 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");
+ }
+}
--- /dev/null
+/*
+ * 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");
+ }
+
+
+}
--- /dev/null
+/*
+ * 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<String, Object> json = ItUtils.jsonToMap(response.content());
+ Collection<Map<String, Object>> results = (Collection<Map<String, Object>>) 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();
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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();
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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");
+ }
+}
+++ /dev/null
-/*
- * 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));
- }
-}
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;
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;
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
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);
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", "**/*");
}
orchestrator.executeBuild(scan);
}
-
- private int count(String condition) {
- return orchestrator.getDatabase().countSql("select count(1) from " + condition);
- }
}
+++ /dev/null
-/*
- * 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<Component> 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");
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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<String, Object> json = ItUtils.jsonToMap(response.content());
- Collection<Map<String, Object>> results = (Collection<Map<String, Object>>) 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();
- }
-}
+++ /dev/null
-/*
- * 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<String> keysInComponentSuggestions(String name) {
- GetRequest request = new GetRequest("api/components/suggestions").setParam("s", name);
- WsResponse response = tester.wsClient().wsConnector().call(request);
- Map<String, Object> json = ItUtils.jsonToMap(response.content());
- Collection<Map<String, Object>> results = (Collection<Map<String, Object>>) json.get("results");
- return results.stream()
- .filter(map -> "TRK".equals(map.get("q")) || "BRC".equals(map.get("q")))
- .flatMap(map -> ((Collection<Map<String, Object>>) map.get("items")).stream())
- .map(map -> (String) map.get("key"))
- .collect(Collectors.toList());
- }
-}
+++ /dev/null
-/*
- * 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<ProjectLinkItem> 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<ProjectLinkItem> 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");
- }
-}
+++ /dev/null
-/*
- * 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<String, Object> json = ItUtils.jsonToMap(response.content());
- Collection<Map<String, Object>> results = (Collection<Map<String, Object>>) 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();
- }
-}
+++ /dev/null
-/*
- * 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();
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-
-}
+++ /dev/null
-/*
- * 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<ProjectAnalysisItem> 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));
- }
-}
+++ /dev/null
-/*
- * 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<String> 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])));
- }
-}
+++ /dev/null
-/*
- * 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");
- }
-}
+++ /dev/null
-/*
- * 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<String> 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();
- }
-}
--- /dev/null
+/*
+ * 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();
+ }
+}
@RunWith(Suite.class)
@Suite.SuiteClasses({
+ ProjectQualityGatePageTest.class,
QualityGateTest.class,
QualityGateUiTest.class,
QualityGateNotificationTest.class,
+++ /dev/null
-/*
- * 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");
- }
-}
@RunWith(Suite.class)
@Suite.SuiteClasses({
EncodingTest.class,
- ProjectCodeTest.class,
ScmTest.class,
SourceViewerTest.class
})
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.$;
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<String, Object> 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<String, Object> 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")
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")));
}
}