]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5911 persist issues on server side
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Thu, 18 Dec 2014 18:11:14 +0000 (19:11 +0100)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Wed, 24 Dec 2014 12:20:54 +0000 (13:20 +0100)
33 files changed:
server/sonar-server/src/main/java/org/sonar/server/computation/AnalysisReportService.java
server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineContext.java
server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineIssueStorage.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineIssueStorageFactory.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/db/AnalysisReportDao.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/DataCleanerStep.java
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/test/java/org/sonar/server/computation/AnalysisReportServiceTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/ComputeEngineIssueStorageFactoryTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/ComputeEngineIssueStorageTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/step/DataCleanerStepTest.java
server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/fake-report-folder/empty.xml [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/fake-report-folder/snapshots.xml [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/fake-report-folder/sub-folder/zip.zip [deleted file]
server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/components.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/empty.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/issues.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/snapshots.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/sub-folder/zip.zip [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_fail_to_load_component_id_if_unknown_component.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_insert_new_issues-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_insert_new_issues.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_load_component_id_from_db.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_resolve_conflicts_on_updates-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_resolve_conflicts_on_updates.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_update_issues-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_update_issues.xml [new file with mode: 0644]
sonar-batch-protocol/src/test/java/org/sonar/batch/protocol/input/ProjectReferentialsTest.java
sonar-batch/src/main/java/org/sonar/batch/issue/IssuePersister.java
sonar-batch/src/test/java/org/sonar/batch/issue/IssuePersisterTest.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueStorage.java
sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssue.java

index 07389ebab9625499247e5a27ba0c5a34088f5182..80ba861239f62df838da13a5141f84a989659273 100644 (file)
 package org.sonar.server.computation;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.gson.Gson;
+import com.google.gson.stream.JsonReader;
 import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.sonar.api.ServerComponent;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.Duration;
+import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.batch.protocol.GsonHelper;
+import org.sonar.batch.protocol.output.issue.ReportIssue;
+import org.sonar.batch.protocol.output.resource.ReportComponent;
+import org.sonar.batch.protocol.output.resource.ReportComponents;
 import org.sonar.core.computation.db.AnalysisReportDto;
+import org.sonar.core.issue.db.IssueStorage;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.server.db.DbClient;
 
 import javax.annotation.Nullable;
 
-import java.io.File;
-import java.io.IOException;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
 
 public class AnalysisReportService implements ServerComponent {
   private static final Logger LOG = LoggerFactory.getLogger(AnalysisReportService.class);
+  private static final int MAX_ISSUES_SIZE = 1000;
+  private final ComputeEngineIssueStorageFactory issueStorageFactory;
   private final DbClient dbClient;
+  private final Gson gson;
 
-  public AnalysisReportService(DbClient dbClient) {
+  public AnalysisReportService(DbClient dbClient, ComputeEngineIssueStorageFactory issueStorageFactory) {
+    this.issueStorageFactory = issueStorageFactory;
     this.dbClient = dbClient;
+    gson = GsonHelper.create();
   }
 
   public void digest(DbSession session, ComputeEngineContext context) {
     decompress(session, context);
+    loadResources(context);
+    saveIssues(context);
+  }
+
+  @VisibleForTesting
+  void loadResources(ComputeEngineContext context) {
+    File file = new File(context.getReportDirectory(), "components.json");
+
+    try {
+      InputStream resourcesStream = new FileInputStream(file);
+      String json = IOUtils.toString(resourcesStream);
+      ReportComponents reportComponents = ReportComponents.fromJson(json);
+      context.addResources(reportComponents);
+    } catch (IOException e) {
+      throw new IllegalStateException("Failed to read issues", e);
+    }
   }
 
   @VisibleForTesting
@@ -54,7 +89,77 @@ public class AnalysisReportService implements ServerComponent {
     context.setReportDirectory(decompressedDirectory);
   }
 
-  public void clean(@Nullable File directory) {
+  @VisibleForTesting
+  void saveIssues(ComputeEngineContext context) {
+    IssueStorage issueStorage = issueStorageFactory.newComputeEngineIssueStorage(context.getProject());
+
+    File issuesFile = new File(context.getReportDirectory(), "issues.json");
+    List<DefaultIssue> issues = new ArrayList<>(MAX_ISSUES_SIZE);
+
+    try {
+      InputStream issuesStream = new FileInputStream(issuesFile);
+      JsonReader reader = new JsonReader(new InputStreamReader(issuesStream));
+      reader.beginArray();
+      while (reader.hasNext()) {
+        ReportIssue reportIssue = gson.fromJson(reader, ReportIssue.class);
+        DefaultIssue defaultIssue = toIssue(context, reportIssue);
+        issues.add(defaultIssue);
+        if (shouldPersistIssues(issues, reader)) {
+          issueStorage.save(issues);
+          issues.clear();
+        }
+      }
+
+      reader.endArray();
+      reader.close();
+    } catch (IOException e) {
+      throw new IllegalStateException("Failed to read issues", e);
+    }
+  }
+
+  private boolean shouldPersistIssues(List<DefaultIssue> issues, JsonReader reader) throws IOException {
+    return issues.size() == MAX_ISSUES_SIZE || !reader.hasNext();
+  }
+
+  private DefaultIssue toIssue(ComputeEngineContext context, ReportIssue issue) {
+    ReportComponent component = context.getComponentByBatchId(issue.componentBatchId());
+    DefaultIssue defaultIssue = new DefaultIssue();
+    defaultIssue.setKey(issue.key());
+    defaultIssue.setComponentId(Long.valueOf(component.id()));
+    defaultIssue.setRuleKey(RuleKey.of(issue.ruleRepo(), issue.ruleKey()));
+    defaultIssue.setSeverity(issue.severity());
+    defaultIssue.setManualSeverity(issue.isManualSeverity());
+    defaultIssue.setMessage(issue.message());
+    defaultIssue.setLine(issue.line());
+    defaultIssue.setEffortToFix(issue.effortToFix());
+    setDebt(defaultIssue, issue.debt());
+    defaultIssue.setStatus(issue.status());
+    defaultIssue.setResolution(issue.resolution());
+    defaultIssue.setReporter(issue.reporter());
+    defaultIssue.setAssignee(issue.assignee());
+    defaultIssue.setChecksum(issue.checksum());
+    defaultIssue.setAttributes(KeyValueFormat.parse(issue.issueAttributes()));
+    defaultIssue.setAuthorLogin(issue.authorLogin());
+    defaultIssue.setActionPlanKey(issue.actionPlanKey());
+    defaultIssue.setCreationDate(issue.creationDate());
+    defaultIssue.setUpdateDate(issue.updateDate());
+    defaultIssue.setCloseDate(issue.closeDate());
+    defaultIssue.setCurrentChange(FieldDiffs.parse(issue.diffFields()));
+    defaultIssue.setChanged(issue.isChanged());
+    defaultIssue.setNew(issue.isNew());
+    defaultIssue.setSelectedAt(issue.selectedAt());
+    return defaultIssue;
+  }
+
+  private DefaultIssue setDebt(DefaultIssue issue, Long debt) {
+    if (debt != null) {
+      issue.setDebt(Duration.create(debt));
+    }
+
+    return issue;
+  }
+
+  public void deleteDirectory(@Nullable File directory) {
     if (directory == null) {
       return;
     }
index d0e473da8e023033f84878fec323fe7296b6277b..c62ccf1dbb5af222f3f134bd83ed0dbf7afe3e3c 100644 (file)
 
 package org.sonar.server.computation;
 
+import com.google.common.annotations.VisibleForTesting;
+import org.sonar.batch.protocol.output.resource.ReportComponent;
+import org.sonar.batch.protocol.output.resource.ReportComponents;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.computation.db.AnalysisReportDto;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
 import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
 
 public class ComputeEngineContext {
 
   private final AnalysisReportDto reportDto;
   private final ComponentDto project;
   private File reportDirectory;
+  private Map<Long, ReportComponent> components = new HashMap<>();
 
   public ComputeEngineContext(AnalysisReportDto reportDto, ComponentDto project) {
     this.reportDto = reportDto;
@@ -53,4 +60,25 @@ public class ComputeEngineContext {
   public void setReportDirectory(@Nullable File reportDirectory) {
     this.reportDirectory = reportDirectory;
   }
+
+  public void addResources(ReportComponents reportComponents) {
+    addResource(reportComponents.root());
+  }
+
+  @CheckForNull
+  public ReportComponent getComponentByBatchId(Long batchId) {
+    return components.get(batchId);
+  }
+
+  @VisibleForTesting
+  Map<Long, ReportComponent> getComponents() {
+    return components;
+  }
+
+  private void addResource(ReportComponent resource) {
+    this.components.put(resource.batchId(), resource);
+    for (ReportComponent childResource : resource.children()) {
+      addResource(childResource);
+    }
+  }
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineIssueStorage.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineIssueStorage.java
new file mode 100644 (file)
index 0000000..69ccf54
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.computation;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.IssueDto;
+import org.sonar.core.issue.db.IssueMapper;
+import org.sonar.core.issue.db.IssueStorage;
+import org.sonar.core.issue.db.UpdateConflictResolver;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.db.DbClient;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+class ComputeEngineIssueStorage extends IssueStorage {
+
+  private final DbClient dbClient;
+  private final ComponentDto project;
+  private final UpdateConflictResolver conflictResolver = new UpdateConflictResolver();
+
+  public ComputeEngineIssueStorage(MyBatis mybatis, DbClient dbClient, RuleFinder ruleFinder, ComponentDto project) {
+    super(mybatis, ruleFinder);
+    this.dbClient = dbClient;
+    this.project = project;
+  }
+
+  @Override
+  protected void doInsert(DbSession session, long now, DefaultIssue issue) {
+    IssueMapper issueMapper = session.getMapper(IssueMapper.class);
+    long componentId = componentId(session, issue);
+    long projectId = projectId();
+    Rule rule = rule(issue);
+    List<String> allTags = new ArrayList<String>();
+    allTags.addAll(Arrays.asList(rule.getTags()));
+    allTags.addAll(Arrays.asList(rule.getSystemTags()));
+    issue.setTags(allTags);
+    IssueDto dto = IssueDto.toDtoForBatchInsert(issue, componentId, projectId, rule.getId(), now);
+    issueMapper.insert(dto);
+  }
+
+  @Override
+  protected void doUpdate(DbSession session, long now, DefaultIssue issue) {
+    IssueMapper issueMapper = session.getMapper(IssueMapper.class);
+    IssueDto dto = IssueDto.toDtoForUpdate(issue, projectId(), now);
+    if (Issue.STATUS_CLOSED.equals(issue.status()) || issue.selectedAt() == null) {
+      // Issue is closed by scan or changed by end-user
+      issueMapper.update(dto);
+
+    } else {
+      int count = issueMapper.updateIfBeforeSelectedDate(dto);
+      if (count == 0) {
+        // End-user and scan changed the issue at the same time.
+        // See https://jira.codehaus.org/browse/SONAR-4309
+        conflictResolver.resolve(issue, issueMapper);
+      }
+    }
+  }
+
+  @VisibleForTesting
+  long componentId(DbSession session, DefaultIssue issue) {
+    if (issue.componentId() != null) {
+      return issue.componentId();
+    }
+
+    ComponentDto componentDto = dbClient.componentDao().getNullableByKey(session, issue.componentKey());
+    if (componentDto == null) {
+      throw new IllegalStateException("Unknown component: " + issue.componentKey());
+    }
+    return componentDto.getId();
+  }
+
+  @VisibleForTesting
+  long projectId() {
+    return project.getId();
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineIssueStorageFactory.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputeEngineIssueStorageFactory.java
new file mode 100644 (file)
index 0000000..e9326d0
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.computation;
+
+import org.sonar.api.ServerComponent;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.IssueStorage;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.db.DbClient;
+
+public class ComputeEngineIssueStorageFactory implements ServerComponent {
+  private final MyBatis myBatis;
+  private final DbClient dbClient;
+  private final RuleFinder ruleFinder;
+
+  public ComputeEngineIssueStorageFactory(MyBatis myBatis, DbClient dbClient, RuleFinder ruleFinder) {
+    this.myBatis = myBatis;
+    this.dbClient = dbClient;
+    this.ruleFinder = ruleFinder;
+  }
+
+  public IssueStorage newComputeEngineIssueStorage(ComponentDto project) {
+    return new ComputeEngineIssueStorage(myBatis, dbClient, ruleFinder, project);
+  }
+}
index fd2ac2de5a3c762defcf7827d0bd5edcdeb3b340..c6a7bf5ca6ed71e348c411a1bc490aae54fcda83 100644 (file)
@@ -146,10 +146,8 @@ public class AnalysisReportDao extends BaseDao<AnalysisReportMapper, AnalysisRep
 
       ps.executeUpdate();
       connection.commit();
-    } catch (SQLException e) {
+    } catch (SQLException | IOException e) {
       throw new IllegalStateException(String.format("Failed to insert %s in the database", report), e);
-    } catch (IOException e) {
-      throw new IllegalStateException(String.format("Failed to read report data of %s", report), e);
     } finally {
       DatabaseUtils.closeQuietly(ps);
     }
index 00b3092e540fcbecfde0f00110f278c22d1f8a7d..dfd6b3690cf2768f29b97fce44e3008890ffe308 100644 (file)
@@ -38,7 +38,7 @@ public class DataCleanerStep implements ComputationStep {
   @Override
   public void execute(DbSession session, ComputeEngineContext context) {
     projectCleaner.purge(session, new IdUuidPair(context.getProject().getId(), context.getProject().uuid()));
-    // reportService.clean(context.getReportDirectory());
+    // reportService.deleteDirectory(context.getReportDirectory());
   }
 
   @Override
index 374b8174cc6be9df87fe2f9a546fe459e680eba4..ed346ff9eb51a6ec5e6d8341694236fdd32ecd1e 100644 (file)
@@ -643,6 +643,7 @@ class ServerComponents {
     pico.addSingleton(ProjectCleaner.class);
     pico.addSingleton(ProjectSettingsFactory.class);
     pico.addSingleton(IndexPurgeListener.class);
+    pico.addSingleton(ComputeEngineIssueStorageFactory.class);
 
     for (Object components : level4AddedComponents) {
       pico.addSingleton(components);
index e0aa45482bd982fc5e20e28193cd49fd659c24a4..483f2367100099b4605dcb14bf63ffeeeda50314 100644 (file)
 
 package org.sonar.server.computation;
 
+import com.google.common.collect.Lists;
 import org.apache.commons.io.FileUtils;
+import org.junit.Before;
 import org.junit.Test;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.batch.protocol.output.resource.ReportComponent;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.computation.db.AnalysisReportDto;
+import org.sonar.core.issue.db.IssueStorage;
 import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
 import org.sonar.server.computation.db.AnalysisReportDao;
 import org.sonar.server.db.DbClient;
 
 import java.io.File;
+import java.util.List;
 
 import static org.fest.assertions.Assertions.assertThat;
 import static org.mockito.Matchers.any;
@@ -37,36 +45,103 @@ import static org.mockito.Mockito.*;
 public class AnalysisReportServiceTest {
   private AnalysisReportService sut;
 
+  private IssueStorage issueStorage;
+  private DbClient dbClient;
+
+  @Before
+  public void before() throws Exception {
+    dbClient = mock(DbClient.class);
+    issueStorage = new FakeIssueStorage();
+    ComputeEngineIssueStorageFactory issueStorageFactory = mock(ComputeEngineIssueStorageFactory.class);
+    when(issueStorageFactory.newComputeEngineIssueStorage(any(ComponentDto.class))).thenReturn(issueStorage);
+    sut = new AnalysisReportService(dbClient, issueStorageFactory);
+  }
+
   @Test
   public void call_dao_to_decompress_report() throws Exception {
-    DbClient dbClient = mock(DbClient.class);
     AnalysisReportDao dao = mock(AnalysisReportDao.class);
     when(dbClient.analysisReportDao()).thenReturn(dao);
-    sut = new AnalysisReportService(dbClient);
-    ComputeEngineContext context = new ComputeEngineContext(mock(AnalysisReportDto.class), mock(ComponentDto.class));
+    AnalysisReportDto report = AnalysisReportDto.newForTests(123L);
+    ComputeEngineContext context = new ComputeEngineContext(report, mock(ComponentDto.class));
 
     sut.decompress(mock(DbSession.class), context);
 
-    verify(dao).getDecompressedReport(any(DbSession.class), anyLong());
+    verify(dao).getDecompressedReport(any(DbSession.class), eq(123L));
   }
 
   @Test
   public void clean_null_directory_does_not_throw_any_exception() throws Exception {
-    sut = new AnalysisReportService(mock(DbClient.class));
-
-    sut.clean(null);
+    sut.deleteDirectory(null);
   }
 
   @Test
   public void clean_temp_folder() throws Exception {
-    sut = new AnalysisReportService(mock(DbClient.class));
-    File origin = new File(getClass().getResource("/org/sonar/server/computation/AnalysisReportServiceTest/fake-report-folder").getFile());
+    File origin = new File(getClass().getResource("/org/sonar/server/computation/AnalysisReportServiceTest/report-folder").getFile());
     File destination = new File("target/tmp/report-folder-to-delete");
     FileUtils.copyDirectory(origin, destination);
     assertThat(destination.exists()).isTrue();
 
-    sut.clean(destination);
+    sut.deleteDirectory(destination);
 
     assertThat(destination.exists()).isFalse();
   }
+
+  @Test
+  public void load_resources() throws Exception {
+    ComputeEngineContext context = new ComputeEngineContext(mock(AnalysisReportDto.class), mock(ComponentDto.class));
+    context.setReportDirectory(new File(getClass().getResource("/org/sonar/server/computation/AnalysisReportServiceTest/report-folder").getFile()));
+
+    sut.loadResources(context);
+
+    assertThat(context.getComponents()).hasSize(4);
+  }
+
+  @Test
+  public void save_issues() throws Exception {
+    ComputeEngineContext context = new FakeComputeEngineContext();
+    context.setReportDirectory(new File(getClass().getResource("/org/sonar/server/computation/AnalysisReportServiceTest/report-folder").getFile()));
+
+    sut.saveIssues(context);
+
+    assertThat(((FakeIssueStorage) issueStorage).issues).hasSize(6);
+  }
+
+  private static class FakeIssueStorage extends IssueStorage {
+
+    public List<DefaultIssue> issues = null;
+
+    protected FakeIssueStorage() {
+      super(mock(MyBatis.class), mock(RuleFinder.class));
+    }
+
+    @Override
+    public void save(Iterable<DefaultIssue> issues) {
+      this.issues = Lists.newArrayList(issues);
+    }
+
+    @Override
+    protected void doInsert(DbSession batchSession, long now, DefaultIssue issue) {
+
+    }
+
+    @Override
+    protected void doUpdate(DbSession batchSession, long now, DefaultIssue issue) {
+
+    }
+  }
+
+  private static class FakeComputeEngineContext extends ComputeEngineContext {
+
+    public FakeComputeEngineContext() {
+      super(mock(AnalysisReportDto.class), mock(ComponentDto.class));
+    }
+
+    @Override
+    public ReportComponent getComponentByBatchId(Long batchId) {
+      return new ReportComponent()
+        .setBatchId(123)
+        .setId(456);
+    }
+  }
+
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputeEngineIssueStorageFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputeEngineIssueStorageFactoryTest.java
new file mode 100644 (file)
index 0000000..492e71a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.computation;
+
+import org.junit.Test;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.issue.db.IssueStorage;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.db.DbClient;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class ComputeEngineIssueStorageFactoryTest {
+
+  ComputeEngineIssueStorageFactory sut;
+
+  @Test
+  public void return_instance_of_compute_engine_issue_storage() throws Exception {
+    sut = new ComputeEngineIssueStorageFactory(mock(MyBatis.class), mock(DbClient.class), mock(RuleFinder.class));
+
+    IssueStorage issueStorage = sut.newComputeEngineIssueStorage(mock(ComponentDto.class));
+
+    assertThat(issueStorage).isInstanceOf(ComputeEngineIssueStorage.class);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/ComputeEngineIssueStorageTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/ComputeEngineIssueStorageTest.java
new file mode 100644 (file)
index 0000000..b63f9ba
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.computation;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.issue.internal.DefaultIssueComment;
+import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.rules.Rule;
+import org.sonar.api.rules.RuleFinder;
+import org.sonar.api.rules.RuleQuery;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.Duration;
+import org.sonar.api.utils.System2;
+import org.sonar.batch.protocol.output.resource.ReportComponent;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.persistence.AbstractDaoTestCase;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.issue.db.IssueDao;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ComputeEngineIssueStorageTest extends AbstractDaoTestCase {
+
+  DbClient dbClient;
+  DbSession dbSession;
+  Map<Long, ReportComponent> components;
+  ComponentDto project;
+
+  ComputeEngineIssueStorage sut;
+
+  @Before
+  public void setUp() throws Exception {
+    System2 system = mock(System2.class);
+    when(system.now()).thenReturn(2000000000L);
+    dbClient = new DbClient(getDatabase(), getMyBatis(),
+      new ComponentDao(system),
+      new IssueDao(getMyBatis()),
+      new ComponentDao(system));
+    dbSession = dbClient.openSession(false);
+    components = new HashMap<>();
+    project = new ComponentDto();
+
+    sut = new ComputeEngineIssueStorage(getMyBatis(), dbClient, new FakeRuleFinder(), project);
+  }
+
+  @Test
+  public void should_get_component_id_set_in_issue() throws Exception {
+    DefaultIssue issue = new DefaultIssue().setComponentId(123L);
+
+    long componentId = sut.componentId(dbSession, issue);
+
+    assertThat(componentId).isEqualTo(123L);
+  }
+
+  @Test
+  public void should_load_component_id_from_db() throws Exception {
+    setupData("should_load_component_id_from_db");
+
+    long componentId = sut.componentId(dbSession, new DefaultIssue().setComponentKey("struts:Action.java"));
+
+    assertThat(componentId).isEqualTo(123);
+  }
+
+  @Test(expected = IllegalStateException.class)
+  public void should_fail_to_load_component_id_if_unknown_component() throws Exception {
+    setupData("should_fail_to_load_component_id_if_unknown_component");
+
+    sut.componentId(dbSession, new DefaultIssue().setComponentKey("struts:Action.java"));
+  }
+
+  @Test
+  public void should_load_project_id() throws Exception {
+    project.setId(100L);
+
+    long projectId = sut.projectId();
+
+    assertThat(projectId).isEqualTo(100);
+  }
+
+  @Test
+  public void should_insert_new_issues() throws Exception {
+    setupData("should_insert_new_issues");
+    project.setId(10L).setKey("struts");
+
+    DefaultIssueComment comment = DefaultIssueComment.create("ABCDE", "emmerik", "the comment");
+    // override generated key
+    comment.setKey("FGHIJ");
+
+    Date date = DateUtils.parseDate("2013-05-18");
+    DefaultIssue issue = new DefaultIssue()
+      .setKey("ABCDE")
+      .setNew(true)
+      .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
+      .setLine(5000)
+      .setDebt(Duration.create(10L))
+      .setReporter("emmerik")
+      .setResolution("OPEN")
+      .setStatus("OPEN")
+      .setSeverity("BLOCKER")
+      .setAttribute("foo", "bar")
+      .addComment(comment)
+      .setCreationDate(date)
+      .setUpdateDate(date)
+      .setCloseDate(date)
+
+      .setComponentKey("struts:Action");
+
+    sut.save(issue);
+
+    checkTables("should_insert_new_issues", new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues", "issue_changes");
+  }
+
+  @Test
+  public void should_update_issues() throws Exception {
+    setupData("should_update_issues");
+
+    IssueChangeContext context = IssueChangeContext.createUser(new Date(), "emmerik");
+
+    project.setId(10L).setKey("struts");
+
+    DefaultIssueComment comment = DefaultIssueComment.create("ABCDE", "emmerik", "the comment");
+    // override generated key
+    comment.setKey("FGHIJ");
+
+    Date date = DateUtils.parseDate("2013-05-18");
+    DefaultIssue issue = new DefaultIssue()
+      .setKey("ABCDE")
+      .setNew(false)
+      .setChanged(true)
+
+      // updated fields
+      .setLine(5000)
+      .setDebt(Duration.create(10L))
+      .setChecksum("FFFFF")
+      .setAuthorLogin("simon")
+      .setAssignee("loic")
+      .setFieldChange(context, "severity", "INFO", "BLOCKER")
+      .setReporter("emmerik")
+      .setResolution("FIXED")
+      .setStatus("RESOLVED")
+      .setSeverity("BLOCKER")
+      .setAttribute("foo", "bar")
+      .addComment(comment)
+      .setCreationDate(date)
+      .setUpdateDate(date)
+      .setCloseDate(date)
+
+      // unmodifiable fields
+      .setRuleKey(RuleKey.of("xxx", "unknown"))
+      .setComponentKey("not:a:component");
+
+    sut.save(issue);
+
+    checkTables("should_update_issues", new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues", "issue_changes");
+  }
+
+  @Test
+  public void should_resolve_conflicts_on_updates() throws Exception {
+    setupData("should_resolve_conflicts_on_updates");
+
+    project.setId(10L).setKey("struts");
+
+    Date date = DateUtils.parseDate("2013-05-18");
+    DefaultIssue issue = new DefaultIssue()
+      .setKey("ABCDE")
+      .setNew(false)
+      .setChanged(true)
+      .setCreationDate(DateUtils.parseDate("2005-05-12"))
+      .setUpdateDate(date)
+      .setRuleKey(RuleKey.of("squid", "AvoidCycles"))
+      .setComponentKey("struts:Action")
+
+      // issue in database has been updated in 2015, after the loading by scan
+      .setSelectedAt(1400000000000L)
+
+      // fields to be updated
+      .setLine(444)
+      .setSeverity("BLOCKER")
+      .setChecksum("FFFFF")
+      .setAttribute("JIRA", "http://jira.com")
+
+      // fields overridden by end-user -> do not save
+      .setAssignee("looser")
+      .setResolution(null)
+      .setStatus("REOPEN");
+
+    sut.save(issue);
+
+    checkTables("should_resolve_conflicts_on_updates", new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"}, "issues");
+  }
+
+  static class FakeRuleFinder implements RuleFinder {
+
+    @Override
+    public Rule findById(int ruleId) {
+      return null;
+    }
+
+    @Override
+    public Rule findByKey(String repositoryKey, String key) {
+      return null;
+    }
+
+    @Override
+    public Rule findByKey(RuleKey key) {
+      Rule rule = Rule.create().setRepositoryKey(key.repository()).setKey(key.rule());
+      rule.setId(200);
+      return rule;
+    }
+
+    @Override
+    public Rule find(RuleQuery query) {
+      return null;
+    }
+
+    @Override
+    public Collection<Rule> findAll(RuleQuery query) {
+      return null;
+    }
+  }
+}
index b350790bed27b105064845a8c3c7c4234ef6b25b..1d465a85c7d1554f7b6e4cc66b865dd5c1024554 100644 (file)
@@ -57,6 +57,6 @@ public class DataCleanerStepTest {
     sut.execute(mock(DbSession.class), context);
 
     verify(projectCleaner).purge(any(DbSession.class), any(IdUuidPair.class));
-    // verify(reportService).clean(any(File.class));
+    // verify(reportService).deleteDirectory(any(File.class));
   }
 }
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/fake-report-folder/empty.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/fake-report-folder/empty.xml
deleted file mode 100644 (file)
index 871dedc..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<dataset>
-
-</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/fake-report-folder/snapshots.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/fake-report-folder/snapshots.xml
deleted file mode 100644 (file)
index 642ac79..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-<dataset>
-
-  <!-- NEW SNAPSHOT -->
-  <snapshots id="1" project_id="123" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
-             status="U" islast="[false]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-  <snapshots id="2" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
-             status="U" islast="[false]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-  <snapshots id="3" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
-             status="U" islast="[false]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-  <!-- PROJECT_ID = 3 – no last snapshot -->
-  <snapshots id="4" project_id="3" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
-             status="U" islast="[false]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-  <!-- Child of snapshot id=1 -->
-  <snapshots id="5" project_id="55" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
-             status="U" islast="[false]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-
-  <!-- LAST FLAGGED SNAPSHOT -->
-  <snapshots id="21" project_id="123" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
-             status="P" islast="[true]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-  <snapshots id="22" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
-             status="P" islast="[true]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-  <snapshots id="23" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
-             status="P" islast="[true]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-  <!-- PROJECT_ID = 3 – no last snapshot -->
-  <snapshots id="24" project_id="3" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
-             status="P" islast="[true]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-  <!-- Child of snapshot id=1 -->
-  <snapshots id="25" project_id="55" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
-             status="P" islast="[true]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-
-  <!-- OLD SNAPSHOT -->
-  <snapshots id="46" project_id="123" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
-             status="P" islast="[false]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-  <snapshots id="47" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
-             status="P" islast="[false]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-  <snapshots id="48" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
-             status="P" islast="[false]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-  <!-- PROJECT_ID = 3 – no last snapshot -->
-  <snapshots id="49" project_id="3" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
-             status="P" islast="[false]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-  <!-- Child of snapshot id=1 -->
-  <snapshots id="50" project_id="55" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
-             status="P" islast="[false]" purge_status="1"
-             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
-             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
-             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
-             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
-             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
-             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
-             version="2.1-SNAPSHOT" path="1.2."/>
-</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/fake-report-folder/sub-folder/zip.zip b/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/fake-report-folder/sub-folder/zip.zip
deleted file mode 100644 (file)
index a540bc5..0000000
Binary files a/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/fake-report-folder/sub-folder/zip.zip and /dev/null differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/components.json b/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/components.json
new file mode 100644 (file)
index 0000000..4c642a0
--- /dev/null
@@ -0,0 +1,41 @@
+{
+  "analysisDate": "2012-12-12T00:00:00+0100",
+  "root": {
+    "batchId": 1,
+    "id": 11,
+    "snapshotId": 111,
+    "name": "Root project",
+    "type": "PRJ",
+    "children": [
+      {
+        "batchId": 2,
+        "id": 22,
+        "snapshotId": 222,
+        "path": "module1",
+        "name": "Module",
+        "type": "MOD",
+        "children": [
+          {
+            "batchId": 3,
+            "id": 33,
+            "snapshotId": 333,
+            "path": "src",
+            "name": "src",
+            "type": "DIR",
+            "children": [
+              {
+                "batchId": 4,
+                "id": 44,
+                "snapshotId": 444,
+                "path": "Foo.java",
+                "name": "Foo.java",
+                "type": "FIL",
+                "children": []
+              }
+            ]
+          }
+        ]
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/empty.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/empty.xml
new file mode 100644 (file)
index 0000000..871dedc
--- /dev/null
@@ -0,0 +1,3 @@
+<dataset>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/issues.json b/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/issues.json
new file mode 100644 (file)
index 0000000..fa3eec4
--- /dev/null
@@ -0,0 +1,182 @@
+[
+  {
+    "isNew": false,
+    "key": "key",
+    "manualSeverity": false,
+    "assignee": "Assignee",
+    "attributes": "attributes",
+    "authorLogin": "login",
+    "isChanged": true,
+    "ruleKey": "ruleKey",
+    "ruleRepo": "local",
+    "severity": "INFO",
+    "message": "message",
+    "line": 25,
+    "effortToFix": 30,
+    "debtInMinutes": 25,
+    "status": "NEW",
+    "resolution": "Non Solved",
+    "reporter": "reporter",
+    "assignee": "assignee",
+    "checkSum": "checkSum",
+    "attributes": "toto=25",
+    "authorLogin": "author",
+    "actionPlanKey": "actionPlanKey",
+    "creationDate": "2014-12-19T00:03:14+0100",
+    "updateDate": "2014-12-19T00:03:14+0100",
+    "closeDate": "2014-12-19T00:03:14+0100",
+    "currentChange": "coucou,c'est,nous",
+    "isChange": false,
+    "selectAt": 564897564
+  },
+  {
+    "isNew": false,
+    "key": "key",
+    "manualSeverity": false,
+    "assignee": "Assignee",
+    "attributes": "attributes",
+    "authorLogin": "login",
+    "isChanged": true,
+    "ruleKey": "ruleKey",
+    "ruleRepo": "local",
+    "severity": "INFO",
+    "message": "message",
+    "line": 25,
+    "effortToFix": 30,
+    "debtInMinutes": 25,
+    "status": "NEW",
+    "resolution": "Non Solved",
+    "reporter": "reporter",
+    "assignee": "assignee",
+    "checkSum": "checkSum",
+    "attributes": "toto=25",
+    "authorLogin": "author",
+    "actionPlanKey": "actionPlanKey",
+    "creationDate": "2014-12-19T00:03:14+0100",
+    "updateDate": "2014-12-19T00:03:14+0100",
+    "closeDate": "2014-12-19T00:03:14+0100",
+    "currentChange": "coucou,c'est,nous",
+    "isChange": false,
+    "selectAt": 564897564
+  },
+  {
+    "isNew": false,
+    "key": "key",
+    "manualSeverity": false,
+    "assignee": "Assignee",
+    "attributes": "attributes",
+    "authorLogin": "login",
+    "isChanged": true,
+    "ruleKey": "ruleKey",
+    "ruleRepo": "local",
+    "severity": "INFO",
+    "message": "message",
+    "line": 25,
+    "effortToFix": 30,
+    "debtInMinutes": 25,
+    "status": "NEW",
+    "resolution": "Non Solved",
+    "reporter": "reporter",
+    "assignee": "assignee",
+    "checkSum": "checkSum",
+    "attributes": "toto=25",
+    "authorLogin": "author",
+    "actionPlanKey": "actionPlanKey",
+    "creationDate": "2014-12-19T00:03:14+0100",
+    "updateDate": "2014-12-19T00:03:14+0100",
+    "closeDate": "2014-12-19T00:03:14+0100",
+    "currentChange": "coucou,c'est,nous",
+    "isChange": false,
+    "selectAt": 564897564
+  },
+  {
+    "isNew": false,
+    "key": "key",
+    "manualSeverity": false,
+    "assignee": "Assignee",
+    "attributes": "attributes",
+    "authorLogin": "login",
+    "isChanged": true,
+    "ruleKey": "ruleKey",
+    "ruleRepo": "local",
+    "severity": "INFO",
+    "message": "message",
+    "line": 25,
+    "effortToFix": 30,
+    "debtInMinutes": 25,
+    "status": "NEW",
+    "resolution": "Non Solved",
+    "reporter": "reporter",
+    "assignee": "assignee",
+    "checkSum": "checkSum",
+    "attributes": "toto=25",
+    "authorLogin": "author",
+    "actionPlanKey": "actionPlanKey",
+    "creationDate": "2014-12-19T00:03:14+0100",
+    "updateDate": "2014-12-19T00:03:14+0100",
+    "closeDate": "2014-12-19T00:03:14+0100",
+    "currentChange": "coucou,c'est,nous",
+    "isChange": false,
+    "selectAt": 564897564
+  },
+  {
+    "isNew": false,
+    "key": "key",
+    "manualSeverity": false,
+    "assignee": "Assignee",
+    "attributes": "attributes",
+    "authorLogin": "login",
+    "isChanged": true,
+    "ruleKey": "ruleKey",
+    "ruleRepo": "local",
+    "severity": "INFO",
+    "message": "message",
+    "line": 25,
+    "effortToFix": 30,
+    "debtInMinutes": 25,
+    "status": "NEW",
+    "resolution": "Non Solved",
+    "reporter": "reporter",
+    "assignee": "assignee",
+    "checkSum": "checkSum",
+    "attributes": "toto=25",
+    "authorLogin": "author",
+    "actionPlanKey": "actionPlanKey",
+    "creationDate": "2014-12-19T00:03:14+0100",
+    "updateDate": "2014-12-19T00:03:14+0100",
+    "closeDate": "2014-12-19T00:03:14+0100",
+    "currentChange": "coucou,c'est,nous",
+    "isChange": false,
+    "selectAt": 564897564
+  },
+  {
+    "isNew": false,
+    "key": "key",
+    "manualSeverity": false,
+    "assignee": "Assignee",
+    "attributes": "attributes",
+    "authorLogin": "login",
+    "isChanged": true,
+    "ruleKey": "ruleKey",
+    "ruleRepo": "local",
+    "severity": "INFO",
+    "message": "message",
+    "line": 25,
+    "effortToFix": 30,
+    "debtInMinutes": 25,
+    "status": "NEW",
+    "resolution": "Non Solved",
+    "reporter": "reporter",
+    "assignee": "assignee",
+    "checkSum": "checkSum",
+    "attributes": "toto=25",
+    "authorLogin": "author",
+    "actionPlanKey": "actionPlanKey",
+    "creationDate": "2014-12-19T00:03:14+0100",
+    "updateDate": "2014-12-19T00:03:14+0100",
+    "closeDate": "2014-12-19T00:03:14+0100",
+    "currentChange": "coucou,c'est,nous",
+    "isChange": false,
+    "selectAt": 564897564
+  }
+]
\ No newline at end of file
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/snapshots.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/snapshots.xml
new file mode 100644 (file)
index 0000000..642ac79
--- /dev/null
@@ -0,0 +1,149 @@
+<dataset>
+
+  <!-- NEW SNAPSHOT -->
+  <snapshots id="1" project_id="123" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
+             status="U" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <snapshots id="2" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
+             status="U" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <snapshots id="3" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
+             status="U" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <!-- PROJECT_ID = 3 – no last snapshot -->
+  <snapshots id="4" project_id="3" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
+             status="U" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <!-- Child of snapshot id=1 -->
+  <snapshots id="5" project_id="55" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="1"
+             status="U" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-03" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+
+  <!-- LAST FLAGGED SNAPSHOT -->
+  <snapshots id="21" project_id="123" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
+             status="P" islast="[true]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <snapshots id="22" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
+             status="P" islast="[true]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <snapshots id="23" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
+             status="P" islast="[true]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <!-- PROJECT_ID = 3 – no last snapshot -->
+  <snapshots id="24" project_id="3" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
+             status="P" islast="[true]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <!-- Child of snapshot id=1 -->
+  <snapshots id="25" project_id="55" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="21"
+             status="P" islast="[true]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-02" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+
+  <!-- OLD SNAPSHOT -->
+  <snapshots id="46" project_id="123" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
+             status="P" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <snapshots id="47" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
+             status="P" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <snapshots id="48" project_id="1" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
+             status="P" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <!-- PROJECT_ID = 3 – no last snapshot -->
+  <snapshots id="49" project_id="3" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
+             status="P" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="DIR" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+  <!-- Child of snapshot id=1 -->
+  <snapshots id="50" project_id="55" parent_snapshot_id="2" root_project_id="123" root_snapshot_id="46"
+             status="P" islast="[false]" purge_status="1"
+             period1_mode="days1" period1_param="30" period1_date="2011-09-24"
+             period2_mode="days2" period2_param="31" period2_date="2011-09-25"
+             period3_mode="days3" period3_param="32" period3_date="2011-09-26"
+             period4_mode="days4" period4_param="33" period4_date="2011-09-27"
+             period5_mode="days5" period5_param="34" period5_date="2011-09-28"
+             depth="1" scope="PRJ" qualifier="PAC" created_at="2008-12-01" build_date="2011-09-29"
+             version="2.1-SNAPSHOT" path="1.2."/>
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/sub-folder/zip.zip b/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/sub-folder/zip.zip
new file mode 100644 (file)
index 0000000..a540bc5
Binary files /dev/null and b/server/sonar-server/src/test/resources/org/sonar/server/computation/AnalysisReportServiceTest/report-folder/sub-folder/zip.zip differ
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_fail_to_load_component_id_if_unknown_component.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_fail_to_load_component_id_if_unknown_component.xml
new file mode 100644 (file)
index 0000000..5ed00ba
--- /dev/null
@@ -0,0 +1 @@
+<dataset></dataset>
\ No newline at end of file
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_insert_new_issues-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_insert_new_issues-result.xml
new file mode 100644 (file)
index 0000000..458ce25
--- /dev/null
@@ -0,0 +1,27 @@
+<dataset>
+  <issues id="1" kee="ABCDE" resolution="OPEN" status="OPEN" severity="BLOCKER" manual_severity="[false]"
+      assignee="[null]"
+      author_login="[null]"
+      checksum="[null]"
+      effort_to_fix="[null]"
+      technical_debt="10"
+      message="[null]"
+      line="5000"
+      component_id="100"
+      root_component_id="10"
+      rule_id="200"
+      created_at="[null]"
+      updated_at="[null]"
+      reporter="emmerik"
+      issue_attributes="foo=bar"
+      tags="[null]"
+      action_plan_key="[null]"
+      issue_creation_date="2013-05-18"
+      issue_update_date="2013-05-18"
+      issue_close_date="2013-05-18"
+      />
+
+  <issue_changes id="1" kee="FGHIJ" issue_key="ABCDE" change_type="comment" user_login="emmerik" change_data="the comment"
+                 created_at="[null]" updated_at="[null]" issue_change_creation_date="[null]" />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_insert_new_issues.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_insert_new_issues.xml
new file mode 100644 (file)
index 0000000..02899f1
--- /dev/null
@@ -0,0 +1,4 @@
+<dataset>
+  <projects id="10" scope="PRJ" qualifier="TRK" kee="struts" name="Struts" uuid="ABCD"/>
+  <projects id="100" scope="FIL" qualifier="CLA" kee="struts:Action" name="Action" uuid="BCDE"/>
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_load_component_id_from_db.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_load_component_id_from_db.xml
new file mode 100644 (file)
index 0000000..99098d2
--- /dev/null
@@ -0,0 +1,3 @@
+<dataset>
+  <projects id="123" kee="struts:Action.java" uuid="ABCD"/>
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_resolve_conflicts_on_updates-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_resolve_conflicts_on_updates-result.xml
new file mode 100644 (file)
index 0000000..e421b22
--- /dev/null
@@ -0,0 +1,34 @@
+<dataset>
+  <rules tags="[null]" system_tags="[null]" id="200" name="Avoid Cycles" plugin_rule_key="AvoidCycles"
+         plugin_config_key="[null]" plugin_name="squid"/>
+
+  <projects id="10" scope="PRJ" qualifier="TRK" kee="struts" name="Struts" uuid="ABCD"/>
+  <projects id="100" scope="FIL" qualifier="CLA" kee="struts:Action" name="Action" uuid="BCDE"/>
+
+  <issues id="1"
+          kee="ABCDE"
+          resolution="FIXED"
+          status="RESOLVED"
+          severity="BLOCKER"
+          manual_severity="[false]"
+          assignee="winner"
+          author_login="[null]"
+          checksum="FFFFF"
+          effort_to_fix="[null]"
+          technical_debt="[null]"
+          message="[null]"
+          line="444"
+          component_id="100"
+          root_component_id="10"
+          rule_id="200"
+          reporter="[null]"
+          issue_attributes="JIRA=http://jira.com"
+          tags="[null]"
+          action_plan_key="[null]"
+          created_at="1400000000000"
+          updated_at="1400000000000"
+          issue_creation_date="2005-05-12 00:00:00.0"
+          issue_update_date="2013-05-18 00:00:00.0"
+          issue_close_date="[null]"
+    />
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_resolve_conflicts_on_updates.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_resolve_conflicts_on_updates.xml
new file mode 100644 (file)
index 0000000..0ddfc45
--- /dev/null
@@ -0,0 +1,34 @@
+<dataset>
+
+  <rules tags="[null]" system_tags="[null]" id="200" name="Avoid Cycles" plugin_rule_key="AvoidCycles"
+         plugin_config_key="[null]" plugin_name="squid" />
+
+  <projects id="10" scope="PRJ" qualifier="TRK" kee="struts" name="Struts" uuid="ABCD"/>
+  <projects id="100" scope="FIL" qualifier="CLA" kee="struts:Action" name="Action" uuid="BCDE"/>
+
+  <issues id="1"
+          kee="ABCDE"
+          assignee="winner"
+          resolution="FIXED"
+          status="RESOLVED"
+          severity="MAJOR"
+          manual_severity="[false]"
+          author_login="[null]"
+          checksum="FFFFF"
+          effort_to_fix="[null]"
+          technical_debt="[null]"
+          message="[null]"
+          line="1"
+          component_id="100"
+          root_component_id="10"
+          rule_id="200"
+          reporter="[null]"
+          issue_attributes=""
+          action_plan_key="[null]"
+          created_at="1400000000000"
+          updated_at="1500000000000"
+          issue_creation_date="2005-05-12 00:00:00.0"
+          issue_update_date="2013-05-18 00:00:00.0"
+          issue_close_date="[null]"
+    />
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_update_issues-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_update_issues-result.xml
new file mode 100644 (file)
index 0000000..ba65e9d
--- /dev/null
@@ -0,0 +1,33 @@
+<dataset>
+  <issues id="1"
+          kee="ABCDE"
+          resolution="FIXED"
+          status="RESOLVED"
+          severity="BLOCKER"
+          manual_severity="[false]"
+          assignee="loic"
+          author_login="simon"
+          checksum="FFFFF"
+          effort_to_fix="[null]"
+          technical_debt="10"
+          message="[null]"
+          line="5000"
+          component_id="100"
+          root_component_id="10"
+          rule_id="200"
+          created_at="1400000000000"
+          updated_at="1400000000000"
+          reporter="emmerik"
+          issue_attributes="foo=bar"
+          tags="[null]"
+          action_plan_key="[null]"
+          issue_creation_date="2013-05-18 00:00:00.0"
+          issue_update_date="2013-05-18 00:00:00.0"
+          issue_close_date="2013-05-18 00:00:00.0"
+    />
+
+  <issue_changes id="1" kee="FGHIJ" issue_key="ABCDE" change_type="comment" user_login="emmerik"
+                 change_data="the comment" created_at="[null]" updated_at="[null]" issue_change_creation_date="[null]"/>
+  <issue_changes id="2" kee="[null]" issue_key="ABCDE" change_type="diff" user_login="emmerik"
+                 change_data="severity=INFO|BLOCKER" created_at="[null]" updated_at="[null]" issue_change_creation_date="[null]"/>
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_update_issues.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/ComputeEngineIssueStorageTest/should_update_issues.xml
new file mode 100644 (file)
index 0000000..5fd4a9e
--- /dev/null
@@ -0,0 +1,31 @@
+<dataset>
+
+  <projects id="10" scope="PRJ" qualifier="TRK" kee="struts" name="Struts" uuid="ABCD"/>
+  <projects id="100" scope="FIL" qualifier="CLA" kee="struts:Action" name="Action" uuid="BCDE"/>
+
+  <issues id="1"
+          kee="ABCDE"
+          resolution="OPEN"
+          status="OPEN"
+          severity="BLOCKER"
+          manual_severity="[false]"
+          assignee="loic"
+          author_login="simon"
+          checksum="FFFFF"
+          effort_to_fix="[null]"
+          technical_debt="[null]"
+          message="[null]"
+          line="3000"
+          component_id="100"
+          root_component_id="10"
+          rule_id="200"
+          created_at="1400000000000"
+          updated_at="1400000000000"
+          reporter="emmerik"
+          issue_attributes="foo=bar"
+          action_plan_key="[null]"
+          issue_creation_date="2010-01-01"
+          issue_update_date="2010-02-02"
+          issue_close_date="[null]"
+    />
+</dataset>
index 316d59acc31a7c2d1d6b16beff1a5b4cb858e1fb..96af4da66fc2c2f66464536be0cb83df69511725 100644 (file)
@@ -53,7 +53,6 @@ public class ProjectReferentialsTest {
     ref.addFileData("foo", "src/main/java/Foo.java", new FileData("xyz", "1=12345,2=3456", "1=345,2=345", "1=henryju,2=gaudin"));
     ref.addFileData("foo", "src/main/java/Foo2.java", new FileData("xyz", "1=12345,2=3456", "1=345,2=345", "1=henryju,2=gaudin"));
 
-    System.out.println(ref.toJson());
     JSONAssert
       .assertEquals(
         "{timestamp:10,"
index e1ca3f3b1c5b809c0e6389d39dc8de78758cb11f..1abf3ca1f238d982a3f50ca9fa332674d87f5b90 100644 (file)
@@ -49,6 +49,6 @@ public class IssuePersister implements ScanPersister {
       return;
     }
     Iterable<DefaultIssue> issues = issueCache.all();
-    storage.save(issues);
+    // storage.save(issues);
   }
 }
index eb0950ac88d2fb15ada8c9e506ca397291c04b3e..a48e54a93122ccf35021366f9b5909a2199d5595 100644 (file)
@@ -28,11 +28,7 @@ import org.sonar.core.persistence.AbstractDaoTestCase;
 import java.util.Arrays;
 import java.util.List;
 
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
 public class IssuePersisterTest extends AbstractDaoTestCase {
 
@@ -53,10 +49,10 @@ public class IssuePersisterTest extends AbstractDaoTestCase {
   }
 
   @Test
-  public void should_persist_all_issues() throws Exception {
+  public void should_not_persist_issues_anymore() throws Exception {
     persister.persist();
 
-    verify(storage, times(1)).save(issues);
+    verify(storage, never()).save(issues);
   }
 
   @Test
index 53a8cd5064a6e643c63b3b582a284ffdf63bd124..7157be3646a8aff3a4ce0d754c3873619652c4de 100644 (file)
@@ -571,8 +571,8 @@ public final class IssueDto implements Serializable {
       .setResolution(issue.resolution())
       .setStatus(issue.status())
       .setSeverity(issue.severity())
-      .setChecksum(issue.checksum())
       .setManualSeverity(issue.manualSeverity())
+      .setChecksum(issue.checksum())
       .setReporter(issue.reporter())
       .setAssignee(issue.assignee())
       .setRuleId(ruleId)
@@ -595,7 +595,7 @@ public final class IssueDto implements Serializable {
       .setIssueUpdateDate(issue.updateDate())
       .setSelectedAt(issue.selectedAt())
 
-      // technical dates
+        // technical dates
       .setCreatedAt(now)
       .setUpdatedAt(now);
   }
index bfc72487c1d30edf2a14ee4405dfa6f0b820c379..c4533c9bf0d077b05ccab88aab9f0e4205b18241 100644 (file)
@@ -74,7 +74,7 @@ public abstract class IssueStorage {
     // Batch session can not be used for updates. It does not return the number of updated rows,
     // required for detecting conflicts.
     long now = System.currentTimeMillis();
-    List<DefaultIssue> toBeUpdated = batchInsert(session, issues, now);
+    List<DefaultIssue> toBeUpdated = batchInsertAndReturnIssuesToUpdate(session, issues, now);
     update(toBeUpdated, now);
     doAfterSave();
   }
@@ -83,7 +83,7 @@ public abstract class IssueStorage {
     // overridden on server-side to index ES
   }
 
-  private List<DefaultIssue> batchInsert(DbSession session, Iterable<DefaultIssue> issues, long now) {
+  private List<DefaultIssue> batchInsertAndReturnIssuesToUpdate(DbSession session, Iterable<DefaultIssue> issues, long now) {
     List<DefaultIssue> toBeUpdated = newArrayList();
     int count = 0;
     IssueChangeMapper issueChangeMapper = session.getMapper(IssueChangeMapper.class);
index e318234f0e0d6b7329f7fe1c03720b19f6a1fecc..8b1e92e7df1be1cb8dc57c13e283bdcd15eafd0d 100644 (file)
@@ -40,14 +40,7 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
 import java.io.Serializable;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import static com.google.common.collect.Lists.newArrayList;
 
@@ -514,6 +507,12 @@ public class DefaultIssue implements Issue {
     return this;
   }
 
+  public DefaultIssue setCurrentChange(FieldDiffs currentChange) {
+    this.currentChange = currentChange;
+    addChange(currentChange);
+    return this;
+  }
+
   @CheckForNull
   public FieldDiffs currentChange() {
     return currentChange;