]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6635 Check analysis date is after latest analysis 388/head
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 19 Jun 2015 15:02:11 +0000 (17:02 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 19 Jun 2015 15:03:40 +0000 (17:03 +0200)
server/sonar-server/src/main/java/org/sonar/server/computation/step/ValidateProjectStep.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/ValidateProjectStepTest.java

index 58c1292fb636bc28440f5459f770dbcbe5b8b69c..37382a8e8eb084e09793824c4be697485a31403e 100644 (file)
@@ -24,6 +24,7 @@ import com.google.common.base.Function;
 import com.google.common.base.Joiner;
 import com.google.common.collect.FluentIterable;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import javax.annotation.CheckForNull;
@@ -35,6 +36,7 @@ import org.sonar.api.utils.MessageException;
 import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.component.ComponentKeys;
+import org.sonar.core.component.SnapshotDto;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.server.component.db.ComponentDao;
 import org.sonar.server.computation.batch.BatchReportReader;
@@ -43,6 +45,8 @@ import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
 import org.sonar.server.computation.component.TreeRootHolder;
 import org.sonar.server.db.DbClient;
 
+import static org.sonar.api.utils.DateUtils.formatDateTime;
+
 /**
  * Validate project and modules. It will fail in the following cases :
  * <ol>
@@ -121,9 +125,10 @@ public class ValidateProjectStep implements ComputationStep {
       ComponentDto baseProject = loadBaseComponent(rawProjectKey);
       validateWhenProvisioningEnforced(baseProject, rawProjectKey);
       validateProjectKey(baseProject, rawProjectKey);
+      validateAnalysisDate(baseProject);
     }
 
-    private void validateWhenProvisioningEnforced(@Nullable ComponentDto baseProject, String rawProjectKey){
+    private void validateWhenProvisioningEnforced(@Nullable ComponentDto baseProject, String rawProjectKey) {
       if (baseProject == null) {
         if (preventAutomaticProjectCreation) {
           validationMessages.add(String.format("Unable to scan non-existing project '%s'", rawProjectKey));
@@ -131,16 +136,29 @@ public class ValidateProjectStep implements ComputationStep {
       }
     }
 
-    private void validateProjectKey(@Nullable ComponentDto baseProject, String rawProjectKey){
+    private void validateProjectKey(@Nullable ComponentDto baseProject, String rawProjectKey) {
       if (baseProject != null && !baseProject.projectUuid().equals(baseProject.uuid())) {
         // Project key is already used as a module of another project
         ComponentDto anotherBaseProject = componentDao.selectByUuid(session, baseProject.projectUuid());
         validationMessages.add(String.format("The project \"%s\" is already defined in SonarQube but as a module of project \"%s\". "
-            + "If you really want to stop directly analysing project \"%s\", please first delete it from SonarQube and then relaunch the analysis of project \"%s\".",
+          + "If you really want to stop directly analysing project \"%s\", please first delete it from SonarQube and then relaunch the analysis of project \"%s\".",
           rawProjectKey, anotherBaseProject.key(), anotherBaseProject.key(), rawProjectKey));
       }
     }
 
+    private void validateAnalysisDate(@Nullable ComponentDto baseProject) {
+      if (baseProject != null) {
+        SnapshotDto snapshotDto = dbClient.snapshotDao().selectLastSnapshotByComponentId(session, baseProject.getId());
+        long currentAnalysisDate = reportReader.readMetadata().getAnalysisDate();
+        Long lastAnalysisDate = snapshotDto != null ? snapshotDto.getCreatedAt() : null;
+        if (lastAnalysisDate != null && currentAnalysisDate <= snapshotDto.getCreatedAt()) {
+          validationMessages.add(String.format("Date of analysis cannot be older than the date of the last known analysis on this project. Value: \"%s\". " +
+            "Latest analysis: \"%s\". It's only possible to rebuild the past in a chronological order.",
+            formatDateTime(new Date(currentAnalysisDate)), formatDateTime(new Date(lastAnalysisDate))));
+        }
+      }
+    }
+
     @Override
     public void visitModule(Component rawModule) {
       String rawProjectKey = rawProject.getKey();
@@ -156,16 +174,16 @@ public class ValidateProjectStep implements ComputationStep {
       validateModuleKeyIsNotAlreadyUsedInAnotherProject(baseModule, rawModuleKey);
     }
 
-    private void validateModuleIsNotAlreadyUsedAsProject(ComponentDto baseModule, String rawProjectKey, String rawModuleKey){
+    private void validateModuleIsNotAlreadyUsedAsProject(ComponentDto baseModule, String rawProjectKey, String rawModuleKey) {
       if (baseModule.projectUuid().equals(baseModule.uuid())) {
         // module is actually a project
         validationMessages.add(String.format("The project \"%s\" is already defined in SonarQube but not as a module of project \"%s\". "
-            + "If you really want to stop directly analysing project \"%s\", please first delete it from SonarQube and then relaunch the analysis of project \"%s\".",
+          + "If you really want to stop directly analysing project \"%s\", please first delete it from SonarQube and then relaunch the analysis of project \"%s\".",
           rawModuleKey, rawProjectKey, rawModuleKey, rawProjectKey));
       }
     }
 
-    private void validateModuleKeyIsNotAlreadyUsedInAnotherProject(ComponentDto baseModule, String rawModuleKey){
+    private void validateModuleKeyIsNotAlreadyUsedInAnotherProject(ComponentDto baseModule, String rawModuleKey) {
       if (!baseModule.projectUuid().equals(baseModule.uuid()) && !baseModule.projectUuid().equals(rawProject.getUuid())) {
         ComponentDto projectModule = componentDao.selectByUuid(session, baseModule.projectUuid());
         validationMessages.add(String.format("Module \"%s\" is already part of project \"%s\"", rawModuleKey, projectModule.key()));
index cbfab26eab7f2649230d15e4d6efe0096f177a1e..feca62fff9daa0ee0235e7a15361f65e0f81b26c 100644 (file)
@@ -25,6 +25,7 @@ import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.config.Settings;
@@ -35,15 +36,20 @@ import org.sonar.core.component.ComponentDto;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.DbTester;
 import org.sonar.server.component.ComponentTesting;
+import org.sonar.server.component.SnapshotTesting;
 import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.component.db.SnapshotDao;
 import org.sonar.server.computation.batch.BatchReportReaderRule;
 import org.sonar.server.computation.batch.TreeRootHolderRule;
 import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.DumbComponent;
 import org.sonar.server.db.DbClient;
+import org.sonar.test.DbTests;
 
+@Category(DbTests.class)
 public class ValidateProjectStepTest {
 
+  private static long DEFAULT_ANALYSIS_TIME = 1433131200000L; // 2015-06-01
   private static final String PROJECT_KEY = "PROJECT_KEY";
   private static final String MODULE_KEY = "MODULE_KEY";
 
@@ -67,7 +73,7 @@ public class ValidateProjectStepTest {
   @Before
   public void setUp() throws Exception {
     dbTester.truncateTables();
-    dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao());
+    dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao(), new SnapshotDao());
     dbSession = dbClient.openSession(false);
     settings = new Settings();
 
@@ -81,7 +87,7 @@ public class ValidateProjectStepTest {
 
   @Test
   public void not_fail_if_provisioning_enforced_and_project_exists() throws Exception {
-    reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+    reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
     reportReader.putComponent(BatchReport.Component.newBuilder()
       .setRef(1)
       .setType(Constants.ComponentType.PROJECT)
@@ -101,7 +107,7 @@ public class ValidateProjectStepTest {
     thrown.expect(MessageException.class);
     thrown.expectMessage("Unable to scan non-existing project '" + PROJECT_KEY + "'");
 
-    reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+    reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
     reportReader.putComponent(BatchReport.Component.newBuilder()
       .setRef(1)
       .setType(Constants.ComponentType.PROJECT)
@@ -116,7 +122,7 @@ public class ValidateProjectStepTest {
 
   @Test
   public void fail_if_provisioning_not_enforced_and_project_does_not_exists() throws Exception {
-    reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+    reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
     reportReader.putComponent(BatchReport.Component.newBuilder()
       .setRef(1)
       .setType(Constants.ComponentType.PROJECT)
@@ -132,6 +138,7 @@ public class ValidateProjectStepTest {
   @Test
   public void not_fail_on_valid_branch() throws Exception {
     reportReader.setMetadata(BatchReport.Metadata.newBuilder()
+      .setAnalysisDate(DEFAULT_ANALYSIS_TIME)
       .setBranch("origin/master")
       .build());
     reportReader.putComponent(BatchReport.Component.newBuilder()
@@ -151,6 +158,7 @@ public class ValidateProjectStepTest {
       "  o \"bran#ch\" is not a valid branch name. Allowed characters are alphanumeric, '-', '_', '.' and '/'.");
 
     reportReader.setMetadata(BatchReport.Metadata.newBuilder()
+      .setAnalysisDate(DEFAULT_ANALYSIS_TIME)
       .setBranch("bran#ch")
       .build());
     reportReader.putComponent(BatchReport.Component.newBuilder()
@@ -172,7 +180,7 @@ public class ValidateProjectStepTest {
       "  o \"Project\\Key\" is not a valid project or module key. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.\n" +
       "  o \"Module$Key\" is not a valid project or module key. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit");
 
-    reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+    reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
     reportReader.putComponent(BatchReport.Component.newBuilder()
       .setRef(1)
       .setType(Constants.ComponentType.PROJECT)
@@ -199,7 +207,7 @@ public class ValidateProjectStepTest {
       "If you really want to stop directly analysing project \"" + MODULE_KEY + "\", please first delete it from SonarQube and then relaunch the analysis of project \""
       + PROJECT_KEY + "\".");
 
-    reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+    reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
     reportReader.putComponent(BatchReport.Component.newBuilder()
       .setRef(1)
       .setType(Constants.ComponentType.PROJECT)
@@ -230,7 +238,7 @@ public class ValidateProjectStepTest {
     thrown.expectMessage("Validation of project failed:\n" +
       "  o Module \"" + MODULE_KEY + "\" is already part of project \"" + anotherProjectKey + "\"");
 
-    reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+    reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
     reportReader.putComponent(BatchReport.Component.newBuilder()
       .setRef(1)
       .setType(Constants.ComponentType.PROJECT)
@@ -266,7 +274,7 @@ public class ValidateProjectStepTest {
       "If you really want to stop directly analysing project \"" + anotherProjectKey + "\", please first delete it from SonarQube and then relaunch the analysis of project \""
       + PROJECT_KEY + "\".");
 
-    reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+    reportReader.setMetadata(BatchReport.Metadata.newBuilder().setAnalysisDate(DEFAULT_ANALYSIS_TIME).build());
     reportReader.putComponent(BatchReport.Component.newBuilder()
       .setRef(1)
       .setType(Constants.ComponentType.PROJECT)
@@ -291,4 +299,53 @@ public class ValidateProjectStepTest {
 
     sut.execute();
   }
+
+  @Test
+  public void not_fail_if_analysis_date_is_after_last_analysis() throws Exception {
+    reportReader.setMetadata(BatchReport.Metadata.newBuilder()
+      .setAnalysisDate(DEFAULT_ANALYSIS_TIME) // 2015-06-01
+      .build());
+    reportReader.putComponent(BatchReport.Component.newBuilder()
+      .setRef(1)
+      .setType(Constants.ComponentType.PROJECT)
+      .setKey(PROJECT_KEY)
+      .addChildRef(2)
+      .build());
+
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY);
+    dbClient.componentDao().insert(dbSession, project);
+    dbClient.snapshotDao().insert(dbSession, SnapshotTesting.createForProject(project).setCreatedAt(1420088400000L)); // 2015-01-01
+    dbSession.commit();
+
+    treeRootHolder.setRoot(DumbComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).build());
+
+    sut.execute();
+  }
+
+  @Test
+  public void fail_if_analysis_date_is_before_last_analysis() throws Exception {
+    thrown.expect(MessageException.class);
+    thrown.expectMessage("Validation of project failed:");
+    thrown.expectMessage("Date of analysis cannot be older than the date of the last known analysis on this project. Value: ");
+    thrown.expectMessage("Latest analysis: ");
+
+    reportReader.setMetadata(BatchReport.Metadata.newBuilder()
+      .setAnalysisDate(1420088400000L) // 2015-01-01
+      .build());
+    reportReader.putComponent(BatchReport.Component.newBuilder()
+      .setRef(1)
+      .setType(Constants.ComponentType.PROJECT)
+      .setKey(PROJECT_KEY)
+      .addChildRef(2)
+      .build());
+
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY);
+    dbClient.componentDao().insert(dbSession, project);
+    dbClient.snapshotDao().insert(dbSession, SnapshotTesting.createForProject(project).setCreatedAt(1433131200000L)); // 2015-06-01
+    dbSession.commit();
+
+    treeRootHolder.setRoot(DumbComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).build());
+
+    sut.execute();
+  }
 }