import org.sonar.ce.task.projectanalysis.component.ReportModulesPath;
import org.sonar.ce.task.projectanalysis.component.SiblingComponentsWithOpenIssues;
import org.sonar.ce.task.projectanalysis.component.TreeRootHolderImpl;
-import org.sonar.ce.task.projectanalysis.dbmigration.DbMigrationModule;
import org.sonar.ce.task.projectanalysis.duplication.CrossProjectDuplicationStatusHolderImpl;
import org.sonar.ce.task.projectanalysis.duplication.DuplicationMeasures;
import org.sonar.ce.task.projectanalysis.duplication.DuplicationRepositoryImpl;
// File System
new ComputationTempFolderProvider(),
- DbMigrationModule.class,
ReportModulesPath.class,
MetricModule.class,
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.dbmigration;
-
-import org.sonar.core.platform.Module;
-
-public class DbMigrationModule extends Module {
- @Override
- protected void configureModule() {
- add(ProjectAnalysisDataChangesImpl.class);
- ProjectAnalysisDataChangesImpl.getDataChangeClasses().forEach(this::add);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.dbmigration;
-
-import com.google.common.collect.Iterables;
-import java.sql.SQLException;
-import org.sonar.ce.task.CeTask;
-import org.sonar.db.Database;
-import org.sonar.db.source.FileSourceDto;
-import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.server.platform.db.migration.step.MassUpdate;
-import org.sonar.server.platform.db.migration.step.Select;
-import org.sonar.server.platform.db.migration.step.SqlStatement;
-
-import static org.sonar.db.source.FileSourceDto.LINE_COUNT_NOT_POPULATED;
-
-public class PopulateFileSourceLineCount extends DataChange implements ProjectAnalysisDataChange {
- private final CeTask ceTask;
-
- public PopulateFileSourceLineCount(Database database, CeTask ceTask) {
- super(database);
- this.ceTask = ceTask;
- }
-
- @Override
- protected void execute(Context context) throws SQLException {
- String componentUuid = ceTask.getComponent().get().getUuid();
- Long unInitializedFileSources = context.prepareSelect("select count(1) from file_sources where line_count = ? and project_uuid = ?")
- .setInt(1, LINE_COUNT_NOT_POPULATED)
- .setString(2, componentUuid)
- .get(row -> row.getLong(1));
-
- if (unInitializedFileSources != null && unInitializedFileSources > 0) {
- MassUpdate massUpdate = context.prepareMassUpdate();
- massUpdate.select("select uuid,line_hashes from file_sources where line_count = ? and project_uuid = ?")
- .setInt(1, LINE_COUNT_NOT_POPULATED)
- .setString(2, componentUuid);
- massUpdate.update("update file_sources set line_count = ? where uuid = ?");
- massUpdate.rowPluralName("line counts of sources of project " + componentUuid);
- massUpdate.execute(PopulateFileSourceLineCount::handle);
- }
- }
-
- private static boolean handle(Select.Row row, SqlStatement update) throws SQLException {
- String rowUuid = row.getString(1);
- String rawData = row.getNullableString(2);
-
- int lineCount = rawData == null ? 0 : Iterables.size(FileSourceDto.LINES_HASHES_SPLITTER.split(rawData));
- update.setInt(1, lineCount);
- update.setString(2, rowUuid);
- return true;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.dbmigration;
-
-import org.sonar.server.platform.db.migration.step.MigrationStep;
-
-/**
- * Marker interface of {@link MigrationStep} for the implementations to be run in
- * {@link org.sonar.ce.task.projectanalysis.step.DbMigrationsStep DbMigrationsStep}.
- * <p>
- * {@link MigrationStep} execute during project report analysis should perform <strong>only data change operations</strong>.
- */
-public interface ProjectAnalysisDataChange extends MigrationStep {
-
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.dbmigration;
-
-import java.util.List;
-
-public interface ProjectAnalysisDataChanges {
- /**
- * @return {@link ProjectAnalysisDataChange} instances to be executed in order.
- */
- List<ProjectAnalysisDataChange> getDataChanges();
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.dbmigration;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.ImmutableList.of;
-import static org.sonar.core.util.stream.MoreCollectors.toList;
-import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
-
-/**
- * Implementation of {@link ProjectAnalysisDataChanges} based on an ordered list of {@link ProjectAnalysisDataChange}
- * classes and the {@link ProjectAnalysisDataChange} instances which can be injected by the container.
- */
-public class ProjectAnalysisDataChangesImpl implements ProjectAnalysisDataChanges {
- private static final List<Class<? extends ProjectAnalysisDataChange>> DATA_CHANGE_CLASSES_IN_ORDER_OF_EXECUTION = of(
- PopulateFileSourceLineCount.class);
- private final List<ProjectAnalysisDataChange> dataChangeInstances;
-
- public ProjectAnalysisDataChangesImpl(ProjectAnalysisDataChange[] dataChanges) {
- checkArgument(dataChanges.length == DATA_CHANGE_CLASSES_IN_ORDER_OF_EXECUTION.size(),
- "Number of ProjectAnalysisDataChange instance available (%s) is inconsistent with the number of declared ProjectAnalysisDataChange types (%s)",
- dataChanges.length,
- DATA_CHANGE_CLASSES_IN_ORDER_OF_EXECUTION.size());
- Map<? extends Class<? extends ProjectAnalysisDataChange>, ProjectAnalysisDataChange> dataChangesByClass = Arrays.stream(dataChanges)
- .collect(uniqueIndex(ProjectAnalysisDataChange::getClass));
- dataChangeInstances = DATA_CHANGE_CLASSES_IN_ORDER_OF_EXECUTION.stream()
- .map(dataChangesByClass::get)
- .filter(Objects::nonNull)
- .collect(toList(DATA_CHANGE_CLASSES_IN_ORDER_OF_EXECUTION.size()));
- checkState(dataChangeInstances.size() == DATA_CHANGE_CLASSES_IN_ORDER_OF_EXECUTION.size(),
- "Some of the ProjectAnalysisDataChange type declared have no instance in the container");
- }
-
- static List<Class<? extends ProjectAnalysisDataChange>> getDataChangeClasses() {
- return DATA_CHANGE_CLASSES_IN_ORDER_OF_EXECUTION;
- }
-
- @Override
- public List<ProjectAnalysisDataChange> getDataChanges() {
- return dataChangeInstances;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-@ParametersAreNonnullByDefault
-package org.sonar.ce.task.projectanalysis.dbmigration;
-
-import javax.annotation.ParametersAreNonnullByDefault;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.step;
-
-import java.sql.SQLException;
-import org.sonar.ce.task.projectanalysis.dbmigration.ProjectAnalysisDataChange;
-import org.sonar.ce.task.projectanalysis.dbmigration.ProjectAnalysisDataChanges;
-import org.sonar.ce.task.step.ComputationStep;
-
-public class DbMigrationsStep implements ComputationStep {
- private final ProjectAnalysisDataChanges dataChanges;
-
- public DbMigrationsStep(ProjectAnalysisDataChanges dataChanges) {
- this.dataChanges = dataChanges;
- }
-
- @Override
- public String getDescription() {
- return "Execute DB migrations for current project";
- }
-
- @Override
- public void execute(ComputationStep.Context context) {
- dataChanges.getDataChanges().forEach(DbMigrationsStep::execute);
- }
-
- private static void execute(ProjectAnalysisDataChange dataChange) {
- try {
- dataChange.execute();
- } catch (SQLException e) {
- throw new IllegalStateException("Failed to perform DB migration for project", e);
- }
- }
-
-}
ExtractReportStep.class,
PersistScannerContextStep.class,
PersistAnalysisWarningsStep.class,
- DbMigrationsStep.class,
GenerateAnalysisUuid.class,
// Builds Component tree
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.dbmigration;
-
-import java.util.Objects;
-import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DbMigrationModuleTest {
- private DbMigrationModule underTest = new DbMigrationModule();
-
- @Test
- public void module_configure_ProjectAnalysisDataChanges_implementation() {
- ComponentContainer container = new ComponentContainer();
-
- underTest.configure(container);
-
- assertThat(container.getPicoContainer().getComponentAdapters(ProjectAnalysisDataChanges.class))
- .hasSize(1);
- }
-
- @Test
- public void module_includes_ProjectAnalysisDataChange_classes() {
- ComponentContainer container = new ComponentContainer();
-
- underTest.configure(container);
-
- assertThat(ProjectAnalysisDataChangesImpl.getDataChangeClasses()
- .stream()
- .map(t -> container.getPicoContainer().getComponentAdapter(t))
- .filter(Objects::nonNull)).hasSize(ProjectAnalysisDataChangesImpl.getDataChangeClasses().size());
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.dbmigration;
-
-import java.sql.SQLException;
-import java.util.Optional;
-import java.util.Random;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-import javax.annotation.Nullable;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.System2;
-import org.sonar.ce.task.CeTask;
-import org.sonar.core.util.SequenceUuidFactory;
-import org.sonar.core.util.UuidFactory;
-import org.sonar.db.DbTester;
-
-import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.db.source.FileSourceDto.LINE_COUNT_NOT_POPULATED;
-
-public class PopulateFileSourceLineCountTest {
-
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- @Rule
- public DbTester db = DbTester.create(System2.INSTANCE);
-
- private UuidFactory uuidFactory = new SequenceUuidFactory();
-
- private Random random = new Random();
- private CeTask ceTask = mock(CeTask.class);
- private PopulateFileSourceLineCount underTest = new PopulateFileSourceLineCount(db.database(), ceTask);
-
- @Test
- public void execute_has_no_effect_on_empty_table() throws SQLException {
- String projectUuid = randomAlphanumeric(4);
- when(ceTask.getComponent()).thenReturn(newComponent(projectUuid));
-
- underTest.execute();
- }
-
- @Test
- public void execute_populates_line_count_of_any_type() throws SQLException {
- String projectUuid = randomAlphanumeric(4);
- String fileUuid = randomAlphanumeric(5);
- when(ceTask.getComponent()).thenReturn(newComponent(projectUuid));
- int lineCount = 1 + random.nextInt(15);
- insertUnpopulatedFileSource(projectUuid, fileUuid, lineCount);
- assertThat(getLineCountByFileUuid(fileUuid)).isEqualTo(LINE_COUNT_NOT_POPULATED);
-
- underTest.execute();
-
- assertThat(getLineCountByFileUuid(fileUuid)).isEqualTo(lineCount);
- }
-
- @Test
- public void execute_changes_only_file_source_with_LINE_COUNT_NOT_POPULATED_value() throws SQLException {
- String projectUuid = randomAlphanumeric(4);
- String fileUuid1 = randomAlphanumeric(5);
- String fileUuid2 = randomAlphanumeric(6);
- String fileUuid3 = randomAlphanumeric(7);
- int lineCountFile1 = 100 + random.nextInt(15);
- int lineCountFile2 = 50 + random.nextInt(15);
- int lineCountFile3 = 150 + random.nextInt(15);
-
- when(ceTask.getComponent()).thenReturn(newComponent(projectUuid));
- insertPopulatedFileSource(projectUuid, fileUuid1, lineCountFile1);
- int badLineCountFile2 = insertInconsistentPopulatedFileSource(projectUuid, fileUuid2, lineCountFile2);
- insertUnpopulatedFileSource(projectUuid, fileUuid3, lineCountFile3);
- assertThat(getLineCountByFileUuid(fileUuid1)).isEqualTo(lineCountFile1);
- assertThat(getLineCountByFileUuid(fileUuid2)).isEqualTo(badLineCountFile2);
- assertThat(getLineCountByFileUuid(fileUuid3)).isEqualTo(LINE_COUNT_NOT_POPULATED);
-
- underTest.execute();
-
- assertThat(getLineCountByFileUuid(fileUuid1)).isEqualTo(lineCountFile1);
- assertThat(getLineCountByFileUuid(fileUuid2)).isEqualTo(badLineCountFile2);
- assertThat(getLineCountByFileUuid(fileUuid3)).isEqualTo(lineCountFile3);
- }
-
- @Test
- public void execute_changes_only_file_source_of_CeTask_component_uuid() throws SQLException {
- String projectUuid1 = randomAlphanumeric(4);
- String projectUuid2 = randomAlphanumeric(5);
- String fileUuid1 = randomAlphanumeric(6);
- String fileUuid2 = randomAlphanumeric(7);
- int lineCountFile1 = 100 + random.nextInt(15);
- int lineCountFile2 = 30 + random.nextInt(15);
-
- when(ceTask.getComponent()).thenReturn(newComponent(projectUuid1));
- insertUnpopulatedFileSource(projectUuid1, fileUuid1, lineCountFile1);
- insertUnpopulatedFileSource(projectUuid2, fileUuid2, lineCountFile2);
-
- underTest.execute();
-
- assertThat(getLineCountByFileUuid(fileUuid1)).isEqualTo(lineCountFile1);
- assertThat(getLineCountByFileUuid(fileUuid2)).isEqualTo(LINE_COUNT_NOT_POPULATED);
- }
-
- @Test
- public void execute_set_line_count_to_zero_when_file_source_has_no_line_hashes() throws SQLException {
- String projectUuid = randomAlphanumeric(4);
- String fileUuid1 = randomAlphanumeric(5);
-
- when(ceTask.getComponent()).thenReturn(newComponent(projectUuid));
- insertFileSource(projectUuid, fileUuid1, null, LINE_COUNT_NOT_POPULATED);
-
- underTest.execute();
-
- assertThat(getLineCountByFileUuid(fileUuid1)).isZero();
- }
-
- @Test
- public void execute_set_line_count_to_1_when_file_source_has_empty_line_hashes() throws SQLException {
- String projectUuid = randomAlphanumeric(4);
- String fileUuid1 = randomAlphanumeric(5);
-
- when(ceTask.getComponent()).thenReturn(newComponent(projectUuid));
- insertFileSource(projectUuid, fileUuid1, "", LINE_COUNT_NOT_POPULATED);
-
- underTest.execute();
-
- assertThat(getLineCountByFileUuid(fileUuid1)).isEqualTo(1);
- }
-
- private int getLineCountByFileUuid(String fileUuid) {
- Long res = (Long) db.selectFirst("select line_count as \"LINE_COUNT\" from file_sources where file_uuid = '" + fileUuid + "'")
- .get("LINE_COUNT");
- return res.intValue();
- }
-
- private void insertUnpopulatedFileSource(String projectUuid, String fileUuid, int numberOfHashes) {
- String lineHashes = generateLineHashes(numberOfHashes);
-
- insertFileSource(projectUuid, fileUuid, lineHashes, LINE_COUNT_NOT_POPULATED);
- }
-
- private void insertPopulatedFileSource(String projectUuid, String fileUuid, int lineCount) {
- String lineHashes = generateLineHashes(lineCount);
-
- insertFileSource(projectUuid, fileUuid, lineHashes, lineCount);
- }
-
- private int insertInconsistentPopulatedFileSource(String projectUuid, String fileUuid, int lineCount) {
- String lineHashes = generateLineHashes(lineCount);
- int badLineCount = lineCount + random.nextInt(6);
-
- insertFileSource(projectUuid, fileUuid, lineHashes, badLineCount);
-
- return badLineCount;
- }
-
- private static String generateLineHashes(int numberOfHashes) {
- return IntStream.range(0, numberOfHashes)
- .mapToObj(String::valueOf)
- .collect(Collectors.joining("\n"));
- }
-
- private void insertFileSource(String projectUuid, String fileUuid, @Nullable String lineHashes, int lineCount) {
- db.executeInsert(
- "FILE_SOURCES",
- "UUID", uuidFactory.create(),
- "PROJECT_UUID", projectUuid,
- "FILE_UUID", fileUuid,
- "LINE_HASHES", lineHashes,
- "LINE_COUNT", lineCount,
- "CREATED_AT", 1_222_333L,
- "UPDATED_AT", 1_222_333L);
- db.commit();
- }
-
- private static Optional<CeTask.Component> newComponent(String projectUuid) {
- return Optional.of(new CeTask.Component(projectUuid, "key_" + projectUuid, "name_" + projectUuid));
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.dbmigration;
-
-import java.util.List;
-import java.util.stream.Collectors;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.ce.task.CeTask;
-import org.sonar.db.Database;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class ProjectAnalysisDataChangesImplTest {
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
- @Test
- public void constructor_throws_IAE_if_argument_is_empty() {
- ProjectAnalysisDataChange[] empty = new ProjectAnalysisDataChange[0];
- int expectedArraySize = ProjectAnalysisDataChangesImpl.getDataChangeClasses().size();
-
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("Number of ProjectAnalysisDataChange instance available (0) is inconsistent with " +
- "the number of declared ProjectAnalysisDataChange types (" + expectedArraySize + ")");
-
- new ProjectAnalysisDataChangesImpl(empty);
- }
-
- @Test
- public void constructor_throws_ISE_if_an_instance_of_declared_class_is_missing() {
- ProjectAnalysisDataChange[] wrongInstance = new ProjectAnalysisDataChange[] {
- mock(ProjectAnalysisDataChange.class)
- };
-
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Some of the ProjectAnalysisDataChange type declared have no instance in the container");
-
- new ProjectAnalysisDataChangesImpl(wrongInstance);
-
- }
-
- @Test
- public void getDataChanges_returns_instances_of_classes_in_order_defined_by_getDataChangeClasses() {
- Database database = mock(Database.class);
- CeTask ceTask = mock(CeTask.class);
- ProjectAnalysisDataChangesImpl underTest = new ProjectAnalysisDataChangesImpl(new ProjectAnalysisDataChange[] {
- new PopulateFileSourceLineCount(database, ceTask)
- });
-
- List<ProjectAnalysisDataChange> dataChanges = underTest.getDataChanges();
-
- List<? extends Class<?>> dataChangeClasses = dataChanges
- .stream()
- .map(ProjectAnalysisDataChange::getClass)
- .collect(Collectors.toList());
- assertThat(dataChangeClasses).isEqualTo(ProjectAnalysisDataChangesImpl.getDataChangeClasses());
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.step;
-
-import com.google.common.collect.ImmutableList;
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.Random;
-import java.util.stream.IntStream;
-import org.junit.Test;
-import org.mockito.InOrder;
-import org.mockito.Mockito;
-import org.sonar.ce.task.projectanalysis.dbmigration.ProjectAnalysisDataChange;
-import org.sonar.ce.task.projectanalysis.dbmigration.ProjectAnalysisDataChanges;
-import org.sonar.ce.task.step.TestComputationStepContext;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.fail;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class DbMigrationsStepTest {
- private ProjectAnalysisDataChanges projectAnalysisDataChanges = mock(ProjectAnalysisDataChanges.class);
-
- private DbMigrationsStep underTest = new DbMigrationsStep(projectAnalysisDataChanges);
-
- @Test
- public void execute_has_no_effect_if_there_is_no_DataChange() {
- underTest.execute(new TestComputationStepContext());
- }
-
- @Test
- public void execute_calls_execute_on_DataChange_instances_in_order_provided_by_ProjectAnalysisDataChanges() {
- ProjectAnalysisDataChange[] dataChanges = IntStream.range(0, 5 + new Random().nextInt(5))
- .mapToObj(i -> mock(ProjectAnalysisDataChange.class))
- .toArray(ProjectAnalysisDataChange[]::new);
- InOrder inOrder = Mockito.inOrder(dataChanges);
- when(projectAnalysisDataChanges.getDataChanges()).thenReturn(Arrays.asList(dataChanges));
-
- underTest.execute(new TestComputationStepContext());
-
- Arrays.stream(dataChanges).forEach(t -> {
- try {
- inOrder.verify(t).execute();
- } catch (SQLException e) {
- throw new RuntimeException("mock execute method throw an exception??!!??", e);
- }
- });
- }
-
- @Test
- public void execute_stops_executing_and_throws_ISE_at_first_failing_DataChange() throws SQLException {
- ProjectAnalysisDataChange okMock1 = mock(ProjectAnalysisDataChange.class);
- ProjectAnalysisDataChange okMock2 = mock(ProjectAnalysisDataChange.class);
- ProjectAnalysisDataChange failingMock1 = mock(ProjectAnalysisDataChange.class);
- SQLException expected = new SQLException("Faiking DataChange throwing a SQLException");
- doThrow(expected).when(failingMock1).execute();
- ProjectAnalysisDataChange okMock3 = mock(ProjectAnalysisDataChange.class);
- ProjectAnalysisDataChange failingMock2 = mock(ProjectAnalysisDataChange.class);
- doThrow(new SQLException("Faiking another failing DataChange throwing a SQLException but which should never be thrown"))
- .when(failingMock2)
- .execute();
- ProjectAnalysisDataChange okMock4 = mock(ProjectAnalysisDataChange.class);
- InOrder inOrder = Mockito.inOrder(okMock1, okMock2, failingMock1, okMock3, failingMock2, okMock4);
- when(projectAnalysisDataChanges.getDataChanges()).thenReturn(ImmutableList.of(
- okMock1, okMock2, failingMock1, okMock3, failingMock2, okMock4));
-
- try {
- underTest.execute(new TestComputationStepContext());
- fail("A IllegalStateException should have been thrown");
- } catch (IllegalStateException e) {
- assertThat(e)
- .hasCause(expected);
- inOrder.verify(okMock1).execute();
- inOrder.verify(okMock2).execute();
- inOrder.verify(failingMock1).execute();
- inOrder.verifyNoMoreInteractions();
- }
- }
-
- @Test
- public void verify_description() {
- assertThat(underTest.getDescription()).isNotEmpty();
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v85;
+
+import java.sql.SQLException;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
+
+public class PopulateFileSourceLineCount extends DataChange {
+ static final int LINE_COUNT_NOT_POPULATED = -1;
+ private static final String NEW_LINE = "\n";
+
+ public PopulateFileSourceLineCount(Database database) {
+ super(database);
+ }
+
+ @Override
+ protected void execute(Context context) throws SQLException {
+ MassUpdate massUpdate = context.prepareMassUpdate();
+ massUpdate.select("select uuid, line_hashes from file_sources where line_count = ?").setInt(1, LINE_COUNT_NOT_POPULATED);
+ massUpdate.update("update file_sources set line_count = ? where uuid = ?");
+ massUpdate.rowPluralName("line counts of file sources");
+ massUpdate.execute(PopulateFileSourceLineCount::handle);
+ }
+
+ private static boolean handle(Select.Row row, SqlStatement update) throws SQLException {
+ String rowUuid = row.getString(1);
+ String rawData = row.getNullableString(2);
+
+ int lineCount = rawData == null ? 0 : (StringUtils.countMatches(rawData, NEW_LINE) + 1);
+ update.setInt(1, lineCount);
+ update.setString(2, rowUuid);
+ return true;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v85;
+
+import java.sql.SQLException;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.core.util.SequenceUuidFactory;
+import org.sonar.core.util.UuidFactory;
+import org.sonar.db.CoreDbTester;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.server.platform.db.migration.version.v85.PopulateFileSourceLineCount.LINE_COUNT_NOT_POPULATED;
+
+public class PopulateFileSourceLineCountTest {
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(PopulateFileSourceLineCountTest.class, "schema.sql");
+
+ private UuidFactory uuidFactory = new SequenceUuidFactory();
+
+ private PopulateFileSourceLineCount underTest = new PopulateFileSourceLineCount(db.database());
+
+ @Test
+ public void execute_has_no_effect_on_empty_table() throws SQLException {
+ underTest.execute();
+ assertThat(db.countRowsOfTable("file_sources")).isZero();
+ }
+
+ @Test
+ public void execute_populates_line_count_of_any_type() throws SQLException {
+ String projectUuid = randomAlphanumeric(4);
+ String fileUuid = randomAlphanumeric(5);
+ int lineCount = 10;
+ insertUnpopulatedFileSource(projectUuid, fileUuid, lineCount);
+ assertThat(getLineCountByFileUuid(fileUuid)).isEqualTo(LINE_COUNT_NOT_POPULATED);
+
+ underTest.execute();
+
+ assertThat(getLineCountByFileUuid(fileUuid)).isEqualTo(lineCount);
+ }
+
+ @Test
+ public void execute_changes_only_file_source_with_LINE_COUNT_NOT_POPULATED_value() throws SQLException {
+ String projectUuid = randomAlphanumeric(4);
+ String fileUuid1 = randomAlphanumeric(5);
+ String fileUuid2 = randomAlphanumeric(6);
+ String fileUuid3 = randomAlphanumeric(7);
+ int lineCountFile1 = 10;
+ int lineCountFile2 = 50;
+ int lineCountFile3 = 150;
+
+ insertPopulatedFileSource(projectUuid, fileUuid1, lineCountFile1);
+ int badLineCountFile2 = insertInconsistentPopulatedFileSource(projectUuid, fileUuid2, lineCountFile2);
+ insertUnpopulatedFileSource(projectUuid, fileUuid3, lineCountFile3);
+ assertThat(getLineCountByFileUuid(fileUuid1)).isEqualTo(lineCountFile1);
+ assertThat(getLineCountByFileUuid(fileUuid2)).isEqualTo(badLineCountFile2);
+ assertThat(getLineCountByFileUuid(fileUuid3)).isEqualTo(LINE_COUNT_NOT_POPULATED);
+
+ underTest.execute();
+
+ assertThat(getLineCountByFileUuid(fileUuid1)).isEqualTo(lineCountFile1);
+ assertThat(getLineCountByFileUuid(fileUuid2)).isEqualTo(badLineCountFile2);
+ assertThat(getLineCountByFileUuid(fileUuid3)).isEqualTo(lineCountFile3);
+ }
+
+ @Test
+ public void execute_set_line_count_to_zero_when_file_source_has_no_line_hashes() throws SQLException {
+ String projectUuid = randomAlphanumeric(4);
+ String fileUuid1 = randomAlphanumeric(5);
+
+ insertFileSource(projectUuid, fileUuid1, null, LINE_COUNT_NOT_POPULATED);
+
+ underTest.execute();
+
+ assertThat(getLineCountByFileUuid(fileUuid1)).isZero();
+ }
+
+ @Test
+ public void execute_set_line_count_to_1_when_file_source_has_empty_line_hashes() throws SQLException {
+ String projectUuid = randomAlphanumeric(4);
+ String fileUuid1 = randomAlphanumeric(5);
+
+ insertFileSource(projectUuid, fileUuid1, "", LINE_COUNT_NOT_POPULATED);
+
+ underTest.execute();
+
+ assertThat(getLineCountByFileUuid(fileUuid1)).isEqualTo(1);
+ }
+
+ private int getLineCountByFileUuid(String fileUuid) {
+ Long res = (Long) db.selectFirst("select line_count as \"LINE_COUNT\" from file_sources where file_uuid = '" + fileUuid + "'")
+ .get("LINE_COUNT");
+ return res.intValue();
+ }
+
+ private void insertUnpopulatedFileSource(String projectUuid, String fileUuid, int numberOfHashes) {
+ String lineHashes = generateLineHashes(numberOfHashes);
+
+ insertFileSource(projectUuid, fileUuid, lineHashes, LINE_COUNT_NOT_POPULATED);
+ }
+
+ private void insertPopulatedFileSource(String projectUuid, String fileUuid, int lineCount) {
+ String lineHashes = generateLineHashes(lineCount);
+
+ insertFileSource(projectUuid, fileUuid, lineHashes, lineCount);
+ }
+
+ private int insertInconsistentPopulatedFileSource(String projectUuid, String fileUuid, int lineCount) {
+ String lineHashes = generateLineHashes(lineCount);
+ int badLineCount = lineCount + 6;
+
+ insertFileSource(projectUuid, fileUuid, lineHashes, badLineCount);
+
+ return badLineCount;
+ }
+
+ private static String generateLineHashes(int numberOfHashes) {
+ return IntStream.range(0, numberOfHashes)
+ .mapToObj(String::valueOf)
+ .collect(Collectors.joining("\n"));
+ }
+
+ private void insertFileSource(String projectUuid, String fileUuid, @Nullable String lineHashes, int lineCount) {
+ db.executeInsert(
+ "FILE_SOURCES",
+ "UUID", uuidFactory.create(),
+ "PROJECT_UUID", projectUuid,
+ "FILE_UUID", fileUuid,
+ "LINE_HASHES", lineHashes,
+ "LINE_COUNT", lineCount,
+ "CREATED_AT", 1_222_333L,
+ "UPDATED_AT", 1_222_333L);
+ }
+}
--- /dev/null
+CREATE TABLE "FILE_SOURCES"(
+ "PROJECT_UUID" VARCHAR(50) NOT NULL,
+ "FILE_UUID" VARCHAR(50) NOT NULL,
+ "LINE_HASHES" CLOB(2147483647),
+ "LINE_HASHES_VERSION" INTEGER,
+ "DATA_HASH" VARCHAR(50),
+ "SRC_HASH" VARCHAR(50),
+ "REVISION" VARCHAR(100),
+ "LINE_COUNT" INTEGER NOT NULL,
+ "BINARY_DATA" BLOB,
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL,
+ "UUID" VARCHAR(40) NOT NULL
+);
+ALTER TABLE "FILE_SOURCES" ADD CONSTRAINT "PK_FILE_SOURCES" PRIMARY KEY("UUID");
+CREATE UNIQUE INDEX "FILE_SOURCES_FILE_UUID" ON "FILE_SOURCES"("FILE_UUID");
+CREATE INDEX "FILE_SOURCES_PROJECT_UUID" ON "FILE_SOURCES"("PROJECT_UUID");
+CREATE INDEX "FILE_SOURCES_UPDATED_AT" ON "FILE_SOURCES"("UPDATED_AT");