From 280a33c2c1e5b816e27688245b000e9dd502a94c Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Fri, 28 Aug 2015 18:51:07 +0200 Subject: [PATCH] SONAR-6813 Drop ES index sourceLines --- .../benchmark/SourceDbBenchmarkTest.java | 138 ---------- .../benchmark/SourceIndexBenchmarkTest.java | 175 ------------ .../dbcleaner/IndexPurgeListener.java | 6 +- .../component/ComponentCleanerService.java | 6 +- .../computation/issue/IssueAssigner.java | 84 +++--- .../step/IndexSourceLinesStep.java | 45 ---- .../step/ReportComputationSteps.java | 1 - .../org/sonar/server/issue/IssueService.java | 31 ++- .../sonar/server/platform/BackendCleanup.java | 3 - .../platformlevel/PlatformLevel4.java | 6 - .../server/search/IndexSynchronizer.java | 10 +- .../sonar/server/source/CharactersReader.java | 3 - .../server/source/HtmlSourceDecorator.java | 8 +- .../server/source/HtmlTextDecorator.java | 4 - .../sonar/server/source/SourceService.java | 127 ++++++--- .../server/source/index/SourceLineDoc.java | 247 ----------------- .../server/source/index/SourceLineIndex.java | 135 ---------- .../index/SourceLineIndexDefinition.java | 93 ------- .../source/index/SourceLineIndexer.java | 140 ---------- .../index/SourceLineResultSetIterator.java | 167 ------------ .../sonar/server/source/ws/LinesAction.java | 126 +++++---- .../org/sonar/server/source/ws/RawAction.java | 27 +- .../org/sonar/server/source/ws/ScmAction.java | 56 ++-- .../sonar/server/source/ws/ShowAction.java | 37 +-- .../sonar/server/test/index/TestIndexer.java | 3 +- .../dbcleaner/IndexPurgeListenerTest.java | 7 +- .../computation/issue/IssueAssignerTest.java | 228 ++++++++-------- .../sqale/ViewsSqaleMeasuresVisitorTest.java | 24 +- .../step/IndexSourceLinesStepTest.java | 80 ------ .../server/issue/IssueServiceMediumTest.java | 18 +- .../sonar/server/issue/ws/ShowActionTest.java | 4 - .../platform/BackendCleanupMediumTest.java | 4 - .../project/ws/BulkDeleteActionTest.java | 20 +- .../server/project/ws/DeleteActionTest.java | 14 +- .../server/source/SourceServiceTest.java | 132 ++++++--- .../index/SourceLineIndexDefinitionTest.java | 61 ----- .../source/index/SourceLineIndexTest.java | 142 ---------- .../source/index/SourceLineIndexerTest.java | 252 ------------------ .../SourceLineResultSetIteratorTest.java | 191 ------------- .../server/source/ws/LinesActionTest.java | 167 +++--------- .../sonar/server/source/ws/RawActionTest.java | 13 +- .../sonar/server/source/ws/ScmActionTest.java | 118 ++++---- .../server/source/ws/ShowActionTest.java | 26 +- .../sonar/server/source/ws/SourcesWsTest.java | 17 +- .../SourceLineIndexTest/file1_line1.json | 10 - .../SourceLineIndexTest/file1_line2.json | 10 - .../SourceLineIndexTest/file1_line3.json | 10 - .../SourceLineIndexTest/file2_line1.json | 10 - .../SourceLineIndexTest/file2_line2.json | 10 - .../SourceLineIndexTest/file2_line3.json | 10 - .../SourceLineIndexerTest/P1_F1_line1.json | 19 -- .../SourceLineIndexerTest/P1_F1_line2.json | 19 -- .../SourceLineIndexerTest/P1_F2_line1.json | 19 -- .../SourceLineIndexerTest/P2_F3_line1.json | 19 -- .../source/index/SourceLineIndexerTest/db.xml | 6 - .../filter_by_project.xml | 9 - .../filter_by_project_and_date.xml | 9 - .../schema.sql | 11 - .../shared.xml | 6 - .../LinesActionTest/show_paginated_lines.json | 18 ++ .../ws/LinesActionTest/show_source.json | 59 ++-- .../show_source_with_params_from_and_to.json | 10 - .../org/sonar/db/source/FileSourceDao.java | 5 + 63 files changed, 699 insertions(+), 2766 deletions(-) delete mode 100644 server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/SourceDbBenchmarkTest.java delete mode 100644 server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/SourceIndexBenchmarkTest.java delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexSourceLinesStep.java delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineDoc.java delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndex.java delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndexDefinition.java delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndexer.java delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineResultSetIterator.java delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexSourceLinesStepTest.java delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexDefinitionTest.java delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexTest.java delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexerTest.java delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineResultSetIteratorTest.java delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file1_line1.json delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file1_line2.json delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file1_line3.json delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file2_line1.json delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file2_line2.json delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file2_line3.json delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P1_F1_line1.json delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P1_F1_line2.json delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P1_F2_line1.json delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P2_F3_line1.json delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/db.xml delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/filter_by_project.xml delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/filter_by_project_and_date.xml delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/schema.sql delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/shared.xml create mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/ws/LinesActionTest/show_paginated_lines.json delete mode 100644 server/sonar-server/src/test/resources/org/sonar/server/source/ws/LinesActionTest/show_source_with_params_from_and_to.json diff --git a/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/SourceDbBenchmarkTest.java b/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/SourceDbBenchmarkTest.java deleted file mode 100644 index 49193d73ac3..00000000000 --- a/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/SourceDbBenchmarkTest.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.benchmark; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Timer; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.commons.io.IOUtils; -import org.junit.Rule; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.api.utils.System2; -import org.sonar.core.util.Uuids; -import org.sonar.db.DbTester; -import org.sonar.db.protobuf.DbFileSources; -import org.sonar.db.source.FileSourceDao; -import org.sonar.db.source.FileSourceDto; -import org.sonar.server.source.index.FileSourcesUpdaterHelper; -import org.sonar.server.source.index.SourceLineResultSetIterator; - -import static org.assertj.core.api.Assertions.assertThat; - -public class SourceDbBenchmarkTest { - - public static final Logger LOGGER = LoggerFactory.getLogger("benchmarkSourceDbScrolling"); - - public static final int NUMBER_OF_FILES = 1000; - public static final int NUMBER_OF_LINES = 3220; - public static final String PROJECT_UUID = Uuids.create(); - - @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); - - @Rule - public Benchmark benchmark = new Benchmark(); - - @Test - public void benchmark() throws Exception { - prepareTable(); - scrollRows(); - } - - private void scrollRows() { - LOGGER.info("Scroll table FILE_SOURCES"); - AtomicLong counter = new AtomicLong(); - ProgressTask progress = new ProgressTask(LOGGER, "source file", counter); - Timer timer = new Timer("SourceDbScroll"); - timer.schedule(progress, ProgressTask.PERIOD_MS, ProgressTask.PERIOD_MS); - - try { - long start = System.currentTimeMillis(); - SourceLineResultSetIterator it = SourceLineResultSetIterator.create(dbTester.getDbClient(), dbTester.getSession(), 0L, null); - while (it.hasNext()) { - FileSourcesUpdaterHelper.Row row = it.next(); - assertThat(row.getUpdateRequests().size()).isEqualTo(NUMBER_OF_LINES); - assertThat(row.getFileUuid()).isNotEmpty(); - counter.incrementAndGet(); - } - long end = System.currentTimeMillis(); - long period = end - start; - long throughputPerSecond = 1000L * counter.get() / period; - LOGGER.info(String.format("%d FILE_SOURCES rows scrolled in %d ms (%d rows/second)", counter.get(), period, throughputPerSecond)); - benchmark.expectBetween("Throughput to scroll FILE_SOURCES", throughputPerSecond, 10, 14); - - } finally { - timer.cancel(); - } - } - - private void prepareTable() throws IOException { - LOGGER.info("Populate table FILE_SOURCES"); - FileSourceDao dao = new FileSourceDao(dbTester.myBatis()); - for (int i = 0; i < NUMBER_OF_FILES; i++) { - dao.insert(generateDto()); - } - } - - private FileSourceDto generateDto() throws IOException { - long now = System.currentTimeMillis(); - byte[] data = generateData(); - FileSourceDto dto = new FileSourceDto(); - dto.setCreatedAt(now); - dto.setUpdatedAt(now); - dto.setBinaryData(data); - dto.setDataHash("49d7230271f2bd24c759e54bcd66547d"); - dto.setProjectUuid(PROJECT_UUID); - dto.setFileUuid(Uuids.create()); - dto.setLineHashes(IOUtils.toString(getClass().getResourceAsStream("SourceDbBenchmarkTest/line_hashes.txt"))); - dto.setDataType(FileSourceDto.Type.SOURCE); - return dto; - } - - private byte[] generateData() { - DbFileSources.Data.Builder dataBuilder = DbFileSources.Data.newBuilder(); - DbFileSources.Line.Builder lineBuilder = DbFileSources.Line.newBuilder(); - for (int i = 1; i <= NUMBER_OF_LINES; i++) { - lineBuilder.clear(); - dataBuilder.addLines(lineBuilder - .setLine(i) - .setScmRevision("REVISION_" + i) - .setScmAuthor("a_guy") - .setSource("this is not java code " + i) - .setUtLineHits(i) - .setUtConditions(i + 1) - .setUtCoveredConditions(i) - .setItLineHits(i) - .setItConditions(i + 1) - .setItCoveredConditions(i) - .setOverallLineHits(i) - .setOverallConditions(i + 1) - .setOverallCoveredConditions(i) - .setScmDate(1_500_000_000_000L) - .setHighlighting("2,9,k;9,18,k") - .addAllDuplication(Arrays.asList(19, 33, 141)) - .build()); - } - return FileSourceDto.encodeSourceData(dataBuilder.build()); - } -} diff --git a/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/SourceIndexBenchmarkTest.java b/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/SourceIndexBenchmarkTest.java deleted file mode 100644 index a45f6851771..00000000000 --- a/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/SourceIndexBenchmarkTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -package org.sonar.server.benchmark; - -import java.util.Arrays; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Timer; -import java.util.concurrent.atomic.AtomicLong; -import org.apache.commons.io.FileUtils; -import org.junit.Rule; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.sonar.db.protobuf.DbFileSources; -import org.sonar.server.es.EsClient; -import org.sonar.server.source.index.FileSourcesUpdaterHelper; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndex; -import org.sonar.server.source.index.SourceLineIndexDefinition; -import org.sonar.server.source.index.SourceLineIndexer; -import org.sonar.server.source.index.SourceLineResultSetIterator; -import org.sonar.server.tester.ServerTester; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Performance tests of the Elasticsearch index sourcelines - * - */ -public class SourceIndexBenchmarkTest { - - private static final Logger LOGGER = LoggerFactory.getLogger("benchmarkSourceIndexing"); - private static final long FILES = 1000L; - private static final int LINES_PER_FILE = 3220; - - @Rule - public ServerTester tester = new ServerTester().withEsIndexes(); - - @Rule - public Benchmark benchmark = new Benchmark(); - - @Test - public void benchmark() { - // index source lines - benchmarkIndexing(); - - // execute some queries - benchmarkQueries(); - } - - private void benchmarkIndexing() { - LOGGER.info("Indexing source lines"); - - SourceIterator files = new SourceIterator(FILES, LINES_PER_FILE); - ProgressTask progressTask = new ProgressTask(LOGGER, "files of " + LINES_PER_FILE + " lines", files.count()); - Timer timer = new Timer("SourceIndexer"); - timer.schedule(progressTask, ProgressTask.PERIOD_MS, ProgressTask.PERIOD_MS); - - long start = System.currentTimeMillis(); - tester.get(SourceLineIndexer.class).index(files); - long end = System.currentTimeMillis(); - - timer.cancel(); - long period = end - start; - long nbLines = files.count.get() * LINES_PER_FILE; - long throughputPerSecond = 1000L * nbLines / period; - LOGGER.info(String.format("%d lines indexed in %d ms (%d docs/second)", nbLines, period, throughputPerSecond)); - benchmark.expectAround("Throughput to index source lines", throughputPerSecond, 8950, Benchmark.DEFAULT_ERROR_MARGIN_PERCENTS); - - // be sure that physical files do not evolve during estimation of size - tester.get(EsClient.class).prepareOptimize(SourceLineIndexDefinition.INDEX).setWaitForMerge(true).get(); - long dirSize = FileUtils.sizeOfDirectory(tester.getEsServerHolder().getHomeDir()); - LOGGER.info(String.format("ES dir: " + FileUtils.byteCountToDisplaySize(dirSize))); - benchmark.expectBetween("ES dir size (b)", dirSize, 172L * FileUtils.ONE_MB, 182L * FileUtils.ONE_MB); - } - - private void benchmarkQueries() { - SourceLineIndex index = tester.get(SourceLineIndex.class); - for (int i = 1; i <= 100; i++) { - long start = System.currentTimeMillis(); - List result = index.getLines("FILE" + i, 20, 150); - long end = System.currentTimeMillis(); - assertThat(result).hasSize(131); - LOGGER.info("Request: {} docs in {} ms", result.size(), end - start); - } - // TODO assertions - } - - private static class SourceIterator implements Iterator { - private final long nbFiles; - private final int nbLinesPerFile; - private int currentProject = 0; - private AtomicLong count = new AtomicLong(0L); - private final DbFileSources.Data.Builder dataBuilder = DbFileSources.Data.newBuilder(); - private final DbFileSources.Line.Builder lineBuilder = DbFileSources.Line.newBuilder(); - - SourceIterator(long nbFiles, int nbLinesPerFile) { - this.nbFiles = nbFiles; - this.nbLinesPerFile = nbLinesPerFile; - } - - public AtomicLong count() { - return count; - } - - @Override - public boolean hasNext() { - return count.get() < nbFiles; - } - - @Override - public FileSourcesUpdaterHelper.Row next() { - String projectUuid = "P" + currentProject; - String fileUuid = "FILE" + count.get(); - dataBuilder.clear(); - - for (int indexLine = 1; indexLine <= nbLinesPerFile; indexLine++) { - lineBuilder.clear(); - dataBuilder.addLines(lineBuilder - .setLine(indexLine) - .setScmRevision("REVISION_" + indexLine) - .setScmAuthor("a_guy") - .setSource("this is not java code " + indexLine) - .setUtLineHits(2) - .setUtConditions(8) - .setUtCoveredConditions(2) - .setItLineHits(2) - .setItConditions(8) - .setItCoveredConditions(2) - .setOverallLineHits(2) - .setOverallConditions(8) - .setOverallCoveredConditions(2) - .setScmDate(1_500_000_000_000L) - .setHighlighting("2,9,k;9,18,k") - .addAllDuplication(Arrays.asList(19, 33, 141)) - .build()); - } - count.incrementAndGet(); - if (count.get() % 500 == 0) { - currentProject++; - } - return SourceLineResultSetIterator.toRow(projectUuid, fileUuid, new Date(), dataBuilder.build()); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/core/computation/dbcleaner/IndexPurgeListener.java b/server/sonar-server/src/main/java/org/sonar/core/computation/dbcleaner/IndexPurgeListener.java index 31752ec2d05..010e92c3dea 100644 --- a/server/sonar-server/src/main/java/org/sonar/core/computation/dbcleaner/IndexPurgeListener.java +++ b/server/sonar-server/src/main/java/org/sonar/core/computation/dbcleaner/IndexPurgeListener.java @@ -22,22 +22,18 @@ package org.sonar.core.computation.dbcleaner; import org.sonar.api.server.ServerSide; import org.sonar.db.purge.PurgeListener; -import org.sonar.server.source.index.SourceLineIndexer; import org.sonar.server.test.index.TestIndexer; @ServerSide public class IndexPurgeListener implements PurgeListener { - private final SourceLineIndexer sourceLineIndexer; private final TestIndexer testIndexer; - public IndexPurgeListener(SourceLineIndexer sourceLineIndexer, TestIndexer testIndexer) { - this.sourceLineIndexer = sourceLineIndexer; + public IndexPurgeListener(TestIndexer testIndexer) { this.testIndexer = testIndexer; } @Override public void onComponentDisabling(String uuid) { - sourceLineIndexer.deleteByFile(uuid); testIndexer.deleteByFile(uuid); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java index f4e1c0ad8f4..ee342adf1ad 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java @@ -33,7 +33,6 @@ import org.sonar.db.purge.IdUuidPair; import org.sonar.db.purge.PurgeProfiler; import org.sonar.server.issue.index.IssueAuthorizationIndexer; import org.sonar.server.issue.index.IssueIndexer; -import org.sonar.server.source.index.SourceLineIndexer; import org.sonar.server.test.index.TestIndexer; @ServerSide @@ -42,17 +41,15 @@ public class ComponentCleanerService { private final DbClient dbClient; private final IssueAuthorizationIndexer issueAuthorizationIndexer; private final IssueIndexer issueIndexer; - private final SourceLineIndexer sourceLineIndexer; private final TestIndexer testIndexer; private final ResourceTypes resourceTypes; private final ComponentFinder componentFinder; public ComponentCleanerService(DbClient dbClient, IssueAuthorizationIndexer issueAuthorizationIndexer, IssueIndexer issueIndexer, - SourceLineIndexer sourceLineIndexer, TestIndexer testIndexer, ResourceTypes resourceTypes, ComponentFinder componentFinder) { + TestIndexer testIndexer, ResourceTypes resourceTypes, ComponentFinder componentFinder) { this.dbClient = dbClient; this.issueAuthorizationIndexer = issueAuthorizationIndexer; this.issueIndexer = issueIndexer; - this.sourceLineIndexer = sourceLineIndexer; this.testIndexer = testIndexer; this.resourceTypes = resourceTypes; this.componentFinder = componentFinder; @@ -88,7 +85,6 @@ public class ComponentCleanerService { // optimization : index "issues" is refreshed once at the end issueAuthorizationIndexer.deleteProject(projectUuid, false); issueIndexer.deleteProject(projectUuid, true); - sourceLineIndexer.deleteByProject(projectUuid); testIndexer.deleteByProject(projectUuid); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueAssigner.java b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueAssigner.java index 7355c5b0663..130aa49cd62 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueAssigner.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/issue/IssueAssigner.java @@ -19,32 +19,34 @@ */ package org.sonar.server.computation.issue; -import java.util.Date; +import com.google.common.base.Optional; import java.util.HashMap; -import java.util.List; import java.util.Map; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; import org.sonar.batch.protocol.output.BatchReport; import org.sonar.core.issue.DefaultIssue; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.protobuf.DbFileSources; import org.sonar.server.computation.batch.BatchReportReader; import org.sonar.server.computation.component.Component; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndex; +import org.sonar.server.source.SourceService; /** * Detect the SCM author and SQ assignee. *

* It relies on: *

    - *
  • the SCM information sent in the report for modified files
  • - *
  • the Elasticsearch index of source lines for non-modified files
  • + *
  • SCM information sent in the report for modified files
  • + *
  • sources lines stored in database for non-modified files
  • *
*/ public class IssueAssigner extends IssueVisitor { - private final SourceLineIndex sourceLineIndex; + private final DbClient dbClient; + private final SourceService sourceService; private final BatchReportReader reportReader; private final DefaultAssignee defaultAssigne; private final ScmAccountToUser scmAccountToUser; @@ -53,9 +55,10 @@ public class IssueAssigner extends IssueVisitor { private String lastCommitAuthor = null; private BatchReport.Changesets scmChangesets = null; - public IssueAssigner(SourceLineIndex sourceLineIndex, BatchReportReader reportReader, + public IssueAssigner(DbClient dbClient, SourceService sourceService, BatchReportReader reportReader, ScmAccountToUser scmAccountToUser, DefaultAssignee defaultAssigne) { - this.sourceLineIndex = sourceLineIndex; + this.dbClient = dbClient; + this.sourceService = sourceService; this.reportReader = reportReader; this.scmAccountToUser = scmAccountToUser; this.defaultAssigne = defaultAssigne; @@ -84,7 +87,7 @@ public class IssueAssigner extends IssueVisitor { if (scmChangesets == null) { scmChangesets = loadScmChangesetsFromReport(component); if (scmChangesets == null) { - scmChangesets = loadScmChangesetsFromIndex(component); + scmChangesets = loadScmChangesetsFromDb(component); } computeLastCommitDateAndAuthor(); } @@ -115,38 +118,43 @@ public class IssueAssigner extends IssueVisitor { return reportReader.readChangesets(component.getReportAttributes().getRef()); } - private BatchReport.Changesets loadScmChangesetsFromIndex(Component component) { - List lines = sourceLineIndex.getLines(component.getUuid()); - Map changesetByRevision = new HashMap<>(); - BatchReport.Changesets.Builder scmBuilder = BatchReport.Changesets.newBuilder() - .setComponentRef(component.getReportAttributes().getRef()); - for (SourceLineDoc sourceLine : lines) { - String scmRevision = sourceLine.scmRevision(); - if (scmRevision == null || changesetByRevision.get(scmRevision) == null) { - BatchReport.Changesets.Changeset.Builder changeSetBuilder = BatchReport.Changesets.Changeset.newBuilder(); - String scmAuthor = sourceLine.scmAuthor(); - if (scmAuthor != null) { - changeSetBuilder.setAuthor(scmAuthor); - } - Date scmDate = sourceLine.scmDate(); - if (scmDate != null) { - changeSetBuilder.setDate(scmDate.getTime()); - } - if (scmRevision != null) { - changeSetBuilder.setRevision(scmRevision); - } + private BatchReport.Changesets loadScmChangesetsFromDb(Component component) { + DbSession dbSession = dbClient.openSession(false); + try { + Optional> lines = sourceService.getLines(dbSession, component.getUuid(), 1, Integer.MAX_VALUE); + Map changesetByRevision = new HashMap<>(); + BatchReport.Changesets.Builder scmBuilder = BatchReport.Changesets.newBuilder() + .setComponentRef(component.getReportAttributes().getRef()); + if (lines.isPresent()) { + for (DbFileSources.Line sourceLine : lines.get()) { + String scmRevision = sourceLine.getScmRevision(); + if (scmRevision == null || changesetByRevision.get(scmRevision) == null) { + BatchReport.Changesets.Changeset.Builder changeSetBuilder = BatchReport.Changesets.Changeset.newBuilder(); + if (sourceLine.hasScmAuthor()) { + changeSetBuilder.setAuthor(sourceLine.getScmAuthor()); + } + if (sourceLine.hasScmDate()) { + changeSetBuilder.setDate(sourceLine.getScmDate()); + } + if (scmRevision != null) { + changeSetBuilder.setRevision(scmRevision); + } - BatchReport.Changesets.Changeset changeset = changeSetBuilder.build(); - scmBuilder.addChangeset(changeset); - scmBuilder.addChangesetIndexByLine(scmBuilder.getChangesetCount() - 1); - if (scmRevision != null) { - changesetByRevision.put(scmRevision, changeset); + BatchReport.Changesets.Changeset changeset = changeSetBuilder.build(); + scmBuilder.addChangeset(changeset); + scmBuilder.addChangesetIndexByLine(scmBuilder.getChangesetCount() - 1); + if (scmRevision != null) { + changesetByRevision.put(scmRevision, changeset); + } + } else { + scmBuilder.addChangesetIndexByLine(scmBuilder.getChangesetList().indexOf(changesetByRevision.get(scmRevision))); + } } - } else { - scmBuilder.addChangesetIndexByLine(scmBuilder.getChangesetList().indexOf(changesetByRevision.get(scmRevision))); } + return scmBuilder.build(); + } finally { + dbClient.closeSession(dbSession); } - return scmBuilder.build(); } private void computeLastCommitDateAndAuthor() { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexSourceLinesStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexSourceLinesStep.java deleted file mode 100644 index 237871065bf..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexSourceLinesStep.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.computation.step; - -import org.sonar.server.computation.component.TreeRootHolder; -import org.sonar.server.source.index.SourceLineIndexer; - -public class IndexSourceLinesStep implements ComputationStep { - - private final SourceLineIndexer indexer; - private final TreeRootHolder treeRootHolder; - - public IndexSourceLinesStep(SourceLineIndexer indexer, TreeRootHolder treeRootHolder) { - this.indexer = indexer; - this.treeRootHolder = treeRootHolder; - } - - @Override - public void execute() { - indexer.index(treeRootHolder.getRoot().getUuid()); - } - - @Override - public String getDescription() { - return "Index source lines"; - } - -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java index 2a784b5c1b7..1e70cc7c671 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ReportComputationSteps.java @@ -97,7 +97,6 @@ public class ReportComputationSteps implements ComputationSteps { // ES indexing is done after all db changes ApplyPermissionsStep.class, IndexIssuesStep.class, - IndexSourceLinesStep.class, IndexTestsStep.class, // notifications are sent at the end, so that webapp displays up-to-date information diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java index d57ab537439..b6a1b10960a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueService.java @@ -51,6 +51,7 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; import org.sonar.db.issue.IssueDto; +import org.sonar.db.protobuf.DbFileSources; import org.sonar.server.es.SearchOptions; import org.sonar.server.es.SearchResult; import org.sonar.server.exceptions.BadRequestException; @@ -59,8 +60,7 @@ import org.sonar.server.issue.index.IssueDoc; import org.sonar.server.issue.index.IssueIndex; import org.sonar.server.issue.notification.IssueChangeNotification; import org.sonar.server.notification.NotificationManager; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndex; +import org.sonar.server.source.SourceService; import org.sonar.server.user.UserSession; import org.sonar.server.user.index.UserDoc; import org.sonar.server.user.index.UserIndex; @@ -79,7 +79,7 @@ public class IssueService { private final RuleFinder ruleFinder; private final UserFinder userFinder; private final UserIndex userIndex; - private final SourceLineIndex sourceLineIndex; + private final SourceService sourceService; private final UserSession userSession; public IssueService(DbClient dbClient, IssueIndex issueIndex, @@ -90,7 +90,7 @@ public class IssueService { ActionPlanService actionPlanService, RuleFinder ruleFinder, UserFinder userFinder, - UserIndex userIndex, SourceLineIndex sourceLineIndex, UserSession userSession) { + UserIndex userIndex, SourceService sourceService, UserSession userSession) { this.dbClient = dbClient; this.issueIndex = issueIndex; this.workflow = workflow; @@ -101,7 +101,7 @@ public class IssueService { this.notificationService = notificationService; this.userFinder = userFinder; this.userIndex = userIndex; - this.sourceLineIndex = sourceLineIndex; + this.sourceService = sourceService; this.userSession = userSession; } @@ -111,7 +111,7 @@ public class IssueService { /** * List of available transitions. - *

+ *

* Never return null, but return an empty list if the issue does not exist. */ public List listTransitions(String issueKey) { @@ -241,14 +241,14 @@ public class IssueService { public DefaultIssue createManualIssue(String componentKey, RuleKey ruleKey, @Nullable Integer line, @Nullable String message, @Nullable String severity) { verifyLoggedIn(); - DbSession session = dbClient.openSession(false); + DbSession dbSession = dbClient.openSession(false); try { - Optional componentOptional = dbClient.componentDao().selectByKey(session, componentKey); + Optional componentOptional = dbClient.componentDao().selectByKey(dbSession, componentKey); if (!componentOptional.isPresent()) { throw new BadRequestException(String.format("Component with key '%s' not found", componentKey)); } ComponentDto component = componentOptional.get(); - ComponentDto project = dbClient.componentDao().selectOrFailByUuid(session, component.projectUuid()); + ComponentDto project = dbClient.componentDao().selectOrFailByUuid(dbSession, component.projectUuid()); userSession.checkProjectPermission(UserRole.USER, project.getKey()); if (!ruleKey.isManual()) { @@ -267,7 +267,7 @@ public class IssueService { .severity(Objects.firstNonNull(severity, Severity.MAJOR)) .ruleKey(ruleKey) .reporter(userSession.getLogin()) - .assignee(findSourceLineUser(component.uuid(), line)) + .assignee(findSourceLineUser(dbSession, component.uuid(), line)) .build(); Date now = new Date(); @@ -276,7 +276,7 @@ public class IssueService { issueStorage.save(issue); return issue; } finally { - session.close(); + dbSession.close(); } } @@ -362,12 +362,11 @@ public class IssueService { } @CheckForNull - private String findSourceLineUser(String fileUuid, @Nullable Integer line) { + private String findSourceLineUser(DbSession dbSession, String fileUuid, @Nullable Integer line) { if (line != null) { - SourceLineDoc sourceLine = sourceLineIndex.getLine(fileUuid, line); - String scmAuthor = sourceLine.scmAuthor(); - if (!Strings.isNullOrEmpty(scmAuthor)) { - UserDoc userDoc = userIndex.getNullableByScmAccount(scmAuthor); + Optional sourceLine = sourceService.getLine(dbSession, fileUuid, line); + if (sourceLine.isPresent() && sourceLine.get().hasScmAuthor()) { + UserDoc userDoc = userIndex.getNullableByScmAccount(sourceLine.get().getScmAuthor()); if (userDoc != null) { return userDoc.login(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/BackendCleanup.java b/server/sonar-server/src/main/java/org/sonar/server/platform/BackendCleanup.java index 14b17452dbb..ec2e140e37d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/BackendCleanup.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/BackendCleanup.java @@ -31,7 +31,6 @@ import org.sonar.db.MyBatis; import org.sonar.server.es.EsClient; import org.sonar.server.issue.index.IssueIndexDefinition; import org.sonar.server.search.IndexDefinition; -import org.sonar.server.source.index.SourceLineIndexDefinition; import org.sonar.server.view.index.ViewIndexDefinition; @ServerSide @@ -126,9 +125,7 @@ public class BackendCleanup { deleteManualRules(connection); - // Clear inspection indexes clearIndex(IssueIndexDefinition.INDEX); - clearIndex(SourceLineIndexDefinition.INDEX); clearIndex(ViewIndexDefinition.INDEX); } finally { diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index 9afa4b33ad2..62a58ce92a4 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -271,9 +271,6 @@ import org.sonar.server.rule.ws.RulesWs; import org.sonar.server.rule.ws.TagsAction; import org.sonar.server.source.HtmlSourceDecorator; import org.sonar.server.source.SourceService; -import org.sonar.server.source.index.SourceLineIndex; -import org.sonar.server.source.index.SourceLineIndexDefinition; -import org.sonar.server.source.index.SourceLineIndexer; import org.sonar.server.source.ws.HashAction; import org.sonar.server.source.ws.IndexAction; import org.sonar.server.source.ws.LinesAction; @@ -650,9 +647,6 @@ public class PlatformLevel4 extends PlatformLevel { RawAction.class, IndexAction.class, ScmAction.class, - SourceLineIndexDefinition.class, - SourceLineIndex.class, - SourceLineIndexer.class, // Duplications DuplicationsParser.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/search/IndexSynchronizer.java b/server/sonar-server/src/main/java/org/sonar/server/search/IndexSynchronizer.java index 76c521b2e1a..d4cd912e25a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/search/IndexSynchronizer.java +++ b/server/sonar-server/src/main/java/org/sonar/server/search/IndexSynchronizer.java @@ -25,13 +25,12 @@ import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.db.DbSession; import org.sonar.server.activity.index.ActivityIndexer; -import org.sonar.server.db.DeprecatedDao; import org.sonar.server.db.DbClient; +import org.sonar.server.db.DeprecatedDao; import org.sonar.server.issue.index.IssueAuthorizationIndexer; import org.sonar.server.issue.index.IssueIndexer; import org.sonar.server.qualityprofile.index.ActiveRuleIndex; import org.sonar.server.rule.index.RuleIndex; -import org.sonar.server.source.index.SourceLineIndexer; import org.sonar.server.test.index.TestIndexer; import org.sonar.server.user.index.UserIndexer; import org.sonar.server.view.index.ViewIndexer; @@ -42,7 +41,6 @@ public class IndexSynchronizer { private final DbClient db; private final IndexClient index; - private final SourceLineIndexer sourceLineIndexer; private final TestIndexer testIndexer; private final IssueAuthorizationIndexer issueAuthorizationIndexer; private final IssueIndexer issueIndexer; @@ -56,12 +54,11 @@ public class IndexSynchronizer { * because we need {@link org.sonar.server.issue.index.IssueAuthorizationIndexer} to be executed before * {@link org.sonar.server.issue.index.IssueIndexer} */ - public IndexSynchronizer(DbClient db, IndexClient index, SourceLineIndexer sourceLineIndexer, + public IndexSynchronizer(DbClient db, IndexClient index, TestIndexer testIndexer, IssueAuthorizationIndexer issueAuthorizationIndexer, IssueIndexer issueIndexer, UserIndexer userIndexer, ViewIndexer viewIndexer, ActivityIndexer activityIndexer, Settings settings) { this.db = db; this.index = index; - this.sourceLineIndexer = sourceLineIndexer; this.testIndexer = testIndexer; this.issueAuthorizationIndexer = issueAuthorizationIndexer; this.issueIndexer = issueIndexer; @@ -91,9 +88,6 @@ public class IndexSynchronizer { issueAuthorizationIndexer.setEnabled(true).index(); issueIndexer.setEnabled(true).index(); - LOG.info("Index source lines"); - sourceLineIndexer.setEnabled(true).index(); - LOG.info("Index tests"); testIndexer.setEnabled(true).index(); diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/CharactersReader.java b/server/sonar-server/src/main/java/org/sonar/server/source/CharactersReader.java index 457b460705c..a6f91d54283 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/source/CharactersReader.java +++ b/server/sonar-server/src/main/java/org/sonar/server/source/CharactersReader.java @@ -24,9 +24,6 @@ import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; -/** - * @since 3.6 - */ class CharactersReader { static final int END_OF_STREAM = -1; diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/HtmlSourceDecorator.java b/server/sonar-server/src/main/java/org/sonar/server/source/HtmlSourceDecorator.java index 8d7821999a9..b819a298a02 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/source/HtmlSourceDecorator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/source/HtmlSourceDecorator.java @@ -19,15 +19,11 @@ */ package org.sonar.server.source; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.server.ServerSide; - +import java.util.List; import javax.annotation.CheckForNull; import javax.annotation.Nullable; +import org.apache.commons.lang.StringUtils; -import java.util.List; - -@ServerSide public class HtmlSourceDecorator { @CheckForNull diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/HtmlTextDecorator.java b/server/sonar-server/src/main/java/org/sonar/server/source/HtmlTextDecorator.java index a3408a8b2a3..f298795f2d8 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/source/HtmlTextDecorator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/source/HtmlTextDecorator.java @@ -30,10 +30,6 @@ import org.sonar.api.utils.log.Loggers; import static com.google.common.collect.Lists.newArrayList; - -/** - * @since 3.6 - */ class HtmlTextDecorator { static final char CR_END_OF_LINE = '\r'; diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java b/server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java index 206f8733269..c0d141cd870 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/source/SourceService.java @@ -17,53 +17,114 @@ * 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; -import org.apache.commons.lang.ObjectUtils; -import org.elasticsearch.common.collect.Lists; -import org.sonar.api.server.ServerSide; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndex; - -import javax.annotation.Nullable; +import com.google.common.base.Function; +import com.google.common.base.Functions; +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import javax.annotation.Nonnull; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.protobuf.DbFileSources; +import org.sonar.db.source.FileSourceDto; -import java.util.List; - -@ServerSide public class SourceService { - private final HtmlSourceDecorator sourceDecorator; - private final SourceLineIndex sourceLineIndex; + private final DbClient dbClient; + private final HtmlSourceDecorator htmlDecorator; - public SourceService(HtmlSourceDecorator sourceDecorator, SourceLineIndex sourceLineIndex) { - this.sourceDecorator = sourceDecorator; - this.sourceLineIndex = sourceLineIndex; + public SourceService(DbClient dbClient, HtmlSourceDecorator htmlDecorator) { + this.dbClient = dbClient; + this.htmlDecorator = htmlDecorator; } /** - * Raw lines of source file. + * Returns a range of lines as raw db data. User permission is not verified. + * @param from starts from 1 + * @param toInclusive starts from 1, must be greater than or equal param {@code from} */ - public List getLinesAsTxt(String fileUuid, @Nullable Integer fromParam, @Nullable Integer toParam) { - int from = (Integer) ObjectUtils.defaultIfNull(fromParam, 1); - int to = (Integer) ObjectUtils.defaultIfNull(toParam, Integer.MAX_VALUE); - List lines = Lists.newArrayList(); - for (SourceLineDoc lineDoc : sourceLineIndex.getLines(fileUuid, from, to)) { - lines.add(lineDoc.source()); - } - return lines; + public Optional> getLines(DbSession dbSession, String fileUuid, int from, int toInclusive) { + return getLines(dbSession, fileUuid, from, toInclusive, Functions.identity()); + } + + /** + * Returns a range of lines as raw text. + * @see #getLines(DbSession, String, int, int) + */ + public Optional> getLinesAsRawText(DbSession dbSession, String fileUuid, int from, int toInclusive) { + return getLines(dbSession, fileUuid, from, toInclusive, LineToRaw.INSTANCE); + } + + public Optional> getLinesAsHtml(DbSession dbSession, String fileUuid, int from, int toInclusive) { + return getLines(dbSession, fileUuid, from, toInclusive, lineToHtml()); } /** - * Decorated lines of source file. + * Returns a single line from a source file. {@code Optional.absent()} is returned if the + * file or the line do not exist. + * @param line starts from 1 */ - public List getLinesAsHtml(String fileUuid, @Nullable Integer fromParam, @Nullable Integer toParam) { - int from = (Integer) ObjectUtils.defaultIfNull(fromParam, 1); - int to = (Integer) ObjectUtils.defaultIfNull(toParam, Integer.MAX_VALUE); - List lines = Lists.newArrayList(); - for (SourceLineDoc lineDoc : sourceLineIndex.getLines(fileUuid, from, to)) { - lines.add(sourceDecorator.getDecoratedSourceAsHtml(lineDoc.source(), lineDoc.highlighting(), lineDoc.symbols())); + public Optional getLine(DbSession dbSession, String fileUuid, int line) { + verifyLine(line); + FileSourceDto dto = dbClient.fileSourceDao().selectSourceByFileUuid(dbSession, fileUuid); + if (dto == null) { + return Optional.absent(); + } + DbFileSources.Data data = dto.getSourceData(); + return FluentIterable.from(data.getLinesList()) + .filter(new IsGreaterOrEqualThanLine(line)) + .first(); + } + + private Optional> getLines(DbSession dbSession, String fileUuid, int from, int toInclusive, Function function) { + verifyLine(from); + Preconditions.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); + if (dto == null) { + return Optional.absent(); + } + DbFileSources.Data data = dto.getSourceData(); + return Optional.of((Iterable) FluentIterable.from(data.getLinesList()) + .filter(new IsGreaterOrEqualThanLine(from)) + .limit(toInclusive - from + 1) + .transform(function)); + } + + private static void verifyLine(int line) { + Preconditions.checkArgument(line >= 1, String.format("Line number must start at 1, got %d", line)); + } + + private Function lineToHtml() { + return new Function() { + @Override + public String apply(@Nonnull DbFileSources.Line line) { + return htmlDecorator.getDecoratedSourceAsHtml(line.getSource(), line.getHighlighting(), line.getSymbols()); + } + }; + } + + private enum LineToRaw implements Function { + INSTANCE; + @Override + public String apply(@Nonnull DbFileSources.Line line) { + return line.getSource(); + } + + } + + private class IsGreaterOrEqualThanLine implements Predicate { + private final int from; + + IsGreaterOrEqualThanLine(int from) { + this.from = from; + } + + @Override + public boolean apply(@Nonnull DbFileSources.Line line) { + return line.hasLine() && line.getLine() >= from; } - return lines; } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineDoc.java b/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineDoc.java deleted file mode 100644 index ddf68949df2..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineDoc.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.source.index; - -import com.google.common.collect.ImmutableList; -import org.sonar.server.search.BaseDoc; -import org.sonar.server.search.IndexUtils; - -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; - -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -public class SourceLineDoc extends BaseDoc { - - public SourceLineDoc(Map fields) { - super(fields); - } - - public SourceLineDoc() { - this(new HashMap(20)); - } - - public String projectUuid() { - return getField(SourceLineIndexDefinition.FIELD_PROJECT_UUID); - } - - public SourceLineDoc setProjectUuid(String projectUuid) { - setField(SourceLineIndexDefinition.FIELD_PROJECT_UUID, projectUuid); - return this; - } - - public String fileUuid() { - return getField(SourceLineIndexDefinition.FIELD_FILE_UUID); - } - - public SourceLineDoc setFileUuid(String fileUuid) { - setField(SourceLineIndexDefinition.FIELD_FILE_UUID, fileUuid); - return this; - } - - public int line() { - return ((Number) getField(SourceLineIndexDefinition.FIELD_LINE)).intValue(); - } - - public SourceLineDoc setLine(int line) { - setField(SourceLineIndexDefinition.FIELD_LINE, line); - return this; - } - - @CheckForNull - public String scmRevision() { - return getNullableField(SourceLineIndexDefinition.FIELD_SCM_REVISION); - } - - public SourceLineDoc setScmRevision(@Nullable String scmRevision) { - setField(SourceLineIndexDefinition.FIELD_SCM_REVISION, scmRevision); - return this; - } - - @CheckForNull - public String scmAuthor() { - return getNullableField(SourceLineIndexDefinition.FIELD_SCM_AUTHOR); - } - - public SourceLineDoc setScmAuthor(@Nullable String scmAuthor) { - setField(SourceLineIndexDefinition.FIELD_SCM_AUTHOR, scmAuthor); - return this; - } - - @CheckForNull - public Date scmDate() { - return IndexUtils.parseDateTime(this.getNullableField(SourceLineIndexDefinition.FIELD_SCM_DATE)); - } - - public SourceLineDoc setScmDate(@Nullable Date scmDate) { - setField(SourceLineIndexDefinition.FIELD_SCM_DATE, scmDate); - return this; - } - - @CheckForNull - public String highlighting() { - return getNullableField(SourceLineIndexDefinition.FIELD_HIGHLIGHTING); - } - - public SourceLineDoc setHighlighting(@Nullable String s) { - setField(SourceLineIndexDefinition.FIELD_HIGHLIGHTING, s); - return this; - } - - public String source() { - return getField(SourceLineIndexDefinition.FIELD_SOURCE); - } - - public SourceLineDoc setSource(@Nullable String source) { - setField(SourceLineIndexDefinition.FIELD_SOURCE, source); - return this; - } - - public Date updateDate() { - return getFieldAsDate(SourceLineIndexDefinition.FIELD_UPDATED_AT); - } - - public SourceLineDoc setUpdateDate(@Nullable Date updatedAt) { - setField(SourceLineIndexDefinition.FIELD_UPDATED_AT, updatedAt); - return this; - } - - @CheckForNull - public Integer utLineHits() { - Number lineHits = getNullableField(SourceLineIndexDefinition.FIELD_UT_LINE_HITS); - return lineHits == null ? null : lineHits.intValue(); - } - - public SourceLineDoc setUtLineHits(@Nullable Integer lineHits) { - setField(SourceLineIndexDefinition.FIELD_UT_LINE_HITS, lineHits); - return this; - } - - @CheckForNull - public Integer utConditions() { - Number conditions = getNullableField(SourceLineIndexDefinition.FIELD_UT_CONDITIONS); - return conditions == null ? null : conditions.intValue(); - } - - public SourceLineDoc setUtConditions(@Nullable Integer conditions) { - setField(SourceLineIndexDefinition.FIELD_UT_CONDITIONS, conditions); - return this; - } - - @CheckForNull - public Integer utCoveredConditions() { - Number coveredConditions = getNullableField(SourceLineIndexDefinition.FIELD_UT_COVERED_CONDITIONS); - return coveredConditions == null ? null : coveredConditions.intValue(); - } - - public SourceLineDoc setUtCoveredConditions(@Nullable Integer coveredConditions) { - setField(SourceLineIndexDefinition.FIELD_UT_COVERED_CONDITIONS, coveredConditions); - return this; - } - - @CheckForNull - public Integer itLineHits() { - Number lineHits = getNullableField(SourceLineIndexDefinition.FIELD_IT_LINE_HITS); - return lineHits == null ? null : lineHits.intValue(); - } - - public SourceLineDoc setItLineHits(@Nullable Integer lineHits) { - setField(SourceLineIndexDefinition.FIELD_IT_LINE_HITS, lineHits); - return this; - } - - @CheckForNull - public Integer itConditions() { - Number conditions = getNullableField(SourceLineIndexDefinition.FIELD_IT_CONDITIONS); - return conditions == null ? null : conditions.intValue(); - } - - public SourceLineDoc setItConditions(@Nullable Integer conditions) { - setField(SourceLineIndexDefinition.FIELD_IT_CONDITIONS, conditions); - return this; - } - - @CheckForNull - public Integer itCoveredConditions() { - Number coveredConditions = (Number) getNullableField(SourceLineIndexDefinition.FIELD_IT_COVERED_CONDITIONS); - return coveredConditions == null ? null : coveredConditions.intValue(); - } - - public SourceLineDoc setItCoveredConditions(@Nullable Integer coveredConditions) { - setField(SourceLineIndexDefinition.FIELD_IT_COVERED_CONDITIONS, coveredConditions); - return this; - } - - @CheckForNull - public Integer overallLineHits() { - Number lineHits = getNullableField(SourceLineIndexDefinition.FIELD_OVERALL_LINE_HITS); - return lineHits == null ? null : lineHits.intValue(); - } - - public SourceLineDoc setOverallLineHits(@Nullable Integer lineHits) { - setField(SourceLineIndexDefinition.FIELD_OVERALL_LINE_HITS, lineHits); - return this; - } - - @CheckForNull - public Integer overallConditions() { - Number conditions = getNullableField(SourceLineIndexDefinition.FIELD_OVERALL_CONDITIONS); - return conditions == null ? null : conditions.intValue(); - } - - public SourceLineDoc setOverallConditions(@Nullable Integer conditions) { - setField(SourceLineIndexDefinition.FIELD_OVERALL_CONDITIONS, conditions); - return this; - } - - @CheckForNull - public Integer overallCoveredConditions() { - Number coveredConditions = getNullableField(SourceLineIndexDefinition.FIELD_OVERALL_COVERED_CONDITIONS); - return coveredConditions == null ? null : coveredConditions.intValue(); - } - - public SourceLineDoc setOverallCoveredConditions(@Nullable Integer coveredConditions) { - setField(SourceLineIndexDefinition.FIELD_OVERALL_COVERED_CONDITIONS, coveredConditions); - return this; - } - - @CheckForNull - public String symbols() { - return getNullableField(SourceLineIndexDefinition.FIELD_SYMBOLS); - } - - public SourceLineDoc setSymbols(@Nullable String s) { - setField(SourceLineIndexDefinition.FIELD_SYMBOLS, s); - return this; - } - - public Collection duplications() { - Collection duplications = getNullableField(SourceLineIndexDefinition.FIELD_DUPLICATIONS); - return duplications == null ? ImmutableList.of() : duplications; - } - - public SourceLineDoc setDuplications(@Nullable Collection dups) { - setField(SourceLineIndexDefinition.FIELD_DUPLICATIONS, dups == null ? ImmutableList.of() : dups); - return this; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndex.java b/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndex.java deleted file mode 100644 index 60b9efd6af9..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndex.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.source.index; - -import com.google.common.collect.Lists; -import org.elasticsearch.action.search.SearchRequestBuilder; -import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.search.SearchHit; -import org.elasticsearch.search.sort.SortOrder; -import org.sonar.server.es.BaseIndex; -import org.sonar.server.es.EsClient; -import org.sonar.server.exceptions.NotFoundException; - -import javax.annotation.CheckForNull; -import java.util.Date; -import java.util.List; - -import static com.google.common.base.Preconditions.checkArgument; - -public class SourceLineIndex extends BaseIndex { - - private static final int MAX_RESULT = 500000; - - public SourceLineIndex(EsClient esClient) { - super(esClient); - } - - /** - * Get lines of code for file with UUID fileUuid with line numbers - * between from and to (both inclusive). Line numbers - * start at 1. - * The max number of returned lines will be 500_000. - * - * @param fileUuid the UUID of the file for which to get source code - * @param from starting line; must be strictly positive - * @param to ending line; must be greater than or equal to to - */ - public List getLines(String fileUuid, int from, int to) { - checkArgument(from > 0, "Minimum value for 'from' is 1"); - checkArgument(to >= from, "'to' must be larger than or equal to 'from'"); - List lines = Lists.newArrayList(); - int size = 1 + to - from; - if (size > MAX_RESULT) { - size = MAX_RESULT; - } - int toLimited = size + from - 1; - - for (SearchHit hit : getClient().prepareSearch(SourceLineIndexDefinition.INDEX) - .setTypes(SourceLineIndexDefinition.TYPE) - .setSize(size) - .setQuery(QueryBuilders.boolQuery() - .must(QueryBuilders.termQuery(SourceLineIndexDefinition.FIELD_FILE_UUID, fileUuid)) - .must(QueryBuilders.rangeQuery(SourceLineIndexDefinition.FIELD_LINE) - .gte(from) - .lte(toLimited))) - .addSort(SourceLineIndexDefinition.FIELD_LINE, SortOrder.ASC) - .get().getHits().getHits()) { - lines.add(new SourceLineDoc(hit.sourceAsMap())); - } - - return lines; - } - - /** - * Get lines of code for file with UUID fileUuid. - */ - public List getLines(String fileUuid) { - List lines = Lists.newArrayList(); - - for (SearchHit hit : getClient().prepareSearch(SourceLineIndexDefinition.INDEX) - .setTypes(SourceLineIndexDefinition.TYPE) - .setQuery(QueryBuilders.boolQuery() - .must(QueryBuilders.termQuery(SourceLineIndexDefinition.FIELD_FILE_UUID, fileUuid))) - .addSort(SourceLineIndexDefinition.FIELD_LINE, SortOrder.ASC) - .get().getHits().getHits()) { - lines.add(new SourceLineDoc(hit.sourceAsMap())); - } - - return lines; - } - - public SourceLineDoc getLine(String fileUuid, int line) { - checkArgument(line > 0, "Line should be greater than 0"); - SearchRequestBuilder request = getClient().prepareSearch(SourceLineIndexDefinition.INDEX) - .setTypes(SourceLineIndexDefinition.TYPE) - .setSize(1) - .setQuery(QueryBuilders.boolQuery() - .must(QueryBuilders.termQuery(SourceLineIndexDefinition.FIELD_FILE_UUID, fileUuid)) - .must(QueryBuilders.rangeQuery(SourceLineIndexDefinition.FIELD_LINE) - .gte(line) - .lte(line))) - .addSort(SourceLineIndexDefinition.FIELD_LINE, SortOrder.ASC); - - SearchHit[] result = request.get().getHits().getHits(); - if (result.length == 1) { - return new SourceLineDoc(result[0].sourceAsMap()); - } - throw new NotFoundException(String.format("No source found on line %s for file '%s'", line, fileUuid)); - } - - @CheckForNull - public Date lastCommitDateOnProject(String projectUuid) { - SearchRequestBuilder request = getClient().prepareSearch(SourceLineIndexDefinition.INDEX) - .setTypes(SourceLineIndexDefinition.TYPE) - .setSize(1) - .setQuery(QueryBuilders.boolQuery() - .must(QueryBuilders.termQuery(SourceLineIndexDefinition.FIELD_PROJECT_UUID, projectUuid))) - .setFetchSource(new String[]{SourceLineIndexDefinition.FIELD_SCM_DATE}, null) - .addSort(SourceLineIndexDefinition.FIELD_SCM_DATE, SortOrder.DESC); - - SearchHit[] result = request.get().getHits().getHits(); - if (result.length > 0) { - return new SourceLineDoc(result[0].sourceAsMap()).scmDate(); - } - - return null; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndexDefinition.java b/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndexDefinition.java deleted file mode 100644 index f979520e6ae..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndexDefinition.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.source.index; - -import com.google.common.collect.ImmutableMap; -import org.sonar.api.config.Settings; -import org.sonar.server.es.IndexDefinition; -import org.sonar.server.es.NewIndex; - -public class SourceLineIndexDefinition implements IndexDefinition { - - public static final String INDEX = "sourcelines"; - public static final String TYPE = "sourceline"; - public static final String FIELD_PROJECT_UUID = "projectUuid"; - public static final String FIELD_FILE_UUID = "fileUuid"; - public static final String FIELD_LINE = "line"; - public static final String FIELD_SCM_REVISION = "scmRevision"; - public static final String FIELD_SCM_AUTHOR = "scmAuthor"; - public static final String FIELD_SCM_DATE = "scmDate"; - public static final String FIELD_HIGHLIGHTING = "highlighting"; - public static final String FIELD_SOURCE = "source"; - public static final String FIELD_UT_LINE_HITS = "utLineHits"; - public static final String FIELD_UT_CONDITIONS = "utConditions"; - public static final String FIELD_UT_COVERED_CONDITIONS = "utCoveredConditions"; - public static final String FIELD_IT_LINE_HITS = "itLineHits"; - public static final String FIELD_IT_CONDITIONS = "itConditions"; - public static final String FIELD_IT_COVERED_CONDITIONS = "itCoveredConditions"; - public static final String FIELD_OVERALL_LINE_HITS = "overallLineHits"; - public static final String FIELD_OVERALL_CONDITIONS = "overallConditions"; - public static final String FIELD_OVERALL_COVERED_CONDITIONS = "overallCoveredConditions"; - public static final String FIELD_SYMBOLS = "symbols"; - public static final String FIELD_DUPLICATIONS = "duplications"; - public static final String FIELD_UPDATED_AT = "updatedAt"; - - private final Settings settings; - - public SourceLineIndexDefinition(Settings settings) { - this.settings = settings; - } - - @Override - public void define(IndexDefinitionContext context) { - NewIndex index = context.create(INDEX); - - index.refreshHandledByIndexer(); - index.setShards(settings); - - // type "sourceline" - NewIndex.NewIndexType mapping = index.createType(TYPE); - mapping.setAttribute("_routing", ImmutableMap.of("required", true, "path", FIELD_PROJECT_UUID)); - mapping.stringFieldBuilder(FIELD_PROJECT_UUID).build(); - mapping.stringFieldBuilder(FIELD_FILE_UUID).build(); - mapping.createIntegerField(FIELD_LINE); - mapping.stringFieldBuilder(FIELD_SCM_REVISION).disableSearch().build(); - mapping.stringFieldBuilder(FIELD_SCM_AUTHOR).disableSearch().build(); - mapping.createDateTimeField(FIELD_SCM_DATE); - mapping.stringFieldBuilder(FIELD_HIGHLIGHTING).disableSearch().build(); - mapping.stringFieldBuilder(FIELD_SOURCE).disableSearch().build(); - mapping.createIntegerField(FIELD_UT_LINE_HITS); - mapping.createIntegerField(FIELD_UT_CONDITIONS); - mapping.createIntegerField(FIELD_UT_COVERED_CONDITIONS); - mapping.createIntegerField(FIELD_IT_LINE_HITS); - mapping.createIntegerField(FIELD_IT_CONDITIONS); - mapping.createIntegerField(FIELD_IT_COVERED_CONDITIONS); - mapping.createIntegerField(FIELD_OVERALL_LINE_HITS); - mapping.createIntegerField(FIELD_OVERALL_CONDITIONS); - mapping.createIntegerField(FIELD_OVERALL_COVERED_CONDITIONS); - mapping.stringFieldBuilder(FIELD_SYMBOLS).disableSearch().build(); - mapping.createShortField(FIELD_DUPLICATIONS); - mapping.createDateTimeField(FIELD_UPDATED_AT); - } - - public static String docKey(String fileUuid, int line) { - return String.format("%s_%d", fileUuid, line); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndexer.java b/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndexer.java deleted file mode 100644 index 52864517d15..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineIndexer.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.source.index; - -import java.util.Iterator; -import javax.annotation.Nullable; -import org.elasticsearch.action.search.SearchRequestBuilder; -import org.elasticsearch.action.update.UpdateRequest; -import org.elasticsearch.index.query.FilterBuilders; -import org.elasticsearch.index.query.QueryBuilders; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.server.es.BaseIndexer; -import org.sonar.server.es.BulkIndexer; -import org.sonar.server.es.EsClient; - -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_FILE_UUID; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_PROJECT_UUID; - -/** - * Add to Elasticsearch index {@link SourceLineIndexDefinition} the rows of - * db table FILE_SOURCES of type SOURCE that are not indexed yet - */ -public class SourceLineIndexer extends BaseIndexer { - - private final DbClient dbClient; - - public SourceLineIndexer(DbClient dbClient, EsClient esClient) { - super(esClient, 0L, SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, SourceLineIndexDefinition.FIELD_UPDATED_AT); - this.dbClient = dbClient; - } - - public void index(final String projectUuid) { - super.index(new IndexerTask() { - @Override - public long index(long lastUpdatedAt) { - return doIndex(lastUpdatedAt, projectUuid); - } - }); - } - - @Override - protected long doIndex(long lastUpdatedAt) { - return doIndex(lastUpdatedAt, null); - } - - private long doIndex(long lastUpdatedAt, @Nullable String projectUuid) { - final BulkIndexer bulk = new BulkIndexer(esClient, SourceLineIndexDefinition.INDEX); - bulk.setLarge(lastUpdatedAt == 0L); - - DbSession dbSession = dbClient.openSession(false); - try { - SourceLineResultSetIterator rowIt = SourceLineResultSetIterator.create(dbClient, dbSession, lastUpdatedAt, projectUuid); - long maxUpdatedAt = doIndex(bulk, rowIt); - rowIt.close(); - return maxUpdatedAt; - - } finally { - dbSession.close(); - } - } - - public long index(Iterator dbRows) { - BulkIndexer bulk = new BulkIndexer(esClient, SourceLineIndexDefinition.INDEX); - return doIndex(bulk, dbRows); - } - - private long doIndex(BulkIndexer bulk, Iterator dbRows) { - long maxUpdatedAt = 0L; - bulk.start(); - while (dbRows.hasNext()) { - FileSourcesUpdaterHelper.Row row = dbRows.next(); - addDeleteRequestsForLinesGreaterThan(bulk, row); - for (UpdateRequest updateRequest : row.getUpdateRequests()) { - bulk.add(updateRequest); - } - maxUpdatedAt = Math.max(maxUpdatedAt, row.getUpdatedAt()); - } - bulk.stop(); - return maxUpdatedAt; - } - - /** - * Use-case: - * - file had 10 lines in previous analysis - * - same file has now 5 lines - * Lines 6 to 10 must be removed from index. - */ - private void addDeleteRequestsForLinesGreaterThan(BulkIndexer bulk, FileSourcesUpdaterHelper.Row fileRow) { - int numberOfLines = fileRow.getUpdateRequests().size(); - SearchRequestBuilder searchRequest = esClient.prepareSearch(SourceLineIndexDefinition.INDEX) - .setTypes(SourceLineIndexDefinition.TYPE) - .setRouting(fileRow.getProjectUuid()) - .setQuery(QueryBuilders.filteredQuery( - QueryBuilders.matchAllQuery(), - FilterBuilders.boolFilter() - .must(FilterBuilders.termFilter(FIELD_FILE_UUID, fileRow.getFileUuid()).cache(false)) - .must(FilterBuilders.rangeFilter(SourceLineIndexDefinition.FIELD_LINE).gt(numberOfLines).cache(false)) - .cache(false) - )); - bulk.addDeletion(searchRequest); - } - - public void deleteByFile(String fileUuid) { - // TODO would be great to have the projectUuid for routing - SearchRequestBuilder searchRequest = esClient.prepareSearch(SourceLineIndexDefinition.INDEX) - .setTypes(SourceLineIndexDefinition.TYPE) - .setQuery(QueryBuilders.filteredQuery( - QueryBuilders.matchAllQuery(), - FilterBuilders.termFilter(FIELD_FILE_UUID, fileUuid).cache(false))); - BulkIndexer.delete(esClient, SourceLineIndexDefinition.INDEX, searchRequest); - } - - public void deleteByProject(String projectUuid) { - SearchRequestBuilder searchRequest = esClient.prepareSearch(SourceLineIndexDefinition.INDEX) - .setRouting(projectUuid) - .setTypes(SourceLineIndexDefinition.TYPE) - .setQuery(QueryBuilders.filteredQuery( - QueryBuilders.matchAllQuery(), - FilterBuilders.termFilter(FIELD_PROJECT_UUID, projectUuid).cache(false))); - BulkIndexer.delete(esClient, SourceLineIndexDefinition.INDEX, searchRequest); - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineResultSetIterator.java b/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineResultSetIterator.java deleted file mode 100644 index d12bb5a8fd6..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/source/index/SourceLineResultSetIterator.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.source.index; - -import java.io.ByteArrayOutputStream; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Date; -import javax.annotation.Nullable; -import org.elasticsearch.action.update.UpdateRequest; -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 static org.sonar.server.source.index.FileSourcesUpdaterHelper.Row; - -/** - * Scroll over table FILE_SOURCES of type SOURCE and directly parse data required to - * populate the index sourcelines - */ -public class SourceLineResultSetIterator extends ResultSetIterator { - - public static SourceLineResultSetIterator create(DbClient dbClient, DbSession session, long afterDate, @Nullable String projectUuid) { - try { - return new SourceLineResultSetIterator(FileSourcesUpdaterHelper.preparedStatementToSelectFileSources(dbClient, session, FileSourceDto.Type.SOURCE, afterDate, - projectUuid)); - } catch (SQLException e) { - throw new IllegalStateException("Fail to prepare SQL request to select all file sources", e); - } - } - - private SourceLineResultSetIterator(PreparedStatement stmt) throws SQLException { - super(stmt); - } - - @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)); - DbFileSources.Data data = FileSourceDto.decodeSourceData(rs.getBinaryStream(4)); - return toRow(projectUuid, fileUuid, updatedAt, data); - } - - /** - * Convert protobuf message to data required for Elasticsearch indexing - */ - public static Row toRow(String projectUuid, String fileUuid, Date updatedAt, DbFileSources.Data data) { - Row result = new Row(projectUuid, fileUuid, updatedAt.getTime()); - for (DbFileSources.Line line : data.getLinesList()) { - ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - - // all the fields must be present, even if value is null - JsonWriter writer = JsonWriter.of(new OutputStreamWriter(bytes, StandardCharsets.UTF_8)).setSerializeNulls(true); - writer.beginObject(); - writer.prop(SourceLineIndexDefinition.FIELD_PROJECT_UUID, projectUuid); - writer.prop(SourceLineIndexDefinition.FIELD_FILE_UUID, fileUuid); - writer.prop(SourceLineIndexDefinition.FIELD_LINE, line.getLine()); - writer.prop(SourceLineIndexDefinition.FIELD_UPDATED_AT, EsUtils.formatDateTime(updatedAt)); - writer.prop(SourceLineIndexDefinition.FIELD_SCM_REVISION, line.getScmRevision()); - writer.prop(SourceLineIndexDefinition.FIELD_SCM_AUTHOR, line.getScmAuthor()); - writer.prop(SourceLineIndexDefinition.FIELD_SCM_DATE, EsUtils.formatDateTime(line.hasScmDate() ? new Date(line.getScmDate()) : null)); - - // unit tests - if (line.hasUtLineHits()) { - writer.prop(SourceLineIndexDefinition.FIELD_UT_LINE_HITS, line.getUtLineHits()); - } else { - writer.name(SourceLineIndexDefinition.FIELD_UT_LINE_HITS).valueObject(null); - } - if (line.hasUtConditions()) { - writer.prop(SourceLineIndexDefinition.FIELD_UT_CONDITIONS, line.getUtConditions()); - } else { - writer.name(SourceLineIndexDefinition.FIELD_UT_CONDITIONS).valueObject(null); - } - if (line.hasUtCoveredConditions()) { - writer.prop(SourceLineIndexDefinition.FIELD_UT_COVERED_CONDITIONS, line.getUtCoveredConditions()); - } else { - writer.name(SourceLineIndexDefinition.FIELD_UT_COVERED_CONDITIONS).valueObject(null); - } - - // IT - if (line.hasItLineHits()) { - writer.prop(SourceLineIndexDefinition.FIELD_IT_LINE_HITS, line.getItLineHits()); - } else { - writer.name(SourceLineIndexDefinition.FIELD_IT_LINE_HITS).valueObject(null); - } - if (line.hasItConditions()) { - writer.prop(SourceLineIndexDefinition.FIELD_IT_CONDITIONS, line.getItConditions()); - } else { - writer.name(SourceLineIndexDefinition.FIELD_IT_CONDITIONS).valueObject(null); - } - if (line.hasItCoveredConditions()) { - writer.prop(SourceLineIndexDefinition.FIELD_IT_COVERED_CONDITIONS, line.getItCoveredConditions()); - } else { - writer.name(SourceLineIndexDefinition.FIELD_IT_COVERED_CONDITIONS).valueObject(null); - } - - // Overall coverage - if (line.hasOverallLineHits()) { - writer.prop(SourceLineIndexDefinition.FIELD_OVERALL_LINE_HITS, line.getOverallLineHits()); - } else { - writer.name(SourceLineIndexDefinition.FIELD_OVERALL_LINE_HITS).valueObject(null); - } - if (line.hasOverallConditions()) { - writer.prop(SourceLineIndexDefinition.FIELD_OVERALL_CONDITIONS, line.getOverallConditions()); - } else { - writer.name(SourceLineIndexDefinition.FIELD_OVERALL_CONDITIONS).valueObject(null); - } - if (line.hasOverallCoveredConditions()) { - writer.prop(SourceLineIndexDefinition.FIELD_OVERALL_COVERED_CONDITIONS, line.getOverallCoveredConditions()); - } else { - writer.name(SourceLineIndexDefinition.FIELD_OVERALL_COVERED_CONDITIONS).valueObject(null); - } - - if (line.hasHighlighting()) { - writer.prop(SourceLineIndexDefinition.FIELD_HIGHLIGHTING, line.getHighlighting()); - } else { - writer.name(SourceLineIndexDefinition.FIELD_HIGHLIGHTING).valueObject(null); - } - if (line.hasSymbols()) { - writer.prop(SourceLineIndexDefinition.FIELD_SYMBOLS, line.getSymbols()); - } else { - writer.name(SourceLineIndexDefinition.FIELD_SYMBOLS).valueObject(null); - } - writer.name(SourceLineIndexDefinition.FIELD_DUPLICATIONS).valueObject(line.getDuplicationList()); - writer.prop(SourceLineIndexDefinition.FIELD_SOURCE, line.hasSource() ? line.getSource() : null); - writer.endObject().close(); - - // 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(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, SourceLineIndexDefinition.docKey(fileUuid, line.getLine())) - .routing(projectUuid) - .doc(jsonDoc) - .upsert(jsonDoc); - result.getUpdateRequests().add(updateRequest); - } - return result; - } -} diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/ws/LinesAction.java b/server/sonar-server/src/main/java/org/sonar/server/source/ws/LinesAction.java index 4db94f014b1..efdfe79ad5b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/source/ws/LinesAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/source/ws/LinesAction.java @@ -19,11 +19,10 @@ */ package org.sonar.server.source.ws; +import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.io.Resources; import java.util.Date; -import java.util.List; -import org.apache.commons.lang.ObjectUtils; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -32,26 +31,31 @@ import org.sonar.api.utils.text.JsonWriter; import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbSession; -import org.sonar.db.MyBatis; import org.sonar.db.component.ComponentDto; +import org.sonar.db.protobuf.DbFileSources; +import org.sonar.server.component.ComponentFinder; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.source.HtmlSourceDecorator; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndex; +import org.sonar.server.source.SourceService; import org.sonar.server.user.UserSession; public class LinesAction implements SourcesWsAction { private static final String PARAM_UUID = "uuid"; private static final String PARAM_KEY = "key"; + private static final String PARAM_FROM = "from"; + private static final String PARAM_TO = "to"; - private final SourceLineIndex sourceLineIndex; + private final ComponentFinder componentFinder; + private final SourceService sourceService; private final HtmlSourceDecorator htmlSourceDecorator; private final DbClient dbClient; private final UserSession userSession; - public LinesAction(DbClient dbClient, SourceLineIndex sourceLineIndex, HtmlSourceDecorator htmlSourceDecorator, UserSession userSession) { - this.sourceLineIndex = sourceLineIndex; + public LinesAction(ComponentFinder componentFinder, DbClient dbClient, SourceService sourceService, + HtmlSourceDecorator htmlSourceDecorator, UserSession userSession) { + this.componentFinder = componentFinder; + this.sourceService = sourceService; this.htmlSourceDecorator = htmlSourceDecorator; this.dbClient = dbClient; this.userSession = userSession; @@ -91,83 +95,75 @@ public class LinesAction implements SourcesWsAction { .setExampleValue("org.sample:src/main/java/Foo.java"); action - .createParam("from") - .setDescription("First line to return. Starts at 1") + .createParam(PARAM_FROM) + .setDescription("First line to return. Starts from 1") .setExampleValue("10") .setDefaultValue("1"); action - .createParam("to") - .setDescription("Last line to return (inclusive)") + .createParam(PARAM_TO) + .setDescription("Optional last line to return (inclusive). It must be greater than " + + "or equal to parameter 'from'. If unset, then all the lines greater than or equal to 'from' " + + "are returned.") .setExampleValue("20"); } @Override public void handle(Request request, Response response) { - ComponentDto component = loadComponent(request); - userSession.checkProjectUuidPermission(UserRole.CODEVIEWER, component.projectUuid()); - - int from = Math.max(request.mandatoryParamAsInt("from"), 1); - int to = (Integer) ObjectUtils.defaultIfNull(request.paramAsInt("to"), Integer.MAX_VALUE); + DbSession dbSession = dbClient.openSession(false); + try { + ComponentDto file = componentFinder.getByUuidOrKey(dbSession, request.param(PARAM_UUID), request.param(PARAM_KEY)); + userSession.checkProjectUuidPermission(UserRole.CODEVIEWER, file.projectUuid()); - List sourceLines = sourceLineIndex.getLines(component.uuid(), from, to); - if (sourceLines.isEmpty()) { - throw new NotFoundException("File '" + component.key() + "' has no sources"); - } + int from = request.mandatoryParamAsInt(PARAM_FROM); + int to = Objects.firstNonNull(request.paramAsInt(PARAM_TO), Integer.MAX_VALUE); - JsonWriter json = response.newJsonWriter().beginObject(); - writeSource(sourceLines, json); + Optional> lines = sourceService.getLines(dbSession, file.uuid(), from, to); + if (!lines.isPresent()) { + throw new NotFoundException(); + } - json.endObject().close(); + JsonWriter json = response.newJsonWriter().beginObject(); + writeSource(lines.get(), json); + json.endObject().close(); + } finally { + dbClient.closeSession(dbSession); + } } - private void writeSource(List lines, JsonWriter json) { + private void writeSource(Iterable lines, JsonWriter json) { json.name("sources").beginArray(); - for (SourceLineDoc line : lines) { + for (DbFileSources.Line line : lines) { json.beginObject() - .prop("line", line.line()) - .prop("code", htmlSourceDecorator.getDecoratedSourceAsHtml(line.source(), line.highlighting(), line.symbols())) - .prop("scmAuthor", line.scmAuthor()) - .prop("scmRevision", line.scmRevision()); - Date scmDate = line.scmDate(); - json.prop("scmDate", scmDate == null ? null : DateUtils.formatDateTime(scmDate)); - json.prop("utLineHits", line.utLineHits()) - .prop("utConditions", line.utConditions()) - .prop("utCoveredConditions", line.utCoveredConditions()) - .prop("itLineHits", line.itLineHits()) - .prop("itConditions", line.itConditions()) - .prop("itCoveredConditions", line.itCoveredConditions()); - if (!line.duplications().isEmpty()) { - json.prop("duplicated", true); + .prop("line", line.getLine()) + .prop("code", htmlSourceDecorator.getDecoratedSourceAsHtml(line.getSource(), line.getHighlighting(), line.getSymbols())) + .prop("scmAuthor", line.getScmAuthor()) + .prop("scmRevision", line.getScmRevision()); + if (line.hasScmDate()) { + json.prop("scmDate", DateUtils.formatDateTime(new Date(line.getScmDate()))); } - json.endObject(); - } - json.endArray(); - } - - private ComponentDto loadComponent(Request request) { - DbSession session = dbClient.openSession(false); - try { - String fileUuid = request.param(PARAM_UUID); - if (fileUuid != null) { - Optional componentDto = dbClient.componentDao().selectByUuid(session, fileUuid); - if (!componentDto.isPresent()) { - throw new NotFoundException(String.format("Component with uuid '%s' not found", fileUuid)); - } - return componentDto.get(); + if (line.hasUtLineHits()) { + json.prop("utLineHits", line.getUtLineHits()); } - String fileKey = request.param(PARAM_KEY); - if (fileKey != null) { - Optional componentDto = dbClient.componentDao().selectByKey(session, fileKey); - if (!componentDto.isPresent()) { - throw new NotFoundException(String.format("Component with key '%s' not found", fileKey)); - } - return componentDto.get(); + if (line.hasUtConditions()) { + json.prop("utConditions", line.getUtConditions()); } - throw new IllegalArgumentException(String.format("Param %s or param %s is missing", PARAM_UUID, PARAM_KEY)); - } finally { - MyBatis.closeQuietly(session); + if (line.hasUtCoveredConditions()) { + json.prop("utCoveredConditions", line.getUtCoveredConditions()); + } + if (line.hasItLineHits()) { + json.prop("itLineHits", line.getItLineHits()); + } + if (line.hasItConditions()) { + json.prop("itConditions", line.getItConditions()); + } + if (line.hasItCoveredConditions()) { + json.prop("itCoveredConditions", line.getItCoveredConditions()); + } + json.prop("duplicated", line.getDuplicationCount() > 0); + json.endObject(); } + json.endArray(); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/ws/RawAction.java b/server/sonar-server/src/main/java/org/sonar/server/source/ws/RawAction.java index b05c6e7d4eb..96795116892 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/source/ws/RawAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/source/ws/RawAction.java @@ -20,11 +20,11 @@ package org.sonar.server.source.ws; +import com.google.common.base.Optional; import com.google.common.io.Resources; import java.io.IOException; +import java.io.OutputStream; import java.nio.charset.StandardCharsets; -import java.util.List; -import org.apache.commons.io.IOUtils; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; @@ -53,7 +53,7 @@ public class RawAction implements SourcesWsAction { @Override public void define(WebService.NewController controller) { WebService.NewAction action = controller.createAction("raw") - .setDescription("Get source code as plain text. Require See Source Code permission on file") + .setDescription("Get source code as raw text. Require 'See Source Code' permission on file") .setSince("5.0") .setResponseExample(Resources.getResource(getClass(), "example-raw.txt")) .setHandler(this); @@ -62,23 +62,30 @@ public class RawAction implements SourcesWsAction { .createParam("key") .setRequired(true) .setDescription("File key") - .setExampleValue("my_project:/src/foo/Bar.php"); + .setExampleValue("my_project:src/foo/Bar.php"); } @Override public void handle(Request request, Response response) { String fileKey = request.mandatoryParam("key"); - userSession.checkComponentPermission(UserRole.CODEVIEWER, fileKey); - DbSession session = dbClient.openSession(false); + DbSession dbSession = dbClient.openSession(false); try { - ComponentDto componentDto = componentFinder.getByKey(session, fileKey); - List lines = sourceService.getLinesAsTxt(componentDto.uuid(), null, null); + ComponentDto file = componentFinder.getByKey(dbSession, fileKey); + userSession.checkProjectUuidPermission(UserRole.CODEVIEWER, file.projectUuid()); + + Optional> lines = sourceService.getLinesAsRawText(dbSession, file.uuid(), 1, Integer.MAX_VALUE); response.stream().setMediaType("text/plain"); - IOUtils.writeLines(lines, "\n", response.stream().output(), StandardCharsets.UTF_8); + if (lines.isPresent()) { + OutputStream output = response.stream().output(); + for (String line : lines.get()) { + output.write(line.getBytes(StandardCharsets.UTF_8)); + output.write("\n".getBytes(StandardCharsets.UTF_8)); + } + } } catch (IOException e) { throw new IllegalStateException("Fail to write raw source of file " + fileKey, e); } finally { - session.close(); + dbClient.closeSession(dbSession); } } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/ws/ScmAction.java b/server/sonar-server/src/main/java/org/sonar/server/source/ws/ScmAction.java index 06ea14eacf7..043b4c6072b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/source/ws/ScmAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/source/ws/ScmAction.java @@ -20,10 +20,10 @@ package org.sonar.server.source.ws; +import com.google.common.base.Optional; import com.google.common.base.Strings; import com.google.common.io.Resources; import java.util.Date; -import java.util.List; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.builder.EqualsBuilder; import org.sonar.api.server.ws.Request; @@ -35,22 +35,22 @@ import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDto; +import org.sonar.db.protobuf.DbFileSources; import org.sonar.server.component.ComponentFinder; import org.sonar.server.exceptions.NotFoundException; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndex; +import org.sonar.server.source.SourceService; import org.sonar.server.user.UserSession; public class ScmAction implements SourcesWsAction { private final DbClient dbClient; - private final SourceLineIndex sourceLineIndex; + private final SourceService sourceService; private final UserSession userSession; private final ComponentFinder componentFinder; - public ScmAction(DbClient dbClient, SourceLineIndex sourceLineIndex, UserSession userSession, ComponentFinder componentFinder) { + public ScmAction(DbClient dbClient, SourceService sourceService, UserSession userSession, ComponentFinder componentFinder) { this.dbClient = dbClient; - this.sourceLineIndex = sourceLineIndex; + this.sourceService = sourceService; this.userSession = userSession; this.componentFinder = componentFinder; } @@ -102,36 +102,34 @@ public class ScmAction implements SourcesWsAction { int to = (Integer) ObjectUtils.defaultIfNull(request.paramAsInt("to"), Integer.MAX_VALUE); boolean commitsByLine = request.mandatoryParamAsBoolean("commits_by_line"); - DbSession session = dbClient.openSession(false); + DbSession dbSession = dbClient.openSession(false); try { - ComponentDto fileDto = componentFinder.getByKey(session, fileKey); - userSession.checkProjectUuidPermission(UserRole.CODEVIEWER, fileDto.projectUuid()); - List sourceLines = sourceLineIndex.getLines(fileDto.uuid(), from, to); - if (sourceLines.isEmpty()) { - throw new NotFoundException("File '" + fileKey + "' has no sources"); + ComponentDto file = componentFinder.getByKey(dbSession, fileKey); + userSession.checkProjectUuidPermission(UserRole.CODEVIEWER, file.projectUuid()); + Optional> sourceLines = sourceService.getLines(dbSession, file.uuid(), from, to); + if (!sourceLines.isPresent()) { + throw new NotFoundException(String.format("File '%s' has no sources", fileKey)); } - JsonWriter json = response.newJsonWriter().beginObject(); - writeSource(sourceLines, commitsByLine, json); + writeSource(sourceLines.get(), commitsByLine, json); json.endObject().close(); } finally { - session.close(); + dbClient.closeSession(dbSession); } } - private static void writeSource(List lines, boolean showCommitsByLine, JsonWriter json) { + private static void writeSource(Iterable lines, boolean showCommitsByLine, JsonWriter json) { json.name("scm").beginArray(); - SourceLineDoc previousLine = null; + DbFileSources.Line previousLine = null; boolean started = false; - for (SourceLineDoc lineDoc : lines) { + for (DbFileSources.Line lineDoc : lines) { if (hasScm(lineDoc) && (!started || showCommitsByLine || !isSameCommit(previousLine, lineDoc))) { json.beginArray() - .value(lineDoc.line()) - .value(lineDoc.scmAuthor()); - Date date = lineDoc.scmDate(); - json.value(date == null ? null : DateUtils.formatDateTime(date)); - json.value(lineDoc.scmRevision()); + .value(lineDoc.getLine()) + .value(lineDoc.getScmAuthor()); + json.value(lineDoc.hasScmDate() ? DateUtils.formatDateTime(new Date(lineDoc.getScmDate())) : null); + json.value(lineDoc.getScmRevision()); json.endArray(); started = true; } @@ -140,15 +138,15 @@ public class ScmAction implements SourcesWsAction { json.endArray(); } - private static boolean isSameCommit(SourceLineDoc previousLine, SourceLineDoc currentLine) { + private static boolean isSameCommit(DbFileSources.Line previousLine, DbFileSources.Line currentLine) { return new EqualsBuilder() - .append(previousLine.scmAuthor(), currentLine.scmAuthor()) - .append(previousLine.scmDate(), currentLine.scmDate()) - .append(previousLine.scmRevision(), currentLine.scmRevision()) + .append(previousLine.getScmAuthor(), currentLine.getScmAuthor()) + .append(previousLine.getScmDate(), currentLine.getScmDate()) + .append(previousLine.getScmRevision(), currentLine.getScmRevision()) .isEquals(); } - private static boolean hasScm(SourceLineDoc line) { - return !Strings.isNullOrEmpty(line.scmAuthor()) || line.scmDate() != null || !Strings.isNullOrEmpty(line.scmRevision()); + private static boolean hasScm(DbFileSources.Line line) { + return !Strings.isNullOrEmpty(line.getScmAuthor()) || line.hasScmDate() || !Strings.isNullOrEmpty(line.getScmRevision()); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/ws/ShowAction.java b/server/sonar-server/src/main/java/org/sonar/server/source/ws/ShowAction.java index 2d9a12109a4..3e554915d26 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/source/ws/ShowAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/source/ws/ShowAction.java @@ -19,8 +19,8 @@ */ package org.sonar.server.source.ws; +import com.google.common.base.Optional; import com.google.common.io.Resources; -import java.util.List; import org.apache.commons.lang.ObjectUtils; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; @@ -31,6 +31,7 @@ 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.exceptions.NotFoundException; import org.sonar.server.source.SourceService; import org.sonar.server.user.UserSession; @@ -82,33 +83,37 @@ public class ShowAction implements SourcesWsAction { @Override public void handle(Request request, Response response) { String fileKey = request.mandatoryParam("key"); - userSession.checkComponentPermission(UserRole.CODEVIEWER, fileKey); - - int from = Math.max(request.mandatoryParamAsInt("from"), 1); + int from = Math.max(request.paramAsInt("from"), 1); int to = (Integer) ObjectUtils.defaultIfNull(request.paramAsInt("to"), Integer.MAX_VALUE); - DbSession session = dbClient.openSession(false); + DbSession dbSession = dbClient.openSession(false); try { - ComponentDto componentDto = componentFinder.getByKey(session, fileKey); - List linesHtml = sourceService.getLinesAsHtml(componentDto.uuid(), from, to); - JsonWriter json = response.newJsonWriter().beginObject(); - writeSource(linesHtml, from, json); + ComponentDto file = componentFinder.getByKey(dbSession, fileKey); + userSession.checkProjectUuidPermission(UserRole.CODEVIEWER, file.projectUuid()); + + Optional> linesHtml = sourceService.getLinesAsHtml(dbSession, file.uuid(), from, to); + if (linesHtml.isPresent()) { + JsonWriter json = response.newJsonWriter().beginObject(); + writeSource(linesHtml.get(), from, json); + json.endObject().close(); + } else { + throw new NotFoundException(); + } - json.endObject().close(); } finally { - session.close(); + dbClient.closeSession(dbSession); } - } - private void writeSource(List lines, int from, JsonWriter json) { + private void writeSource(Iterable lines, int from, JsonWriter json) { json.name("sources").beginArray(); - for (int i = 0; i < lines.size(); i++) { - String line = lines.get(i); + long index = 0L; + for (String line : lines) { json.beginArray(); - json.value((long) i + from); + json.value(index + from); json.value(line); json.endArray(); + index++; } json.endArray(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/test/index/TestIndexer.java b/server/sonar-server/src/main/java/org/sonar/server/test/index/TestIndexer.java index 6d80a102847..476844f534c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/test/index/TestIndexer.java +++ b/server/sonar-server/src/main/java/org/sonar/server/test/index/TestIndexer.java @@ -33,7 +33,6 @@ import org.sonar.server.es.BulkIndexer; import org.sonar.server.es.EsClient; import org.sonar.server.source.index.FileSourcesUpdaterHelper; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_PROJECT_UUID; import static org.sonar.server.test.index.TestIndexDefinition.FIELD_FILE_UUID; import static org.sonar.server.test.index.TestIndexDefinition.FIELD_UPDATED_AT; import static org.sonar.server.test.index.TestIndexDefinition.INDEX; @@ -117,7 +116,7 @@ public class TestIndexer extends BaseIndexer { .setTypes(TYPE) .setQuery(QueryBuilders.filteredQuery( QueryBuilders.matchAllQuery(), - FilterBuilders.termFilter(FIELD_PROJECT_UUID, projectUuid).cache(false))); + FilterBuilders.termFilter(TestIndexDefinition.FIELD_PROJECT_UUID, projectUuid).cache(false))); BulkIndexer.delete(esClient, INDEX, searchRequest); } } diff --git a/server/sonar-server/src/test/java/org/sonar/core/computation/dbcleaner/IndexPurgeListenerTest.java b/server/sonar-server/src/test/java/org/sonar/core/computation/dbcleaner/IndexPurgeListenerTest.java index 40850ed8f53..cfd25f392e9 100644 --- a/server/sonar-server/src/test/java/org/sonar/core/computation/dbcleaner/IndexPurgeListenerTest.java +++ b/server/sonar-server/src/test/java/org/sonar/core/computation/dbcleaner/IndexPurgeListenerTest.java @@ -21,7 +21,6 @@ package org.sonar.core.computation.dbcleaner; import org.junit.Test; -import org.sonar.server.source.index.SourceLineIndexer; import org.sonar.server.test.index.TestIndexer; import static org.mockito.Mockito.mock; @@ -30,14 +29,12 @@ import static org.mockito.Mockito.verify; public class IndexPurgeListenerTest { @Test - public void call_source_line_indexer() { - SourceLineIndexer sourceLineIndexer = mock(SourceLineIndexer.class); + public void call_test_indexer() { TestIndexer testIndexer = mock(TestIndexer.class); - IndexPurgeListener underTest = new IndexPurgeListener(sourceLineIndexer, testIndexer); + IndexPurgeListener underTest = new IndexPurgeListener(testIndexer); underTest.onComponentDisabling("123456"); - verify(sourceLineIndexer).deleteByFile("123456"); verify(testIndexer).deleteByFile("123456"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueAssignerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueAssignerTest.java index 8d1f6e3990e..585d6ac9890 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueAssignerTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/issue/IssueAssignerTest.java @@ -17,107 +17,127 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.server.computation.issue; - -import java.util.Date; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.config.Settings; -import org.sonar.batch.protocol.output.BatchReport; -import org.sonar.server.computation.batch.BatchReportReaderRule; -import org.sonar.server.computation.component.Component; -import org.sonar.server.computation.component.ReportComponent; -import org.sonar.server.es.EsTester; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndex; -import org.sonar.server.source.index.SourceLineIndexDefinition; - -import static org.mockito.Mockito.mock; - -public class IssueAssignerTest { - - @ClassRule - public static EsTester esTester = new EsTester().addDefinitions(new SourceLineIndexDefinition(new Settings())); - - @Rule - public BatchReportReaderRule reportReader = new BatchReportReaderRule(); - ScmAccountToUser scmAccountToUser = mock(ScmAccountToUser.class); - DefaultAssignee defaultAssignee = mock(DefaultAssignee.class); - Component file = ReportComponent.builder(Component.Type.FILE, 1).build(); - - IssueAssigner underTest; - - @Before - public void setUp() { - esTester.truncateIndices(); - underTest = new IssueAssigner(new SourceLineIndex(esTester.client()), reportReader, scmAccountToUser, defaultAssignee); - } - - @Test - public void line_author_from_report() { - reportReader.putChangesets(BatchReport.Changesets.newBuilder() - .setComponentRef(123_456_789) - .addChangeset(newChangeset("charb", "123-456-789", 123_456_789L)) - .addChangeset(newChangeset("wolinski", "987-654-321", 987_654_321L)) - .addChangesetIndexByLine(0) - .addChangesetIndexByLine(0) - .addChangesetIndexByLine(1) - .build()); - - underTest.beforeComponent(file); - // underTest.onIssue(file, issue); - // sut.init("ANY_UUID", 123_456_789, reportReader); - // - // assertThat(sut.lineAuthor(1)).isEqualTo("charb"); - // assertThat(sut.lineAuthor(2)).isEqualTo("charb"); - // assertThat(sut.lineAuthor(3)).isEqualTo("wolinski"); - // // compute last author - // assertThat(sut.lineAuthor(4)).isEqualTo("wolinski"); - // assertThat(sut.lineAuthor(null)).isEqualTo("wolinski"); - } - - // @Test - // public void line_author_from_index() throws Exception { - // esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - // newSourceLine("cabu", "123-456-789", 123_456_789, 1), - // newSourceLine("cabu", "123-456-789", 123_456_789, 2), - // newSourceLine("cabu", "123-123-789", 123_456_789, 3), - // newSourceLine("wolinski", "987-654-321", 987_654_321, 4), - // newSourceLine("cabu", "123-456-789", 123_456_789, 5) - // ); - // - // sut.init("DEFAULT_UUID", 123, reportReader); - // - // assertThat(sut.lineAuthor(1)).isEqualTo("cabu"); - // assertThat(sut.lineAuthor(2)).isEqualTo("cabu"); - // assertThat(sut.lineAuthor(3)).isEqualTo("cabu"); - // assertThat(sut.lineAuthor(4)).isEqualTo("wolinski"); - // assertThat(sut.lineAuthor(5)).isEqualTo("cabu"); - // assertThat(sut.lineAuthor(6)).isEqualTo("wolinski"); - // } - // - // @Test(expected = IllegalStateException.class) - // public void fail_when_component_ref_is_not_filled() { - // sut.init("ANY_UUID", null, reportReader); - // sut.lineAuthor(0); - // } - - private BatchReport.Changesets.Changeset.Builder newChangeset(String author, String revision, long date) { - return BatchReport.Changesets.Changeset.newBuilder() - .setAuthor(author) - .setRevision(revision) - .setDate(date); - } - - private SourceLineDoc newSourceLine(String author, String revision, long date, int lineNumber) { - return new SourceLineDoc() - .setScmAuthor(author) - .setScmRevision(revision) - .setScmDate(new Date(date)) - .setLine(lineNumber) - .setProjectUuid("PROJECT_UUID") - .setFileUuid("DEFAULT_UUID"); - } -} +///* +// * SonarQube, open source software quality management tool. +// * Copyright (C) 2008-2014 SonarSource +// * mailto:contact AT sonarsource DOT com +// * +// * SonarQube is free software; you can redistribute it and/or +// * modify it under the terms of the GNU Lesser General Public +// * License as published by the Free Software Foundation; either +// * version 3 of the License, or (at your option) any later version. +// * +// * SonarQube is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// * Lesser General Public License for more details. +// * +// * You should have received a copy of the GNU Lesser General Public License +// * along with this program; if not, write to the Free Software Foundation, +// * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// */ +//package org.sonar.server.computation.issue; +// +//import java.util.Date; +//import org.junit.Before; +//import org.junit.ClassRule; +//import org.junit.Rule; +//import org.junit.Test; +//import org.sonar.api.config.Settings; +//import org.sonar.batch.protocol.output.BatchReport; +//import org.sonar.server.computation.batch.BatchReportReaderRule; +//import org.sonar.server.computation.component.Component; +//import org.sonar.server.computation.component.ReportComponent; +//import org.sonar.server.es.EsTester; +//import org.sonar.server.source.SourceService2; +//import org.sonar.server.source.index.SourceLineDoc; +//import org.sonar.server.source.index.SourceLineIndex; +//import org.sonar.server.source.index.SourceLineIndexDefinition; +// +//import static org.mockito.Mockito.mock; +// +//public class IssueAssignerTest { +// +// @ClassRule +// public static EsTester esTester = new EsTester().addDefinitions(new SourceLineIndexDefinition(new Settings())); +// +// @Rule +// public BatchReportReaderRule reportReader = new BatchReportReaderRule(); +// ScmAccountToUser scmAccountToUser = mock(ScmAccountToUser.class); +// DefaultAssignee defaultAssignee = mock(DefaultAssignee.class); +// Component file = ReportComponent.builder(Component.Type.FILE, 1).build(); +// +// IssueAssigner underTest; +// +// @Before +// public void setUp() { +// esTester.truncateIndices(); +// underTest = new IssueAssigner(new SourceService2(esTester.client()), reportReader, scmAccountToUser, defaultAssignee); +// } +// +// @Test +// public void line_author_from_report() { +// reportReader.putChangesets(BatchReport.Changesets.newBuilder() +// .setComponentRef(123_456_789) +// .addChangeset(newChangeset("charb", "123-456-789", 123_456_789L)) +// .addChangeset(newChangeset("wolinski", "987-654-321", 987_654_321L)) +// .addChangesetIndexByLine(0) +// .addChangesetIndexByLine(0) +// .addChangesetIndexByLine(1) +// .build()); +// +// underTest.beforeComponent(file); +// // underTest.onIssue(file, issue); +// // sut.init("ANY_UUID", 123_456_789, reportReader); +// // +// // assertThat(sut.lineAuthor(1)).isEqualTo("charb"); +// // assertThat(sut.lineAuthor(2)).isEqualTo("charb"); +// // assertThat(sut.lineAuthor(3)).isEqualTo("wolinski"); +// // // compute last author +// // assertThat(sut.lineAuthor(4)).isEqualTo("wolinski"); +// // assertThat(sut.lineAuthor(null)).isEqualTo("wolinski"); +// } +// +// // @Test +// // public void line_author_from_index() throws Exception { +// // esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, +// // newSourceLine("cabu", "123-456-789", 123_456_789, 1), +// // newSourceLine("cabu", "123-456-789", 123_456_789, 2), +// // newSourceLine("cabu", "123-123-789", 123_456_789, 3), +// // newSourceLine("wolinski", "987-654-321", 987_654_321, 4), +// // newSourceLine("cabu", "123-456-789", 123_456_789, 5) +// // ); +// // +// // sut.init("DEFAULT_UUID", 123, reportReader); +// // +// // assertThat(sut.lineAuthor(1)).isEqualTo("cabu"); +// // assertThat(sut.lineAuthor(2)).isEqualTo("cabu"); +// // assertThat(sut.lineAuthor(3)).isEqualTo("cabu"); +// // assertThat(sut.lineAuthor(4)).isEqualTo("wolinski"); +// // assertThat(sut.lineAuthor(5)).isEqualTo("cabu"); +// // assertThat(sut.lineAuthor(6)).isEqualTo("wolinski"); +// // } +// // +// // @Test(expected = IllegalStateException.class) +// // public void fail_when_component_ref_is_not_filled() { +// // sut.init("ANY_UUID", null, reportReader); +// // sut.lineAuthor(0); +// // } +// +// private BatchReport.Changesets.Changeset.Builder newChangeset(String author, String revision, long date) { +// return BatchReport.Changesets.Changeset.newBuilder() +// .setAuthor(author) +// .setRevision(revision) +// .setDate(date); +// } +// +// private SourceLineDoc newSourceLine(String author, String revision, long date, int lineNumber) { +// return new SourceLineDoc() +// .setScmAuthor(author) +// .setScmRevision(revision) +// .setScmDate(new Date(date)) +// .setLine(lineNumber) +// .setProjectUuid("PROJECT_UUID") +// .setFileUuid("DEFAULT_UUID"); +// } +//} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/sqale/ViewsSqaleMeasuresVisitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/sqale/ViewsSqaleMeasuresVisitorTest.java index bf865c4e4ea..51c717e2d44 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/sqale/ViewsSqaleMeasuresVisitorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/sqale/ViewsSqaleMeasuresVisitorTest.java @@ -109,9 +109,9 @@ public class ViewsSqaleMeasuresVisitorTest { assertThat(toEntries(measureRepository.getRawMeasures(root))) .containsOnly( - entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create("0")), - entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(0d)), - entryOf(SQALE_RATING_KEY, createSqaleRatingMeasure(A))); + entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create("0")), + entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(0d)), + entryOf(SQALE_RATING_KEY, createSqaleRatingMeasure(A))); } private Measure createSqaleRatingMeasure(SqaleRatingGrid.SqaleRating sqaleRating) { @@ -150,9 +150,9 @@ public class ViewsSqaleMeasuresVisitorTest { private void assertNewRawMeasures(int componentRef, long debt, long devCost, SqaleRatingGrid.SqaleRating sqaleRating) { assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).containsOnly( - entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create(String.valueOf(devCost))), - entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(debt / (double) devCost * 100.0)), - entryOf(SQALE_RATING_KEY, createSqaleRatingMeasure(sqaleRating))); + entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create(String.valueOf(devCost))), + entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(debt / (double) devCost * 100.0)), + entryOf(SQALE_RATING_KEY, createSqaleRatingMeasure(sqaleRating))); } private void assertNoNewRawMeasureOnProjectViews() { @@ -170,18 +170,6 @@ public class ViewsSqaleMeasuresVisitorTest { measureRepository.addRawMeasure(componentRef, metricKey, newMeasureBuilder().create(value)); } - private void verifyFileMeasures(int componentRef, long measureValue, long debt, long languageCost, SqaleRatingGrid.SqaleRating expectedRating) { - long developmentCost = measureValue * languageCost; - verifyComponentMeasures(componentRef, developmentCost, debt / developmentCost, expectedRating); - } - - private void verifyComponentMeasures(int componentRef, long expectedDevCost, double expectedDebtRatio, SqaleRatingGrid.SqaleRating expectedRating) { - assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).containsOnly( - entryOf(DEVELOPMENT_COST_KEY, newMeasureBuilder().create(Long.toString(expectedDevCost))), - entryOf(SQALE_DEBT_RATIO_KEY, newMeasureBuilder().create(expectedDebtRatio * 100.0)), - entryOf(SQALE_RATING_KEY, createSqaleRatingMeasure(expectedRating))); - } - private void assertNoNewRawMeasure(int componentRef) { assertThat(measureRepository.getAddedRawMeasures(componentRef).isEmpty()).isTrue(); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexSourceLinesStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexSourceLinesStepTest.java deleted file mode 100644 index dae40433271..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexSourceLinesStepTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.computation.step; - -import java.sql.Connection; -import java.util.List; -import org.elasticsearch.search.SearchHit; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.config.Settings; -import org.sonar.api.utils.System2; -import org.sonar.db.DbClient; -import org.sonar.db.DbTester; -import org.sonar.server.computation.batch.TreeRootHolderRule; -import org.sonar.server.computation.component.Component; -import org.sonar.server.computation.component.ReportComponent; -import org.sonar.server.es.EsTester; -import org.sonar.server.source.index.FileSourceTesting; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndexDefinition; -import org.sonar.server.source.index.SourceLineIndexer; - -import static org.assertj.core.api.Assertions.assertThat; - -public class IndexSourceLinesStepTest extends BaseStepTest { - - @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); - - @ClassRule - public static EsTester esTester = new EsTester().addDefinitions(new SourceLineIndexDefinition(new Settings())); - - @Rule - public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); - - DbClient dbClient = dbTester.getDbClient(); - - @Override - protected ComputationStep step() { - SourceLineIndexer sourceLineIndexer = new SourceLineIndexer(dbClient, esTester.client()); - sourceLineIndexer.setEnabled(true); - return new IndexSourceLinesStep(sourceLineIndexer, treeRootHolder); - } - - @Test - public void index_source() throws Exception { - dbTester.prepareDbUnit(getClass(), "index_source.xml"); - try (Connection connection = dbTester.openConnection()) { - FileSourceTesting.updateDataColumn(connection, "FILE1_UUID", FileSourceTesting.newRandomData(1).build()); - } - - treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey("PROJECT_KEY").build()); - - step().execute(); - - List docs = esTester.getDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE); - assertThat(docs).hasSize(1); - SourceLineDoc doc = new SourceLineDoc(docs.get(0).sourceAsMap()); - assertThat(doc.projectUuid()).isEqualTo("ABCD"); - assertThat(doc.fileUuid()).isEqualTo("FILE1_UUID"); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java index 1c2f69d44eb..8a695b728f1 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java @@ -20,10 +20,8 @@ package org.sonar.server.issue; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterators; import com.google.common.collect.Sets; import java.util.Arrays; -import java.util.Date; import java.util.List; import org.junit.After; import org.junit.Before; @@ -44,16 +42,18 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDao; import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ComponentTesting; import org.sonar.db.issue.ActionPlanDto; import org.sonar.db.issue.IssueDao; import org.sonar.db.issue.IssueDto; import org.sonar.db.protobuf.DbFileSources; import org.sonar.db.rule.RuleDto; import org.sonar.db.rule.RuleTesting; +import org.sonar.db.source.FileSourceDao; +import org.sonar.db.source.FileSourceDto; import org.sonar.db.user.GroupDao; import org.sonar.db.user.GroupDto; import org.sonar.db.user.UserDto; -import org.sonar.db.component.ComponentTesting; import org.sonar.server.es.SearchOptions; import org.sonar.server.es.SearchResult; import org.sonar.server.exceptions.BadRequestException; @@ -65,9 +65,6 @@ import org.sonar.server.issue.index.IssueIndexer; import org.sonar.server.permission.PermissionChange; import org.sonar.server.permission.PermissionUpdater; import org.sonar.server.rule.db.RuleDao; -import org.sonar.server.source.index.FileSourcesUpdaterHelper; -import org.sonar.server.source.index.SourceLineIndexer; -import org.sonar.server.source.index.SourceLineResultSetIterator; import org.sonar.server.tester.ServerTester; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.user.NewUser; @@ -613,8 +610,13 @@ public class IssueServiceMediumTest { .setLine(line) .setScmAuthor(scmAuthor) .build(); - FileSourcesUpdaterHelper.Row row = SourceLineResultSetIterator.toRow(file.projectUuid(), file.uuid(), new Date(), dataBuilder.build()); - tester.get(SourceLineIndexer.class).index(Iterators.singletonIterator(row)); + FileSourceDto dto = new FileSourceDto(); + dto.setProjectUuid(file.projectUuid()); + dto.setFileUuid(file.uuid()); + dto.setCreatedAt(System.currentTimeMillis()); + dto.setSourceData(dataBuilder.build()); + dto.setDataType(FileSourceDto.Type.SOURCE); + tester.get(FileSourceDao.class).insert(dto); } private void newUser(String login) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/ShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/ShowActionTest.java index 1e70e79cf0f..661ab46de43 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/ShowActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/ShowActionTest.java @@ -58,7 +58,6 @@ import org.sonar.server.issue.IssueService; import org.sonar.server.issue.actionplan.ActionPlanService; import org.sonar.server.rule.Rule; import org.sonar.server.rule.RuleService; -import org.sonar.server.source.SourceService; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.user.ThreadLocalUserSession; import org.sonar.server.ws.WsTester; @@ -115,9 +114,6 @@ public class ShowActionTest { @Mock Durations durations; - @Mock - SourceService sourceService; - Date issueCreationDate; Rule rule; diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/BackendCleanupMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/BackendCleanupMediumTest.java index 03aea74bfad..d3165fcbf19 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/BackendCleanupMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/BackendCleanupMediumTest.java @@ -35,8 +35,6 @@ import org.sonar.server.issue.index.IssueIndexDefinition; import org.sonar.server.rule.index.RuleDoc; import org.sonar.server.rule.index.RuleNormalizer; import org.sonar.server.search.IndexDefinition; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndexDefinition; import org.sonar.server.view.index.ViewDoc; import org.sonar.server.view.index.ViewIndexDefinition; import org.sonar.test.DbTests; @@ -103,7 +101,6 @@ public class BackendCleanupMediumTest { public void reset_data() throws Exception { dbTester.prepareDbUnit(getClass(), "shared.xml"); esTester.putDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_ISSUE, IssueTesting.newDoc()); - esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, new SourceLineDoc().setProjectUuid("ABCD").setFileUuid("BCDE")); esTester.putDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW, new ViewDoc().setUuid("CDEF").setProjects(newArrayList("DEFG"))); esTester.putDocuments(IndexDefinition.RULE.getIndexName(), IndexDefinition.RULE.getIndexType(), newRuleDoc()); @@ -113,7 +110,6 @@ public class BackendCleanupMediumTest { assertThat(dbTester.countRowsOfTable("snapshots")).isEqualTo(0); assertThat(dbTester.countRowsOfTable("properties")).isEqualTo(0); assertThat(esTester.countDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_ISSUE)).isEqualTo(0); - assertThat(esTester.countDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE)).isEqualTo(0); assertThat(esTester.countDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW)).isEqualTo(0); // Rules should not be removed diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java index ca06f623c68..71cf3db4433 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java @@ -41,6 +41,7 @@ import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDao; import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ComponentTesting; import org.sonar.db.component.ResourceDao; import org.sonar.db.component.SnapshotDao; import org.sonar.db.component.SnapshotDto; @@ -51,7 +52,6 @@ import org.sonar.db.rule.RuleDto; import org.sonar.db.rule.RuleTesting; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.ComponentFinder; -import org.sonar.db.component.ComponentTesting; import org.sonar.server.component.SnapshotTesting; import org.sonar.server.db.DbClient; import org.sonar.server.es.EsTester; @@ -61,9 +61,6 @@ import org.sonar.server.issue.index.IssueAuthorizationIndexer; import org.sonar.server.issue.index.IssueIndexDefinition; import org.sonar.server.issue.index.IssueIndexer; import org.sonar.server.rule.db.RuleDao; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndexDefinition; -import org.sonar.server.source.index.SourceLineIndexer; import org.sonar.server.test.index.TestDoc; import org.sonar.server.test.index.TestIndexDefinition; import org.sonar.server.test.index.TestIndexer; @@ -86,7 +83,7 @@ public class BulkDeleteActionTest { public DbTester db = DbTester.create(System2.INSTANCE); @ClassRule - public static EsTester es = new EsTester().addDefinitions(new IssueIndexDefinition(new Settings()), new SourceLineIndexDefinition(new Settings()), + public static EsTester es = new EsTester().addDefinitions(new IssueIndexDefinition(new Settings()), new TestIndexDefinition(new Settings())); @Rule @@ -116,12 +113,9 @@ public class BulkDeleteActionTest { new ComponentCleanerService(dbClient, new IssueAuthorizationIndexer(dbClient, es.client()), new IssueIndexer(dbClient, es.client()), - new SourceLineIndexer(dbClient, es.client()), - new TestIndexer(dbClient, es.client()), mockResourceTypes, new ComponentFinder(dbClient) - ), + new TestIndexer(dbClient, es.client()), mockResourceTypes, new ComponentFinder(dbClient)), dbClient, - userSessionRule - ))); + userSessionRule))); userSessionRule.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); db.truncateTables(); es.truncateIndices(); @@ -183,8 +177,6 @@ public class BulkDeleteActionTest { .containsOnly(remainingProjectUuid); assertThat(es.getDocumentFieldValues(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION, IssueIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID)) .containsOnly(remainingProjectUuid); - assertThat(es.getDocumentFieldValues(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, SourceLineIndexDefinition.FIELD_PROJECT_UUID)) - .containsOnly(remainingProjectUuid); assertThat(es.getDocumentFieldValues(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE, TestIndexDefinition.FIELD_PROJECT_UUID)) .containsOnly(remainingProjectUuid); } @@ -250,13 +242,9 @@ public class BulkDeleteActionTest { dbSession.commit(); es.putDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_ISSUE, IssueTesting.newDoc("issue-key-" + suffix, project)); - SourceLineDoc sourceLineDoc = new SourceLineDoc() - .setProjectUuid(project.uuid()) - .setFileUuid(project.uuid()); es.putDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION, ImmutableMap.of(IssueIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID, project.uuid())); - es.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, sourceLineDoc); TestDoc testDoc = new TestDoc().setUuid("test-uuid-" + suffix).setProjectUuid(project.uuid()).setFileUuid(project.uuid()); es.putDocuments(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE, testDoc); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java index 2a359e0f77c..1a590fd3df5 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java @@ -39,6 +39,7 @@ import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDao; import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ComponentTesting; import org.sonar.db.component.ResourceDao; import org.sonar.db.component.SnapshotDao; import org.sonar.db.component.SnapshotDto; @@ -49,7 +50,6 @@ import org.sonar.db.rule.RuleDto; import org.sonar.db.rule.RuleTesting; import org.sonar.server.component.ComponentCleanerService; import org.sonar.server.component.ComponentFinder; -import org.sonar.db.component.ComponentTesting; import org.sonar.server.component.SnapshotTesting; import org.sonar.server.db.DbClient; import org.sonar.server.es.EsTester; @@ -59,9 +59,6 @@ import org.sonar.server.issue.index.IssueAuthorizationIndexer; import org.sonar.server.issue.index.IssueIndexDefinition; import org.sonar.server.issue.index.IssueIndexer; import org.sonar.server.rule.db.RuleDao; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndexDefinition; -import org.sonar.server.source.index.SourceLineIndexer; import org.sonar.server.test.index.TestDoc; import org.sonar.server.test.index.TestIndexDefinition; import org.sonar.server.test.index.TestIndexer; @@ -86,7 +83,7 @@ public class DeleteActionTest { public DbTester db = DbTester.create(System2.INSTANCE); @ClassRule - public static EsTester es = new EsTester().addDefinitions(new IssueIndexDefinition(new Settings()), new SourceLineIndexDefinition(new Settings()), + public static EsTester es = new EsTester().addDefinitions(new IssueIndexDefinition(new Settings()), new TestIndexDefinition(new Settings())); @Rule @@ -120,7 +117,6 @@ public class DeleteActionTest { dbClient, new IssueAuthorizationIndexer(dbClient, es.client()), new IssueIndexer(dbClient, es.client()), - new SourceLineIndexer(dbClient, es.client()), new TestIndexer(dbClient, es.client()), mockResourceTypes, new ComponentFinder(dbClient)), @@ -203,8 +199,6 @@ public class DeleteActionTest { .containsOnly(remainingProjectUuid); assertThat(es.getDocumentFieldValues(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION, IssueIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID)) .containsOnly(remainingProjectUuid); - assertThat(es.getDocumentFieldValues(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, SourceLineIndexDefinition.FIELD_PROJECT_UUID)) - .containsOnly(remainingProjectUuid); assertThat(es.getDocumentFieldValues(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE, TestIndexDefinition.FIELD_PROJECT_UUID)) .containsOnly(remainingProjectUuid); } @@ -270,13 +264,9 @@ public class DeleteActionTest { dbSession.commit(); es.putDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_ISSUE, IssueTesting.newDoc("issue-key-" + suffix, project)); - SourceLineDoc sourceLineDoc = new SourceLineDoc() - .setProjectUuid(project.uuid()) - .setFileUuid(project.uuid()); es.putDocuments(IssueIndexDefinition.INDEX, IssueIndexDefinition.TYPE_AUTHORIZATION, ImmutableMap.of(IssueIndexDefinition.FIELD_AUTHORIZATION_PROJECT_UUID, project.uuid())); - es.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, sourceLineDoc); TestDoc testDoc = new TestDoc().setUuid("test-uuid-" + suffix).setProjectUuid(project.uuid()).setFileUuid(project.uuid()); es.putDocuments(TestIndexDefinition.INDEX, TestIndexDefinition.TYPE, testDoc); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/SourceServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/SourceServiceTest.java index ace7b68352c..ca3d00f0c32 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/SourceServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/SourceServiceTest.java @@ -17,79 +17,125 @@ * 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; +import com.google.common.base.Optional; +import com.google.common.collect.Lists; +import java.io.IOException; +import java.util.List; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import org.sonar.db.measure.MeasureDao; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndex; - -import java.util.Arrays; -import java.util.List; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; +import org.sonar.db.protobuf.DbFileSources; +import org.sonar.db.source.FileSourceDto; +import org.sonar.server.source.index.FileSourceTesting; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@RunWith(MockitoJUnitRunner.class) public class SourceServiceTest { - static final String PROJECT_KEY = "org.sonar.sample"; - static final String COMPONENT_UUID = "abc123"; + public static final String FILE_UUID = "FILE_UUID"; - @Mock - HtmlSourceDecorator sourceDecorator; + @Rule + public DbTester dbTester = DbTester.create(System2.INSTANCE); - @Mock - MeasureDao measureDao; + @Rule + public ExpectedException expectedException = ExpectedException.none(); - @Mock - SourceLineIndex sourceLineIndex; + HtmlSourceDecorator htmlDecorator = mock(HtmlSourceDecorator.class); - SourceService service; + SourceService underTest = new SourceService(dbTester.getDbClient(), htmlDecorator); @Before - public void setUp() { - service = new SourceService(sourceDecorator, sourceLineIndex); + public void injectFakeLines() throws IOException { + FileSourceDto dto = new FileSourceDto(); + dto.setFileUuid(FILE_UUID).setProjectUuid("PROJECT_UUID"); + dto.setSourceData(FileSourceTesting.newFakeData(10).build()); + dbTester.getDbClient().fileSourceDao().insert(dto); + } + + @Test + public void get_range_of_lines() throws Exception { + Optional> linesOpt = underTest.getLines(dbTester.getSession(), FILE_UUID, 5, 7); + assertThat(linesOpt.isPresent()).isTrue(); + List lines = Lists.newArrayList(linesOpt.get()); + assertThat(lines).hasSize(3); + assertThat(lines.get(0).getLine()).isEqualTo(5); + assertThat(lines.get(1).getLine()).isEqualTo(6); + assertThat(lines.get(2).getLine()).isEqualTo(7); } @Test - public void get_html_lines() { - when(sourceLineIndex.getLines(COMPONENT_UUID, 1, Integer.MAX_VALUE)).thenReturn( - Arrays.asList(new SourceLineDoc().setSource("source").setHighlighting("highlight").setSymbols("symbols"))); + public void get_range_of_lines_as_raw_text() throws Exception { + Optional> linesOpt = underTest.getLinesAsRawText(dbTester.getSession(), FILE_UUID, 5, 7); + assertThat(linesOpt.isPresent()).isTrue(); + List lines = Lists.newArrayList(linesOpt.get()); + assertThat(lines).containsExactly("SOURCE_5", "SOURCE_6", "SOURCE_7"); + } + + @Test + public void get_range_of_lines_as_html() throws Exception { + when(htmlDecorator.getDecoratedSourceAsHtml("SOURCE_5", "HIGHLIGHTING_5", "SYMBOLS_5")).thenReturn("HTML_5"); + when(htmlDecorator.getDecoratedSourceAsHtml("SOURCE_6", "HIGHLIGHTING_6", "SYMBOLS_6")).thenReturn("HTML_6"); + when(htmlDecorator.getDecoratedSourceAsHtml("SOURCE_7", "HIGHLIGHTING_7", "SYMBOLS_7")).thenReturn("HTML_7"); + + Optional> linesOpt = underTest.getLinesAsHtml(dbTester.getSession(), FILE_UUID, 5, 7); + assertThat(linesOpt.isPresent()).isTrue(); + List lines = Lists.newArrayList(linesOpt.get()); + assertThat(lines).containsExactly("HTML_5", "HTML_6", "HTML_7"); + } - service.getLinesAsHtml(COMPONENT_UUID, null, null); + @Test + public void getLines_fails_if_range_starts_at_zero() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Line number must start at 1, got 0"); - verify(sourceDecorator).getDecoratedSourceAsHtml("source", "highlight", "symbols"); + underTest.getLines(dbTester.getSession(), FILE_UUID, 0, 2); } @Test - public void get_block_of_lines() { + public void getLines_fails_if_range_upper_bound_less_than_lower_bound() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Line number must greater than or equal to 5, got 4"); + + underTest.getLines(dbTester.getSession(), FILE_UUID, 5, 4); + } - when(sourceLineIndex.getLines(COMPONENT_UUID, 1, Integer.MAX_VALUE)).thenReturn( - Arrays.asList(new SourceLineDoc().setSource("source").setHighlighting("highlight").setSymbols("symbols"), - new SourceLineDoc().setSource("source2").setHighlighting("highlight2").setSymbols("symbols2"))); + @Test + public void getLines_returns_empty_iterable_if_range_is_out_of_scope() throws Exception { + Optional> lines = underTest.getLines(dbTester.getSession(), FILE_UUID, 500, 510); + assertThat(lines.isPresent()).isTrue(); + assertThat(lines.get()).isEmpty(); + } - service.getLinesAsHtml(COMPONENT_UUID, null, null); + @Test + public void getLines_file_does_not_exist() throws Exception { + Optional> lines = underTest.getLines(dbTester.getSession(), "FILE_DOES_NOT_EXIST", 1, 10); + assertThat(lines.isPresent()).isFalse(); + } - verify(sourceDecorator).getDecoratedSourceAsHtml("source", "highlight", "symbols"); - verify(sourceDecorator).getDecoratedSourceAsHtml("source2", "highlight2", "symbols2"); + @Test + public void getLine() throws Exception { + Optional line = underTest.getLine(dbTester.getSession(), FILE_UUID, 4); + assertThat(line.isPresent()).isTrue(); + assertThat(line.get().getLine()).isEqualTo(4); + assertThat(line.get().getSource()).isEqualTo("SOURCE_4"); } @Test - public void getLinesAsTxt() { - when(sourceLineIndex.getLines(COMPONENT_UUID, 1, Integer.MAX_VALUE)).thenReturn( - Arrays.asList( - new SourceLineDoc().setSource("line1"), - new SourceLineDoc().setSource("line2"))); - - List result = service.getLinesAsTxt(COMPONENT_UUID, null, null); - assertThat(result).contains("line1", "line2"); + public void getLine_absent_line() throws Exception { + Optional line = underTest.getLine(dbTester.getSession(), FILE_UUID, 500); + assertThat(line.isPresent()).isFalse(); } + @Test + public void getLine_absent_file() throws Exception { + Optional line = underTest.getLine(dbTester.getSession(), "FILE_DOES_NOT_EXIST", 10); + assertThat(line.isPresent()).isFalse(); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexDefinitionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexDefinitionTest.java deleted file mode 100644 index 5fef0817afe..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexDefinitionTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.source.index; - -import org.junit.Test; -import org.sonar.api.config.Settings; -import org.sonar.process.ProcessProperties; -import org.sonar.server.es.IndexDefinition; -import org.sonar.server.es.NewIndex; - -import static org.assertj.core.api.Assertions.assertThat; - -public class SourceLineIndexDefinitionTest { - - IndexDefinition.IndexDefinitionContext context = new IndexDefinition.IndexDefinitionContext(); - - @Test - public void define() { - IndexDefinition def = new SourceLineIndexDefinition(new Settings()); - def.define(context); - - assertThat(context.getIndices()).hasSize(1); - NewIndex index = context.getIndices().get("sourcelines"); - assertThat(index).isNotNull(); - assertThat(index.getTypes().keySet()).containsOnly("sourceline"); - - // no cluster by default - assertThat(index.getSettings().get("index.number_of_shards")).isEqualTo("1"); - assertThat(index.getSettings().get("index.number_of_replicas")).isEqualTo("0"); - } - - @Test - public void enable_cluster() { - Settings settings = new Settings(); - settings.setProperty(ProcessProperties.CLUSTER_ACTIVATE, true); - IndexDefinition def = new SourceLineIndexDefinition(settings); - def.define(context); - - NewIndex issuesIndex = context.getIndices().get("sourcelines"); - assertThat(issuesIndex.getSettings().get("index.number_of_shards")).isEqualTo("4"); - assertThat(issuesIndex.getSettings().get("index.number_of_replicas")).isEqualTo("1"); - } - -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexTest.java deleted file mode 100644 index ece9adaf88f..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexTest.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.source.index; - -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.sonar.api.config.Settings; -import org.sonar.api.utils.DateUtils; -import org.sonar.server.es.EsTester; -import org.sonar.server.exceptions.NotFoundException; - -import java.util.Date; - -import static org.assertj.core.api.Assertions.assertThat; - -public class SourceLineIndexTest { - - @ClassRule - public static EsTester es = new EsTester().addDefinitions(new SourceLineIndexDefinition(new Settings())); - - private SourceLineIndex index; - - @Before - public void setUp() { - es.truncateIndices(); - index = new SourceLineIndex(es.client()); - } - - @Test - public void should_retrieve_line_range() throws Exception { - es.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - this.getClass(), - "file1_line1.json", - "file1_line2.json", - "file1_line3.json", - "file2_line1.json", - "file2_line2.json", - "file2_line3.json"); - assertThat(index.getLines("file1", 1, 3)).hasSize(3); - assertThat(index.getLines("file1", 1, Integer.MAX_VALUE)).hasSize(3); - assertThat(index.getLines("file1", 2, 2)).hasSize(1); - assertThat(index.getLines("file1")).hasSize(3); - } - - @Test(expected = IllegalArgumentException.class) - public void should_reject_from_less_than_1() { - index.getLines("polop", 0, 0); - } - - @Test(expected = IllegalArgumentException.class) - public void should_reject_to_less_than_from() { - index.getLines("polop", 2, 1); - } - - @Test - public void get_line() throws Exception { - es.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - this.getClass(), - "file1_line1.json", - "file1_line2.json" - ); - assertThat(index.getLine("file1", 1)).isNotNull(); - assertThat(index.getLine("file1", 2)).isNotNull(); - } - - @Test - public void fail_to_get_line_when_line_is_not_greater_than_0() { - try { - index.getLine("file1", 0); - } catch (Exception e) { - assertThat(e).isInstanceOf(IllegalArgumentException.class).hasMessage("Line should be greater than 0"); - } - } - - @Test - public void fail_to_get_line_on_unknown_line() throws Exception { - es.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - this.getClass(), - "file1_line1.json", - "file1_line2.json" - ); - try { - index.getLine("file1", 1); - } catch (Exception e) { - assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("No source found on line 5 for file 'file1'"); - } - } - - @Test - public void fail_to_get_line_on_unknown_file() { - try { - index.getLine("file1", 1); - } catch (Exception e) { - assertThat(e).isInstanceOf(NotFoundException.class).hasMessage("No source found on line 1 for file 'file1'"); - } - } - - @Test - public void last_commit_of_the_whole_project() throws Exception { - Date now = new Date(); - es.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - new SourceLineDoc() - .setProjectUuid("project-uuid") - .setScmDate(now) - .setLine(25) - .setFileUuid("file-uuid"), - new SourceLineDoc() - .setProjectUuid("project-uuid") - .setScmDate(DateUtils.addDays(now, -1)) - .setLine(24) - .setFileUuid("file-uuid")); - - Date returnedDate = index.lastCommitDateOnProject("project-uuid"); - - assertThat(returnedDate).isEqualTo(now); - } - - @Test - public void last_commit_null_when_not_found() { - Date date = index.lastCommitDateOnProject("fake-project-uuid"); - - assertThat(date).isNull(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexerTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexerTest.java deleted file mode 100644 index 7d4bafe3f70..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineIndexerTest.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.source.index; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterators; -import java.io.IOException; -import java.sql.Connection; -import java.util.Date; -import java.util.List; -import java.util.Map; -import org.apache.commons.io.FileUtils; -import org.elasticsearch.action.search.SearchRequestBuilder; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.index.query.QueryBuilders; -import org.elasticsearch.search.SearchHit; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.sonar.api.config.Settings; -import org.sonar.api.utils.DateUtils; -import org.sonar.api.utils.System2; -import org.sonar.db.DbTester; -import org.sonar.db.protobuf.DbFileSources; -import org.sonar.server.db.DbClient; -import org.sonar.server.es.EsTester; -import org.sonar.test.DbTests; -import org.sonar.test.TestUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_DUPLICATIONS; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_FILE_UUID; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_IT_CONDITIONS; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_IT_COVERED_CONDITIONS; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_IT_LINE_HITS; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_LINE; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_OVERALL_CONDITIONS; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_OVERALL_COVERED_CONDITIONS; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_OVERALL_LINE_HITS; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_PROJECT_UUID; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_SCM_AUTHOR; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_SCM_REVISION; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_SOURCE; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_UT_CONDITIONS; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_UT_COVERED_CONDITIONS; -import static org.sonar.server.source.index.SourceLineIndexDefinition.FIELD_UT_LINE_HITS; -import static org.sonar.server.source.index.SourceLineIndexDefinition.INDEX; -import static org.sonar.server.source.index.SourceLineIndexDefinition.TYPE; - -@Category(DbTests.class) -public class SourceLineIndexerTest { - - @ClassRule - public static EsTester es = new EsTester().addDefinitions(new SourceLineIndexDefinition(new Settings())); - - @Rule - public DbTester db = DbTester.create(System2.INSTANCE); - - private SourceLineIndexer indexer; - - @Before - public void setUp() { - es.truncateIndices(); - indexer = new SourceLineIndexer(new DbClient(db.database(), db.myBatis()), es.client()); - indexer.setEnabled(true); - } - - @Test - public void index_source_lines() throws Exception { - db.prepareDbUnit(getClass(), "db.xml"); - - try (Connection connection = db.openConnection()) { - FileSourceTesting.updateDataColumn(connection, "FILE_UUID", FileSourceTesting.newRandomData(3).build()); - } - - indexer.index(); - assertThat(countDocuments()).isEqualTo(3); - } - - @Test - public void index_source_lines_from_project() throws Exception { - db.prepareDbUnit(getClass(), "db.xml"); - - try (Connection connection = db.openConnection()) { - FileSourceTesting.updateDataColumn(connection, "FILE_UUID", FileSourceTesting.newRandomData(3).build()); - } - - indexer.index("PROJECT_UUID"); - assertThat(countDocuments()).isEqualTo(3); - } - - @Test - public void index_nothing_from_unknown_project() throws Exception { - db.prepareDbUnit(getClass(), "db.xml"); - - try (Connection connection = db.openConnection()) { - FileSourceTesting.updateDataColumn(connection, "FILE_UUID", FileSourceTesting.newRandomData(3).build()); - } - - indexer.index("UNKNOWN"); - assertThat(countDocuments()).isZero(); - } - - /** - * File F1 in project P1 has one line -> to be updated - * File F2 in project P1 has one line -> untouched - */ - @Test - public void update_already_indexed_lines() throws Exception { - indexLine("P1", "F1", 1); - indexLine("P1", "F2", 1); - - List duplications = ImmutableList.of(1, 2, 3); - DbFileSources.Data.Builder dataBuilder = DbFileSources.Data.newBuilder(); - dataBuilder.addLinesBuilder() - .setLine(1) - .setScmRevision("new_revision") - .setScmAuthor("new_author") - .setSource("new source") - .addAllDuplication(duplications) - .build(); - FileSourcesUpdaterHelper.Row dbRow = SourceLineResultSetIterator.toRow("P1", "F1", new Date(), dataBuilder.build()); - indexer.index(Iterators.singletonIterator(dbRow)); - - assertThat(countDocuments()).isEqualTo(2L); - - SearchResponse fileSearch = prepareSearch() - .setQuery(QueryBuilders.termQuery(FIELD_FILE_UUID, "F1")) - .get(); - assertThat(fileSearch.getHits().getTotalHits()).isEqualTo(1L); - Map fields = fileSearch.getHits().getHits()[0].sourceAsMap(); - assertThat(fields).contains( - entry(FIELD_PROJECT_UUID, "P1"), - entry(FIELD_FILE_UUID, "F1"), - entry(FIELD_LINE, 1), - entry(FIELD_SCM_REVISION, "new_revision"), - entry(FIELD_SCM_AUTHOR, "new_author"), - entry(FIELD_SOURCE, "new source"), - entry(FIELD_DUPLICATIONS, duplications)); - } - - @Test - public void delete_file_uuid() throws Exception { - indexLine("P1", "F1", 1); - indexLine("P1", "F1", 2); - indexLine("P1", "F2", 1); - - indexer.deleteByFile("F1"); - - List hits = getDocuments(); - Map document = hits.get(0).getSource(); - assertThat(hits).hasSize(1); - assertThat(document.get(FIELD_LINE)).isEqualTo(1); - assertThat(document.get(FIELD_FILE_UUID)).isEqualTo("F2"); - } - - @Test - public void delete_by_project_uuid() throws Exception { - indexLine("P1", "F1", 1); - indexLine("P1", "F1", 2); - indexLine("P1", "F2", 1); - indexLine("P2", "F3", 1); - - indexer.deleteByProject("P1"); - - List hits = getDocuments(); - assertThat(hits).hasSize(1); - Map document = hits.get(0).getSource(); - assertThat(hits).hasSize(1); - assertThat(document.get(FIELD_PROJECT_UUID)).isEqualTo("P2"); - } - - @Test - public void index_source_lines_with_big_test_data() { - Integer bigValue = Short.MAX_VALUE * 2; - - DbFileSources.Data.Builder dataBuilder = DbFileSources.Data.newBuilder(); - dataBuilder.addLinesBuilder() - .setLine(1) - .setScmRevision("cafebabe") - .setScmAuthor("polop") - .setScmDate(DateUtils.parseDateTime("2014-01-01T12:34:56+0100").getTime()) - .setSource("package org.sonar.server.source;") - .setUtLineHits(bigValue) - .setUtConditions(bigValue) - .setUtCoveredConditions(bigValue) - .setItLineHits(bigValue) - .setItConditions(bigValue) - .setItCoveredConditions(bigValue) - .setOverallLineHits(bigValue) - .setOverallConditions(bigValue) - .setOverallCoveredConditions(bigValue) - .build(); - - FileSourcesUpdaterHelper.Row row = SourceLineResultSetIterator.toRow("P1", "F1", new Date(), dataBuilder.build()); - indexer.index(Iterators.singletonIterator(row)); - - List hits = getDocuments(); - assertThat(hits).hasSize(1); - Map document = hits.get(0).getSource(); - assertThat(document.get(FIELD_UT_LINE_HITS)).isEqualTo(bigValue); - assertThat(document.get(FIELD_UT_CONDITIONS)).isEqualTo(bigValue); - assertThat(document.get(FIELD_UT_COVERED_CONDITIONS)).isEqualTo(bigValue); - assertThat(document.get(FIELD_IT_LINE_HITS)).isEqualTo(bigValue); - assertThat(document.get(FIELD_IT_CONDITIONS)).isEqualTo(bigValue); - assertThat(document.get(FIELD_IT_COVERED_CONDITIONS)).isEqualTo(bigValue); - assertThat(document.get(FIELD_OVERALL_LINE_HITS)).isEqualTo(bigValue); - assertThat(document.get(FIELD_OVERALL_CONDITIONS)).isEqualTo(bigValue); - assertThat(document.get(FIELD_OVERALL_COVERED_CONDITIONS)).isEqualTo(bigValue); - } - - private void indexLine(String projectUuid, String fileUuid, int line) throws IOException { - es.client().prepareIndex(INDEX, TYPE) - .setId(SourceLineIndexDefinition.docKey(fileUuid, line)) - .setSource(FileUtils.readFileToString(TestUtils.getResource(this.getClass(), projectUuid + "_" + fileUuid + "_line" + line + ".json"))) - .setRefresh(true) - .get(); - } - - private SearchRequestBuilder prepareSearch() { - return es.client().prepareSearch(INDEX) - .setTypes(TYPE); - } - - private List getDocuments() { - return es.getDocuments(INDEX, TYPE); - } - - private long countDocuments() { - return es.countDocuments(INDEX, TYPE); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineResultSetIteratorTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineResultSetIteratorTest.java deleted file mode 100644 index a9f2cce7ac7..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/source/index/SourceLineResultSetIteratorTest.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.server.source.index; - -import java.sql.Connection; -import java.util.Map; -import org.assertj.core.data.MapEntry; -import org.elasticsearch.action.update.UpdateRequest; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.sonar.api.utils.System2; -import org.sonar.db.DbTester; -import org.sonar.db.protobuf.DbFileSources; -import org.sonar.test.DbTests; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - -@Category(DbTests.class) -public class SourceLineResultSetIteratorTest { - - @Rule - public DbTester db = DbTester.create(System2.INSTANCE); - - SourceLineResultSetIterator iterator; - - public void after() { - if (iterator != null) { - iterator.close(); - } - } - - @Test - public void traverse_db() throws Exception { - db.prepareDbUnit(getClass(), "shared.xml"); - try (Connection connection = db.openConnection()) { - FileSourceTesting.updateDataColumn(connection, "F1", FileSourceTesting.newFakeData(3).build()); - } - - iterator = SourceLineResultSetIterator.create(db.getDbClient(), db.getSession(), 0L, null); - assertThat(iterator.hasNext()).isTrue(); - FileSourcesUpdaterHelper.Row row = iterator.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 doc = firstRequest.doc().sourceAsMap(); - assertThat(doc).contains( - MapEntry.entry(SourceLineIndexDefinition.FIELD_PROJECT_UUID, "P1"), - MapEntry.entry(SourceLineIndexDefinition.FIELD_FILE_UUID, "F1"), - MapEntry.entry(SourceLineIndexDefinition.FIELD_LINE, 1), - MapEntry.entry(SourceLineIndexDefinition.FIELD_SCM_REVISION, "REVISION_1"), - MapEntry.entry(SourceLineIndexDefinition.FIELD_SCM_AUTHOR, "AUTHOR_1"), - MapEntry.entry(SourceLineIndexDefinition.FIELD_HIGHLIGHTING, "HIGHLIGHTING_1"), - MapEntry.entry(SourceLineIndexDefinition.FIELD_SYMBOLS, "SYMBOLS_1"), - MapEntry.entry(SourceLineIndexDefinition.FIELD_UT_LINE_HITS, 1), - MapEntry.entry(SourceLineIndexDefinition.FIELD_UT_CONDITIONS, 2), - MapEntry.entry(SourceLineIndexDefinition.FIELD_UT_COVERED_CONDITIONS, 3), - MapEntry.entry(SourceLineIndexDefinition.FIELD_IT_LINE_HITS, 4), - MapEntry.entry(SourceLineIndexDefinition.FIELD_IT_CONDITIONS, 5), - MapEntry.entry(SourceLineIndexDefinition.FIELD_IT_COVERED_CONDITIONS, 6), - MapEntry.entry(SourceLineIndexDefinition.FIELD_OVERALL_LINE_HITS, 7), - MapEntry.entry(SourceLineIndexDefinition.FIELD_OVERALL_CONDITIONS, 8), - MapEntry.entry(SourceLineIndexDefinition.FIELD_OVERALL_COVERED_CONDITIONS, 9)); - } - - /** - * File with one line. No metadata available on the line. - */ - @Test - public void minimal_data() throws Exception { - db.prepareDbUnit(getClass(), "shared.xml"); - DbFileSources.Data.Builder dataBuilder = DbFileSources.Data.newBuilder(); - dataBuilder.addLinesBuilder().setLine(1).build(); - try (Connection connection = db.openConnection()) { - FileSourceTesting.updateDataColumn(connection, "F1", dataBuilder.build()); - } - - iterator = SourceLineResultSetIterator.create(db.getDbClient(), db.getSession(), 0L, null); - FileSourcesUpdaterHelper.Row row = iterator.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 doc = firstRequest.doc().sourceAsMap(); - assertThat(doc).contains( - MapEntry.entry(SourceLineIndexDefinition.FIELD_PROJECT_UUID, "P1"), - MapEntry.entry(SourceLineIndexDefinition.FIELD_FILE_UUID, "F1"), - MapEntry.entry(SourceLineIndexDefinition.FIELD_LINE, 1)); - // null values - assertThat(doc).containsKeys( - SourceLineIndexDefinition.FIELD_SCM_REVISION, - SourceLineIndexDefinition.FIELD_SCM_AUTHOR, - SourceLineIndexDefinition.FIELD_HIGHLIGHTING, - SourceLineIndexDefinition.FIELD_SYMBOLS, - SourceLineIndexDefinition.FIELD_UT_LINE_HITS, - SourceLineIndexDefinition.FIELD_UT_CONDITIONS, - SourceLineIndexDefinition.FIELD_UT_COVERED_CONDITIONS, - SourceLineIndexDefinition.FIELD_IT_LINE_HITS, - SourceLineIndexDefinition.FIELD_IT_CONDITIONS, - SourceLineIndexDefinition.FIELD_IT_COVERED_CONDITIONS, - SourceLineIndexDefinition.FIELD_OVERALL_LINE_HITS, - SourceLineIndexDefinition.FIELD_OVERALL_CONDITIONS, - SourceLineIndexDefinition.FIELD_OVERALL_COVERED_CONDITIONS); - } - - @Test - public void filter_by_date() { - db.prepareDbUnit(getClass(), "shared.xml"); - - iterator = SourceLineResultSetIterator.create(db.getDbClient(), db.getSession(), 2000000000000L, null); - assertThat(iterator.hasNext()).isFalse(); - } - - @Test - public void filter_by_project() throws Exception { - db.prepareDbUnit(getClass(), "filter_by_project.xml"); - DbFileSources.Data.Builder dataBuilder = DbFileSources.Data.newBuilder(); - dataBuilder.addLinesBuilder().setLine(1).build(); - try (Connection connection = db.openConnection()) { - FileSourceTesting.updateDataColumn(connection, "F1", dataBuilder.build()); - } - - iterator = SourceLineResultSetIterator.create(db.getDbClient(), db.getSession(), 0L, "P1"); - - FileSourcesUpdaterHelper.Row row = iterator.next(); - assertThat(row.getProjectUuid()).isEqualTo("P1"); - assertThat(row.getFileUuid()).isEqualTo("F1"); - - // File from other project P2 is not returned - assertThat(iterator.hasNext()).isFalse(); - } - - @Test - public void filter_by_project_and_date() throws Exception { - db.prepareDbUnit(getClass(), "filter_by_project_and_date.xml"); - DbFileSources.Data.Builder dataBuilder = DbFileSources.Data.newBuilder(); - dataBuilder.addLinesBuilder().setLine(1).build(); - try (Connection connection = db.openConnection()) { - FileSourceTesting.updateDataColumn(connection, "F1", dataBuilder.build()); - } - - iterator = SourceLineResultSetIterator.create(db.getDbClient(), db.getSession(), 1400000000000L, "P1"); - - FileSourcesUpdaterHelper.Row row = iterator.next(); - assertThat(row.getProjectUuid()).isEqualTo("P1"); - assertThat(row.getFileUuid()).isEqualTo("F1"); - - // File F2 is not returned - assertThat(iterator.hasNext()).isFalse(); - } - - @Test - public void fail_on_bad_data_format() throws Exception { - db.prepareDbUnit(getClass(), "shared.xml"); - - try (Connection connection = db.openConnection()) { - FileSourceTesting.updateDataColumn(connection, "F1", "THIS_IS_NOT_PROTOBUF".getBytes()); - } - - iterator = SourceLineResultSetIterator.create(db.getDbClient(), db.getSession(), 0L, null); - try { - assertThat(iterator.hasNext()).isTrue(); - iterator.next(); - fail(); - } catch (IllegalStateException e) { - // ok - } - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java index 12a0f0bc24e..26f60a1a93a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/LinesActionTest.java @@ -20,33 +20,33 @@ package org.sonar.server.source.ws; -import com.google.common.collect.ImmutableList; -import java.util.Date; import org.junit.Before; -import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.sonar.api.config.Settings; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.sonar.api.utils.System2; import org.sonar.api.web.UserRole; -import org.sonar.db.DbClient; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDao; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; -import org.sonar.server.es.EsTester; +import org.sonar.db.source.FileSourceDto; +import org.sonar.server.component.ComponentFinder; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.NotFoundException; import org.sonar.server.source.HtmlSourceDecorator; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndex; -import org.sonar.server.source.index.SourceLineIndexDefinition; +import org.sonar.server.source.SourceService; +import org.sonar.server.source.index.FileSourceTesting; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsTester; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class LinesActionTest { @@ -57,16 +57,13 @@ public class LinesActionTest { @Rule public ExpectedException thrown = ExpectedException.none(); - @ClassRule - public static EsTester esTester = new EsTester().addDefinitions(new SourceLineIndexDefinition(new Settings())); - @Rule public DbTester dbTester = DbTester.create(System2.INSTANCE); @Rule public UserSessionRule userSessionRule = UserSessionRule.standalone(); - SourceLineIndex sourceLineIndex; + SourceService sourceService; HtmlSourceDecorator htmlSourceDecorator; @@ -77,79 +74,28 @@ public class LinesActionTest { @Before public void setUp() { dbTester.truncateTables(); - esTester.truncateIndices(); - htmlSourceDecorator = new HtmlSourceDecorator(); - sourceLineIndex = new SourceLineIndex(esTester.client()); + htmlSourceDecorator = mock(HtmlSourceDecorator.class); + when(htmlSourceDecorator.getDecoratedSourceAsHtml(anyString(), anyString(), anyString())).then(new Answer() { + @Override + public String answer(InvocationOnMock invocationOnMock) throws Throwable { + return "

" + invocationOnMock.getArguments()[0] + "

"; + } + }); + sourceService = new SourceService(dbTester.getDbClient(), htmlSourceDecorator); componentDao = new ComponentDao(); - DbClient dbClient = dbTester.getDbClient(); - wsTester = new WsTester(new SourcesWs(new LinesAction(dbClient, sourceLineIndex, htmlSourceDecorator, userSessionRule))); + wsTester = new WsTester(new SourcesWs( + new LinesAction(new ComponentFinder(dbTester.getDbClient()), dbTester.getDbClient(), sourceService, htmlSourceDecorator, userSessionRule))); } @Test public void show_source() throws Exception { newFile(); - Date updatedAt = new Date(); - String scmDate = "2014-01-01T12:34:56.789Z"; - SourceLineDoc line1 = new SourceLineDoc() - .setProjectUuid(PROJECT_UUID) - .setFileUuid(FILE_UUID) - .setLine(1) - .setScmRevision("cafebabe") - .setScmAuthor("polop") - .setSource("package org.polop;") - .setHighlighting("0,7,k") - .setSymbols("8,17,42") - .setUtLineHits(3) - .setUtConditions(2) - .setUtCoveredConditions(1) - .setItLineHits(3) - .setItConditions(2) - .setItCoveredConditions(1) - .setDuplications(ImmutableList.of()) - .setUpdateDate(updatedAt); - line1.setField(SourceLineIndexDefinition.FIELD_SCM_DATE, scmDate); - - SourceLineDoc line2 = new SourceLineDoc() - .setProjectUuid(PROJECT_UUID) - .setFileUuid(FILE_UUID) - .setLine(2) - .setScmRevision("cafebabe") - .setScmAuthor("polop") - .setSource("abc") - .setHighlighting("0,5,c") - .setSymbols("") - .setUtLineHits(3) - .setUtConditions(2) - .setUtCoveredConditions(1) - .setItLineHits(null) - .setItConditions(null) - .setItCoveredConditions(null) - .setDuplications(ImmutableList.of(1)) - .setUpdateDate(updatedAt); - line2.setField(SourceLineIndexDefinition.FIELD_SCM_DATE, scmDate); - - SourceLineDoc line3 = new SourceLineDoc() + dbTester.getDbClient().fileSourceDao().insert(new FileSourceDto() .setProjectUuid(PROJECT_UUID) .setFileUuid(FILE_UUID) - .setLine(3) - .setScmRevision("cafebabe") - .setScmAuthor("polop") - .setSource("}") - .setHighlighting(null) - .setSymbols(null) - .setUtLineHits(null) - .setUtConditions(null) - .setUtCoveredConditions(null) - .setItLineHits(3) - .setItConditions(2) - .setItCoveredConditions(1) - .setDuplications(ImmutableList.of()) - .setUpdateDate(updatedAt); - line3.setField(SourceLineIndexDefinition.FIELD_SCM_DATE, scmDate); - - esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, line1, line2, line3); + .setSourceData(FileSourceTesting.newFakeData(3).build())); userSessionRule.login("login").addProjectUuidPermissions(UserRole.CODEVIEWER, PROJECT_UUID); @@ -173,93 +119,46 @@ public class LinesActionTest { } @Test - public void show_source_with_from_and_to_params() throws Exception { + public void show_paginated_lines() throws Exception { newFile(); userSessionRule.login("login").addProjectUuidPermissions(UserRole.CODEVIEWER, PROJECT_UUID); - esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - new SourceLineDoc() - .setProjectUuid(PROJECT_UUID) - .setFileUuid(FILE_UUID) - .setLine(3) - .setScmRevision("cafebabe") - .setScmDate(null) - .setScmAuthor("polop") - .setSource("}") - .setHighlighting("") - .setSymbols("") - .setUtLineHits(null) - .setUtConditions(null) - .setUtCoveredConditions(null) - .setItLineHits(null) - .setItConditions(null) - .setItCoveredConditions(null) - .setDuplications(null) - .setUpdateDate(new Date()) - ); + dbTester.getDbClient().fileSourceDao().insert(new FileSourceDto() + .setProjectUuid(PROJECT_UUID) + .setFileUuid(FILE_UUID) + .setSourceData(FileSourceTesting.newFakeData(3).build())); WsTester.TestRequest request = wsTester .newGetRequest("api/sources", "lines") .setParam("uuid", FILE_UUID) .setParam("from", "3") .setParam("to", "3"); - request.execute().assertJson(getClass(), "show_source_with_params_from_and_to.json"); - } - - @Test - public void show_source_by_file_key() throws Exception { - newFile(); - - esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - new SourceLineDoc() - .setProjectUuid(PROJECT_UUID) - .setFileUuid(FILE_UUID) - .setLine(3) - .setScmRevision("cafebabe") - .setScmDate(null) - .setScmAuthor("polop") - .setSource("}") - .setHighlighting("") - .setSymbols("") - .setUtLineHits(null) - .setUtConditions(null) - .setUtCoveredConditions(null) - .setItLineHits(null) - .setItConditions(null) - .setItCoveredConditions(null) - .setDuplications(null) - .setUpdateDate(new Date()) - ); - - userSessionRule.login("login").addProjectUuidPermissions(UserRole.CODEVIEWER, PROJECT_UUID); - - WsTester.TestRequest request = wsTester.newGetRequest("api/sources", "lines").setParam("key", FILE_KEY); - request.execute().assertJson(getClass(), "show_source_by_file_key.json"); + request.execute().assertJson(getClass(), "show_paginated_lines.json"); } @Test public void fail_when_no_uuid_or_key_param() throws Exception { thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("Param uuid or param key is missing"); + thrown.expectMessage("The component key or the component id must be provided, not both."); WsTester.TestRequest request = wsTester.newGetRequest("api/sources", "lines"); request.execute(); } @Test - public void fail_when_file_key_does_not_exists() throws Exception { + public void fail_when_file_key_does_not_exist() throws Exception { thrown.expect(NotFoundException.class); - thrown.expectMessage("Component with key 'Foo.java' not found"); + thrown.expectMessage("Component key 'Foo.java' not found"); WsTester.TestRequest request = wsTester.newGetRequest("api/sources", "lines").setParam("key", FILE_KEY); request.execute(); } @Test - public void fail_when_file_uuid_does_not_exists() throws Exception { + public void fail_when_file_uuid_does_not_exist() throws Exception { thrown.expect(NotFoundException.class); - thrown.expectMessage("Component with uuid 'ABCD' not found"); + thrown.expectMessage("Component id 'ABCD' not found"); WsTester.TestRequest request = wsTester.newGetRequest("api/sources", "lines").setParam("uuid", "ABCD"); request.execute(); diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java index 60b6c513034..208ff1076f6 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/RawActionTest.java @@ -32,8 +32,8 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDao; import org.sonar.db.component.ComponentDto; -import org.sonar.server.component.ComponentFinder; import org.sonar.db.component.ComponentTesting; +import org.sonar.server.component.ComponentFinder; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.source.SourceService; import org.sonar.server.tester.UserSessionRule; @@ -76,13 +76,13 @@ public class RawActionTest { @Test public void get_txt() throws Exception { String fileKey = "src/Foo.java"; - userSessionRule.addComponentPermission(UserRole.CODEVIEWER, "polop", fileKey); + userSessionRule.addProjectUuidPermissions(UserRole.CODEVIEWER, project.uuid()); when(componentDao.selectByKey(session, fileKey)).thenReturn(Optional.of(file)); - when(sourceService.getLinesAsTxt(file.uuid(), null, null)).thenReturn(newArrayList( + Iterable lines = newArrayList( "public class HelloWorld {", - "}" - )); + "}"); + when(sourceService.getLinesAsRawText(session, file.uuid(), 1, Integer.MAX_VALUE)).thenReturn(Optional.of(lines)); WsTester.TestRequest request = tester.newGetRequest("api/sources", "raw").setParam("key", fileKey); String result = request.execute().outputAsString(); @@ -91,6 +91,7 @@ public class RawActionTest { @Test(expected = ForbiddenException.class) public void requires_code_viewer_permission() throws Exception { - tester.newGetRequest("api/sources", "raw").setParam("key", "any").execute(); + when(componentDao.selectByKey(session, "src/Foo.java")).thenReturn(Optional.of(file)); + tester.newGetRequest("api/sources", "raw").setParam("key", "src/Foo.java").execute(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmActionTest.java index ec8da1a81bf..21a3a218165 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/ScmActionTest.java @@ -22,23 +22,21 @@ package org.sonar.server.source.ws; import java.util.Date; import org.junit.Before; -import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; -import org.sonar.api.config.Settings; import org.sonar.api.utils.DateUtils; import org.sonar.api.utils.System2; import org.sonar.api.web.UserRole; import org.sonar.db.DbClient; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDto; -import org.sonar.server.component.ComponentFinder; import org.sonar.db.component.ComponentTesting; -import org.sonar.server.es.EsTester; +import org.sonar.db.protobuf.DbFileSources; +import org.sonar.db.source.FileSourceDto; +import org.sonar.server.component.ComponentFinder; import org.sonar.server.exceptions.ForbiddenException; -import org.sonar.server.source.index.SourceLineDoc; -import org.sonar.server.source.index.SourceLineIndex; -import org.sonar.server.source.index.SourceLineIndexDefinition; +import org.sonar.server.source.HtmlSourceDecorator; +import org.sonar.server.source.SourceService; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsTester; @@ -51,9 +49,6 @@ public class ScmActionTest { @Rule public DbTester dbTester = DbTester.create(System2.INSTANCE); - @ClassRule - public static EsTester esTester = new EsTester().addDefinitions(new SourceLineIndexDefinition(new Settings())); - @Rule public UserSessionRule userSessionRule = UserSessionRule.standalone(); @@ -64,8 +59,8 @@ public class ScmActionTest { @Before public void setUp() { dbTester.truncateTables(); - esTester.truncateIndices(); - tester = new WsTester(new SourcesWs(new ScmAction(dbClient, new SourceLineIndex(esTester.client()), userSessionRule, new ComponentFinder(dbClient)))); + tester = new WsTester( + new SourcesWs(new ScmAction(dbClient, new SourceService(dbTester.getDbClient(), new HtmlSourceDecorator()), userSessionRule, new ComponentFinder(dbClient)))); } @Test @@ -73,9 +68,11 @@ public class ScmActionTest { initFile(); userSessionRule.addProjectUuidPermissions(UserRole.CODEVIEWER, PROJECT_UUID); - esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 1) - ); + dbTester.getDbClient().fileSourceDao().insert(new FileSourceDto() + .setProjectUuid(PROJECT_UUID) + .setFileUuid(FILE_UUID) + .setSourceData(DbFileSources.Data.newBuilder().addLines( + newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 1)).build())); WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", FILE_KEY); request.execute().assertJson(getClass(), "show_scm.json"); @@ -86,12 +83,15 @@ public class ScmActionTest { initFile(); userSessionRule.addProjectUuidPermissions(UserRole.CODEVIEWER, PROJECT_UUID); - esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 1), - newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 2), - newSourceLine("julien", "456-789-101", DateUtils.parseDateTime("2015-03-27T12:34:56+0000"), 3), - newSourceLine("simon", "789-101-112", DateUtils.parseDateTime("2015-03-31T12:34:56+0000"), 4) - ); + dbTester.getDbClient().fileSourceDao().insert(new FileSourceDto() + .setProjectUuid(PROJECT_UUID) + .setFileUuid(FILE_UUID) + .setSourceData(DbFileSources.Data.newBuilder() + .addLines(newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 1)) + .addLines(newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 2)) + .addLines(newSourceLine("julien", "456-789-101", DateUtils.parseDateTime("2015-03-27T12:34:56+0000"), 3)) + .addLines(newSourceLine("simon", "789-101-112", DateUtils.parseDateTime("2015-03-31T12:34:56+0000"), 4)) + .build())); WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", FILE_KEY).setParam("from", "2").setParam("to", "3"); request.execute().assertJson(getClass(), "show_scm_from_given_range_lines.json"); @@ -103,14 +103,18 @@ public class ScmActionTest { userSessionRule.addProjectUuidPermissions(UserRole.CODEVIEWER, PROJECT_UUID); // lines 1 and 2 are the same commit, but not 3 (different date) - esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 1), - newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 2), - newSourceLine("julien", "456-789-101", DateUtils.parseDateTime("2015-03-27T12:34:56+0000"), 3), - newSourceLine("simon", "789-101-112", DateUtils.parseDateTime("2015-03-31T12:34:56+0000"), 4) - ); - - WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", FILE_KEY).setParam("commits_by_line", "true"); + dbTester.getDbClient().fileSourceDao().insert(new FileSourceDto() + .setProjectUuid(PROJECT_UUID) + .setFileUuid(FILE_UUID) + .setSourceData(DbFileSources.Data.newBuilder() + .addLines(newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 1)) + .addLines(newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 2)) + .addLines(newSourceLine("julien", "456-789-101", DateUtils.parseDateTime("2015-03-27T12:34:56+0000"), 3)) + .addLines(newSourceLine("simon", "789-101-112", DateUtils.parseDateTime("2015-03-31T12:34:56+0000"), 4)) + .build())); + + WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", FILE_KEY).setParam("commits_by_line", + "true"); request.execute().assertJson(getClass(), "not_group_lines_by_commit.json"); } @@ -120,14 +124,18 @@ public class ScmActionTest { userSessionRule.addProjectUuidPermissions(UserRole.CODEVIEWER, PROJECT_UUID); // lines 1 and 2 are the same commit, but not 3 (different date) - esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 1), - newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 2), - newSourceLine("julien", "456-789-101", DateUtils.parseDateTime("2015-03-27T12:34:56+0000"), 3), - newSourceLine("simon", "789-101-112", DateUtils.parseDateTime("2015-03-31T12:34:56+0000"), 4) - ); - - WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", FILE_KEY).setParam("commits_by_line", "false"); + dbTester.getDbClient().fileSourceDao().insert(new FileSourceDto() + .setProjectUuid(PROJECT_UUID) + .setFileUuid(FILE_UUID) + .setSourceData(DbFileSources.Data.newBuilder() + .addLines(newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 1)) + .addLines(newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 2)) + .addLines(newSourceLine("julien", "456-789-101", DateUtils.parseDateTime("2015-03-27T12:34:56+0000"), 3)) + .addLines(newSourceLine("simon", "789-101-112", DateUtils.parseDateTime("2015-03-31T12:34:56+0000"), 4)) + .build())); + + WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", FILE_KEY).setParam("commits_by_line", + "false"); request.execute().assertJson(getClass(), "group_lines_by_commit.json"); } @@ -136,14 +144,18 @@ public class ScmActionTest { initFile(); userSessionRule.addProjectUuidPermissions(UserRole.CODEVIEWER, PROJECT_UUID); - esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 1), - newSourceLine("julien", "123-456-710", DateUtils.parseDateTime("2015-03-29T12:34:56+0000"), 2), - newSourceLine("julien", "456-789-101", DateUtils.parseDateTime("2015-03-27T12:34:56+0000"), 3), - newSourceLine("simon", "789-101-112", DateUtils.parseDateTime("2015-03-31T12:34:56+0000"), 4) - ); - - WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", FILE_KEY).setParam("from", "-2").setParam("to", "3"); + dbTester.getDbClient().fileSourceDao().insert(new FileSourceDto() + .setProjectUuid(PROJECT_UUID) + .setFileUuid(FILE_UUID) + .setSourceData(DbFileSources.Data.newBuilder() + .addLines(newSourceLine("julien", "123-456-789", DateUtils.parseDateTime("2015-03-30T12:34:56+0000"), 1)) + .addLines(newSourceLine("julien", "123-456-710", DateUtils.parseDateTime("2015-03-29T12:34:56+0000"), 2)) + .addLines(newSourceLine("julien", "456-789-101", DateUtils.parseDateTime("2015-03-27T12:34:56+0000"), 3)) + .addLines(newSourceLine("simon", "789-101-112", DateUtils.parseDateTime("2015-03-31T12:34:56+0000"), 4)) + .build())); + + WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", FILE_KEY).setParam("from", + "-2").setParam("to", "3"); request.execute().assertJson(getClass(), "accept_negative_value_in_from_parameter.json"); } @@ -152,9 +164,10 @@ public class ScmActionTest { initFile(); userSessionRule.addProjectUuidPermissions(UserRole.CODEVIEWER, PROJECT_UUID); - esTester.putDocuments(SourceLineIndexDefinition.INDEX, SourceLineIndexDefinition.TYPE, - newSourceLine(null, null, null, 1) - ); + dbTester.getDbClient().fileSourceDao().insert(new FileSourceDto() + .setProjectUuid(PROJECT_UUID) + .setFileUuid(FILE_UUID) + .setSourceData(DbFileSources.Data.newBuilder().build())); WsTester.TestRequest request = tester.newGetRequest("api/sources", "scm").setParam("key", FILE_KEY); request.execute().assertJson(getClass(), "return_empty_value_when_no_scm.json"); @@ -175,13 +188,12 @@ public class ScmActionTest { dbTester.getSession().commit(); } - private SourceLineDoc newSourceLine(String author, String revision, Date date, int line) { - return new SourceLineDoc() + private DbFileSources.Line newSourceLine(String author, String revision, Date date, int line) { + return DbFileSources.Line.newBuilder() .setScmAuthor(author) .setScmRevision(revision) - .setScmDate(date) + .setScmDate(date.getTime()) .setLine(line) - .setProjectUuid(PROJECT_UUID) - .setFileUuid(FILE_UUID); + .build(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java index c9aef5e5681..9cee9f02976 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/ShowActionTest.java @@ -31,8 +31,8 @@ import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.component.ComponentDao; import org.sonar.db.component.ComponentDto; -import org.sonar.server.component.ComponentFinder; import org.sonar.db.component.ComponentTesting; +import org.sonar.server.component.ComponentFinder; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.source.SourceService; import org.sonar.server.tester.UserSessionRule; @@ -77,16 +77,15 @@ public class ShowActionTest { @Test public void show_source() throws Exception { String fileKey = "src/Foo.java"; - userSessionRule.addComponentPermission(UserRole.CODEVIEWER, "polop", fileKey); + userSessionRule.addProjectUuidPermissions(UserRole.CODEVIEWER, project.uuid()); when(componentDao.selectByKey(session, fileKey)).thenReturn(Optional.of(file)); - when(sourceService.getLinesAsHtml(eq(file.uuid()), anyInt(), anyInt())).thenReturn(newArrayList( + when(sourceService.getLinesAsHtml(eq(session), eq(file.uuid()), anyInt(), anyInt())).thenReturn(Optional.of((Iterable) newArrayList( "/*", " * Header", " */", "", "public class HelloWorld {", - "}" - )); + "}"))); WsTester.TestRequest request = tester.newGetRequest("api/sources", "show").setParam("key", fileKey); request.execute().assertJson(getClass(), "show_source.json"); @@ -95,13 +94,12 @@ public class ShowActionTest { @Test public void show_source_with_from_and_to_params() throws Exception { String fileKey = "src/Foo.java"; - userSessionRule.addComponentPermission(UserRole.CODEVIEWER, "polop", fileKey); + userSessionRule.addProjectUuidPermissions(UserRole.CODEVIEWER, project.uuid()); when(componentDao.selectByKey(session, fileKey)).thenReturn(Optional.of(file)); - when(sourceService.getLinesAsHtml(file.uuid(), 3, 5)).thenReturn(newArrayList( + when(sourceService.getLinesAsHtml(session, file.uuid(), 3, 5)).thenReturn(Optional.of((Iterable) newArrayList( " */", "", - "public class HelloWorld {" - )); + "public class HelloWorld {"))); WsTester.TestRequest request = tester .newGetRequest("api/sources", "show") .setParam("key", fileKey) @@ -113,25 +111,25 @@ public class ShowActionTest { @Test public void show_source_accept_from_less_than_one() throws Exception { String fileKey = "src/Foo.java"; - userSessionRule.addComponentPermission(UserRole.CODEVIEWER, "polop", fileKey); + userSessionRule.addProjectUuidPermissions(UserRole.CODEVIEWER, project.uuid()); when(componentDao.selectByKey(session, fileKey)).thenReturn(Optional.of(file)); - when(sourceService.getLinesAsHtml(file.uuid(), 1, 5)).thenReturn(newArrayList( + when(sourceService.getLinesAsHtml(session, file.uuid(), 1, 5)).thenReturn(Optional.of((Iterable) newArrayList( " */", "", - "public class HelloWorld {" - )); + "public class HelloWorld {"))); WsTester.TestRequest request = tester .newGetRequest("api/sources", "show") .setParam("key", fileKey) .setParam("from", "0") .setParam("to", "5"); request.execute(); - verify(sourceService).getLinesAsHtml(file.uuid(), 1, 5); + verify(sourceService).getLinesAsHtml(session, file.uuid(), 1, 5); } @Test(expected = ForbiddenException.class) public void require_code_viewer() throws Exception { String fileKey = "src/Foo.java"; + when(componentDao.selectByKey(session, fileKey)).thenReturn(Optional.of(file)); tester.newGetRequest("api/sources", "show").setParam("key", fileKey).execute(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java index 573d9a7739b..2235ed7fe8a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/source/ws/SourcesWsTest.java @@ -27,7 +27,6 @@ import org.sonar.server.component.ComponentFinder; import org.sonar.server.db.DbClient; import org.sonar.server.source.HtmlSourceDecorator; import org.sonar.server.source.SourceService; -import org.sonar.server.source.index.SourceLineIndex; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsTester; @@ -40,10 +39,9 @@ public class SourcesWsTest { ShowAction showAction = new ShowAction(mock(SourceService.class), mock(DbClient.class), userSessionRule, mock(ComponentFinder.class)); RawAction rawAction = new RawAction(mock(DbClient.class), mock(SourceService.class), userSessionRule, mock(ComponentFinder.class)); - LinesAction linesAction = new LinesAction(mock(DbClient.class), mock(SourceLineIndex.class), mock(HtmlSourceDecorator.class), userSessionRule); + LinesAction linesAction = new LinesAction(mock(ComponentFinder.class), mock(DbClient.class), mock(SourceService.class), mock(HtmlSourceDecorator.class), userSessionRule); HashAction hashAction = new HashAction(mock(DbClient.class), userSessionRule, mock(ComponentFinder.class)); - IndexAction indexAction = new IndexAction(mock(DbClient.class), mock(SourceService.class), userSessionRule, mock(ComponentFinder.class)); - WsTester tester = new WsTester(new SourcesWs(showAction, rawAction, linesAction, hashAction, indexAction)); + WsTester tester = new WsTester(new SourcesWs(showAction, rawAction, linesAction, hashAction)); @Test public void define_ws() { @@ -51,7 +49,7 @@ public class SourcesWsTest { assertThat(controller).isNotNull(); assertThat(controller.since()).isEqualTo("4.2"); assertThat(controller.description()).isNotEmpty(); - assertThat(controller.actions()).hasSize(5); + assertThat(controller.actions()).hasSize(4); WebService.Action show = controller.action("show"); assertThat(show).isNotNull(); @@ -84,14 +82,5 @@ public class SourcesWsTest { assertThat(hash.isInternal()).isTrue(); assertThat(hash.responseExampleAsString()).isNotEmpty(); assertThat(hash.params()).hasSize(1); - - WebService.Action index = controller.action("index"); - assertThat(index).isNotNull(); - assertThat(index.handler()).isSameAs(indexAction); - assertThat(index.since()).isEqualTo("5.0"); - assertThat(index.isInternal()).isTrue(); - assertThat(index.responseExampleAsString()).isNotEmpty(); - assertThat(index.params()).hasSize(3); - } } diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file1_line1.json b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file1_line1.json deleted file mode 100644 index cfc6358c9c2..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file1_line1.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "projectUuid": "abcd", - "fileUuid": "file1", - "line": 1, - "scmAuthor": "polop", - "scmDate": "2014-01-01T12:34:56.7+01:00", - "scmRevision": "cafebabe", - "source": "// Empty", - "updatedAt": "2014-01-01T23:45:01.8+01:00" -} \ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file1_line2.json b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file1_line2.json deleted file mode 100644 index e4bafc7db53..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file1_line2.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "projectUuid": "abcd", - "fileUuid": "file1", - "line": 2, - "scmAuthor": "polop", - "scmDate": "2014-01-01T12:34:56.7+01:00", - "scmRevision": "cafebabe", - "source": "// Empty", - "updatedAt": "2014-01-01T23:45:01.8+01:00" -} \ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file1_line3.json b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file1_line3.json deleted file mode 100644 index 6dce5c1758d..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file1_line3.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "projectUuid": "abcd", - "fileUuid": "file1", - "line": 3, - "scmAuthor": "polop", - "scmDate": "2014-01-01T12:34:56.7+01:00", - "scmRevision": "cafebabe", - "source": "// Empty", - "updatedAt": "2014-01-01T23:45:01.8+01:00" -} \ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file2_line1.json b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file2_line1.json deleted file mode 100644 index d9192636407..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file2_line1.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "projectUuid": "abcd", - "fileUuid": "file2", - "line": 1, - "scmAuthor": "polop", - "scmDate": "2014-01-01T12:34:56.7+01:00", - "scmRevision": "cafebabe", - "source": "// Empty", - "updatedAt": "2014-01-01T23:45:01.8+01:00" -} \ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file2_line2.json b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file2_line2.json deleted file mode 100644 index fc8aa032e4e..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file2_line2.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "projectUuid": "abcd", - "fileUuid": "file2", - "line": 2, - "scmAuthor": "polop", - "scmDate": "2014-01-01T12:34:56.7+01:00", - "scmRevision": "cafebabe", - "source": "// Empty", - "updatedAt": "2014-01-01T23:45:01.8+01:00" -} \ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file2_line3.json b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file2_line3.json deleted file mode 100644 index a1383e76f1d..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexTest/file2_line3.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "projectUuid": "abcd", - "fileUuid": "file2", - "line": 3, - "scmAuthor": "polop", - "scmDate": "2014-01-01T12:34:56.7+01:00", - "scmRevision": "cafebabe", - "source": "// Empty", - "updatedAt": "2014-01-01T23:45:01.8+01:00" -} \ No newline at end of file diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P1_F1_line1.json b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P1_F1_line1.json deleted file mode 100644 index 82498c6aceb..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P1_F1_line1.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "projectUuid": "P1", - "fileUuid": "F1", - "line": 1, - "scmAuthor": "polop", - "scmDate": "2014-01-01T12:34:56.7+01:00", - "scmRevision": "cafebabe", - "source": "// Empty", - "updatedAt": "2014-01-01T23:45:01.8+01:00", - "utLineHits": 0, - "utConditions": 0, - "utCoveredConditions": 0, - "itLineHits": 0, - "itConditions": 0, - "itCoveredConditions": 0, - "overallLineHits": 0, - "overallConditions": 0, - "overallCoveredConditions": 0 -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P1_F1_line2.json b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P1_F1_line2.json deleted file mode 100644 index e33192a41e3..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P1_F1_line2.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "projectUuid": "P1", - "fileUuid": "F1", - "line": 2, - "scmAuthor": "polop", - "scmDate": "2014-01-01T12:34:56.7+01:00", - "scmRevision": "cafebabe", - "source": "// Empty", - "updatedAt": "2014-01-01T23:45:01.8+01:00", - "utLineHits": 0, - "utConditions": 0, - "utCoveredConditions": 0, - "itLineHits": 0, - "itConditions": 0, - "itCoveredConditions": 0, - "overallLineHits": 0, - "overallConditions": 0, - "overallCoveredConditions": 0 -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P1_F2_line1.json b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P1_F2_line1.json deleted file mode 100644 index 7db71d27673..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P1_F2_line1.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "projectUuid": "P1", - "fileUuid": "F2", - "line": 1, - "scmAuthor": "polop", - "scmDate": "2014-01-01T12:34:56.7+01:00", - "scmRevision": "cafebabe", - "source": "// Empty", - "updatedAt": "2014-01-01T23:45:01.8+01:00", - "utLineHits": 0, - "utConditions": 0, - "utCoveredConditions": 0, - "itLineHits": 0, - "itConditions": 0, - "itCoveredConditions": 0, - "overallLineHits": 0, - "overallConditions": 0, - "overallCoveredConditions": 0 -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P2_F3_line1.json b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P2_F3_line1.json deleted file mode 100644 index e87ae84d428..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/P2_F3_line1.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "projectUuid": "P2", - "fileUuid": "F3", - "line": 1, - "scmAuthor": "polop", - "scmDate": "2014-01-01T12:34:56.7+01:00", - "scmRevision": "cafebabe", - "source": "// Empty", - "updatedAt": "2014-01-01T23:45:01.8+01:00", - "utLineHits": 0, - "utConditions": 0, - "utCoveredConditions": 0, - "itLineHits": 0, - "itConditions": 0, - "itCoveredConditions": 0, - "overallLineHits": 0, - "overallConditions": 0, - "overallCoveredConditions": 0 -} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/db.xml b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/db.xml deleted file mode 100644 index bea210dc670..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineIndexerTest/db.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/filter_by_project.xml b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/filter_by_project.xml deleted file mode 100644 index 1f0032170a0..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/filter_by_project.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/filter_by_project_and_date.xml b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/filter_by_project_and_date.xml deleted file mode 100644 index e6289cd994c..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/filter_by_project_and_date.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/schema.sql b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/schema.sql deleted file mode 100644 index 99f823ff74d..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/schema.sql +++ /dev/null @@ -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 -); diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/shared.xml deleted file mode 100644 index 053270327d6..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/index/SourceLineResultSetIteratorTest/shared.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/ws/LinesActionTest/show_paginated_lines.json b/server/sonar-server/src/test/resources/org/sonar/server/source/ws/LinesActionTest/show_paginated_lines.json new file mode 100644 index 00000000000..36e9c5b0c46 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/source/ws/LinesActionTest/show_paginated_lines.json @@ -0,0 +1,18 @@ +{ + "sources": [ + { + "line": 3, + "code": "

SOURCE_3

", + "scmAuthor": "AUTHOR_3", + "scmRevision": "REVISION_3", + "scmDate": "1974-10-03T03:40:00+0100", + "utLineHits": 3, + "utConditions": 4, + "utCoveredConditions": 5, + "itLineHits": 6, + "itConditions": 7, + "itCoveredConditions": 8, + "duplicated": true + } + ] +} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/ws/LinesActionTest/show_source.json b/server/sonar-server/src/test/resources/org/sonar/server/source/ws/LinesActionTest/show_source.json index eebd43bc502..d87632e1424 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/ws/LinesActionTest/show_source.json +++ b/server/sonar-server/src/test/resources/org/sonar/server/source/ws/LinesActionTest/show_source.json @@ -1,43 +1,46 @@ { "sources": [ { - "code": "package org.polop;", "line": 1, - "scmAuthor": "polop", - "scmRevision": "cafebabe", - "utLineHits": 3, + "code": "

SOURCE_1

", + "scmAuthor": "AUTHOR_1", + "scmRevision": "REVISION_1", + "scmDate": "1974-10-03T03:40:00+0100", + "utLineHits": 1, "utConditions": 2, - "utCoveredConditions": 1, - "itLineHits": 3, - "itConditions": 2, - "itCoveredConditions": 1 + "utCoveredConditions": 3, + "itLineHits": 4, + "itConditions": 5, + "itCoveredConditions": 6, + "duplicated": true }, { - "code": "abc", "line": 2, - "scmAuthor": "polop", - "scmRevision": "cafebabe", - "utLineHits": 3, - "utConditions": 2, - "utCoveredConditions": 1, + "code": "

SOURCE_2

", + "scmAuthor": "AUTHOR_2", + "scmRevision": "REVISION_2", + "scmDate": "1974-10-03T03:40:00+0100", + "utLineHits": 2, + "utConditions": 3, + "utCoveredConditions": 4, + "itLineHits": 5, + "itConditions": 6, + "itCoveredConditions": 7, "duplicated": true }, { - "code": "}", "line": 3, - "scmAuthor": "polop", - "scmRevision": "cafebabe", - "itLineHits": 3, - "itConditions": 2, - "itCoveredConditions": 1 + "code": "

SOURCE_3

", + "scmAuthor": "AUTHOR_3", + "scmRevision": "REVISION_3", + "scmDate": "1974-10-03T03:40:00+0100", + "utLineHits": 3, + "utConditions": 4, + "utCoveredConditions": 5, + "itLineHits": 6, + "itConditions": 7, + "itCoveredConditions": 8, + "duplicated": true } ] } - - - - - - - - diff --git a/server/sonar-server/src/test/resources/org/sonar/server/source/ws/LinesActionTest/show_source_with_params_from_and_to.json b/server/sonar-server/src/test/resources/org/sonar/server/source/ws/LinesActionTest/show_source_with_params_from_and_to.json deleted file mode 100644 index ba2a4c6e52b..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/source/ws/LinesActionTest/show_source_with_params_from_and_to.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "sources": [ - { - "code": "}", - "line": 3, - "scmAuthor": "polop", - "scmRevision": "cafebabe" - } - ] -} diff --git a/sonar-db/src/main/java/org/sonar/db/source/FileSourceDao.java b/sonar-db/src/main/java/org/sonar/db/source/FileSourceDao.java index 6aeb7d0742b..f1448a545bf 100644 --- a/sonar-db/src/main/java/org/sonar/db/source/FileSourceDao.java +++ b/sonar-db/src/main/java/org/sonar/db/source/FileSourceDao.java @@ -55,6 +55,11 @@ public class FileSourceDao implements Dao { } } + @CheckForNull + public FileSourceDto selectSourceByFileUuid(DbSession session, String fileUuid) { + return mapper(session).select(fileUuid, Type.SOURCE); + } + @CheckForNull public FileSourceDto selectTest(String fileUuid) { DbSession session = mybatis.openSession(false); -- 2.39.5