]> source.dussan.org Git - sonarqube.git/commitdiff
update WS to rely on new tests - SONAR-6255 290/head
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Mon, 4 May 2015 09:34:54 +0000 (11:34 +0200)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Thu, 7 May 2015 07:46:13 +0000 (09:46 +0200)
52 files changed:
server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/SourceDbBenchmarkTest.java
server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/SourceIndexBenchmarkTest.java
server/sonar-server/src/main/java/org/sonar/core/computation/dbcleaner/IndexPurgeListener.java
server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.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/PersistTestsStep.java
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/main/java/org/sonar/server/search/IndexSynchronizer.java
server/sonar-server/src/main/java/org/sonar/server/source/index/FileSourcesUpdaterHelper.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/source/index/FileSourcesUpdaterUtil.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndexer.java
server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineResultSetIterator.java
server/sonar-server/src/main/java/org/sonar/server/test/index/CoveredFileDoc.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/test/index/TestDoc.java
server/sonar-server/src/main/java/org/sonar/server/test/index/TestIndex.java
server/sonar-server/src/main/java/org/sonar/server/test/index/TestIndexDefinition.java
server/sonar-server/src/main/java/org/sonar/server/test/index/TestIndexer.java
server/sonar-server/src/main/java/org/sonar/server/test/index/TestResultSetIterator.java
server/sonar-server/src/main/java/org/sonar/server/test/ws/TestAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsCoveredFilesAction.java
server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsListAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsShowAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsTestCasesAction.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsWs.java
server/sonar-server/src/main/java/org/sonar/server/user/UserSession.java
server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-covered-files.json [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-list.json [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-plan.json [deleted file]
server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-show.json [deleted file]
server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-testable.json [deleted file]
server/sonar-server/src/test/java/org/sonar/core/computation/dbcleaner/IndexPurgeListenerTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/ComputationStepsTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexTestsStepTest.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistTestsStepTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexerTest.java
server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineResultSetIteratorTest.java
server/sonar-server/src/test/java/org/sonar/server/test/db/TestTesting.java
server/sonar-server/src/test/java/org/sonar/server/test/index/TestIndexTest.java
server/sonar-server/src/test/java/org/sonar/server/test/index/TestIndexerTest.java
server/sonar-server/src/test/java/org/sonar/server/test/index/TestResultSetIteratorTest.java
server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsCoveredFilesActionTest.java
server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsListActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsShowActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsTestCasesActionTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsWsTest.java
server/sonar-server/src/test/java/org/sonar/server/user/UserSessionTest.java
server/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsCoveredFilesActionTest/tests-covered-files.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsListActionTest/list-main-file.json [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsListActionTest/list-test-uuid.json [new file with mode: 0644]
sonar-batch-protocol/src/main/gen-java/org/sonar/server/source/db/FileSourceDb.java
sonar-batch-protocol/src/main/protobuf/file_source_db.proto

index 953f036f12e4cbe80cbc64125dc138295fc0c55c..5ce4e1e6c55d9eb02f07b09f242b1b9163c7b71d 100644 (file)
@@ -31,7 +31,7 @@ import org.sonar.core.source.db.FileSourceDto;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.source.db.FileSourceDao;
 import org.sonar.server.source.db.FileSourceDb;
-import org.sonar.server.source.index.FileSourcesUpdaterUtil;
+import org.sonar.server.source.index.FileSourcesUpdaterHelper;
 import org.sonar.server.source.index.SourceLineResultSetIterator;
 
 import java.io.IOException;
@@ -76,7 +76,7 @@ public class SourceDbBenchmarkTest {
       long start = System.currentTimeMillis();
       SourceLineResultSetIterator it = SourceLineResultSetIterator.create(dbClient, connection, 0L, null);
       while (it.hasNext()) {
-        FileSourcesUpdaterUtil.Row row = it.next();
+        FileSourcesUpdaterHelper.Row row = it.next();
         assertThat(row.getUpdateRequests().size()).isEqualTo(NUMBER_OF_LINES);
         assertThat(row.getFileUuid()).isNotEmpty();
         counter.incrementAndGet();
index de4c7e274e82a88c9214e936eff4efdc0b7eb5d2..73943f97720e03e897b6f99e4e6d3ca986950f69 100644 (file)
@@ -102,7 +102,7 @@ public class SourceIndexBenchmarkTest {
     // TODO assertions
   }
 
-  private static class SourceIterator implements Iterator<FileSourcesUpdaterUtil.Row> {
+  private static class SourceIterator implements Iterator<FileSourcesUpdaterHelper.Row> {
     private final long nbFiles;
     private final int nbLinesPerFile;
     private int currentProject = 0;
@@ -125,7 +125,7 @@ public class SourceIndexBenchmarkTest {
     }
 
     @Override
-    public FileSourcesUpdaterUtil.Row next() {
+    public FileSourcesUpdaterHelper.Row next() {
       String projectUuid = "P" + currentProject;
       String fileUuid = "FILE" + count.get();
       dataBuilder.clear();
index 08db1573952e033550a9dec63c8d905fb4daaa68..8be40ab93b10190f3e4548ef263d142f3d91313a 100644 (file)
@@ -23,16 +23,20 @@ package org.sonar.core.computation.dbcleaner;
 import org.sonar.api.ServerComponent;
 import org.sonar.core.purge.PurgeListener;
 import org.sonar.server.source.index.SourceLineIndexer;
+import org.sonar.server.test.index.TestIndexer;
 
 public class IndexPurgeListener implements PurgeListener, ServerComponent {
   private final SourceLineIndexer sourceLineIndexer;
+  private final TestIndexer testIndexer;
 
-  public IndexPurgeListener(SourceLineIndexer sourceLineIndexer) {
+  public IndexPurgeListener(SourceLineIndexer sourceLineIndexer, TestIndexer testIndexer) {
     this.sourceLineIndexer = sourceLineIndexer;
+    this.testIndexer = testIndexer;
   }
 
   @Override
   public void onComponentDisabling(String uuid) {
     sourceLineIndexer.deleteByFile(uuid);
+    testIndexer.deleteByFile(uuid);
   }
 }
index 3626869b849db20b3a48f1937d9d80ea0ed999db..696b31b88647462f8528ab99e87574a7bc0a3c3f 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.server.db.DbClient;
 import org.sonar.server.issue.index.IssueAuthorizationIndexer;
 import org.sonar.server.issue.index.IssueIndexer;
 import org.sonar.server.source.index.SourceLineIndexer;
+import org.sonar.server.test.index.TestIndexer;
 
 public class ComponentCleanerService implements ServerComponent {
 
@@ -39,14 +40,16 @@ public class ComponentCleanerService implements ServerComponent {
   private final IssueAuthorizationIndexer issueAuthorizationIndexer;
   private final IssueIndexer issueIndexer;
   private final SourceLineIndexer sourceLineIndexer;
+  private final TestIndexer testIndexer;
 
   public ComponentCleanerService(DbClient dbClient, PurgeDao purgeDao, IssueAuthorizationIndexer issueAuthorizationIndexer, IssueIndexer issueIndexer,
-    SourceLineIndexer sourceLineIndexer) {
+                                 SourceLineIndexer sourceLineIndexer, TestIndexer testIndexer) {
     this.dbClient = dbClient;
     this.purgeDao = purgeDao;
     this.issueAuthorizationIndexer = issueAuthorizationIndexer;
     this.issueIndexer = issueIndexer;
     this.sourceLineIndexer = sourceLineIndexer;
+    this.testIndexer = testIndexer;
   }
 
   public void delete(String projectKey) {
@@ -70,6 +73,7 @@ public class ComponentCleanerService implements ServerComponent {
     issueAuthorizationIndexer.deleteProject(projectUuid, false);
     issueIndexer.deleteProject(projectUuid, true);
     sourceLineIndexer.deleteByProject(projectUuid);
+    testIndexer.deleteByProject(projectUuid);
   }
 
 }
index 30c26cb844dbc8331b028678c54d2b12126311a9..e4c0b273fa8a5be9e8c986b79323852f3ec2e918 100644 (file)
@@ -48,6 +48,7 @@ public class ComputationSteps {
       PersistEventsStep.class,
       PersistDuplicationMeasuresStep.class,
       PersistFileSourcesStep.class,
+      PersistTestsStep.class,
       PersistFileDependenciesStep.class,
 
       // Switch snapshot and purge
@@ -59,6 +60,7 @@ public class ComputationSteps {
       ApplyPermissionsStep.class,
       IndexIssuesStep.class,
       IndexSourceLinesStep.class,
+      IndexTestsStep.class,
       IndexViewsStep.class,
 
       // Purge of removed views has to be done after Views has been indexed
index 0d955de040eeca66cc2bee62c86ac566a5425ea5..c3180f8e665b3866daa8fcb15f9cc0b84c8af37f 100644 (file)
@@ -43,6 +43,7 @@ import org.sonar.server.computation.ComputationContext;
 import org.sonar.server.computation.source.ReportIterator;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.source.db.FileSourceDb;
+import org.sonar.server.source.db.FileSourceDb.Test.TestStatus;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -177,7 +178,7 @@ public class PersistTestsStep implements ComputationStep {
           dbTest.setStacktrace(batchTest.getStacktrace());
         }
         if (batchTest.hasStatus()) {
-          dbTest.setStatus(batchTest.getStatus());
+          dbTest.setStatus(TestStatus.valueOf(batchTest.getStatus().name()));
         }
         if (batchTest.hasMsg()) {
           dbTest.setMsg(batchTest.getMsg());
index ee2eb8f31e23779b07d21478be0dea5f2b2da90b..14edd65aa0a70c96960fe4b0e67d8b1f7bce1eb7 100644 (file)
@@ -349,9 +349,11 @@ import org.sonar.server.startup.RenameDeprecatedPropertyKeys;
 import org.sonar.server.startup.RenameIssueWidgets;
 import org.sonar.server.startup.ServerMetadataPersister;
 import org.sonar.server.test.CoverageService;
+import org.sonar.server.test.index.TestIndex;
+import org.sonar.server.test.index.TestIndexDefinition;
+import org.sonar.server.test.index.TestIndexer;
 import org.sonar.server.test.ws.TestsCoveredFilesAction;
-import org.sonar.server.test.ws.TestsShowAction;
-import org.sonar.server.test.ws.TestsTestCasesAction;
+import org.sonar.server.test.ws.TestsListAction;
 import org.sonar.server.test.ws.TestsWs;
 import org.sonar.server.text.MacroInterpreter;
 import org.sonar.server.text.RubyTextService;
@@ -897,9 +899,11 @@ class ServerComponents {
     // Tests
     pico.addSingleton(CoverageService.class);
     pico.addSingleton(TestsWs.class);
-    pico.addSingleton(TestsTestCasesAction.class);
     pico.addSingleton(TestsCoveredFilesAction.class);
-    pico.addSingleton(TestsShowAction.class);
+    pico.addSingleton(TestsListAction.class);
+    pico.addSingleton(TestIndexDefinition.class);
+    pico.addSingleton(TestIndex.class);
+    pico.addSingleton(TestIndexer.class);
 
     // Properties
     pico.addSingleton(PropertiesWs.class);
index 95bafedf6eef7ff68d8e202692c8ae65cf050e30..8d24946a043703d2bd64ca79385ad499fb17c42a 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.server.issue.index.IssueIndexer;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.source.index.SourceLineIndexer;
+import org.sonar.server.test.index.TestIndexer;
 import org.sonar.server.user.index.UserIndexer;
 import org.sonar.server.view.index.ViewIndexer;
 
@@ -43,6 +44,7 @@ public class IndexSynchronizer {
   private final DbClient db;
   private final IndexClient index;
   private final SourceLineIndexer sourceLineIndexer;
+  private final TestIndexer testIndexer;
   private final IssueAuthorizationIndexer issueAuthorizationIndexer;
   private final IssueIndexer issueIndexer;
   private final UserIndexer userIndexer;
@@ -55,11 +57,12 @@ public class IndexSynchronizer {
    * {@link org.sonar.server.issue.index.IssueIndexer}
    */
   public IndexSynchronizer(DbClient db, IndexClient index, SourceLineIndexer sourceLineIndexer,
-                           IssueAuthorizationIndexer issueAuthorizationIndexer, IssueIndexer issueIndexer,
+                           TestIndexer testIndexer, IssueAuthorizationIndexer issueAuthorizationIndexer, IssueIndexer issueIndexer,
                            UserIndexer userIndexer, ViewIndexer viewIndexer, ActivityIndexer activityIndexer) {
     this.db = db;
     this.index = index;
     this.sourceLineIndexer = sourceLineIndexer;
+    this.testIndexer = testIndexer;
     this.issueAuthorizationIndexer = issueAuthorizationIndexer;
     this.issueIndexer = issueIndexer;
     this.userIndexer = userIndexer;
@@ -89,6 +92,9 @@ public class IndexSynchronizer {
     LOG.info("Index source lines");
     sourceLineIndexer.setEnabled(true).index();
 
+    LOG.info("Index tests");
+    testIndexer.setEnabled(true).index();
+
     LOG.info("Index users");
     userIndexer.setEnabled(true).index();
 
diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/index/FileSourcesUpdaterHelper.java b/server/sonar-server/src/main/java/org/sonar/server/source/index/FileSourcesUpdaterHelper.java
new file mode 100644 (file)
index 0000000..b8b215a
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.source.index;
+
+import com.google.common.base.Joiner;
+import org.elasticsearch.action.update.UpdateRequest;
+import org.sonar.server.db.DbClient;
+
+import javax.annotation.Nullable;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FileSourcesUpdaterHelper {
+
+  private static final String SQL_ALL = "SELECT %s FROM file_sources WHERE data_type='%s' ";
+  private static final String AFTER_DATE_FILTER = " AND updated_at>?";
+  private static final String PROJECT_FILTER = " AND project_uuid=?";
+
+  private static final String[] FIELDS = {
+    "project_uuid",
+    "file_uuid",
+    "updated_at",
+    "binary_data"
+  };
+  private static final String FIELDS_ONE_LINE = Joiner.on(",").join(FIELDS);
+
+  private FileSourcesUpdaterHelper() {
+    // only static stuff
+  }
+
+  public static PreparedStatement preparedStatementToSelectFileSources(DbClient dbClient, Connection connection, String dataType, long afterDate, @Nullable String projectUuid)
+    throws SQLException {
+    String sql = createSQL(dataType, afterDate, projectUuid);
+    // rows are big, so they are scrolled once at a time (one row in memory at a time)
+    PreparedStatement stmt = dbClient.newScrollingSingleRowSelectStatement(connection, sql);
+    int index = 1;
+    if (afterDate > 0L) {
+      stmt.setLong(index, afterDate);
+      index++;
+    }
+    if (projectUuid != null) {
+      stmt.setString(index, projectUuid);
+    }
+    return stmt;
+  }
+
+  private static String createSQL(String dataType, long afterDate, @Nullable String projectUuid) {
+    StringBuilder sql = new StringBuilder(String.format(SQL_ALL, FIELDS_ONE_LINE, dataType));
+    if (afterDate > 0L || projectUuid != null) {
+      if (afterDate > 0L) {
+        sql.append(AFTER_DATE_FILTER);
+      }
+      if (projectUuid != null) {
+        sql.append(PROJECT_FILTER);
+      }
+    }
+    return sql.toString();
+  }
+
+  public static class Row {
+    private final String fileUuid, projectUuid;
+    private final long updatedAt;
+    private final List<UpdateRequest> updateRequests = new ArrayList<>();
+
+    public Row(String projectUuid, String fileUuid, long updatedAt) {
+      this.projectUuid = projectUuid;
+      this.fileUuid = fileUuid;
+      this.updatedAt = updatedAt;
+    }
+
+    public String getProjectUuid() {
+      return projectUuid;
+    }
+
+    public String getFileUuid() {
+      return fileUuid;
+    }
+
+    public long getUpdatedAt() {
+      return updatedAt;
+    }
+
+    public List<UpdateRequest> getUpdateRequests() {
+      return updateRequests;
+    }
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/index/FileSourcesUpdaterUtil.java b/server/sonar-server/src/main/java/org/sonar/server/source/index/FileSourcesUpdaterUtil.java
deleted file mode 100644 (file)
index 392792e..0000000
+++ /dev/null
@@ -1,107 +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.source.index;
-
-import com.google.common.base.Joiner;
-import org.elasticsearch.action.update.UpdateRequest;
-import org.sonar.server.db.DbClient;
-
-import javax.annotation.Nullable;
-
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-
-public class FileSourcesUpdaterUtil {
-
-  private static final String SQL_ALL = "SELECT %s FROM file_sources WHERE data_type='%s' ";
-  private static final String AFTER_DATE_FILTER = " AND updated_at>?";
-  private static final String PROJECT_FILTER = " AND project_uuid=?";
-
-  private static final String[] FIELDS = {
-    "project_uuid",
-    "file_uuid",
-    "updated_at",
-    "binary_data"
-  };
-
-  private FileSourcesUpdaterUtil() {
-    // only static stuff
-  }
-
-  public static PreparedStatement preparedStatementToSelectFileSources(DbClient dbClient, Connection connection, String dataType, long afterDate, @Nullable String projectUuid) throws SQLException {
-    String sql = createSQL(dataType, afterDate, projectUuid);
-    // rows are big, so they are scrolled once at a time (one row in memory at a time)
-    PreparedStatement stmt = dbClient.newScrollingSingleRowSelectStatement(connection, sql);
-    int index = 1;
-    if (afterDate > 0L) {
-      stmt.setLong(index, afterDate);
-      index++;
-    }
-    if (projectUuid != null) {
-      stmt.setString(index, projectUuid);
-    }
-    return stmt;
-  }
-
-  private static String createSQL(String dataType, long afterDate, @Nullable String projectUuid) {
-    String sql = String.format(SQL_ALL, Joiner.on(",").join(FIELDS), dataType);
-    if (afterDate > 0L || projectUuid != null) {
-      if (afterDate > 0L) {
-        sql += AFTER_DATE_FILTER;
-      }
-      if (projectUuid != null) {
-        sql += PROJECT_FILTER;
-      }
-    }
-    return sql;
-  }
-
-  public static class Row {
-    private final String fileUuid, projectUuid;
-    private final long updatedAt;
-    private final List<UpdateRequest> updateRequests = new ArrayList<>();
-
-    public Row(String projectUuid, String fileUuid, long updatedAt) {
-      this.projectUuid = projectUuid;
-      this.fileUuid = fileUuid;
-      this.updatedAt = updatedAt;
-    }
-
-    public String getProjectUuid() {
-      return projectUuid;
-    }
-
-    public String getFileUuid() {
-      return fileUuid;
-    }
-
-    public long getUpdatedAt() {
-      return updatedAt;
-    }
-
-    public List<UpdateRequest> getUpdateRequests() {
-      return updateRequests;
-    }
-  }
-}
index fa4b10807a3451d0fca6f04c514c23e35654b5aa..c22ea01b49f5461f7bcb4013eb181b884272f028 100644 (file)
@@ -39,7 +39,7 @@ import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_PROJ
 
 /**
  * Add to Elasticsearch index {@link SourceLineIndexDefinition} the rows of
- * db table FILE_SOURCES that are not indexed yet
+ * db table FILE_SOURCES of type SOURCE that are not indexed yet
  */
 public class SourceLineIndexer extends BaseIndexer {
 
@@ -81,16 +81,16 @@ public class SourceLineIndexer extends BaseIndexer {
     }
   }
 
-  public long index(Iterator<FileSourcesUpdaterUtil.Row> dbRows) {
+  public long index(Iterator<FileSourcesUpdaterHelper.Row> dbRows) {
     BulkIndexer bulk = new BulkIndexer(esClient, SourceLineIndexDefinition.INDEX);
     return doIndex(bulk, dbRows);
   }
 
-  private long doIndex(BulkIndexer bulk, Iterator<FileSourcesUpdaterUtil.Row> dbRows) {
+  private long doIndex(BulkIndexer bulk, Iterator<FileSourcesUpdaterHelper.Row> dbRows) {
     long maxUpdatedAt = 0L;
     bulk.start();
     while (dbRows.hasNext()) {
-      FileSourcesUpdaterUtil.Row row = dbRows.next();
+      FileSourcesUpdaterHelper.Row row = dbRows.next();
       addDeleteRequestsForLinesGreaterThan(bulk, row);
       for (UpdateRequest updateRequest : row.getUpdateRequests()) {
         bulk.add(updateRequest);
@@ -107,7 +107,7 @@ public class SourceLineIndexer extends BaseIndexer {
    * - same file has now 5 lines
    * Lines 6 to 10 must be removed from index.
    */
-  private void addDeleteRequestsForLinesGreaterThan(BulkIndexer bulk, FileSourcesUpdaterUtil.Row fileRow) {
+  private void addDeleteRequestsForLinesGreaterThan(BulkIndexer bulk, FileSourcesUpdaterHelper.Row fileRow) {
     int numberOfLines = fileRow.getUpdateRequests().size();
     SearchRequestBuilder searchRequest = esClient.prepareSearch(SourceLineIndexDefinition.INDEX)
       .setTypes(SourceLineIndexDefinition.TYPE)
index e187700d869c1585194107eefe651b98ae89cf87..95561fd4c6bf1335d73a9fa8a18ea64f0dda7821 100644 (file)
@@ -38,17 +38,17 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.Date;
 
-import static org.sonar.server.source.index.FileSourcesUpdaterUtil.Row;
+import static org.sonar.server.source.index.FileSourcesUpdaterHelper.Row;
 
 /**
- * Scroll over table FILE_SOURCES and directly parse data required to
+ * Scroll over table FILE_SOURCES of type SOURCE and directly parse data required to
  * populate the index sourcelines
  */
-public class SourceLineResultSetIterator extends ResultSetIterator<FileSourcesUpdaterUtil.Row> {
+public class SourceLineResultSetIterator extends ResultSetIterator<FileSourcesUpdaterHelper.Row> {
 
   public static SourceLineResultSetIterator create(DbClient dbClient, Connection connection, long afterDate, @Nullable String projectUuid) {
     try {
-      return new SourceLineResultSetIterator(FileSourcesUpdaterUtil.preparedStatementToSelectFileSources(dbClient, connection, FileSourceDto.Type.SOURCE, afterDate,
+      return new SourceLineResultSetIterator(FileSourcesUpdaterHelper.preparedStatementToSelectFileSources(dbClient, connection, FileSourceDto.Type.SOURCE, afterDate,
         projectUuid));
     } catch (SQLException e) {
       throw new IllegalStateException("Fail to prepare SQL request to select all file sources", e);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/test/index/CoveredFileDoc.java b/server/sonar-server/src/main/java/org/sonar/server/test/index/CoveredFileDoc.java
new file mode 100644 (file)
index 0000000..69cc1ab
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.test.index;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Maps;
+import org.sonar.server.search.BaseDoc;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_COVERED_FILE_LINES;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_COVERED_FILE_UUID;
+
+public class CoveredFileDoc extends BaseDoc {
+  public CoveredFileDoc(Map<String, Object> fields) {
+    super(fields);
+  }
+
+  @VisibleForTesting
+  public CoveredFileDoc() {
+    super(Maps.<String, Object>newHashMapWithExpectedSize(2));
+  }
+
+  public String fileUuid() {
+    return getField(FIELD_COVERED_FILE_UUID);
+  }
+
+  public CoveredFileDoc setFileUuid(String fileUuid) {
+    setField(FIELD_COVERED_FILE_UUID, fileUuid);
+    return this;
+  }
+
+  public List<Integer> coveredLines() {
+    return getField(FIELD_COVERED_FILE_LINES);
+  }
+
+  public CoveredFileDoc setCoveredLines(List<Integer> coveredLines) {
+    setField(FIELD_COVERED_FILE_LINES, coveredLines);
+    return this;
+  }
+
+}
index 7d0210e94685b5f4be257ea57feb74843c0f431c..3490c7e0f250c8fdb3d0b6ef140f72d92d3ba8bb 100644 (file)
@@ -24,10 +24,20 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.Maps;
 import org.sonar.server.search.BaseDoc;
 
+import javax.annotation.CheckForNull;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
-import static org.sonar.server.test.index.TestIndexDefinition.*;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_COVERED_FILES;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_DURATION_IN_MS;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_FILE_UUID;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_MESSAGE;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_NAME;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_PROJECT_UUID;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_STACKTRACE;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_STATUS;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_TEST_UUID;
 
 public class TestDoc extends BaseDoc {
   public TestDoc(Map<String, Object> fields) {
@@ -35,7 +45,7 @@ public class TestDoc extends BaseDoc {
   }
 
   @VisibleForTesting
-  TestDoc() {
+  public TestDoc() {
     super(Maps.<String, Object>newHashMapWithExpectedSize(10));
   }
 
@@ -84,8 +94,9 @@ public class TestDoc extends BaseDoc {
     return this;
   }
 
+  @CheckForNull
   public String message() {
-    return getField(FIELD_MESSAGE);
+    return getNullableField(FIELD_MESSAGE);
   }
 
   public TestDoc setMessage(String message) {
@@ -93,8 +104,9 @@ public class TestDoc extends BaseDoc {
     return this;
   }
 
+  @CheckForNull
   public String stackTrace() {
-    return getField(FIELD_STACKTRACE);
+    return getNullableField(FIELD_STACKTRACE);
   }
 
   public TestDoc setStackTrace(String stackTrace) {
@@ -102,8 +114,10 @@ public class TestDoc extends BaseDoc {
     return this;
   }
 
+  @CheckForNull
   public Long durationInMs() {
-    return getField(FIELD_DURATION_IN_MS);
+    Number number =  getNullableField(FIELD_DURATION_IN_MS);
+    return number == null ? null : number.longValue();
   }
 
   public TestDoc setDurationInMs(Long durationInMs) {
@@ -111,13 +125,24 @@ public class TestDoc extends BaseDoc {
     return this;
   }
 
-  // TODO TBE - it should be a CoverageBlockDoc list
-  public List<Map<String, Object>> coverageBlocks() {
-    return getField(FIELD_COVERAGE_BLOCKS);
-  }
-
-  public TestDoc setCoverageBlocks(List<Map<String, Object>> coverageBlocks) {
-    setField(FIELD_COVERAGE_BLOCKS, coverageBlocks);
+  public List<CoveredFileDoc> coveredFiles() {
+    List<Map<String, Object>> coveredFilesAsMaps = getNullableField(FIELD_COVERED_FILES);
+    if (coveredFilesAsMaps == null) {
+      return new ArrayList<>();
+    }
+    List<CoveredFileDoc> coveredFiles = new ArrayList<>();
+    for (Map<String, Object> coveredFileMap : coveredFilesAsMaps) {
+      coveredFiles.add(new CoveredFileDoc(coveredFileMap));
+    }
+    return coveredFiles;
+  }
+
+  public TestDoc setCoveredFiles(List<CoveredFileDoc> coveredFiles) {
+    List<Map<String, Object>> coveredFilesAsMaps = new ArrayList<>();
+    for (CoveredFileDoc coveredFile : coveredFiles) {
+      coveredFilesAsMaps.add(coveredFile.getFields());
+    }
+    setField(FIELD_COVERED_FILES, coveredFilesAsMaps);
     return this;
   }
 }
index af3abccc40533b4d2959e9457f25d1ae6d9c3f57..f862d5dd85d141cdf9a1ab1f583664ffff9d2374 100644 (file)
 
 package org.sonar.server.test.index;
 
+import com.google.common.base.Function;
+import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.index.query.FilterBuilders;
 import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.search.SearchHit;
+import org.sonar.core.util.NonNullInputFunction;
 import org.sonar.server.es.BaseIndex;
 import org.sonar.server.es.EsClient;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
-import static org.sonar.server.test.index.TestIndexDefinition.*;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_COVERED_FILES;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_COVERED_FILE_LINES;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_COVERED_FILE_UUID;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_FILE_UUID;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_TEST_UUID;
 
 public class TestIndex extends BaseIndex {
+  private static final Function<Map<String, Object>, TestDoc> CONVERTER = new NonNullInputFunction<Map<String, Object>, TestDoc>() {
+    @Override
+    protected TestDoc doApply(Map<String, Object> fields) {
+      return new TestDoc(fields);
+    }
+  };
+
   public TestIndex(EsClient client) {
     super(client);
   }
 
-  public List<Map<String, Object>> coveredLines(String testFileUuid, String methodName) {
-    List<Map<String, Object>> coverageBlocks = new ArrayList<>();
+  public List<CoveredFileDoc> coveredFiles(String testUuid) {
+    List<CoveredFileDoc> coveredFiles = new ArrayList<>();
 
     for (SearchHit hit : getClient().prepareSearch(TestIndexDefinition.INDEX)
       .setTypes(TestIndexDefinition.TYPE)
       .setSize(1)
-      .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.boolFilter()
-        .must(FilterBuilders.termFilter(FIELD_FILE_UUID, testFileUuid).cache(false))
-        .must(FilterBuilders.termFilter(TestIndexDefinition.FIELD_NAME, methodName).cache(false))))
+      .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.termFilter(FIELD_TEST_UUID, testUuid)))
       .get().getHits().getHits()) {
-      coverageBlocks.addAll(new TestDoc(hit.sourceAsMap()).coverageBlocks());
+      coveredFiles.addAll(new TestDoc(hit.sourceAsMap()).coveredFiles());
     }
 
-    return coverageBlocks;
+    return coveredFiles;
   }
 
-  public List<TestDoc> testMethods(String testFileUuid) {
-    List<TestDoc> testDocs = new ArrayList<>();
-
-    for (SearchHit hit : getClient().prepareSearch(TestIndexDefinition.INDEX)
+  public SearchResult<TestDoc> searchByTestFileUuid(String testFileUuid, SearchOptions searchOptions) {
+    SearchRequestBuilder searchRequest = getClient().prepareSearch(TestIndexDefinition.INDEX)
       .setTypes(TestIndexDefinition.TYPE)
-      .setSize(10_000)
-      .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.termFilter(FIELD_FILE_UUID, testFileUuid)))
-      .get().getHits().getHits()) {
-      testDocs.add(new TestDoc(hit.sourceAsMap()));
-    }
+      .setSize(searchOptions.getLimit())
+      .setFrom(searchOptions.getOffset())
+      .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.termFilter(FIELD_FILE_UUID, testFileUuid)));
 
-    return testDocs;
+    return new SearchResult<>(searchRequest.get(), CONVERTER);
   }
 
-  public List<TestDoc> testsCovering(String mainFileUuid, int line) {
-    List<TestDoc> testDocs = new ArrayList<>();
+  public SearchResult<TestDoc> searchBySourceFileUuidAndLineNumber(String sourceFileUuid, int lineNumber, SearchOptions searchOptions) {
+    SearchRequestBuilder searchRequest = getClient().prepareSearch(TestIndexDefinition.INDEX)
+      .setTypes(TestIndexDefinition.TYPE)
+      .setSize(searchOptions.getLimit())
+      .setFrom(searchOptions.getOffset())
+      .setQuery(QueryBuilders.nestedQuery(FIELD_COVERED_FILES, FilterBuilders.boolFilter()
+        .must(FilterBuilders.termFilter(FIELD_COVERED_FILES + "." + FIELD_COVERED_FILE_UUID, sourceFileUuid).cache(false))
+        .must(FilterBuilders.termFilter(FIELD_COVERED_FILES + "." + FIELD_COVERED_FILE_LINES, lineNumber).cache(false))));
+
+    return new SearchResult<>(searchRequest.get(), CONVERTER);
+  }
 
+  public TestDoc searchByTestUuid(String testUuid) {
     for (SearchHit hit : getClient().prepareSearch(TestIndexDefinition.INDEX)
       .setTypes(TestIndexDefinition.TYPE)
-      .setSize(10_000)
-      .setQuery(QueryBuilders.nestedQuery(FIELD_COVERAGE_BLOCKS, FilterBuilders.boolFilter()
-        .must(FilterBuilders.termFilter(FIELD_COVERAGE_BLOCKS + "." + FIELD_COVERAGE_BLOCK_UUID, mainFileUuid).cache(false))
-        .must(FilterBuilders.termFilter(FIELD_COVERAGE_BLOCKS + "." + FIELD_COVERAGE_BLOCK_LINES, line).cache(false))))
+      .setSize(1)
+      .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.termFilter(FIELD_TEST_UUID, testUuid)))
       .get().getHits().getHits()) {
-      testDocs.add(new TestDoc(hit.sourceAsMap()));
+      return new TestDoc(hit.sourceAsMap());
     }
 
-    return testDocs;
+    throw new IllegalStateException(String.format("Test uuid '%s' not found", testUuid));
+  }
+
+  public SearchResult<TestDoc> searchByTestUuid(String testUuid, SearchOptions searchOptions) {
+    SearchRequestBuilder searchRequest = getClient().prepareSearch(TestIndexDefinition.INDEX)
+      .setTypes(TestIndexDefinition.TYPE)
+      .setSize(searchOptions.getLimit())
+      .setFrom(searchOptions.getOffset())
+      .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(), FilterBuilders.termFilter(FIELD_TEST_UUID, testUuid)));
+
+    return new SearchResult<>(searchRequest.get(), CONVERTER);
   }
 }
index 7aef0a61fa9292153b682d2daf2c0e659fb4e244..25be407be28e3c824777f1e2497637abad95218b 100644 (file)
@@ -35,9 +35,9 @@ public class TestIndexDefinition implements IndexDefinition {
   public static final String FIELD_DURATION_IN_MS = "durationInMs";
   public static final String FIELD_MESSAGE = "message";
   public static final String FIELD_STACKTRACE = "stacktrace";
-  public static final String FIELD_COVERAGE_BLOCKS = "coverageBlocks";
-  public static final String FIELD_COVERAGE_BLOCK_UUID = "uuid";
-  public static final String FIELD_COVERAGE_BLOCK_LINES = "lines";
+  public static final String FIELD_COVERED_FILES = "coveredFiles";
+  public static final String FIELD_COVERED_FILE_UUID = "sourceFileUuid";
+  public static final String FIELD_COVERED_FILE_LINES = "coveredLines";
   public static final String FIELD_UPDATED_AT = "updatedAt";
 
   private final Settings settings;
@@ -54,19 +54,19 @@ public class TestIndexDefinition implements IndexDefinition {
     index.setShards(settings);
 
     NewIndex.NewIndexType nestedMapping = index.createType(TYPE);
-    nestedMapping.stringFieldBuilder(FIELD_COVERAGE_BLOCK_UUID).build();
-    nestedMapping.createIntegerField(FIELD_COVERAGE_BLOCK_LINES);
+    nestedMapping.stringFieldBuilder(FIELD_COVERED_FILE_UUID).build();
+    nestedMapping.createIntegerField(FIELD_COVERED_FILE_LINES);
 
     NewIndex.NewIndexType mapping = index.createType(TYPE);
     mapping.stringFieldBuilder(FIELD_PROJECT_UUID).build();
     mapping.stringFieldBuilder(FIELD_FILE_UUID).build();
     mapping.stringFieldBuilder(FIELD_TEST_UUID).build();
-    mapping.stringFieldBuilder(FIELD_NAME).build();
+    mapping.stringFieldBuilder(FIELD_NAME).disableSearch().build();
     mapping.stringFieldBuilder(FIELD_STATUS).disableSearch().build();
     mapping.createLongField(FIELD_DURATION_IN_MS);
     mapping.stringFieldBuilder(FIELD_MESSAGE).disableSearch().build();
     mapping.stringFieldBuilder(FIELD_STACKTRACE).disableSearch().build();
-    mapping.nestedObjectBuilder(FIELD_COVERAGE_BLOCKS, nestedMapping).build();
+    mapping.nestedObjectBuilder(FIELD_COVERED_FILES, nestedMapping).build();
     mapping.createDateTimeField(FIELD_UPDATED_AT);
   }
 }
index 13da026477d032505f7f4d4325bce05d82f7799f..193db4007034669b5fa130fbe66398ffa0630169 100644 (file)
@@ -29,7 +29,7 @@ import org.sonar.server.db.DbClient;
 import org.sonar.server.es.BaseIndexer;
 import org.sonar.server.es.BulkIndexer;
 import org.sonar.server.es.EsClient;
-import org.sonar.server.source.index.FileSourcesUpdaterUtil;
+import org.sonar.server.source.index.FileSourcesUpdaterHelper;
 
 import javax.annotation.Nullable;
 import java.sql.Connection;
@@ -40,7 +40,7 @@ import static org.sonar.server.test.index.TestIndexDefinition.*;
 
 /**
  * Add to Elasticsearch index {@link TestIndexDefinition} the rows of
- * db table FILE_SOURCES that are not indexed yet
+ * db table FILE_SOURCES of type TEST that are not indexed yet
  */
 public class TestIndexer extends BaseIndexer {
 
@@ -82,16 +82,16 @@ public class TestIndexer extends BaseIndexer {
     }
   }
 
-  public long index(Iterator<FileSourcesUpdaterUtil.Row> dbRows) {
+  public long index(Iterator<FileSourcesUpdaterHelper.Row> dbRows) {
     BulkIndexer bulk = new BulkIndexer(esClient, INDEX);
     return doIndex(bulk, dbRows);
   }
 
-  private long doIndex(BulkIndexer bulk, Iterator<FileSourcesUpdaterUtil.Row> dbRows) {
+  private long doIndex(BulkIndexer bulk, Iterator<FileSourcesUpdaterHelper.Row> dbRows) {
     long maxUpdatedAt = 0L;
     bulk.start();
     while (dbRows.hasNext()) {
-      FileSourcesUpdaterUtil.Row row = dbRows.next();
+      FileSourcesUpdaterHelper.Row row = dbRows.next();
       for (UpdateRequest updateRequest : row.getUpdateRequests()) {
         bulk.add(updateRequest);
       }
index e8827abf96ae5183be96358698489bf83d6f8112..482b867635a1903fff3ecfc2e6da771945e6bdc4 100644 (file)
@@ -27,8 +27,8 @@ import org.sonar.core.source.db.FileSourceDto;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.db.ResultSetIterator;
 import org.sonar.server.source.db.FileSourceDb;
-import org.sonar.server.source.index.FileSourcesUpdaterUtil;
-import org.sonar.server.source.index.FileSourcesUpdaterUtil.Row;
+import org.sonar.server.source.index.FileSourcesUpdaterHelper;
+import org.sonar.server.source.index.FileSourcesUpdaterHelper.Row;
 
 import javax.annotation.Nullable;
 
@@ -41,17 +41,29 @@ import java.sql.SQLException;
 import java.util.Date;
 import java.util.List;
 
-import static org.sonar.server.test.index.TestIndexDefinition.*;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_COVERED_FILES;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_COVERED_FILE_LINES;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_COVERED_FILE_UUID;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_DURATION_IN_MS;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_FILE_UUID;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_MESSAGE;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_NAME;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_PROJECT_UUID;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_STACKTRACE;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_STATUS;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_TEST_UUID;
+import static org.sonar.server.test.index.TestIndexDefinition.INDEX;
+import static org.sonar.server.test.index.TestIndexDefinition.TYPE;
 
 /**
- * Scroll over table FILE_SOURCES and directly parse data required to
+ * Scroll over table FILE_SOURCES of test type and directly parse data required to
  * populate the index sourcelines
  */
 public class TestResultSetIterator extends ResultSetIterator<Row> {
 
   public static TestResultSetIterator create(DbClient dbClient, Connection connection, long afterDate, @Nullable String projectUuid) {
     try {
-      return new TestResultSetIterator(FileSourcesUpdaterUtil.preparedStatementToSelectFileSources(dbClient, connection, FileSourceDto.Type.TEST, afterDate, projectUuid));
+      return new TestResultSetIterator(FileSourcesUpdaterHelper.preparedStatementToSelectFileSources(dbClient, connection, FileSourceDto.Type.TEST, afterDate, projectUuid));
     } catch (SQLException e) {
       throw new IllegalStateException("Fail to prepare SQL request to select all tests", e);
     }
@@ -89,12 +101,12 @@ public class TestResultSetIterator extends ResultSetIterator<Row> {
       writer.prop(FIELD_DURATION_IN_MS, test.hasExecutionTimeMs() ? test.getExecutionTimeMs() : null);
       writer.prop(FIELD_MESSAGE, test.hasMsg() ? test.getMsg() : null);
       writer.prop(FIELD_STACKTRACE, test.hasStacktrace() ? test.getStacktrace() : null);
-      writer.name(FIELD_COVERAGE_BLOCKS);
+      writer.name(FIELD_COVERED_FILES);
       writer.beginArray();
       for (FileSourceDb.Test.CoveredFile coveredFile : test.getCoveredFileList()) {
         writer.beginObject();
-        writer.prop(FIELD_COVERAGE_BLOCK_UUID, coveredFile.getFileUuid());
-        writer.name(FIELD_COVERAGE_BLOCK_LINES).valueObject(coveredFile.getCoveredLineList());
+        writer.prop(FIELD_COVERED_FILE_UUID, coveredFile.getFileUuid());
+        writer.name(FIELD_COVERED_FILE_LINES).valueObject(coveredFile.getCoveredLineList());
         writer.endObject();
       }
       writer.endArray();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/test/ws/TestAction.java b/server/sonar-server/src/main/java/org/sonar/server/test/ws/TestAction.java
new file mode 100644 (file)
index 0000000..7af1805
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.test.ws;
+
+import org.sonar.server.ws.WsAction;
+
+public interface TestAction extends WsAction {
+  // marker interface
+}
index d18f57b34a88829ca83bde7250c5ce4030cd2c6d..7617fc6c2e34c22b051336a3b87713c2e8541605 100644 (file)
 
 package org.sonar.server.test.ws;
 
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 import com.google.common.io.Resources;
-import org.sonar.api.component.Component;
 import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.RequestHandler;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
-import org.sonar.api.test.*;
 import org.sonar.api.utils.text.JsonWriter;
 import org.sonar.api.web.UserRole;
-import org.sonar.core.component.SnapshotPerspectives;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.test.index.CoveredFileDoc;
+import org.sonar.server.test.index.TestIndex;
 import org.sonar.server.user.UserSession;
 
-public class TestsCoveredFilesAction implements RequestHandler {
+import java.util.List;
+import java.util.Map;
 
-  private static final String KEY = "key";
-  private static final String TEST = "test";
+public class TestsCoveredFilesAction implements TestAction {
 
-  private final SnapshotPerspectives snapshotPerspectives;
+  public static final String TEST_UUID = "testUuid";
 
-  public TestsCoveredFilesAction(SnapshotPerspectives snapshotPerspectives) {
-    this.snapshotPerspectives = snapshotPerspectives;
+  private final DbClient dbClient;
+  private final TestIndex index;
+
+  public TestsCoveredFilesAction(DbClient dbClient, TestIndex index) {
+    this.dbClient = dbClient;
+    this.index = index;
   }
 
-  void define(WebService.NewController controller) {
+  @Override
+  public void define(WebService.NewController controller) {
     WebService.NewAction action = controller.createAction("covered_files")
-      .setDescription("Get the list of files covered by a test plan. Require Browse permission on file's project")
+      .setDescription("Get the list of source files covered by a test. Require Browse permission on test file's project")
       .setSince("4.4")
-      .setResponseExample(Resources.getResource(getClass(), "tests-example-plan.json"))
-      .setHandler(this);
-
-    action
-      .createParam(KEY)
-      .setRequired(true)
-      .setDescription("Test plan key")
-      .setExampleValue("my_project:/src/test/BarTest.java");
+      .setResponseExample(Resources.getResource(getClass(), "tests-example-covered-files.json"))
+      .setHandler(this)
+      .addPagingParams(100);
 
     action
-      .createParam(TEST)
+      .createParam(TEST_UUID)
       .setRequired(true)
-      .setDescription("Test case used to list files covered by the test plan")
-      .setExampleValue("my_test");
+      .setDescription("Test uuid")
+      .setExampleValue("ce4c03d6-430f-40a9-b777-ad877c00aa4d");
   }
 
   @Override
   public void handle(Request request, Response response) {
-    String fileKey = request.mandatoryParam(KEY);
-    UserSession.get().checkComponentPermission(UserRole.CODEVIEWER, fileKey);
-    String test = request.mandatoryParam(TEST);
+    String testUuid = request.mandatoryParam(TEST_UUID);
+    UserSession.get().checkComponentUuidPermission(UserRole.CODEVIEWER, index.searchByTestUuid(testUuid).fileUuid());
 
-    MutableTestPlan testPlan = snapshotPerspectives.as(MutableTestPlan.class, fileKey);
+    List<CoveredFileDoc> coveredFiles = index.coveredFiles(testUuid);
+    Map<String, ComponentDto> componentsByUuid = buildComponentsByUuid(coveredFiles);
     JsonWriter json = response.newJsonWriter().beginObject();
-    if (testPlan != null) {
-      writeTests(testPlan, test, json);
+    if (!coveredFiles.isEmpty()) {
+      writeTests(coveredFiles, componentsByUuid, json);
     }
     json.endObject().close();
   }
 
-  private void writeTests(TestPlan<MutableTestCase> testPlan, String test, JsonWriter json) {
+  private void writeTests(List<CoveredFileDoc> coveredFiles, Map<String, ComponentDto> componentsByUuid, JsonWriter json) {
     json.name("files").beginArray();
-    for (TestCase testCase : testPlan.testCasesByName(test)) {
-      for (CoverageBlock coverageBlock : testCase.coverageBlocks()) {
-        json.beginObject();
-        Component file = coverageBlock.testable().component();
-        json.prop("key", file.key());
-        json.prop("longName", file.longName());
-        json.prop("coveredLines", coverageBlock.lines().size());
-        json.endObject();
-      }
+    for (CoveredFileDoc coveredFile : coveredFiles) {
+      json.beginObject();
+      json.prop("key", componentsByUuid.get(coveredFile.fileUuid()).key());
+      json.prop("longName", componentsByUuid.get(coveredFile.fileUuid()).longName());
+      json.prop("coveredLines", coveredFile.coveredLines().size());
+      json.endObject();
     }
     json.endArray();
   }
 
+  private Map<String, ComponentDto> buildComponentsByUuid(List<CoveredFileDoc> coveredFiles) {
+    List<String> sourceFileUuids = Lists.transform(coveredFiles, new Function<CoveredFileDoc, String>() {
+      @Override
+      public String apply(CoveredFileDoc coveredFile) {
+        return coveredFile.fileUuid();
+      }
+    });
+    DbSession dbSession = dbClient.openSession(false);
+    List<ComponentDto> components;
+    try {
+      components = dbClient.componentDao().getByUuids(dbSession, sourceFileUuids);
+    } finally {
+      MyBatis.closeQuietly(dbSession);
+    }
+    return Maps.uniqueIndex(components, new Function<ComponentDto, String>() {
+      @Override
+      public String apply(ComponentDto component) {
+        return component.uuid();
+      }
+    });
+  }
+
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsListAction.java b/server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsListAction.java
new file mode 100644 (file)
index 0000000..95cff15
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * 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.test.ws;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.io.Resources;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.core.util.NonNullInputFunction;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.es.SearchOptions;
+import org.sonar.server.es.SearchResult;
+import org.sonar.server.test.index.CoveredFileDoc;
+import org.sonar.server.test.index.TestDoc;
+import org.sonar.server.test.index.TestIndex;
+import org.sonar.server.user.UserSession;
+
+import javax.annotation.Nullable;
+
+import java.util.List;
+import java.util.Map;
+
+public class TestsListAction implements TestAction {
+  public static final String TEST_UUID = "testUuid";
+  public static final String TEST_FILE_UUID = "testFileUuid";
+  public static final String TEST_FILE_KEY = "testFileKey";
+  public static final String SOURCE_FILE_UUID = "sourceFileUuid";
+  public static final String SOURCE_FILE_LINE_NUMBER = "sourceFileLineNumber";
+
+  private final DbClient dbClient;
+  private final TestIndex testIndex;
+
+  public TestsListAction(DbClient dbClient, TestIndex testIndex) {
+    this.dbClient = dbClient;
+    this.testIndex = testIndex;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    WebService.NewAction action = controller
+      .createAction("list")
+      .setDescription(
+        "Get the list of tests.<br /> " +
+          "Require Browse permission on file's project.<br /> " +
+          "One (and only one) of the following combination of parameters must be provided: " +
+          "<ul>" +
+          "<li>Test file UUID</li>" +
+          "<li>Test UUID</li>" +
+          "<li>Source file UUID and Source file line number</li>" +
+          "</ul>")
+      .setSince("5.2")
+      .setResponseExample(Resources.getResource(getClass(), "tests-example-list.json"))
+      .setHandler(this)
+      .addPagingParams(100);
+
+    action
+      .createParam(TEST_FILE_UUID)
+      .setDescription("Test file UUID")
+      .setExampleValue("ce4c03d6-430f-40a9-b777-ad877c00aa4d");
+
+    action
+      .createParam(TEST_FILE_KEY)
+      .setDescription("Test file key")
+      .setExampleValue("org.codehaus.sonar:sonar-server:src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java");
+
+    action
+      .createParam(TEST_UUID)
+      .setDescription("Test UUID")
+      .setExampleValue("c526ef20-131b-4486-9357-063fa64b5079");
+
+    action
+      .createParam(SOURCE_FILE_UUID)
+      .setDescription("Source file UUID. Must be provided with the source file line number.")
+      .setExampleValue("584a89f2-8037-4f7b-b82c-8b45d2d63fb2");
+
+    action
+      .createParam(SOURCE_FILE_LINE_NUMBER)
+      .setDescription("Source file line number. Must be provided with the source file UUID.")
+      .setExampleValue("10");
+  }
+
+  @Override
+  public void handle(Request request, Response response) {
+    String testUuid = request.param(TEST_UUID);
+    String testFileUuid = request.param(TEST_FILE_UUID);
+    String testFileKey = request.param(TEST_FILE_KEY);
+    String sourceFileUuid = request.param(SOURCE_FILE_UUID);
+    Integer sourceFileLineNumber = request.paramAsInt(SOURCE_FILE_LINE_NUMBER);
+    SearchOptions searchOptions = new SearchOptions().setPage(
+      request.mandatoryParamAsInt(WebService.Param.PAGE),
+      request.mandatoryParamAsInt(WebService.Param.PAGE_SIZE)
+      );
+
+    DbSession dbSession = dbClient.openSession(false);
+    SearchResult<TestDoc> tests;
+    Map<String, ComponentDto> componentsByTestFileUuid;
+    try {
+      tests = searchTests(dbSession, testUuid, testFileUuid, testFileKey, sourceFileUuid, sourceFileLineNumber, searchOptions);
+      componentsByTestFileUuid = buildComponentsByTestFileUuid(dbSession, tests.getDocs());
+    } finally {
+      MyBatis.closeQuietly(dbSession);
+    }
+
+    JsonWriter json = response.newJsonWriter().beginObject();
+    writeTests(tests.getDocs(), componentsByTestFileUuid, json);
+    searchOptions.writeJson(json, tests.getTotal());
+    json.endObject().close();
+  }
+
+  private void writeTests(List<TestDoc> tests, Map<String, ComponentDto> componentsByTestFileUuid, JsonWriter json) {
+    json.name("tests").beginArray();
+    for (TestDoc test : tests) {
+      String fileUuid = test.fileUuid();
+      json.beginObject();
+      json.prop("testUuid", test.testUuid());
+      json.prop("fileUuid", fileUuid);
+      json.prop("name", test.name());
+      json.prop("status", test.status());
+      json.prop("durationInMs", test.durationInMs());
+      json.prop("message", test.message());
+      json.prop("stacktrace", test.stackTrace());
+      json.prop("coveredLines", coveredLines(test.coveredFiles()));
+      json.prop("fileKey", componentsByTestFileUuid.get(fileUuid).key());
+      json.prop("fileLongName", componentsByTestFileUuid.get(fileUuid).longName());
+      json.endObject();
+    }
+    json.endArray();
+  }
+
+  private long coveredLines(List<CoveredFileDoc> coveredFiles) {
+    long numberOfLinesCovered = 0L;
+    for (CoveredFileDoc coveredFile : coveredFiles) {
+      numberOfLinesCovered += coveredFile.coveredLines().size();
+    }
+
+    return numberOfLinesCovered;
+  }
+
+  private Map<String, ComponentDto> buildComponentsByTestFileUuid(DbSession dbSession, List<TestDoc> tests) {
+    List<String> fileUuids = Lists.transform(tests, new NonNullInputFunction<TestDoc, String>() {
+      @Override
+      protected String doApply(TestDoc testDoc) {
+        return testDoc.fileUuid();
+      }
+    });
+    List<ComponentDto> components = dbClient.componentDao().getByUuids(dbSession, fileUuids);
+
+    return Maps.uniqueIndex(components, new NonNullInputFunction<ComponentDto, String>() {
+      @Override
+      public String doApply(ComponentDto componentDto) {
+        return componentDto.uuid();
+      }
+    });
+  }
+
+  private SearchResult<TestDoc> searchTests(DbSession dbSession, @Nullable String testUuid, @Nullable String testFileUuid, @Nullable String testFileKey,
+    @Nullable String sourceFileUuid, @Nullable Integer sourceFileLineNumber, SearchOptions searchOptions) {
+    if (testUuid != null) {
+      return searchTestsByTestUuid(dbSession, testUuid, searchOptions);
+    } else if (testFileUuid != null) {
+      return searchTestsByTestFileUuid(dbSession, testFileUuid, searchOptions);
+    } else if (testFileKey != null) {
+      return searchTestsByTestFileKey(dbSession, testFileKey, searchOptions);
+    } else if (sourceFileUuid != null && sourceFileLineNumber != null) {
+      return searchTestsBySourceFileUuidAndLineNumber(dbSession, sourceFileUuid, sourceFileLineNumber, searchOptions);
+    }
+
+    throw new IllegalArgumentException(
+      "One (and only one) of the following combination of parameters must be provided: 1) test UUID. 2) test file UUID. 3) test file key. 4) source file UUID and source file line number.");
+  }
+
+  private SearchResult<TestDoc> searchTestsBySourceFileUuidAndLineNumber(DbSession dbSession, String sourceFileUuid, Integer sourceFileLineNumber, SearchOptions searchOptions) {
+    checkComponentUuidPermission(dbSession, sourceFileUuid);
+    return testIndex.searchBySourceFileUuidAndLineNumber(sourceFileUuid, sourceFileLineNumber, searchOptions);
+  }
+
+  private SearchResult<TestDoc> searchTestsByTestFileKey(DbSession dbSession, String testFileKey, SearchOptions searchOptions) {
+    UserSession.get().checkComponentPermission(UserRole.CODEVIEWER, testFileKey);
+    ComponentDto testFile = dbClient.componentDao().getByKey(dbSession, testFileKey);
+
+    return testIndex.searchByTestFileUuid(testFile.uuid(), searchOptions);
+  }
+
+  private SearchResult<TestDoc> searchTestsByTestFileUuid(DbSession dbSession, String testFileUuid, SearchOptions searchOptions) {
+    checkComponentUuidPermission(dbSession, testFileUuid);
+    return testIndex.searchByTestFileUuid(testFileUuid, searchOptions);
+  }
+
+  private SearchResult<TestDoc> searchTestsByTestUuid(DbSession dbSession, String testUuid, SearchOptions searchOptions) {
+    checkComponentUuidPermission(dbSession, testIndex.searchByTestUuid(testUuid).fileUuid());
+    return testIndex.searchByTestUuid(testUuid, searchOptions);
+  }
+
+  private void checkComponentUuidPermission(DbSession dbSession, String componentUuid) {
+    ComponentDto component = dbClient.componentDao().getByUuid(dbSession, componentUuid);
+    UserSession.get().checkProjectUuidPermission(UserRole.CODEVIEWER, component.projectUuid());
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsShowAction.java b/server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsShowAction.java
deleted file mode 100644 (file)
index 2b04e68..0000000
+++ /dev/null
@@ -1,161 +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.test.ws;
-
-import com.google.common.io.Resources;
-import org.codehaus.staxmate.SMInputFactory;
-import org.codehaus.staxmate.in.SMHierarchicCursor;
-import org.codehaus.staxmate.in.SMInputCursor;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.RequestHandler;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.api.test.MutableTestPlan;
-import org.sonar.api.test.TestCase;
-import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.component.SnapshotPerspectives;
-import org.sonar.core.measure.db.MeasureDto;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.user.UserSession;
-
-import javax.annotation.CheckForNull;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-
-import java.io.StringReader;
-
-public class TestsShowAction implements RequestHandler {
-
-  private static final String KEY = "key";
-
-  private final DbClient dbClient;
-  private final SnapshotPerspectives snapshotPerspectives;
-
-  public TestsShowAction(DbClient dbClient, SnapshotPerspectives snapshotPerspectives) {
-    this.dbClient = dbClient;
-    this.snapshotPerspectives = snapshotPerspectives;
-  }
-
-  void define(WebService.NewController controller) {
-    WebService.NewAction action = controller.createAction("show")
-      .setDescription("Get the list of test cases of a test plan. Require Browse permission on file's project")
-      .setSince("4.4")
-      .setResponseExample(Resources.getResource(getClass(), "tests-example-show.json"))
-      .setHandler(this);
-
-    action
-      .createParam(KEY)
-      .setRequired(true)
-      .setDescription("Test plan key")
-      .setExampleValue("my_project:/src/test/BarTest.java");
-  }
-
-  @Override
-  public void handle(Request request, Response response) {
-    String fileKey = request.mandatoryParam(KEY);
-    UserSession.get().checkComponentPermission(UserRole.CODEVIEWER, fileKey);
-
-    String testData = findTestData(fileKey);
-    JsonWriter json = response.newJsonWriter().beginObject();
-    if (testData != null) {
-      writeFromTestData(testData, json);
-    } else {
-      MutableTestPlan testPlan = snapshotPerspectives.as(MutableTestPlan.class, fileKey);
-      if (testPlan != null) {
-        writeFromTestable(testPlan, json);
-      }
-    }
-    json.endObject().close();
-  }
-
-  private void writeFromTestable(MutableTestPlan testPlan, JsonWriter json) {
-    json.name("tests").beginArray();
-    for (TestCase testCase : testPlan.testCases()) {
-      json.beginObject();
-      json.prop("name", testCase.name());
-      json.prop("status", testCase.status().name());
-      json.prop("durationInMs", testCase.durationInMs());
-      json.prop("coveredLines", testCase.countCoveredLines());
-      json.prop("message", testCase.message());
-      json.prop("stackTrace", testCase.stackTrace());
-      json.endObject();
-    }
-    json.endArray();
-  }
-
-  private void writeFromTestData(String data, JsonWriter json) {
-    SMInputFactory inputFactory = initStax();
-    try {
-      SMHierarchicCursor root = inputFactory.rootElementCursor(new StringReader(data));
-      root.advance(); // tests-details
-      SMInputCursor cursor = root.childElementCursor();
-      json.name("tests").beginArray();
-      while (cursor.getNext() != null) {
-        json.beginObject();
-
-        json.prop("name", cursor.getAttrValue("name"));
-        json.prop("status", cursor.getAttrValue("status").toUpperCase());
-        // time can contain float value, we have to truncate it
-        json.prop("durationInMs", ((Double) Double.parseDouble(cursor.getAttrValue("time"))).longValue());
-
-        SMInputCursor errorCursor = cursor.childElementCursor();
-        if (errorCursor.getNext() != null) {
-          json.prop("message", errorCursor.getAttrValue("message"));
-          json.prop("stackTrace", errorCursor.getElemStringValue());
-        }
-
-        json.endObject();
-      }
-      json.endArray();
-    } catch (XMLStreamException e) {
-      throw new IllegalStateException("XML is not valid: " + e.getMessage(), e);
-    }
-  }
-
-  @CheckForNull
-  private String findTestData(String fileKey) {
-    DbSession session = dbClient.openSession(false);
-    try {
-      MeasureDto testData = dbClient.measureDao().findByComponentKeyAndMetricKey(session, fileKey, CoreMetrics.TEST_DATA_KEY);
-      if (testData != null) {
-        return testData.getData();
-      }
-    } finally {
-      MyBatis.closeQuietly(session);
-    }
-    return null;
-  }
-
-  private SMInputFactory initStax() {
-    XMLInputFactory xmlFactory = XMLInputFactory.newInstance();
-    xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
-    xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
-    // just so it won't try to load DTD in if there's DOCTYPE
-    xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
-    xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
-    return new SMInputFactory(xmlFactory);
-  }
-
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsTestCasesAction.java b/server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsTestCasesAction.java
deleted file mode 100644 (file)
index f4fa253..0000000
+++ /dev/null
@@ -1,156 +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.test.ws;
-
-import com.google.common.base.Preconditions;
-import com.google.common.io.Resources;
-import org.sonar.api.component.Component;
-import org.sonar.api.server.ws.Request;
-import org.sonar.api.server.ws.RequestHandler;
-import org.sonar.api.server.ws.Response;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.api.test.MutableTestable;
-import org.sonar.api.test.TestCase;
-import org.sonar.api.test.Testable;
-import org.sonar.api.utils.text.JsonWriter;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.component.SnapshotPerspectives;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.server.component.ComponentService;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.user.UserSession;
-
-import java.util.Map;
-
-import static com.google.common.collect.Maps.newHashMap;
-
-public class TestsTestCasesAction implements RequestHandler {
-
-  private static final String KEY = "key";
-  private static final String UUID = "uuid";
-  private static final String LINE = "line";
-
-  private final SnapshotPerspectives snapshotPerspectives;
-  private final ComponentService componentService;
-  private final DbClient dbClient;
-
-  public TestsTestCasesAction(SnapshotPerspectives snapshotPerspectives, ComponentService componentService, DbClient dbClient) {
-    this.snapshotPerspectives = snapshotPerspectives;
-    this.componentService = componentService;
-    this.dbClient = dbClient;
-  }
-
-  void define(WebService.NewController controller) {
-    WebService.NewAction action = controller.createAction("test_cases")
-      .setDescription("Get the list of test cases covering a given file and line. Require Browse permission on file's project")
-      .setSince("4.4")
-      .setResponseExample(Resources.getResource(getClass(), "tests-example-testable.json"))
-      .setHandler(this);
-
-    action
-      .createParam(KEY)
-      .setDescription("File key")
-      .setExampleValue("my_project:/src/foo/Bar.php");
-
-    action
-      .createParam(UUID)
-      .setDescription("File UUID")
-      .setExampleValue("584a89f2-8037-4f7b-b82c-8b45d2d63fb2");
-
-    action
-      .createParam(LINE)
-      .setRequired(true)
-      .setDescription("Line of the file used to get test cases")
-      .setExampleValue("10");
-  }
-
-  @Override
-  public void handle(Request request, Response response) {
-    String fileKey = request.param(KEY);
-    String fileUuid = request.param(UUID);
-    Preconditions.checkArgument(fileKey != null || fileUuid != null, "At least one of 'key' or 'uuid' must be provided");
-
-    if (fileKey != null) {
-      UserSession.get().checkComponentPermission(UserRole.CODEVIEWER, fileKey);
-    } else {
-      ComponentDto component = componentService.getByUuid(fileUuid);
-      fileKey = component.getKey();
-      UserSession.get().checkComponentPermission(UserRole.CODEVIEWER, fileKey);
-    }
-    int line = request.mandatoryParamAsInt(LINE);
-
-    Testable testable = snapshotPerspectives.as(MutableTestable.class, fileKey);
-    JsonWriter json = response.newJsonWriter().beginObject();
-    if (testable != null) {
-      Map<String, Integer> refByTestPlan = newHashMap();
-      Map<String, Component> componentsByKey = newHashMap();
-      writeTests(testable, line, refByTestPlan, componentsByKey, json);
-      writeFiles(refByTestPlan, componentsByKey, json);
-    }
-    json.endObject().close();
-  }
-
-  private void writeTests(Testable testable, Integer line, Map<String, Integer> refByTestPlan, Map<String, Component> componentsByKey, JsonWriter json) {
-    json.name("tests").beginArray();
-    for (TestCase testCase : testable.testCasesOfLine(line)) {
-      json.beginObject();
-      json.prop("name", testCase.name());
-      json.prop("status", testCase.status().name());
-      json.prop("durationInMs", testCase.durationInMs());
-
-      Component testPlan = testCase.testPlan().component();
-      Integer ref = refByTestPlan.get(testPlan.key());
-      if (ref == null) {
-        ref = refByTestPlan.size() + 1;
-        refByTestPlan.put(testPlan.key(), ref);
-        componentsByKey.put(testPlan.key(), testPlan);
-      }
-      json.prop("_ref", Integer.toString(ref));
-      json.endObject();
-    }
-    json.endArray();
-  }
-
-  private void writeFiles(Map<String, Integer> refByTestPlan, Map<String, Component> componentsByKey, JsonWriter json) {
-    DbSession session = dbClient.openSession(false);
-    try {
-      for (ComponentDto componentDto : dbClient.componentDao().getByKeys(session, componentsByKey.keySet())) {
-        componentsByKey.put(componentDto.key(), componentDto);
-      }
-    } finally {
-      session.close();
-    }
-
-    json.name("files").beginObject();
-    for (Map.Entry<String, Integer> entry : refByTestPlan.entrySet()) {
-      String componentKey = entry.getKey();
-      Integer ref = entry.getValue();
-      Component file = componentsByKey.get(componentKey);
-      json.name(Integer.toString(ref)).beginObject();
-      json.prop("key", file.key());
-      json.prop("uuid", ((ComponentDto) file).uuid());
-      json.prop("longName", file.longName());
-      json.endObject();
-    }
-    json.endObject();
-  }
-}
index 274e56ade2ab1de33446ffea133f2da87f981cd9..dcccd19d7ae152122a5a75c192dc8669bdb3657a 100644 (file)
@@ -24,14 +24,10 @@ import org.sonar.api.server.ws.WebService;
 
 public class TestsWs implements WebService {
 
-  private final TestsShowAction showAction;
-  private final TestsTestCasesAction testableAction;
-  private final TestsCoveredFilesAction planAction;
-
-  public TestsWs(TestsShowAction showAction, TestsTestCasesAction testableAction, TestsCoveredFilesAction planAction) {
-    this.showAction = showAction;
-    this.testableAction = testableAction;
-    this.planAction = planAction;
+  private final TestAction[] actions;
+
+  public TestsWs(TestAction... actions) {
+    this.actions = actions;
   }
 
   @Override
@@ -40,9 +36,9 @@ public class TestsWs implements WebService {
       .setSince("4.4")
       .setDescription("Tests management");
 
-    showAction.define(controller);
-    testableAction.define(controller);
-    planAction.define(controller);
+    for (TestAction action : actions) {
+      action.define(controller);
+    }
 
     controller.done();
   }
index 1186c16141e0455a463518accb94599396da1bfe..a49b0e37d487d088c1d632e596b6364d51c65a82 100644 (file)
@@ -36,7 +36,13 @@ import org.sonar.server.platform.Platform;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
 
 import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.collect.Maps.newHashMap;
@@ -227,6 +233,16 @@ public class UserSession {
     return this;
   }
 
+  /**
+   * Ensures that user implies the specified component permission on a component. If not a {@link org.sonar.server.exceptions.ForbiddenException} is thrown.
+   */
+  public UserSession checkComponentUuidPermission(String permission, String componentUuid) {
+    if (!hasComponentUuidPermission(permission, componentUuid)) {
+      throw new ForbiddenException(INSUFFICIENT_PRIVILEGES_MESSAGE);
+    }
+    return this;
+  }
+
   /**
    * Does the user have the given project permission for a component key ?
    */
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-covered-files.json b/server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-covered-files.json
new file mode 100644 (file)
index 0000000..ce75518
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "files": [
+    {
+      "key": "org.codehaus.sonar:sonar-server:src/main/java/org/sonar/server/paging/PagedResult.java",
+      "longName": "src/main/java/org/sonar/server/paging/PagedResult.java",
+      "coveredLines": 5
+    },
+    {
+      "key": "org.codehaus.sonar:sonar-server:src/main/java/org/sonar/server/rule/RuleDocumentParser.java",
+      "longName": "src/main/java/org/sonar/server/rule/RuleDocumentParser.java",
+      "coveredLines": 38
+    }
+  ]
+}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-list.json b/server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-list.json
new file mode 100644 (file)
index 0000000..2665f1f
--- /dev/null
@@ -0,0 +1,28 @@
+{
+  "tests": [
+    {
+      "testUuid": "ce4c03d6-430f-40a9-b777-ad877c00aa4d",
+      "fileUuid": "c526ef20-131b-4486-9357-063fa64b5079",
+      "name": "find_by_params",
+      "status": "OK",
+      "durationInMs": 10,
+      "status": "OK",
+      "durationInMs": 10,
+      "coveredLines": 89,
+      "fileKey": "org.codehaus.sonar:sonar-server:src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java",
+      "fileLongName": "src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java"
+    },
+    {
+      "testUuid": "584a89f2-8037-4f7b-b82c-8b45d2d63fb2",
+      "fileUuid": "c526ef20-131b-4486-9357-063fa64b5079",
+      "name": "find_rules_by_characteristics",
+      "status": "ERROR",
+      "durationInMs": 97,
+      "coveredLines": 0,
+      "message": "expected:<true> but was:<false>",
+      "stackTrace": "java.lang.AssertionError: expected:<true> but was:<false>\n\tat org.junit.Assert.fail(Assert.java:91)\n\tat org.junit.Assert.failNotEquals(Assert.java:645)\n\tat org.junit.Assert.assertEquals(Assert.java:126)\n\tat org.junit.Assert.assertEquals(Assert.java:145)\n\tat sonar.samples.testFailures.moduleA.FailTest.testAWithFailure(FailTest.java:12)\n",
+      "fileKey": "org.codehaus.sonar:sonar-server:src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java",
+      "fileLongName": "src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java"
+    }
+  ]
+}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-plan.json b/server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-plan.json
deleted file mode 100644 (file)
index ce75518..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "files": [
-    {
-      "key": "org.codehaus.sonar:sonar-server:src/main/java/org/sonar/server/paging/PagedResult.java",
-      "longName": "src/main/java/org/sonar/server/paging/PagedResult.java",
-      "coveredLines": 5
-    },
-    {
-      "key": "org.codehaus.sonar:sonar-server:src/main/java/org/sonar/server/rule/RuleDocumentParser.java",
-      "longName": "src/main/java/org/sonar/server/rule/RuleDocumentParser.java",
-      "coveredLines": 38
-    }
-  ]
-}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-show.json b/server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-show.json
deleted file mode 100644 (file)
index d4a2716..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "tests": [
-    {
-      "name": "find_by_params",
-      "status": "OK",
-      "durationInMs": 10,
-      "coveredLines" : 89
-    },
-    {
-      "name": "find_rules_by_characteristics",
-      "status": "ERROR",
-      "durationInMs": 97,
-      "coveredLines" : 0,
-      "message": "expected:<true> but was:<false>",
-      "stackTrace" : "java.lang.AssertionError: expected:<true> but was:<false>\n\tat org.junit.Assert.fail(Assert.java:91)\n\tat org.junit.Assert.failNotEquals(Assert.java:645)\n\tat org.junit.Assert.assertEquals(Assert.java:126)\n\tat org.junit.Assert.assertEquals(Assert.java:145)\n\tat sonar.samples.testFailures.moduleA.FailTest.testAWithFailure(FailTest.java:12)\n"
-    }
-  ]
-}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-testable.json b/server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-testable.json
deleted file mode 100644 (file)
index 92e038a..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "tests": [
-    {
-      "_ref": "1",
-      "name": "find_by_params",
-      "status": "OK",
-      "durationInMs": 10
-    },
-    {
-      "_ref": "2",
-      "name": "find_rules_by_characteristics",
-      "status": "ERROR",
-      "durationInMs": 97
-    }
-  ],
-  "files": {
-    "1": {
-      "key": "org.codehaus.sonar:sonar-server:src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java",
-      "longName": "src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java"
-    },
-    "2": {
-      "key": "org.codehaus.sonar:sonar-server:src/test/java/org/sonar/server/rule/RuleRegistryTest.java",
-      "longName": "src/test/java/org/sonar/server/rule/RuleRegistryTest.java"
-    }
-  }
-}
index 461e8f31312835df9e97b2ac1d0ac135a58e1192..137e0fb4b3a86f34ab92a5f599e8b554b3196321 100644 (file)
@@ -22,6 +22,7 @@ package org.sonar.core.computation.dbcleaner;
 
 import org.junit.Test;
 import org.sonar.server.source.index.SourceLineIndexer;
+import org.sonar.server.test.index.TestIndexer;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -30,12 +31,14 @@ public class IndexPurgeListenerTest {
 
   @Test
   public void call_source_line_indexer() {
-    SourceLineIndexer indexer = mock(SourceLineIndexer.class);
-    IndexPurgeListener sut = new IndexPurgeListener(indexer);
+    SourceLineIndexer sourceLineIndexer = mock(SourceLineIndexer.class);
+    TestIndexer testIndexer = mock(TestIndexer.class);
+    IndexPurgeListener sut = new IndexPurgeListener(sourceLineIndexer, testIndexer);
 
     sut.onComponentDisabling("123456");
 
-    verify(indexer).deleteByFile("123456");
+    verify(sourceLineIndexer).deleteByFile("123456");
+    verify(testIndexer).deleteByFile("123456");
   }
 
 }
index d36e4cb2412617fd23be9ae4488b246d8fcd7a20..5023190cd916298f9a1773bd51c5838ff06c48ab 100644 (file)
@@ -49,12 +49,14 @@ public class ComputationStepsTest {
       mock(PersistDuplicationMeasuresStep.class),
       mock(PersistNumberOfDaysSinceLastCommitStep.class),
       mock(PersistFileSourcesStep.class),
-      mock(PersistFileDependenciesStep.class)
+      mock(PersistFileDependenciesStep.class),
+      mock(PersistTestsStep.class),
+      mock(IndexTestsStep.class)
       );
 
-    assertThat(registry.orderedSteps()).hasSize(18);
+    assertThat(registry.orderedSteps()).hasSize(20);
     assertThat(registry.orderedSteps().get(0)).isInstanceOf(ParseReportStep.class);
-    assertThat(registry.orderedSteps().get(17)).isInstanceOf(SendIssueNotificationsStep.class);
+    assertThat(registry.orderedSteps().get(19)).isInstanceOf(SendIssueNotificationsStep.class);
   }
 
   @Test
index 0dd50aec1e549849e6b890a02ef53ec93f599a82..28eb9aeaa177613f37d33306cc6f4dade1498e21 100644 (file)
@@ -86,5 +86,6 @@ public class IndexTestsStepTest extends BaseStepTest {
     TestDoc doc = new TestDoc(docs.get(0).sourceAsMap());
     assertThat(doc.projectUuid()).isEqualTo("ABCD");
     assertThat(doc.fileUuid()).isEqualTo("FILE1_UUID");
+    assertThat(doc.coveredFiles()).isNotEmpty();
   }
 }
index 9513ab4f3e19c8de64ab78617addd37ec5e8d17a..8884d6476ea7dc8951d19aa1a9fcb45e67b7704b 100644 (file)
@@ -30,7 +30,6 @@ import org.sonar.api.utils.System2;
 import org.sonar.api.utils.log.LogTester;
 import org.sonar.api.utils.log.LoggerLevel;
 import org.sonar.batch.protocol.Constants;
-import org.sonar.batch.protocol.Constants.TestStatus;
 import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.batch.protocol.output.BatchReport.CoverageDetail;
 import org.sonar.batch.protocol.output.BatchReportReader;
@@ -128,7 +127,7 @@ public class PersistTestsStepTest extends BaseStepTest {
     writer.writeTests(TEST_FILE_REF_1, batchTests);
     List<CoverageDetail> coverageDetails = Arrays.asList(
       newCoverageDetail(1, MAIN_FILE_REF_1)
-    );
+      );
     writer.writeCoverageDetails(TEST_FILE_REF_1, coverageDetails);
 
     sut.execute(new ComputationContext(new BatchReportReader(reportDir), newProjectDto(PROJECT_UUID)));
@@ -167,7 +166,7 @@ public class PersistTestsStepTest extends BaseStepTest {
     assertThat(test1.getName()).isEqualTo("name#1");
     assertThat(test1.getMsg()).isEqualTo("message#1");
     assertThat(test1.getStacktrace()).isEqualTo("stacktrace#1");
-    assertThat(test1.getStatus()).isEqualTo(TestStatus.FAILURE);
+    assertThat(test1.getStatus()).isEqualTo(FileSourceDb.Test.TestStatus.FAILURE);
     assertThat(test1.getExecutionTimeMs()).isEqualTo(1_000);
     assertThat(test1.getCoveredFileCount()).isEqualTo(1);
     assertThat(test1.getCoveredFile(0).getCoveredLineList()).containsOnly(1, 2, 3);
@@ -233,7 +232,7 @@ public class PersistTestsStepTest extends BaseStepTest {
       .setTestData(Arrays.asList(FileSourceDb.Test.newBuilder()
         .setUuid("test-uuid-1")
         .setName("name#1")
-        .setStatus(TestStatus.ERROR)
+        .setStatus(FileSourceDb.Test.TestStatus.ERROR)
         .setStacktrace("old-stacktrace#1")
         .setMsg("old-message#1")
         .setExecutionTimeMs(987_654_321L)
@@ -262,7 +261,7 @@ public class PersistTestsStepTest extends BaseStepTest {
     FileSourceDb.Test test = dto.getTestData().get(0);
     assertThat(test.getUuid()).isNotEqualTo("test-uuid-1");
     assertThat(test.getName()).isEqualTo("name#1");
-    assertThat(test.getStatus()).isEqualTo(newBatchTest.getStatus());
+    assertThat(test.getStatus()).isEqualTo(FileSourceDb.Test.TestStatus.valueOf(newBatchTest.getStatus().name()));
     assertThat(test.getMsg()).isEqualTo(newBatchTest.getMsg());
     assertThat(test.getStacktrace()).isEqualTo(newBatchTest.getStacktrace());
     assertThat(test.getExecutionTimeMs()).isEqualTo(newBatchTest.getDurationInMs());
@@ -273,7 +272,7 @@ public class PersistTestsStepTest extends BaseStepTest {
 
   private BatchReport.Test newTest(int id) {
     return BatchReport.Test.newBuilder()
-      .setStatus(TestStatus.FAILURE)
+      .setStatus(Constants.TestStatus.FAILURE)
       .setName("name#" + id)
       .setStacktrace("stacktrace#" + id)
       .setMsg("message#" + id)
index 1ba00b7c1e4aececb15db629e6a46521a3d2dd53..a16bbdbe9177808a98d60dea309032d49c0520e7 100644 (file)
@@ -59,7 +59,7 @@ import org.sonar.server.permission.PermissionChange;
 import org.sonar.server.rule.RuleTesting;
 import org.sonar.server.rule.db.RuleDao;
 import org.sonar.server.source.db.FileSourceDb;
-import org.sonar.server.source.index.FileSourcesUpdaterUtil;
+import org.sonar.server.source.index.FileSourcesUpdaterHelper;
 import org.sonar.server.source.index.SourceLineResultSetIterator;
 import org.sonar.server.source.index.SourceLineIndexer;
 import org.sonar.server.tester.ServerTester;
@@ -598,7 +598,7 @@ public class IssueServiceMediumTest {
       .setLine(line)
       .setScmAuthor(scmAuthor)
       .build();
-    FileSourcesUpdaterUtil.Row row = SourceLineResultSetIterator.toRow(file.projectUuid(), file.uuid(), new Date(), dataBuilder.build());
+    FileSourcesUpdaterHelper.Row row = SourceLineResultSetIterator.toRow(file.projectUuid(), file.uuid(), new Date(), dataBuilder.build());
     tester.get(SourceLineIndexer.class).index(Iterators.singletonIterator(row));
   }
 
index e3f4bf04ae3f4e568f73364d8d717c827e62f46f..047c30f8e9e78d1906825f224eda352727ec4912 100644 (file)
@@ -140,7 +140,7 @@ public class SourceLineIndexerTest {
       .setSource("new source")
       .addAllDuplication(duplications)
       .build();
-    FileSourcesUpdaterUtil.Row dbRow = SourceLineResultSetIterator.toRow("P1", "F1", new Date(), dataBuilder.build());
+    FileSourcesUpdaterHelper.Row dbRow = SourceLineResultSetIterator.toRow("P1", "F1", new Date(), dataBuilder.build());
     indexer.index(Iterators.singletonIterator(dbRow));
 
     assertThat(countDocuments()).isEqualTo(2L);
@@ -214,7 +214,7 @@ public class SourceLineIndexerTest {
       .setOverallCoveredConditions(bigValue)
       .build();
 
-    FileSourcesUpdaterUtil.Row row = SourceLineResultSetIterator.toRow("P1", "F1", new Date(), dataBuilder.build());
+    FileSourcesUpdaterHelper.Row row = SourceLineResultSetIterator.toRow("P1", "F1", new Date(), dataBuilder.build());
     indexer.index(Iterators.singletonIterator(row));
 
     List<SearchHit> hits = getDocuments();
index 0429ac3fd180198c2f508707968ac90a1cdc3f94..205e4e4e35ae6dddbc31490d8695cda941b5433c 100644 (file)
@@ -71,7 +71,7 @@ public class SourceLineResultSetIteratorTest {
 
     iterator = SourceLineResultSetIterator.create(dbClient, connection, 0L, null);
     assertThat(iterator.hasNext()).isTrue();
-    FileSourcesUpdaterUtil.Row row = iterator.next();
+    FileSourcesUpdaterHelper.Row row = iterator.next();
     assertThat(row.getProjectUuid()).isEqualTo("P1");
     assertThat(row.getFileUuid()).isEqualTo("F1");
     assertThat(row.getUpdatedAt()).isEqualTo(1416239042000L);
@@ -110,7 +110,7 @@ public class SourceLineResultSetIteratorTest {
     FileSourceTesting.updateDataColumn(connection, "F1", dataBuilder.build());
 
     iterator = SourceLineResultSetIterator.create(dbClient, connection, 0L, null);
-    FileSourcesUpdaterUtil.Row row = iterator.next();
+    FileSourcesUpdaterHelper.Row row = iterator.next();
     assertThat(row.getProjectUuid()).isEqualTo("P1");
     assertThat(row.getFileUuid()).isEqualTo("F1");
     assertThat(row.getUpdatedAt()).isEqualTo(1416239042000L);
@@ -157,7 +157,7 @@ public class SourceLineResultSetIteratorTest {
 
     iterator = SourceLineResultSetIterator.create(dbClient, connection, 0L, "P1");
 
-    FileSourcesUpdaterUtil.Row row = iterator.next();
+    FileSourcesUpdaterHelper.Row row = iterator.next();
     assertThat(row.getProjectUuid()).isEqualTo("P1");
     assertThat(row.getFileUuid()).isEqualTo("F1");
 
@@ -174,7 +174,7 @@ public class SourceLineResultSetIteratorTest {
 
     iterator = SourceLineResultSetIterator.create(dbClient, connection, 1400000000000L, "P1");
 
-    FileSourcesUpdaterUtil.Row row = iterator.next();
+    FileSourcesUpdaterHelper.Row row = iterator.next();
     assertThat(row.getProjectUuid()).isEqualTo("P1");
     assertThat(row.getFileUuid()).isEqualTo("F1");
 
index 7c95d51d9d7392f7962ae8fbd5a7157b01033ebe..9a451e4fd0e80f414f95a6e498710dfeaa12ade2 100644 (file)
@@ -23,9 +23,9 @@ package org.sonar.server.test.db;
 import org.apache.commons.lang.RandomStringUtils;
 import org.apache.commons.lang.math.RandomUtils;
 import org.sonar.api.utils.internal.Uuids;
-import org.sonar.batch.protocol.Constants;
 import org.sonar.core.source.db.FileSourceDto;
 import org.sonar.server.source.db.FileSourceDb;
+import org.sonar.server.source.db.FileSourceDb.Test.TestStatus;
 
 import java.io.IOException;
 import java.sql.Connection;
@@ -52,28 +52,6 @@ public class TestTesting {
     stmt.close();
   }
 
-  public static List<FileSourceDb.Test> newFakeTests(int numberOfTests) throws IOException {
-    List<FileSourceDb.Test> tests = new ArrayList<>();
-    for (int i = 1; i <= numberOfTests; i++) {
-      FileSourceDb.Test.Builder test = FileSourceDb.Test.newBuilder()
-        .setUuid("TEST_FILE_UUID_" + i)
-        .setName("NAME_" + i)
-        .setStatus(Constants.TestStatus.FAILURE)
-        .setStacktrace("STACKTRACE_" + i)
-        .setMsg("MESSAGE_" + i)
-        .setExecutionTimeMs(i);
-      for (int j = 1; j <= numberOfTests; j++) {
-        test.addCoveredFile(
-          FileSourceDb.Test.CoveredFile.newBuilder()
-            .setFileUuid("MAIN_FILE_UUID_" + j)
-            .addCoveredLine(j)
-        );
-      }
-      tests.add(test.build());
-    }
-    return tests;
-  }
-
   /**
    * Generate random data.
    */
@@ -83,7 +61,7 @@ public class TestTesting {
       FileSourceDb.Test.Builder test = FileSourceDb.Test.newBuilder()
         .setUuid(Uuids.create())
         .setName(RandomStringUtils.randomAlphanumeric(20))
-        .setStatus(Constants.TestStatus.FAILURE)
+        .setStatus(TestStatus.FAILURE)
         .setStacktrace(RandomStringUtils.randomAlphanumeric(50))
         .setMsg(RandomStringUtils.randomAlphanumeric(30))
         .setExecutionTimeMs(RandomUtils.nextLong());
@@ -93,7 +71,7 @@ public class TestTesting {
           FileSourceDb.Test.CoveredFile.newBuilder()
             .setFileUuid(Uuids.create())
             .addCoveredLine(RandomUtils.nextInt(500))
-        );
+          );
       }
       tests.add(test.build());
     }
index c02292fdf373b202683ccb04ab49a7bf3257ac92..5b841bc2cf7211b9024f34e2c9c82049520a40fe 100644 (file)
@@ -25,8 +25,10 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.sonar.api.config.Settings;
 import org.sonar.server.es.EsTester;
+import org.sonar.server.es.SearchOptions;
 
-import java.util.*;
+import java.util.Arrays;
+import java.util.List;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -37,67 +39,101 @@ public class TestIndexTest {
   TestIndex sut = new TestIndex(es.client());
 
   @Before
-  public void before() throws Exception {
+  public void setup() throws Exception {
     es.truncateIndices();
   }
 
   @Test
-  public void lines_covered_a_test_method() throws Exception {
+  public void coveredFiles() throws Exception {
     es.putDocuments(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE,
       newTestDoc("1", newCoverageBlock("3"), newCoverageBlock("4"), newCoverageBlock("5")),
       newTestDoc("2", newCoverageBlock("5"), newCoverageBlock("6"), newCoverageBlock("7")));
 
-    List<Map<String, Object>> result = sut.coveredLines("uuid-1", "name-1");
+    List<CoveredFileDoc> result = sut.coveredFiles("uuid-1");
 
     assertThat(result).hasSize(3);
-    assertThat(result.get(0).get("uuid")).isEqualTo("main-uuid-3");
-    assertThat((List<Integer>)result.get(0).get("lines")).containsOnly(25, 33, 82);
+    assertThat(result).extractingResultOf("fileUuid").containsOnly("main-uuid-3", "main-uuid-4", "main-uuid-5");
+    assertThat(result.get(0).coveredLines()).containsOnly(25, 33, 82);
   }
 
   @Test
-  public void test_methods() throws Exception {
+  public void searchByTestFileUuid() throws Exception {
     es.putDocuments(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE,
       newTestDoc("1", newCoverageBlock("3"), newCoverageBlock("4"), newCoverageBlock("5")),
-      newTestDoc("1", newCoverageBlock("5"), newCoverageBlock("6"), newCoverageBlock("7")));
+      newTestDoc("1", newCoverageBlock("5"), newCoverageBlock("6"), newCoverageBlock("7")),
+      newTestDoc("2", newCoverageBlock("5"), newCoverageBlock("6"), newCoverageBlock("7")));
 
-    List<TestDoc> result = sut.testMethods("uuid-1");
+    List<TestDoc> result = sut.searchByTestFileUuid("file-uuid-1", searchOptions()).getDocs();
 
     assertThat(result).hasSize(2);
+    assertThat(result).extractingResultOf("name").containsOnly("name-1");
   }
 
   @Test
-  public void test_covering() throws Exception {
-    List<Map<String, Object>> coverageBlocks = new ArrayList<>();
-    coverageBlocks.add(newCoverageBlock("1"));
-    coverageBlocks.add(newCoverageBlock("2"));
-    coverageBlocks.add(newCoverageBlock("3"));
+  public void searchBySourceFileUuidAndLineNumber() throws Exception {
+    es.putDocuments(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE,
+      newTestDoc("1", newCoverageBlock("10"), newCoverageBlock("11"), newCoverageBlock("12")),
+      newTestDoc("2", newCoverageBlock("3"), newCoverageBlock("4"), newCoverageBlock("5")),
+      newTestDoc("3", newCoverageBlock("5"), newCoverageBlock("6"), newCoverageBlock("7")));
+
+    List<TestDoc> result = sut.searchBySourceFileUuidAndLineNumber("main-uuid-5", 82, searchOptions()).getDocs();
+
+    assertThat(result).hasSize(2);
+    assertThat(result).extractingResultOf("name").containsOnly("name-2", "name-3");
+  }
 
+  @Test
+  public void searchByTestUuid() throws Exception {
     es.putDocuments(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE,
       newTestDoc("1", newCoverageBlock("3"), newCoverageBlock("4"), newCoverageBlock("5")),
-      newTestDoc("1", newCoverageBlock("5"), newCoverageBlock("6"), newCoverageBlock("7")));
+      newTestDoc("2", newCoverageBlock("5"), newCoverageBlock("6"), newCoverageBlock("7")));
 
-    List<TestDoc> result = sut.testsCovering("main-uuid-5", 82);
+    TestDoc test = sut.searchByTestUuid("uuid-1");
 
-    assertThat(result).hasSize(2);
-    assertThat(result.get(0).name()).isEqualTo("name-1");
-    assertThat(result.get(0).coverageBlocks().get(0).get("uuid")).isEqualTo("main-uuid-3");
+    assertThat(test.testUuid()).isEqualTo("uuid-1");
+    assertThat(test.fileUuid()).isEqualTo("file-uuid-1");
+    assertThat(test.name()).isEqualTo("name-1");
+    assertThat(test.durationInMs()).isEqualTo(1L);
+    assertThat(test.status()).isEqualTo("status-1");
+    assertThat(test.message()).isEqualTo("message-1");
+    assertThat(test.coveredFiles()).hasSize(3);
+    assertThat(test.coveredFiles()).extractingResultOf("fileUuid").containsOnly("main-uuid-3", "main-uuid-4", "main-uuid-5");
   }
 
-  private Map<String, Object> newCoverageBlock(String id) {
-    Map<String, Object> coverageBlock = new HashMap<>();
-    coverageBlock.put("key", "project:file-" + id);
-    coverageBlock.put("uuid", "main-uuid-" + id);
-    coverageBlock.put("lines", Arrays.asList(25, 33, 82));
-    return coverageBlock;
+  @Test
+  public void searchByTestUuid_with_SearchOptions() throws Exception {
+    es.putDocuments(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE,
+      newTestDoc("1", newCoverageBlock("3"), newCoverageBlock("4"), newCoverageBlock("5")),
+      newTestDoc("2", newCoverageBlock("5"), newCoverageBlock("6"), newCoverageBlock("7")));
+
+    List<TestDoc> result = sut.searchByTestUuid("uuid-1", searchOptions()).getDocs();
+
+    assertThat(result).hasSize(1);
+    assertThat(result.get(0).testUuid()).isEqualTo("uuid-1");
   }
 
-  private TestDoc newTestDoc(String id, Map<String, Object>... coverageBlocks) {
+  private CoveredFileDoc newCoverageBlock(String id) {
+    return new CoveredFileDoc()
+      .setFileUuid("main-uuid-" + id)
+      .setCoveredLines(Arrays.asList(25, 33, 82));
+  }
+
+  private TestDoc newTestDoc(String id, CoveredFileDoc... coveredFiles) {
     return new TestDoc()
+      .setUuid("uuid-" + id)
       .setName("name-" + id)
       .setMessage("message-" + id)
       .setStackTrace("stacktrace-" + id)
       .setStatus("status-" + id)
-      .setFileUuid("uuid-" + id)
-      .setCoverageBlocks(Arrays.asList(coverageBlocks));
+      .setDurationInMs(Long.valueOf(id))
+      .setFileUuid("file-uuid-" + id)
+      .setProjectUuid("project-uuid-" + id)
+      .setCoveredFiles(Arrays.asList(coveredFiles));
+  }
+
+  private SearchOptions searchOptions() {
+    return new SearchOptions()
+      .setLimit(100)
+      .setOffset(0);
   }
 }
index 5356f4d1885f82359ea104b905564c265886bd27..9445800e6549d60bfaec0584c5866d06660d3547 100644 (file)
@@ -31,12 +31,12 @@ import org.junit.ClassRule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.sonar.api.config.Settings;
-import org.sonar.batch.protocol.Constants;
 import org.sonar.core.persistence.DbTester;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.es.EsTester;
 import org.sonar.server.source.db.FileSourceDb;
-import org.sonar.server.source.index.FileSourcesUpdaterUtil;
+import org.sonar.server.source.db.FileSourceDb.Test.TestStatus;
+import org.sonar.server.source.index.FileSourcesUpdaterHelper;
 import org.sonar.server.test.db.TestTesting;
 import org.sonar.test.DbTests;
 import org.sonar.test.TestUtils;
@@ -50,7 +50,16 @@ import java.util.Map;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.entry;
-import static org.sonar.server.test.index.TestIndexDefinition.*;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_DURATION_IN_MS;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_FILE_UUID;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_MESSAGE;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_NAME;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_PROJECT_UUID;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_STACKTRACE;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_STATUS;
+import static org.sonar.server.test.index.TestIndexDefinition.FIELD_TEST_UUID;
+import static org.sonar.server.test.index.TestIndexDefinition.INDEX;
+import static org.sonar.server.test.index.TestIndexDefinition.TYPE;
 
 @Category(DbTests.class)
 public class TestIndexerTest {
@@ -117,11 +126,11 @@ public class TestIndexerTest {
     indexTest("P1", "F1", "T1", "U111");
     indexTest("P1", "F2", "T1", "U121");
 
-    FileSourcesUpdaterUtil.Row dbRow = TestResultSetIterator.toRow("P1", "F1", new Date(), Arrays.asList(
+    FileSourcesUpdaterHelper.Row dbRow = TestResultSetIterator.toRow("P1", "F1", new Date(), Arrays.asList(
       FileSourceDb.Test.newBuilder()
         .setUuid("U111")
         .setName("NAME_1")
-        .setStatus(Constants.TestStatus.FAILURE)
+        .setStatus(TestStatus.FAILURE)
         .setMsg("NEW_MESSAGE_1")
         .setStacktrace("NEW_STACKTRACE_1")
         .setExecutionTimeMs(123_456L)
index 8aa38143d7e48eb9b56065b37a286d648f18e313..432e924ec1b9590aaf68c926f01a253bbec19249 100644 (file)
@@ -30,12 +30,15 @@ import org.junit.experimental.categories.Category;
 import org.sonar.core.persistence.DbTester;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.source.db.FileSourceDb;
-import org.sonar.server.source.index.FileSourcesUpdaterUtil;
+import org.sonar.server.source.db.FileSourceDb.Test.TestStatus;
+import org.sonar.server.source.index.FileSourcesUpdaterHelper;
 import org.sonar.server.source.index.SourceLineResultSetIteratorTest;
 import org.sonar.server.test.db.TestTesting;
 import org.sonar.test.DbTests;
 
+import java.io.IOException;
 import java.sql.Connection;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -72,10 +75,10 @@ public class TestResultSetIteratorTest {
   @Test
   public void traverse_db() throws Exception {
     db.prepareDbUnit(getClass(), "shared.xml");
-    TestTesting.updateDataColumn(connection, "F1", TestTesting.newFakeTests(3));
+    TestTesting.updateDataColumn(connection, "F1", newFakeTests(3));
     sut = TestResultSetIterator.create(dbClient, connection, 0L, null);
 
-    FileSourcesUpdaterUtil.Row row = sut.next();
+    FileSourcesUpdaterHelper.Row row = sut.next();
     assertThat(row.getProjectUuid()).isEqualTo("P1");
     assertThat(row.getFileUuid()).isEqualTo("F1");
     assertThat(row.getUpdatedAt()).isEqualTo(1416239042000L);
@@ -110,7 +113,7 @@ public class TestResultSetIteratorTest {
     TestTesting.updateDataColumn(connection, "F1", tests);
     sut = TestResultSetIterator.create(dbClient, connection, 0L, null);
 
-    FileSourcesUpdaterUtil.Row row = sut.next();
+    FileSourcesUpdaterHelper.Row row = sut.next();
 
     assertThat(row.getProjectUuid()).isEqualTo("P1");
     assertThat(row.getFileUuid()).isEqualTo("F1");
@@ -130,7 +133,7 @@ public class TestResultSetIteratorTest {
       TestIndexDefinition.FIELD_STACKTRACE,
       TestIndexDefinition.FIELD_MESSAGE,
       TestIndexDefinition.FIELD_STATUS,
-      TestIndexDefinition.FIELD_COVERAGE_BLOCKS
+      TestIndexDefinition.FIELD_COVERED_FILES
       );
   }
 
@@ -145,11 +148,11 @@ public class TestResultSetIteratorTest {
   @Test
   public void filter_by_project() throws Exception {
     db.prepareDbUnit(getClass(), "filter_by_project.xml");
-    TestTesting.updateDataColumn(connection, "F1", TestTesting.newFakeTests(1));
+    TestTesting.updateDataColumn(connection, "F1", newFakeTests(1));
 
     sut = TestResultSetIterator.create(dbClient, connection, 0L, "P1");
 
-    FileSourcesUpdaterUtil.Row row = sut.next();
+    FileSourcesUpdaterHelper.Row row = sut.next();
     assertThat(row.getProjectUuid()).isEqualTo("P1");
     assertThat(row.getFileUuid()).isEqualTo("F1");
 
@@ -160,11 +163,11 @@ public class TestResultSetIteratorTest {
   @Test
   public void filter_by_project_and_date() throws Exception {
     db.prepareDbUnit(getClass(), "filter_by_project_and_date.xml");
-    TestTesting.updateDataColumn(connection, "F1", TestTesting.newFakeTests(1));
+    TestTesting.updateDataColumn(connection, "F1", newFakeTests(1));
 
     sut = TestResultSetIterator.create(dbClient, connection, 1400000000000L, "P1");
 
-    FileSourcesUpdaterUtil.Row row = sut.next();
+    FileSourcesUpdaterHelper.Row row = sut.next();
     assertThat(row.getProjectUuid()).isEqualTo("P1");
     assertThat(row.getFileUuid()).isEqualTo("F1");
 
@@ -188,4 +191,26 @@ public class TestResultSetIteratorTest {
     }
   }
 
+  private static List<FileSourceDb.Test> newFakeTests(int numberOfTests) throws IOException {
+    List<FileSourceDb.Test> tests = new ArrayList<>();
+    for (int i = 1; i <= numberOfTests; i++) {
+      FileSourceDb.Test.Builder test = FileSourceDb.Test.newBuilder()
+        .setUuid("TEST_FILE_UUID_" + i)
+        .setName("NAME_" + i)
+        .setStatus(TestStatus.FAILURE)
+        .setStacktrace("STACKTRACE_" + i)
+        .setMsg("MESSAGE_" + i)
+        .setExecutionTimeMs(i);
+      for (int j = 1; j <= numberOfTests; j++) {
+        test.addCoveredFile(
+          FileSourceDb.Test.CoveredFile.newBuilder()
+            .setFileUuid("MAIN_FILE_UUID_" + j)
+            .addCoveredLine(j)
+          );
+      }
+      tests.add(test.build());
+    }
+    return tests;
+  }
+
 }
index 3cd501885432aad4b71fc7951e0e233d12039a71..35ab69f33a70c39a23f7af9c02691ca7eed640e1 100644 (file)
@@ -22,79 +22,55 @@ package org.sonar.server.test.ws;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.test.CoverageBlock;
-import org.sonar.api.test.MutableTestCase;
-import org.sonar.api.test.MutableTestPlan;
-import org.sonar.api.test.Testable;
 import org.sonar.api.web.UserRole;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.component.SnapshotPerspectives;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.test.index.CoveredFileDoc;
+import org.sonar.server.test.index.TestIndex;
 import org.sonar.server.user.MockUserSession;
 import org.sonar.server.ws.WsTester;
 
 import java.util.Arrays;
 
-import static com.google.common.collect.Lists.newArrayList;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyList;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
+import static org.sonar.server.component.ComponentTesting.newFileDto;
+import static org.sonar.server.component.ComponentTesting.newProjectDto;
+import static org.sonar.server.test.ws.TestsCoveredFilesAction.TEST_UUID;
 
-@RunWith(MockitoJUnitRunner.class)
 public class TestsCoveredFilesActionTest {
 
-  static final String TEST_PLAN_KEY = "src/test/java/org/foo/BarTest.java";
-
-  @Mock
-  MutableTestPlan testPlan;
-
-  WsTester tester;
+  WsTester ws;
+  private DbClient dbClient;
+  private TestIndex testIndex;
 
   @Before
   public void setUp() throws Exception {
-    SnapshotPerspectives snapshotPerspectives = mock(SnapshotPerspectives.class);
-    when(snapshotPerspectives.as(MutableTestPlan.class, TEST_PLAN_KEY)).thenReturn(testPlan);
-    tester = new WsTester(new TestsWs(mock(TestsShowAction.class), mock(TestsTestCasesAction.class), new TestsCoveredFilesAction(snapshotPerspectives)));
+    dbClient = mock(DbClient.class, RETURNS_DEEP_STUBS);
+    testIndex = mock(TestIndex.class, RETURNS_DEEP_STUBS);
+    ws = new WsTester(new TestsWs(new TestsCoveredFilesAction(dbClient, testIndex)));
   }
 
   @Test
-  public void plan() throws Exception {
-    MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, "SonarQube", TEST_PLAN_KEY);
-
-    MutableTestCase testCase1 = testCase("org.foo.Bar.java", "src/main/java/org/foo/Bar.java", 10);
-    MutableTestCase testCase2 = testCase("org.foo.File.java", "src/main/java/org/foo/File.java", 3);
-    when(testPlan.testCasesByName("my_test")).thenReturn(newArrayList(testCase1, testCase2));
-
-    WsTester.TestRequest request = tester.newGetRequest("api/tests", "covered_files").setParam("key", TEST_PLAN_KEY).setParam("test", "my_test");
-
-    request.execute().assertJson("{\n" +
-      "  \"files\": [\n" +
-      "    {\n" +
-      "      \"key\": \"org.foo.Bar.java\",\n" +
-      "      \"longName\": \"src/main/java/org/foo/Bar.java\",\n" +
-      "      \"coveredLines\" : 10\n" +
-      "    },\n" +
-      "    {\n" +
-      "      \"key\": \"org.foo.File.java\",\n" +
-      "      \"longName\": \"src/main/java/org/foo/File.java\",\n" +
-      "      \"coveredLines\" : 3\n" +
-      "    }\n" +
-      "  ]\n" +
-      "}\n");
+  public void covered_files() throws Exception {
+    MockUserSession.set().addComponentUuidPermission(UserRole.CODEVIEWER, "SonarQube", "test-file-uuid");
+
+    when(testIndex.searchByTestUuid(anyString()).fileUuid()).thenReturn("test-file-uuid");
+    when(testIndex.coveredFiles("test-uuid")).thenReturn(Arrays.asList(
+      new CoveredFileDoc().setFileUuid("bar-uuid").setCoveredLines(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
+      new CoveredFileDoc().setFileUuid("file-uuid").setCoveredLines(Arrays.asList(1, 2, 3))
+      ));
+    when(dbClient.componentDao().getByUuids(any(DbSession.class), anyList())).thenReturn(
+      Arrays.asList(
+        newFileDto(newProjectDto(), "bar-uuid").setKey("org.foo.Bar.java").setLongName("src/main/java/org/foo/Bar.java"),
+        newFileDto(newProjectDto(), "file-uuid").setKey("org.foo.File.java").setLongName("src/main/java/org/foo/File.java")));
+
+    WsTester.TestRequest request = ws.newGetRequest("api/tests", "covered_files").setParam(TEST_UUID, "test-uuid");
+
+    request.execute().assertJson(getClass(), "tests-covered-files.json");
   }
-
-  private MutableTestCase testCase(String fileKey, String fileLongName, int coveredLines) {
-    Testable testable = mock(Testable.class);
-    when(testable.component()).thenReturn(new ComponentDto().setKey(fileKey).setLongName(fileLongName));
-
-    CoverageBlock block = mock(CoverageBlock.class);
-    when(block.testable()).thenReturn(testable);
-    when(block.lines()).thenReturn(Arrays.asList(new Integer[coveredLines]));
-
-    MutableTestCase testCase = mock(MutableTestCase.class);
-    when(testCase.coverageBlocks()).thenReturn(newArrayList(block));
-    return testCase;
-  }
-
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsListActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsListActionTest.java
new file mode 100644 (file)
index 0000000..08e1500
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * 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.test.ws;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.test.index.CoveredFileDoc;
+import org.sonar.server.test.index.TestDoc;
+import org.sonar.server.test.index.TestIndex;
+import org.sonar.server.test.index.TestIndexDefinition;
+import org.sonar.server.user.MockUserSession;
+import org.sonar.server.ws.WsTester;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class TestsListActionTest {
+  DbClient dbClient;
+  DbSession dbSession;
+  TestIndex testIndex;
+
+  WsTester ws;
+
+  @ClassRule
+  public static DbTester db = new DbTester();
+  @ClassRule
+  public static EsTester es = new EsTester().addDefinitions(new TestIndexDefinition(new Settings()));
+
+  @Before
+  public void setUp() throws Exception {
+    dbClient = new DbClient(db.database(), db.myBatis(), new ComponentDao());
+    dbSession = dbClient.openSession(false);
+    db.truncateTables();
+    es.truncateIndices();
+    testIndex = new TestIndex(es.client());
+
+    ws = new WsTester(new TestsWs(new TestsListAction(dbClient, testIndex)));
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    dbSession.close();
+  }
+
+  @Test
+  public void list_based_on_test_uuid() throws Exception {
+    MockUserSession.set().addProjectUuidPermissions(UserRole.CODEVIEWER, TestFile1.PROJECT_UUID);
+
+    dbClient.componentDao().insert(dbSession, TestFile1.newDto());
+    dbSession.commit();
+
+    es.putDocuments(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE,
+      new TestDoc()
+        .setUuid(TestFile1.UUID)
+        .setName(TestFile1.NAME)
+        .setFileUuid(TestFile1.FILE_UUID)
+        .setDurationInMs(TestFile1.DURATION_IN_MS)
+        .setStatus(TestFile1.STATUS)
+        .setMessage(TestFile1.MESSAGE)
+        .setCoveredFiles(TestFile1.COVERED_FILES)
+        .setStackTrace(TestFile1.STACKTRACE)
+      );
+
+    WsTester.TestRequest request = ws.newGetRequest("api/tests", "list").setParam(TestsListAction.TEST_UUID, TestFile1.UUID);
+
+    request.execute().assertJson(getClass(), "list-test-uuid.json");
+  }
+
+  @Test
+  public void list_based_on_test_file_uuid() throws Exception {
+    MockUserSession.set().addProjectUuidPermissions(UserRole.CODEVIEWER, TestFile1.PROJECT_UUID);
+    dbClient.componentDao().insert(dbSession, TestFile1.newDto());
+    dbSession.commit();
+
+    es.putDocuments(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE,
+      new TestDoc()
+        .setUuid(TestFile1.UUID)
+        .setName(TestFile1.NAME)
+        .setFileUuid(TestFile1.FILE_UUID)
+        .setDurationInMs(TestFile1.DURATION_IN_MS)
+        .setCoveredFiles(TestFile1.COVERED_FILES)
+        .setStatus(TestFile1.STATUS)
+        .setMessage(TestFile1.MESSAGE)
+        .setStackTrace(TestFile1.STACKTRACE));
+
+    WsTester.TestRequest request = ws.newGetRequest("api/tests", "list").setParam(TestsListAction.TEST_FILE_UUID, TestFile1.FILE_UUID);
+
+    request.execute().assertJson(getClass(), "list-test-uuid.json");
+  }
+
+  @Test
+  public void list_based_on_test_file_key() throws Exception {
+    MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, TestFile1.PROJECT_UUID, TestFile1.KEY);
+    dbClient.componentDao().insert(dbSession, TestFile1.newDto());
+    dbSession.commit();
+
+    es.putDocuments(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE,
+      new TestDoc()
+        .setUuid(TestFile1.UUID)
+        .setName(TestFile1.NAME)
+        .setFileUuid(TestFile1.FILE_UUID)
+        .setDurationInMs(TestFile1.DURATION_IN_MS)
+        .setCoveredFiles(TestFile1.COVERED_FILES)
+        .setStatus(TestFile1.STATUS)
+        .setMessage(TestFile1.MESSAGE)
+        .setStackTrace(TestFile1.STACKTRACE)
+      );
+
+    WsTester.TestRequest request = ws.newGetRequest("api/tests", "list").setParam(TestsListAction.TEST_FILE_KEY, TestFile1.KEY);
+
+    request.execute().assertJson(getClass(), "list-test-uuid.json");
+  }
+
+  @Test
+  public void list_based_on_main_file_and_line_number() throws Exception {
+    String mainFileUuid = "MAIN-FILE-UUID";
+    MockUserSession.set().addProjectUuidPermissions(UserRole.CODEVIEWER, TestFile1.PROJECT_UUID);
+    dbClient.componentDao().insert(dbSession,
+      new ComponentDto()
+        .setUuid(TestFile1.FILE_UUID)
+        .setLongName(TestFile1.LONG_NAME)
+        .setKey(TestFile1.KEY)
+        .setProjectUuid(TestFile1.PROJECT_UUID),
+      new ComponentDto()
+        .setUuid(TestFile2.FILE_UUID)
+        .setLongName(TestFile2.LONG_NAME)
+        .setProjectUuid(TestFile2.PROJECT_UUID)
+        .setKey(TestFile2.KEY),
+      new ComponentDto()
+        .setUuid(mainFileUuid)
+        .setProjectUuid(TestFile1.PROJECT_UUID)
+      );
+    dbSession.commit();
+
+    es.putDocuments(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE,
+      new TestDoc()
+        .setUuid(TestFile1.UUID)
+        .setName(TestFile1.NAME)
+        .setFileUuid(TestFile1.FILE_UUID)
+        .setDurationInMs(TestFile1.DURATION_IN_MS)
+        .setStatus(TestFile1.STATUS)
+        .setMessage(TestFile1.MESSAGE)
+        .setCoveredFiles(TestFile1.COVERED_FILES)
+        .setStackTrace(TestFile1.STACKTRACE),
+      new TestDoc()
+        .setUuid(TestFile2.UUID)
+        .setName(TestFile2.NAME)
+        .setFileUuid(TestFile2.FILE_UUID)
+        .setDurationInMs(TestFile2.DURATION_IN_MS)
+        .setStatus(TestFile2.STATUS)
+        .setStackTrace(TestFile2.STATUS)
+        .setMessage(TestFile2.MESSAGE)
+        .setCoveredFiles(TestFile2.COVERED_FILES)
+        .setStackTrace(TestFile2.STACKTRACE));
+
+    WsTester.TestRequest request = ws.newGetRequest("api/tests", "list")
+      .setParam(TestsListAction.SOURCE_FILE_UUID, mainFileUuid)
+      .setParam(TestsListAction.SOURCE_FILE_LINE_NUMBER, "10");
+
+    request.execute().assertJson(getClass(), "list-main-file.json");
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void fail_when_no_argument() throws Exception {
+    ws.newGetRequest("api/tests", "list").execute();
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void fail_when_main_file_uuid_without_line_number() throws Exception {
+    ws.newGetRequest("api/tests", "list").setParam(TestsListAction.SOURCE_FILE_UUID, "ANY-UUID").execute();
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void fail_when_no_sufficent_privilege_on_file_uuid() throws Exception {
+    MockUserSession.set().addProjectUuidPermissions(UserRole.USER, TestFile1.PROJECT_UUID);
+    dbClient.componentDao().insert(dbSession, TestFile1.newDto());
+    dbSession.commit();
+    ws.newGetRequest("api/tests", "list").setParam(TestsListAction.TEST_FILE_UUID, TestFile1.FILE_UUID).execute();
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void fail_when_no_sufficent_privilege_on_test_uuid() throws Exception {
+    MockUserSession.set().addProjectUuidPermissions(UserRole.USER, TestFile1.PROJECT_UUID);
+    dbClient.componentDao().insert(dbSession, TestFile1.newDto());
+    dbSession.commit();
+    ws.newGetRequest("api/tests", "list").setParam(TestsListAction.TEST_FILE_UUID, TestFile1.FILE_UUID).execute();
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void fail_when_no_sufficent_privilege_on_file_key() throws Exception {
+    MockUserSession.set().addProjectUuidPermissions(UserRole.USER, TestFile1.PROJECT_UUID);
+    dbClient.componentDao().insert(dbSession, TestFile1.newDto());
+    dbSession.commit();
+    ws.newGetRequest("api/tests", "list").setParam(TestsListAction.TEST_FILE_KEY, TestFile1.KEY).execute();
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void fail_when_no_sufficient_privilege_on_main_file_uuid() throws Exception {
+    MockUserSession.set().addProjectUuidPermissions(UserRole.USER, TestFile1.PROJECT_UUID);
+    String mainFileUuid = "MAIN-FILE-UUID";
+    dbClient.componentDao().insert(dbSession, new ComponentDto().setUuid(mainFileUuid).setProjectUuid(TestFile1.PROJECT_UUID));
+    dbSession.commit();
+
+    ws.newGetRequest("api/tests", "list")
+      .setParam(TestsListAction.SOURCE_FILE_UUID, mainFileUuid)
+      .setParam(TestsListAction.SOURCE_FILE_LINE_NUMBER, "10")
+      .execute();
+  }
+
+  private static final class TestFile1 {
+    public static final String UUID = "TEST-UUID-1";
+    public static final String FILE_UUID = "ABCD";
+    public static final String PROJECT_UUID = "PROJECT-UUID";
+    public static final String NAME = "test1";
+    public static final String STATUS = "OK";
+    public static final long DURATION_IN_MS = 10;
+    public static final String MESSAGE = "MESSAGE-1";
+    public static final String STACKTRACE = "STACKTRACE-1";
+    public static final String KEY = "org.foo.BarTest.java";
+    public static final String LONG_NAME = "src/test/java/org/foo/BarTest.java";
+    public static final List<CoveredFileDoc> COVERED_FILES = Arrays.asList(new CoveredFileDoc().setFileUuid("MAIN-FILE-UUID").setCoveredLines(Arrays.asList(1, 2, 3, 10)));
+
+    public static ComponentDto newDto() {
+      return new ComponentDto()
+        .setUuid(TestFile1.FILE_UUID)
+        .setLongName(TestFile1.LONG_NAME)
+        .setProjectUuid(TestFile1.PROJECT_UUID)
+        .setKey(TestFile1.KEY);
+    }
+
+    private TestFile1() {
+      // static stuff for test purposes
+    }
+  }
+
+  private static final class TestFile2 {
+    public static final String UUID = "TEST-UUID-2";
+    public static final String FILE_UUID = "BCDE";
+    public static final String PROJECT_UUID = "PROJECT-UUID";
+    public static final String NAME = "test2";
+    public static final String STATUS = "ERROR";
+    public static final long DURATION_IN_MS = 97;
+    public static final String MESSAGE = "MESSAGE-2";
+    public static final String STACKTRACE = "STACKTRACE-2";
+    public static final String KEY = "org.foo.FileTest.java";
+    public static final String LONG_NAME = "src/test/java/org/foo/FileTest.java";
+    public static final List<CoveredFileDoc> COVERED_FILES = Arrays.asList(new CoveredFileDoc().setFileUuid("MAIN-FILE-UUID").setCoveredLines(Arrays.asList(11, 12, 13, 10)));
+
+    private TestFile2() {
+      // static stuff for test purposes
+    }
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsShowActionTest.java
deleted file mode 100644 (file)
index 0c1117c..0000000
+++ /dev/null
@@ -1,149 +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.test.ws;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.test.MutableTestCase;
-import org.sonar.api.test.MutableTestPlan;
-import org.sonar.api.test.TestCase;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.component.SnapshotPerspectives;
-import org.sonar.core.measure.db.MeasureDto;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.measure.persistence.MeasureDao;
-import org.sonar.server.user.MockUserSession;
-import org.sonar.server.ws.WsTester;
-
-import javax.annotation.Nullable;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class TestsShowActionTest {
-
-  static final String TEST_PLAN_KEY = "src/test/java/org/foo/BarTest.java";
-
-  @Mock
-  DbSession session;
-
-  @Mock
-  MeasureDao measureDao;
-
-  @Mock
-  MutableTestPlan testPlan;
-
-  @Mock
-  SnapshotPerspectives snapshotPerspectives;
-
-  WsTester tester;
-
-  @Before
-  public void setUp() throws Exception {
-    DbClient dbClient = mock(DbClient.class);
-    when(dbClient.openSession(false)).thenReturn(session);
-    when(dbClient.measureDao()).thenReturn(measureDao);
-
-    tester = new WsTester(new TestsWs(new TestsShowAction(dbClient, snapshotPerspectives), mock(TestsTestCasesAction.class), mock(TestsCoveredFilesAction.class)));
-  }
-
-  @Test
-  public void show() throws Exception {
-    MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, "SonarQube", TEST_PLAN_KEY);
-
-    when(snapshotPerspectives.as(MutableTestPlan.class, TEST_PLAN_KEY)).thenReturn(testPlan);
-
-    MutableTestCase testCase1 = testCase("test1", TestCase.Status.OK, 10L, 32, null, null);
-    MutableTestCase testCase2 = testCase("test2", TestCase.Status.ERROR, 97L, 21, "expected:<true> but was:<false>",
-      "java.lang.AssertionError: expected:<true> but was:<false>\n\t" +
-        "at org.junit.Assert.fail(Assert.java:91)\n\t" +
-        "at org.junit.Assert.failNotEquals(Assert.java:645)\n\t" +
-        "at org.junit.Assert.assertEquals(Assert.java:126)\n\t" +
-        "at org.junit.Assert.assertEquals(Assert.java:145)\n");
-    when(testPlan.testCases()).thenReturn(newArrayList(testCase1, testCase2));
-
-    WsTester.TestRequest request = tester.newGetRequest("api/tests", "show").setParam("key", TEST_PLAN_KEY);
-
-    request.execute().assertJson(getClass(), "show.json");
-  }
-
-  @Test
-  public void show_from_test_data() throws Exception {
-    MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, "SonarQube", TEST_PLAN_KEY);
-
-    when(measureDao.findByComponentKeyAndMetricKey(session, TEST_PLAN_KEY, "test_data")).thenReturn(new MeasureDto()
-      .setComponentKey(TEST_PLAN_KEY)
-      .setMetricKey("test_data")
-      .setData("<tests-details>" +
-        "<testcase status=\"ok\" time=\"10\" name=\"test1\"/>" +
-        "<testcase status=\"error\" time=\"97\" name=\"test2\">" +
-        "<error message=\"expected:&lt;true&gt; but was:&lt;false&gt;\">" +
-        "<![CDATA[" +
-        "java.lang.AssertionError: expected:<true> but was:<false>\n\t" +
-        "at org.junit.Assert.fail(Assert.java:91)\n\t" +
-        "at org.junit.Assert.failNotEquals(Assert.java:645)\n\t" +
-        "at org.junit.Assert.assertEquals(Assert.java:126)\n\t" +
-        "at org.junit.Assert.assertEquals(Assert.java:145)\n" +
-        "]]>" +
-        "</error>" +
-        "</testcase>" +
-        "</tests-details>"));
-
-    WsTester.TestRequest request = tester.newGetRequest("api/tests", "show").setParam("key", TEST_PLAN_KEY);
-
-    request.execute().assertJson(getClass(), "show_from_test_data.json");
-  }
-
-  @Test
-  public void show_from_test_data_with_a_time_in_float() throws Exception {
-    MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, "SonarQube", TEST_PLAN_KEY);
-
-    when(measureDao.findByComponentKeyAndMetricKey(session, TEST_PLAN_KEY, "test_data")).thenReturn(
-      new MeasureDto()
-        .setComponentKey(TEST_PLAN_KEY)
-        .setMetricKey("test_data")
-        .setData("<tests-details>" +
-          "<testcase status=\"ok\" time=\"12.5\" name=\"test1\"/>" +
-          "</tests-details>"));
-
-    WsTester.TestRequest request = tester.newGetRequest("api/tests", "show").setParam("key", TEST_PLAN_KEY);
-
-    request.execute().assertJson(getClass(), "show_from_test_data_with_a_time_in_float.json");
-  }
-
-  private MutableTestCase testCase(String name, TestCase.Status status, Long durationInMs, int coveredLines, @Nullable String message, @Nullable String stackTrace) {
-    MutableTestCase testCase = mock(MutableTestCase.class);
-    when(testCase.name()).thenReturn(name);
-    when(testCase.status()).thenReturn(status);
-    when(testCase.durationInMs()).thenReturn(durationInMs);
-    when(testCase.countCoveredLines()).thenReturn(coveredLines);
-    when(testCase.message()).thenReturn(message);
-    when(testCase.stackTrace()).thenReturn(stackTrace);
-    return testCase;
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsTestCasesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/test/ws/TestsTestCasesActionTest.java
deleted file mode 100644 (file)
index 3e8f5a9..0000000
+++ /dev/null
@@ -1,170 +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.test.ws;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Matchers;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.test.MutableTestable;
-import org.sonar.api.test.TestCase;
-import org.sonar.api.test.TestPlan;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.component.ComponentVertex;
-import org.sonar.core.component.SnapshotPerspectives;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.server.component.ComponentService;
-import org.sonar.server.component.db.ComponentDao;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.user.MockUserSession;
-import org.sonar.server.ws.WsTester;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-@RunWith(MockitoJUnitRunner.class)
-public class TestsTestCasesActionTest {
-
-  private static final String FILE_KEY = "src/main/java/org/foo/Foo.java";
-
-  private static final String EXPECTED_JSON = "{\n" +
-    "  \"tests\": [\n" +
-    "    {\n" +
-    "      \"name\": \"test1\",\n" +
-    "      \"status\": \"OK\",\n" +
-    "      \"durationInMs\": 10,\n" +
-    "      \"_ref\": \"1\"\n" +
-    "    },\n" +
-    "    {\n" +
-    "      \"name\": \"test2\",\n" +
-    "      \"status\": \"ERROR\",\n" +
-    "      \"durationInMs\": 97,\n" +
-    "      \"_ref\": \"2\"\n" +
-    "    }\n" +
-    "  ],\n" +
-    "  \"files\": {\n" +
-    "    \"1\": {\n" +
-    "      \"key\": \"org.foo.BarTest.java\",\n" +
-    "      \"uuid\": \"ABCD\",\n" +
-    "      \"longName\": \"src/test/java/org/foo/BarTest.java\"\n" +
-    "    },\n" +
-    "    \"2\": {\n" +
-    "      \"key\": \"org.foo.FileTest.java\",\n" +
-    "      \"uuid\": \"BCDE\",\n" +
-    "      \"longName\": \"src/test/java/org/foo/FileTest.java\"\n" +
-    "    }\n" +
-    "  }\n" +
-    "}";
-
-
-  @Mock
-  MutableTestable testable;
-
-  @Mock
-  ComponentService componentService;
-
-  @Mock
-  DbClient dbClient;
-
-  @Mock
-  ComponentDao componentDao;
-
-  WsTester tester;
-
-  @Before
-  public void setUp() throws Exception {
-    SnapshotPerspectives snapshotPerspectives = mock(SnapshotPerspectives.class);
-    when(snapshotPerspectives.as(MutableTestable.class, FILE_KEY)).thenReturn(testable);
-    when(dbClient.componentDao()).thenReturn(componentDao);
-    when(dbClient.openSession(false)).thenReturn(mock(DbSession.class));
-    tester = new WsTester(new TestsWs(mock(TestsShowAction.class), new TestsTestCasesAction(snapshotPerspectives, componentService, dbClient), mock(TestsCoveredFilesAction.class)));
-  }
-
-  @Test
-  public void testable() throws Exception {
-    MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, "SonarQube", FILE_KEY);
-
-    String key1 = "org.foo.BarTest.java";
-    String name1 = "src/test/java/org/foo/BarTest.java";
-    String uuid1 = "ABCD";
-    TestCase testCase1 = testCase("test1", TestCase.Status.OK, 10L, key1);
-    ComponentDto component1 = new ComponentDto().setKey(key1).setLongName(name1).setUuid(uuid1);
-    String key2 = "org.foo.FileTest.java";
-    String name2 = "src/test/java/org/foo/FileTest.java";
-    String uuid2 = "BCDE";
-    TestCase testCase2 = testCase("test2", TestCase.Status.ERROR, 97L, key2);
-    ComponentDto component2 = new ComponentDto().setKey(key2).setLongName(name2).setUuid(uuid2);
-    when(testable.testCasesOfLine(10)).thenReturn(newArrayList(testCase1, testCase2));
-    when(componentDao.getByKeys(Matchers.isA(DbSession.class), Matchers.anyCollectionOf(String.class))).thenReturn(newArrayList(component1, component2));
-
-    WsTester.TestRequest request = tester.newGetRequest("api/tests", "test_cases").setParam("key", FILE_KEY).setParam("line", "10");
-
-    request.execute().assertJson(EXPECTED_JSON);
-  }
-
-  @Test
-  public void testable_with_uuid() throws Exception {
-    String uuid = "1234";
-    when(componentService.getByUuid(uuid)).thenReturn(new ComponentDto().setKey(FILE_KEY));
-    MockUserSession.set().addComponentPermission(UserRole.CODEVIEWER, "SonarQube", FILE_KEY);
-
-    String key1 = "org.foo.BarTest.java";
-    String name1 = "src/test/java/org/foo/BarTest.java";
-    String uuid1 = "ABCD";
-    TestCase testCase1 = testCase("test1", TestCase.Status.OK, 10L, key1);
-    ComponentDto component1 = new ComponentDto().setKey(key1).setLongName(name1).setUuid(uuid1);
-    String key2 = "org.foo.FileTest.java";
-    String name2 = "src/test/java/org/foo/FileTest.java";
-    String uuid2 = "BCDE";
-    TestCase testCase2 = testCase("test2", TestCase.Status.ERROR, 97L, key2);
-    ComponentDto component2 = new ComponentDto().setKey(key2).setLongName(name2).setUuid(uuid2);
-    when(testable.testCasesOfLine(10)).thenReturn(newArrayList(testCase1, testCase2));
-    when(componentDao.getByKeys(Matchers.isA(DbSession.class), Matchers.anyCollectionOf(String.class))).thenReturn(newArrayList(component1, component2));
-
-    WsTester.TestRequest request = tester.newGetRequest("api/tests", "test_cases").setParam("uuid", uuid).setParam("line", "10");
-
-    request.execute().assertJson(EXPECTED_JSON);
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void fail_on_missing_parameters() throws Exception {
-    tester.newGetRequest("api/tests", "test_cases").execute();
-  }
-
-  private TestCase testCase(String name, TestCase.Status status, Long durationInMs, String testPlanKey) {
-    TestCase testCase = mock(TestCase.class);
-    when(testCase.name()).thenReturn(name);
-    when(testCase.status()).thenReturn(status);
-    when(testCase.durationInMs()).thenReturn(durationInMs);
-
-    TestPlan testPlan = mock(TestPlan.class);
-    ComponentVertex component = mock(ComponentVertex.class);
-    when(component.key()).thenReturn(testPlanKey);
-    when(testPlan.component()).thenReturn(component);
-    when(testCase.testPlan()).thenReturn(testPlan);
-    return testCase;
-  }
-
-}
index 7337006dede8d7d28a51e885d64920ca2bb8b548..590777108bcf9113951a401be0028b0dc8641114 100644 (file)
@@ -23,9 +23,8 @@ package org.sonar.server.test.ws;
 import org.junit.Before;
 import org.junit.Test;
 import org.sonar.api.server.ws.WebService;
-import org.sonar.core.component.SnapshotPerspectives;
-import org.sonar.server.component.ComponentService;
 import org.sonar.server.db.DbClient;
+import org.sonar.server.test.index.TestIndex;
 import org.sonar.server.ws.WsTester;
 
 import static org.assertj.core.api.Assertions.assertThat;
@@ -37,11 +36,9 @@ public class TestsWsTest {
 
   @Before
   public void setUp() throws Exception {
-    SnapshotPerspectives snapshotPerspectives = mock(SnapshotPerspectives.class);
     WsTester tester = new WsTester(new TestsWs(
-      new TestsShowAction(mock(DbClient.class), snapshotPerspectives),
-      new TestsTestCasesAction(snapshotPerspectives, mock(ComponentService.class), mock(DbClient.class)),
-      new TestsCoveredFilesAction(snapshotPerspectives)));
+      new TestsListAction(mock(DbClient.class), mock(TestIndex.class)),
+      new TestsCoveredFilesAction(mock(DbClient.class), mock(TestIndex.class))));
     controller = tester.controller("api/tests");
   }
 
@@ -50,40 +47,28 @@ public class TestsWsTest {
     assertThat(controller).isNotNull();
     assertThat(controller.since()).isEqualTo("4.4");
     assertThat(controller.description()).isNotEmpty();
-    assertThat(controller.actions()).hasSize(3);
+    assertThat(controller.actions()).hasSize(2);
   }
 
   @Test
-  public void define_show_action() throws Exception {
-    WebService.Action action = controller.action("show");
+  public void define_list_action() throws Exception {
+    WebService.Action action = controller.action("list");
     assertThat(action).isNotNull();
     assertThat(action.isInternal()).isFalse();
     assertThat(action.isPost()).isFalse();
     assertThat(action.handler()).isNotNull();
     assertThat(action.responseExampleAsString()).isNotEmpty();
-    assertThat(action.params()).hasSize(1);
+    assertThat(action.params()).hasSize(7);
   }
 
   @Test
-  public void define_covered_files_action() throws Exception {
+  public void define_covered_files() throws Exception {
     WebService.Action action = controller.action("covered_files");
     assertThat(action).isNotNull();
     assertThat(action.isInternal()).isFalse();
     assertThat(action.isPost()).isFalse();
     assertThat(action.handler()).isNotNull();
     assertThat(action.responseExampleAsString()).isNotEmpty();
-    assertThat(action.params()).hasSize(2);
-  }
-
-  @Test
-  public void define_test_cases_action() throws Exception {
-    WebService.Action action = controller.action("test_cases");
-    assertThat(action).isNotNull();
-    assertThat(action.isInternal()).isFalse();
-    assertThat(action.isPost()).isFalse();
-    assertThat(action.handler()).isNotNull();
-    assertThat(action.responseExampleAsString()).isNotEmpty();
     assertThat(action.params()).hasSize(3);
   }
-
 }
index 299b2631a7131425c09d2560d165a03071a28bda..589ccd36a6e23978ec73a7d8c66e5bcd41c83fe8 100644 (file)
@@ -31,7 +31,6 @@ import org.sonar.server.component.ComponentTesting;
 import org.sonar.server.exceptions.ForbiddenException;
 
 import javax.annotation.Nullable;
-
 import java.util.Arrays;
 import java.util.Locale;
 
@@ -211,6 +210,34 @@ public class UserSessionTest {
     session.checkComponentPermission(UserRole.USER, "com.foo:Bar:BarFile.xoo");
   }
 
+  @Test
+  public void check_component_uuid_permission_ok() throws Exception {
+    AuthorizationDao authorizationDao = mock(AuthorizationDao.class);
+    ResourceDao resourceDao = mock(ResourceDao.class);
+    UserSession session = new SpyUserSession("marius", authorizationDao,resourceDao).setUserId(1);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    ComponentDto file = ComponentTesting.newFileDto(project, "file-uuid");
+    when(resourceDao.getResource("file-uuid")).thenReturn(new ResourceDto().setProjectUuid(project.uuid()));
+    when(authorizationDao.selectAuthorizedRootProjectsUuids(1, UserRole.USER)).thenReturn(newArrayList(project.uuid()));
+
+    session.checkComponentUuidPermission(UserRole.USER, file.uuid());
+  }
+
+  @Test(expected = ForbiddenException.class)
+  public void check_component_uuid_permission_ko() throws Exception {
+    AuthorizationDao authorizationDao = mock(AuthorizationDao.class);
+    ResourceDao resourceDao = mock(ResourceDao.class);
+    UserSession session = new SpyUserSession("marius", authorizationDao,resourceDao).setUserId(1);
+
+    ComponentDto project = ComponentTesting.newProjectDto();
+    ComponentDto file = ComponentTesting.newFileDto(project, "file-uuid");
+    when(resourceDao.getResource("file-uuid")).thenReturn(new ResourceDto().setProjectUuid(project.uuid()));
+    when(authorizationDao.selectAuthorizedRootProjectsUuids(1, UserRole.USER)).thenReturn(newArrayList(project.uuid()));
+
+    session.checkComponentUuidPermission(UserRole.USER, "another-uuid");
+  }
+
   @Test(expected = ForbiddenException.class)
   public void check_component_key_permission_when_project_not_found() throws Exception {
     AuthorizationDao authorizationDao = mock(AuthorizationDao.class);
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsCoveredFilesActionTest/tests-covered-files.json b/server/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsCoveredFilesActionTest/tests-covered-files.json
new file mode 100644 (file)
index 0000000..7b37f47
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "files": [
+    {
+      "key": "org.foo.Bar.java",
+      "longName": "src/main/java/org/foo/Bar.java",
+      "coveredLines": 10
+    },
+    {
+      "key": "org.foo.File.java",
+      "longName": "src/main/java/org/foo/File.java",
+      "coveredLines": 3
+    }
+  ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsListActionTest/list-main-file.json b/server/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsListActionTest/list-main-file.json
new file mode 100644 (file)
index 0000000..5a1e625
--- /dev/null
@@ -0,0 +1,28 @@
+{
+  "tests": [
+    {
+      "testUuid": "TEST-UUID-1",
+      "fileUuid": "ABCD",
+      "name": "test1",
+      "status": "OK",
+      "durationInMs": 10,
+      "coveredLines": 4,
+      "message": "MESSAGE-1",
+      "stacktrace": "STACKTRACE-1",
+      "fileKey": "org.foo.BarTest.java",
+      "fileLongName": "src/test/java/org/foo/BarTest.java"
+    },
+    {
+      "testUuid": "TEST-UUID-2",
+      "fileUuid": "BCDE",
+      "name": "test2",
+      "status": "ERROR",
+      "durationInMs": 97,
+      "coveredLines": 4,
+      "message": "MESSAGE-2",
+      "stacktrace": "STACKTRACE-2",
+      "fileKey": "org.foo.FileTest.java",
+      "fileLongName": "src/test/java/org/foo/FileTest.java"
+    }
+  ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsListActionTest/list-test-uuid.json b/server/sonar-server/src/test/resources/org/sonar/server/test/ws/TestsListActionTest/list-test-uuid.json
new file mode 100644 (file)
index 0000000..de6d8d8
--- /dev/null
@@ -0,0 +1,16 @@
+{
+  "tests": [
+    {
+      "testUuid": "TEST-UUID-1",
+      "fileUuid": "ABCD",
+      "name": "test1",
+      "status": "OK",
+      "durationInMs": 10,
+      "coveredLines": 4,
+      "message": "MESSAGE-1",
+      "stacktrace": "STACKTRACE-1",
+      "fileKey": "org.foo.BarTest.java",
+      "fileLongName": "src/test/java/org/foo/BarTest.java"
+    }
+  ]
+}
index 987acb9659f9bf0e91fa8b3c6a61b2fc7ac88332..afc771a998ff6ee708888f89a6ab2fa62761dc1a 100644 (file)
@@ -2988,13 +2988,13 @@ public final class FileSourceDb {
         getNameBytes();
 
     /**
-     * <code>optional .TestStatus status = 3;</code>
+     * <code>optional .org.sonar.server.source.db.Test.TestStatus status = 3;</code>
      */
     boolean hasStatus();
     /**
-     * <code>optional .TestStatus status = 3;</code>
+     * <code>optional .org.sonar.server.source.db.Test.TestStatus status = 3;</code>
      */
-    org.sonar.batch.protocol.Constants.TestStatus getStatus();
+    org.sonar.server.source.db.FileSourceDb.Test.TestStatus getStatus();
 
     /**
      * <code>optional int64 execution_time_ms = 4;</code>
@@ -3123,7 +3123,7 @@ public final class FileSourceDb {
             }
             case 24: {
               int rawValue = input.readEnum();
-              org.sonar.batch.protocol.Constants.TestStatus value = org.sonar.batch.protocol.Constants.TestStatus.valueOf(rawValue);
+              org.sonar.server.source.db.FileSourceDb.Test.TestStatus value = org.sonar.server.source.db.FileSourceDb.Test.TestStatus.valueOf(rawValue);
               if (value == null) {
                 unknownFields.mergeVarintField(3, rawValue);
               } else {
@@ -3199,6 +3199,106 @@ public final class FileSourceDb {
       return PARSER;
     }
 
+    /**
+     * Protobuf enum {@code org.sonar.server.source.db.Test.TestStatus}
+     */
+    public enum TestStatus
+        implements com.google.protobuf.ProtocolMessageEnum {
+      /**
+       * <code>OK = 1;</code>
+       */
+      OK(0, 1),
+      /**
+       * <code>FAILURE = 2;</code>
+       */
+      FAILURE(1, 2),
+      /**
+       * <code>ERROR = 3;</code>
+       */
+      ERROR(2, 3),
+      /**
+       * <code>SKIPPED = 4;</code>
+       */
+      SKIPPED(3, 4),
+      ;
+
+      /**
+       * <code>OK = 1;</code>
+       */
+      public static final int OK_VALUE = 1;
+      /**
+       * <code>FAILURE = 2;</code>
+       */
+      public static final int FAILURE_VALUE = 2;
+      /**
+       * <code>ERROR = 3;</code>
+       */
+      public static final int ERROR_VALUE = 3;
+      /**
+       * <code>SKIPPED = 4;</code>
+       */
+      public static final int SKIPPED_VALUE = 4;
+
+
+      public final int getNumber() { return value; }
+
+      public static TestStatus valueOf(int value) {
+        switch (value) {
+          case 1: return OK;
+          case 2: return FAILURE;
+          case 3: return ERROR;
+          case 4: return SKIPPED;
+          default: return null;
+        }
+      }
+
+      public static com.google.protobuf.Internal.EnumLiteMap<TestStatus>
+          internalGetValueMap() {
+        return internalValueMap;
+      }
+      private static com.google.protobuf.Internal.EnumLiteMap<TestStatus>
+          internalValueMap =
+            new com.google.protobuf.Internal.EnumLiteMap<TestStatus>() {
+              public TestStatus findValueByNumber(int number) {
+                return TestStatus.valueOf(number);
+              }
+            };
+
+      public final com.google.protobuf.Descriptors.EnumValueDescriptor
+          getValueDescriptor() {
+        return getDescriptor().getValues().get(index);
+      }
+      public final com.google.protobuf.Descriptors.EnumDescriptor
+          getDescriptorForType() {
+        return getDescriptor();
+      }
+      public static final com.google.protobuf.Descriptors.EnumDescriptor
+          getDescriptor() {
+        return org.sonar.server.source.db.FileSourceDb.Test.getDescriptor().getEnumTypes().get(0);
+      }
+
+      private static final TestStatus[] VALUES = values();
+
+      public static TestStatus valueOf(
+          com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
+        if (desc.getType() != getDescriptor()) {
+          throw new java.lang.IllegalArgumentException(
+            "EnumValueDescriptor is not for this type.");
+        }
+        return VALUES[desc.getIndex()];
+      }
+
+      private final int index;
+      private final int value;
+
+      private TestStatus(int index, int value) {
+        this.index = index;
+        this.value = value;
+      }
+
+      // @@protoc_insertion_point(enum_scope:org.sonar.server.source.db.Test.TestStatus)
+    }
+
     public interface CoveredFileOrBuilder extends
         // @@protoc_insertion_point(interface_extends:org.sonar.server.source.db.Test.CoveredFile)
         com.google.protobuf.MessageOrBuilder {
@@ -3926,17 +4026,17 @@ public final class FileSourceDb {
     }
 
     public static final int STATUS_FIELD_NUMBER = 3;
-    private org.sonar.batch.protocol.Constants.TestStatus status_;
+    private org.sonar.server.source.db.FileSourceDb.Test.TestStatus status_;
     /**
-     * <code>optional .TestStatus status = 3;</code>
+     * <code>optional .org.sonar.server.source.db.Test.TestStatus status = 3;</code>
      */
     public boolean hasStatus() {
       return ((bitField0_ & 0x00000004) == 0x00000004);
     }
     /**
-     * <code>optional .TestStatus status = 3;</code>
+     * <code>optional .org.sonar.server.source.db.Test.TestStatus status = 3;</code>
      */
-    public org.sonar.batch.protocol.Constants.TestStatus getStatus() {
+    public org.sonar.server.source.db.FileSourceDb.Test.TestStatus getStatus() {
       return status_;
     }
 
@@ -4077,7 +4177,7 @@ public final class FileSourceDb {
     private void initFields() {
       uuid_ = "";
       name_ = "";
-      status_ = org.sonar.batch.protocol.Constants.TestStatus.OK;
+      status_ = org.sonar.server.source.db.FileSourceDb.Test.TestStatus.OK;
       executionTimeMs_ = 0L;
       stacktrace_ = "";
       msg_ = "";
@@ -4276,7 +4376,7 @@ public final class FileSourceDb {
         bitField0_ = (bitField0_ & ~0x00000001);
         name_ = "";
         bitField0_ = (bitField0_ & ~0x00000002);
-        status_ = org.sonar.batch.protocol.Constants.TestStatus.OK;
+        status_ = org.sonar.server.source.db.FileSourceDb.Test.TestStatus.OK;
         bitField0_ = (bitField0_ & ~0x00000004);
         executionTimeMs_ = 0L;
         bitField0_ = (bitField0_ & ~0x00000008);
@@ -4598,23 +4698,23 @@ public final class FileSourceDb {
         return this;
       }
 
-      private org.sonar.batch.protocol.Constants.TestStatus status_ = org.sonar.batch.protocol.Constants.TestStatus.OK;
+      private org.sonar.server.source.db.FileSourceDb.Test.TestStatus status_ = org.sonar.server.source.db.FileSourceDb.Test.TestStatus.OK;
       /**
-       * <code>optional .TestStatus status = 3;</code>
+       * <code>optional .org.sonar.server.source.db.Test.TestStatus status = 3;</code>
        */
       public boolean hasStatus() {
         return ((bitField0_ & 0x00000004) == 0x00000004);
       }
       /**
-       * <code>optional .TestStatus status = 3;</code>
+       * <code>optional .org.sonar.server.source.db.Test.TestStatus status = 3;</code>
        */
-      public org.sonar.batch.protocol.Constants.TestStatus getStatus() {
+      public org.sonar.server.source.db.FileSourceDb.Test.TestStatus getStatus() {
         return status_;
       }
       /**
-       * <code>optional .TestStatus status = 3;</code>
+       * <code>optional .org.sonar.server.source.db.Test.TestStatus status = 3;</code>
        */
-      public Builder setStatus(org.sonar.batch.protocol.Constants.TestStatus value) {
+      public Builder setStatus(org.sonar.server.source.db.FileSourceDb.Test.TestStatus value) {
         if (value == null) {
           throw new NullPointerException();
         }
@@ -4624,11 +4724,11 @@ public final class FileSourceDb {
         return this;
       }
       /**
-       * <code>optional .TestStatus status = 3;</code>
+       * <code>optional .org.sonar.server.source.db.Test.TestStatus status = 3;</code>
        */
       public Builder clearStatus() {
         bitField0_ = (bitField0_ & ~0x00000004);
-        status_ = org.sonar.batch.protocol.Constants.TestStatus.OK;
+        status_ = org.sonar.server.source.db.FileSourceDb.Test.TestStatus.OK;
         onChanged();
         return this;
       }
@@ -5098,25 +5198,27 @@ public final class FileSourceDb {
   static {
     java.lang.String[] descriptorData = {
       "\n\024file_source_db.proto\022\032org.sonar.server" +
-      ".source.db\032\017constants.proto\"\223\003\n\004Line\022\014\n\004" +
-      "line\030\001 \001(\005\022\016\n\006source\030\002 \001(\t\022\024\n\014scm_revisi" +
-      "on\030\003 \001(\t\022\022\n\nscm_author\030\004 \001(\t\022\020\n\010scm_date" +
-      "\030\005 \001(\003\022\024\n\014ut_line_hits\030\006 \001(\005\022\025\n\rut_condi" +
-      "tions\030\007 \001(\005\022\035\n\025ut_covered_conditions\030\010 \001" +
-      "(\005\022\024\n\014it_line_hits\030\t \001(\005\022\025\n\rit_condition" +
-      "s\030\n \001(\005\022\035\n\025it_covered_conditions\030\013 \001(\005\022\031" +
-      "\n\021overall_line_hits\030\014 \001(\005\022\032\n\022overall_con" +
-      "ditions\030\r \001(\005\022\"\n\032overall_covered_conditi",
-      "ons\030\016 \001(\005\022\024\n\014highlighting\030\017 \001(\t\022\017\n\007symbo" +
-      "ls\030\020 \001(\t\022\027\n\013duplication\030\021 \003(\005B\002\020\001\"7\n\004Dat" +
-      "a\022/\n\005lines\030\001 \003(\0132 .org.sonar.server.sour" +
-      "ce.db.Line\"\373\001\n\004Test\022\014\n\004uuid\030\001 \001(\t\022\014\n\004nam" +
-      "e\030\002 \001(\t\022\033\n\006status\030\003 \001(\0162\013.TestStatus\022\031\n\021" +
-      "execution_time_ms\030\004 \001(\003\022\022\n\nstacktrace\030\005 " +
-      "\001(\t\022\013\n\003msg\030\006 \001(\t\022B\n\014covered_file\030\007 \003(\0132," +
-      ".org.sonar.server.source.db.Test.Covered" +
-      "File\032:\n\013CoveredFile\022\021\n\tfile_uuid\030\001 \001(\t\022\030" +
-      "\n\014covered_line\030\002 \003(\005B\002\020\001B\002H\001"
+      ".source.db\"\223\003\n\004Line\022\014\n\004line\030\001 \001(\005\022\016\n\006sou" +
+      "rce\030\002 \001(\t\022\024\n\014scm_revision\030\003 \001(\t\022\022\n\nscm_a" +
+      "uthor\030\004 \001(\t\022\020\n\010scm_date\030\005 \001(\003\022\024\n\014ut_line" +
+      "_hits\030\006 \001(\005\022\025\n\rut_conditions\030\007 \001(\005\022\035\n\025ut" +
+      "_covered_conditions\030\010 \001(\005\022\024\n\014it_line_hit" +
+      "s\030\t \001(\005\022\025\n\rit_conditions\030\n \001(\005\022\035\n\025it_cov" +
+      "ered_conditions\030\013 \001(\005\022\031\n\021overall_line_hi" +
+      "ts\030\014 \001(\005\022\032\n\022overall_conditions\030\r \001(\005\022\"\n\032" +
+      "overall_covered_conditions\030\016 \001(\005\022\024\n\014high",
+      "lighting\030\017 \001(\t\022\017\n\007symbols\030\020 \001(\t\022\027\n\013dupli" +
+      "cation\030\021 \003(\005B\002\020\001\"7\n\004Data\022/\n\005lines\030\001 \003(\0132" +
+      " .org.sonar.server.source.db.Line\"\326\002\n\004Te" +
+      "st\022\014\n\004uuid\030\001 \001(\t\022\014\n\004name\030\002 \001(\t\022;\n\006status" +
+      "\030\003 \001(\0162+.org.sonar.server.source.db.Test" +
+      ".TestStatus\022\031\n\021execution_time_ms\030\004 \001(\003\022\022" +
+      "\n\nstacktrace\030\005 \001(\t\022\013\n\003msg\030\006 \001(\t\022B\n\014cover" +
+      "ed_file\030\007 \003(\0132,.org.sonar.server.source." +
+      "db.Test.CoveredFile\032:\n\013CoveredFile\022\021\n\tfi" +
+      "le_uuid\030\001 \001(\t\022\030\n\014covered_line\030\002 \003(\005B\002\020\001\"",
+      "9\n\nTestStatus\022\006\n\002OK\020\001\022\013\n\007FAILURE\020\002\022\t\n\005ER" +
+      "ROR\020\003\022\013\n\007SKIPPED\020\004B\002H\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
         new com.google.protobuf.Descriptors.FileDescriptor.    InternalDescriptorAssigner() {
@@ -5129,7 +5231,6 @@ public final class FileSourceDb {
     com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
         new com.google.protobuf.Descriptors.FileDescriptor[] {
-          org.sonar.batch.protocol.Constants.getDescriptor(),
         }, assigner);
     internal_static_org_sonar_server_source_db_Line_descriptor =
       getDescriptor().getMessageTypes().get(0);
@@ -5155,7 +5256,6 @@ public final class FileSourceDb {
       com.google.protobuf.GeneratedMessage.FieldAccessorTable(
         internal_static_org_sonar_server_source_db_Test_CoveredFile_descriptor,
         new java.lang.String[] { "FileUuid", "CoveredLine", });
-    org.sonar.batch.protocol.Constants.getDescriptor();
   }
 
   // @@protoc_insertion_point(outer_class_scope)
index b14bd891038574ce666abbd8c82186a10e056ea8..48b916dbd78dcdbb3b351497b1f7239bb13b9d66 100644 (file)
@@ -37,8 +37,6 @@ Notes
 
 package org.sonar.server.source.db;
 
-import "constants.proto";
-
 option optimize_for = SPEED;
 
 message Line {
@@ -87,4 +85,11 @@ message Test {
     optional string file_uuid = 1;
     repeated int32 covered_line = 2 [packed = true];
   }
+
+  enum TestStatus {
+    OK = 1;
+    FAILURE = 2;
+    ERROR = 3;
+    SKIPPED = 4;
+  }
 }