Browse Source

SONAR-11632 Remove api/tests WS

- Drop api/tests WS
- Drop persistance of tests and coverage details from compute engine
- Drop tests and coverage details from scanner report
tags/7.6
Julien Lancelot 5 years ago
parent
commit
b5cc291883
82 changed files with 97 additions and 4760 deletions
  1. 0
    4
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/batch/BatchReportReader.java
  2. 0
    69
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/batch/BatchReportReaderImpl.java
  3. 1
    9
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListener.java
  4. 3
    3
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoader.java
  5. 1
    3
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/PersistFileSourcesStep.java
  6. 0
    249
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistTestsStep.java
  7. 0
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java
  8. 0
    32
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/batch/BatchReportReaderImplTest.java
  9. 0
    24
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/batch/BatchReportReaderRule.java
  10. 20
    42
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/dbmigration/PopulateFileSourceLineCountTest.java
  11. 1
    2
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/filemove/FileMoveDetectionStepTest.java
  12. 1
    4
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListenerTest.java
  13. 14
    17
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/source/PersistFileSourcesStepTest.java
  14. 0
    280
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistTestsStepTest.java
  15. 0
    4
      server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
  16. 1
    1
      server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
  17. 5
    13
      server/sonar-db-dao/src/main/java/org/sonar/db/source/FileSourceDao.java
  18. 0
    84
      server/sonar-db-dao/src/main/java/org/sonar/db/source/FileSourceDto.java
  19. 2
    2
      server/sonar-db-dao/src/main/java/org/sonar/db/source/FileSourceMapper.java
  20. 6
    8
      server/sonar-db-dao/src/main/resources/org/sonar/db/source/FileSourceMapper.xml
  21. 0
    21
      server/sonar-db-dao/src/test/java/org/sonar/db/component/ScrollForFileMoveComponentDaoTest.java
  22. 4
    5
      server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java
  23. 6
    51
      server/sonar-db-dao/src/test/java/org/sonar/db/source/FileSourceDaoTest.java
  24. 1
    18
      server/sonar-db-dao/src/test/java/org/sonar/db/source/FileSourceDtoTest.java
  25. 0
    96
      server/sonar-server-common/src/main/java/org/sonar/server/source/index/FileSourcesUpdaterHelper.java
  26. 0
    74
      server/sonar-server-common/src/main/java/org/sonar/server/test/index/CoveredFileDoc.java
  27. 0
    162
      server/sonar-server-common/src/main/java/org/sonar/server/test/index/TestDoc.java
  28. 0
    116
      server/sonar-server-common/src/main/java/org/sonar/server/test/index/TestIndex.java
  29. 0
    151
      server/sonar-server-common/src/main/java/org/sonar/server/test/index/TestIndexer.java
  30. 0
    144
      server/sonar-server-common/src/main/java/org/sonar/server/test/index/TestResultSetIterator.java
  31. 0
    41
      server/sonar-server-common/src/test/java/org/sonar/server/source/index/FileSourceTesting.java
  32. 0
    96
      server/sonar-server-common/src/test/java/org/sonar/server/test/db/TestTesting.java
  33. 0
    161
      server/sonar-server-common/src/test/java/org/sonar/server/test/index/TestIndexTest.java
  34. 0
    168
      server/sonar-server-common/src/test/java/org/sonar/server/test/index/TestIndexerTest.java
  35. 0
    192
      server/sonar-server-common/src/test/java/org/sonar/server/test/index/TestResultSetIteratorTest.java
  36. 0
    11
      server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P1_F1_T1.json
  37. 0
    11
      server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P1_F1_T2.json
  38. 0
    11
      server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P1_F2_T1.json
  39. 0
    11
      server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P2_F3_T1.json
  40. 0
    11
      server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P3_F1_long_message.json
  41. 0
    11
      server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P3_F1_long_name.json
  42. 0
    11
      server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P3_F1_long_stacktrace.json
  43. 0
    14
      server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/db.xml
  44. 0
    23
      server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestResultSetIteratorTest/filter_by_project.xml
  45. 0
    23
      server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestResultSetIteratorTest/filter_by_project_and_date.xml
  46. 0
    11
      server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestResultSetIteratorTest/schema.sql
  47. 0
    13
      server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestResultSetIteratorTest/shared.xml
  48. 0
    7
      server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
  49. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java
  50. 0
    124
      server/sonar-server/src/main/java/org/sonar/server/test/ws/CoveredFilesAction.java
  51. 0
    266
      server/sonar-server/src/main/java/org/sonar/server/test/ws/ListAction.java
  52. 19
    10
      server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsWs.java
  53. 0
    26
      server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsWsAction.java
  54. 0
    14
      server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-covered-files.json
  55. 0
    31
      server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-list.json
  56. 0
    1
      server/sonar-server/src/test/java/org/sonar/server/batch/ProjectDataLoaderTest.java
  57. 0
    16
      server/sonar-server/src/test/java/org/sonar/server/source/ws/HashActionTest.java
  58. 0
    159
      server/sonar-server/src/test/java/org/sonar/server/test/ws/CoveredFilesActionTest.java
  59. 0
    434
      server/sonar-server/src/test/java/org/sonar/server/test/ws/ListActionTest.java
  60. 0
    16
      server/sonar-server/src/test/resources/org/sonar/server/test/ws/CoveredFilesActionTest/tests-covered-files.json
  61. 0
    34
      server/sonar-server/src/test/resources/org/sonar/server/test/ws/ListActionTest/list-main-file.json
  62. 0
    16
      server/sonar-server/src/test/resources/org/sonar/server/test/ws/ListActionTest/list-test-uuid.json
  63. 0
    34
      sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/AnalysisResult.java
  64. 0
    126
      sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionAndCoveragePublisher.java
  65. 1
    3
      sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
  66. 0
    147
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/tests/CoveragePerTestMediumTest.java
  67. 5
    110
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/tests/GenericTestExecutionMediumTest.java
  68. 0
    93
      sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/tests/TestExecutionMediumTest.java
  69. 0
    68
      sonar-scanner-engine/src/test/java/org/sonar/scanner/report/TestExecutionAndCoveragePublisherTest.java
  70. 0
    3
      sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/FileStructure.java
  71. 0
    20
      sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportReader.java
  72. 0
    12
      sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java
  73. 0
    19
      sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/viewer/ScannerReportViewerApp.java
  74. 0
    26
      sonar-scanner-protocol/src/main/protobuf/scanner_report.proto
  75. 5
    55
      sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/output/ScannerReportReaderTest.java
  76. 0
    20
      sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/output/ScannerReportWriterTest.java
  77. 0
    8
      sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java
  78. 0
    3
      sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java
  79. 0
    74
      sonar-ws/src/main/java/org/sonarqube/ws/client/tests/CoveredFilesRequest.java
  80. 0
    166
      sonar-ws/src/main/java/org/sonarqube/ws/client/tests/ListRequest.java
  81. 0
    84
      sonar-ws/src/main/java/org/sonarqube/ws/client/tests/TestsService.java
  82. 0
    26
      sonar-ws/src/main/java/org/sonarqube/ws/client/tests/package-info.java

+ 0
- 4
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/batch/BatchReportReader.java View File

@@ -59,10 +59,6 @@ public interface BatchReportReader {
*/
Optional<CloseableIterator<String>> readFileSource(int fileRef);

CloseableIterator<ScannerReport.Test> readTests(int testFileRef);

CloseableIterator<ScannerReport.CoverageDetail> readCoverageDetails(int testFileRef);

CloseableIterator<ScannerReport.ContextProperty> readContextProperties();

Optional<CloseableIterator<ScannerReport.LineSgnificantCode>> readComponentSignificantCode(int fileRef);

+ 0
- 69
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/batch/BatchReportReaderImpl.java View File

@@ -19,11 +19,7 @@
*/
package org.sonar.ce.task.projectanalysis.batch;

import com.google.common.base.Throwables;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Parser;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.NoSuchElementException;
@@ -92,7 +88,6 @@ public class BatchReportReaderImpl implements BatchReportReader {
return delegate.readAdHocRules();
}


@Override
public CloseableIterator<ScannerReport.Measure> readComponentMeasures(int componentRef) {
ensureInitialized();
@@ -198,76 +193,12 @@ public class BatchReportReaderImpl implements BatchReportReader {
}
}

@Override
public CloseableIterator<ScannerReport.Test> readTests(int testFileRef) {
ensureInitialized();
File file = delegate.readTests(testFileRef);
if (file == null) {
return CloseableIterator.emptyCloseableIterator();
}

try {
return new ParserCloseableIterator<>(ScannerReport.Test.parser(), FileUtils.openInputStream(file));
} catch (IOException e) {
Throwables.propagate(e);
// actually never reached
return CloseableIterator.emptyCloseableIterator();
}
}

@Override
public CloseableIterator<ScannerReport.CoverageDetail> readCoverageDetails(int testFileRef) {
ensureInitialized();
File file = delegate.readCoverageDetails(testFileRef);
if (file == null) {
return CloseableIterator.emptyCloseableIterator();
}

try {
return new ParserCloseableIterator<>(ScannerReport.CoverageDetail.parser(), FileUtils.openInputStream(file));
} catch (IOException e) {
Throwables.propagate(e);
// actually never reached
return CloseableIterator.emptyCloseableIterator();
}
}

@Override
public CloseableIterator<ScannerReport.ContextProperty> readContextProperties() {
ensureInitialized();
return delegate.readContextProperties();
}

private static class ParserCloseableIterator<T> extends CloseableIterator<T> {
private final Parser<T> parser;
private final FileInputStream fileInputStream;

public ParserCloseableIterator(Parser<T> parser, FileInputStream fileInputStream) {
this.parser = parser;
this.fileInputStream = fileInputStream;
}

@Override
protected T doNext() {
try {
return parser.parseDelimitedFrom(fileInputStream);
} catch (InvalidProtocolBufferException e) {
Throwables.propagate(e);
// actually never reached
return null;
}
}

@Override
protected void doClose() throws Exception {
fileInputStream.close();
}
}

public boolean hasSignificantCode(int fileRef) {
return delegate.hasSignificantCode(fileRef);
}

@Override
public Optional<CloseableIterator<LineSgnificantCode>> readComponentSignificantCode(int fileRef) {
ensureInitialized();

+ 1
- 9
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListener.java View File

@@ -25,16 +25,13 @@ import org.sonar.api.server.ServerSide;
import org.sonar.db.purge.PurgeListener;
import org.sonar.server.component.index.ComponentIndexer;
import org.sonar.server.issue.index.IssueIndexer;
import org.sonar.server.test.index.TestIndexer;

@ServerSide
public class IndexPurgeListener implements PurgeListener {
private final TestIndexer testIndexer;
private final IssueIndexer issueIndexer;
private final ComponentIndexer componentIndexer;

public IndexPurgeListener(TestIndexer testIndexer, IssueIndexer issueIndexer, ComponentIndexer componentIndexer) {
this.testIndexer = testIndexer;
public IndexPurgeListener(IssueIndexer issueIndexer, ComponentIndexer componentIndexer) {
this.issueIndexer = issueIndexer;
this.componentIndexer = componentIndexer;
}
@@ -42,11 +39,6 @@ public class IndexPurgeListener implements PurgeListener {
@Override
public void onComponentsDisabling(String projectUuid, Collection<String> disabledComponentUuids) {
componentIndexer.delete(projectUuid, disabledComponentUuids);
disabledComponentUuids.forEach(this::onComponentDisabling);
}

private void onComponentDisabling(String uuid) {
testIndexer.deleteByFile(uuid);
}

@Override

+ 3
- 3
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/scm/ScmInfoDbLoader.java View File

@@ -22,13 +22,13 @@ package org.sonar.ce.task.projectanalysis.scm;
import java.util.Optional;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.analysis.Branch;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.MergeBranchComponentUuids;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.source.FileSourceDto;
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
import org.sonar.ce.task.projectanalysis.analysis.Branch;

public class ScmInfoDbLoader {
private static final Logger LOGGER = Loggers.get(ScmInfoDbLoader.class);
@@ -51,7 +51,7 @@ public class ScmInfoDbLoader {

LOGGER.trace("Reading SCM info from DB for file '{}'", uuid.get());
try (DbSession dbSession = dbClient.openSession(false)) {
FileSourceDto dto = dbClient.fileSourceDao().selectSourceByFileUuid(dbSession, uuid.get());
FileSourceDto dto = dbClient.fileSourceDao().selectByFileUuid(dbSession, uuid.get());
if (dto == null) {
return Optional.empty();
}

+ 1
- 3
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/source/PersistFileSourcesStep.java View File

@@ -39,7 +39,6 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.protobuf.DbFileSources;
import org.sonar.db.source.FileSourceDto;
import org.sonar.db.source.FileSourceDto.Type;

import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER;

@@ -87,7 +86,7 @@ public class PersistFileSourcesStep implements ComputationStep {
@Override
public void visitProject(Component project) {
this.projectUuid = project.getUuid();
session.select("org.sonar.db.source.FileSourceMapper.selectHashesForProject", ImmutableMap.of("projectUuid", projectUuid, "dataType", Type.SOURCE),
session.select("org.sonar.db.source.FileSourceMapper.selectHashesForProject", ImmutableMap.of("projectUuid", projectUuid),
context -> {
FileSourceDto dto = (FileSourceDto) context.getResultObject();
previousFileSourcesByUuid.put(dto.getFileUuid(), dto);
@@ -119,7 +118,6 @@ public class PersistFileSourcesStep implements ComputationStep {
FileSourceDto dto = new FileSourceDto()
.setProjectUuid(projectUuid)
.setFileUuid(file.getUuid())
.setDataType(Type.SOURCE)
.setBinaryData(binaryData)
.setSrcHash(srcHash)
.setDataHash(dataHash)

+ 0
- 249
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/PersistTestsStep.java View File

@@ -1,249 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.ce.task.projectanalysis.step;

import com.google.common.base.Joiner;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Table;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.ce.task.projectanalysis.batch.BatchReportReader;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.ComponentVisitor;
import org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit;
import org.sonar.ce.task.projectanalysis.component.DepthTraversalTypeAwareCrawler;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitorAdapter;
import org.sonar.ce.task.step.ComputationStep;
import org.sonar.core.util.CloseableIterator;
import org.sonar.core.util.Uuids;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.protobuf.DbFileSources;
import org.sonar.db.source.FileSourceDto;
import org.sonar.db.source.FileSourceDto.Type;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Test.TestStatus;

public class PersistTestsStep implements ComputationStep {

private static final Logger LOG = Loggers.get(PersistTestsStep.class);

private final DbClient dbClient;
private final System2 system;
private final BatchReportReader reportReader;
private final TreeRootHolder treeRootHolder;

public PersistTestsStep(DbClient dbClient, System2 system, BatchReportReader reportReader, TreeRootHolder treeRootHolder) {
this.dbClient = dbClient;
this.system = system;
this.reportReader = reportReader;
this.treeRootHolder = treeRootHolder;
}

@Override
public void execute(ComputationStep.Context context) {
try (DbSession dbSession = dbClient.openSession(true)) {
TestDepthTraversalTypeAwareVisitor visitor = new TestDepthTraversalTypeAwareVisitor(dbSession);
new DepthTraversalTypeAwareCrawler(visitor).visit(treeRootHolder.getRoot());
dbSession.commit();
if (visitor.hasUnprocessedCoverageDetails) {
LOG.warn("Some coverage tests are not taken into account during analysis of project '{}'", visitor.getProjectKey());
}
}
}

@Override
public String getDescription() {
return "Persist tests";
}

private class TestDepthTraversalTypeAwareVisitor extends TypeAwareVisitorAdapter {
final DbSession session;
final Map<String, FileSourceDto> existingFileSourcesByUuid;
final String projectUuid;
final String projectKey;
boolean hasUnprocessedCoverageDetails = false;

public TestDepthTraversalTypeAwareVisitor(DbSession session) {
super(CrawlerDepthLimit.FILE, ComponentVisitor.Order.PRE_ORDER);
this.session = session;
this.existingFileSourcesByUuid = new HashMap<>();
this.projectUuid = treeRootHolder.getRoot().getUuid();
this.projectKey = treeRootHolder.getRoot().getDbKey();
session.select("org.sonar.db.source.FileSourceMapper.selectHashesForProject",
ImmutableMap.of("projectUuid", treeRootHolder.getRoot().getUuid(), "dataType", Type.TEST),
context -> {
FileSourceDto dto = (FileSourceDto) context.getResultObject();
existingFileSourcesByUuid.put(dto.getFileUuid(), dto);
});
}

@Override
public void visitFile(Component file) {
if (file.getFileAttributes().isUnitTest()) {
persistTestResults(file);
}
}

private void persistTestResults(Component component) {
Multimap<String, DbFileSources.Test.Builder> testsByName = buildDbTests(component.getReportAttributes().getRef());
Table<String, String, DbFileSources.Test.CoveredFile.Builder> coveredFilesByName = loadCoverageDetails(component.getReportAttributes().getRef());
List<DbFileSources.Test> tests = addCoveredFilesToTests(testsByName, coveredFilesByName);
if (checkIfThereAreUnprocessedCoverageDetails(testsByName, coveredFilesByName, component.getDbKey())) {
hasUnprocessedCoverageDetails = true;
}

if (tests.isEmpty()) {
return;
}

String componentUuid = getUuid(component.getReportAttributes().getRef());
FileSourceDto existingDto = existingFileSourcesByUuid.get(componentUuid);
long now = system.now();
if (existingDto != null) {
// update
existingDto
.setTestData(tests)
.setUpdatedAt(now);
dbClient.fileSourceDao().update(session, existingDto);
} else {
// insert
FileSourceDto newDto = new FileSourceDto()
.setTestData(tests)
.setFileUuid(componentUuid)
.setProjectUuid(projectUuid)
.setDataType(Type.TEST)
.setCreatedAt(now)
.setUpdatedAt(now);
dbClient.fileSourceDao().insert(session, newDto);
}
}

private boolean checkIfThereAreUnprocessedCoverageDetails(Multimap<String, DbFileSources.Test.Builder> testsByName,
Table<String, String, DbFileSources.Test.CoveredFile.Builder> coveredFilesByName, String componentKey) {
Set<String> unprocessedCoverageDetailNames = new HashSet<>(coveredFilesByName.rowKeySet());
unprocessedCoverageDetailNames.removeAll(testsByName.keySet());
boolean hasUnprocessedCoverage = !unprocessedCoverageDetailNames.isEmpty();
if (hasUnprocessedCoverage) {
LOG.trace("The following test coverages for file '{}' have not been taken into account: {}", componentKey, Joiner.on(", ").join(unprocessedCoverageDetailNames));
}
return hasUnprocessedCoverage;
}

private List<DbFileSources.Test> addCoveredFilesToTests(Multimap<String, DbFileSources.Test.Builder> testsByName,
Table<String, String, DbFileSources.Test.CoveredFile.Builder> coveredFilesByName) {
List<DbFileSources.Test> tests = new ArrayList<>();
for (DbFileSources.Test.Builder test : testsByName.values()) {
Collection<DbFileSources.Test.CoveredFile.Builder> coveredFiles = coveredFilesByName.row(test.getName()).values();
if (!coveredFiles.isEmpty()) {
for (DbFileSources.Test.CoveredFile.Builder coveredFile : coveredFiles) {
test.addCoveredFile(coveredFile);
}
}
tests.add(test.build());
}

return tests;
}

private Multimap<String, DbFileSources.Test.Builder> buildDbTests(int componentRed) {
Multimap<String, DbFileSources.Test.Builder> tests = ArrayListMultimap.create();

try (CloseableIterator<ScannerReport.Test> testIterator = reportReader.readTests(componentRed)) {
while (testIterator.hasNext()) {
ScannerReport.Test batchTest = testIterator.next();
DbFileSources.Test.Builder dbTest = DbFileSources.Test.newBuilder();
dbTest.setUuid(Uuids.create());
dbTest.setName(batchTest.getName());
if (!batchTest.getStacktrace().isEmpty()) {
dbTest.setStacktrace(batchTest.getStacktrace());
}
if (batchTest.getStatus() != TestStatus.UNSET) {
dbTest.setStatus(DbFileSources.Test.TestStatus.valueOf(batchTest.getStatus().name()));
}
if (!batchTest.getMsg().isEmpty()) {
dbTest.setMsg(batchTest.getMsg());
}
dbTest.setExecutionTimeMs(batchTest.getDurationInMs());

tests.put(dbTest.getName(), dbTest);
}
}

return tests;
}

/**
* returns a Table of (test name, main file uuid, covered file)
*/
private Table<String, String, DbFileSources.Test.CoveredFile.Builder> loadCoverageDetails(int testFileRef) {
Table<String, String, DbFileSources.Test.CoveredFile.Builder> nameToCoveredFiles = HashBasedTable.create();

try (CloseableIterator<ScannerReport.CoverageDetail> coverageIterator = reportReader.readCoverageDetails(testFileRef)) {
while (coverageIterator.hasNext()) {
ScannerReport.CoverageDetail batchCoverageDetail = coverageIterator.next();
String testName = batchCoverageDetail.getTestName();
for (ScannerReport.CoverageDetail.CoveredFile batchCoveredFile : batchCoverageDetail.getCoveredFileList()) {
loadCoverageFile(batchCoveredFile, testName, nameToCoveredFiles);
}
}
}
return nameToCoveredFiles;
}

private void loadCoverageFile(ScannerReport.CoverageDetail.CoveredFile batchCoveredFile, String testName, Table<String, String,
DbFileSources.Test.CoveredFile.Builder> nameToCoveredFiles) {
String mainFileUuid = getUuid(batchCoveredFile.getFileRef());
DbFileSources.Test.CoveredFile.Builder existingDbCoveredFile = nameToCoveredFiles.get(testName, mainFileUuid);
List<Integer> batchCoveredLines = batchCoveredFile.getCoveredLineList();
if (existingDbCoveredFile == null) {
DbFileSources.Test.CoveredFile.Builder dbCoveredFile = DbFileSources.Test.CoveredFile.newBuilder()
.setFileUuid(getUuid(batchCoveredFile.getFileRef()))
.addAllCoveredLine(batchCoveredLines);
nameToCoveredFiles.put(testName, mainFileUuid, dbCoveredFile);
} else {
List<Integer> remainingBatchCoveredLines = new ArrayList<>(batchCoveredLines);
remainingBatchCoveredLines.removeAll(existingDbCoveredFile.getCoveredLineList());
existingDbCoveredFile.addAllCoveredLine(batchCoveredLines);
}
}

private String getUuid(int fileRef) {
return treeRootHolder.getComponentByRef(fileRef).getUuid();
}

public String getProjectKey() {
return projectKey;
}
}

}

+ 0
- 1
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/ReportComputationSteps.java View File

@@ -99,7 +99,6 @@ public class ReportComputationSteps extends AbstractComputationSteps {
PersistProjectLinksStep.class,
PersistEventsStep.class,
PersistFileSourcesStep.class,
PersistTestsStep.class,
PersistCrossProjectDuplicationIndexStep.class,
EnableAnalysisStep.class,


+ 0
- 32
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/batch/BatchReportReaderImplTest.java View File

@@ -47,10 +47,6 @@ public class BatchReportReaderImplTest {
private static final ScannerReport.SyntaxHighlightingRule SYNTAX_HIGHLIGHTING_2 = ScannerReport.SyntaxHighlightingRule.newBuilder().build();
private static final ScannerReport.LineCoverage COVERAGE_1 = ScannerReport.LineCoverage.newBuilder().build();
private static final ScannerReport.LineCoverage COVERAGE_2 = ScannerReport.LineCoverage.newBuilder().build();
private static final ScannerReport.Test TEST_1 = ScannerReport.Test.newBuilder().setName("1").build();
private static final ScannerReport.Test TEST_2 = ScannerReport.Test.newBuilder().setName("2").build();
private static final ScannerReport.CoverageDetail COVERAGE_DETAIL_1 = ScannerReport.CoverageDetail.newBuilder().setTestName("1").build();
private static final ScannerReport.CoverageDetail COVERAGE_DETAIL_2 = ScannerReport.CoverageDetail.newBuilder().setTestName("2").build();

@Rule
public JUnitTempFolder tempFolder = new JUnitTempFolder();
@@ -288,34 +284,6 @@ public class BatchReportReaderImplTest {
res.close();
}

@Test
public void readTests_returns_empty_CloseableIterator_when_file_does_not_exist() {
assertThat(underTest.readTests(COMPONENT_REF)).isEmpty();
}

@Test
public void verify_readTests() {
writer.writeTests(COMPONENT_REF, of(TEST_1, TEST_2));

CloseableIterator<ScannerReport.Test> res = underTest.readTests(COMPONENT_REF);
assertThat(res).containsExactly(TEST_1, TEST_2);
res.close();
}

@Test
public void readCoverageDetails_returns_empty_CloseableIterator_when_file_does_not_exist() {
assertThat(underTest.readCoverageDetails(COMPONENT_REF)).isEmpty();
}

@Test
public void verify_readCoverageDetails() {
writer.writeCoverageDetails(COMPONENT_REF, of(COVERAGE_DETAIL_1, COVERAGE_DETAIL_2));

CloseableIterator<ScannerReport.CoverageDetail> res = underTest.readCoverageDetails(COMPONENT_REF);
assertThat(res).containsExactly(COVERAGE_DETAIL_1, COVERAGE_DETAIL_2);
res.close();
}

@Test
public void verify_readAnalysisWarnings() {
ScannerReport.AnalysisWarning warning1 = ScannerReport.AnalysisWarning.newBuilder().setText("warning 1").build();

+ 0
- 24
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/batch/BatchReportReaderRule.java View File

@@ -54,8 +54,6 @@ public class BatchReportReaderRule implements TestRule, BatchReportReader {
private Map<Integer, List<ScannerReport.SyntaxHighlightingRule>> syntaxHighlightings = new HashMap<>();
private Map<Integer, List<ScannerReport.LineCoverage>> coverages = new HashMap<>();
private Map<Integer, List<String>> fileSources = new HashMap<>();
private Map<Integer, List<ScannerReport.Test>> tests = new HashMap<>();
private Map<Integer, List<ScannerReport.CoverageDetail>> coverageDetails = new HashMap<>();
private Map<Integer, List<ScannerReport.LineSgnificantCode>> significantCode = new HashMap<>();
private Map<Integer, ScannerReport.ChangedLines> changedLines = new HashMap<>();
private List<ScannerReport.AnalysisWarning> analysisWarnings = Collections.emptyList();
@@ -87,8 +85,6 @@ public class BatchReportReaderRule implements TestRule, BatchReportReader {
this.syntaxHighlightings.clear();
this.coverages.clear();
this.fileSources.clear();
this.tests.clear();
this.coverageDetails.clear();
this.significantCode.clear();
}

@@ -308,24 +304,4 @@ public class BatchReportReaderRule implements TestRule, BatchReportReader {
return this;
}

@Override
public CloseableIterator<ScannerReport.Test> readTests(int testFileRef) {
return closeableIterator(this.tests.get(testFileRef));
}

public BatchReportReaderRule putTests(int testFileRed, List<ScannerReport.Test> tests) {
this.tests.put(testFileRed, tests);
return this;
}

@Override
public CloseableIterator<ScannerReport.CoverageDetail> readCoverageDetails(int testFileRef) {
return closeableIterator(this.coverageDetails.get(testFileRef));
}

public BatchReportReaderRule putCoverageDetails(int testFileRef, List<ScannerReport.CoverageDetail> coverageDetails) {
this.coverageDetails.put(testFileRef, coverageDetails);
return this;
}

}

+ 20
- 42
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/dbmigration/PopulateFileSourceLineCountTest.java View File

@@ -19,9 +19,6 @@
*/
package org.sonar.ce.task.projectanalysis.dbmigration;

import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.sql.SQLException;
import java.util.Optional;
import java.util.Random;
@@ -31,11 +28,9 @@ import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.sonar.api.utils.System2;
import org.sonar.ce.task.CeTask;
import org.sonar.db.DbTester;
import org.sonar.db.source.FileSourceDto;

import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
@@ -43,7 +38,6 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.db.source.FileSourceDto.LINE_COUNT_NOT_POPULATED;

@RunWith(DataProviderRunner.class)
public class PopulateFileSourceLineCountTest {

@Rule
@@ -65,13 +59,12 @@ public class PopulateFileSourceLineCountTest {
}

@Test
@UseDataProvider("anyType")
public void execute_populates_line_count_of_any_type(String type) throws SQLException {
public void execute_populates_line_count_of_any_type() throws SQLException {
String projectUuid = randomAlphanumeric(4);
String fileUuid = randomAlphanumeric(5);
when(ceTask.getComponent()).thenReturn(newComponent(projectUuid));
int lineCount = 1 + random.nextInt(15);
insertUnpopulatedFileSource(projectUuid, fileUuid, type, lineCount);
insertUnpopulatedFileSource(projectUuid, fileUuid, lineCount);
assertThat(getLineCountByFileUuid(fileUuid)).isEqualTo(LINE_COUNT_NOT_POPULATED);

underTest.execute();
@@ -80,8 +73,7 @@ public class PopulateFileSourceLineCountTest {
}

@Test
@UseDataProvider("anyType")
public void execute_changes_only_file_source_with_LINE_COUNT_NOT_POPULATED_value(String type) throws SQLException {
public void execute_changes_only_file_source_with_LINE_COUNT_NOT_POPULATED_value() throws SQLException {
String projectUuid = randomAlphanumeric(4);
String fileUuid1 = randomAlphanumeric(5);
String fileUuid2 = randomAlphanumeric(6);
@@ -91,9 +83,9 @@ public class PopulateFileSourceLineCountTest {
int lineCountFile3 = 150 + random.nextInt(15);

when(ceTask.getComponent()).thenReturn(newComponent(projectUuid));
insertPopulatedFileSource(projectUuid, fileUuid1, type, lineCountFile1);
int badLineCountFile2 = insertInconsistentPopulatedFileSource(projectUuid, fileUuid2, type, lineCountFile2);
insertUnpopulatedFileSource(projectUuid, fileUuid3, type, lineCountFile3);
insertPopulatedFileSource(projectUuid, fileUuid1, lineCountFile1);
int badLineCountFile2 = insertInconsistentPopulatedFileSource(projectUuid, fileUuid2, lineCountFile2);
insertUnpopulatedFileSource(projectUuid, fileUuid3, lineCountFile3);
assertThat(getLineCountByFileUuid(fileUuid1)).isEqualTo(lineCountFile1);
assertThat(getLineCountByFileUuid(fileUuid2)).isEqualTo(badLineCountFile2);
assertThat(getLineCountByFileUuid(fileUuid3)).isEqualTo(LINE_COUNT_NOT_POPULATED);
@@ -106,8 +98,7 @@ public class PopulateFileSourceLineCountTest {
}

@Test
@UseDataProvider("anyType")
public void execute_changes_only_file_source_of_CeTask_component_uuid(String type) throws SQLException {
public void execute_changes_only_file_source_of_CeTask_component_uuid() throws SQLException {
String projectUuid1 = randomAlphanumeric(4);
String projectUuid2 = randomAlphanumeric(5);
String fileUuid1 = randomAlphanumeric(6);
@@ -116,8 +107,8 @@ public class PopulateFileSourceLineCountTest {
int lineCountFile2 = 30 + random.nextInt(15);

when(ceTask.getComponent()).thenReturn(newComponent(projectUuid1));
insertUnpopulatedFileSource(projectUuid1, fileUuid1, type, lineCountFile1);
insertUnpopulatedFileSource(projectUuid2, fileUuid2, type, lineCountFile2);
insertUnpopulatedFileSource(projectUuid1, fileUuid1, lineCountFile1);
insertUnpopulatedFileSource(projectUuid2, fileUuid2, lineCountFile2);

underTest.execute();

@@ -126,13 +117,12 @@ public class PopulateFileSourceLineCountTest {
}

@Test
@UseDataProvider("anyType")
public void execute_set_line_count_to_zero_when_file_source_has_no_line_hashes(String type) throws SQLException {
public void execute_set_line_count_to_zero_when_file_source_has_no_line_hashes() throws SQLException {
String projectUuid = randomAlphanumeric(4);
String fileUuid1 = randomAlphanumeric(5);

when(ceTask.getComponent()).thenReturn(newComponent(projectUuid));
insertFileSource(projectUuid, fileUuid1, type, null, LINE_COUNT_NOT_POPULATED);
insertFileSource(projectUuid, fileUuid1, null, LINE_COUNT_NOT_POPULATED);

underTest.execute();

@@ -140,52 +130,41 @@ public class PopulateFileSourceLineCountTest {
}

@Test
@UseDataProvider("anyType")
public void execute_set_line_count_to_1_when_file_source_has_empty_line_hashes(String type) throws SQLException {
public void execute_set_line_count_to_1_when_file_source_has_empty_line_hashes() throws SQLException {
String projectUuid = randomAlphanumeric(4);
String fileUuid1 = randomAlphanumeric(5);

when(ceTask.getComponent()).thenReturn(newComponent(projectUuid));
insertFileSource(projectUuid, fileUuid1, type, "", LINE_COUNT_NOT_POPULATED);
insertFileSource(projectUuid, fileUuid1, "", LINE_COUNT_NOT_POPULATED);

underTest.execute();

assertThat(getLineCountByFileUuid(fileUuid1)).isEqualTo(1);
}

@DataProvider
public static Object[][] anyType() {
return new Object[][] {
{FileSourceDto.Type.SOURCE},
{FileSourceDto.Type.TEST},
{null},
{randomAlphanumeric(3)},
};
}

private int getLineCountByFileUuid(String fileUuid) {
Long res = (Long) db.selectFirst("select line_count as \"LINE_COUNT\" from file_sources where file_uuid = '" + fileUuid + "'")
.get("LINE_COUNT");
return res.intValue();
}

private void insertUnpopulatedFileSource(String projectUuid, String fileUuid, @Nullable String dataType, int numberOfHashes) {
private void insertUnpopulatedFileSource(String projectUuid, String fileUuid, int numberOfHashes) {
String lineHashes = generateLineHashes(numberOfHashes);

insertFileSource(projectUuid, fileUuid, dataType, lineHashes, LINE_COUNT_NOT_POPULATED);
insertFileSource(projectUuid, fileUuid, lineHashes, LINE_COUNT_NOT_POPULATED);
}

private void insertPopulatedFileSource(String projectUuid, String fileUuid, @Nullable String dataType, int lineCount) {
private void insertPopulatedFileSource(String projectUuid, String fileUuid, int lineCount) {
String lineHashes = generateLineHashes(lineCount);

insertFileSource(projectUuid, fileUuid, dataType, lineHashes, lineCount);
insertFileSource(projectUuid, fileUuid, lineHashes, lineCount);
}

private int insertInconsistentPopulatedFileSource(String projectUuid, String fileUuid, @Nullable String dataType, int lineCount) {
private int insertInconsistentPopulatedFileSource(String projectUuid, String fileUuid, int lineCount) {
String lineHashes = generateLineHashes(lineCount);
int badLineCount = lineCount + random.nextInt(6);

insertFileSource(projectUuid, fileUuid, dataType, lineHashes, badLineCount);
insertFileSource(projectUuid, fileUuid, lineHashes, badLineCount);

return badLineCount;
}
@@ -196,13 +175,12 @@ public class PopulateFileSourceLineCountTest {
.collect(Collectors.joining("\n"));
}

private void insertFileSource(String projectUuid, String fileUuid, @Nullable String dataType, @Nullable String lineHashes, int lineCount) {
private void insertFileSource(String projectUuid, String fileUuid, @Nullable String lineHashes, int lineCount) {
db.executeInsert(
"FILE_SOURCES",
"PROJECT_UUID", projectUuid,
"FILE_UUID", fileUuid,
"LINE_HASHES", lineHashes,
"DATA_TYPE", dataType,
"LINE_COUNT", lineCount,
"CREATED_AT", 1_222_333L,
"UPDATED_AT", 1_222_333L);

+ 1
- 2
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/filemove/FileMoveDetectionStepTest.java View File

@@ -600,8 +600,7 @@ public class FileMoveDetectionStepTest {
FileSourceDto fileSourceDto = new FileSourceDto()
.setFileUuid(file.uuid())
.setProjectUuid(file.projectUuid())
.setLineHashes(linesHashesComputer.getLineHashes())
.setDataType(FileSourceDto.Type.SOURCE);
.setLineHashes(linesHashesComputer.getLineHashes());
dbTester.getDbClient().fileSourceDao().insert(dbTester.getSession(), fileSourceDto);
dbTester.commit();
return fileSourceDto;

+ 1
- 4
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/purge/IndexPurgeListenerTest.java View File

@@ -23,7 +23,6 @@ import java.util.List;
import org.junit.Test;
import org.sonar.server.component.index.ComponentIndexer;
import org.sonar.server.issue.index.IssueIndexer;
import org.sonar.server.test.index.TestIndexer;

import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
@@ -32,11 +31,10 @@ import static org.mockito.Mockito.verify;

public class IndexPurgeListenerTest {

private TestIndexer testIndexer = mock(TestIndexer.class);
private IssueIndexer issueIndexer = mock(IssueIndexer.class);
private ComponentIndexer componentIndexer = mock(ComponentIndexer.class);

private IndexPurgeListener underTest = new IndexPurgeListener(testIndexer, issueIndexer, componentIndexer);
private IndexPurgeListener underTest = new IndexPurgeListener(issueIndexer, componentIndexer);

@Test
public void test_onComponentDisabling() {
@@ -45,7 +43,6 @@ public class IndexPurgeListenerTest {
List<String> uuids = singletonList(uuid);
underTest.onComponentsDisabling(projectUuid, uuids);

verify(testIndexer).deleteByFile(uuid);
verify(componentIndexer).delete(projectUuid, uuids);
}


+ 14
- 17
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/source/PersistFileSourcesStepTest.java View File

@@ -43,7 +43,6 @@ import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.protobuf.DbFileSources;
import org.sonar.db.source.FileSourceDto;
import org.sonar.db.source.FileSourceDto.Type;
import org.sonar.db.source.LineHashVersion;

import static org.assertj.core.api.Assertions.assertThat;
@@ -107,7 +106,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
underTest.execute(new TestComputationStepContext());

assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
assertThat(fileSourceDto.getProjectUuid()).isEqualTo(PROJECT_UUID);
assertThat(fileSourceDto.getFileUuid()).isEqualTo(FILE1_UUID);
assertThat(fileSourceDto.getBinaryData()).isNotEmpty();
@@ -135,7 +134,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
underTest.execute(new TestComputationStepContext());

assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
assertThat(fileSourceDto.getLineHashes()).containsExactly("137f72c3708c6bd0de00a0e5a69c699b", "e6251bcf1a7dc3ba5e7933e325bbe605");
assertThat(fileSourceDto.getSrcHash()).isEqualTo("ee5a58024a155466b43bc559d953e018");
verify(fileSourceDataWarnings).commitWarnings();
@@ -156,7 +155,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
underTest.execute(new TestComputationStepContext());

assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
assertThat(fileSourceDto.getSourceData()).isEqualTo(dbData);
verify(fileSourceDataWarnings).commitWarnings();
}
@@ -179,7 +178,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
underTest.execute(new TestComputationStepContext());

assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
assertThat(fileSourceDto.getSourceData()).isEqualTo(dbData);
assertThat(fileSourceDto.getRevision()).isNull();
verify(fileSourceDataWarnings).commitWarnings();
@@ -204,7 +203,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
underTest.execute(new TestComputationStepContext());

assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);

DbFileSources.Data data = fileSourceDto.getSourceData();

@@ -236,7 +235,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
underTest.execute(new TestComputationStepContext());

assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
DbFileSources.Data data = fileSourceDto.getSourceData();
assertThat(data).isEqualTo(dbData);
assertThat(data.getLinesList()).hasSize(1);
@@ -260,7 +259,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
underTest.execute(new TestComputationStepContext());

assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
assertThat(fileSourceDto.getSourceData()).isEqualTo(dbData);
verify(fileSourceDataWarnings).commitWarnings();
}
@@ -277,7 +276,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
underTest.execute(new TestComputationStepContext());

assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
assertThat(fileSourceDto.getSourceData()).isEqualTo(dbData);
verify(fileSourceDataWarnings).commitWarnings();
}
@@ -289,7 +288,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {

underTest.execute(new TestComputationStepContext());

FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
assertThat(fileSourceDto.getRevision()).isEqualTo("rev-1");
verify(fileSourceDataWarnings).commitWarnings();
}
@@ -300,7 +299,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {

underTest.execute(new TestComputationStepContext());

FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
assertThat(fileSourceDto.getRevision()).isNull();
verify(fileSourceDataWarnings).commitWarnings();
}
@@ -316,7 +315,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
underTest.execute(new TestComputationStepContext());

assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
assertThat(fileSourceDto.getSrcHash()).isEqualTo("sourceHash");
assertThat(fileSourceDto.getLineHashes()).isEqualTo(Collections.singletonList("lineHash"));
assertThat(fileSourceDto.getCreatedAt()).isEqualTo(PAST);
@@ -331,7 +330,6 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
dbClient.fileSourceDao().insert(dbTester.getSession(), new FileSourceDto()
.setProjectUuid(PROJECT_UUID)
.setFileUuid(FILE1_UUID)
.setDataType(Type.SOURCE)
.setSrcHash("5b4bd9815cdb17b8ceae19eb1810c34c")
.setLineHashes(Collections.singletonList("6438c669e0d0de98e6929c2cc0fac474"))
.setDataHash("6cad150e3d065976c230cddc5a09efaa")
@@ -362,7 +360,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
underTest.execute(new TestComputationStepContext());

assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
assertThat(fileSourceDto.getCreatedAt()).isEqualTo(past);
assertThat(fileSourceDto.getUpdatedAt()).isEqualTo(NOW);
assertThat(fileSourceDto.getRevision()).isEqualTo("rev-1");
@@ -380,7 +378,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
underTest.execute(new TestComputationStepContext());

assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
assertThat(fileSourceDto.getCreatedAt()).isEqualTo(PAST);
assertThat(fileSourceDto.getUpdatedAt()).isEqualTo(NOW);
assertThat(fileSourceDto.getSrcHash()).isEqualTo("newSourceHash");
@@ -405,7 +403,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
underTest.execute(new TestComputationStepContext());

assertThat(dbTester.countRowsOfTable("file_sources")).isEqualTo(1);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectSourceByFileUuid(session, FILE1_UUID);
FileSourceDto fileSourceDto = dbClient.fileSourceDao().selectByFileUuid(session, FILE1_UUID);
assertThat(fileSourceDto.getCreatedAt()).isEqualTo(PAST);
assertThat(fileSourceDto.getUpdatedAt()).isEqualTo(NOW);
assertThat(fileSourceDto.getRevision()).isEqualTo("revision");
@@ -425,7 +423,6 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
FileSourceDto dto = new FileSourceDto()
.setProjectUuid(PROJECT_UUID)
.setFileUuid(FILE1_UUID)
.setDataType(Type.SOURCE)
.setSrcHash("sourceHash")
.setLineHashes(Collections.singletonList("lineHash"))
.setDataHash(dataHash)

+ 0
- 280
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/PersistTestsStepTest.java View File

@@ -1,280 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.ce.task.projectanalysis.step;

import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
import org.sonar.ce.task.projectanalysis.component.Component;
import org.sonar.ce.task.projectanalysis.component.FileAttributes;
import org.sonar.ce.task.projectanalysis.component.ReportComponent;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
import org.sonar.ce.task.step.ComputationStep;
import org.sonar.ce.task.step.TestComputationStepContext;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.protobuf.DbFileSources;
import org.sonar.db.source.FileSourceDto;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.CoverageDetail;
import org.sonar.scanner.protocol.output.ScannerReport.Test.TestStatus;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class PersistTestsStepTest extends BaseStepTest {

private static final String PROJECT_UUID = "PROJECT";
private static final String PROJECT_KEY = "PROJECT_KEY";
private static final int TEST_FILE_REF_1 = 3;
private static final int TEST_FILE_REF_2 = 4;
private static final int MAIN_FILE_REF_1 = 5;
private static final int MAIN_FILE_REF_2 = 6;
private static final String TEST_FILE_UUID_1 = "TEST-FILE-1";
private static final String TEST_FILE_UUID_2 = "TEST-FILE-2";
private static final String MAIN_FILE_UUID_1 = "MAIN-FILE-1";
private static final String MAIN_FILE_UUID_2 = "MAIN-FILE-2";

@Rule
public DbTester db = DbTester.create(System2.INSTANCE);

@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();

@Rule
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();

@Rule
public LogTester log = new LogTester();

DbClient dbClient = db.getDbClient();
Component root;

PersistTestsStep underTest;

long now = 123456789L;

@Before
public void setup() {
System2 system2 = mock(System2.class);
when(system2.now()).thenReturn(now);

underTest = new PersistTestsStep(dbClient, system2, reportReader, treeRootHolder);

root = ReportComponent.builder(Component.Type.PROJECT, 1).setUuid(PROJECT_UUID).setKey(PROJECT_KEY).addChildren(
ReportComponent.builder(Component.Type.FILE, 3).setUuid(TEST_FILE_UUID_1).setKey("TEST_FILE1_KEY").setFileAttributes(new FileAttributes(true, null, 1)).build(),
ReportComponent.builder(Component.Type.FILE, 4).setUuid(TEST_FILE_UUID_2).setKey("TEST_FILE2_KEY").setFileAttributes(new FileAttributes(true, null, 1)).build(),
ReportComponent.builder(Component.Type.FILE, 5).setUuid(MAIN_FILE_UUID_1).setKey("MAIN_FILE1_KEY").build(),
ReportComponent.builder(Component.Type.FILE, 6).setUuid(MAIN_FILE_UUID_2).setKey("MAIN_FILE2_KEY").build())
.build();
treeRootHolder.setRoot(root);
}

@Override
protected ComputationStep step() {
return underTest;
}

@Test
public void no_test_in_database_and_batch_report() {
underTest.execute(new TestComputationStepContext());

assertThat(dbClient.fileSourceDao().selectTestByFileUuid(db.getSession(), TEST_FILE_UUID_1)).isNull();
assertThat(log.logs()).isEmpty();
}

@Test
public void insert_several_tests_in_a_report() {
List<ScannerReport.Test> batchTests = Arrays.asList(
newTest(1), newTest(2));
reportReader.putTests(TEST_FILE_REF_1, batchTests);
List<CoverageDetail> coverageDetails = Arrays.asList(
newCoverageDetail(1, MAIN_FILE_REF_1));
reportReader.putCoverageDetails(TEST_FILE_REF_1, coverageDetails);

underTest.execute(new TestComputationStepContext());

assertThat(db.countRowsOfTable("file_sources")).isEqualTo(1);

FileSourceDto dto = dbClient.fileSourceDao().selectTestByFileUuid(db.getSession(), TEST_FILE_UUID_1);
assertThat(dto.getCreatedAt()).isEqualTo(now);
assertThat(dto.getUpdatedAt()).isEqualTo(now);
assertThat(dto.getProjectUuid()).isEqualTo(PROJECT_UUID);
assertThat(dto.getFileUuid()).isEqualTo(TEST_FILE_UUID_1);
assertThat(dto.getTestData()).hasSize(2);

assertThat(dto.getTestData()).extracting("name", "coveredFileCount").containsOnly(
tuple("name#1", 1),
tuple("name#2", 0));

assertThat(log.logs()).isEmpty();
}

@Test
public void insert_all_data_of_a_test() {
reportReader.putTests(TEST_FILE_REF_1, Arrays.asList(newTest(1)));
reportReader.putCoverageDetails(TEST_FILE_REF_1, Arrays.asList(newCoverageDetail(1, MAIN_FILE_REF_1)));

underTest.execute(new TestComputationStepContext());

FileSourceDto dto = dbClient.fileSourceDao().selectTestByFileUuid(db.getSession(), TEST_FILE_UUID_1);
assertThat(dto.getCreatedAt()).isEqualTo(now);
assertThat(dto.getUpdatedAt()).isEqualTo(now);
assertThat(dto.getProjectUuid()).isEqualTo(PROJECT_UUID);
assertThat(dto.getFileUuid()).isEqualTo(TEST_FILE_UUID_1);
assertThat(dto.getTestData()).hasSize(1);

DbFileSources.Test test1 = dto.getTestData().get(0);
assertThat(test1.getUuid()).isNotEmpty();
assertThat(test1.getName()).isEqualTo("name#1");
assertThat(test1.getMsg()).isEqualTo("message#1");
assertThat(test1.getStacktrace()).isEqualTo("stacktrace#1");
assertThat(test1.getStatus()).isEqualTo(DbFileSources.Test.TestStatus.FAILURE);
assertThat(test1.getExecutionTimeMs()).isEqualTo(1_000);
assertThat(test1.getCoveredFileCount()).isEqualTo(1);
assertThat(test1.getCoveredFile(0).getCoveredLineList()).containsOnly(1, 2, 3);
assertThat(test1.getCoveredFile(0).getFileUuid()).isEqualTo(MAIN_FILE_UUID_1);
}

@Test
public void insert_tests_without_coverage_details() {
List<ScannerReport.Test> batchTests = Arrays.asList(newTest(1));
reportReader.putTests(TEST_FILE_REF_1, batchTests);

underTest.execute(new TestComputationStepContext());

FileSourceDto dto = dbClient.fileSourceDao().selectTestByFileUuid(db.getSession(), TEST_FILE_UUID_1);
assertThat(dto.getFileUuid()).isEqualTo(TEST_FILE_UUID_1);
List<DbFileSources.Test> tests = dto.getTestData();
assertThat(tests).hasSize(1);
assertThat(tests.get(0).getCoveredFileList()).isEmpty();
assertThat(tests.get(0).getMsg()).isEqualTo("message#1");
}

@Test
public void insert_coverage_details_not_taken_into_account() {
List<ScannerReport.Test> batchTests = Arrays.asList(newTest(1));
reportReader.putTests(TEST_FILE_REF_1, batchTests);
List<CoverageDetail> coverageDetails = Arrays.asList(newCoverageDetail(1, MAIN_FILE_REF_1), newCoverageDetail(2, MAIN_FILE_REF_2));
reportReader.putCoverageDetails(TEST_FILE_REF_1, coverageDetails);
reportReader.putCoverageDetails(TEST_FILE_REF_2, coverageDetails);

underTest.execute(new TestComputationStepContext());

assertThat(log.logs(LoggerLevel.WARN)).hasSize(1);
assertThat(log.logs(LoggerLevel.WARN).get(0)).isEqualTo("Some coverage tests are not taken into account during analysis of project 'PROJECT_KEY'");
assertThat(log.logs(LoggerLevel.TRACE)).hasSize(2);
assertThat(log.logs(LoggerLevel.TRACE).get(0)).isEqualTo("The following test coverages for file 'TEST_FILE1_KEY' have not been taken into account: name#2");
assertThat(log.logs(LoggerLevel.TRACE).get(1)).startsWith("The following test coverages for file 'TEST_FILE2_KEY' have not been taken into account: ");
assertThat(log.logs(LoggerLevel.TRACE).get(1)).contains("name#1", "name#2");
}

@Test
public void aggregate_coverage_details() {
reportReader.putTests(TEST_FILE_REF_1, Arrays.asList(newTest(1)));
reportReader.putCoverageDetails(TEST_FILE_REF_1, Arrays.asList(
newCoverageDetailWithLines(1, MAIN_FILE_REF_1, 1, 3),
newCoverageDetailWithLines(1, MAIN_FILE_REF_1, 2, 4)));

underTest.execute(new TestComputationStepContext());

FileSourceDto dto = dbClient.fileSourceDao().selectTestByFileUuid(db.getSession(), TEST_FILE_UUID_1);
List<Integer> coveredLines = dto.getTestData().get(0).getCoveredFile(0).getCoveredLineList();
assertThat(coveredLines).containsOnly(1, 2, 3, 4);
}

@Test
public void update_existing_test() {
// ARRANGE
dbClient.fileSourceDao().insert(db.getSession(), new FileSourceDto()
.setProjectUuid(PROJECT_UUID)
.setFileUuid(TEST_FILE_UUID_1)
.setTestData(Arrays.asList(DbFileSources.Test.newBuilder()
.setUuid("test-uuid-1")
.setName("name#1")
.setStatus(DbFileSources.Test.TestStatus.ERROR)
.setStacktrace("old-stacktrace#1")
.setMsg("old-message#1")
.setExecutionTimeMs(987_654_321L)
.build()))
.setCreatedAt(100_000)
.setUpdatedAt(100_000));
db.getSession().commit();
assertThat(dbClient.fileSourceDao().selectTestByFileUuid(db.getSession(), TEST_FILE_UUID_1)).isNotNull();

ScannerReport.Test newBatchTest = newTest(1);
reportReader.putTests(TEST_FILE_REF_1, Arrays.asList(newBatchTest));

CoverageDetail newCoverageDetail = newCoverageDetail(1, MAIN_FILE_REF_1);
reportReader.putCoverageDetails(TEST_FILE_REF_1, Arrays.asList(newCoverageDetail));

// ACT
underTest.execute(new TestComputationStepContext());

// ASSERT
FileSourceDto dto = dbClient.fileSourceDao().selectTestByFileUuid(db.getSession(), TEST_FILE_UUID_1);
assertThat(dto.getCreatedAt()).isEqualTo(100_000);
assertThat(dto.getUpdatedAt()).isEqualTo(now);
assertThat(dto.getTestData()).hasSize(1);

DbFileSources.Test test = dto.getTestData().get(0);
assertThat(test.getUuid()).isNotEqualTo("test-uuid-1");
assertThat(test.getName()).isEqualTo("name#1");
assertThat(test.getStatus()).isEqualTo(DbFileSources.Test.TestStatus.valueOf(newBatchTest.getStatus().name()));
assertThat(test.getMsg()).isEqualTo(newBatchTest.getMsg());
assertThat(test.getStacktrace()).isEqualTo(newBatchTest.getStacktrace());
assertThat(test.getExecutionTimeMs()).isEqualTo(newBatchTest.getDurationInMs());
assertThat(test.getCoveredFileCount()).isEqualTo(1);
assertThat(test.getCoveredFile(0).getCoveredLineList()).containsOnly(1, 2, 3);
assertThat(test.getCoveredFile(0).getFileUuid()).isEqualTo(MAIN_FILE_UUID_1);
}

private ScannerReport.Test newTest(int id) {
return ScannerReport.Test.newBuilder()
.setStatus(TestStatus.FAILURE)
.setName("name#" + id)
.setStacktrace("stacktrace#" + id)
.setMsg("message#" + id)
.setDurationInMs(1_000)
.build();
}

private ScannerReport.CoverageDetail newCoverageDetail(int id, int covered_file_ref) {
return newCoverageDetailWithLines(id, covered_file_ref, 1, 2, 3);
}

private ScannerReport.CoverageDetail newCoverageDetailWithLines(int id, int covered_file_ref, Integer... lines) {
return CoverageDetail.newBuilder()
.setTestName("name#" + id)
.addCoveredFile(CoverageDetail.CoveredFile.newBuilder()
.addAllCoveredLine(Arrays.asList(lines))
.setFileRef(covered_file_ref)
.build())
.build();
}
}

+ 0
- 4
server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java View File

@@ -149,7 +149,6 @@ import org.sonar.server.rule.index.RuleIndexer;
import org.sonar.server.setting.DatabaseSettingLoader;
import org.sonar.server.setting.DatabaseSettingsEnabler;
import org.sonar.server.setting.ThreadLocalSettings;
import org.sonar.server.test.index.TestIndexer;
import org.sonar.server.user.index.UserIndex;
import org.sonar.server.user.index.UserIndexer;
import org.sonar.server.util.OkHttpClientProvider;
@@ -425,9 +424,6 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
EmailNotificationChannel.class,
ReportAnalysisFailureNotificationModule.class,

// Tests
TestIndexer.class,

// System
ServerLogging.class,


+ 1
- 1
server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java View File

@@ -97,7 +97,7 @@ public class ComputeEngineContainerImplTest {
assertThat(picoContainer.getComponentAdapters())
.hasSize(
CONTAINER_ITSELF
+ 70 // level 4
+ 69 // level 4
+ 6 // content of CeConfigurationModule
+ 4 // content of CeQueueModule
+ 3 // content of CeHttpModule

+ 5
- 13
server/sonar-db-dao/src/main/java/org/sonar/db/source/FileSourceDao.java View File

@@ -35,7 +35,6 @@ import org.apache.commons.io.IOUtils;
import org.apache.ibatis.session.ResultHandler;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
import org.sonar.db.source.FileSourceDto.Type;

import static org.sonar.db.DatabaseUtils.toUniqueAndSortedPartitions;

@@ -44,18 +43,13 @@ public class FileSourceDao implements Dao {
private static final Splitter END_OF_LINE_SPLITTER = Splitter.on('\n');

@CheckForNull
public FileSourceDto selectSourceByFileUuid(DbSession session, String fileUuid) {
return mapper(session).select(fileUuid, Type.SOURCE);
}

@CheckForNull
public FileSourceDto selectTestByFileUuid(DbSession dbSession, String fileUuid) {
return mapper(dbSession).select(fileUuid, Type.TEST);
public FileSourceDto selectByFileUuid(DbSession session, String fileUuid) {
return mapper(session).selectByFileUuid(fileUuid);
}

@CheckForNull
public LineHashVersion selectLineHashesVersion(DbSession dbSession, String fileUuid) {
Integer version = mapper(dbSession).selectLineHashesVersion(fileUuid, Type.SOURCE);
Integer version = mapper(dbSession).selectLineHashesVersion(fileUuid);
return version == null ? LineHashVersion.WITHOUT_SIGNIFICANT_CODE : LineHashVersion.valueOf(version);
}

@@ -65,9 +59,8 @@ public class FileSourceDao implements Dao {
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = connection.prepareStatement("SELECT line_hashes FROM file_sources WHERE file_uuid=? AND data_type=?");
pstmt = connection.prepareStatement("SELECT line_hashes FROM file_sources WHERE file_uuid=? AND data_type='SOURCE'");
pstmt.setString(1, fileUuid);
pstmt.setString(2, Type.SOURCE);
rs = pstmt.executeQuery();
if (rs.next()) {
String string = rs.getString(1);
@@ -100,9 +93,8 @@ public class FileSourceDao implements Dao {
ResultSet rs = null;
Reader reader = null;
try {
pstmt = connection.prepareStatement("SELECT line_hashes FROM file_sources WHERE file_uuid=? AND data_type=?");
pstmt = connection.prepareStatement("SELECT line_hashes FROM file_sources WHERE file_uuid=? AND data_type='SOURCE'");
pstmt.setString(1, fileUuid);
pstmt.setString(2, Type.SOURCE);
rs = pstmt.executeQuery();
if (rs.next()) {
reader = rs.getCharacterStream(1);

+ 0
- 84
server/sonar-db-dao/src/main/java/org/sonar/db/source/FileSourceDto.java View File

@@ -26,8 +26,6 @@ import com.google.protobuf.InvalidProtocolBufferException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.CheckForNull;
@@ -68,7 +66,6 @@ public class FileSourceDto {
private int lineCount = LINE_COUNT_NOT_POPULATED;
private String srcHash;
private byte[] binaryData = new byte[0];
private String dataType;
private String dataHash;
private String revision;
@Nullable
@@ -170,56 +167,6 @@ public class FileSourceDto {
}
}

public static List<DbFileSources.Test> decodeTestData(byte[] binaryData) {
// stream is always closed
return decodeTestData(new ByteArrayInputStream(binaryData));
}

/**
* Decompress and deserialize content of column FILE_SOURCES.BINARY_DATA.
* The parameter "input" is always closed by this method.
*/
public static List<DbFileSources.Test> decodeTestData(InputStream binaryInput) {
LZ4BlockInputStream lz4Input = null;
List<DbFileSources.Test> tests = new ArrayList<>();
try {
lz4Input = new LZ4BlockInputStream(binaryInput);

DbFileSources.Test currentTest;
do {
currentTest = DbFileSources.Test.parseDelimitedFrom(lz4Input);
if (currentTest != null) {
tests.add(currentTest);
}
} while (currentTest != null);
return tests;
} catch (IOException e) {
throw new IllegalStateException("Fail to decompress and deserialize source data", e);
} finally {
IOUtils.closeQuietly(lz4Input);
}
}

/**
* Serialize and compress protobuf message {@link org.sonar.db.protobuf.DbFileSources.Data}
* in the column BINARY_DATA.
*/
public static byte[] encodeTestData(List<DbFileSources.Test> tests) {
ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
LZ4BlockOutputStream compressedOutput = new LZ4BlockOutputStream(byteOutput);
try {
for (DbFileSources.Test test : tests) {
test.writeDelimitedTo(compressedOutput);
}
compressedOutput.close();
return byteOutput.toByteArray();
} catch (IOException e) {
throw new IllegalStateException("Fail to serialize and compress source tests", e);
} finally {
IOUtils.closeQuietly(compressedOutput);
}
}

/**
* Compressed value of serialized protobuf message {@link org.sonar.db.protobuf.DbFileSources.Data}
*/
@@ -243,24 +190,10 @@ public class FileSourceDto {
}

public FileSourceDto setSourceData(DbFileSources.Data data) {
this.dataType = Type.SOURCE;
this.binaryData = encodeSourceData(data);
return this;
}

/**
* Compressed value of serialized protobuf message {@link org.sonar.db.protobuf.DbFileSources.Data}
*/
public List<DbFileSources.Test> getTestData() {
return decodeTestData(binaryData);
}

public FileSourceDto setTestData(List<DbFileSources.Test> data) {
this.dataType = Type.TEST;
this.binaryData = encodeTestData(data);
return this;
}

/** Used by MyBatis */
public String getRawLineHashes() {
return lineHashes;
@@ -332,15 +265,6 @@ public class FileSourceDto {
return this;
}

public String getDataType() {
return dataType;
}

public FileSourceDto setDataType(String dataType) {
this.dataType = dataType;
return this;
}

public String getRevision() {
return revision;
}
@@ -350,12 +274,4 @@ public class FileSourceDto {
return this;
}

public static class Type {
public static final String SOURCE = "SOURCE";
public static final String TEST = "TEST";

private Type() {
// utility class
}
}
}

+ 2
- 2
server/sonar-db-dao/src/main/java/org/sonar/db/source/FileSourceMapper.java View File

@@ -30,12 +30,12 @@ public interface FileSourceMapper {
List<FileSourceDto> selectHashesForProject(@Param("projectUuid") String projectUuid, @Param("dataType") String dataType);

@CheckForNull
FileSourceDto select(@Param("fileUuid") String fileUuid, @Param("dataType") String dataType);
FileSourceDto selectByFileUuid(@Param("fileUuid") String fileUuid);

void scrollLineHashes(@Param("fileUuids") Collection<String> fileUuids, ResultHandler<LineHashesWithUuidDto> rowHandler);

@CheckForNull
Integer selectLineHashesVersion(@Param("fileUuid") String fileUuid, @Param("dataType") String dataType);
Integer selectLineHashesVersion(@Param("fileUuid") String fileUuid);

void insert(FileSourceDto dto);


+ 6
- 8
server/sonar-db-dao/src/main/resources/org/sonar/db/source/FileSourceMapper.xml View File

@@ -4,7 +4,7 @@

<mapper namespace="org.sonar.db.source.FileSourceMapper">

<select id="select" parameterType="map" resultType="org.sonar.db.source.FileSourceDto">
<select id="selectByFileUuid" parameterType="map" resultType="org.sonar.db.source.FileSourceDto">
select
id,
project_uuid as projectUuid,
@@ -17,14 +17,12 @@
line_count as lineCount,
data_hash as dataHash,
src_hash as srcHash,
data_type as
dataType,
revision
from
file_sources
where
file_uuid = #{fileUuid,jdbcType=VARCHAR}
and data_type = #{dataType,jdbcType=VARCHAR}
and data_type = 'SOURCE'
</select>

<select id="selectHashesForProject" parameterType="map" resultType="org.sonar.db.source.FileSourceDto">
@@ -35,11 +33,11 @@
src_hash as srcHash,
revision,
updated_at as updatedAt
from
from
file_sources
where
project_uuid = #{projectUuid,jdbcType=VARCHAR}
and data_type = #{dataType,jdbcType=VARCHAR}
and data_type = 'SOURCE'
</select>

<select id="scrollLineHashes" parameterType="map" resultType="org.sonar.db.source.LineHashesWithUuidDto" fetchSize="${_scrollFetchSize}" resultSetType="FORWARD_ONLY">
@@ -66,7 +64,7 @@
file_sources
WHERE
file_uuid = #{fileUuid,jdbcType=VARCHAR}
and data_type=#{dataType,jdbcType=VARCHAR}
and data_type = 'SOURCE'
</select>

<insert id="insert" parameterType="org.sonar.db.source.FileSourceDto" useGeneratedKeys="false">
@@ -97,7 +95,7 @@
#{lineCount,jdbcType=INTEGER},
#{dataHash,jdbcType=VARCHAR},
#{srcHash,jdbcType=VARCHAR},
#{dataType,jdbcType=VARCHAR},
'SOURCE',
#{revision,jdbcType=VARCHAR}
)
</insert>

+ 0
- 21
server/sonar-db-dao/src/test/java/org/sonar/db/component/ScrollForFileMoveComponentDaoTest.java View File

@@ -123,26 +123,6 @@ public class ScrollForFileMoveComponentDaoTest {
verifyFileMoveRowDto(resultHandler, file3);
}

@Test
public void scrollAllFilesForFileMove_ignores_file_source_of_type_TEST() {
OrganizationDto organization = db.organizations().insert();
ComponentDto project = random.nextBoolean() ? db.components().insertPrivateProject(organization) : db.components().insertPublicProject(organization);
ComponentDto module1 = db.components().insertComponent(ComponentTesting.newModuleDto(project));
ComponentDto module2 = db.components().insertComponent(ComponentTesting.newModuleDto(module1));
ComponentAndSource file1 = insertFileAndSource(project, FILE);
ComponentDto file2 = db.components().insertComponent(ComponentTesting.newFileDto(module1).setQualifier(UNIT_TEST_FILE));
db.fileSources().insertFileSource(file2, t -> t.setDataType(UNIT_TEST_FILE));
ComponentAndSource file3 = insertFileAndSource(module2, FILE);
db.fileSources().insertFileSource(file3.component, t -> t.setDataType(UNIT_TEST_FILE));
RecordingResultHandler resultHandler = new RecordingResultHandler();

underTest.scrollAllFilesForFileMove(dbSession, project.uuid(), resultHandler);

assertThat(resultHandler.dtos).hasSize(2);
verifyFileMoveRowDto(resultHandler, file1);
verifyFileMoveRowDto(resultHandler, file3);
}

@Test
public void scrollAllFilesForFileMove_scrolls_large_number_of_files_and_uts() {
OrganizationDto organization = db.organizations().insert();
@@ -268,5 +248,4 @@ public class ScrollForFileMoveComponentDaoTest {
assertThat(dto.getLineCount()).isEqualTo(componentAndSource.source.getLineCount());
}


}

+ 4
- 5
server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java View File

@@ -214,9 +214,8 @@ public class PurgeDaoTest {
assertThat(db.countSql("select count(*) from issues where resolution = 'REMOVED'")).isEqualTo(0);

db.fileSources().insertFileSource(srcFile);
db.fileSources().insertFileSource(testFile, f -> f.setDataType("TEST"));
FileSourceDto nonSelectedFileSource = db.fileSources().insertFileSource(nonSelectedFile);
assertThat(db.countRowsOfTable("file_sources")).isEqualTo(3);
assertThat(db.countRowsOfTable("file_sources")).isEqualTo(2);

MetricDto metric1 = db.measures().insertMetric();
MetricDto metric2 = db.measures().insertMetric();
@@ -254,11 +253,12 @@ public class PurgeDaoTest {

// delete file sources of selected
assertThat(db.countRowsOfTable("file_sources")).isEqualTo(1);
assertThat(db.getDbClient().fileSourceDao().selectSourceByFileUuid(dbSession, nonSelectedFileSource.getFileUuid())).isNotNull();
assertThat(db.getDbClient().fileSourceDao().selectByFileUuid(dbSession, nonSelectedFileSource.getFileUuid())).isNotNull();

// deletes live measure of selected
assertThat(db.countRowsOfTable("live_measures")).isEqualTo(4);
List<LiveMeasureDto> liveMeasureDtos = db.getDbClient().liveMeasureDao().selectByComponentUuidsAndMetricIds(dbSession, ImmutableSet.of(srcFile.uuid(), dir.uuid(), project.uuid(), nonSelectedFile.uuid()), ImmutableSet.of(metric1.getId(), metric2.getId()));
List<LiveMeasureDto> liveMeasureDtos = db.getDbClient().liveMeasureDao().selectByComponentUuidsAndMetricIds(dbSession,
ImmutableSet.of(srcFile.uuid(), dir.uuid(), project.uuid(), nonSelectedFile.uuid()), ImmutableSet.of(metric1.getId(), metric2.getId()));
assertThat(liveMeasureDtos)
.extracting(LiveMeasureDto::getComponentUuid)
.containsOnly(nonSelectedFile.uuid(), project.uuid());
@@ -275,7 +275,6 @@ public class PurgeDaoTest {
db.assertDbUnit(getClass(), "shouldDeleteAnalyses-result.xml", "snapshots");
}


@Test
public void deleteAnalyses_deletes_rows_in_events_and_event_component_changes() {
ComponentDto project = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization());

+ 6
- 51
server/sonar-db-dao/src/test/java/org/sonar/db/source/FileSourceDaoTest.java View File

@@ -41,7 +41,6 @@ import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.source.FileSourceDto.Type;

import static com.google.common.collect.ImmutableList.of;
import static java.util.Collections.emptyList;
@@ -64,7 +63,7 @@ public class FileSourceDaoTest {
public void select() {
dbTester.prepareDbUnit(getClass(), "shared.xml");

FileSourceDto fileSourceDto = underTest.selectSourceByFileUuid(dbSession, "FILE1_UUID");
FileSourceDto fileSourceDto = underTest.selectByFileUuid(dbSession, "FILE1_UUID");

assertThat(fileSourceDto.getBinaryData()).isNotEmpty();
assertThat(fileSourceDto.getDataHash()).isEqualTo("hash");
@@ -72,7 +71,6 @@ public class FileSourceDaoTest {
assertThat(fileSourceDto.getFileUuid()).isEqualTo("FILE1_UUID");
assertThat(fileSourceDto.getCreatedAt()).isEqualTo(1500000000000L);
assertThat(fileSourceDto.getUpdatedAt()).isEqualTo(1500000000000L);
assertThat(fileSourceDto.getDataType()).isEqualTo(Type.SOURCE);
assertThat(fileSourceDto.getRevision()).isEqualTo("123456789");
assertThat(fileSourceDto.getLineHashesVersion()).isEqualTo(0);

@@ -117,7 +115,6 @@ public class FileSourceDaoTest {
.setDataHash("FILE2_DATA_HASH")
.setLineHashes(of("LINE1_HASH", "LINE2_HASH"))
.setSrcHash("FILE2_HASH")
.setDataType(Type.SOURCE)
.setCreatedAt(1500000000000L)
.setUpdatedAt(1500000000001L)
.setLineHashesVersion(1)
@@ -125,7 +122,7 @@ public class FileSourceDaoTest {
underTest.insert(dbSession, expected);
dbSession.commit();

FileSourceDto fileSourceDto = underTest.selectSourceByFileUuid(dbSession, expected.getFileUuid());
FileSourceDto fileSourceDto = underTest.selectByFileUuid(dbSession, expected.getFileUuid());

assertThat(fileSourceDto.getProjectUuid()).isEqualTo(expected.getProjectUuid());
assertThat(fileSourceDto.getFileUuid()).isEqualTo(expected.getFileUuid());
@@ -156,30 +153,12 @@ public class FileSourceDaoTest {
FileSourceDto fileSourceDto = new FileSourceDto()
.setProjectUuid("Foo")
.setFileUuid("Bar")
.setDataType(Type.SOURCE)
.setCreatedAt(1500000000000L)
.setUpdatedAt(1500000000001L);
underTest.insert(dbSession, fileSourceDto);
dbSession.commit();

FileSourceDto res = underTest.selectSourceByFileUuid(dbSession, fileSourceDto.getFileUuid());

assertThat(res.getLineCount()).isEqualTo(0);
assertThat(res.getLineHashes()).isEmpty();
}

@Test
public void selectTest_reads_test_without_line_hashes() {
FileSourceDto fileSourceDto = new FileSourceDto()
.setProjectUuid("Foo")
.setFileUuid("Bar")
.setDataType(Type.TEST)
.setCreatedAt(1500000000000L)
.setUpdatedAt(1500000000001L);
underTest.insert(dbSession, fileSourceDto);
dbSession.commit();

FileSourceDto res = underTest.selectTestByFileUuid(dbSession, fileSourceDto.getFileUuid());
FileSourceDto res = underTest.selectByFileUuid(dbSession, fileSourceDto.getFileUuid());

assertThat(res.getLineCount()).isEqualTo(0);
assertThat(res.getLineHashes()).isEmpty();
@@ -195,7 +174,6 @@ public class FileSourceDaoTest {
.setBinaryData("FILE2_BINARY_DATA".getBytes())
.setDataHash("FILE2_DATA_HASH")
.setSrcHash("FILE2_HASH")
.setDataType(Type.SOURCE)
.setCreatedAt(1500000000000L)
.setUpdatedAt(1500000000001L)
.setRevision("123456789"));
@@ -213,7 +191,6 @@ public class FileSourceDaoTest {
.setDataHash("FILE2_DATA_HASH")
.setLineHashes(singletonList("hashes"))
.setSrcHash("FILE2_HASH")
.setDataType(Type.SOURCE)
.setCreatedAt(1500000000000L)
.setUpdatedAt(1500000000001L)
.setRevision("123456789"));
@@ -231,7 +208,6 @@ public class FileSourceDaoTest {
.setDataHash("FILE2_DATA_HASH")
.setLineHashes(singletonList("hashes"))
.setSrcHash("FILE2_HASH")
.setDataType(Type.SOURCE)
.setCreatedAt(1500000000000L)
.setUpdatedAt(1500000000001L)
.setLineHashesVersion(1)
@@ -251,7 +227,6 @@ public class FileSourceDaoTest {
.setBinaryData("FILE2_BINARY_DATA".getBytes())
.setDataHash("FILE2_DATA_HASH")
.setSrcHash("FILE2_HASH")
.setDataType(Type.SOURCE)
.setCreatedAt(1500000000000L)
.setUpdatedAt(1500000000001L)
.setRevision("123456789"));
@@ -313,24 +288,6 @@ public class FileSourceDaoTest {
verifyLinesHashes(handler, file1, fileSource1);
}

@Test
public void scrollLineHashes_does_not_scroll_hashes_of_component_with_TEST_source() {
OrganizationDto organization = dbTester.organizations().insert();
ComponentDto project = new Random().nextBoolean() ? dbTester.components().insertPrivateProject(organization) : dbTester.components().insertPublicProject(organization);
ComponentDto file1 = dbTester.components().insertComponent(newFileDto(project));
FileSourceDto fileSource1 = dbTester.fileSources().insertFileSource(file1);
ComponentDto file2 = dbTester.components().insertComponent(newFileDto(project));
FileSourceDto fileSource2 = dbTester.fileSources().insertFileSource(file2, t -> t.setDataType(Type.TEST));
ComponentDto file3 = dbTester.components().insertComponent(newFileDto(project));
FileSourceDto fileSource3 = dbTester.fileSources().insertFileSource(file3, t -> t.setDataType(Type.SOURCE));
FileSourceDto testFileSource3 = dbTester.fileSources().insertFileSource(file3, t -> t.setDataType(Type.TEST));

LineHashesWithKeyDtoHandler handler = scrollLineHashes(file2.uuid(), file1.uuid(), file3.uuid());
assertThat(handler.dtos).hasSize(2);
verifyLinesHashes(handler, file1, fileSource1);
verifyLinesHashes(handler, file3, fileSource3);
}

@Test
public void scrollLineHashes_handles_scrolling_more_than_1000_files() {
OrganizationDto organization = dbTester.organizations().insert();
@@ -390,14 +347,13 @@ public class FileSourceDaoTest {
.setDataHash("NEW_DATA_HASH")
.setSrcHash("NEW_FILE_HASH")
.setLineHashes(singletonList("NEW_LINE_HASHES"))
.setDataType(Type.SOURCE)
.setUpdatedAt(1500000000002L)
.setLineHashesVersion(1)
.setRevision("987654321"));
dbSession.commit();

dbTester.assertDbUnitTable(getClass(), "update-result.xml", "file_sources", "project_uuid", "file_uuid",
"data_hash", "line_hashes", "src_hash", "created_at", "updated_at", "data_type", "revision", "line_hashes_version");
"data_hash", "line_hashes", "src_hash", "created_at", "updated_at", "revision", "line_hashes_version");
}

@Test
@@ -406,14 +362,13 @@ public class FileSourceDaoTest {
FileSourceDto fileSourceDto = new FileSourceDto()
.setProjectUuid("Foo")
.setFileUuid("Bar")
.setDataType(Type.SOURCE)
.setLineHashes(lineHashes)
.setCreatedAt(1500000000000L)
.setUpdatedAt(1500000000001L);
underTest.insert(dbSession, fileSourceDto);
dbSession.commit();

FileSourceDto resBefore = underTest.selectSourceByFileUuid(dbSession, fileSourceDto.getFileUuid());
FileSourceDto resBefore = underTest.selectByFileUuid(dbSession, fileSourceDto.getFileUuid());
assertThat(resBefore.getLineCount()).isEqualTo(lineHashes.size());
assertThat(resBefore.getLineHashes()).isEqualTo(lineHashes);

@@ -422,7 +377,7 @@ public class FileSourceDaoTest {
underTest.update(dbSession, fileSourceDto);
dbSession.commit();

FileSourceDto res = underTest.selectSourceByFileUuid(dbSession, fileSourceDto.getFileUuid());
FileSourceDto res = underTest.selectByFileUuid(dbSession, fileSourceDto.getFileUuid());
assertThat(res.getLineHashes()).isEmpty();
assertThat(res.getLineCount()).isEqualTo(1);
}

+ 1
- 18
server/sonar-db-dao/src/test/java/org/sonar/db/source/FileSourceDtoTest.java View File

@@ -20,7 +20,6 @@
package org.sonar.db.source;

import com.google.common.base.Joiner;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
@@ -43,22 +42,6 @@ public class FileSourceDtoTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();

@Test
public void encode_and_decode_test_data() {
List<DbFileSources.Test> tests = Arrays.asList(
DbFileSources.Test.newBuilder()
.setName("name#1")
.build(),
DbFileSources.Test.newBuilder()
.setName("name#2")
.build());

FileSourceDto underTest = new FileSourceDto().setTestData(tests);

assertThat(underTest.getTestData()).hasSize(2);
assertThat(underTest.getTestData().get(0).getName()).isEqualTo("name#1");
}

@Test
public void getSourceData_throws_ISE_with_id_fileUuid_and_projectUuid_in_message_when_data_cant_be_read() {
long id = 12L;
@@ -98,7 +81,7 @@ public class FileSourceDtoTest {
}

@Test
public void new_FileSourceDto_as_lineCount_0_and_rawLineHashes_to_null() {
public void new_FileSourceDto_as_lineCount_0_and_rawLineHashes_to_null() {
FileSourceDto underTest = new FileSourceDto();

assertThat(underTest.getLineCount()).isZero();

+ 0
- 96
server/sonar-server-common/src/main/java/org/sonar/server/source/index/FileSourcesUpdaterHelper.java View File

@@ -1,96 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.source.index;

import com.google.common.base.Joiner;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import org.elasticsearch.action.update.UpdateRequest;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;

public class FileSourcesUpdaterHelper {

private static final String SQL_ALL = "SELECT %s FROM file_sources WHERE data_type='%s' ";
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, DbSession session, String dataType, @Nullable String projectUuid)
throws SQLException {
String sql = createSQL(dataType, projectUuid);
// rows are big, so they are scrolled once at a time (one row in memory at a time)
PreparedStatement stmt = dbClient.getMyBatis().newScrollingSingleRowSelectStatement(session, sql);
if (projectUuid != null) {
stmt.setString(1, projectUuid);
}
return stmt;
}

private static String createSQL(String dataType, @Nullable String projectUuid) {
StringBuilder sql = new StringBuilder(String.format(SQL_ALL, FIELDS_ONE_LINE, dataType));
if (projectUuid != null) {
sql.append(PROJECT_FILTER);
}
return sql.toString();
}

public static class Row {
private final String fileUuid;
private final String 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;
}
}
}

+ 0
- 74
server/sonar-server-common/src/main/java/org/sonar/server/test/index/CoveredFileDoc.java View File

@@ -1,74 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.test.index;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import java.util.List;
import java.util.Map;
import org.sonar.server.es.BaseDoc;

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.newHashMapWithExpectedSize(2));
}

@Override
public String getId() {
throw new UnsupportedOperationException();
}

@Override
public String getRouting() {
throw new UnsupportedOperationException();
}

@Override
public String getParent() {
throw new UnsupportedOperationException();
}

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;
}

}

+ 0
- 162
server/sonar-server-common/src/main/java/org/sonar/server/test/index/TestDoc.java View File

@@ -1,162 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.test.index;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
import org.sonar.server.es.BaseDoc;

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) {
super(fields);
}

@VisibleForTesting
public TestDoc() {
super(Maps.newHashMapWithExpectedSize(10));
}

@Override
public String getId() {
return testUuid();
}

@Override
public String getRouting() {
return projectUuid();
}

@Override
public String getParent() {
return null;
}

public String projectUuid() {
return getField(FIELD_PROJECT_UUID);
}

public TestDoc setProjectUuid(String projectUuid) {
setField(FIELD_PROJECT_UUID, projectUuid);
return this;
}

public String fileUuid() {
return getField(FIELD_FILE_UUID);
}

public TestDoc setFileUuid(String fileUuid) {
setField(FIELD_FILE_UUID, fileUuid);
return this;
}

public String testUuid() {
return getField(FIELD_TEST_UUID);
}

public TestDoc setUuid(String testUuid) {
setField(FIELD_TEST_UUID, testUuid);
return this;
}

public String name() {
return getField(FIELD_NAME);
}

public TestDoc setName(String name) {
setField(FIELD_NAME, name);
return this;
}

public String status() {
return getField(FIELD_STATUS);
}

public TestDoc setStatus(String status) {
setField(FIELD_STATUS, status);
return this;
}

@CheckForNull
public String message() {
return getNullableField(FIELD_MESSAGE);
}

public TestDoc setMessage(String message) {
setField(FIELD_MESSAGE, message);
return this;
}

@CheckForNull
public String stackTrace() {
return getNullableField(FIELD_STACKTRACE);
}

public TestDoc setStackTrace(String stackTrace) {
setField(FIELD_STACKTRACE, stackTrace);
return this;
}

@CheckForNull
public Long durationInMs() {
Number number = getNullableField(FIELD_DURATION_IN_MS);
return number == null ? null : number.longValue();
}

public TestDoc setDurationInMs(Long durationInMs) {
setField(FIELD_DURATION_IN_MS, durationInMs);
return this;
}

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;
}
}

+ 0
- 116
server/sonar-server-common/src/main/java/org/sonar/server/test/index/TestIndex.java View File

@@ -1,116 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.test.index;

import com.google.common.base.Optional;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.search.SearchHit;
import org.sonar.api.utils.System2;
import org.sonar.server.es.EsClient;
import org.sonar.server.es.SearchOptions;
import org.sonar.server.es.SearchResult;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
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 {
private final EsClient client;
private final System2 system2;

public TestIndex(EsClient client, System2 system2) {
this.client = client;
this.system2 = system2;
}

public List<CoveredFileDoc> coveredFiles(String testUuid) {
List<CoveredFileDoc> coveredFiles = new ArrayList<>();

for (SearchHit hit : client.prepareSearch(TestIndexDefinition.INDEX_TYPE_TEST)
.setSize(1)
.setQuery(boolQuery().must(matchAllQuery()).filter(termQuery(FIELD_TEST_UUID, testUuid)))
.get().getHits().getHits()) {
coveredFiles.addAll(new TestDoc(hit.getSourceAsMap()).coveredFiles());
}

return coveredFiles;
}

public SearchResult<TestDoc> searchByTestFileUuid(String testFileUuid, SearchOptions searchOptions) {
SearchRequestBuilder searchRequest = client.prepareSearch(TestIndexDefinition.INDEX_TYPE_TEST)
.setSize(searchOptions.getLimit())
.setFrom(searchOptions.getOffset())
.setQuery(boolQuery().must(matchAllQuery()).filter(termQuery(FIELD_FILE_UUID, testFileUuid)));

return new SearchResult<>(searchRequest.get(), TestDoc::new, system2.getDefaultTimeZone());
}

public SearchResult<TestDoc> searchBySourceFileUuidAndLineNumber(String sourceFileUuid, int lineNumber, SearchOptions searchOptions) {
SearchRequestBuilder searchRequest = client.prepareSearch(TestIndexDefinition.INDEX_TYPE_TEST)
.setSize(searchOptions.getLimit())
.setFrom(searchOptions.getOffset())
.setQuery(nestedQuery(
FIELD_COVERED_FILES,
boolQuery()
.must(termQuery(FIELD_COVERED_FILES + "." + FIELD_COVERED_FILE_UUID, sourceFileUuid))
.must(termQuery(FIELD_COVERED_FILES + "." + FIELD_COVERED_FILE_LINES, lineNumber)),
ScoreMode.Avg));

return new SearchResult<>(searchRequest.get(), TestDoc::new, system2.getDefaultTimeZone());
}

public TestDoc getByTestUuid(String testUuid) {
Optional<TestDoc> testDoc = getNullableByTestUuid(testUuid);
if (testDoc.isPresent()) {
return testDoc.get();
}

throw new IllegalStateException(String.format("Test id '%s' not found", testUuid));
}

public Optional<TestDoc> getNullableByTestUuid(String testUuid) {
SearchHit[] hits = client.prepareSearch(TestIndexDefinition.INDEX_TYPE_TEST)
.setSize(1)
.setQuery(boolQuery().must(matchAllQuery()).filter(termQuery(FIELD_TEST_UUID, testUuid)))
.get().getHits().getHits();
if (hits.length > 0) {
return Optional.of(new TestDoc(hits[0].getSourceAsMap()));
}
return Optional.absent();
}

public SearchResult<TestDoc> searchByTestUuid(String testUuid, SearchOptions searchOptions) {
SearchRequestBuilder searchRequest = client.prepareSearch(TestIndexDefinition.INDEX_TYPE_TEST)
.setSize(searchOptions.getLimit())
.setFrom(searchOptions.getOffset())
.setQuery(boolQuery().must(matchAllQuery()).filter(termQuery(FIELD_TEST_UUID, testUuid)));

return new SearchResult<>(searchRequest.get(), TestDoc::new, system2.getDefaultTimeZone());
}
}

+ 0
- 151
server/sonar-server-common/src/main/java/org/sonar/server/test/index/TestIndexer.java View File

@@ -1,151 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.test.index;

import com.google.common.collect.ImmutableSet;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.es.EsQueueDto;
import org.sonar.server.es.BulkIndexer;
import org.sonar.server.es.BulkIndexer.Size;
import org.sonar.server.es.EsClient;
import org.sonar.server.es.IndexType;
import org.sonar.server.es.IndexingListener;
import org.sonar.server.es.IndexingResult;
import org.sonar.server.es.OneToManyResilientIndexingListener;
import org.sonar.server.es.ProjectIndexer;
import org.sonar.server.source.index.FileSourcesUpdaterHelper;

import static java.util.Collections.emptyList;
import static org.sonar.server.test.index.TestIndexDefinition.FIELD_FILE_UUID;
import static org.sonar.server.test.index.TestIndexDefinition.INDEX_TYPE_TEST;

/**
* Add to Elasticsearch index {@link TestIndexDefinition} the rows of
* db table FILE_SOURCES of type TEST that are not indexed yet
* <p>
* This indexer is not resilient by itself since it's called by Compute Engine
*/
public class TestIndexer implements ProjectIndexer {

private final DbClient dbClient;
private final EsClient esClient;

public TestIndexer(DbClient dbClient, EsClient esClient) {
this.dbClient = dbClient;
this.esClient = esClient;
}

@Override
public Set<IndexType> getIndexTypes() {
return ImmutableSet.of(INDEX_TYPE_TEST);
}

@Override
public void indexOnStartup(Set<IndexType> uninitializedIndexTypes) {
try (DbSession dbSession = dbClient.openSession(false);
TestResultSetIterator rowIt = TestResultSetIterator.create(dbClient, dbSession, null)) {

BulkIndexer bulkIndexer = new BulkIndexer(esClient, INDEX_TYPE_TEST, Size.LARGE);
bulkIndexer.start();
addTestsToBulkIndexer(rowIt, bulkIndexer);
bulkIndexer.stop();
}
}

@Override
public void indexOnAnalysis(String branchUuid) {
BulkIndexer bulkIndexer = new BulkIndexer(esClient, INDEX_TYPE_TEST, Size.REGULAR);
bulkIndexer.start();
addProjectDeletionToBulkIndexer(bulkIndexer, branchUuid);
try (DbSession dbSession = dbClient.openSession(false);
TestResultSetIterator rowIt = TestResultSetIterator.create(dbClient, dbSession, branchUuid)) {
addTestsToBulkIndexer(rowIt, bulkIndexer);
}
bulkIndexer.stop();
}

@Override
public Collection<EsQueueDto> prepareForRecovery(DbSession dbSession, Collection<String> projectUuids, Cause cause) {
switch (cause) {
case PROJECT_CREATION:
// no tests at that time
case MEASURE_CHANGE:
case PROJECT_KEY_UPDATE:
case PROJECT_TAGS_UPDATE:
case PERMISSION_CHANGE:
// Measures, project key, tags and permissions are not part of tests/test
return emptyList();

case PROJECT_DELETION:
List<EsQueueDto> items = projectUuids.stream()
.map(projectUuid -> EsQueueDto.create(INDEX_TYPE_TEST.format(), projectUuid, null, projectUuid))
.collect(MoreCollectors.toArrayList(projectUuids.size()));
return dbClient.esQueueDao().insert(dbSession, items);

default:
// defensive case
throw new IllegalStateException("Unsupported cause: " + cause);
}
}

public void deleteByFile(String fileUuid) {
SearchRequestBuilder searchRequest = esClient.prepareSearch(INDEX_TYPE_TEST)
.setQuery(QueryBuilders.termQuery(FIELD_FILE_UUID, fileUuid));
BulkIndexer.delete(esClient, INDEX_TYPE_TEST, searchRequest);
}

@Override
public IndexingResult index(DbSession dbSession, Collection<EsQueueDto> items) {
// The items are to be deleted
if (items.isEmpty()) {
return new IndexingResult();
}

IndexingListener listener = new OneToManyResilientIndexingListener(dbClient, dbSession, items);
BulkIndexer bulkIndexer = new BulkIndexer(esClient, INDEX_TYPE_TEST, Size.REGULAR, listener);
bulkIndexer.start();
items.forEach(i -> {
String projectUuid = i.getDocId();
addProjectDeletionToBulkIndexer(bulkIndexer, projectUuid);
});

return bulkIndexer.stop();
}

private void addProjectDeletionToBulkIndexer(BulkIndexer bulkIndexer, String projectUuid) {
SearchRequestBuilder searchRequest = esClient.prepareSearch(INDEX_TYPE_TEST)
.setQuery(QueryBuilders.termQuery(TestIndexDefinition.FIELD_PROJECT_UUID, projectUuid));
bulkIndexer.addDeletion(searchRequest);
}

private static void addTestsToBulkIndexer(TestResultSetIterator rowIt, BulkIndexer bulkIndexer) {
while (rowIt.hasNext()) {
FileSourcesUpdaterHelper.Row row = rowIt.next();
row.getUpdateRequests().forEach(bulkIndexer::add);
}
}
}

+ 0
- 144
server/sonar-server-common/src/main/java/org/sonar/server/test/index/TestResultSetIterator.java View File

@@ -1,144 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.test.index;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import javax.annotation.Nullable;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.sonar.api.utils.log.Loggers;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.ResultSetIterator;
import org.sonar.db.protobuf.DbFileSources;
import org.sonar.db.source.FileSourceDto;
import org.sonar.server.es.EsUtils;
import org.sonar.server.source.index.FileSourcesUpdaterHelper.Row;

import static org.sonar.server.source.index.FileSourcesUpdaterHelper.preparedStatementToSelectFileSources;
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.FIELD_UPDATED_AT;
import static org.sonar.server.test.index.TestIndexDefinition.INDEX_TYPE_TEST;

/**
* Scroll over table FILE_SOURCES of test type and directly parse data required to
* populate the index tests/test
*/
public class TestResultSetIterator extends ResultSetIterator<Row> {

private TestResultSetIterator(PreparedStatement stmt) throws SQLException {
super(stmt);
}

public static TestResultSetIterator create(DbClient dbClient, DbSession session, @Nullable String projectUuid) {
try {
return new TestResultSetIterator(preparedStatementToSelectFileSources(dbClient, session, FileSourceDto.Type.TEST, projectUuid));
} catch (SQLException e) {
throw new IllegalStateException("Fail to prepare SQL request to select all tests", e);
}
}

@Override
protected Row read(ResultSet rs) throws SQLException {
String projectUuid = rs.getString(1);
String fileUuid = rs.getString(2);
Date updatedAt = new Date(rs.getLong(3));
List<DbFileSources.Test> tests = parseData(fileUuid, rs.getBinaryStream(4));
return toRow(projectUuid, fileUuid, updatedAt, tests);
}

private static List<DbFileSources.Test> parseData(String fileUuid, @Nullable InputStream dataInput) {
List<DbFileSources.Test> tests = Collections.emptyList();
if (dataInput != null) {
try {
tests = FileSourceDto.decodeTestData(dataInput);
} catch (Exception e) {
Loggers.get(TestResultSetIterator.class).warn(String.format("Invalid file_sources.binary_data on row with file_uuid='%s', test file will be ignored", fileUuid), e);
}
}
return tests;
}

/**
* Convert protobuf message to tests required for Elasticsearch indexing
*/
public static Row toRow(String projectUuid, String fileUuid, Date updatedAt, List<DbFileSources.Test> tests) {
Row result = new Row(projectUuid, fileUuid, updatedAt.getTime());
for (DbFileSources.Test test : tests) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();

// all the fields must be present, even if value is null
try (JsonWriter writer = JsonWriter.of(new OutputStreamWriter(bytes, StandardCharsets.UTF_8)).setSerializeNulls(true)) {
writer.beginObject();
writer.prop(FIELD_PROJECT_UUID, projectUuid);
writer.prop(FIELD_FILE_UUID, fileUuid);
writer.prop(FIELD_TEST_UUID, test.getUuid());
writer.prop(FIELD_NAME, test.getName());
writer.prop(FIELD_STATUS, test.hasStatus() ? test.getStatus().toString() : null);
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.prop(FIELD_UPDATED_AT, EsUtils.formatDateTime(updatedAt));
writer.name(FIELD_COVERED_FILES);
writer.beginArray();
for (DbFileSources.Test.CoveredFile coveredFile : test.getCoveredFileList()) {
writer.beginObject();
writer.prop(FIELD_COVERED_FILE_UUID, coveredFile.getFileUuid());
writer.name(FIELD_COVERED_FILE_LINES).valueObject(coveredFile.getCoveredLineList());
writer.endObject();
}
writer.endArray();
writer.endObject();
}
// This is an optimization to reduce memory consumption and multiple conversions from Map to JSON.
// UpdateRequest#doc() and #upsert() take the same parameter values, so:
// - passing the same Map would execute two JSON serializations
// - Map is a useless temporarily structure: read JDBC result set -> convert to map -> convert to JSON. Generating
// directly JSON from result set is more efficient.
byte[] jsonDoc = bytes.toByteArray();
UpdateRequest updateRequest = new UpdateRequest(INDEX_TYPE_TEST.getIndex(), INDEX_TYPE_TEST.getType(), test.getUuid())
.routing(projectUuid)
.doc(jsonDoc, XContentType.JSON)
.upsert(jsonDoc, XContentType.JSON);
result.getUpdateRequests().add(updateRequest);
}
return result;
}
}

+ 0
- 41
server/sonar-server-common/src/test/java/org/sonar/server/source/index/FileSourceTesting.java View File

@@ -19,15 +19,8 @@
*/
package org.sonar.server.source.index;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.sonar.db.protobuf.DbFileSources;
import org.sonar.db.source.FileSourceDto;

public class FileSourceTesting {

@@ -35,18 +28,6 @@ public class FileSourceTesting {
// only static stuff
}

public static void updateDataColumn(Connection connection, String fileUuid, DbFileSources.Data data) throws SQLException {
updateDataColumn(connection, fileUuid, FileSourceDto.encodeSourceData(data));
}

public static void updateDataColumn(Connection connection, String fileUuid, byte[] data) throws SQLException {
PreparedStatement stmt = connection.prepareStatement("UPDATE file_sources SET binary_data = ? WHERE file_uuid=? AND data_type='" + FileSourceDto.Type.SOURCE + "'");
stmt.setBytes(1, data);
stmt.setString(2, fileUuid);
stmt.executeUpdate();
stmt.close();
}

/**
* Generate predefined fake data. Result is mutable.
*/
@@ -71,26 +52,4 @@ public class FileSourceTesting {
return dataBuilder;
}

/**
* Generate random data. Result is mutable.
*/
public static DbFileSources.Data.Builder newRandomData(int numberOfLines) {
DbFileSources.Data.Builder dataBuilder = DbFileSources.Data.newBuilder();
for (int i = 1; i <= numberOfLines; i++) {
dataBuilder.addLinesBuilder()
.setLine(i)
.setScmRevision(RandomStringUtils.randomAlphanumeric(15))
.setScmAuthor(RandomStringUtils.randomAlphanumeric(10))
.setScmDate(RandomUtils.nextLong())
.setSource(RandomStringUtils.randomAlphanumeric(20))
.setLineHits(RandomUtils.nextInt(4))
.setConditions(RandomUtils.nextInt(4))
.setCoveredConditions(RandomUtils.nextInt(4))
.setHighlighting(RandomStringUtils.randomAlphanumeric(40))
.setSymbols(RandomStringUtils.randomAlphanumeric(30))
.addAllDuplication(Arrays.asList(RandomUtils.nextInt(200), RandomUtils.nextInt(200)))
.build();
}
return dataBuilder;
}
}

+ 0
- 96
server/sonar-server-common/src/test/java/org/sonar/server/test/db/TestTesting.java View File

@@ -1,96 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.test.db;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.sonar.core.util.Uuids;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.protobuf.DbFileSources;
import org.sonar.db.source.FileSourceDto;

import static java.util.Arrays.asList;

public class TestTesting {

private TestTesting() {
// only static stuff
}

public static void updateDataColumn(DbSession session, String fileUuid, List<DbFileSources.Test> tests) throws SQLException {
updateDataColumn(session, fileUuid, FileSourceDto.encodeTestData(tests));
}

public static void updateDataColumn(DbSession session, String fileUuid, byte[] data) throws SQLException {
Connection connection = session.getConnection();
PreparedStatement stmt = connection.prepareStatement("UPDATE file_sources SET binary_data = ? WHERE file_uuid=? AND data_type='TEST'");
stmt.setBytes(1, data);
stmt.setString(2, fileUuid);
stmt.executeUpdate();
stmt.close();
connection.commit();
}

/**
* Generate random data.
*/
public static List<DbFileSources.Test> newRandomTests(int numberOfTests) {
List<DbFileSources.Test> tests = new ArrayList<>();
for (int i = 1; i <= numberOfTests; i++) {
DbFileSources.Test.Builder test = DbFileSources.Test.newBuilder()
.setUuid(Uuids.create())
.setName(RandomStringUtils.randomAlphanumeric(20))
.setStatus(DbFileSources.Test.TestStatus.FAILURE)
.setStacktrace(RandomStringUtils.randomAlphanumeric(50))
.setMsg(RandomStringUtils.randomAlphanumeric(30))
.setExecutionTimeMs(RandomUtils.nextLong());
for (int j = 0; j < numberOfTests; j++) {
test.addCoveredFile(
DbFileSources.Test.CoveredFile.newBuilder()
.setFileUuid(Uuids.create())
.addCoveredLine(RandomUtils.nextInt(500)));
}
tests.add(test.build());
}
return tests;
}

public static DbFileSources.Test.Builder newTest(ComponentDto mainFile, Integer... coveredLines) {
DbFileSources.Test.Builder test = DbFileSources.Test.newBuilder()
.setUuid(Uuids.create())
.setName(RandomStringUtils.randomAlphanumeric(20))
.setStatus(DbFileSources.Test.TestStatus.FAILURE)
.setStacktrace(RandomStringUtils.randomAlphanumeric(50))
.setMsg(RandomStringUtils.randomAlphanumeric(30))
.setExecutionTimeMs(RandomUtils.nextLong());
test.addCoveredFile(
DbFileSources.Test.CoveredFile.newBuilder()
.setFileUuid(mainFile.uuid())
.addAllCoveredLine(asList(coveredLines)));
return test;
}
}

+ 0
- 161
server/sonar-server-common/src/test/java/org/sonar/server/test/index/TestIndexTest.java View File

@@ -1,161 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.test.index;

import com.google.common.base.Optional;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
import org.sonar.server.es.EsTester;
import org.sonar.server.es.SearchOptions;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.guava.api.Assertions.assertThat;
import static org.sonar.server.test.index.TestIndexDefinition.INDEX_TYPE_TEST;

public class TestIndexTest {
@Rule
public EsTester es = EsTester.create();

private TestIndex underTest = new TestIndex(es.client(), System2.INSTANCE);

@Test
public void coveredFiles() {
es.putDocuments(INDEX_TYPE_TEST,
newTestDoc("1", "TESTFILE1", newCoveredFileDoc("3"), newCoveredFileDoc("4"), newCoveredFileDoc("5")),
newTestDoc("2", "TESTFILE1", newCoveredFileDoc("5"), newCoveredFileDoc("6"), newCoveredFileDoc("7")));

List<CoveredFileDoc> result = underTest.coveredFiles("1");

assertThat(result).hasSize(3);
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 searchByTestFileUuid() {
es.putDocuments(INDEX_TYPE_TEST,
newTestDoc("1", "TESTFILE1", newCoveredFileDoc("3"), newCoveredFileDoc("4"), newCoveredFileDoc("5")),
newTestDoc("2", "TESTFILE1", newCoveredFileDoc("5"), newCoveredFileDoc("6"), newCoveredFileDoc("7")),
newTestDoc("3", "TESTFILE2", newCoveredFileDoc("5"), newCoveredFileDoc("6"), newCoveredFileDoc("7")));

List<TestDoc> result = underTest.searchByTestFileUuid("TESTFILE1", searchOptions()).getDocs();

assertThat(result).hasSize(2);
assertThat(result).extractingResultOf("name").containsOnly("name-1", "name-2");
}

@Test
public void searchBySourceFileUuidAndLineNumber() {
es.putDocuments(INDEX_TYPE_TEST,
newTestDoc("1", "TESTFILE1", newCoveredFileDoc("10"), newCoveredFileDoc("11"), newCoveredFileDoc("12")),
newTestDoc("2", "TESTFILE1", newCoveredFileDoc("3"), newCoveredFileDoc("4"), newCoveredFileDoc("5")),
newTestDoc("3", "TESTFILE1", newCoveredFileDoc("5"), newCoveredFileDoc("6"), newCoveredFileDoc("7")));

List<TestDoc> result = underTest.searchBySourceFileUuidAndLineNumber("main-uuid-5", 82, searchOptions()).getDocs();

assertThat(result).hasSize(2);
assertThat(result).extractingResultOf("name").containsOnly("name-2", "name-3");
}

@Test
public void searchByTestUuid() {
es.putDocuments(INDEX_TYPE_TEST,
newTestDoc("1", "TESTFILE1", newCoveredFileDoc("3"), newCoveredFileDoc("4"), newCoveredFileDoc("5")),
newTestDoc("2", "TESTFILE1", newCoveredFileDoc("5"), newCoveredFileDoc("6"), newCoveredFileDoc("7")));

TestDoc test = underTest.getByTestUuid("1");

assertThat(test.testUuid()).isEqualTo("1");
assertThat(test.fileUuid()).isEqualTo("TESTFILE1");
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");
}

@Test
public void getNullableByTestUuid() {
es.putDocuments(INDEX_TYPE_TEST,
newTestDoc("1", "TESTFILE1", newCoveredFileDoc("3"), newCoveredFileDoc("4"), newCoveredFileDoc("5")),
newTestDoc("2", "TESTFILE1", newCoveredFileDoc("5"), newCoveredFileDoc("6"), newCoveredFileDoc("7")));

Optional<TestDoc> result = underTest.getNullableByTestUuid("1");

assertThat(result).isPresent();
TestDoc test = result.get();
assertThat(test.testUuid()).isEqualTo("1");
assertThat(test.fileUuid()).isEqualTo("TESTFILE1");
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");
}

@Test
public void getNullableByTestUuid_with_absent_value() {
Optional<TestDoc> result = underTest.getNullableByTestUuid("unknown-uuid");

assertThat(result).isAbsent();
}

@Test
public void searchByTestUuid_with_SearchOptions() {
es.putDocuments(INDEX_TYPE_TEST,
newTestDoc("1", "TESTFILE1", newCoveredFileDoc("3"), newCoveredFileDoc("4"), newCoveredFileDoc("5")),
newTestDoc("2", "TESTFILE1", newCoveredFileDoc("5"), newCoveredFileDoc("6"), newCoveredFileDoc("7")));

List<TestDoc> result = underTest.searchByTestUuid("1", searchOptions()).getDocs();

assertThat(result).hasSize(1);
assertThat(result.get(0).testUuid()).isEqualTo("1");
}

private CoveredFileDoc newCoveredFileDoc(String id) {
return new CoveredFileDoc()
.setFileUuid("main-uuid-" + id)
.setCoveredLines(asList(25, 33, 82));
}

private TestDoc newTestDoc(String testUuid, String fileUuid, CoveredFileDoc... coveredFiles) {
return new TestDoc()
.setUuid(testUuid)
.setProjectUuid("P1")
.setName("name-" + testUuid)
.setMessage("message-" + testUuid)
.setStackTrace("stacktrace-" + testUuid)
.setStatus("status-" + testUuid)
.setDurationInMs(Long.valueOf(testUuid))
.setFileUuid(fileUuid)
.setCoveredFiles(asList(coveredFiles));
}

private SearchOptions searchOptions() {
return new SearchOptions()
.setLimit(100)
.setOffset(0);
}
}

+ 0
- 168
server/sonar-server-common/src/test/java/org/sonar/server/test/index/TestIndexerTest.java View File

@@ -1,168 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.test.index;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.search.SearchHit;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.server.es.EsTester;
import org.sonar.server.test.db.TestTesting;

import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.sonar.server.es.DefaultIndexSettings.REFRESH_IMMEDIATE;
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_STACKTRACE;
import static org.sonar.server.test.index.TestIndexDefinition.INDEX_TYPE_TEST;

public class TestIndexerTest {

private System2 system2 = System2.INSTANCE;

@Rule
public EsTester es = EsTester.create();

@Rule
public DbTester db = DbTester.create(system2);

private TestIndexer underTest = new TestIndexer(db.getDbClient(), es.client());

@Test
public void index_on_startup() {
TestIndexer indexer = spy(underTest);
doNothing().when(indexer).indexOnStartup(null);
indexer.indexOnStartup(null);
verify(indexer).indexOnStartup(null);
}

@Test
public void index_tests() throws Exception {
db.prepareDbUnit(getClass(), "db.xml");
TestTesting.updateDataColumn(db.getSession(), "FILE_UUID", TestTesting.newRandomTests(3));

underTest.indexOnStartup(null);

assertThat(countDocuments()).isEqualTo(3);
}

@Test
public void index_tests_from_project() throws Exception {
db.prepareDbUnit(getClass(), "db.xml");

TestTesting.updateDataColumn(db.getSession(), "FILE_UUID", TestTesting.newRandomTests(3));

underTest.indexOnAnalysis("PROJECT_UUID");
assertThat(countDocuments()).isEqualTo(3);
}

@Test
public void index_nothing_from_unknown_project() throws Exception {
db.prepareDbUnit(getClass(), "db.xml");

TestTesting.updateDataColumn(db.getSession(), "FILE_UUID", TestTesting.newRandomTests(3));

underTest.indexOnAnalysis("UNKNOWN");
assertThat(countDocuments()).isZero();
}

@Test
public void delete_file_by_uuid() throws Exception {
indexTest("P1", "F1", "T1", "U111");
indexTest("P1", "F1", "T2", "U112");
indexTest("P1", "F2", "T1", "U121");

underTest.deleteByFile("F1");

List<SearchHit> hits = getDocuments();
Map<String, Object> document = hits.get(0).getSource();
assertThat(hits).hasSize(1);
assertThat(document.get(FIELD_NAME)).isEqualTo("NAME_1");
assertThat(document.get(FIELD_FILE_UUID)).isEqualTo("F2");
}

@Test
public void long_message_can_be_indexed() throws Exception {
indexTest("P3", "F1", "long_message", "U111");

assertThat(countDocuments()).isEqualTo(1);

List<SearchHit> hits = getDocuments();
Map<String, Object> document = hits.get(0).getSource();
assertThat(hits).hasSize(1);
assertThat(document.get(FIELD_MESSAGE).toString()).hasSize(50000);
assertThat(document.get(FIELD_FILE_UUID)).isEqualTo("F1");
}

@Test
public void long_stacktrace_can_be_indexed() throws Exception {
indexTest("P3", "F1", "long_stacktrace", "U111");

assertThat(countDocuments()).isEqualTo(1);

List<SearchHit> hits = getDocuments();
Map<String, Object> document = hits.get(0).getSource();
assertThat(hits).hasSize(1);
assertThat(document.get(FIELD_STACKTRACE).toString()).hasSize(50000);
assertThat(document.get(FIELD_FILE_UUID)).isEqualTo("F1");
}

@Test
public void long_name_can_be_indexed() throws Exception {
indexTest("P3", "F1", "long_name", "U111");

assertThat(countDocuments()).isEqualTo(1);

List<SearchHit> hits = getDocuments();
Map<String, Object> document = hits.get(0).getSource();
assertThat(hits).hasSize(1);
assertThat(document.get(FIELD_NAME).toString()).hasSize(50000);
assertThat(document.get(FIELD_FILE_UUID)).isEqualTo("F1");
}

private void indexTest(String projectUuid, String fileUuid, String testName, String uuid) throws IOException {
String json = IOUtils.toString(getClass().getResource(format("%s/%s_%s_%s.json", getClass().getSimpleName(), projectUuid, fileUuid, testName)));
es.client().prepareIndex(INDEX_TYPE_TEST)
.setId(uuid)
.setRouting(projectUuid)
.setSource(json, XContentType.JSON)
.setRefreshPolicy(REFRESH_IMMEDIATE)
.get();
}

private List<SearchHit> getDocuments() {
return es.getDocuments(INDEX_TYPE_TEST);
}

private long countDocuments() {
return es.countDocuments(INDEX_TYPE_TEST);
}
}

+ 0
- 192
server/sonar-server-common/src/test/java/org/sonar/server/test/index/TestResultSetIteratorTest.java View File

@@ -1,192 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.test.index;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.elasticsearch.action.update.UpdateRequest;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.db.DbTester;
import org.sonar.db.protobuf.DbFileSources;
import org.sonar.server.source.index.FileSourcesUpdaterHelper;
import org.sonar.server.test.db.TestTesting;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.data.MapEntry.entry;
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 TestResultSetIteratorTest {

@Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);

@Rule
public LogTester logTester = new LogTester();

TestResultSetIterator underTest;

private static List<DbFileSources.Test> newFakeTests(int numberOfTests) {
List<DbFileSources.Test> tests = new ArrayList<>();
for (int i = 1; i <= numberOfTests; i++) {
DbFileSources.Test.Builder test = DbFileSources.Test.newBuilder()
.setUuid("TEST_FILE_UUID_" + i)
.setName("NAME_" + i)
.setStatus(DbFileSources.Test.TestStatus.FAILURE)
.setStacktrace("STACKTRACE_" + i)
.setMsg("MESSAGE_" + i)
.setExecutionTimeMs(i);
for (int j = 1; j <= numberOfTests; j++) {
test.addCoveredFile(
DbFileSources.Test.CoveredFile.newBuilder()
.setFileUuid("MAIN_FILE_UUID_" + j)
.addCoveredLine(j));
}
tests.add(test.build());
}
return tests;
}

@After
public void after() {
if (underTest != null) {
underTest.close();
}
}

@Test
public void traverse_db() throws Exception {
dbTester.prepareDbUnit(getClass(), "shared.xml");
TestTesting.updateDataColumn(dbTester.getSession(), "F1", newFakeTests(3));
underTest = TestResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), null);

FileSourcesUpdaterHelper.Row row = underTest.next();
assertThat(row.getProjectUuid()).isEqualTo("P1");
assertThat(row.getFileUuid()).isEqualTo("F1");
assertThat(row.getUpdatedAt()).isEqualTo(1416239042000L);
assertThat(row.getUpdateRequests()).hasSize(3);

UpdateRequest firstRequest = row.getUpdateRequests().get(0);
Map<String, Object> doc = firstRequest.doc().sourceAsMap();
assertThat(doc).contains(
entry(FIELD_PROJECT_UUID, "P1"),
entry(FIELD_FILE_UUID, "F1"),
entry(FIELD_TEST_UUID, "TEST_FILE_UUID_1"),
entry(FIELD_STATUS, "FAILURE"),
entry(FIELD_MESSAGE, "MESSAGE_1"),
entry(FIELD_DURATION_IN_MS, 1),
entry(FIELD_STACKTRACE, "STACKTRACE_1"),
entry(FIELD_NAME, "NAME_1"));
}

/**
* File with one line. No metadata available on the line.
*/
@Test
public void minimal_data() throws Exception {
dbTester.prepareDbUnit(getClass(), "shared.xml");
List<DbFileSources.Test> tests = Arrays.asList(
DbFileSources.Test.newBuilder()
.setUuid("U1")
.setName("N1")
.build());
TestTesting.updateDataColumn(dbTester.getSession(), "F1", tests);
underTest = TestResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), null);

FileSourcesUpdaterHelper.Row row = underTest.next();

assertThat(row.getProjectUuid()).isEqualTo("P1");
assertThat(row.getFileUuid()).isEqualTo("F1");
assertThat(row.getUpdatedAt()).isEqualTo(1416239042000L);
assertThat(row.getUpdateRequests()).hasSize(1);
UpdateRequest firstRequest = row.getUpdateRequests().get(0);
Map<String, Object> doc = firstRequest.doc().sourceAsMap();
assertThat(doc).contains(
entry(FIELD_PROJECT_UUID, "P1"),
entry(FIELD_FILE_UUID, "F1"),
entry(FIELD_TEST_UUID, "U1"),
entry(FIELD_NAME, "N1"));
// null values
assertThat(doc).containsKeys(
FIELD_DURATION_IN_MS,
FIELD_STACKTRACE,
FIELD_MESSAGE,
FIELD_STATUS,
FIELD_COVERED_FILES);
}

@Test
public void filter_by_project() throws Exception {
dbTester.prepareDbUnit(getClass(), "filter_by_project.xml");
TestTesting.updateDataColumn(dbTester.getSession(), "F1", newFakeTests(1));

underTest = TestResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), "P1");

FileSourcesUpdaterHelper.Row row = underTest.next();
assertThat(row.getProjectUuid()).isEqualTo("P1");
assertThat(row.getFileUuid()).isEqualTo("F1");

// File from other project P2 is not returned
assertThat(underTest.hasNext()).isFalse();
}

@Test
public void read_does_not_fail_if_corrupted_data() throws Exception {
dbTester.prepareDbUnit(getClass(), "shared.xml");

TestTesting.updateDataColumn(dbTester.getSession(), "F1", "THIS_IS_NOT_PROTOBUF".getBytes());

underTest = TestResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), null);
FileSourcesUpdaterHelper.Row row = underTest.next();
assertThat(row.getFileUuid()).isEqualTo("F1");
assertThat(row.getUpdateRequests()).isEmpty();
assertThat(underTest.hasNext()).isFalse();

assertThat(logTester.logs(LoggerLevel.WARN)).contains("Invalid file_sources.binary_data on row with file_uuid='F1', test file will be ignored");
}

@Test
public void read_does_not_fail_if_null_data() throws Exception {
dbTester.prepareDbUnit(getClass(), "shared.xml");
TestTesting.updateDataColumn(dbTester.getSession(), "F1", (byte[])null);

underTest = TestResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), null);

FileSourcesUpdaterHelper.Row row = underTest.next();
assertThat(row.getFileUuid()).isEqualTo("F1");
assertThat(row.getUpdateRequests()).isEmpty();
assertThat(underTest.hasNext()).isFalse();
}
}

+ 0
- 11
server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P1_F1_T1.json View File

@@ -1,11 +0,0 @@
{
"projectUuid": "P1",
"fileUuid": "F1",
"testUuid": "U111",
"name": "NAME_1",
"status": "FAILURE",
"durationInMs": 100000,
"message": "MESSAGE_1",
"stacktrace": "STACKTRACE_1",
"updatedAt": "2014-01-01T23:45:01.8+01:00"
}

+ 0
- 11
server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P1_F1_T2.json View File

@@ -1,11 +0,0 @@
{
"projectUuid": "P1",
"fileUuid": "F1",
"testUuid": "U112",
"name": "NAME_2",
"status": "FAILURE",
"durationInMs": 100000,
"message": "MESSAGE_1",
"stacktrace": "STACKTRACE_1",
"updatedAt": "2014-01-01T23:45:01.8+01:00"
}

+ 0
- 11
server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P1_F2_T1.json View File

@@ -1,11 +0,0 @@
{
"projectUuid": "P1",
"fileUuid": "F2",
"testUuid": "U121",
"name": "NAME_1",
"status": "FAILURE",
"durationInMs": 100000,
"message": "MESSAGE_1",
"stacktrace": "STACKTRACE_1",
"updatedAt": "2014-01-01T23:45:01.8+01:00"
}

+ 0
- 11
server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P2_F3_T1.json View File

@@ -1,11 +0,0 @@
{
"projectUuid": "P2",
"fileUuid": "F3",
"testUuid": "U231",
"name": "NAME_1",
"status": "FAILURE",
"durationInMs": 100000,
"message": "MESSAGE_1",
"stacktrace": "STACKTRACE_1",
"updatedAt": "2014-01-01T23:45:01.8+01:00"
}

+ 0
- 11
server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P3_F1_long_message.json
File diff suppressed because it is too large
View File


+ 0
- 11
server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P3_F1_long_name.json
File diff suppressed because it is too large
View File


+ 0
- 11
server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/P3_F1_long_stacktrace.json
File diff suppressed because it is too large
View File


+ 0
- 14
server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestIndexerTest/db.xml View File

@@ -1,14 +0,0 @@
<dataset>

<file_sources id="1"
project_uuid="PROJECT_UUID"
file_uuid="FILE_UUID"
line_count="0"
created_at="1416238020000"
updated_at="1416239042000"
binary_data=""
data_hash=""
data_type="TEST"
/>

</dataset>

+ 0
- 23
server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestResultSetIteratorTest/filter_by_project.xml View File

@@ -1,23 +0,0 @@
<dataset>

<file_sources id="1"
project_uuid="P1"
file_uuid="F1"
created_at="1416238020000"
updated_at="1416239042000"
line_count="0"
binary_data=""
data_hash=""
data_type="TEST"/>

<file_sources id="2"
project_uuid="P2"
file_uuid="F2"
created_at="1416238020000"
updated_at="1416239042000"
line_count="0"
binary_data=""
data_hash=""
data_type="TEST"/>

</dataset>

+ 0
- 23
server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestResultSetIteratorTest/filter_by_project_and_date.xml View File

@@ -1,23 +0,0 @@
<dataset>

<file_sources id="1"
project_uuid="P1"
file_uuid="F1"
created_at="1416238020000"
updated_at="1416239042000"
line_count="0"
binary_data=""
data_hash=""
data_type="TEST"/>

<file_sources id="2"
project_uuid="P1"
file_uuid="F2"
created_at="1416238020000"
updated_at="1300000000000"
line_count="0"
binary_data=""
data_hash=""
data_type="TEST"/>

</dataset>

+ 0
- 11
server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestResultSetIteratorTest/schema.sql View File

@@ -1,11 +0,0 @@

CREATE TABLE "FILE_SOURCES" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"PROJECT_UUID" VARCHAR(50) NOT NULL,
"FILE_UUID" VARCHAR(50) NOT NULL,
"BINARY_DATA" BINARY(167772150),
"DATA_HASH" VARCHAR(50) NOT NULL,
"DATA_TYPE" VARCHAR(50),
"CREATED_AT" BIGINT NOT NULL,
"UPDATED_AT" BIGINT NOT NULL
);

+ 0
- 13
server/sonar-server-common/src/test/resources/org/sonar/server/test/index/TestResultSetIteratorTest/shared.xml View File

@@ -1,13 +0,0 @@
<dataset>

<file_sources id="1"
project_uuid="P1"
file_uuid="F1"
created_at="1416238020000"
updated_at="1416239042000"
line_count="0"
binary_data=""
data_hash=""
data_type="TEST"/>

</dataset>

+ 0
- 7
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java View File

@@ -199,10 +199,7 @@ import org.sonar.server.startup.LogServerId;
import org.sonar.server.telemetry.TelemetryClient;
import org.sonar.server.telemetry.TelemetryDaemon;
import org.sonar.server.telemetry.TelemetryDataLoader;
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.CoveredFilesAction;
import org.sonar.server.test.ws.TestsWs;
import org.sonar.server.text.MacroInterpreter;
import org.sonar.server.ui.DeprecatedViews;
@@ -479,11 +476,7 @@ public class PlatformLevel4 extends PlatformLevel {

// Tests
TestsWs.class,
CoveredFilesAction.class,
org.sonar.server.test.ws.ListAction.class,
TestIndexDefinition.class,
TestIndex.class,
TestIndexer.class,

// Settings
PersistentSettings.class,

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java View File

@@ -65,7 +65,7 @@ public class SourceService {
private <E> Optional<Iterable<E>> getLines(DbSession dbSession, String fileUuid, int from, int toInclusive, Function<DbFileSources.Line, E> function) {
verifyLine(from);
checkArgument(toInclusive >= from, String.format("Line number must greater than or equal to %d, got %d", from, toInclusive));
FileSourceDto dto = dbClient.fileSourceDao().selectSourceByFileUuid(dbSession, fileUuid);
FileSourceDto dto = dbClient.fileSourceDao().selectByFileUuid(dbSession, fileUuid);
if (dto == null) {
return Optional.empty();
}

+ 0
- 124
server/sonar-server/src/main/java/org/sonar/server/test/ws/CoveredFilesAction.java View File

@@ -1,124 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.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 java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import org.sonar.api.server.ws.Change;
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.web.UserRole;
import org.sonar.core.util.Uuids;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
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 org.sonarqube.ws.Tests;

import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
import static org.sonar.server.ws.WsUtils.writeProtobuf;

public class CoveredFilesAction implements TestsWsAction {

public static final String TEST_ID = "testId";

private final DbClient dbClient;
private final TestIndex index;
private final UserSession userSession;

public CoveredFilesAction(DbClient dbClient, TestIndex index, UserSession userSession) {
this.dbClient = dbClient;
this.index = index;
this.userSession = userSession;
}

@Override
public void define(WebService.NewController controller) {
WebService.NewAction action = controller.createAction("covered_files")
.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-covered-files.json"))
.setDeprecatedSince("5.6")
.setHandler(this)
.setChangelog(new Change("6.6", "\"branch\" field is now returned"))
.addPagingParams(100);

action
.createParam(TEST_ID)
.setRequired(true)
.setDescription("Test ID")
.setExampleValue(Uuids.UUID_EXAMPLE_01);
}

@Override
public void handle(Request request, Response response) throws Exception {
String testId = request.mandatoryParam(TEST_ID);
TestDoc testDoc = checkFoundWithOptional(index.getNullableByTestUuid(testId), "Test with id '%s' is not found", testId);
userSession.checkComponentUuidPermission(UserRole.CODEVIEWER, testDoc.fileUuid());

List<CoveredFileDoc> coveredFiles = index.coveredFiles(testId);
Map<String, ComponentDto> componentsByUuid = buildComponentsByUuid(coveredFiles);

Tests.CoveredFilesResponse.Builder responseBuilder = Tests.CoveredFilesResponse.newBuilder();
if (!coveredFiles.isEmpty()) {
for (CoveredFileDoc doc : coveredFiles) {
Tests.CoveredFilesResponse.CoveredFile.Builder fileBuilder = Tests.CoveredFilesResponse.CoveredFile.newBuilder();
fileBuilder.setId(doc.fileUuid());
fileBuilder.setCoveredLines(doc.coveredLines().size());
ComponentDto component = componentsByUuid.get(doc.fileUuid());
if (component != null) {
fileBuilder.setKey(component.getKey());
fileBuilder.setLongName(component.longName());
setNullable(component.getBranch(), fileBuilder::setBranch);
}

responseBuilder.addFiles(fileBuilder);
}
}
writeProtobuf(responseBuilder.build(), request, response);
}

private Map<String, ComponentDto> buildComponentsByUuid(List<CoveredFileDoc> coveredFiles) {
List<String> sourceFileUuids = Lists.transform(coveredFiles, new CoveredFileToFileUuidFunction());
List<ComponentDto> components;
try (DbSession dbSession = dbClient.openSession(false)) {
components = dbClient.componentDao().selectByUuids(dbSession, sourceFileUuids);
}
return Maps.uniqueIndex(components, ComponentDto::uuid);
}

private static class CoveredFileToFileUuidFunction implements Function<CoveredFileDoc, String> {
@Override
public String apply(@Nonnull CoveredFileDoc coveredFile) {
return coveredFile.fileUuid();
}
}

}

+ 0
- 266
server/sonar-server/src/main/java/org/sonar/server/test/ws/ListAction.java View File

@@ -1,266 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.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 java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.core.util.Uuids;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.server.component.ComponentFinder;
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 org.sonar.server.ws.KeyExamples;
import org.sonar.server.ws.WsUtils;
import org.sonarqube.ws.Common;
import org.sonarqube.ws.Tests;

import static org.sonar.api.server.ws.WebService.Param.PAGE;
import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
import static org.sonar.api.web.UserRole.CODEVIEWER;
import static org.sonar.core.util.Protobuf.setNullable;
import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
import static org.sonar.server.ws.KeyExamples.KEY_BRANCH_EXAMPLE_001;
import static org.sonar.server.ws.KeyExamples.KEY_PULL_REQUEST_EXAMPLE_001;
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;

public class ListAction implements TestsWsAction {
public static final String TEST_ID = "testId";
public static final String TEST_FILE_ID = "testFileId";
public static final String TEST_FILE_KEY = "testFileKey";
public static final String SOURCE_FILE_ID = "sourceFileId";
public static final String SOURCE_FILE_KEY = "sourceFileKey";
public static final String SOURCE_FILE_LINE_NUMBER = "sourceFileLineNumber";
public static final String PARAM_BRANCH = "branch";
public static final String PARAM_PULL_REQUEST = "pullRequest";

private final DbClient dbClient;
private final TestIndex testIndex;
private final UserSession userSession;
private final ComponentFinder componentFinder;

public ListAction(DbClient dbClient, TestIndex testIndex, UserSession userSession, ComponentFinder componentFinder) {
this.dbClient = dbClient;
this.testIndex = testIndex;
this.userSession = userSession;
this.componentFinder = componentFinder;
}

@Override
public void define(WebService.NewController controller) {
WebService.NewAction action = controller
.createAction("list")
.setDescription(String.format(
"Get the list of tests either in a test file or that test a given line of source code.<br /> " +
"Requires 'Browse' permission on the file's project.<br /> " +
"One (and only one) of the following combination of parameters must be provided: " +
"<ul>" +
"<li>%s - get a specific test</li>" +
"<li>%s - get the tests in a test file</li>" +
"<li>%s - get the tests in a test file</li>" +
"<li>%s and %6$s - get the tests that cover a specific line of code</li>" +
"<li>%s and %6$s - get the tests that cover a specific line of code</li>" +
"</ul>",
TEST_ID, TEST_FILE_ID, TEST_FILE_KEY, SOURCE_FILE_ID, SOURCE_FILE_KEY, SOURCE_FILE_LINE_NUMBER))
.setSince("5.2")
.setResponseExample(Resources.getResource(getClass(), "tests-example-list.json"))
.setDeprecatedSince("5.6")
.setHandler(this)
.setChangelog(new Change("6.6", "\"fileBranch\" field is now returned"))
.setChangelog(new Change("7.1", "\"filePullRequest\" field is now returned"))
.addPagingParams(100, MAX_LIMIT);

action
.createParam(TEST_FILE_ID)
.setDescription("ID of test file")
.setExampleValue(Uuids.UUID_EXAMPLE_01);

action
.createParam(TEST_FILE_KEY)
.setDescription("Key of test file")
.setExampleValue("MY_PROJECT:src/test/java/foo/BarTest.java");

action
.createParam(TEST_ID)
.setDescription("ID of test")
.setExampleValue(Uuids.UUID_EXAMPLE_02);

action
.createParam(SOURCE_FILE_ID)
.setDescription("ID of source file. Must be provided with the source file line number.")
.setExampleValue(Uuids.UUID_EXAMPLE_03);

action
.createParam(SOURCE_FILE_KEY)
.setSince("5.4")
.setDescription("Key of source file. Must be provided with the source file line number.")
.setExampleValue(KeyExamples.KEY_FILE_EXAMPLE_001);

action
.createParam(SOURCE_FILE_LINE_NUMBER)
.setDescription("Source file line number. Must be provided with the source file ID or key.")
.setExampleValue("10");

action.createParam(PARAM_BRANCH)
.setDescription("Branch key")
.setSince("6.6")
.setInternal(true)
.setExampleValue(KEY_BRANCH_EXAMPLE_001);

action.createParam(PARAM_PULL_REQUEST)
.setDescription("Pull request id")
.setSince("7.1")
.setInternal(true)
.setExampleValue(KEY_PULL_REQUEST_EXAMPLE_001);
}

@Override
public void handle(Request request, Response response) throws Exception {
String testUuid = request.param(TEST_ID);
String testFileUuid = request.param(TEST_FILE_ID);
String testFileKey = request.param(TEST_FILE_KEY);
String sourceFileUuid = request.param(SOURCE_FILE_ID);
String sourceFileKey = request.param(SOURCE_FILE_KEY);
String branch = request.param(PARAM_BRANCH);
String pullRequest = request.param(PARAM_PULL_REQUEST);
Integer sourceFileLineNumber = request.paramAsInt(SOURCE_FILE_LINE_NUMBER);
SearchOptions searchOptions = new SearchOptions().setPage(
request.mandatoryParamAsInt(PAGE),
request.mandatoryParamAsInt(PAGE_SIZE));

SearchResult<TestDoc> tests;
Map<String, ComponentDto> componentsByTestFileUuid;
try (DbSession dbSession = dbClient.openSession(false)) {
tests = searchTests(dbSession, testUuid, testFileUuid, testFileKey, sourceFileUuid, sourceFileKey, branch, pullRequest, sourceFileLineNumber, searchOptions);
componentsByTestFileUuid = buildComponentsByTestFileUuid(dbSession, tests.getDocs());
}

Tests.ListResponse.Builder responseBuilder = Tests.ListResponse.newBuilder();
responseBuilder.setPaging(Common.Paging.newBuilder()
.setPageIndex(searchOptions.getPage())
.setPageSize(searchOptions.getLimit())
.setTotal((int) tests.getTotal())
.build());

for (TestDoc testDoc : tests.getDocs()) {
Tests.Test.Builder testBuilder = Tests.Test.newBuilder();
testBuilder.setId(testDoc.testUuid());
testBuilder.setName(StringUtils.defaultString(testDoc.name()));
testBuilder.setFileId(testDoc.fileUuid());
ComponentDto component = componentsByTestFileUuid.get(testDoc.fileUuid());
if (component != null) {
testBuilder.setFileKey(component.getKey());
testBuilder.setFileName(component.longName());
setNullable(component.getBranch(), testBuilder::setFileBranch);
setNullable(component.getPullRequest(), testBuilder::setFilePullRequest);
}
testBuilder.setStatus(Tests.TestStatus.valueOf(testDoc.status()));
if (testDoc.durationInMs() != null) {
testBuilder.setDurationInMs(testDoc.durationInMs());
}
testBuilder.setCoveredLines(coveredLines(testDoc.coveredFiles()));
if (testDoc.message() != null) {
testBuilder.setMessage(testDoc.message());
}
if (testDoc.stackTrace() != null) {
testBuilder.setStacktrace(testDoc.stackTrace());
}
responseBuilder.addTests(testBuilder.build());
}
WsUtils.writeProtobuf(responseBuilder.build(), request, response);
}

private static int coveredLines(List<CoveredFileDoc> coveredFiles) {
int numberOfLinesCovered = 0;
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 TestToFileUuidFunction());
List<ComponentDto> components = dbClient.componentDao().selectByUuids(dbSession, fileUuids);

return Maps.uniqueIndex(components, ComponentDto::uuid);
}

private SearchResult<TestDoc> searchTests(DbSession dbSession, @Nullable String testUuid, @Nullable String testFileUuid, @Nullable String testFileKey,
@Nullable String sourceFileUuid, @Nullable String sourceFileKey, @Nullable String branch, @Nullable String pullRequest,
@Nullable Integer sourceFileLineNumber, SearchOptions searchOptions) {
if (testUuid != null) {
TestDoc testDoc = checkFoundWithOptional(testIndex.getNullableByTestUuid(testUuid), "Test with id '%s' is not found", testUuid);
checkComponentUuidPermission(dbSession, testDoc.fileUuid());
return testIndex.searchByTestUuid(testUuid, searchOptions);
}
if (testFileUuid != null) {
checkComponentUuidPermission(dbSession, testFileUuid);
return testIndex.searchByTestFileUuid(testFileUuid, searchOptions);
}
if (testFileKey != null) {
ComponentDto testFile = componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, testFileKey, branch, pullRequest);
userSession.checkComponentPermission(CODEVIEWER, testFile);
return testIndex.searchByTestFileUuid(testFile.uuid(), searchOptions);
}
if (sourceFileUuid != null && sourceFileLineNumber != null) {
ComponentDto sourceFile = componentFinder.getByUuid(dbSession, sourceFileUuid);
userSession.checkComponentPermission(CODEVIEWER, sourceFile);
return testIndex.searchBySourceFileUuidAndLineNumber(sourceFile.uuid(), sourceFileLineNumber, searchOptions);
}
if (sourceFileKey != null && sourceFileLineNumber != null) {
ComponentDto sourceFile = componentFinder.getByKeyAndOptionalBranchOrPullRequest(dbSession, sourceFileKey, branch, pullRequest);
userSession.checkComponentPermission(CODEVIEWER, sourceFile);
return testIndex.searchBySourceFileUuidAndLineNumber(sourceFile.uuid(), 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 ID or key with a source file line number.");
}

private void checkComponentUuidPermission(DbSession dbSession, String componentUuid) {
ComponentDto component = componentFinder.getByUuid(dbSession, componentUuid);
userSession.checkComponentPermission(CODEVIEWER, component);
}

private static class TestToFileUuidFunction implements Function<TestDoc, String> {
@Override
public String apply(@Nonnull TestDoc testDoc) {
return testDoc.fileUuid();
}
}
}

+ 19
- 10
server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsWs.java View File

@@ -19,25 +19,34 @@
*/
package org.sonar.server.test.ws;

import org.sonar.api.server.ws.Change;
import org.sonar.api.server.ws.WebService;
import org.sonar.server.ws.RemovedWebServiceHandler;

public class TestsWs implements WebService {

private final TestsWsAction[] actions;

public TestsWs(TestsWsAction... actions) {
this.actions = actions;
}

@Override
public void define(Context context) {
NewController controller = context.createController("api/tests")
.setSince("4.4")
.setDescription("Get details on test files. See also api/sources. Deprecated since 5.6.");
.setDescription("Removed in 7.6");

for (TestsWsAction action : actions) {
action.define(controller);
}
controller.createAction("covered_files")
.setDescription("This web API is no longer supported")
.setSince("4.4")
.setDeprecatedSince("5.6")
.setChangelog(new Change("7.6", "This action has been removed"))
.setResponseExample(RemovedWebServiceHandler.INSTANCE.getResponseExample())
.setHandler(RemovedWebServiceHandler.INSTANCE);

controller
.createAction("list")
.setDescription("This web API is no longer supported")
.setSince("5.2")
.setDeprecatedSince("5.6")
.setChangelog(new Change("7.6", "This action has been removed"))
.setResponseExample(RemovedWebServiceHandler.INSTANCE.getResponseExample())
.setHandler(RemovedWebServiceHandler.INSTANCE);

controller.done();
}

+ 0
- 26
server/sonar-server/src/main/java/org/sonar/server/test/ws/TestsWsAction.java View File

@@ -1,26 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.test.ws;

import org.sonar.server.ws.WsAction;

public interface TestsWsAction extends WsAction {
// marker interface
}

+ 0
- 14
server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-covered-files.json View File

@@ -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
}
]
}

+ 0
- 31
server/sonar-server/src/main/resources/org/sonar/server/test/ws/tests-example-list.json View File

@@ -1,31 +0,0 @@
{
"paging": {
"pageIndex": 1,
"pageSize": 10,
"total": 2
},
"tests": [
{
"id": "AU-TpxcB-iU5OvuD2FL7",
"name": "find_by_params",
"status": "OK",
"fileId": "AU-TpxcB-iU5OvuD2Fd8",
"fileKey": "org.codehaus.sonar:sonar-server:src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java",
"fileName": "src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java",
"durationInMs": 10,
"coveredLines": 89
},
{
"id": "AU-TpxcB-iU5OvuD2FP9",
"name": "find_rules_by_characteristics",
"status": "ERROR",
"fileId": "AU-TpxcB-iU5OvuD2FR2",
"fileKey": "org.codehaus.sonar:sonar-server:src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java",
"fileName": "src/test/java/org/sonar/server/rule/RubyRuleServiceTest.java",
"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"
}
]
}

+ 0
- 1
server/sonar-server/src/test/java/org/sonar/server/batch/ProjectDataLoaderTest.java View File

@@ -268,7 +268,6 @@ public class ProjectDataLoaderTest {
.setLineHashes(of("8d7b3d6b83c0a517eac07e1aac94b773"))
.setCreatedAt(System.currentTimeMillis())
.setUpdatedAt(System.currentTimeMillis())
.setDataType(FileSourceDto.Type.SOURCE)
.setRevision("123456789")
.setSrcHash("123456");
}

+ 0
- 16
server/sonar-server/src/test/java/org/sonar/server/source/ws/HashActionTest.java View File

@@ -26,7 +26,6 @@ import org.sonar.api.utils.System2;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.protobuf.DbFileSources;
import org.sonar.db.source.FileSourceDto;
import org.sonar.server.component.TestComponentFinder;
import org.sonar.server.exceptions.ForbiddenException;
@@ -38,7 +37,6 @@ import org.sonar.server.ws.WsActionTester;
import static java.lang.String.format;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.resources.Qualifiers.UNIT_TEST_FILE;
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.db.component.ComponentTesting.newFileDto;

@@ -66,20 +64,6 @@ public class HashActionTest {
assertThat(request.execute().getInput()).isEqualTo("ABC");
}

@Test
public void show_hashes_on_test_file() {
OrganizationDto organizationDto = db.organizations().insert();
ComponentDto project = db.components().insertPrivateProject(organizationDto);
ComponentDto test = db.components().insertComponent(newFileDto(project).setQualifier(UNIT_TEST_FILE));
FileSourceDto fileSource = db.fileSources().insertFileSource(test, f -> f.setLineHashes(singletonList("ABC")));
FileSourceDto fileTest = db.fileSources().insertFileSource(test, f -> f.setTestData(singletonList(DbFileSources.Test.newBuilder().build())));
loginAsProjectViewer(project);

TestRequest request = tester.newRequest().setParam("key", test.getKey());

assertThat(request.execute().getInput()).isEqualTo("ABC");
}

@Test
public void hashes_empty_if_no_source() {
OrganizationDto organizationDto = db.organizations().insert();

+ 0
- 159
server/sonar-server/src/test/java/org/sonar/server/test/ws/CoveredFilesActionTest.java View File

@@ -1,159 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.test.ws;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.core.util.Uuids;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.protobuf.DbFileSources;
import org.sonar.db.protobuf.DbFileSources.Test.CoveredFile;
import org.sonar.db.source.FileSourceDto;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.test.index.TestIndex;
import org.sonar.server.test.index.TestIndexer;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;

import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.sonar.api.resources.Qualifiers.UNIT_TEST_FILE;
import static org.sonar.api.web.UserRole.CODEVIEWER;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.server.test.ws.CoveredFilesAction.TEST_ID;
import static org.sonar.test.JsonAssert.assertJson;

public class CoveredFilesActionTest {

@Rule
public UserSessionRule userSession = UserSessionRule.standalone();
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public EsTester es = EsTester.create();
@Rule
public DbTester db = DbTester.create();

private TestIndex testIndex = new TestIndex(es.client(), System2.INSTANCE);
private TestIndexer testIndexer = new TestIndexer(db.getDbClient(), es.client());

private WsActionTester ws = new WsActionTester(new CoveredFilesAction(db.getDbClient(), testIndex, userSession));

@Test
public void define_covered_files() {
WebService.Action action = ws.getDef();
assertThat(action).isNotNull();
assertThat(action.isInternal()).isFalse();
assertThat(action.isPost()).isFalse();
assertThat(action.handler()).isNotNull();
assertThat(action.responseExampleAsString()).isNotEmpty();
assertThat(action.params()).hasSize(3);
}

@Test
public void covered_files() {
ComponentDto project = db.components().insertPrivateProject();
ComponentDto mainFile1 = db.components().insertComponent(newFileDto(project));
ComponentDto mainFile2 = db.components().insertComponent(newFileDto(project));
ComponentDto testFile = db.components().insertComponent(newFileDto(project).setQualifier(UNIT_TEST_FILE));
userSession.addProjectPermission(CODEVIEWER, project, testFile);

DbFileSources.Test test = DbFileSources.Test.newBuilder().setUuid(Uuids.create())
.addCoveredFile(CoveredFile.newBuilder()
.setFileUuid(mainFile1.uuid())
.addAllCoveredLine(asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)))
.addCoveredFile(CoveredFile.newBuilder()
.setFileUuid(mainFile2.uuid())
.addAllCoveredLine(asList(1, 2, 3)))
.build();
insertTests(testFile, test);

TestRequest request = ws.newRequest().setParam(TEST_ID, test.getUuid());

assertJson(request.execute().getInput()).isSimilarTo("{\n" +
" \"files\": [\n" +
" {\n" +
" \"id\": \"" + mainFile1.uuid() + "\",\n" +
" \"key\": \"" + mainFile1.getKey() + "\",\n" +
" \"longName\": \"" + mainFile1.longName() + "\",\n" +
" \"coveredLines\": 10\n" +
" },\n" +
" {\n" +
" \"id\": \"" + mainFile2.uuid() + "\",\n" +
" \"key\": \"" + mainFile2.getKey() + "\",\n" +
" \"longName\": \"" + mainFile2.longName() + "\",\n" +
" \"coveredLines\": 3\n" +
" }\n" +
" ]\n" +
"}");
}

@Test
public void covered_files_on_branch() {
ComponentDto project = db.components().insertMainBranch();
ComponentDto branch = db.components().insertProjectBranch(project);
ComponentDto mainFile = db.components().insertComponent(newFileDto(branch));
ComponentDto testFile = db.components().insertComponent(newFileDto(branch).setQualifier(UNIT_TEST_FILE));
userSession.addProjectPermission(CODEVIEWER, project, testFile);
DbFileSources.Test test = DbFileSources.Test.newBuilder().setUuid(Uuids.create())
.addCoveredFile(CoveredFile.newBuilder()
.setFileUuid(mainFile.uuid())
.addAllCoveredLine(asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)))
.build();
insertTests(testFile, test);

TestRequest request = ws.newRequest().setParam(TEST_ID, test.getUuid());

assertJson(request.execute().getInput()).isSimilarTo("{\n" +
" \"files\": [\n" +
" {\n" +
" \"id\": \"" + mainFile.uuid() + "\",\n" +
" \"key\": \"" + mainFile.getKey() + "\",\n" +
" \"branch\": \"" + mainFile.getBranch() + "\",\n" +
" \"longName\": \"" + mainFile.longName() + "\",\n" +
" \"coveredLines\": 10\n" +
" }\n" +
" ]\n" +
"}");
}

@Test
public void fail_when_test_uuid_is_unknown() {
expectedException.expect(NotFoundException.class);
expectedException.expectMessage("Test with id 'unknown' is not found");

ws.newRequest().setParam(TEST_ID, "unknown").execute();
}

private void insertTests(ComponentDto testFile, DbFileSources.Test... tests) {
db.getDbClient().fileSourceDao().insert(db.getSession(), new FileSourceDto()
.setProjectUuid(testFile.projectUuid())
.setFileUuid(testFile.uuid())
.setTestData(asList(tests)));
db.commit();
testIndexer.indexOnStartup(null);
}
}

+ 0
- 434
server/sonar-server/src/test/java/org/sonar/server/test/ws/ListActionTest.java View File

@@ -1,434 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.test.ws;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.System2;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.component.ComponentTesting;
import org.sonar.db.protobuf.DbFileSources;
import org.sonar.db.source.FileSourceDto;
import org.sonar.server.component.TestComponentFinder;
import org.sonar.server.es.EsTester;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.test.index.TestIndex;
import org.sonar.server.test.index.TestIndexer;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
import org.sonarqube.ws.Tests;
import org.sonarqube.ws.Tests.ListResponse;

import static java.lang.String.format;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
import static org.sonar.api.resources.Qualifiers.UNIT_TEST_FILE;
import static org.sonar.api.web.UserRole.CODEVIEWER;
import static org.sonar.api.web.UserRole.USER;
import static org.sonar.db.component.BranchType.PULL_REQUEST;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.protobuf.DbFileSources.Test.TestStatus.OK;
import static org.sonar.server.test.db.TestTesting.newTest;
import static org.sonar.server.test.ws.ListAction.PARAM_PULL_REQUEST;
import static org.sonar.server.test.ws.ListAction.SOURCE_FILE_ID;
import static org.sonar.server.test.ws.ListAction.SOURCE_FILE_KEY;
import static org.sonar.server.test.ws.ListAction.SOURCE_FILE_LINE_NUMBER;
import static org.sonar.server.test.ws.ListAction.TEST_FILE_ID;
import static org.sonar.server.test.ws.ListAction.TEST_FILE_KEY;
import static org.sonar.server.test.ws.ListAction.TEST_ID;

public class ListActionTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
public EsTester es = EsTester.create();
@Rule
public UserSessionRule userSessionRule = UserSessionRule.standalone();
@Rule
public DbTester db = DbTester.create();

private DbClient dbClient = db.getDbClient();

private TestIndex testIndex = new TestIndex(es.client(), System2.INSTANCE);
private TestIndexer testIndexer = new TestIndexer(db.getDbClient(), es.client());

private ComponentDto project;
private ComponentDto mainFile;
private ComponentDto testFile;

private WsActionTester ws = new WsActionTester(new ListAction(dbClient, testIndex, userSessionRule, TestComponentFinder.from(db)));

@Before
public void setUp() throws Exception {
project = db.components().insertComponent(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()));
mainFile = db.components().insertComponent(newFileDto(project));
testFile = db.components().insertComponent(newFileDto(project).setQualifier(UNIT_TEST_FILE));
}

@Test
public void test_definition() {
WebService.Action action = ws.getDef();
assertThat(action).isNotNull();
assertThat(action.isInternal()).isFalse();
assertThat(action.isPost()).isFalse();
assertThat(action.handler()).isNotNull();
assertThat(action.responseExampleAsString()).isNotEmpty();
assertThat(action.params()).hasSize(10);
assertThat(action.description()).isEqualTo("Get the list of tests either in a test file or that test a given line of source code.<br /> " +
"Requires 'Browse' permission on the file's project.<br /> " +
"One (and only one) of the following combination of parameters must be provided: " +
"<ul>" +
"<li>testId - get a specific test</li>" +
"<li>testFileId - get the tests in a test file</li>" +
"<li>testFileKey - get the tests in a test file</li>" +
"<li>sourceFileId and sourceFileLineNumber - get the tests that cover a specific line of code</li>" +
"<li>sourceFileKey and sourceFileLineNumber - get the tests that cover a specific line of code</li>" +
"</ul>");
}

@Test
public void list_tests() {
userSessionRule.addProjectPermission(CODEVIEWER, project);
DbFileSources.Test test = newTest(mainFile, 10, 11, 12, 20, 21, 25).setStatus(OK).build();
insertTests(testFile, test);

ListResponse request = call(ws.newRequest().setParam(TEST_ID, test.getUuid()));

assertThat(request.getTestsList()).hasSize(1);
Tests.Test result = request.getTests(0);
assertThat(result.getId()).isEqualTo(test.getUuid());
assertThat(result.getName()).isEqualTo(test.getName());
assertThat(result.getStatus()).isEqualTo(Tests.TestStatus.OK);
assertThat(result.getFileId()).isEqualTo(testFile.uuid());
assertThat(result.getFileKey()).isEqualTo(testFile.getDbKey());
assertThat(result.getFileName()).isEqualTo(testFile.path());
assertThat(result.getDurationInMs()).isEqualTo(test.getExecutionTimeMs());
assertThat(result.getMessage()).isEqualTo(test.getMsg());
assertThat(result.getStacktrace()).isEqualTo(test.getStacktrace());
assertThat(result.getCoveredLines()).isEqualTo(6);
}

@Test
public void list_tests_by_test_uuid() {
userSessionRule.addProjectPermission(CODEVIEWER, project);
DbFileSources.Test test1 = newTest(mainFile, 10).build();
DbFileSources.Test test2 = newTest(mainFile, 11).build();
insertTests(testFile, test1, test2);

ListResponse request = call(ws.newRequest()
.setParam(TEST_ID, test1.getUuid()));

assertThat(request.getTestsList())
.extracting(Tests.Test::getId)
.containsOnly(test1.getUuid());
}

@Test
public void list_tests_by_test_file_uuid() {
userSessionRule.addProjectPermission(CODEVIEWER, project);
ComponentDto anotherTestFile = db.components().insertComponent(newFileDto(project));
DbFileSources.Test test1 = newTest(mainFile, 10).build();
DbFileSources.Test test2 = newTest(mainFile, 11).build();
DbFileSources.Test test3 = newTest(mainFile, 12).build();
insertTests(testFile, test1, test2);
insertTests(anotherTestFile, test3);

ListResponse request = call(ws.newRequest()
.setParam(TEST_FILE_ID, testFile.uuid()));

assertThat(request.getTestsList())
.extracting(Tests.Test::getId)
.containsOnly(test1.getUuid(), test2.getUuid());
}

@Test
public void list_tests_by_test_file_key() {
userSessionRule.addProjectPermission(CODEVIEWER, project);
ComponentDto anotherTestFile = db.components().insertComponent(newFileDto(project));
DbFileSources.Test test1 = newTest(mainFile, 10).build();
DbFileSources.Test test2 = newTest(mainFile, 11).build();
DbFileSources.Test test3 = newTest(mainFile, 12).build();
insertTests(testFile, test1, test2);
insertTests(anotherTestFile, test3);

ListResponse request = call(ws.newRequest()
.setParam(TEST_FILE_KEY, testFile.getDbKey()));

assertThat(request.getTestsList())
.extracting(Tests.Test::getId)
.containsOnly(test1.getUuid(), test2.getUuid());
}

@Test
public void list_tests_by_test_file_key_and_branch() {
ComponentDto project = db.components().insertMainBranch();
userSessionRule.addProjectPermission(CODEVIEWER, project);
ComponentDto branch = db.components().insertProjectBranch(project);
ComponentDto mainFile = db.components().insertComponent(newFileDto(branch));
ComponentDto testFile = db.components().insertComponent(newFileDto(branch).setQualifier(UNIT_TEST_FILE));

DbFileSources.Test test1 = newTest(mainFile, 10).build();
DbFileSources.Test test2 = newTest(mainFile, 11).build();
insertTests(testFile, test1, test2);

ListResponse request = call(ws.newRequest()
.setParam(TEST_FILE_KEY, testFile.getKey())
.setParam("branch", testFile.getBranch()));

assertThat(request.getTestsList())
.extracting(Tests.Test::getId, Tests.Test::getFileKey, Tests.Test::getFileBranch)
.containsOnly(
tuple(test1.getUuid(), testFile.getKey(), testFile.getBranch()),
tuple(test2.getUuid(), testFile.getKey(), testFile.getBranch()));
}

@Test
public void list_tests_by_test_file_key_and_pull_request() {
ComponentDto project = db.components().insertMainBranch();
userSessionRule.addProjectPermission(CODEVIEWER, project);
ComponentDto pullRequest = db.components().insertProjectBranch(project, b -> b.setBranchType(PULL_REQUEST));
ComponentDto mainFile = db.components().insertComponent(newFileDto(pullRequest));
ComponentDto testFile = db.components().insertComponent(newFileDto(pullRequest).setQualifier(UNIT_TEST_FILE));

DbFileSources.Test test1 = newTest(mainFile, 10).build();
DbFileSources.Test test2 = newTest(mainFile, 11).build();
insertTests(testFile, test1, test2);

ListResponse request = call(ws.newRequest()
.setParam(TEST_FILE_KEY, testFile.getKey())
.setParam(PARAM_PULL_REQUEST, testFile.getPullRequest()));

assertThat(request.getTestsList())
.extracting(Tests.Test::getId, Tests.Test::getFileKey, Tests.Test::getFilePullRequest)
.containsOnly(
tuple(test1.getUuid(), testFile.getKey(), testFile.getPullRequest()),
tuple(test2.getUuid(), testFile.getKey(), testFile.getPullRequest()));
}

@Test
public void list_tests_by_source_file_uuid_and_line_number() {
userSessionRule.addProjectPermission(CODEVIEWER, project);
ComponentDto anotherMainFile = db.components().insertComponent(newFileDto(project));
DbFileSources.Test test1 = newTest(mainFile, 10, 11, 12).build();
DbFileSources.Test test2 = newTest(mainFile, 9, 11).build();
DbFileSources.Test test3 = newTest(mainFile, 10, 12).build();
DbFileSources.Test test4 = newTest(anotherMainFile, 11).build();
insertTests(testFile, test1, test2, test3, test4);

ListResponse request = call(ws.newRequest()
.setParam(SOURCE_FILE_ID, mainFile.uuid())
.setParam(SOURCE_FILE_LINE_NUMBER, "11"));

assertThat(request.getTestsList()).extracting(Tests.Test::getId).containsOnly(test1.getUuid(), test2.getUuid());
}

@Test
public void list_tests_by_source_file_key_and_line_number() {
userSessionRule.addProjectPermission(CODEVIEWER, project);
ComponentDto anotherMainFile = db.components().insertComponent(newFileDto(project));
DbFileSources.Test test1 = newTest(mainFile, 10, 11, 12).build();
DbFileSources.Test test2 = newTest(mainFile, 9, 11).build();
DbFileSources.Test test3 = newTest(mainFile, 10, 12).build();
DbFileSources.Test test4 = newTest(anotherMainFile, 11).build();
insertTests(testFile, test1, test2, test3, test4);

ListResponse request = call(ws.newRequest()
.setParam(SOURCE_FILE_KEY, mainFile.getDbKey())
.setParam(SOURCE_FILE_LINE_NUMBER, "10"));

assertThat(request.getTestsList())
.extracting(Tests.Test::getId)
.containsOnly(test1.getUuid(), test3.getUuid());
}

@Test
public void list_tests_by_source_file_key_and_branch_and_line_number() {
ComponentDto project = db.components().insertMainBranch();
userSessionRule.addProjectPermission(CODEVIEWER, project);
ComponentDto branch = db.components().insertProjectBranch(project);
ComponentDto mainFile = db.components().insertComponent(newFileDto(branch));
ComponentDto testFile = db.components().insertComponent(newFileDto(branch).setQualifier(UNIT_TEST_FILE));
DbFileSources.Test test1 = newTest(mainFile, 10, 11, 12).build();
DbFileSources.Test test2 = newTest(mainFile, 9, 11).build();
DbFileSources.Test test3 = newTest(mainFile, 10, 12).build();
insertTests(testFile, test1, test2, test3);

ListResponse request = call(ws.newRequest()
.setParam(SOURCE_FILE_KEY, mainFile.getKey())
.setParam(SOURCE_FILE_LINE_NUMBER, "10")
.setParam("branch", testFile.getBranch()));

assertThat(request.getTestsList())
.extracting(Tests.Test::getId, Tests.Test::getFileKey, Tests.Test::getFileBranch)
.containsOnly(
tuple(test1.getUuid(), testFile.getKey(), testFile.getBranch()),
tuple(test3.getUuid(), testFile.getKey(), testFile.getBranch()));
}

@Test
public void tests_are_paginated() {
userSessionRule.addProjectPermission(CODEVIEWER, project);
insertTests(testFile, newTest(mainFile, 10).build(), newTest(mainFile, 11).build(), newTest(mainFile, 12).build());

ListResponse request = call(ws.newRequest().setParam(TEST_FILE_ID, testFile.uuid()));

assertThat(request.getPaging().getPageIndex()).isEqualTo(1);
assertThat(request.getPaging().getPageSize()).isEqualTo(100);
assertThat(request.getPaging().getTotal()).isEqualTo(3);
}

@Test
public void fail_when_no_argument() {
userSessionRule.addProjectPermission(CODEVIEWER, project);

expectedException.expect(IllegalArgumentException.class);
call(ws.newRequest());
}

@Test
public void fail_when_source_file_uuid_without_line_number() {
userSessionRule.addProjectPermission(CODEVIEWER, project);

expectedException.expect(IllegalArgumentException.class);
call(ws.newRequest().setParam(SOURCE_FILE_ID, mainFile.uuid()));
}

@Test
public void fail_when_not_enough_privilege_on_test_uuid() {
userSessionRule.addProjectPermission(USER, project);
DbFileSources.Test test = newTest(mainFile, 10).build();
insertTests(testFile, test);

expectedException.expect(ForbiddenException.class);
call(ws.newRequest().setParam(TEST_ID, test.getUuid()));
}

@Test
public void fail_when_no_enough_privilege_on_test_file_id() {
userSessionRule.addProjectPermission(USER, project);
insertTests(testFile, newTest(mainFile, 10).build());

expectedException.expect(ForbiddenException.class);
call(ws.newRequest().setParam(TEST_FILE_ID, testFile.uuid()));
}

@Test
public void fail_when_not_enough_privilege_on_test_file_key() {
userSessionRule.addProjectPermission(USER, project);
insertTests(testFile, newTest(mainFile, 10).build());

expectedException.expect(ForbiddenException.class);
call(ws.newRequest().setParam(TEST_FILE_KEY, testFile.getDbKey()));
}

@Test
public void fail_when_not_enough_privilege_on_main_file_uuid() {
userSessionRule.addProjectPermission(USER, project);
insertTests(testFile, newTest(mainFile, 10).build());

expectedException.expect(ForbiddenException.class);
call(ws.newRequest().setParam(SOURCE_FILE_ID, mainFile.uuid()).setParam(SOURCE_FILE_LINE_NUMBER, "10"));
}

@Test
public void fail_when_test_uuid_is_unknown() {
expectedException.expect(NotFoundException.class);
call(ws.newRequest().setParam(TEST_ID, "unknown"));
}

@Test
public void fail_when_test_file_id_is_unknown() {
expectedException.expect(NotFoundException.class);
call(ws.newRequest().setParam(TEST_FILE_ID, "unknown"));
}

@Test
public void fail_when_test_file_key_is_unknown() {
expectedException.expect(NotFoundException.class);
call(ws.newRequest().setParam(TEST_FILE_KEY, "unknown"));
}

@Test
public void fail_when_test_branch_is_unknown() {
ComponentDto project = db.components().insertMainBranch();
userSessionRule.addProjectPermission(CODEVIEWER, project);
ComponentDto branch = db.components().insertProjectBranch(project);
ComponentDto testFile = db.components().insertComponent(newFileDto(branch).setQualifier(UNIT_TEST_FILE));

expectedException.expect(NotFoundException.class);
expectedException.expectMessage(format("Component '%s' on branch 'unknown' not found", testFile.getKey()));

call(ws.newRequest()
.setParam(TEST_FILE_KEY, testFile.getKey())
.setParam("branch", "unknown"));
}

@Test
public void fail_when_source_file_id_is_unknown() {
expectedException.expect(NotFoundException.class);
call(ws.newRequest().setParam(SOURCE_FILE_ID, "unknown").setParam(SOURCE_FILE_LINE_NUMBER, "10"));
}

@Test
public void fail_when_source_file_key_is_unknown() {
expectedException.expect(NotFoundException.class);
call(ws.newRequest().setParam(SOURCE_FILE_KEY, "unknown").setParam(SOURCE_FILE_LINE_NUMBER, "10"));
}

@Test
public void fail_when_source_branch_is_unknown() {
ComponentDto project = db.components().insertMainBranch();
userSessionRule.addProjectPermission(CODEVIEWER, project);
ComponentDto branch = db.components().insertProjectBranch(project);
ComponentDto mainFile = db.components().insertComponent(newFileDto(branch));

expectedException.expect(NotFoundException.class);
expectedException.expectMessage(format("Component '%s' on branch 'unknown' not found", mainFile.getKey()));

call(ws.newRequest()
.setParam(SOURCE_FILE_KEY, mainFile.getKey())
.setParam("branch", "unknown")
.setParam(SOURCE_FILE_LINE_NUMBER, "10"));
}

private void insertTests(ComponentDto testFile, DbFileSources.Test... tests) {
db.getDbClient().fileSourceDao().insert(db.getSession(), new FileSourceDto()
.setProjectUuid(testFile.projectUuid())
.setFileUuid(testFile.uuid())
.setTestData(asList(tests)));
db.commit();
testIndexer.indexOnStartup(null);
}

private static ListResponse call(TestRequest request) {
return request
.executeProtobuf(ListResponse.class);
}

}

+ 0
- 16
server/sonar-server/src/test/resources/org/sonar/server/test/ws/CoveredFilesActionTest/tests-covered-files.json View File

@@ -1,16 +0,0 @@
{
"files": [
{
"id": "FILE1",
"key": "org.foo.Bar.java",
"longName": "src/main/java/org/foo/Bar.java",
"coveredLines": 10
},
{
"id": "FILE2",
"key": "org.foo.File.java",
"longName": "src/main/java/org/foo/File.java",
"coveredLines": 3
}
]
}

+ 0
- 34
server/sonar-server/src/test/resources/org/sonar/server/test/ws/ListActionTest/list-main-file.json View File

@@ -1,34 +0,0 @@
{
"paging": {
"pageIndex": 1,
"pageSize": 100,
"total": 2
},
"tests": [
{
"id": "TEST-UUID-1",
"name": "test1",
"status": "OK",
"fileId": "ABCD",
"fileKey": "org.foo.BarTest.java",
"fileName": "src/test/java/org/foo/BarTest.java",
"durationInMs": 10,
"coveredLines": 4,
"message": "MESSAGE-1",
"stacktrace": "STACKTRACE-1"
},
{
"id": "TEST-UUID-2",
"name": "test2",
"status": "ERROR",
"fileId": "BCDE",
"fileKey": "org.foo.FileTest.java",
"fileName": "src/test/java/org/foo/FileTest.java",
"durationInMs": 97,
"coveredLines": 4,
"message": "MESSAGE-2",
"stacktrace": "STACKTRACE-2"

}
]
}

+ 0
- 16
server/sonar-server/src/test/resources/org/sonar/server/test/ws/ListActionTest/list-test-uuid.json View File

@@ -1,16 +0,0 @@
{
"tests": [
{
"id": "TEST-UUID-1",
"name": "test1",
"status": "OK",
"fileId": "ABCD",
"fileKey": "org.foo.BarTest.java",
"fileName": "src/test/java/org/foo/BarTest.java",
"durationInMs": 10,
"coveredLines": 4,
"message": "MESSAGE-1",
"stacktrace": "STACKTRACE-1"
}
]
}

+ 0
- 34
sonar-scanner-engine/src/main/java/org/sonar/scanner/mediumtest/AnalysisResult.java View File

@@ -21,7 +21,6 @@ package org.sonar.scanner.mediumtest;

import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -29,7 +28,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.InputComponent;
@@ -254,38 +252,6 @@ public class AnalysisResult implements AnalysisObserver {
return null;
}

public ScannerReport.Test firstTestExecutionForName(InputFile testFile, String testName) {
int ref = ((DefaultInputComponent) testFile).scannerId();
try (InputStream inputStream = FileUtils.openInputStream(getReportReader().readTests(ref))) {
ScannerReport.Test test = ScannerReport.Test.parser().parseDelimitedFrom(inputStream);
while (test != null) {
if (test.getName().equals(testName)) {
return test;
}
test = ScannerReport.Test.parser().parseDelimitedFrom(inputStream);
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
return null;
}

public ScannerReport.CoverageDetail coveragePerTestFor(InputFile testFile, String testName) {
int ref = ((DefaultInputComponent) testFile).scannerId();
try (InputStream inputStream = FileUtils.openInputStream(getReportReader().readCoverageDetails(ref))) {
ScannerReport.CoverageDetail details = ScannerReport.CoverageDetail.parser().parseDelimitedFrom(inputStream);
while (details != null) {
if (details.getTestName().equals(testName)) {
return details;
}
details = ScannerReport.CoverageDetail.parser().parseDelimitedFrom(inputStream);
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
return null;
}

public List<ScannerReport.AdHocRule> adHocRules() {
List<ScannerReport.AdHocRule> result = new ArrayList<>();
try (CloseableIterator<ScannerReport.AdHocRule> it = getReportReader().readAdHocRules()) {

+ 0
- 126
sonar-scanner-engine/src/main/java/org/sonar/scanner/report/TestExecutionAndCoveragePublisher.java View File

@@ -1,126 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.scanner.report;

import com.google.common.collect.Iterables;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.StreamSupport;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.internal.DefaultInputComponent;
import org.sonar.api.test.CoverageBlock;
import org.sonar.api.test.MutableTestCase;
import org.sonar.api.test.MutableTestPlan;
import org.sonar.api.test.TestCase;
import org.sonar.scanner.deprecated.test.DefaultTestable;
import org.sonar.scanner.deprecated.test.TestPlanBuilder;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.CoverageDetail;
import org.sonar.scanner.protocol.output.ScannerReport.Test;
import org.sonar.scanner.protocol.output.ScannerReport.Test.TestStatus;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.InputComponentStore;

import static java.util.stream.Collectors.toList;

public class TestExecutionAndCoveragePublisher implements ReportPublisherStep {

private final InputComponentStore componentStore;
private final TestPlanBuilder testPlanBuilder;
private final BranchConfiguration branchConfiguration;

public TestExecutionAndCoveragePublisher(InputComponentStore componentStore, TestPlanBuilder testPlanBuilder, BranchConfiguration branchConfiguration) {
this.componentStore = componentStore;
this.testPlanBuilder = testPlanBuilder;
this.branchConfiguration = branchConfiguration;
}

@Override
public void publish(ScannerReportWriter writer) {
if (branchConfiguration.isShortOrPullRequest()) {
return;
}
final ScannerReport.Test.Builder testBuilder = ScannerReport.Test.newBuilder();
final ScannerReport.CoverageDetail.Builder builder = ScannerReport.CoverageDetail.newBuilder();
final ScannerReport.CoverageDetail.CoveredFile.Builder coveredBuilder = ScannerReport.CoverageDetail.CoveredFile.newBuilder();
for (final InputComponent c : componentStore.all()) {
DefaultInputComponent component = (DefaultInputComponent) c;
final MutableTestPlan testPlan = testPlanBuilder.loadPerspective(MutableTestPlan.class, component);
if (testPlan == null || Iterables.isEmpty(testPlan.testCases())) {
continue;
}

final Set<String> testNamesWithCoverage = new HashSet<>();

writer.writeTests(component.scannerId(),
StreamSupport.stream(testPlan.testCases().spliterator(), false)
.map(testCase -> toProtobufTest(testBuilder, testNamesWithCoverage, testCase))
.collect(toList()));

writer.writeCoverageDetails(component.scannerId(), testNamesWithCoverage.stream()
.map(testName -> toProtobufCoverageDetails(builder, coveredBuilder, testPlan, testName))
.collect(toList()));
}
}

private CoverageDetail toProtobufCoverageDetails(final ScannerReport.CoverageDetail.Builder builder, final ScannerReport.CoverageDetail.CoveredFile.Builder coveredBuilder,
final MutableTestPlan testPlan, String testName) {
// Take first test with provided name
MutableTestCase testCase = testPlan.testCasesByName(testName).iterator().next();
builder.clear();
builder.setTestName(testName);
for (CoverageBlock block : testCase.coverageBlocks()) {
coveredBuilder.clear();
DefaultInputComponent c = (DefaultInputComponent) componentStore.getByKey(((DefaultTestable) block.testable()).inputFile().key());
coveredBuilder.setFileRef(c.scannerId());
for (int line : block.lines()) {
coveredBuilder.addCoveredLine(line);
}
builder.addCoveredFile(coveredBuilder.build());
}
return builder.build();
}

private static Test toProtobufTest(final ScannerReport.Test.Builder testBuilder, final Set<String> testNamesWithCoverage, MutableTestCase testCase) {
testBuilder.clear();
testBuilder.setName(testCase.name());
if (testCase.doesCover()) {
testNamesWithCoverage.add(testCase.name());
}
Long durationInMs = testCase.durationInMs();
if (durationInMs != null) {
testBuilder.setDurationInMs(durationInMs.longValue());
}
String msg = testCase.message();
if (msg != null) {
testBuilder.setMsg(msg);
}
String stack = testCase.stackTrace();
if (stack != null) {
testBuilder.setStacktrace(stack);
}
TestCase.Status status = testCase.status();
if (status != null) {
testBuilder.setStatus(TestStatus.valueOf(status.name()));
}
return testBuilder.build();
}
}

+ 1
- 3
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java View File

@@ -80,7 +80,6 @@ import org.sonar.scanner.report.MeasuresPublisher;
import org.sonar.scanner.report.MetadataPublisher;
import org.sonar.scanner.report.ReportPublisher;
import org.sonar.scanner.report.SourcePublisher;
import org.sonar.scanner.report.TestExecutionAndCoveragePublisher;
import org.sonar.scanner.repository.ContextPropertiesCache;
import org.sonar.scanner.repository.DefaultProjectRepositoriesLoader;
import org.sonar.scanner.repository.DefaultQualityProfileLoader;
@@ -294,8 +293,7 @@ public class ProjectScanContainer extends ComponentContainer {
MeasuresPublisher.class,
CoveragePublisher.class,
SourcePublisher.class,
ChangedLinesPublisher.class,
TestExecutionAndCoveragePublisher.class);
ChangedLinesPublisher.class);
}

private void addIssueTrackingComponents() {

+ 0
- 147
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/tests/CoveragePerTestMediumTest.java View File

@@ -1,147 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.scanner.mediumtest.tests;

import com.google.common.collect.ImmutableMap;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.FileUtils;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.xoo.XooPlugin;

import static org.assertj.core.api.Assertions.assertThat;

public class CoveragePerTestMediumTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Rule
public ExpectedException exception = ExpectedException.none();

@Rule
public ScannerMediumTester tester = new ScannerMediumTester()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way");

@Test
// SONAR-6183
public void invalidCoverage() throws IOException {
File baseDir = createTestFiles();
File srcDir = new File(baseDir, "src");

File coverageFile = new File(srcDir, "sample.xoo.coverage");
FileUtils.write(coverageFile, "0:2\n", StandardCharsets.UTF_8);

exception.expect(IllegalStateException.class);
exception.expectMessage("Error processing line 1 of file");
exception.expectCause(new TypeSafeMatcher<Throwable>() {

@Override
public void describeTo(Description description) {
// nothing to do
}

@Override
protected boolean matchesSafely(Throwable item) {
return item.getMessage().contains("Line number must be strictly positive");
}
});
runTask(baseDir);

}

@Test
public void coveragePerTestInReport() throws IOException {
File baseDir = createTestFiles();
File testDir = new File(baseDir, "test");

File xooTestExecutionFile = new File(testDir, "sampleTest.xoo.test");
FileUtils.write(xooTestExecutionFile, "some test:4:::OK:UNIT\n" +
"another test:10:::OK:UNIT\n" +
"test without coverage:10:::OK:UNIT\n", StandardCharsets.UTF_8);

File xooCoveragePerTestFile = new File(testDir, "sampleTest.xoo.testcoverage");
FileUtils.write(xooCoveragePerTestFile, "some test;src/sample.xoo,10,11;src/sample2.xoo,1,2\n" +
"another test;src/sample.xoo,10,20\n", StandardCharsets.UTF_8);

AnalysisResult result = runTask(baseDir);

InputFile file = result.inputFile("test/sampleTest.xoo");
org.sonar.scanner.protocol.output.ScannerReport.CoverageDetail someTest = result.coveragePerTestFor(file, "some test");
assertThat(someTest.getCoveredFileList()).hasSize(2);
assertThat(someTest.getCoveredFile(0).getFileRef()).isGreaterThan(0);
assertThat(someTest.getCoveredFile(0).getCoveredLineList()).containsExactly(10, 11);
assertThat(someTest.getCoveredFile(1).getFileRef()).isGreaterThan(0);
assertThat(someTest.getCoveredFile(1).getCoveredLineList()).containsExactly(1, 2);

org.sonar.scanner.protocol.output.ScannerReport.CoverageDetail anotherTest = result.coveragePerTestFor(file, "another test");
assertThat(anotherTest.getCoveredFileList()).hasSize(1);
assertThat(anotherTest.getCoveredFile(0).getFileRef()).isGreaterThan(0);
assertThat(anotherTest.getCoveredFile(0).getCoveredLineList()).containsExactly(10, 20);
}

private AnalysisResult runTask(File baseDir) {
return tester.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
.put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.projectName", "Foo Project")
.put("sonar.projectVersion", "1.0-SNAPSHOT")
.put("sonar.projectDescription", "Description of Foo Project")
.put("sonar.sources", "src")
.put("sonar.tests", "test")
.build())
.execute();
}

private File createTestFiles() throws IOException {
File baseDir = temp.getRoot();
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File testDir = new File(baseDir, "test");
testDir.mkdir();

File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "foo", StandardCharsets.UTF_8);

File xooFile2 = new File(srcDir, "sample2.xoo");
FileUtils.write(xooFile2, "foo", StandardCharsets.UTF_8);

File xooTestFile = new File(testDir, "sampleTest.xoo");
FileUtils.write(xooTestFile, "failure\nerror\nok\nskipped", StandardCharsets.UTF_8);

File xooTestFile2 = new File(testDir, "sample2Test.xoo");
FileUtils.write(xooTestFile2, "test file tests", StandardCharsets.UTF_8);

return baseDir;
}

}

+ 5
- 110
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/tests/GenericTestExecutionMediumTest.java View File

@@ -19,22 +19,15 @@
*/
package org.sonar.scanner.mediumtest.tests;

import com.google.common.collect.ImmutableMap;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReport.Test.TestStatus;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.xoo.XooPlugin;

import static org.assertj.core.api.Assertions.assertThat;
@@ -43,63 +36,13 @@ import static org.assertj.core.api.Assertions.tuple;
public class GenericTestExecutionMediumTest {
private final List<String> logs = new ArrayList<>();

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Rule
public ScannerMediumTester tester = new ScannerMediumTester()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way");

@Test
public void unitTests() throws IOException {

File baseDir = temp.getRoot();
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File testDir = new File(baseDir, "test");
testDir.mkdir();

File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "foo", StandardCharsets.UTF_8);

File xooTestFile = new File(testDir, "sampleTest.xoo");
FileUtils.write(xooTestFile, "failure\nerror\nok\nskipped", StandardCharsets.UTF_8);

File xooTestExecutionFile = new File(testDir, "sampleTest.xoo.test");
FileUtils.write(xooTestExecutionFile, "skipped::::SKIPPED:UNIT\n" +
"failure:2:Failure::FAILURE:UNIT\n" +
"error:2:Error:The stack:ERROR:UNIT\n" +
"success:4:::OK:INTEGRATION", StandardCharsets.UTF_8);

AnalysisResult result = tester
.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
.put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.projectName", "Foo Project")
.put("sonar.projectVersion", "1.0-SNAPSHOT")
.put("sonar.projectDescription", "Description of Foo Project")
.put("sonar.sources", "src")
.put("sonar.tests", "test")
.build())
.execute();

InputFile file = result.inputFile("test/sampleTest.xoo");
org.sonar.scanner.protocol.output.ScannerReport.Test success = result.firstTestExecutionForName(file, "success");
assertThat(success.getDurationInMs()).isEqualTo(4);
assertThat(success.getStatus()).isEqualTo(TestStatus.OK);

org.sonar.scanner.protocol.output.ScannerReport.Test error = result.firstTestExecutionForName(file, "error");
assertThat(error.getDurationInMs()).isEqualTo(2);
assertThat(error.getStatus()).isEqualTo(TestStatus.ERROR);
assertThat(error.getMsg()).isEqualTo("Error");
assertThat(error.getStacktrace()).isEqualTo("The stack");
}

@Test
public void singleReport() throws IOException {
public void singleReport() {

File projectDir = new File("test-resources/mediumtest/xoo/sample-generic-test-exec");

@@ -110,28 +53,6 @@ public class GenericTestExecutionMediumTest {
.execute();

InputFile testFile = result.inputFile("testx/ClassOneTest.xoo");
ScannerReport.Test success = result.firstTestExecutionForName(testFile, "test1");
assertThat(success.getDurationInMs()).isEqualTo(5);
assertThat(success.getStatus()).isEqualTo(TestStatus.OK);

ScannerReport.Test skipped = result.firstTestExecutionForName(testFile, "test2");
assertThat(skipped.getDurationInMs()).isEqualTo(500);
assertThat(skipped.getStatus()).isEqualTo(TestStatus.SKIPPED);
assertThat(skipped.getMsg()).isEqualTo("short message");
assertThat(skipped.getStacktrace()).isEqualTo("other");

ScannerReport.Test failed = result.firstTestExecutionForName(testFile, "test3");
assertThat(failed.getDurationInMs()).isEqualTo(100);
assertThat(failed.getStatus()).isEqualTo(TestStatus.FAILURE);
assertThat(failed.getMsg()).isEqualTo("short");
assertThat(failed.getStacktrace()).isEqualTo("stacktrace");

ScannerReport.Test error = result.firstTestExecutionForName(testFile, "test4");
assertThat(error.getDurationInMs()).isEqualTo(500);
assertThat(error.getStatus()).isEqualTo(TestStatus.ERROR);
assertThat(error.getMsg()).isEqualTo("short");
assertThat(error.getStacktrace()).isEqualTo("stacktrace");

assertThat(result.allMeasures().get(testFile.key())).extracting("metricKey", "intValue.value", "longValue.value")
.containsOnly(
tuple(CoreMetrics.TESTS_KEY, 3, 0L),
@@ -139,12 +60,12 @@ public class GenericTestExecutionMediumTest {
tuple(CoreMetrics.TEST_ERRORS_KEY, 1, 0L),
tuple(CoreMetrics.TEST_EXECUTION_TIME_KEY, 0, 1105L),
tuple(CoreMetrics.TEST_FAILURES_KEY, 1, 0L));
assertThat(logs).noneMatch(l -> l.contains("Please use 'sonar.testExecutionReportPaths'"));
}

@Test
public void twoReports() throws IOException {
public void twoReports() {

File projectDir = new File("test-resources/mediumtest/xoo/sample-generic-test-exec");

@@ -155,32 +76,6 @@ public class GenericTestExecutionMediumTest {
.execute();

InputFile testFile = result.inputFile("testx/ClassOneTest.xoo");
ScannerReport.Test success = result.firstTestExecutionForName(testFile, "test1");
assertThat(success.getDurationInMs()).isEqualTo(5);
assertThat(success.getStatus()).isEqualTo(TestStatus.OK);

ScannerReport.Test success2 = result.firstTestExecutionForName(testFile, "test1b");
assertThat(success2.getDurationInMs()).isEqualTo(5);
assertThat(success2.getStatus()).isEqualTo(TestStatus.OK);

ScannerReport.Test skipped = result.firstTestExecutionForName(testFile, "test2");
assertThat(skipped.getDurationInMs()).isEqualTo(500);
assertThat(skipped.getStatus()).isEqualTo(TestStatus.SKIPPED);
assertThat(skipped.getMsg()).isEqualTo("short message");
assertThat(skipped.getStacktrace()).isEqualTo("other");

ScannerReport.Test failed = result.firstTestExecutionForName(testFile, "test3");
assertThat(failed.getDurationInMs()).isEqualTo(100);
assertThat(failed.getStatus()).isEqualTo(TestStatus.FAILURE);
assertThat(failed.getMsg()).isEqualTo("short");
assertThat(failed.getStacktrace()).isEqualTo("stacktrace");

ScannerReport.Test error = result.firstTestExecutionForName(testFile, "test4");
assertThat(error.getDurationInMs()).isEqualTo(500);
assertThat(error.getStatus()).isEqualTo(TestStatus.ERROR);
assertThat(error.getMsg()).isEqualTo("short");
assertThat(error.getStacktrace()).isEqualTo("stacktrace");

assertThat(result.allMeasures().get(testFile.key())).extracting("metricKey", "intValue.value", "longValue.value")
.containsOnly(
tuple(CoreMetrics.TESTS_KEY, 4, 0L),
@@ -188,7 +83,7 @@ public class GenericTestExecutionMediumTest {
tuple(CoreMetrics.TEST_ERRORS_KEY, 1, 0L),
tuple(CoreMetrics.TEST_EXECUTION_TIME_KEY, 0, 1610L),
tuple(CoreMetrics.TEST_FAILURES_KEY, 1, 0L));
assertThat(logs).noneMatch(l -> l.contains("Please use 'sonar.testExecutionReportPaths'"));
}


+ 0
- 93
sonar-scanner-engine/src/test/java/org/sonar/scanner/mediumtest/tests/TestExecutionMediumTest.java View File

@@ -1,93 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.scanner.mediumtest.tests;

import com.google.common.collect.ImmutableMap;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.scanner.mediumtest.ScannerMediumTester;
import org.sonar.scanner.mediumtest.AnalysisResult;
import org.sonar.scanner.protocol.output.ScannerReport.Test.TestStatus;
import org.sonar.xoo.XooPlugin;

import static org.assertj.core.api.Assertions.assertThat;

public class TestExecutionMediumTest {

@org.junit.Rule
public TemporaryFolder temp = new TemporaryFolder();

@Rule
public ScannerMediumTester tester = new ScannerMediumTester()
.registerPlugin("xoo", new XooPlugin())
.addDefaultQProfile("xoo", "Sonar Way");

@Test
public void unitTests() throws IOException {

File baseDir = temp.getRoot();
File srcDir = new File(baseDir, "src");
srcDir.mkdir();
File testDir = new File(baseDir, "test");
testDir.mkdir();

File xooFile = new File(srcDir, "sample.xoo");
FileUtils.write(xooFile, "foo");

File xooTestFile = new File(testDir, "sampleTest.xoo");
FileUtils.write(xooTestFile, "failure\nerror\nok\nskipped");

File xooTestExecutionFile = new File(testDir, "sampleTest.xoo.test");
FileUtils.write(xooTestExecutionFile, "skipped::::SKIPPED:UNIT\n" +
"failure:2:Failure::FAILURE:UNIT\n" +
"error:2:Error:The stack:ERROR:UNIT\n" +
"success:4:::OK:INTEGRATION");

AnalysisResult result = tester.newAnalysis()
.properties(ImmutableMap.<String, String>builder()
.put("sonar.task", "scan")
.put("sonar.projectBaseDir", baseDir.getAbsolutePath())
.put("sonar.projectKey", "com.foo.project")
.put("sonar.projectName", "Foo Project")
.put("sonar.projectVersion", "1.0-SNAPSHOT")
.put("sonar.projectDescription", "Description of Foo Project")
.put("sonar.sources", "src")
.put("sonar.tests", "test")
.build())
.execute();

InputFile file = result.inputFile("test/sampleTest.xoo");
org.sonar.scanner.protocol.output.ScannerReport.Test success = result.firstTestExecutionForName(file, "success");
assertThat(success.getDurationInMs()).isEqualTo(4);
assertThat(success.getStatus()).isEqualTo(TestStatus.OK);

org.sonar.scanner.protocol.output.ScannerReport.Test error = result.firstTestExecutionForName(file, "error");
assertThat(error.getDurationInMs()).isEqualTo(2);
assertThat(error.getStatus()).isEqualTo(TestStatus.ERROR);
assertThat(error.getMsg()).isEqualTo("Error");
assertThat(error.getStacktrace()).isEqualTo("The stack");
}

}

+ 0
- 68
sonar-scanner-engine/src/test/java/org/sonar/scanner/report/TestExecutionAndCoveragePublisherTest.java View File

@@ -1,68 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.scanner.report;

import java.io.File;
import java.io.IOException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import org.sonar.scanner.scan.filesystem.InputComponentStore;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;

public class TestExecutionAndCoveragePublisherTest {

@Rule
public TemporaryFolder temp = new TemporaryFolder();

@Test
public void do_nothing_for_short_living_branches() throws IOException {
BranchConfiguration branchConfiguration = mock(BranchConfiguration.class);
when(branchConfiguration.isShortOrPullRequest()).thenReturn(true);
InputComponentStore componentStore = mock(InputComponentStore.class);
TestExecutionAndCoveragePublisher publisher = new TestExecutionAndCoveragePublisher(componentStore, null, branchConfiguration);
File outputDir = temp.newFolder();
ScannerReportWriter writer = new ScannerReportWriter(outputDir);

publisher.publish(writer);

verifyZeroInteractions(componentStore);
}

@Test
public void do_nothing_for_pull_requests() throws IOException {
BranchConfiguration branchConfiguration = mock(BranchConfiguration.class);
when(branchConfiguration.isShortOrPullRequest()).thenReturn(true);
InputComponentStore componentStore = mock(InputComponentStore.class);
TestExecutionAndCoveragePublisher publisher = new TestExecutionAndCoveragePublisher(componentStore, null, branchConfiguration);
File outputDir = temp.newFolder();
ScannerReportWriter writer = new ScannerReportWriter(outputDir);

publisher.publish(writer);

verifyZeroInteractions(componentStore);
}

}

+ 0
- 3
sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/FileStructure.java View File

@@ -20,7 +20,6 @@
package org.sonar.scanner.protocol.output;

import java.io.File;

import javax.annotation.concurrent.Immutable;

/**
@@ -40,8 +39,6 @@ public class FileStructure {
CHANGESETS("changesets-", Domain.PB),
SYMBOLS("symbols-", Domain.PB),
COVERAGES("coverages-", Domain.PB),
TESTS("tests-", Domain.PB),
COVERAGE_DETAILS("coverage-details-", Domain.PB),
SOURCE("source-", ".txt"),
SGNIFICANT_CODE("sgnificant-code-", Domain.PB),
CHANGED_LINES("changed-lines-", Domain.PB);

+ 0
- 20
sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportReader.java View File

@@ -181,26 +181,6 @@ public class ScannerReportReader {
return null;
}

@CheckForNull
public File readTests(int testFileRef) {
File file = fileStructure.fileFor(FileStructure.Domain.TESTS, testFileRef);
if (fileExists(file)) {
return file;
}

return null;
}

@CheckForNull
public File readCoverageDetails(int testFileRef) {
File file = fileStructure.fileFor(FileStructure.Domain.COVERAGE_DETAILS, testFileRef);
if (fileExists(file)) {
return file;
}

return null;
}

public CloseableIterator<ScannerReport.ContextProperty> readContextProperties() {
File file = fileStructure.contextProperties();
if (!fileExists(file)) {

+ 0
- 12
sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/output/ScannerReportWriter.java View File

@@ -154,18 +154,6 @@ public class ScannerReportWriter {
return file;
}

public File writeTests(int componentRef, Iterable<ScannerReport.Test> tests) {
File file = fileStructure.fileFor(FileStructure.Domain.TESTS, componentRef);
Protobuf.writeStream(tests, file, false);
return file;
}

public File writeCoverageDetails(int componentRef, Iterable<ScannerReport.CoverageDetail> tests) {
File file = fileStructure.fileFor(FileStructure.Domain.COVERAGE_DETAILS, componentRef);
Protobuf.writeStream(tests, file, false);
return file;
}

public File writeContextProperties(Iterable<ScannerReport.ContextProperty> properties) {
File file = fileStructure.contextProperties();
Protobuf.writeStream(properties, file, false);

+ 0
- 19
sonar-scanner-protocol/src/main/java/org/sonar/scanner/protocol/viewer/ScannerReportViewerApp.java View File

@@ -25,7 +25,6 @@ import java.awt.Dimension;
import java.awt.EventQueue;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
@@ -256,7 +255,6 @@ public class ScannerReportViewerApp {
updateSymbols(component);
updateSource(component);
updateCoverage(component);
updateTests(component);
updateDuplications(component);
updateIssues(component);
updateExternalIssues(component);
@@ -348,23 +346,6 @@ public class ScannerReportViewerApp {
}
}

private void updateTests(Component component) {
testsEditor.setText("");
File tests = reader.readTests(component.getRef());
if (tests == null) {
return;
}
try (InputStream inputStream = FileUtils.openInputStream(tests)) {
ScannerReport.Test test = ScannerReport.Test.parser().parseDelimitedFrom(inputStream);
while (test != null) {
testsEditor.getDocument().insertString(testsEditor.getDocument().getEndPosition().getOffset(), test + "\n", null);
test = ScannerReport.Test.parser().parseDelimitedFrom(inputStream);
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
}

private void updateSource(Component component) {
File sourceFile = reader.getFileStructure().fileFor(Domain.SOURCE, component.getRef());
sourceEditor.setText("");

+ 0
- 26
sonar-scanner-protocol/src/main/protobuf/scanner_report.proto View File

@@ -321,32 +321,6 @@ message SyntaxHighlightingRule {
}
}

message Test {
string name = 1;
TestStatus status = 2;
int64 duration_in_ms = 3;
string stacktrace = 4;
string msg = 5;
enum TestStatus {
UNSET = 0;
OK = 1;
FAILURE = 2;
ERROR = 3;
SKIPPED = 4;
}
}

message CoverageDetail {
string test_name = 1;
repeated CoveredFile covered_file = 2;

message CoveredFile {
int32 file_ref = 1;
repeated int32 covered_line = 2 [packed = true];
}
}

message AnalysisWarning {
string text = 1;
int64 timestamp = 2;

+ 5
- 55
sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/output/ScannerReportReaderTest.java View File

@@ -32,7 +32,6 @@ import org.junit.rules.TemporaryFolder;
import org.sonar.core.util.CloseableIterator;
import org.sonar.scanner.protocol.output.ScannerReport.Measure.StringValue;
import org.sonar.scanner.protocol.output.ScannerReport.SyntaxHighlightingRule.HighlightingType;
import org.sonar.scanner.protocol.output.ScannerReport.Test.TestStatus;

import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
@@ -45,9 +44,9 @@ public class ScannerReportReaderTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();

File dir;
private File dir;

ScannerReportReader underTest;
private ScannerReportReader underTest;

@Before
public void setUp() throws Exception {
@@ -211,7 +210,7 @@ public class ScannerReportReaderTest {
}

@Test
public void read_syntax_highlighting() throws Exception {
public void read_syntax_highlighting() {
ScannerReportWriter writer = new ScannerReportWriter(dir);
writer.writeMetadata(ScannerReport.Metadata.newBuilder()
.setRootComponentRef(1)
@@ -276,7 +275,7 @@ public class ScannerReportReaderTest {
}

@Test
public void read_coverage() throws Exception {
public void read_coverage() {
ScannerReportWriter writer = new ScannerReportWriter(dir);
writer.writeMetadata(ScannerReport.Metadata.newBuilder()
.setRootComponentRef(1)
@@ -323,55 +322,6 @@ public class ScannerReportReaderTest {
assertThat(sourceFile).isEqualTo(file);
}

@Test
public void read_tests() throws Exception {
ScannerReportWriter writer = new ScannerReportWriter(dir);
writer.writeTests(1, asList(
ScannerReport.Test.newBuilder()
.setDurationInMs(60_000)
.setStacktrace("stacktrace")
.setMsg("message")
.setStatus(TestStatus.OK)
.build()));

try (InputStream inputStream = FileUtils.openInputStream(underTest.readTests(1))) {
ScannerReport.Test testResult = ScannerReport.Test.parser().parseDelimitedFrom(inputStream);
assertThat(testResult.getDurationInMs()).isEqualTo(60_000);
assertThat(testResult.getStacktrace()).isEqualTo("stacktrace");
assertThat(testResult.getMsg()).isEqualTo("message");
assertThat(testResult.getStatus()).isEqualTo(TestStatus.OK);
}
}

@Test
public void null_if_no_test_found() {
assertThat(underTest.readTests(UNKNOWN_COMPONENT_REF)).isNull();
}

@Test
public void read_coverage_details() throws Exception {
ScannerReportWriter writer = new ScannerReportWriter(dir);
writer.writeCoverageDetails(1, asList(
ScannerReport.CoverageDetail.newBuilder()
.setTestName("test-name")
.addCoveredFile(ScannerReport.CoverageDetail.CoveredFile.newBuilder()
.addAllCoveredLine(asList(1, 2, 3, 5, 7))
.setFileRef(2))
.build()));

try (InputStream inputStream = FileUtils.openInputStream(underTest.readCoverageDetails(1))) {
ScannerReport.CoverageDetail coverageDetail = ScannerReport.CoverageDetail.parser().parseDelimitedFrom(inputStream);
assertThat(coverageDetail.getTestName()).isEqualTo("test-name");
assertThat(coverageDetail.getCoveredFile(0).getFileRef()).isEqualTo(2);
assertThat(coverageDetail.getCoveredFile(0).getCoveredLineList()).containsExactly(1, 2, 3, 5, 7);
}
}

@Test
public void null_if_no_coverage_detail_found() {
assertThat(underTest.readCoverageDetails(UNKNOWN_COMPONENT_REF)).isNull();
}

@Test
public void read_file_source() throws Exception {
ScannerReportWriter writer = new ScannerReportWriter(dir);
@@ -385,7 +335,7 @@ public class ScannerReportReaderTest {
}

@Test
public void return_null_when_no_file_source() throws Exception {
public void return_null_when_no_file_source() {
assertThat(underTest.readFileSource(UNKNOWN_COMPONENT_REF)).isNull();
}
}

+ 0
- 20
sonar-scanner-protocol/src/test/java/org/sonar/scanner/protocol/output/ScannerReportWriterTest.java View File

@@ -353,24 +353,4 @@ public class ScannerReportWriterTest {
assertThat(underTest.hasComponentData(FileStructure.Domain.COVERAGES, 1)).isTrue();
}

@Test
public void write_tests() {
assertThat(underTest.hasComponentData(FileStructure.Domain.TESTS, 1)).isFalse();

underTest.writeTests(1, asList(
ScannerReport.Test.getDefaultInstance()));

assertThat(underTest.hasComponentData(FileStructure.Domain.TESTS, 1)).isTrue();

}

@Test
public void write_coverage_details() {
assertThat(underTest.hasComponentData(FileStructure.Domain.COVERAGE_DETAILS, 1)).isFalse();

underTest.writeCoverageDetails(1, asList(
ScannerReport.CoverageDetail.getDefaultInstance()));

assertThat(underTest.hasComponentData(FileStructure.Domain.COVERAGE_DETAILS, 1)).isTrue();
}
}

+ 0
- 8
sonar-ws/src/main/java/org/sonarqube/ws/client/DefaultWsClient.java View File

@@ -65,7 +65,6 @@ import org.sonarqube.ws.client.settings.SettingsService;
import org.sonarqube.ws.client.sources.SourcesService;
import org.sonarqube.ws.client.support.SupportService;
import org.sonarqube.ws.client.system.SystemService;
import org.sonarqube.ws.client.tests.TestsService;
import org.sonarqube.ws.client.timemachine.TimemachineService;
import org.sonarqube.ws.client.updatecenter.UpdatecenterService;
import org.sonarqube.ws.client.usergroups.UserGroupsService;
@@ -130,7 +129,6 @@ class DefaultWsClient implements WsClient {
private final SourcesService sourcesService;
private final SupportService supportService;
private final SystemService systemService;
private final TestsService testsService;
private final TimemachineService timemachineService;
private final UpdatecenterService updatecenterService;
private final UserGroupsService userGroupsService;
@@ -189,7 +187,6 @@ class DefaultWsClient implements WsClient {
this.sourcesService = new SourcesService(wsConnector);
this.supportService = new SupportService(wsConnector);
this.systemService = new SystemService(wsConnector);
this.testsService = new TestsService(wsConnector);
this.timemachineService = new TimemachineService(wsConnector);
this.updatecenterService = new UpdatecenterService(wsConnector);
this.userGroupsService = new UserGroupsService(wsConnector);
@@ -424,11 +421,6 @@ class DefaultWsClient implements WsClient {
return systemService;
}

@Override
public TestsService tests() {
return testsService;
}

@Override
public TimemachineService timemachine() {
return timemachineService;

+ 0
- 3
sonar-ws/src/main/java/org/sonarqube/ws/client/WsClient.java View File

@@ -65,7 +65,6 @@ import org.sonarqube.ws.client.settings.SettingsService;
import org.sonarqube.ws.client.sources.SourcesService;
import org.sonarqube.ws.client.support.SupportService;
import org.sonarqube.ws.client.system.SystemService;
import org.sonarqube.ws.client.tests.TestsService;
import org.sonarqube.ws.client.timemachine.TimemachineService;
import org.sonarqube.ws.client.updatecenter.UpdatecenterService;
import org.sonarqube.ws.client.usergroups.UserGroupsService;
@@ -185,8 +184,6 @@ public interface WsClient {

SystemService system();

TestsService tests();

TimemachineService timemachine();

UpdatecenterService updatecenter();

+ 0
- 74
sonar-ws/src/main/java/org/sonarqube/ws/client/tests/CoveredFilesRequest.java View File

@@ -1,74 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonarqube.ws.client.tests;

import java.util.List;
import javax.annotation.Generated;

/**
* This is part of the internal API.
* This is a POST request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/tests/covered_files">Further information about this action online (including a response example)</a>
* @since 4.4
*/
@Generated("sonar-ws-generator")
public class CoveredFilesRequest {

private String p;
private String ps;
private String testId;

/**
* Example value: "42"
*/
public CoveredFilesRequest setP(String p) {
this.p = p;
return this;
}

public String getP() {
return p;
}

/**
* Example value: "20"
*/
public CoveredFilesRequest setPs(String ps) {
this.ps = ps;
return this;
}

public String getPs() {
return ps;
}

/**
* This is a mandatory parameter.
* Example value: "AU-Tpxb--iU5OvuD2FLy"
*/
public CoveredFilesRequest setTestId(String testId) {
this.testId = testId;
return this;
}

public String getTestId() {
return testId;
}
}

+ 0
- 166
sonar-ws/src/main/java/org/sonarqube/ws/client/tests/ListRequest.java View File

@@ -1,166 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonarqube.ws.client.tests;

import java.util.List;
import javax.annotation.Generated;

/**
* This is part of the internal API.
* This is a POST request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/tests/list">Further information about this action online (including a response example)</a>
* @since 5.2
*/
@Generated("sonar-ws-generator")
public class ListRequest {

private String branch;
private String p;
private String ps;
private String pullRequest;
private String sourceFileId;
private String sourceFileKey;
private String sourceFileLineNumber;
private String testFileId;
private String testFileKey;
private String testId;

/**
* This is part of the internal API.
* Example value: "feature/my_branch"
*/
public ListRequest setBranch(String branch) {
this.branch = branch;
return this;
}

public String getBranch() {
return branch;
}

/**
* Example value: "42"
*/
public ListRequest setP(String p) {
this.p = p;
return this;
}

public String getP() {
return p;
}

/**
* Example value: "20"
*/
public ListRequest setPs(String ps) {
this.ps = ps;
return this;
}

public String getPs() {
return ps;
}

/**
* This is part of the internal API.
* Example value: "5461"
*/
public ListRequest setPullRequest(String pullRequest) {
this.pullRequest = pullRequest;
return this;
}

public String getPullRequest() {
return pullRequest;
}

/**
* Example value: "AU-TpxcA-iU5OvuD2FL0"
*/
public ListRequest setSourceFileId(String sourceFileId) {
this.sourceFileId = sourceFileId;
return this;
}

public String getSourceFileId() {
return sourceFileId;
}

/**
* Example value: "my_project:/src/foo/Bar.php"
*/
public ListRequest setSourceFileKey(String sourceFileKey) {
this.sourceFileKey = sourceFileKey;
return this;
}

public String getSourceFileKey() {
return sourceFileKey;
}

/**
* Example value: "10"
*/
public ListRequest setSourceFileLineNumber(String sourceFileLineNumber) {
this.sourceFileLineNumber = sourceFileLineNumber;
return this;
}

public String getSourceFileLineNumber() {
return sourceFileLineNumber;
}

/**
* Example value: "AU-Tpxb--iU5OvuD2FLy"
*/
public ListRequest setTestFileId(String testFileId) {
this.testFileId = testFileId;
return this;
}

public String getTestFileId() {
return testFileId;
}

/**
* Example value: "MY_PROJECT:src/test/java/foo/BarTest.java"
*/
public ListRequest setTestFileKey(String testFileKey) {
this.testFileKey = testFileKey;
return this;
}

public String getTestFileKey() {
return testFileKey;
}

/**
* Example value: "AU-TpxcA-iU5OvuD2FLz"
*/
public ListRequest setTestId(String testId) {
this.testId = testId;
return this;
}

public String getTestId() {
return testId;
}
}

+ 0
- 84
sonar-ws/src/main/java/org/sonarqube/ws/client/tests/TestsService.java View File

@@ -1,84 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonarqube.ws.client.tests;

import java.util.stream.Collectors;
import javax.annotation.Generated;
import org.sonarqube.ws.MediaTypes;
import org.sonarqube.ws.client.BaseService;
import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.PostRequest;
import org.sonarqube.ws.client.WsConnector;
import org.sonarqube.ws.Tests.CoveredFilesResponse;
import org.sonarqube.ws.Tests.ListResponse;

/**
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/tests">Further information about this web service online</a>
*/
@Generated("sonar-ws-generator")
public class TestsService extends BaseService {

public TestsService(WsConnector wsConnector) {
super(wsConnector, "api/tests");
}

/**
*
* This is part of the internal API.
* This is a GET request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/tests/covered_files">Further information about this action online (including a response example)</a>
* @since 4.4
* @deprecated since 5.6
*/
@Deprecated
public CoveredFilesResponse coveredFiles(CoveredFilesRequest request) {
return call(
new GetRequest(path("covered_files"))
.setParam("p", request.getP())
.setParam("ps", request.getPs())
.setParam("testId", request.getTestId()),
CoveredFilesResponse.parser());
}

/**
*
* This is part of the internal API.
* This is a GET request.
* @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/tests/list">Further information about this action online (including a response example)</a>
* @since 5.2
* @deprecated since 5.6
*/
@Deprecated
public ListResponse list(ListRequest request) {
return call(
new GetRequest(path("list"))
.setParam("branch", request.getBranch())
.setParam("p", request.getP())
.setParam("ps", request.getPs())
.setParam("pullRequest", request.getPullRequest())
.setParam("sourceFileId", request.getSourceFileId())
.setParam("sourceFileKey", request.getSourceFileKey())
.setParam("sourceFileLineNumber", request.getSourceFileLineNumber())
.setParam("testFileId", request.getTestFileId())
.setParam("testFileKey", request.getTestFileKey())
.setParam("testId", request.getTestId()),
ListResponse.parser());
}
}

+ 0
- 26
sonar-ws/src/main/java/org/sonarqube/ws/client/tests/package-info.java View File

@@ -1,26 +0,0 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
@ParametersAreNonnullByDefault
@Generated("sonar-ws-generator")
package org.sonarqube.ws.client.tests;

import javax.annotation.ParametersAreNonnullByDefault;
import javax.annotation.Generated;


Loading…
Cancel
Save