From: Julien HENRY Date: Tue, 8 Aug 2017 17:22:52 +0000 (+0200) Subject: SONAR-9661 Add IT for issue backdating on plugin update X-Git-Tag: 6.6-RC1~430 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=0c9958691ea0fb870762e77384555d2a63ec635a;p=sonarqube.git SONAR-9661 Add IT for issue backdating on plugin update --- diff --git a/tests/plugins/backdating-plugin-v1/pom.xml b/tests/plugins/backdating-plugin-v1/pom.xml new file mode 100644 index 00000000000..34cee6c1ca4 --- /dev/null +++ b/tests/plugins/backdating-plugin-v1/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + org.sonarsource.sonarqube + sonarqube + 6.6-SNAPSHOT + ../.. + + backdating-plugin-v1 + SonarQube :: Plugins :: Backdating (V1) + sonar-plugin + Sample of plugin to test issue backdating + + + true + + + + + com.google.guava + guava + + + commons-io + commons-io + + + commons-lang + commons-lang + + + com.google.code.findbugs + jsr305 + provided + + + org.sonarsource.sonarqube + sonar-plugin-api + provided + + + + + junit + junit + test + + + org.assertj + assertj-core + test + + + org.mockito + mockito-core + test + + + + + + + org.sonarsource.sonar-packaging-maven-plugin + sonar-packaging-maven-plugin + + backdating + Foo + org.sonar.backdating.BackdatingPlugin + + + + + diff --git a/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/BackdatingPlugin.java b/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/BackdatingPlugin.java new file mode 100644 index 00000000000..57152b85726 --- /dev/null +++ b/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/BackdatingPlugin.java @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.backdating; + +import org.sonar.api.Plugin; +import org.sonar.backdating.rule.BackRulesDefinition; +import org.sonar.backdating.rule.BackSensorV1; + +/** + * Plugin entry-point, as declared in pom.xml. + */ +public class BackdatingPlugin implements Plugin { + + @Override + public void define(Context context) { + context.addExtensions( + BackRulesDefinition.class, + BackSensorV1.class); + } + +} diff --git a/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/package-info.java b/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/package-info.java new file mode 100644 index 00000000000..7ed72718c44 --- /dev/null +++ b/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.backdating; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/rule/BackRulesDefinition.java b/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/rule/BackRulesDefinition.java new file mode 100644 index 00000000000..d7fe20f2a5d --- /dev/null +++ b/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/rule/BackRulesDefinition.java @@ -0,0 +1,44 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.backdating.rule; + +import org.sonar.api.server.rule.RulesDefinition; + +public class BackRulesDefinition implements RulesDefinition { + + public static final String RULE_KEY = "Rule"; + public static final String BACK_REPOSITORY = "back"; + + @Override + public void define(Context context) { + defineRulesXoo(context); + } + + private static void defineRulesXoo(Context context) { + NewRepository repo = context.createRepository(BACK_REPOSITORY, "xoo").setName("Back"); + createRule(repo, RULE_KEY); + repo.done(); + } + + private static NewRule createRule(NewRepository repo, String key) { + return repo.createRule(key).setName(key).setHtmlDescription(key); + } + +} diff --git a/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/rule/BackSensorV1.java b/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/rule/BackSensorV1.java new file mode 100644 index 00000000000..51cf7a0c671 --- /dev/null +++ b/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/rule/BackSensorV1.java @@ -0,0 +1,63 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.backdating.rule; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.Sensor; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.SensorDescriptor; +import org.sonar.api.batch.sensor.issue.NewIssue; +import org.sonar.api.rule.RuleKey; + +public class BackSensorV1 implements Sensor { + + @Override + public void describe(SensorDescriptor descriptor) { + descriptor.createIssuesForRuleRepositories(BackRulesDefinition.BACK_REPOSITORY) + .onlyOnLanguage("xoo") + .name("Back V1"); + } + + @Override + public void execute(SensorContext context) { + for (InputFile inputFile : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguage("xoo"))) { + int lineNb = 0; + try { + BufferedReader reader = new BufferedReader(new StringReader(inputFile.contents())); + String line; + while ((line = reader.readLine()) != null) { + lineNb++; + if (line.contains("BACKV1")) { + NewIssue newIssue = context.newIssue(); + newIssue.at(newIssue.newLocation().on(inputFile).at(inputFile.selectLine(lineNb))) + .forRule(RuleKey.of(BackRulesDefinition.BACK_REPOSITORY, BackRulesDefinition.RULE_KEY)) + .save(); + } + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + } + +} diff --git a/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/rule/package-info.java b/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/rule/package-info.java new file mode 100644 index 00000000000..02d0eb7fe6f --- /dev/null +++ b/tests/plugins/backdating-plugin-v1/src/main/java/org/sonar/backdating/rule/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.backdating.rule; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/tests/plugins/backdating-plugin-v2/pom.xml b/tests/plugins/backdating-plugin-v2/pom.xml new file mode 100644 index 00000000000..9736566f83c --- /dev/null +++ b/tests/plugins/backdating-plugin-v2/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + org.sonarsource.sonarqube + sonarqube + 6.6-SNAPSHOT + ../.. + + backdating-plugin-v2 + SonarQube :: Plugins :: Backdating (V2) + sonar-plugin + Sample of plugin to test issue backdating + + + true + + + + + com.google.guava + guava + + + commons-io + commons-io + + + commons-lang + commons-lang + + + com.google.code.findbugs + jsr305 + provided + + + org.sonarsource.sonarqube + sonar-plugin-api + provided + + + + + junit + junit + test + + + org.assertj + assertj-core + test + + + org.mockito + mockito-core + test + + + + + + + org.sonarsource.sonar-packaging-maven-plugin + sonar-packaging-maven-plugin + + backdating + Foo + org.sonar.backdating.BackdatingPlugin + + + + + diff --git a/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/BackdatingPlugin.java b/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/BackdatingPlugin.java new file mode 100644 index 00000000000..b79527ccf45 --- /dev/null +++ b/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/BackdatingPlugin.java @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.backdating; + +import org.sonar.api.Plugin; +import org.sonar.backdating.rule.BackRulesDefinition; +import org.sonar.backdating.rule.BackSensorV2; + +/** + * Plugin entry-point, as declared in pom.xml. + */ +public class BackdatingPlugin implements Plugin { + + @Override + public void define(Context context) { + context.addExtensions( + BackRulesDefinition.class, + BackSensorV2.class); + } + +} diff --git a/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/package-info.java b/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/package-info.java new file mode 100644 index 00000000000..7ed72718c44 --- /dev/null +++ b/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.backdating; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/rule/BackRulesDefinition.java b/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/rule/BackRulesDefinition.java new file mode 100644 index 00000000000..d7fe20f2a5d --- /dev/null +++ b/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/rule/BackRulesDefinition.java @@ -0,0 +1,44 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.backdating.rule; + +import org.sonar.api.server.rule.RulesDefinition; + +public class BackRulesDefinition implements RulesDefinition { + + public static final String RULE_KEY = "Rule"; + public static final String BACK_REPOSITORY = "back"; + + @Override + public void define(Context context) { + defineRulesXoo(context); + } + + private static void defineRulesXoo(Context context) { + NewRepository repo = context.createRepository(BACK_REPOSITORY, "xoo").setName("Back"); + createRule(repo, RULE_KEY); + repo.done(); + } + + private static NewRule createRule(NewRepository repo, String key) { + return repo.createRule(key).setName(key).setHtmlDescription(key); + } + +} diff --git a/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/rule/BackSensorV2.java b/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/rule/BackSensorV2.java new file mode 100644 index 00000000000..82864f9a28a --- /dev/null +++ b/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/rule/BackSensorV2.java @@ -0,0 +1,63 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.backdating.rule; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.Sensor; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.SensorDescriptor; +import org.sonar.api.batch.sensor.issue.NewIssue; +import org.sonar.api.rule.RuleKey; + +public class BackSensorV2 implements Sensor { + + @Override + public void describe(SensorDescriptor descriptor) { + descriptor.createIssuesForRuleRepositories(BackRulesDefinition.BACK_REPOSITORY) + .onlyOnLanguage("xoo") + .name("Back V2"); + } + + @Override + public void execute(SensorContext context) { + for (InputFile inputFile : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguage("xoo"))) { + int lineNb = 0; + try { + BufferedReader reader = new BufferedReader(new StringReader(inputFile.contents())); + String line; + while ((line = reader.readLine()) != null) { + lineNb++; + if (line.contains("BACKV1") || line.contains("BACKV2")) { + NewIssue newIssue = context.newIssue(); + newIssue.at(newIssue.newLocation().on(inputFile).at(inputFile.selectLine(lineNb))) + .forRule(RuleKey.of(BackRulesDefinition.BACK_REPOSITORY, BackRulesDefinition.RULE_KEY)) + .save(); + } + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + } + +} diff --git a/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/rule/package-info.java b/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/rule/package-info.java new file mode 100644 index 00000000000..02d0eb7fe6f --- /dev/null +++ b/tests/plugins/backdating-plugin-v2/src/main/java/org/sonar/backdating/rule/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.backdating.rule; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/tests/plugins/pom.xml b/tests/plugins/pom.xml index b5f3af0d112..7ba2dfebd1b 100644 --- a/tests/plugins/pom.xml +++ b/tests/plugins/pom.xml @@ -61,5 +61,7 @@ ui-extensions-plugin posttask-plugin ws-plugin + backdating-plugin-v1 + backdating-plugin-v2 diff --git a/tests/projects/issue/creationDatePluginChanged/sonar-project.properties b/tests/projects/issue/creationDatePluginChanged/sonar-project.properties new file mode 100644 index 00000000000..3a25a96024f --- /dev/null +++ b/tests/projects/issue/creationDatePluginChanged/sonar-project.properties @@ -0,0 +1,5 @@ +sonar.projectKey=creation-date-sample +sonar.projectName=Creation date sample +sonar.projectVersion=SNAPSHOT +sonar.sources=src/main/xoo +sonar.language=xoo diff --git a/tests/projects/issue/creationDatePluginChanged/src/main/xoo/sample/Sample.xoo b/tests/projects/issue/creationDatePluginChanged/src/main/xoo/sample/Sample.xoo new file mode 100644 index 00000000000..879889f64bd --- /dev/null +++ b/tests/projects/issue/creationDatePluginChanged/src/main/xoo/sample/Sample.xoo @@ -0,0 +1,2 @@ +BACKV1 +BACKV2 \ No newline at end of file diff --git a/tests/projects/issue/creationDatePluginChanged/src/main/xoo/sample/Sample.xoo.scm b/tests/projects/issue/creationDatePluginChanged/src/main/xoo/sample/Sample.xoo.scm new file mode 100644 index 00000000000..9f3bb6c0dcb --- /dev/null +++ b/tests/projects/issue/creationDatePluginChanged/src/main/xoo/sample/Sample.xoo.scm @@ -0,0 +1,2 @@ +1,jhenry,2005-01-01T00:00:00+0000 +1,jhenry,2005-01-01T00:00:00+0000 diff --git a/tests/src/test/java/org/sonarqube/tests/Category2Suite.java b/tests/src/test/java/org/sonarqube/tests/Category2Suite.java index c3b8a749925..244ca12aa36 100644 --- a/tests/src/test/java/org/sonarqube/tests/Category2Suite.java +++ b/tests/src/test/java/org/sonarqube/tests/Category2Suite.java @@ -20,12 +20,16 @@ package org.sonarqube.tests; import com.sonar.orchestrator.Orchestrator; +import org.junit.ClassRule; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; import org.sonarqube.tests.issue.AutoAssignTest; import org.sonarqube.tests.issue.CommonRulesTest; import org.sonarqube.tests.issue.CustomRulesTest; import org.sonarqube.tests.issue.IssueActionTest; import org.sonarqube.tests.issue.IssueBulkChangeTest; import org.sonarqube.tests.issue.IssueChangelogTest; +import org.sonarqube.tests.issue.IssueCreationDateQPChangedTest; import org.sonarqube.tests.issue.IssueCreationTest; import org.sonarqube.tests.issue.IssueFilterExtensionTest; import org.sonarqube.tests.issue.IssueFilterOnCommonRulesTest; @@ -51,9 +55,6 @@ import org.sonarqube.tests.test.CoverageTest; import org.sonarqube.tests.test.CoverageTrackingTest; import org.sonarqube.tests.test.NewCoverageTest; import org.sonarqube.tests.test.TestExecutionTest; -import org.junit.ClassRule; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; import static util.ItUtils.pluginArtifact; import static util.ItUtils.xooPlugin; @@ -85,6 +86,7 @@ import static util.ItUtils.xooPlugin; IssueTrackingTest.class, IssueWorkflowTest.class, NewIssuesMeasureTest.class, + IssueCreationDateQPChangedTest.class, // debt MaintainabilityMeasureTest.class, MaintainabilityRatingMeasureTest.class, diff --git a/tests/src/test/java/org/sonarqube/tests/Category5Suite.java b/tests/src/test/java/org/sonarqube/tests/Category5Suite.java index 7bc3331d1d3..9ef6a74a20f 100644 --- a/tests/src/test/java/org/sonarqube/tests/Category5Suite.java +++ b/tests/src/test/java/org/sonarqube/tests/Category5Suite.java @@ -23,10 +23,11 @@ import org.junit.runner.RunWith; import org.junit.runners.Suite; import org.sonarqube.tests.ce.CeShutdownTest; import org.sonarqube.tests.ce.CeWorkersTest; +import org.sonarqube.tests.cluster.ClusterTest; +import org.sonarqube.tests.issue.IssueCreationDatePluginChangedTest; import org.sonarqube.tests.qualityProfile.ActiveRuleEsResilienceTest; import org.sonarqube.tests.qualityProfile.BuiltInQualityProfilesNotificationTest; import org.sonarqube.tests.rule.RuleEsResilienceTest; -import org.sonarqube.tests.cluster.ClusterTest; import org.sonarqube.tests.serverSystem.RestartTest; import org.sonarqube.tests.serverSystem.ServerSystemRestartingOrchestrator; import org.sonarqube.tests.settings.ElasticsearchSettingsTest; @@ -66,6 +67,8 @@ import org.sonarqube.tests.user.UserEsResilienceTest; // ce CeShutdownTest.class, CeWorkersTest.class, + // issues + IssueCreationDatePluginChangedTest.class, // elasticsearch ElasticsearchSettingsTest.class diff --git a/tests/src/test/java/org/sonarqube/tests/issue/IssueCreationDatePluginChangedTest.java b/tests/src/test/java/org/sonarqube/tests/issue/IssueCreationDatePluginChangedTest.java new file mode 100644 index 00000000000..e5bd0a3d55c --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/issue/IssueCreationDatePluginChangedTest.java @@ -0,0 +1,123 @@ +/* + * 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.issue; + +import com.sonar.orchestrator.Orchestrator; +import com.sonar.orchestrator.build.SonarScanner; +import java.io.File; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.wsclient.issue.Issue; +import org.sonar.wsclient.issue.IssueQuery; +import org.sonarqube.ws.client.PostRequest; +import util.ItUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static util.ItUtils.pluginArtifact; +import static util.ItUtils.projectDir; +import static util.ItUtils.xooPlugin; + +/** + * @see MMF-766 + */ +public class IssueCreationDatePluginChangedTest { + + private static final String ISSUE_STATUS_OPEN = "OPEN"; + + private static final String LANGUAGE_XOO = "xoo"; + + private static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ"; + + private static final String SAMPLE_PROJECT_KEY = "creation-date-sample"; + private static final String SAMPLE_PROJECT_NAME = "Creation date sample"; + private static final String SAMPLE_QUALITY_PROFILE_NAME = "creation-date-plugin"; + + @ClassRule + public static final Orchestrator ORCHESTRATOR = Orchestrator.builderEnv() + .addPlugin(xooPlugin()) + .addPlugin(ItUtils.pluginArtifact("backdating-plugin-v1")) + .build(); + + @Before + public void cleanup() { + ORCHESTRATOR.resetData(); + } + + @Test + public void should_use_scm_date_for_new_issues_if_plugin_updated() { + ItUtils.restoreProfile(ORCHESTRATOR, getClass().getResource("/issue/IssueCreationDatePluginChangedTest/one-rule.xml")); + + ORCHESTRATOR.getServer().provisionProject(SAMPLE_PROJECT_KEY, SAMPLE_PROJECT_NAME); + ORCHESTRATOR.getServer().associateProjectToQualityProfile(SAMPLE_PROJECT_KEY, LANGUAGE_XOO, SAMPLE_QUALITY_PROFILE_NAME); + + // First analysis + SonarScanner scanner = SonarScanner.create(projectDir("issue/creationDatePluginChanged")) + .setProperty("sonar.scm.provider", "xoo") + .setProperty("sonar.scm.disabled", "false"); + ORCHESTRATOR.executeBuild(scanner); + + List issues = getIssues(issueQuery().components("creation-date-sample:src/main/xoo/sample/Sample.xoo")); + + // Check that issue is backdated to SCM (because it is the first analysis) + assertThat(issues) + .extracting(Issue::line, Issue::creationDate) + .containsExactly(tuple(1, dateTimeParse("2005-01-01T00:00:00+0000"))); + + // Update the plugin + // uninstall plugin V1 + ItUtils.newAdminWsClient(ORCHESTRATOR).wsConnector().call(new PostRequest("api/plugins/uninstall").setParam("key", "backdating")).failIfNotSuccessful(); + // install plugin V2 + File pluginsDir = new File(ORCHESTRATOR.getServer().getHome() + "/extensions/plugins"); + ORCHESTRATOR.getConfiguration().fileSystem().copyToDirectory(pluginArtifact("backdating-plugin-v2"), pluginsDir); + + ORCHESTRATOR.restartServer(); + + // New analysis that should raise a new issue + ORCHESTRATOR.executeBuild(scanner); + issues = getIssues(issueQuery().components("creation-date-sample:src/main/xoo/sample/Sample.xoo")); + assertThat(issues) + .extracting(Issue::line, Issue::creationDate) + .containsExactly(tuple(1, dateTimeParse("2005-01-01T00:00:00+0000")), + tuple(2, dateTimeParse("2005-01-01T00:00:00+0000"))); + } + + private static List getIssues(IssueQuery query) { + return ORCHESTRATOR.getServer().wsClient().issueClient().find(query).list(); + } + + private static IssueQuery issueQuery() { + return IssueQuery.create().statuses(ISSUE_STATUS_OPEN); + } + + private static Date dateTimeParse(String expectedDate) { + try { + return new SimpleDateFormat(DATETIME_FORMAT).parse(expectedDate); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/tests/src/test/java/org/sonarqube/tests/issue/IssueCreationDateQPChangedTest.java b/tests/src/test/java/org/sonarqube/tests/issue/IssueCreationDateQPChangedTest.java new file mode 100644 index 00000000000..c454ab681da --- /dev/null +++ b/tests/src/test/java/org/sonarqube/tests/issue/IssueCreationDateQPChangedTest.java @@ -0,0 +1,370 @@ +/* + * 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.issue; + +import com.sonar.orchestrator.build.SonarScanner; +import com.sonar.orchestrator.container.Server; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; +import org.junit.Before; +import org.junit.Test; +import org.sonar.wsclient.issue.Issue; +import org.sonar.wsclient.issue.IssueQuery; +import org.sonarqube.ws.ProjectAnalyses; +import org.sonarqube.ws.client.projectanalysis.SearchRequest; +import util.ItUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static util.ItUtils.projectDir; + +/** + * @see MMF-567 + */ +public class IssueCreationDateQPChangedTest extends AbstractIssueTest { + + private static final String ISSUE_STATUS_OPEN = "OPEN"; + + private static final String LANGUAGE_XOO = "xoo"; + + private static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ"; + + private static final String SAMPLE_PROJECT_KEY = "creation-date-sample"; + private static final String SAMPLE_PROJECT_NAME = "Creation date sample"; + private static final String SAMPLE_QUALITY_PROFILE_NAME = "creation-date-quality-profile"; + private static final String SAMPLE_EXPLICIT_DATE_1 = todayMinusDays(2); + private static final String SAMPLE_EXPLICIT_DATE_2 = todayMinusDays(1); + + private Server server = ORCHESTRATOR.getServer(); + + @Before + public void resetData() { + ORCHESTRATOR.resetData(); + server.provisionProject(SAMPLE_PROJECT_KEY, SAMPLE_PROJECT_NAME); + } + + @Test + public void should_use_scm_date_for_new_issues_if_scm_is_available() { + analysis(QProfile.ONE_RULE, SourceCode.INITIAL, ScannerFeature.SCM); + + assertNumberOfIssues(3); + assertIssueCreationDate(Component.OnlyInInitial, IssueCreationDate.OnlyInInitial_R1); + assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R1); + assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1); + } + + @Test + public void should_use_analysis_date_for_new_issues_if_scm_is_not_available() { + analysis(QProfile.ONE_RULE, SourceCode.INITIAL); + + assertNumberOfIssues(3); + assertIssueCreationDates(COMPONENTS_OF_SOURCE_INITIAL, IssueCreationDate.FIRST_ANALYSIS); + } + + @Test + public void use_explicit_project_date_if_scm_is_not_available() { + analysis(QProfile.ONE_RULE, SourceCode.INITIAL, ScannerFeature.EXPLICIT_DATE_1); + + assertNumberOfIssues(3); + assertIssueCreationDates(COMPONENTS_OF_SOURCE_INITIAL, IssueCreationDate.EXPLICIT_DATE_1); + } + + @Test + public void use_scm_date_even_if_explicit_project_date_is_set() { + analysis(QProfile.ONE_RULE, SourceCode.INITIAL, ScannerFeature.SCM, ScannerFeature.EXPLICIT_DATE_1); + + assertNumberOfIssues(3); + assertIssueCreationDate(Component.OnlyInInitial, IssueCreationDate.OnlyInInitial_R1); + assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R1); + assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1); + } + + @Test + public void no_rules_no_issues_if_scm_is_available() { + analysis(QProfile.NO_RULES, SourceCode.INITIAL, ScannerFeature.SCM); + + assertNoIssue(); + } + + @Test + public void no_rules_no_issues_if_scm_is_not_available() { + analysis(QProfile.NO_RULES, SourceCode.INITIAL); + + assertNoIssue(); + } + + @Test + public void use_scm_date_for_issues_raised_by_new_rules_if_scm_is_newly_available() { + analysis(QProfile.NO_RULES, SourceCode.INITIAL); + analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.SCM); + + assertNumberOfIssues(3); + assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R2); + assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1); + assertIssueCreationDate(Component.OnlyInChanged, IssueCreationDate.OnlyInChanged_R1); + } + + @Test + public void use_scm_date_for_issues_raised_by_new_rules_if_scm_is_available_and_ever_has_been_available() { + analysis(QProfile.NO_RULES, SourceCode.INITIAL, ScannerFeature.SCM); + analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.SCM); + + assertNumberOfIssues(3); + assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R2); + assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1); + assertIssueCreationDate(Component.OnlyInChanged, IssueCreationDate.OnlyInChanged_R1); + } + + @Test + public void use_analysis_date_for_issues_raised_by_new_rules_if_scm_is_not_available() { + analysis(QProfile.NO_RULES, SourceCode.INITIAL); + analysis(QProfile.ONE_RULE, SourceCode.CHANGED); + + assertNumberOfIssues(3); + Stream.of(COMPONENTS_OF_SOURCE_CHANGED) + .forEach(component -> { + assertIssueCreationDate(component, IssueCreationDate.LATEST_ANALYSIS); + }); + } + + @Test + public void keep_the_date_of_an_existing_issue_even_if_the_blame_information_changes() { + analysis(QProfile.ONE_RULE, SourceCode.INITIAL, ScannerFeature.SCM); + analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.SCM); + + assertNumberOfIssues(3); + assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R1); + assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1); + + // this file is new to the second analysis + assertIssueCreationDate(Component.OnlyInChanged, IssueCreationDate.LATEST_ANALYSIS); + } + + @Test + public void ignore_explicit_date_for_issues_related_to_new_rules_if_scm_is_available() { + analysis(QProfile.NO_RULES, SourceCode.INITIAL, ScannerFeature.SCM, ScannerFeature.EXPLICIT_DATE_1); + analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.SCM, ScannerFeature.EXPLICIT_DATE_2); + + assertNumberOfIssues(3); + assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R2); + assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1); + assertIssueCreationDate(Component.OnlyInChanged, IssueCreationDate.OnlyInChanged_R1); + } + + @Test + public void use_explicit_date_for_issues_related_to_new_rules_if_scm_is_not_available() { + analysis(QProfile.NO_RULES, SourceCode.INITIAL, ScannerFeature.EXPLICIT_DATE_1); + analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.EXPLICIT_DATE_2); + + assertNumberOfIssues(3); + assertIssueCreationDates(COMPONENTS_OF_SOURCE_CHANGED, IssueCreationDate.EXPLICIT_DATE_2); + } + + private void analysis(QProfile qProfile, SourceCode sourceCode, ScannerFeature... scm) { + ItUtils.restoreProfile(ORCHESTRATOR, getClass().getResource(qProfile.path)); + server.associateProjectToQualityProfile(SAMPLE_PROJECT_KEY, LANGUAGE_XOO, SAMPLE_QUALITY_PROFILE_NAME); + + SonarScanner scanner = SonarScanner.create(projectDir(sourceCode.path)); + Arrays.stream(scm).forEach(s -> s.configure(scanner)); + ORCHESTRATOR.executeBuild(scanner); + } + + private static void assertNoIssue() { + assertNumberOfIssues(0); + } + + private static void assertNumberOfIssues(int number) { + assertThat(getIssues(issueQuery())).hasSize(number); + } + + private static void assertIssueCreationDate(Component component, IssueCreationDate expectedDate) { + assertIssueCreationDates(new Component[] {component}, expectedDate); + } + + private static void assertIssueCreationDates(Component[] components, IssueCreationDate expectedDate) { + String[] keys = Arrays.stream(components).map(Component::getKey).toArray(String[]::new); + List issues = getIssues(issueQuery().components(keys)); + Date[] dates = Arrays.stream(components).map(x -> expectedDate.getDate()).toArray(Date[]::new); + + assertThat(issues) + .extracting(Issue::creationDate) + .containsExactly(dates); + } + + private static List getIssues(IssueQuery query) { + return issueClient().find(query).list(); + } + + private static IssueQuery issueQuery() { + return IssueQuery.create().statuses(ISSUE_STATUS_OPEN); + } + + private static Date dateTimeParse(String expectedDate) { + try { + return new SimpleDateFormat(DATETIME_FORMAT).parse(expectedDate); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + private static String todayMinusDays(int numberOfDays) { + return DateTimeFormatter.ofPattern(DATETIME_FORMAT).format(LocalDate.now().atStartOfDay().minusDays(numberOfDays).atZone(ZoneId.systemDefault())); + } + + private enum SourceCode { + INITIAL("issue/creationDateSampleInitial"), + CHANGED("issue/creationDateSampleChanged"), + ; + + private final String path; + + private SourceCode(String path) { + this.path = path; + } + } + + private enum Component { + OnlyInInitial("creation-date-sample:src/main/xoo/sample/OnlyInInitial.xoo"), + ForeverAndModified("creation-date-sample:src/main/xoo/sample/ForeverAndModified.xoo"), + ForeverAndUnmodified("creation-date-sample:src/main/xoo/sample/ForeverAndUnmodified.xoo"), + OnlyInChanged("creation-date-sample:src/main/xoo/sample/OnlyInChanged.xoo"), + ; + private final String key; + + private Component(String key) { + this.key = key; + } + + public String getKey() { + return key; + } + } + + private static final Component[] COMPONENTS_OF_SOURCE_INITIAL = {Component.OnlyInInitial, Component.ForeverAndModified, Component.ForeverAndUnmodified}; + private static final Component[] COMPONENTS_OF_SOURCE_CHANGED = {Component.ForeverAndModified, Component.ForeverAndUnmodified, Component.OnlyInChanged}; + + private enum QProfile { + ONE_RULE("/issue/IssueCreationDateQPChangedTest/one-rule.xml"), + NO_RULES("/issue/IssueCreationDateQPChangedTest/no-rules.xml"), + ; + + private final String path; + + private QProfile(String path) { + this.path = path; + } + } + + private enum ScannerFeature { + SCM { + @Override + void configure(SonarScanner scanner) { + scanner + .setProperty("sonar.scm.provider", "xoo") + .setProperty("sonar.scm.disabled", "false"); + } + }, + EXPLICIT_DATE_1 { + @Override + void configure(SonarScanner scanner) { + scanner + .setProperty("sonar.projectDate", SAMPLE_EXPLICIT_DATE_1); + } + }, + EXPLICIT_DATE_2 { + @Override + void configure(SonarScanner scanner) { + scanner + .setProperty("sonar.projectDate", SAMPLE_EXPLICIT_DATE_2); + } + }, + ; + + void configure(SonarScanner scanner) { + } + } + + private enum IssueCreationDate { + OnlyInInitial_R1(dateTimeParse("2001-01-01T00:00:00+0000")), + ForeverAndUnmodified_R1(dateTimeParse("2002-01-01T00:00:00+0000")), + ForeverAndModified_R1(dateTimeParse("2003-01-01T00:00:00+0000")), + ForeverAndModified_R2(dateTimeParse("2004-01-01T00:00:00+0000")), + OnlyInChanged_R1(dateTimeParse("2005-01-01T00:00:00+0000")), + EXPLICIT_DATE_1(dateTimeParse(SAMPLE_EXPLICIT_DATE_1)), + EXPLICIT_DATE_2(dateTimeParse(SAMPLE_EXPLICIT_DATE_2)), + FIRST_ANALYSIS { + @Override + Date getDate() { + return getAnalysisDate(l -> { + if (l.isEmpty()) { + return Optional.empty(); + } + return Optional.of(l.get(l.size() - 1)); + }); + } + }, + LATEST_ANALYSIS { + @Override + Date getDate() { + return getAnalysisDate(l -> { + if (l.size() > 0) { + return Optional.of(l.get(0)); + } + return Optional.empty(); + }); + } + }, + ; + + private final Date date; + + private IssueCreationDate() { + this.date = null; + } + + private IssueCreationDate(Date date) { + this.date = date; + } + + Date getDate() { + return date; + } + + private static Date getAnalysisDate(Function, Optional> chooseItem) { + return Optional.of( + ItUtils.newWsClient(ORCHESTRATOR) + .projectAnalysis() + .search(SearchRequest.builder().setProject(SAMPLE_PROJECT_KEY).build()) + .getAnalysesList()) + .flatMap(chooseItem) + .map(ProjectAnalyses.Analysis::getDate) + .map(IssueCreationDateQPChangedTest::dateTimeParse) + .orElseThrow(() -> new IllegalStateException("There is no analysis")); + } + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/issue/IssueCreationDateTest.java b/tests/src/test/java/org/sonarqube/tests/issue/IssueCreationDateTest.java deleted file mode 100644 index 47ce6e5ac9f..00000000000 --- a/tests/src/test/java/org/sonarqube/tests/issue/IssueCreationDateTest.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonarqube.tests.issue; - -import com.sonar.orchestrator.build.SonarScanner; -import com.sonar.orchestrator.container.Server; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Stream; -import org.junit.Before; -import org.junit.Test; -import org.sonar.wsclient.issue.Issue; -import org.sonar.wsclient.issue.IssueQuery; -import org.sonarqube.ws.ProjectAnalyses; -import org.sonarqube.ws.client.projectanalysis.SearchRequest; -import util.ItUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static util.ItUtils.projectDir; - -/** - * @see MMF-567 - */ -public class IssueCreationDateTest extends AbstractIssueTest { - - private static final String ISSUE_STATUS_OPEN = "OPEN"; - - private static final String LANGUAGE_XOO = "xoo"; - - private static final String DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ"; - private static final String DATE_FORMAT = "yyyy-MM-dd"; - - private static final String SAMPLE_PROJECT_KEY = "creation-date-sample"; - private static final String SAMPLE_PROJECT_NAME = "Creation date sample"; - private static final String SAMPLE_QUALITY_PROFILE_NAME = "creation-date-quality-profile"; - private static final String SAMPLE_EXPLICIT_DATE_1 = todayMinusDays(2); - private static final String SAMPLE_EXPLICIT_DATE_2 = todayMinusDays(1); - - private Server server = ORCHESTRATOR.getServer(); - - @Before - public void resetData() { - ORCHESTRATOR.resetData(); - server.provisionProject(SAMPLE_PROJECT_KEY, SAMPLE_PROJECT_NAME); - } - - @Test - public void should_use_scm_date_for_new_issues_if_scm_is_available() { - analysis(QProfile.ONE_RULE, SourceCode.INITIAL, ScannerFeature.SCM); - - assertNumberOfIssues(3); - assertIssueCreationDate(Component.OnlyInInitial, IssueCreationDate.OnlyInInitial_R1); - assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R1); - assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1); - } - - @Test - public void should_use_analysis_date_for_new_issues_if_scm_is_not_available() { - analysis(QProfile.ONE_RULE, SourceCode.INITIAL); - - assertNumberOfIssues(3); - assertIssueCreationDates(COMPONENTS_OF_SOURCE_INITIAL, IssueCreationDate.FIRST_ANALYSIS); - } - - @Test - public void use_explicit_project_date_if_scm_is_not_available() { - analysis(QProfile.ONE_RULE, SourceCode.INITIAL, ScannerFeature.EXPLICIT_DATE_1); - - assertNumberOfIssues(3); - assertIssueCreationDates(COMPONENTS_OF_SOURCE_INITIAL, IssueCreationDate.EXPLICIT_DATE_1); - } - - @Test - public void use_scm_date_even_if_explicit_project_date_is_set() { - analysis(QProfile.ONE_RULE, SourceCode.INITIAL, ScannerFeature.SCM, ScannerFeature.EXPLICIT_DATE_1); - - assertNumberOfIssues(3); - assertIssueCreationDate(Component.OnlyInInitial, IssueCreationDate.OnlyInInitial_R1); - assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R1); - assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1); - } - - @Test - public void no_rules_no_issues_if_scm_is_available() { - analysis(QProfile.NO_RULES, SourceCode.INITIAL, ScannerFeature.SCM); - - assertNoIssue(); - } - - @Test - public void no_rules_no_issues_if_scm_is_not_available() { - analysis(QProfile.NO_RULES, SourceCode.INITIAL); - - assertNoIssue(); - } - - @Test - public void use_scm_date_for_issues_raised_by_new_rules_if_scm_is_newly_available() { - analysis(QProfile.NO_RULES, SourceCode.INITIAL); - analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.SCM); - - assertNumberOfIssues(3); - assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R2); - assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1); - assertIssueCreationDate(Component.OnlyInChanged, IssueCreationDate.OnlyInChanged_R1); - } - - @Test - public void use_scm_date_for_issues_raised_by_new_rules_if_scm_is_available_and_ever_has_been_available() { - analysis(QProfile.NO_RULES, SourceCode.INITIAL, ScannerFeature.SCM); - analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.SCM); - - assertNumberOfIssues(3); - assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R2); - assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1); - assertIssueCreationDate(Component.OnlyInChanged, IssueCreationDate.OnlyInChanged_R1); - } - - @Test - public void use_analysis_date_for_issues_raised_by_new_rules_if_scm_is_not_available() { - analysis(QProfile.NO_RULES, SourceCode.INITIAL); - analysis(QProfile.ONE_RULE, SourceCode.CHANGED); - - assertNumberOfIssues(3); - Stream.of(COMPONENTS_OF_SOURCE_CHANGED) - .forEach(component -> { - assertIssueCreationDate(component, IssueCreationDate.LATEST_ANALYSIS); - }); - } - - @Test - public void keep_the_date_of_an_existing_issue_even_if_the_blame_information_changes() { - analysis(QProfile.ONE_RULE, SourceCode.INITIAL, ScannerFeature.SCM); - analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.SCM); - - assertNumberOfIssues(3); - assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R1); - assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1); - - // this file is new to the second analysis - assertIssueCreationDate(Component.OnlyInChanged, IssueCreationDate.LATEST_ANALYSIS); - } - - @Test - public void ignore_explicit_date_for_issues_related_to_new_rules_if_scm_is_available() { - analysis(QProfile.NO_RULES, SourceCode.INITIAL, ScannerFeature.SCM, ScannerFeature.EXPLICIT_DATE_1); - analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.SCM, ScannerFeature.EXPLICIT_DATE_2); - - assertNumberOfIssues(3); - assertIssueCreationDate(Component.ForeverAndModified, IssueCreationDate.ForeverAndModified_R2); - assertIssueCreationDate(Component.ForeverAndUnmodified, IssueCreationDate.ForeverAndUnmodified_R1); - assertIssueCreationDate(Component.OnlyInChanged, IssueCreationDate.OnlyInChanged_R1); - } - - @Test - public void use_explicit_date_for_issues_related_to_new_rules_if_scm_is_not_available() { - analysis(QProfile.NO_RULES, SourceCode.INITIAL, ScannerFeature.EXPLICIT_DATE_1); - analysis(QProfile.ONE_RULE, SourceCode.CHANGED, ScannerFeature.EXPLICIT_DATE_2); - - assertNumberOfIssues(3); - assertIssueCreationDates(COMPONENTS_OF_SOURCE_CHANGED, IssueCreationDate.EXPLICIT_DATE_2); - } - - private void analysis(QProfile qProfile, SourceCode sourceCode, ScannerFeature... scm) { - ItUtils.restoreProfile(ORCHESTRATOR, getClass().getResource(qProfile.path)); - server.associateProjectToQualityProfile(SAMPLE_PROJECT_KEY, LANGUAGE_XOO, SAMPLE_QUALITY_PROFILE_NAME); - - SonarScanner scanner = SonarScanner.create(projectDir(sourceCode.path)); - Arrays.stream(scm).forEach(s -> s.configure(scanner)); - ORCHESTRATOR.executeBuild(scanner); - } - - private static void assertNoIssue() { - assertNumberOfIssues(0); - } - - private static void assertNumberOfIssues(int number) { - assertThat(getIssues(issueQuery())).hasSize(number); - } - - private static void assertIssueCreationDate(Component component, IssueCreationDate expectedDate) { - assertIssueCreationDates(new Component[] {component}, expectedDate); - } - - private static void assertIssueCreationDates(Component[] components, IssueCreationDate expectedDate) { - String[] keys = Arrays.stream(components).map(Component::getKey).toArray(String[]::new); - List issues = getIssues(issueQuery().components(keys)); - Date[] dates = Arrays.stream(components).map(x -> expectedDate.getDate()).toArray(Date[]::new); - - assertThat(issues) - .extracting(Issue::creationDate) - .containsExactly(dates); - } - - private static List getIssues(IssueQuery query) { - return issueClient().find(query).list(); - } - - private static IssueQuery issueQuery() { - return IssueQuery.create().statuses(ISSUE_STATUS_OPEN); - } - - private static Date dateTimeParse(String expectedDate) { - try { - return new SimpleDateFormat(DATETIME_FORMAT).parse(expectedDate); - } catch (ParseException e) { - throw new RuntimeException(e); - } - } - - private static Date dateParse(String expectedDate) { - try { - return new SimpleDateFormat(DATE_FORMAT).parse(expectedDate); - } catch (ParseException e) { - throw new RuntimeException(e); - } - } - - private static String todayMinusDays(int numberOfDays) { - return DateTimeFormatter.ofPattern(DATE_FORMAT).format(LocalDate.now().atStartOfDay().minusDays(numberOfDays)); - } - - private enum SourceCode { - INITIAL("issue/creationDateSampleInitial"), - CHANGED("issue/creationDateSampleChanged"), - ; - - private final String path; - - private SourceCode(String path) { - this.path = path; - } - } - - private enum Component { - OnlyInInitial("creation-date-sample:src/main/xoo/sample/OnlyInInitial.xoo"), - ForeverAndModified("creation-date-sample:src/main/xoo/sample/ForeverAndModified.xoo"), - ForeverAndUnmodified("creation-date-sample:src/main/xoo/sample/ForeverAndUnmodified.xoo"), - OnlyInChanged("creation-date-sample:src/main/xoo/sample/OnlyInChanged.xoo"), - ; - private final String key; - - private Component(String key) { - this.key = key; - } - - public String getKey() { - return key; - } - } - - private static final Component[] COMPONENTS_OF_SOURCE_INITIAL = {Component.OnlyInInitial, Component.ForeverAndModified, Component.ForeverAndUnmodified}; - private static final Component[] COMPONENTS_OF_SOURCE_CHANGED = {Component.ForeverAndModified, Component.ForeverAndUnmodified, Component.OnlyInChanged}; - - private enum QProfile { - ONE_RULE("/issue/IssueCreationDateTest/one-rule.xml"), - NO_RULES("/issue/IssueCreationDateTest/no-rules.xml"), - ; - - private final String path; - - private QProfile(String path) { - this.path = path; - } - } - - private enum ScannerFeature { - SCM { - @Override - void configure(SonarScanner scanner) { - scanner - .setProperty("sonar.scm.provider", "xoo") - .setProperty("sonar.scm.disabled", "false"); - } - }, - EXPLICIT_DATE_1 { - @Override - void configure(SonarScanner scanner) { - scanner - .setProperty("sonar.projectDate", SAMPLE_EXPLICIT_DATE_1); - } - }, - EXPLICIT_DATE_2 { - @Override - void configure(SonarScanner scanner) { - scanner - .setProperty("sonar.projectDate", SAMPLE_EXPLICIT_DATE_2); - } - }, - ; - - void configure(SonarScanner scanner) { - } - } - - private enum IssueCreationDate { - OnlyInInitial_R1(dateTimeParse("2001-01-01T00:00:00+0000")), - ForeverAndUnmodified_R1(dateTimeParse("2002-01-01T00:00:00+0000")), - ForeverAndModified_R1(dateTimeParse("2003-01-01T00:00:00+0000")), - ForeverAndModified_R2(dateTimeParse("2004-01-01T00:00:00+0000")), - OnlyInChanged_R1(dateTimeParse("2005-01-01T00:00:00+0000")), - EXPLICIT_DATE_1(dateParse(SAMPLE_EXPLICIT_DATE_1)), - EXPLICIT_DATE_2(dateParse(SAMPLE_EXPLICIT_DATE_2)), - FIRST_ANALYSIS { - @Override - Date getDate() { - return getAnalysisDate(l -> { - if (l.isEmpty()) { - return Optional.empty(); - } - return Optional.of(l.get(l.size() - 1)); - }); - } - }, - LATEST_ANALYSIS { - @Override - Date getDate() { - return getAnalysisDate(l -> { - if (l.size() > 0) { - return Optional.of(l.get(0)); - } - return Optional.empty(); - }); - } - }, - ; - - private final Date date; - - private IssueCreationDate() { - this.date = null; - } - - private IssueCreationDate(Date date) { - this.date = date; - } - - Date getDate() { - return date; - } - - private static Date getAnalysisDate(Function, Optional> chooseItem) { - return Optional.of( - ItUtils.newWsClient(ORCHESTRATOR) - .projectAnalysis() - .search(SearchRequest.builder().setProject(SAMPLE_PROJECT_KEY).build()) - .getAnalysesList()) - .flatMap(chooseItem) - .map(ProjectAnalyses.Analysis::getDate) - .map(IssueCreationDateTest::dateTimeParse) - .orElseThrow(() -> new IllegalStateException("There is no analysis")); - } - } -} diff --git a/tests/src/test/resources/issue/IssueCreationDatePluginChangedTest/one-rule.xml b/tests/src/test/resources/issue/IssueCreationDatePluginChangedTest/one-rule.xml new file mode 100644 index 00000000000..8857d01b00f --- /dev/null +++ b/tests/src/test/resources/issue/IssueCreationDatePluginChangedTest/one-rule.xml @@ -0,0 +1,11 @@ + + creation-date-plugin + xoo + + + back + Rule + MAJOR + + + diff --git a/tests/src/test/resources/issue/IssueCreationDateQPChangedTest/no-rules.xml b/tests/src/test/resources/issue/IssueCreationDateQPChangedTest/no-rules.xml new file mode 100644 index 00000000000..62ec52d9d10 --- /dev/null +++ b/tests/src/test/resources/issue/IssueCreationDateQPChangedTest/no-rules.xml @@ -0,0 +1,6 @@ + + creation-date-quality-profile + xoo + + + diff --git a/tests/src/test/resources/issue/IssueCreationDateQPChangedTest/one-rule.xml b/tests/src/test/resources/issue/IssueCreationDateQPChangedTest/one-rule.xml new file mode 100644 index 00000000000..c1d7d44f02c --- /dev/null +++ b/tests/src/test/resources/issue/IssueCreationDateQPChangedTest/one-rule.xml @@ -0,0 +1,11 @@ + + creation-date-quality-profile + xoo + + + xoo + OneIssuePerFile + MAJOR + + + diff --git a/tests/src/test/resources/issue/IssueCreationDateTest/no-rules.xml b/tests/src/test/resources/issue/IssueCreationDateTest/no-rules.xml deleted file mode 100644 index 62ec52d9d10..00000000000 --- a/tests/src/test/resources/issue/IssueCreationDateTest/no-rules.xml +++ /dev/null @@ -1,6 +0,0 @@ - - creation-date-quality-profile - xoo - - - diff --git a/tests/src/test/resources/issue/IssueCreationDateTest/one-rule.xml b/tests/src/test/resources/issue/IssueCreationDateTest/one-rule.xml deleted file mode 100644 index c1d7d44f02c..00000000000 --- a/tests/src/test/resources/issue/IssueCreationDateTest/one-rule.xml +++ /dev/null @@ -1,11 +0,0 @@ - - creation-date-quality-profile - xoo - - - xoo - OneIssuePerFile - MAJOR - - -