]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6589 make ReportExtractor a step called ReportExtractionStep
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Fri, 29 May 2015 08:59:33 +0000 (10:59 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 1 Jun 2015 15:08:29 +0000 (17:08 +0200)
15 files changed:
server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolder.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolderImpl.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReaderImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/batch/MutableBatchReportDirectoryHolder.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/batch/ReportExtractor.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportExtractionStep.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/computation/step/ValidateProjectStep.java
server/sonar-server/src/test/java/org/sonar/server/computation/batch/ReportExtractorTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/container/ComputeEngineContainerImplTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/PopulateComponentsUuidAndKeyStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportExtractionStepTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/step/ValidateProjectStepTest.java
server/sonar-server/src/test/resources/org/sonar/server/computation/step/ReportExtractionStepTest/demozip.zip [new file with mode: 0644]

diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolder.java
new file mode 100644 (file)
index 0000000..088dbc5
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.batch;
+
+import java.io.File;
+import org.sonar.server.computation.ReportQueue;
+
+public interface BatchReportDirectoryHolder {
+  /**
+   * The File of the directory where the Batch report files for the current {@link ReportQueue.Item} are stored.
+   *
+   * @throws IllegalStateException if the holder is empty (ie. there is no directory yet)
+   */
+  File getDirectory();
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolderImpl.java
new file mode 100644 (file)
index 0000000..6477b7a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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.batch;
+
+import java.io.File;
+import java.util.Objects;
+
+public class BatchReportDirectoryHolderImpl implements BatchReportDirectoryHolder, MutableBatchReportDirectoryHolder {
+  private File directory;
+
+  @Override
+  public void setDirectory(File newDirectory) {
+    this.directory = Objects.requireNonNull(newDirectory);
+  }
+
+  @Override
+  public File getDirectory() {
+    if (this.directory == null) {
+      throw new IllegalStateException("Directory has not been set yet");
+    }
+    return this.directory;
+  }
+}
index 7799436b9b26ec3629b4288891344cbba3be54c5..6c600f37f6cd166e818f0a51fe91f389b52a6f56 100644 (file)
@@ -33,14 +33,13 @@ import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.LineIterator;
 import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.server.computation.ReportQueue;
 import org.sonar.server.util.CloseableIterator;
 
 public class BatchReportReaderImpl implements BatchReportReader {
   private final org.sonar.batch.protocol.output.BatchReportReader delegate;
 
-  public BatchReportReaderImpl(ReportExtractor reportExtractor, ReportQueue.Item item) {
-    this.delegate = new org.sonar.batch.protocol.output.BatchReportReader(reportExtractor.extractReportInDir(item));
+  public BatchReportReaderImpl(BatchReportDirectoryHolder batchReportDirectoryHolder) {
+    this.delegate = new org.sonar.batch.protocol.output.BatchReportReader(batchReportDirectoryHolder.getDirectory());
   }
 
   @Override
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/batch/MutableBatchReportDirectoryHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/batch/MutableBatchReportDirectoryHolder.java
new file mode 100644 (file)
index 0000000..21a4a1b
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.batch;
+
+import java.io.File;
+
+public interface MutableBatchReportDirectoryHolder extends BatchReportDirectoryHolder {
+  /**
+   * Sets the File of the directory in the BatchReportDirectoryHolder. Settings a File more than once is allowed but it
+   * can never be set to {@code null}.
+   *
+   * @param newDirectory a {@link File}, can not be {@code null}
+   *
+   * @throws NullPointerException if {@code newDirectory} is {@code null}
+   */
+  void setDirectory(File newDirectory);
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/batch/ReportExtractor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/batch/ReportExtractor.java
deleted file mode 100644 (file)
index 61aa6a9..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.batch;
-
-import java.io.File;
-import java.io.IOException;
-import org.apache.commons.io.FileUtils;
-import org.sonar.api.utils.TempFolder;
-import org.sonar.api.utils.ZipUtils;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.api.utils.log.Profiler;
-import org.sonar.server.computation.ReportQueue;
-
-public class ReportExtractor {
-  private static final Logger LOG = Loggers.get(ReportExtractor.class);
-
-  private final TempFolder tempFolder;
-
-  public ReportExtractor(TempFolder tempFolder) {
-    this.tempFolder = tempFolder;
-  }
-
-  public File extractReportInDir(ReportQueue.Item item) {
-    File dir = tempFolder.newDir();
-    try {
-      Profiler profiler = Profiler.createIfDebug(LOG).start();
-      ZipUtils.unzip(item.zipFile, dir);
-      if (profiler.isDebugEnabled()) {
-        String message = String.format("Report extracted | size=%s | project=%s",
-            FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(dir)), item.dto.getProjectKey());
-        profiler.stopDebug(message);
-      }
-      return dir;
-    } catch (IOException e) {
-      throw new IllegalStateException(String.format("Fail to unzip %s into %s", item.zipFile, dir), e);
-    }
-  }
-}
index 1f1f7336c6d26426ef02ced8a17a58dc006b58d1..ff9de6a5da4a7e8075d4c466b5bd71e75b0f1276 100644 (file)
@@ -34,8 +34,8 @@ import org.sonar.core.platform.ComponentContainer;
 import org.sonar.server.computation.ComputationService;
 import org.sonar.server.computation.ReportQueue;
 import org.sonar.server.computation.activity.ActivityManager;
+import org.sonar.server.computation.batch.BatchReportDirectoryHolderImpl;
 import org.sonar.server.computation.batch.BatchReportReaderImpl;
-import org.sonar.server.computation.batch.ReportExtractor;
 import org.sonar.server.computation.component.DbComponentsRefCache;
 import org.sonar.server.computation.component.TreeRootHolderImpl;
 import org.sonar.server.computation.event.EventRepositoryImpl;
@@ -111,11 +111,13 @@ public class ComputeEngineContainerImpl extends ComponentContainer implements Co
   private static List componentClasses() {
     return Arrays.asList(
       ActivityManager.class,
-      ReportExtractor.class,
-      BatchReportReaderImpl.class,
 
       TreeRootHolderImpl.class,
 
+      BatchReportReaderImpl.class,
+
+      BatchReportDirectoryHolderImpl.class,
+
       // repositories
       PlatformLanguageRepository.class,
       MeasureRepositoryImpl.class,
index 7d409691a7791f47dc19145d53163a78ce261e5b..a967fd1052699fd10bac2aed139cf6b497c34031 100644 (file)
@@ -36,6 +36,9 @@ public class ComputationSteps {
    */
   public List<Class<? extends ComputationStep>> orderedStepClasses() {
     return Arrays.asList(
+      // extract report to a temp directory
+      ReportExtractionStep.class,
+
       // Builds Component tree
       BuildComponentTreeStep.class,
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportExtractionStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportExtractionStep.java
new file mode 100644 (file)
index 0000000..f3048e9
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.step;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.commons.io.FileUtils;
+import org.sonar.api.utils.TempFolder;
+import org.sonar.api.utils.ZipUtils;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.api.utils.log.Profiler;
+import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.batch.MutableBatchReportDirectoryHolder;
+
+/**
+ * Extracts the content zip file of the {@link ReportQueue.Item} to a temp directory and adds a {@link File}
+ * representing that temp directory to the {@link MutableBatchReportDirectoryHolder}.
+ */
+public class ReportExtractionStep implements ComputationStep {
+  private static final Logger LOG = Loggers.get(ReportExtractionStep.class);
+
+  private final ReportQueue.Item item;
+  private final TempFolder tempFolder;
+  private final MutableBatchReportDirectoryHolder reportDirectoryHolder;
+
+  public ReportExtractionStep(ReportQueue.Item item, TempFolder tempFolder, MutableBatchReportDirectoryHolder reportDirectoryHolder) {
+    this.item = item;
+    this.tempFolder = tempFolder;
+    this.reportDirectoryHolder = reportDirectoryHolder;
+  }
+
+  @Override
+  public void execute() {
+    File dir = tempFolder.newDir();
+    try {
+      Profiler profiler = Profiler.createIfDebug(LOG).start();
+      ZipUtils.unzip(item.zipFile, dir);
+      if (profiler.isDebugEnabled()) {
+        String message = String.format("Report extracted | size=%s | project=%s",
+            FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(dir)), item.dto.getProjectKey());
+        profiler.stopDebug(message);
+      }
+      reportDirectoryHolder.setDirectory(dir);
+    } catch (IOException e) {
+      throw new IllegalStateException(String.format("Fail to unzip %s into %s", item.zipFile, dir), e);
+    }
+  }
+
+  @Override
+  public String getDescription() {
+    return "Extracting batch report to temp directory";
+  }
+
+}
index 747fec66c8eefdb24c6da175aafbb0032c46c7e9..53c19ad76b772852c46d94d565708be46ee05eee 100644 (file)
@@ -35,10 +35,10 @@ import org.sonar.core.component.ComponentDto;
 import org.sonar.core.component.ComponentKeys;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.server.component.db.ComponentDao;
-import org.sonar.server.computation.ComputationContext;
 import org.sonar.server.computation.batch.BatchReportReader;
 import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
+import org.sonar.server.computation.component.TreeRootHolder;
 import org.sonar.server.db.DbClient;
 
 /**
@@ -58,18 +58,20 @@ public class ValidateProjectStep implements ComputationStep {
   private final DbClient dbClient;
   private final Settings settings;
   private final BatchReportReader reportReader;
+  private final TreeRootHolder treeRootHolder;
 
-  public ValidateProjectStep(DbClient dbClient, Settings settings, BatchReportReader reportReader) {
+  public ValidateProjectStep(DbClient dbClient, Settings settings, BatchReportReader reportReader, TreeRootHolder treeRootHolder) {
     this.dbClient = dbClient;
     this.settings = settings;
     this.reportReader = reportReader;
+    this.treeRootHolder = treeRootHolder;
   }
 
   @Override
-  public void execute(ComputationContext context) {
+  public void execute() {
     DbSession session = dbClient.openSession(false);
     try {
-      List<ComponentDto> modules = dbClient.componentDao().selectModulesFromProjectKey(session, context.getRoot().getKey());
+      List<ComponentDto> modules = dbClient.componentDao().selectModulesFromProjectKey(session, treeRootHolder.getRoot().getKey());
       Map<String, ComponentDto> modulesByKey = Maps.uniqueIndex(modules, new Function<ComponentDto, String>() {
         @Override
         public String apply(@Nonnull ComponentDto input) {
@@ -77,7 +79,7 @@ public class ValidateProjectStep implements ComputationStep {
         }
       });
       ValidateProjectsVisitor visitor = new ValidateProjectsVisitor(session, dbClient.componentDao(), settings.getBoolean(CoreProperties.CORE_PREVENT_AUTOMATIC_PROJECT_CREATION), modulesByKey);
-      visitor.visit(context.getRoot());
+      visitor.visit(treeRootHolder.getRoot());
 
       if (!visitor.validationMessages.isEmpty()) {
         throw new IllegalArgumentException("Validation of project failed:\n  o " + MESSAGES_JOINER.join(visitor.validationMessages));
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/batch/ReportExtractorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/batch/ReportExtractorTest.java
deleted file mode 100644 (file)
index d25761f..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.batch;
-
-import java.io.File;
-import org.apache.commons.io.FileUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.utils.internal.JUnitTempFolder;
-import org.sonar.core.computation.db.AnalysisReportDto;
-import org.sonar.server.computation.ReportQueue;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-
-public class ReportExtractorTest {
-
-  @Rule
-  public JUnitTempFolder tempFolder = new JUnitTempFolder();
-
-  ReportExtractor underTest = new ReportExtractor(tempFolder);
-
-
-  @Test
-  public void fail_if_corrupted_zip() throws Exception {
-    AnalysisReportDto dto = newDefaultReport();
-    File zip = tempFolder.newFile();
-    FileUtils.write(zip, "not a file");
-
-    try {
-      underTest.extractReportInDir(new ReportQueue.Item(dto, zip));
-      fail();
-    } catch (IllegalStateException e) {
-      assertThat(e.getMessage()).startsWith("Fail to unzip " + zip.getAbsolutePath() + " into ");
-    }
-  }
-
-  private AnalysisReportDto newDefaultReport() {
-    return AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1").setStatus(AnalysisReportDto.Status.PENDING);
-  }
-}
index 389e3d3d538348214fb76181151c4646ee292b2d..6c8c69261d08afdb651f227aed34d80d3316df71 100644 (file)
@@ -35,10 +35,12 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 
 public class ComputeEngineContainerImplTest {
+
   @Test(expected = NullPointerException.class)
   public void constructor_fails_fast_on_null_container() {
     new ComputeEngineContainerImpl(null, mock(ReportQueue.Item.class));
   }
+
   @Test(expected = NullPointerException.class)
   public void constructor_fails_fast_on_null_item() {
     new ComputeEngineContainerImpl(new ComponentContainer(), null);
index e436c90de9678d1e7ee713415c1f29d4550b33df..da362bbea173d48548ed0ffe97958ae715282575 100644 (file)
@@ -169,7 +169,7 @@ public class PopulateComponentsUuidAndKeyStepTest extends BaseStepTest {
       .build());
 
 
-    treeRootHolder.setRoot(ComponentTreeBuilders.from(reportReader).build());
+    treeRootHolder.setRoot(ComponentTreeBuilder.from(reportReader));
     sut.execute();
 
     Map<Integer, Component> componentsByRef = getComponentsByRef(treeRootHolder.getRoot());
@@ -322,7 +322,7 @@ public class PopulateComponentsUuidAndKeyStepTest extends BaseStepTest {
       .setPath("pom.xml")
       .build());
 
-    treeRootHolder.setRoot(ComponentTreeBuilders.from(reportReader).build());
+    treeRootHolder.setRoot(ComponentTreeBuilder.from(reportReader));
     sut.execute();
 
     Map<Integer, Component> componentsByRef = getComponentsByRef(treeRootHolder.getRoot());
@@ -382,7 +382,7 @@ public class PopulateComponentsUuidAndKeyStepTest extends BaseStepTest {
       .setPath("src/main/java/dir/Foo.java")
       .build());
 
-    treeRootHolder.setRoot(ComponentTreeBuilders.from(reportReader).build());
+    treeRootHolder.setRoot(ComponentTreeBuilder.from(reportReader));
     sut.execute();
 
     Map<Integer, Component> componentsByRef = getComponentsByRef(treeRootHolder.getRoot());
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportExtractionStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportExtractionStepTest.java
new file mode 100644 (file)
index 0000000..5f0cefd
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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.step;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.sonar.api.utils.internal.JUnitTempFolder;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+import org.sonar.core.computation.db.AnalysisReportDto;
+import org.sonar.server.computation.ReportQueue;
+import org.sonar.server.computation.batch.MutableBatchReportDirectoryHolder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+public class ReportExtractionStepTest {
+
+  @Rule
+  public JUnitTempFolder tempFolder = new JUnitTempFolder();
+  @Rule
+  public LogTester logTester = new LogTester().setLevel(LoggerLevel.INFO);
+
+  private MutableBatchReportDirectoryHolder reportDirectoryHolder = mock(MutableBatchReportDirectoryHolder.class);
+  private AnalysisReportDto dto = newDefaultReport();
+  private ArgumentCaptor<File> fileCaptor = ArgumentCaptor.forClass(File.class);
+
+  @Test
+  public void fail_if_corrupted_zip() throws Exception {
+    File zip = tempFolder.newFile();
+    FileUtils.write(zip, "not a file");
+
+    ReportExtractionStep underTest = new ReportExtractionStep(new ReportQueue.Item(dto, zip), tempFolder, reportDirectoryHolder);
+
+    try {
+      underTest.execute();
+      fail();
+    } catch (IllegalStateException e) {
+      assertThat(e.getMessage()).startsWith("Fail to unzip " + zip.getAbsolutePath() + " into ");
+    }
+    verifyNoMoreInteractions(reportDirectoryHolder);
+  }
+
+  @Test
+  public void verify_zip_decompression() throws URISyntaxException, IOException {
+    new ReportExtractionStep(new ReportQueue.Item(dto, demoZipFile()), tempFolder, reportDirectoryHolder).execute();
+
+    verify(reportDirectoryHolder).setDirectory(fileCaptor.capture());
+    verifyNoMoreInteractions(reportDirectoryHolder);
+
+    File createDir = fileCaptor.getValue();
+    assertThat(createDir.exists()).isTrue();
+    assertThat(createDir.isDirectory()).isTrue();
+    verifyFile(createDir, "1.txt", "1\n");
+    verifyFile(createDir, "2.txt", "2\n");
+    File subDir1 = verifyDir(createDir, "subdir1");
+    verifyFile(subDir1, "3.txt", "3\n");
+    verifyFile(subDir1, "4.txt", "4\n");
+    File subDir2 = verifyDir(createDir, "subdir2");
+    verifyFile(subDir2, "5.txt", "5\n");
+    File subdir3 = verifyDir(subDir2, "subdir3");
+    verifyFile(subdir3, "6.txt", "6\n");
+  }
+
+  @Test
+  public void verify_show_log_at_DEBUG_level() throws URISyntaxException {
+    logTester.setLevel(LoggerLevel.DEBUG);
+
+    new ReportExtractionStep(new ReportQueue.Item(dto, demoZipFile()), tempFolder, reportDirectoryHolder).execute();
+
+    List<String> logs = logTester.logs();
+    assertThat(logs).hasSize(1);
+    String log = logs.get(0);
+    assertThat(log.startsWith("Report extracted | size=")).isTrue();
+    assertThat(log.contains(" | project=P1 | time=")).isTrue();
+  }
+
+  private File demoZipFile() throws URISyntaxException {
+    return new File(getClass().getResource(getClass().getSimpleName() + "/" + "demozip.zip").toURI());
+  }
+
+  @Test
+  public void no_log_at_INFO_level() throws URISyntaxException {
+    logTester.setLevel(LoggerLevel.INFO);
+
+    new ReportExtractionStep(new ReportQueue.Item(dto, demoZipFile()), tempFolder, reportDirectoryHolder).execute();
+
+    assertThat(logTester.logs()).isEmpty();
+  }
+
+  private File verifyDir(File dir, String subDir) {
+    File file = new File(dir, subDir);
+    assertThat(file.exists()).isTrue();
+    assertThat(file.isDirectory()).isTrue();
+    return file;
+  }
+
+  private void verifyFile(File dir, String filename, String content) throws IOException {
+    File file = new File(dir, filename);
+    assertThat(file.exists()).isTrue();
+    assertThat(file.isDirectory()).isFalse();
+    assertThat(IOUtils.toString(new FileInputStream(file), "UTF-8")).isEqualTo(content);
+  }
+
+  private static AnalysisReportDto newDefaultReport() {
+    return AnalysisReportDto.newForTests(1L).setProjectKey("P1").setUuid("U1").setStatus(AnalysisReportDto.Status.PENDING);
+  }
+}
index 3c775d5b11ebec188114291b8e134f1a4e083fc7..290ab589a5f071f31d302a4719cc76e54dbd6e51 100644 (file)
@@ -35,10 +35,9 @@ import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.DbTester;
 import org.sonar.server.component.ComponentTesting;
 import org.sonar.server.component.db.ComponentDao;
-import org.sonar.server.computation.ComputationContext;
 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.ComponentTreeBuilders;
 import org.sonar.server.computation.component.DumbComponent;
 import org.sonar.server.db.DbClient;
 
@@ -53,6 +52,8 @@ public class ValidateProjectStepTest {
   public ExpectedException thrown = ExpectedException.none();
   @Rule
   public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+  @Rule
+  public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
 
   DbClient dbClient;
 
@@ -69,7 +70,7 @@ public class ValidateProjectStepTest {
     dbSession = dbClient.openSession(false);
     settings = new Settings();
 
-    sut = new ValidateProjectStep(dbClient, settings, reportReader);
+    sut = new ValidateProjectStep(dbClient, settings, reportReader, treeRootHolder);
   }
 
   @After
@@ -89,8 +90,9 @@ public class ValidateProjectStepTest {
     settings.appendProperty(CoreProperties.CORE_PREVENT_AUTOMATIC_PROJECT_CREATION, "true");
     dbClient.componentDao().insert(dbSession, ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY));
     dbSession.commit();
+    treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY));
 
-    sut.execute(new ComputationContext(ComponentTreeBuilders.from(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY))));
+    sut.execute();
   }
 
   @Test
@@ -106,8 +108,9 @@ public class ValidateProjectStepTest {
       .build());
 
     settings.appendProperty(CoreProperties.CORE_PREVENT_AUTOMATIC_PROJECT_CREATION, "true");
+    treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY));
 
-    sut.execute(new ComputationContext(ComponentTreeBuilders.from(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY))));
+    sut.execute();
   }
 
   @Test
@@ -120,8 +123,9 @@ public class ValidateProjectStepTest {
       .build());
 
     settings.appendProperty(CoreProperties.CORE_PREVENT_AUTOMATIC_PROJECT_CREATION, "false");
+    treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY));
 
-    sut.execute(new ComputationContext(ComponentTreeBuilders.from(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY))));
+    sut.execute();
   }
 
   @Test
@@ -134,9 +138,9 @@ public class ValidateProjectStepTest {
       .setType(Constants.ComponentType.PROJECT)
       .setKey(PROJECT_KEY)
       .build());
+    treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY + ":origin/master"));
 
-    sut.execute(new ComputationContext(
-      ComponentTreeBuilders.from(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY + ":origin/master"))));
+    sut.execute();
   }
 
   @Test
@@ -153,9 +157,9 @@ public class ValidateProjectStepTest {
       .setType(Constants.ComponentType.PROJECT)
       .setKey(PROJECT_KEY)
       .build());
+    treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY + ":bran#ch"));
 
-    sut.execute(new ComputationContext(
-      ComponentTreeBuilders.from(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY + ":bran#ch"))));
+    sut.execute();
   }
 
   @Test
@@ -179,10 +183,10 @@ public class ValidateProjectStepTest {
       .setType(Constants.ComponentType.MODULE)
       .setKey("Module$Key")
       .build());
+    treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", invalidProjectKey,
+      new DumbComponent(Component.Type.MODULE, 2, "BCDE", "Module$Key")));
 
-    DumbComponent root = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", invalidProjectKey,
-      new DumbComponent(Component.Type.MODULE, 2, "BCDE", "Module$Key"));
-    sut.execute(new ComputationContext(ComponentTreeBuilders.from(root)));
+    sut.execute();
   }
 
   @Test
@@ -210,10 +214,10 @@ public class ValidateProjectStepTest {
     dbClient.componentDao().insert(dbSession, project);
     dbSession.commit();
 
-    DumbComponent root = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
-      new DumbComponent(Component.Type.MODULE, 2, "BCDE", MODULE_KEY));
-    sut.execute(new ComputationContext(
-      ComponentTreeBuilders.from(root)));
+    treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
+      new DumbComponent(Component.Type.MODULE, 2, "BCDE", MODULE_KEY)));
+
+    sut.execute();
   }
 
   @Test
@@ -243,10 +247,10 @@ public class ValidateProjectStepTest {
     dbClient.componentDao().insert(dbSession, module);
     dbSession.commit();
 
-    DumbComponent root = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
-      new DumbComponent(Component.Type.MODULE, 2, "BCDE", MODULE_KEY));
-    sut.execute(new ComputationContext(
-      ComponentTreeBuilders.from(root)));
+    treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
+      new DumbComponent(Component.Type.MODULE, 2, "BCDE", MODULE_KEY)));
+
+    sut.execute();
   }
 
   @Test
@@ -277,10 +281,9 @@ public class ValidateProjectStepTest {
     dbClient.componentDao().insert(dbSession, module);
     dbSession.commit();
 
-    DumbComponent root = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
-      new DumbComponent(Component.Type.MODULE, 2, "BCDE", MODULE_KEY));
-    sut.execute(new ComputationContext(
-      ComponentTreeBuilders.from(root)));
+    treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
+      new DumbComponent(Component.Type.MODULE, 2, "BCDE", MODULE_KEY)));
+    
+    sut.execute();
   }
-
 }
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/ReportExtractionStepTest/demozip.zip b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/ReportExtractionStepTest/demozip.zip
new file mode 100644 (file)
index 0000000..929c067
Binary files /dev/null and b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/ReportExtractionStepTest/demozip.zip differ