diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-02-09 09:01:01 +0100 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-02-11 12:20:48 +0100 |
commit | df2510b3de3aa9909c8451ac813f168f4d6d8a81 (patch) | |
tree | e4b940e97becdb895064887e3df25fc6c7add970 | |
parent | 9e38dcd653981e3b12af225341d21781d9600b10 (diff) | |
download | sonarqube-df2510b3de3aa9909c8451ac813f168f4d6d8a81.tar.gz sonarqube-df2510b3de3aa9909c8451ac813f168f4d6d8a81.zip |
Move IssueSearchTest IT
4 files changed, 441 insertions, 0 deletions
diff --git a/it/it-tests/src/test/java/it/Category2Suite.java b/it/it-tests/src/test/java/it/Category2Suite.java index af7f464ef50..c204d19d74f 100644 --- a/it/it-tests/src/test/java/it/Category2Suite.java +++ b/it/it-tests/src/test/java/it/Category2Suite.java @@ -53,6 +53,7 @@ import it.issue.IssueChangelogTest; import it.issue.IssueFilterExtensionTest; import it.issue.IssueNotificationsTest; import it.issue.IssuePurgeTest; +import it.issue.IssueSearchTest; import it.issue.IssueWorkflowTest; import it.issue.ManualRulesTest; import it.issue.NewIssuesMeasureTest; @@ -95,6 +96,7 @@ import static util.ItUtils.xooPlugin; ManualRulesTest.class, NewIssuesMeasureTest.class, IssueNotificationsTest.class, + IssueSearchTest.class, // debt SqaleRatingMeasureTest.class, TechnicalDebtInIssueChangelogTest.class, diff --git a/it/it-tests/src/test/java/it/issue/IssueSearchTest.java b/it/it-tests/src/test/java/it/issue/IssueSearchTest.java new file mode 100644 index 00000000000..0945578c2d0 --- /dev/null +++ b/it/it-tests/src/test/java/it/issue/IssueSearchTest.java @@ -0,0 +1,339 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package it.issue; + +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.sonar.orchestrator.locator.FileLocation; +import com.sonar.orchestrator.selenium.Selenese; +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import org.apache.commons.lang.time.DateUtils; +import org.assertj.core.api.Fail; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; +import org.sonar.wsclient.base.HttpException; +import org.sonar.wsclient.base.Paging; +import org.sonar.wsclient.component.Component; +import org.sonar.wsclient.issue.ActionPlan; +import org.sonar.wsclient.issue.ActionPlanClient; +import org.sonar.wsclient.issue.Issue; +import org.sonar.wsclient.issue.IssueQuery; +import org.sonar.wsclient.issue.Issues; +import org.sonar.wsclient.issue.NewActionPlan; +import org.sonar.wsclient.issue.NewIssue; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; +import static util.ItUtils.runProjectAnalysis; +import static util.ItUtils.setServerProperty; +import static util.ItUtils.toDate; +import static util.ItUtils.verifyHttpException; + +public class IssueSearchTest extends AbstractIssueTest { + + private static final String PROJECT_KEY = "com.sonarsource.it.samples:multi-modules-sample"; + private static final String PROJECT_KEY2 = "com.sonarsource.it.samples:multi-modules-sample2"; + + private static int DEFAULT_PAGINATED_RESULTS = 100; + private static int TOTAL_NB_ISSUES = 143; + + @BeforeClass + public static void prepareData() { + ORCHESTRATOR.resetData(); + + ORCHESTRATOR.getServer().restoreProfile(FileLocation.ofClasspath("/issue/with-many-rules.xml")); + + // Launch 2 analysis to have more than 100 issues in total + ORCHESTRATOR.getServer().provisionProject(PROJECT_KEY, PROJECT_KEY); + ORCHESTRATOR.getServer().associateProjectToQualityProfile(PROJECT_KEY, "xoo", "with-many-rules"); + runProjectAnalysis(ORCHESTRATOR, "shared/xoo-multi-modules-sample"); + + ORCHESTRATOR.getServer().provisionProject(PROJECT_KEY2, PROJECT_KEY2); + ORCHESTRATOR.getServer().associateProjectToQualityProfile(PROJECT_KEY2, "xoo", "with-many-rules"); + runProjectAnalysis(ORCHESTRATOR, "shared/xoo-multi-modules-sample", "sonar.projectKey", PROJECT_KEY2); + + // Assign a issue to test search by assignee + adminIssueClient().assign(searchRandomIssue().key(), "admin"); + + // Resolve a issue to test search by status and by resolution + adminIssueClient().doTransition(searchRandomIssue().key(), "resolve"); + + // Create a manual issue to test search by reporter + createManualRule(); + adminIssueClient().create( + NewIssue.create().component("com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1:src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo") + .rule("manual:invalidclassname") + .line(3) + .severity("CRITICAL") + .message("The name of the class is invalid")); + } + + @After + public void resetProperties() throws Exception { + setServerProperty(ORCHESTRATOR, "sonar.forceAuthentication", null); + } + + @Test + public void search_all_issues() { + assertThat(search(IssueQuery.create()).list()).hasSize(DEFAULT_PAGINATED_RESULTS); + } + + @Test + public void search_issues_by_component_roots() { + assertThat(search(IssueQuery.create().componentRoots("com.sonarsource.it.samples:multi-modules-sample")).list()).hasSize(72); + assertThat(search(IssueQuery.create().componentRoots("com.sonarsource.it.samples:multi-modules-sample:module_a")).list()).hasSize(44); + assertThat(search(IssueQuery.create().componentRoots("com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1")).list()).hasSize(20); + + assertThat(search(IssueQuery.create().componentRoots("unknown")).list()).isEmpty(); + } + + @Test + public void search_issues_by_components() { + assertThat( + search(IssueQuery.create().components("com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1:src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo")).list()) + .hasSize(19); + assertThat(search(IssueQuery.create().components("unknown")).list()).isEmpty(); + } + + @Test + public void search_issues_by_severities() { + assertThat(search(IssueQuery.create().severities("BLOCKER")).list()).isEmpty(); + assertThat(search(IssueQuery.create().severities("CRITICAL")).list()).hasSize(9); + assertThat(search(IssueQuery.create().severities("MAJOR")).list()).hasSize(8); + assertThat(search(IssueQuery.create().severities("MINOR")).list()).hasSize(DEFAULT_PAGINATED_RESULTS); + assertThat(search(IssueQuery.create().severities("INFO")).list()).hasSize(4); + } + + @Test + public void search_issues_by_statuses() { + assertThat(search(IssueQuery.create().statuses("OPEN")).list()).hasSize(DEFAULT_PAGINATED_RESULTS); + assertThat(search(IssueQuery.create().statuses("RESOLVED")).list()).hasSize(1); + assertThat(search(IssueQuery.create().statuses("CLOSED")).list()).isEmpty(); + } + + @Test + public void search_issues_by_resolutions() { + assertThat(search(IssueQuery.create().resolutions("FIXED")).list()).hasSize(1); + assertThat(search(IssueQuery.create().resolutions("FALSE-POSITIVE")).list()).isEmpty(); + assertThat(search(IssueQuery.create().resolved(true)).list()).hasSize(1); + assertThat(search(IssueQuery.create().resolved(false)).paging().total()).isEqualTo(TOTAL_NB_ISSUES - 1); + } + + @Test + public void search_issues_by_assignees() { + assertThat(search(IssueQuery.create().assignees("admin")).list()).hasSize(1); + assertThat(search(IssueQuery.create().assignees("unknown")).list()).isEmpty(); + assertThat(search(IssueQuery.create().assigned(true)).list()).hasSize(1); + assertThat(search(IssueQuery.create().assigned(false)).paging().total()).isEqualTo(TOTAL_NB_ISSUES - 1); + } + + @Test + public void search_issues_by_reporters() { + assertThat(search(IssueQuery.create().reporters("admin")).list()).hasSize(1); + assertThat(search(IssueQuery.create().reporters("unknown")).list()).isEmpty(); + } + + @Test + public void search_issues_by_rules() { + assertThat(search(IssueQuery.create().rules("xoo:OneIssuePerLine")).list()).hasSize(DEFAULT_PAGINATED_RESULTS); + assertThat(search(IssueQuery.create().rules("xoo:OneIssuePerFile")).list()).hasSize(8); + assertThat(search(IssueQuery.create().rules("manual:invalidclassname")).list()).hasSize(1); + + try { + assertThat(search(IssueQuery.create().rules("unknown")).list()).isEmpty(); + fail(); + } catch (Exception e) { + verifyHttpException(e, 400); + } + } + + /** + * SONAR-2981 + */ + @Test + public void search_issues_by_dates() { + // issues have been created today + Date today = toDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date())); + Date past = toDate("2013-01-01"); + Date future = toDate("2020-12-31"); + + // createdAfter in the future => bad request + try { + search(IssueQuery.create().createdAfter(future)).list(); + Fail.fail("Expecting 400 from issues search WS"); + } catch (HttpException exception) { + assertThat(exception.getMessage()).contains("Start bound cannot be in the future"); + } + + // after date + assertThat(search(IssueQuery.create().createdAfter(today)).list().size()).isGreaterThan(0); + assertThat(search(IssueQuery.create().createdAfter(past)).list().size()).isGreaterThan(0); + + // before + assertThat(search(IssueQuery.create().createdBefore(future)).list().size()).isGreaterThan(0); + assertThat(search(IssueQuery.create().createdBefore(past)).list()).isEmpty(); + + // before and after + assertThat(search(IssueQuery.create().createdBefore(future).createdAfter(past)).list().size()).isGreaterThan(0); + + // createdAfter > createdBefore => bad request + try { + search(IssueQuery.create().createdBefore(past).createdAfter(today)).list(); + Fail.fail("Expecting 400 from issues search WS"); + } catch (HttpException exception) { + assertThat(exception.getMessage()).contains("Start bound cannot be larger than end bound"); + } + + } + + @Test + public void search_issues_by_action_plans() { + // Create an action plan + ActionPlan actionPlan = adminActionPlanClient().create( + NewActionPlan.create().name("Short term").project("com.sonarsource.it.samples:multi-modules-sample").description("Short term issues") + .deadLine(toDate("2113-01-31"))); + + // Associate this action plan to an issue + adminIssueClient().plan(searchRandomIssue().key(), actionPlan.key()); + + assertThat(search(IssueQuery.create().actionPlans(actionPlan.key())).list()).hasSize(1); + assertThat(search(IssueQuery.create().actionPlans("unknown")).list()).isEmpty(); + } + + /** + * SONAR-5132 + */ + @Test + public void search_issues_by_languages() { + assertThat(search(IssueQuery.create().languages("xoo")).list()).hasSize(DEFAULT_PAGINATED_RESULTS); + assertThat(search(IssueQuery.create().languages("foo")).list()).isEmpty(); + } + + @Test + public void paginate_results() { + Issues issues = search(IssueQuery.create().pageSize(20).pageIndex(2)); + + assertThat(issues.list()).hasSize(20); + Paging paging = issues.paging(); + assertThat(paging.pageIndex()).isEqualTo(2); + assertThat(paging.pageSize()).isEqualTo(20); + assertThat(paging.total()).isEqualTo(143); + + // SONAR-3257 + // return max page size results when using negative page size value + assertThat(search(IssueQuery.create().pageSize(0)).list()).hasSize(TOTAL_NB_ISSUES); + assertThat(search(IssueQuery.create().pageSize(-1)).list()).hasSize(TOTAL_NB_ISSUES); + } + + @Test + public void sort_results() { + // 9 issue in CRITICAL (including the manual one), following ones are in MAJOR + List<Issue> issues = search(IssueQuery.create().sort("SEVERITY").asc(false)).list(); + assertThat(issues.get(0).severity()).isEqualTo("CRITICAL"); + assertThat(issues.get(8).severity()).isEqualTo("CRITICAL"); + assertThat(issues.get(9).severity()).isEqualTo("MAJOR"); + } + + /** + * SONAR-4563 + */ + @Test + public void search_by_exact_creation_date() { + final Issue issue = search(IssueQuery.create()).list().get(0); + assertThat(issue.creationDate()).isNotNull(); + + // search the issue key with the same date + assertThat(search(IssueQuery.create().issues().issues(issue.key()).createdAt(issue.creationDate())).list()).hasSize(1); + + // search issue key with 1 second more and less should return nothing + assertThat(search(IssueQuery.create().issues().issues(issue.key()).createdAt(DateUtils.addSeconds(issue.creationDate(), 1))).size()).isEqualTo(0); + assertThat(search(IssueQuery.create().issues().issues(issue.key()).createdAt(DateUtils.addSeconds(issue.creationDate(), -1))).size()).isEqualTo(0); + + // search with future and past dates that do not match any issues + assertThat(search(IssueQuery.create().createdAt(toDate("2020-01-01"))).size()).isEqualTo(0); + assertThat(search(IssueQuery.create().createdAt(toDate("2010-01-01"))).size()).isEqualTo(0); + } + + @Test + public void components_contain_sub_project_id_and_project_id_informations() { + String fileKey = "com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1:src/main/xoo/com/sonar/it/samples/modules/a1/HelloA1.xoo"; + + Issues issues = issueClient().find(IssueQuery.create().components(fileKey)); + assertThat(issues.list()).isNotEmpty(); + + Collection<Component> components = issues.components(); + + Component project = findComponent(components, "com.sonarsource.it.samples:multi-modules-sample"); + assertThat(project.subProjectId()).isNull(); + assertThat(project.projectId()).isNull(); + + Component subModuleA1 = findComponent(components, "com.sonarsource.it.samples:multi-modules-sample:module_a:module_a1"); + assertThat(subModuleA1.subProjectId()).isEqualTo(project.id()); + assertThat(subModuleA1.projectId()).isEqualTo(project.id()); + + Component file = findComponent(components, fileKey); + assertThat(file.subProjectId()).isNotNull(); + assertThat(file.projectId()).isNotNull(); + + Issue issue = issues.list().get(0); + assertThat(issues.component(issue)).isNotNull(); + assertThat(issues.component(issue).subProjectId()).isEqualTo(subModuleA1.id()); + assertThat(issues.component(issue).projectId()).isEqualTo(project.id()); + } + + /** + * SONAR-5659 + */ + @Test + public void redirect_to_search_url_after_wrong_login() { + // Force user authentication to check login on the issues search page + setServerProperty(ORCHESTRATOR, "sonar.forceAuthentication", "true"); + ORCHESTRATOR.executeSelenese(Selenese.builder().setHtmlTestsInClasspath("redirect_to_search_url_after_wrong_login", + "/issue/IssueSearchTest/redirect_to_search_url_after_wrong_login.html" // SONAR-5659 + ).build()); + } + + private static Component findComponent(Collection<Component> components, final String key) { + return Iterables.find(components, new Predicate<Component>() { + @Override + public boolean apply(Component input) { + return key.equals(input.key()); + } + }); + } + + private static void createManualRule() { + ORCHESTRATOR.getServer().adminWsClient().post("/api/rules/create", ImmutableMap.<String, Object>of( + "manual_key", "invalidclassname", + "name", "InvalidClassName", + "markdown_description", "Invalid class name" + )); + } + + private static ActionPlanClient adminActionPlanClient() { + return ORCHESTRATOR.getServer().adminWsClient().actionPlanClient(); + } + +} diff --git a/it/it-tests/src/test/resources/issue/IssueSearchTest/redirect_to_search_url_after_wrong_login.html b/it/it-tests/src/test/resources/issue/IssueSearchTest/redirect_to_search_url_after_wrong_login.html new file mode 100644 index 00000000000..4390d4b8c0e --- /dev/null +++ b/it/it-tests/src/test/resources/issue/IssueSearchTest/redirect_to_search_url_after_wrong_login.html @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> + <tbody> + <tr> + <td>open</td> + <td>/sessions/logout</td> + <td></td> + </tr> + <tr> + <td>open</td> + <td>/issues/search#resolved=true|statuses=OPEN</td> + <td></td> + </tr> + <tr> + <td>assertLocation</td> + <td>*/sessions/new*</td> + <td></td> + </tr> + <tr> + <td>assertElementPresent</td> + <td>login_form</td> + <td></td> + </tr> + <tr> + <td>type</td> + <td>id=login</td> + <td>wrong login</td> + </tr> + <tr> + <td>type</td> + <td>id=password</td> + <td>wrong password</td> + </tr> + <tr> + <td>clickAndWait</td> + <td>commit</td> + <td></td> + </tr> + <tr> + <td>type</td> + <td>id=login</td> + <td>admin</td> + </tr> + <tr> + <td>type</td> + <td>id=password</td> + <td>admin</td> + </tr> + <tr> + <td>clickAndWait</td> + <td>commit</td> + <td></td> + </tr> + <tr> + <td>assertLocation</td> + <td>*#resolved=true|statuses=OPEN*</td> + <td></td> + </tr> + </tbody> +</table> +</body> +</html> diff --git a/it/it-tests/src/test/resources/issue/with-many-rules.xml b/it/it-tests/src/test/resources/issue/with-many-rules.xml new file mode 100644 index 00000000000..a08c9cdd246 --- /dev/null +++ b/it/it-tests/src/test/resources/issue/with-many-rules.xml @@ -0,0 +1,32 @@ +<profile> + <name>with-many-rules</name> + <language>xoo</language> + <rules> + <rule> + <repositoryKey>xoo</repositoryKey> + <key>OneIssuePerLine</key> + <priority>MINOR</priority> + </rule> + <rule> + <repositoryKey>xoo</repositoryKey> + <key>OneIssuePerFile</key> + <priority>MAJOR</priority> + </rule> + <rule> + <repositoryKey>xoo</repositoryKey> + <key>OneIssuePerModule</key> + <priority>CRITICAL</priority> + </rule> + <rule> + <repositoryKey>xoo</repositoryKey> + <key>HasTag</key> + <priority>INFO</priority> + <parameters> + <parameter> + <key>tag</key> + <value>xoo</value> + </parameter> + </parameters> + </rule> + </rules> +</profile> |