From: Julien Lancelot Date: Tue, 19 May 2015 12:02:45 +0000 (+0200) Subject: SONAR-6259 Persist components in db X-Git-Tag: 5.2-RC1~1872 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=a27d5efd0aa3ce834ee20bccd5044c3c36a3467a;p=sonarqube.git SONAR-6259 Persist components in db --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/db/ComponentDao.java b/server/sonar-server/src/main/java/org/sonar/server/component/db/ComponentDao.java index ef9e4482f71..95b22226bcd 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/db/ComponentDao.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/db/ComponentDao.java @@ -136,6 +136,10 @@ public class ComponentDao implements DaoComponent { }); } + public List selectComponentsFromProjectUuid(DbSession session, String projectKey) { + return mapper(session).selectComponentsFromProjectUuid(projectKey); + } + public List selectByKeys(DbSession session, Collection keys) { return mapper(session).selectByKeys(keys); } @@ -153,24 +157,6 @@ public class ComponentDao implements DaoComponent { return mapper(session).selectByKey(key); } - public void insert(DbSession session, ComponentDto item) { - mapper(session).insert(item); - } - - public void insert(DbSession session, Collection items) { - for (ComponentDto item : items) { - insert(session, item); - } - } - - public void insert(DbSession session, ComponentDto item, ComponentDto... others) { - insert(session, Lists.asList(item, others)); - } - - public List selectProjectUuids(DbSession session) { - return mapper(session).selectProjectUuids(); - } - public List selectAllViewsAndSubViews(DbSession session) { return mapper(session).selectUuidsForQualifiers(Qualifiers.VIEW, Qualifiers.SUBVIEW); } @@ -221,6 +207,24 @@ public class ComponentDao implements DaoComponent { parameters.put("qualifier", Qualifiers.PROJECT); } + public void insert(DbSession session, ComponentDto item) { + mapper(session).insert(item); + } + + public void insert(DbSession session, Collection items) { + for (ComponentDto item : items) { + insert(session, item); + } + } + + public void insert(DbSession session, ComponentDto item, ComponentDto... others) { + insert(session, Lists.asList(item, others)); + } + + public void update(DbSession session, ComponentDto item) { + mapper(session).update(item); + } + private ComponentMapper mapper(DbSession session) { return session.getMapper(ComponentMapper.class); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java new file mode 100644 index 00000000000..e3852bc302b --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java @@ -0,0 +1,55 @@ +/* + * 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.component; + +public class Component { + + private Long id; + private String uuid; + private String key; + + public Long getId() { + return id; + } + + public Component setId(Long id) { + this.id = id; + return this; + } + + public String getKey() { + return key; + } + + public Component setKey(String key) { + this.key = key; + return this; + } + + public String getUuid() { + return uuid; + } + + public Component setUuid(String uuid) { + this.uuid = uuid; + return this; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComponentsCache.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComponentsCache.java new file mode 100644 index 00000000000..5865f0e034f --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComponentsCache.java @@ -0,0 +1,44 @@ +/* + * 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.batch.protocol.output.BatchReportReader; +import org.sonar.server.computation.component.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * To be finished + */ +public class ComponentsCache { + + private final Map componentsByRef; + + public ComponentsCache(final BatchReportReader reader) { + this.componentsByRef = new HashMap<>(); + } + + public Component getComponent(int componentRef) { + // TODO should we return null or fail on unknown component ? + return null; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedComponentsCacheStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedComponentsCacheStep.java new file mode 100644 index 00000000000..2ca84a4cb2c --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/FeedComponentsCacheStep.java @@ -0,0 +1,107 @@ +/* + * 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 com.google.common.collect.Maps; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.utils.internal.Uuids; +import org.sonar.batch.protocol.Constants; +import org.sonar.batch.protocol.output.BatchReport; +import org.sonar.batch.protocol.output.BatchReportReader; +import org.sonar.core.component.ComponentDto; +import org.sonar.core.component.ComponentKeys; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.util.NonNullInputFunction; +import org.sonar.server.computation.ComputationContext; +import org.sonar.server.computation.component.Component; +import org.sonar.server.db.DbClient; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * To be finished + */ +public class FeedComponentsCacheStep implements ComputationStep { + + private final DbClient dbClient; + + public FeedComponentsCacheStep(DbClient dbClient) { + this.dbClient = dbClient; + } + + @Override + public String[] supportedProjectQualifiers() { + return new String[] {Qualifiers.PROJECT}; + } + + @Override + public void execute(ComputationContext context) { + DbSession session = dbClient.openSession(false); + try { + List components = dbClient.componentDao().selectComponentsFromProjectUuid(session, context.getProject().uuid()); + Map componentDtosByKey = componentDtosByKey(components); + Map componentsByRef = new HashMap<>(); + int rootComponentRef = context.getReportMetadata().getRootComponentRef(); + recursivelyProcessComponent(context, rootComponentRef, context.getReportReader().readComponent(rootComponentRef), componentDtosByKey, componentsByRef); + } finally { + session.close(); + } + } + + private void recursivelyProcessComponent(ComputationContext context, int componentRef, BatchReport.Component nearestModule, + Map componentDtosByKey, Map componentsByRef) { + BatchReportReader reportReader = context.getReportReader(); + BatchReport.Component reportComponent = reportReader.readComponent(componentRef); + String componentKey = ComponentKeys.createKey(nearestModule.getKey(), reportComponent.getPath(), context.getReportMetadata().getBranch()); + + Component component = new Component().setKey(componentKey); + ComponentDto componentDto = componentDtosByKey.get(componentKey); + if (componentDto == null) { + component.setUuid(Uuids.create()); + } else { + component.setId(component.getId()); + component.setKey(componentKey); + } + + for (Integer childRef : reportComponent.getChildRefList()) { + // If current component is not a module or a project, we need to keep the parent reference to the nearest module + BatchReport.Component nextNearestModule = !reportComponent.getType().equals(Constants.ComponentType.PROJECT) && !reportComponent.getType().equals(Constants.ComponentType.MODULE) ? + nearestModule : reportComponent; + recursivelyProcessComponent(context, childRef, nextNearestModule, componentDtosByKey, componentsByRef); + } + } + + private Map componentDtosByKey(List components){ + return Maps.uniqueIndex(components, new NonNullInputFunction() { + @Override + public String doApply(ComponentDto input) { + return input.key(); + } + }); + } + + @Override + public String getDescription() { + return "Feed components cache"; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistComponentsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistComponentsStep.java new file mode 100644 index 00000000000..2fbcf62f2c8 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistComponentsStep.java @@ -0,0 +1,241 @@ +/* + * 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 com.google.common.collect.Maps; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang.ObjectUtils; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.resources.Qualifiers; +import org.sonar.api.resources.Scopes; +import org.sonar.api.utils.internal.Uuids; +import org.sonar.batch.protocol.Constants; +import org.sonar.batch.protocol.output.BatchReport; +import org.sonar.batch.protocol.output.BatchReportReader; +import org.sonar.core.component.ComponentDto; +import org.sonar.core.component.ComponentKeys; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.util.NonNullInputFunction; +import org.sonar.server.computation.ComputationContext; +import org.sonar.server.db.DbClient; + +import javax.annotation.Nullable; + +import java.util.List; +import java.util.Map; + +public class PersistComponentsStep implements ComputationStep { + + private final DbClient dbClient; + + public PersistComponentsStep(DbClient dbClient) { + this.dbClient = dbClient; + } + + @Override + public String[] supportedProjectQualifiers() { + return new String[] {Qualifiers.PROJECT}; + } + + @Override + public void execute(ComputationContext context) { + DbSession session = dbClient.openSession(false); + try { + List components = dbClient.componentDao().selectComponentsFromProjectUuid(session, context.getProject().uuid()); + Map componentDtosByKey = componentDtosByKey(components); + int rootComponentRef = context.getReportMetadata().getRootComponentRef(); + ComponentContext componentContext = new ComponentContext(context, session, componentDtosByKey); + recursivelyProcessComponent(componentContext, rootComponentRef, null); + session.commit(); + } finally { + session.close(); + } + } + + private void recursivelyProcessComponent(ComponentContext componentContext, int componentRef, @Nullable ComponentDto moduleParent) { + BatchReportReader reportReader = componentContext.context.getReportReader(); + BatchReport.Component reportComponent = reportReader.readComponent(componentRef); + ComponentDto componentDto = processComponent(componentContext, reportComponent, moduleParent); + + for (Integer childRef : reportComponent.getChildRefList()) { + // If current component is not a module or a project, we need to keep the parent reference to the nearest module + ComponentDto nextModuleParent = !reportComponent.getType().equals(Constants.ComponentType.PROJECT) && !reportComponent.getType().equals(Constants.ComponentType.MODULE) ? + moduleParent : componentDto; + recursivelyProcessComponent(componentContext, childRef, nextModuleParent); + } + } + + private ComponentDto processComponent(ComponentContext componentContext, BatchReport.Component reportComponent, @Nullable ComponentDto moduleParent) { + String path = reportComponent.hasPath() ? reportComponent.getPath() : null; + String branch = componentContext.context.getReportMetadata().hasBranch() ? componentContext.context.getReportMetadata().getBranch() : null; + String componentKey = reportComponent.hasKey() || moduleParent == null ? + ComponentKeys.createKey(reportComponent.getKey(), branch) : + ComponentKeys.createEffectiveKey(moduleParent.getKey(), path); + ComponentDto existingComponent = componentContext.componentDtosByKey.get(componentKey); + if (existingComponent == null) { + ComponentDto component = createComponent(reportComponent, componentKey, Uuids.create(), moduleParent); + dbClient.componentDao().insert(componentContext.dbSession, component); + return component; + } else { + ComponentDto component = createComponent(reportComponent, componentKey, existingComponent.uuid(), moduleParent); + if (updateComponent(existingComponent, component)) { + dbClient.componentDao().update(componentContext.dbSession, existingComponent); + } + return existingComponent; + } + } + + private ComponentDto createComponent(BatchReport.Component reportComponent, String componentKey, String uuid, @Nullable ComponentDto parentModule) { + ComponentDto component = new ComponentDto(); + component.setUuid(uuid); + component.setKey(componentKey); + component.setDeprecatedKey(componentKey); + component.setEnabled(true); + component.setScope(getScope(reportComponent)); + component.setQualifier(getQualifier(reportComponent)); + component.setName(getFileName(reportComponent)); + + if (isProjectOrModule(reportComponent)) { + component.setLongName(component.name()); + if (reportComponent.hasDescription()) { + component.setDescription(reportComponent.getDescription()); + } + } else { + component.setLongName(reportComponent.getPath()); + if (reportComponent.hasPath()) { + component.setPath(reportComponent.getPath()); + } + if (reportComponent.hasLanguage()) { + component.setLanguage(reportComponent.getLanguage()); + } + } + if (parentModule != null) { + component.setParentProjectId(parentModule.getId()); + component.setProjectUuid(parentModule.projectUuid()); + component.setModuleUuid(parentModule.uuid()); + component.setModuleUuidPath(reportComponent.getType().equals(Constants.ComponentType.MODULE) ? + parentModule.moduleUuidPath() + component.uuid() + ComponentDto.MODULE_UUID_PATH_SEP : + parentModule.moduleUuidPath()); + } else { + component.setProjectUuid(uuid); + component.setModuleUuidPath(ComponentDto.MODULE_UUID_PATH_SEP + component.uuid() + ComponentDto.MODULE_UUID_PATH_SEP); + } + return component; + } + + private boolean updateComponent(ComponentDto existingComponent, ComponentDto newComponent) { + boolean isUpdated = false; + if (Scopes.PROJECT.equals(existingComponent.scope())) { + if (!newComponent.name().equals(existingComponent.name())) { + existingComponent.setName(newComponent.name()); + isUpdated = true; + } + if (!StringUtils.equals(existingComponent.description(), newComponent.description())) { + existingComponent.setDescription(newComponent.description()); + isUpdated = true; + } + } + + if (!StringUtils.equals(existingComponent.moduleUuid(), newComponent.moduleUuid())) { + existingComponent.setModuleUuid(newComponent.moduleUuid()); + isUpdated = true; + } + if (!existingComponent.moduleUuidPath().equals(newComponent.moduleUuidPath())) { + existingComponent.setModuleUuidPath(newComponent.moduleUuidPath()); + isUpdated = true; + } + if (!ObjectUtils.equals(existingComponent.parentProjectId(), newComponent.parentProjectId())) { + existingComponent.setParentProjectId(newComponent.parentProjectId()); + isUpdated = true; + } + + return isUpdated; + } + + private static boolean isProjectOrModule(BatchReport.Component reportComponent) { + return reportComponent.getType().equals(Constants.ComponentType.PROJECT) || reportComponent.getType().equals(Constants.ComponentType.MODULE); + } + + private static String getScope(BatchReport.Component reportComponent) { + switch (reportComponent.getType()) { + case PROJECT: + return Scopes.PROJECT; + case MODULE: + return Scopes.PROJECT; + case DIRECTORY: + return Scopes.DIRECTORY; + case FILE: + return Scopes.FILE; + } + throw new IllegalArgumentException(String.format("Unknown type '%s'", reportComponent.getType())); + } + + private static String getQualifier(BatchReport.Component reportComponent) { + switch (reportComponent.getType()) { + case PROJECT: + return Qualifiers.PROJECT; + case MODULE: + return Qualifiers.MODULE; + case DIRECTORY: + return Qualifiers.DIRECTORY; + case FILE: + return !reportComponent.getIsTest() ? Qualifiers.FILE : Qualifiers.UNIT_TEST_FILE; + } + throw new IllegalArgumentException(String.format("Unknown type '%s'", reportComponent.getType())); + } + + private static String getFileName(BatchReport.Component reportComponent) { + String path = reportComponent.getPath(); + if (reportComponent.getType() == Constants.ComponentType.PROJECT || reportComponent.getType() == Constants.ComponentType.MODULE) { + return reportComponent.getName(); + } else if (reportComponent.getType().equals(Constants.ComponentType.DIRECTORY)) { + return path; + } else { + return FilenameUtils.getName(path); + } + } + + private Map componentDtosByKey(List components) { + return Maps.uniqueIndex(components, new NonNullInputFunction() { + @Override + public String doApply(ComponentDto input) { + return input.key(); + } + }); + } + + private static class ComponentContext { + private final ComputationContext context; + private final Map componentDtosByKey; + private final DbSession dbSession; + + public ComponentContext(ComputationContext context, DbSession dbSession, Map componentDtosByKey) { + this.componentDtosByKey = componentDtosByKey; + this.context = context; + this.dbSession = dbSession; + } + } + + @Override + public String getDescription() { + return "Feed components cache"; + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java index aa55b64387f..62d3b58548e 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java @@ -173,6 +173,7 @@ public class ComponentDaoTest { assertThat(result.path()).isNull(); assertThat(result.name()).isEqualTo("Struts"); assertThat(result.longName()).isEqualTo("Apache Struts"); + assertThat(result.description()).isEqualTo("the description"); assertThat(result.qualifier()).isEqualTo("TRK"); assertThat(result.scope()).isEqualTo("PRJ"); assertThat(result.language()).isNull(); @@ -452,6 +453,66 @@ public class ComponentDaoTest { assertThat(sut.selectEnabledFilesFromProject(session, "unknown")).isEmpty(); } + @Test + public void select_components_from_project() { + db.prepareDbUnit(getClass(), "multi-modules.xml"); + + List components = sut.selectComponentsFromProjectUuid(session, "ABCD"); + assertThat(components).hasSize(5); + + assertThat(sut.selectComponentsFromProjectUuid(session, "UNKNOWN")).isEmpty(); + } + + @Test + public void select_views_and_sub_views() { + db.prepareDbUnit(getClass(), "shared_views.xml"); + + assertThat(sut.selectAllViewsAndSubViews(session)).extracting("uuid").containsOnly("ABCD", "EFGH", "FGHI", "IJKL"); + assertThat(sut.selectAllViewsAndSubViews(session)).extracting("projectUuid").containsOnly("ABCD", "EFGH", "IJKL"); + } + + @Test + public void select_projects_from_view() { + db.prepareDbUnit(getClass(), "shared_views.xml"); + + assertThat(sut.selectProjectsFromView(session, "ABCD", "ABCD")).containsOnly("JKLM"); + assertThat(sut.selectProjectsFromView(session, "EFGH", "EFGH")).containsOnly("KLMN", "JKLM"); + assertThat(sut.selectProjectsFromView(session, "FGHI", "EFGH")).containsOnly("JKLM"); + assertThat(sut.selectProjectsFromView(session, "IJKL", "IJKL")).isEmpty(); + assertThat(sut.selectProjectsFromView(session, "Unknown", "Unknown")).isEmpty(); + } + + @Test + public void select_provisioned_projects() { + db.prepareDbUnit(getClass(), "select_provisioned_projects.xml"); + + List result = sut.selectProvisionedProjects(session, new SearchOptions(), null); + ComponentDto project = result.get(0); + + assertThat(result).hasSize(1); + assertThat(project.getKey()).isEqualTo("org.provisioned.project"); + } + + @Test + public void count_provisioned_projects() { + db.prepareDbUnit(getClass(), "select_provisioned_projects.xml"); + + int numberOfProjects = sut.countProvisionedProjects(session, null); + + assertThat(numberOfProjects).isEqualTo(1); + } + + @Test + public void select_ghost_projects() throws Exception { + db.prepareDbUnit(getClass(), "select_ghost_projects.xml"); + + List result = sut.selectGhostProjects(session, null, new SearchOptions()); + + assertThat(result).hasSize(1); + assertThat(result.get(0).key()).isEqualTo("org.ghost.project"); + assertThat(sut.countGhostProjects(session, null)).isEqualTo(1); + } + @Test public void insert() { db.prepareDbUnit(getClass(), "empty.xml"); @@ -469,6 +530,7 @@ public class ComponentDaoTest { .setQualifier("FIL") .setScope("FIL") .setLanguage("java") + .setDescription("description") .setPath("src/org/struts/RequestContext.java") .setParentProjectId(3L) .setCopyResourceId(5L) @@ -513,59 +575,31 @@ public class ComponentDaoTest { } @Test - public void find_project_uuids() { - db.prepareDbUnit(getClass(), "find_project_uuids.xml"); - - assertThat(sut.selectProjectUuids(session)).containsExactly("ABCD"); - } - - @Test - public void select_views_and_sub_views() { - db.prepareDbUnit(getClass(), "shared_views.xml"); - - assertThat(sut.selectAllViewsAndSubViews(session)).extracting("uuid").containsOnly("ABCD", "EFGH", "FGHI", "IJKL"); - assertThat(sut.selectAllViewsAndSubViews(session)).extracting("projectUuid").containsOnly("ABCD", "EFGH", "IJKL"); - } - - @Test - public void select_projects_from_view() { - db.prepareDbUnit(getClass(), "shared_views.xml"); - - assertThat(sut.selectProjectsFromView(session, "ABCD", "ABCD")).containsOnly("JKLM"); - assertThat(sut.selectProjectsFromView(session, "EFGH", "EFGH")).containsOnly("KLMN", "JKLM"); - assertThat(sut.selectProjectsFromView(session, "FGHI", "EFGH")).containsOnly("JKLM"); - assertThat(sut.selectProjectsFromView(session, "IJKL", "IJKL")).isEmpty(); - assertThat(sut.selectProjectsFromView(session, "Unknown", "Unknown")).isEmpty(); - } - - @Test - public void select_provisioned_projects() { - db.prepareDbUnit(getClass(), "select_provisioned_projects.xml"); - - List result = sut.selectProvisionedProjects(session, new SearchOptions(), null); - ComponentDto project = result.get(0); - - assertThat(result).hasSize(1); - assertThat(project.getKey()).isEqualTo("org.provisioned.project"); - } - - @Test - public void count_provisioned_projects() { - db.prepareDbUnit(getClass(), "select_provisioned_projects.xml"); + public void update() { + db.prepareDbUnit(getClass(), "update.xml"); - int numberOfProjects = sut.countProvisionedProjects(session, null); - - assertThat(numberOfProjects).isEqualTo(1); - } - - @Test - public void select_ghost_projects() throws Exception { - db.prepareDbUnit(getClass(), "select_ghost_projects.xml"); + ComponentDto componentDto = new ComponentDto() + .setUuid("GHIJ") + .setProjectUuid("DCBA") + .setModuleUuid("HGFE") + .setModuleUuidPath(".DCBA.HGFE.") + .setKey("org.struts:struts-core:src/org/struts/RequestContext2.java") + .setDeprecatedKey("org.struts:struts-core:src/org/struts/RequestContext2.java") + .setName("RequestContext2.java") + .setLongName("org.struts.RequestContext2") + .setQualifier("LIF") + .setScope("LIF") + .setLanguage("java2") + .setDescription("description2") + .setPath("src/org/struts/RequestContext2.java") + .setParentProjectId(4L) + .setCopyResourceId(6L) + .setEnabled(false) + .setAuthorizationUpdatedAt(12345678910L); - List result = sut.selectGhostProjects(session, null, new SearchOptions()); + sut.update(session, componentDto); + session.commit(); - assertThat(result).hasSize(1); - assertThat(result.get(0).key()).isEqualTo("org.ghost.project"); - assertThat(sut.countGhostProjects(session, null)).isEqualTo(1); + db.assertDbUnit(getClass(), "update-result.xml", "projects"); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistComponentsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistComponentsStepTest.java new file mode 100644 index 00000000000..33a3240115f --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistComponentsStepTest.java @@ -0,0 +1,631 @@ +/* + * 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.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; +import org.sonar.batch.protocol.Constants; +import org.sonar.batch.protocol.output.BatchReport; +import org.sonar.batch.protocol.output.BatchReportReader; +import org.sonar.batch.protocol.output.BatchReportWriter; +import org.sonar.core.component.ComponentDto; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.persistence.DbTester; +import org.sonar.server.component.ComponentTesting; +import org.sonar.server.component.db.ComponentDao; +import org.sonar.server.computation.ComputationContext; +import org.sonar.server.db.DbClient; +import org.sonar.test.DbTests; + +import java.io.File; + +import static org.assertj.core.api.Assertions.assertThat; + +@Category(DbTests.class) +public class PersistComponentsStepTest extends BaseStepTest { + + @ClassRule + public static DbTester dbTester = new DbTester(); + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + File reportDir; + + DbSession session; + + DbClient dbClient; + + PersistComponentsStep sut; + + @Before + public void setup() throws Exception { + dbTester.truncateTables(); + session = dbTester.myBatis().openSession(false); + dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao()); + + reportDir = temp.newFolder(); + + sut = new PersistComponentsStep(dbClient); + } + + @Override + protected ComputationStep step() { + return sut; + } + + @After + public void tearDown() { + session.close(); + } + + @Test + public void persist_components() throws Exception { + File reportDir = temp.newFolder(); + BatchReportWriter writer = new BatchReportWriter(reportDir); + writer.writeMetadata(BatchReport.Metadata.newBuilder() + .setRootComponentRef(1) + .build()); + + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(1) + .setType(Constants.ComponentType.PROJECT) + .setKey("PROJECT_KEY") + .setName("Project") + .setDescription("Project description") + .addChildRef(2) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(2) + .setType(Constants.ComponentType.MODULE) + .setKey("MODULE_KEY") + .setName("Module") + .setDescription("Module description") + .addChildRef(3) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(3) + .setType(Constants.ComponentType.DIRECTORY) + .setPath("src/main/java/dir") + .addChildRef(4) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(4) + .setType(Constants.ComponentType.FILE) + .setPath("src/main/java/dir/Foo.java") + .setLanguage("java") + .build()); + + sut.execute(new ComputationContext(new BatchReportReader(reportDir), ComponentTesting.newProjectDto())); + + assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); + + ComponentDto project = dbClient.componentDao().selectNullableByKey(session, "PROJECT_KEY"); + assertThat(project).isNotNull(); + assertThat(project.name()).isEqualTo("Project"); + assertThat(project.description()).isEqualTo("Project description"); + assertThat(project.uuid()).isNotNull(); + assertThat(project.moduleUuid()).isNull(); + assertThat(project.moduleUuidPath()).isEqualTo("." + project.uuid() + "."); + assertThat(project.projectUuid()).isEqualTo(project.uuid()); + assertThat(project.qualifier()).isEqualTo("TRK"); + assertThat(project.scope()).isEqualTo("PRJ"); + assertThat(project.parentProjectId()).isNull(); + + ComponentDto module = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY"); + assertThat(module).isNotNull(); + assertThat(module.name()).isEqualTo("Module"); + assertThat(module.description()).isEqualTo("Module description"); + assertThat(module.uuid()).isNotNull(); + assertThat(module.moduleUuid()).isEqualTo(project.uuid()); + assertThat(module.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + module.uuid() + "."); + assertThat(module.projectUuid()).isEqualTo(project.uuid()); + assertThat(module.qualifier()).isEqualTo("BRC"); + assertThat(module.scope()).isEqualTo("PRJ"); + assertThat(module.parentProjectId()).isEqualTo(project.getId()); + + ComponentDto directory = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir"); + assertThat(directory).isNotNull(); + assertThat(directory.name()).isEqualTo("src/main/java/dir"); + assertThat(directory.path()).isEqualTo("src/main/java/dir"); + assertThat(directory.uuid()).isNotNull(); + assertThat(directory.moduleUuid()).isEqualTo(module.uuid()); + assertThat(directory.moduleUuidPath()).isEqualTo(module.moduleUuidPath()); + assertThat(directory.projectUuid()).isEqualTo(project.uuid()); + assertThat(directory.qualifier()).isEqualTo("DIR"); + assertThat(directory.scope()).isEqualTo("DIR"); + assertThat(directory.parentProjectId()).isEqualTo(module.getId()); + + ComponentDto file = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir/Foo.java"); + assertThat(file).isNotNull(); + assertThat(file.name()).isEqualTo("Foo.java"); + assertThat(file.path()).isEqualTo("src/main/java/dir/Foo.java"); + assertThat(file.language()).isEqualTo("java"); + assertThat(file.uuid()).isNotNull(); + assertThat(file.moduleUuid()).isEqualTo(module.uuid()); + assertThat(file.moduleUuidPath()).isEqualTo(module.moduleUuidPath()); + assertThat(file.projectUuid()).isEqualTo(project.uuid()); + assertThat(file.qualifier()).isEqualTo("FIL"); + assertThat(file.scope()).isEqualTo("FIL"); + assertThat(file.parentProjectId()).isEqualTo(module.getId()); + } + + @Test + public void persist_file_directly_attached_on_root_directory() throws Exception { + File reportDir = temp.newFolder(); + BatchReportWriter writer = new BatchReportWriter(reportDir); + writer.writeMetadata(BatchReport.Metadata.newBuilder() + .setRootComponentRef(1) + .build()); + + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(1) + .setType(Constants.ComponentType.PROJECT) + .setKey("PROJECT_KEY") + .setName("Project") + .addChildRef(2) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(2) + .setType(Constants.ComponentType.DIRECTORY) + .setPath("/") + .addChildRef(3) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(3) + .setType(Constants.ComponentType.FILE) + .setPath("pom.xml") + .build()); + + sut.execute(new ComputationContext(new BatchReportReader(reportDir), ComponentTesting.newProjectDto())); + + ComponentDto directory = dbClient.componentDao().selectNullableByKey(session, "PROJECT_KEY:/"); + assertThat(directory).isNotNull(); + assertThat(directory.name()).isEqualTo("/"); + assertThat(directory.path()).isEqualTo("/"); + + ComponentDto file = dbClient.componentDao().selectNullableByKey(session, "PROJECT_KEY:pom.xml"); + assertThat(file).isNotNull(); + assertThat(file.name()).isEqualTo("pom.xml"); + assertThat(file.path()).isEqualTo("pom.xml"); + } + + @Test + public void persist_unit_test() throws Exception { + File reportDir = temp.newFolder(); + BatchReportWriter writer = new BatchReportWriter(reportDir); + writer.writeMetadata(BatchReport.Metadata.newBuilder() + .setRootComponentRef(1) + .build()); + + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(1) + .setType(Constants.ComponentType.PROJECT) + .setKey("PROJECT_KEY") + .setName("Project") + .addChildRef(2) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(2) + .setType(Constants.ComponentType.DIRECTORY) + .setPath("src/test/java/dir") + .addChildRef(3) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(3) + .setType(Constants.ComponentType.FILE) + .setPath("src/test/java/dir/FooTest.java") + .setIsTest(true) + .build()); + + sut.execute(new ComputationContext(new BatchReportReader(reportDir), ComponentTesting.newProjectDto())); + + ComponentDto file = dbClient.componentDao().selectNullableByKey(session, "PROJECT_KEY:src/test/java/dir/FooTest.java"); + assertThat(file).isNotNull(); + assertThat(file.name()).isEqualTo("FooTest.java"); + assertThat(file.path()).isEqualTo("src/test/java/dir/FooTest.java"); + assertThat(file.qualifier()).isEqualTo("UTS"); + assertThat(file.scope()).isEqualTo("FIL"); + } + + @Test + public void use_latest_module_for_files_key() throws Exception { + File reportDir = temp.newFolder(); + BatchReportWriter writer = new BatchReportWriter(reportDir); + writer.writeMetadata(BatchReport.Metadata.newBuilder() + .setRootComponentRef(1) + .build()); + + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(1) + .setType(Constants.ComponentType.PROJECT) + .setKey("PROJECT_KEY") + .setName("Project") + .addChildRef(2) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(2) + .setType(Constants.ComponentType.MODULE) + .setKey("MODULE_KEY") + .setName("Module") + .addChildRef(3) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(3) + .setType(Constants.ComponentType.MODULE) + .setKey("SUB_MODULE_KEY") + .setName("Sub Module") + .addChildRef(4) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(4) + .setType(Constants.ComponentType.DIRECTORY) + .setPath("src/main/java/dir") + .addChildRef(5) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(5) + .setType(Constants.ComponentType.FILE) + .setPath("src/main/java/dir/Foo.java") + .build()); + + sut.execute(new ComputationContext(new BatchReportReader(reportDir), ComponentTesting.newProjectDto())); + + assertThat(dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY")).isNotNull(); + assertThat(dbClient.componentDao().selectNullableByKey(session, "SUB_MODULE_KEY")).isNotNull(); + assertThat(dbClient.componentDao().selectNullableByKey(session, "SUB_MODULE_KEY:src/main/java/dir")).isNotNull(); + assertThat(dbClient.componentDao().selectNullableByKey(session, "SUB_MODULE_KEY:src/main/java/dir/Foo.java")).isNotNull(); + } + + @Test + public void persist_with_branch() throws Exception { + File reportDir = temp.newFolder(); + BatchReportWriter writer = new BatchReportWriter(reportDir); + writer.writeMetadata(BatchReport.Metadata.newBuilder() + .setRootComponentRef(1) + .setBranch("origin/master") + .build()); + + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(1) + .setType(Constants.ComponentType.PROJECT) + .setKey("PROJECT_KEY") + .setName("Project") + .addChildRef(2) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(2) + .setType(Constants.ComponentType.MODULE) + .setKey("MODULE_KEY") + .setName("Module") + .addChildRef(3) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(3) + .setType(Constants.ComponentType.DIRECTORY) + .setPath("src/main/java/dir") + .addChildRef(4) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(4) + .setType(Constants.ComponentType.FILE) + .setPath("src/main/java/dir/Foo.java") + .build()); + + sut.execute(new ComputationContext(new BatchReportReader(reportDir), ComponentTesting.newProjectDto())); + + assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); + assertThat(dbClient.componentDao().selectNullableByKey(session, "PROJECT_KEY:origin/master")).isNotNull(); + assertThat(dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:origin/master")).isNotNull(); + assertThat(dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:origin/master:src/main/java/dir")).isNotNull(); + assertThat(dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:origin/master:src/main/java/dir/Foo.java")).isNotNull(); + } + + @Test + public void persist_only_new_components() throws Exception { + // Project amd module already exists + ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey("PROJECT_KEY").setName("Project"); + dbClient.componentDao().insert(session, project); + ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module"); + dbClient.componentDao().insert(session, module); + session.commit(); + + File reportDir = temp.newFolder(); + BatchReportWriter writer = new BatchReportWriter(reportDir); + writer.writeMetadata(BatchReport.Metadata.newBuilder() + .setRootComponentRef(1) + .build()); + + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(1) + .setType(Constants.ComponentType.PROJECT) + .setKey("PROJECT_KEY") + .setName("Project") + .addChildRef(2) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(2) + .setType(Constants.ComponentType.MODULE) + .setKey("MODULE_KEY") + .setName("Module") + .addChildRef(3) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(3) + .setType(Constants.ComponentType.DIRECTORY) + .setPath("src/main/java/dir") + .addChildRef(4) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(4) + .setType(Constants.ComponentType.FILE) + .setPath("src/main/java/dir/Foo.java") + .build()); + + sut.execute(new ComputationContext(new BatchReportReader(reportDir), project)); + + assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); + + ComponentDto projectReloaded = dbClient.componentDao().selectNullableByKey(session, "PROJECT_KEY"); + assertThat(projectReloaded.getId()).isEqualTo(project.getId()); + assertThat(projectReloaded.uuid()).isEqualTo(project.uuid()); + + ComponentDto moduleReloaded = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY"); + assertThat(moduleReloaded.getId()).isEqualTo(module.getId()); + assertThat(moduleReloaded.uuid()).isEqualTo(module.uuid()); + assertThat(moduleReloaded.moduleUuid()).isEqualTo(module.moduleUuid()); + assertThat(moduleReloaded.moduleUuidPath()).isEqualTo(module.moduleUuidPath()); + assertThat(moduleReloaded.projectUuid()).isEqualTo(module.projectUuid()); + assertThat(moduleReloaded.parentProjectId()).isEqualTo(module.parentProjectId()); + + ComponentDto directory = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir"); + assertThat(directory).isNotNull(); + assertThat(directory.moduleUuid()).isEqualTo(module.uuid()); + assertThat(directory.moduleUuidPath()).isEqualTo(module.moduleUuidPath()); + assertThat(directory.projectUuid()).isEqualTo(project.uuid()); + assertThat(directory.parentProjectId()).isEqualTo(module.getId()); + + ComponentDto file = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir/Foo.java"); + assertThat(file).isNotNull(); + assertThat(file.moduleUuid()).isEqualTo(module.uuid()); + assertThat(file.moduleUuidPath()).isEqualTo(module.moduleUuidPath()); + assertThat(file.projectUuid()).isEqualTo(project.uuid()); + assertThat(file.parentProjectId()).isEqualTo(module.getId()); + } + + @Test + public void nothing_to_persist() throws Exception { + ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey("PROJECT_KEY").setName("Project"); + dbClient.componentDao().insert(session, project); + ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module"); + dbClient.componentDao().insert(session, module); + ComponentDto directory = ComponentTesting.newDirectory(module, "src/main/java/dir").setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir"); + ComponentDto file = ComponentTesting.newFileDto(module, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java").setKey("MODULE_KEY:src/main/java/dir/Foo.java"); + dbClient.componentDao().insert(session, directory, file); + session.commit(); + + File reportDir = temp.newFolder(); + BatchReportWriter writer = new BatchReportWriter(reportDir); + writer.writeMetadata(BatchReport.Metadata.newBuilder() + .setRootComponentRef(1) + .build()); + + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(1) + .setType(Constants.ComponentType.PROJECT) + .setKey("PROJECT_KEY") + .setName("Project") + .addChildRef(2) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(2) + .setType(Constants.ComponentType.MODULE) + .setKey("MODULE_KEY") + .setName("Module") + .addChildRef(3) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(3) + .setType(Constants.ComponentType.DIRECTORY) + .setPath("src/main/java/dir") + .addChildRef(4) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(4) + .setType(Constants.ComponentType.FILE) + .setPath("src/main/java/dir/Foo.java") + .build()); + + sut.execute(new ComputationContext(new BatchReportReader(reportDir), project)); + + assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4); + assertThat(dbClient.componentDao().selectNullableByKey(session, "PROJECT_KEY").getId()).isEqualTo(project.getId()); + assertThat(dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY").getId()).isEqualTo(module.getId()); + assertThat(dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir").getId()).isEqualTo(directory.getId()); + assertThat(dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir/Foo.java").getId()).isEqualTo(file.getId()); + + ComponentDto projectReloaded = dbClient.componentDao().selectNullableByKey(session, "PROJECT_KEY"); + assertThat(projectReloaded.getId()).isEqualTo(project.getId()); + assertThat(projectReloaded.uuid()).isEqualTo(project.uuid()); + assertThat(projectReloaded.moduleUuid()).isEqualTo(project.moduleUuid()); + assertThat(projectReloaded.moduleUuidPath()).isEqualTo(project.moduleUuidPath()); + assertThat(projectReloaded.projectUuid()).isEqualTo(project.projectUuid()); + assertThat(projectReloaded.parentProjectId()).isEqualTo(project.parentProjectId()); + + ComponentDto moduleReloaded = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY"); + assertThat(moduleReloaded.getId()).isEqualTo(module.getId()); + assertThat(moduleReloaded.uuid()).isEqualTo(module.uuid()); + assertThat(moduleReloaded.moduleUuid()).isEqualTo(module.moduleUuid()); + assertThat(moduleReloaded.moduleUuidPath()).isEqualTo(module.moduleUuidPath()); + assertThat(moduleReloaded.projectUuid()).isEqualTo(module.projectUuid()); + assertThat(moduleReloaded.parentProjectId()).isEqualTo(module.parentProjectId()); + + ComponentDto directoryReloaded = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir"); + assertThat(directoryReloaded).isNotNull(); + assertThat(directoryReloaded.uuid()).isEqualTo(directory.uuid()); + assertThat(directoryReloaded.moduleUuid()).isEqualTo(directory.moduleUuid()); + assertThat(directoryReloaded.moduleUuidPath()).isEqualTo(directory.moduleUuidPath()); + assertThat(directoryReloaded.projectUuid()).isEqualTo(directory.projectUuid()); + assertThat(directoryReloaded.parentProjectId()).isEqualTo(directory.parentProjectId()); + assertThat(directoryReloaded.name()).isEqualTo(directory.name()); + assertThat(directoryReloaded.path()).isEqualTo(directory.path()); + + ComponentDto fileReloaded = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir/Foo.java"); + assertThat(fileReloaded).isNotNull(); + assertThat(fileReloaded.uuid()).isEqualTo(file.uuid()); + assertThat(fileReloaded.moduleUuid()).isEqualTo(file.moduleUuid()); + assertThat(fileReloaded.moduleUuidPath()).isEqualTo(file.moduleUuidPath()); + assertThat(fileReloaded.projectUuid()).isEqualTo(file.projectUuid()); + assertThat(fileReloaded.parentProjectId()).isEqualTo(file.parentProjectId()); + assertThat(fileReloaded.name()).isEqualTo(file.name()); + assertThat(fileReloaded.path()).isEqualTo(file.path()); + } + + @Test + public void update_name_and_description() throws Exception { + ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey("PROJECT_KEY").setName("Project"); + dbClient.componentDao().insert(session, project); + ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module"); + dbClient.componentDao().insert(session, module); + session.commit(); + + File reportDir = temp.newFolder(); + BatchReportWriter writer = new BatchReportWriter(reportDir); + writer.writeMetadata(BatchReport.Metadata.newBuilder() + .setRootComponentRef(1) + .build()); + + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(1) + .setType(Constants.ComponentType.PROJECT) + .setKey("PROJECT_KEY") + .setName("New project name") + .setDescription("New project description") + .addChildRef(2) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(2) + .setType(Constants.ComponentType.MODULE) + .setKey("MODULE_KEY") + .setName("New module name") + .setDescription("New module description") + .build()); + + sut.execute(new ComputationContext(new BatchReportReader(reportDir), project)); + + ComponentDto projectReloaded = dbClient.componentDao().selectNullableByKey(session, "PROJECT_KEY"); + assertThat(projectReloaded.name()).isEqualTo("New project name"); + assertThat(projectReloaded.description()).isEqualTo("New project description"); + + ComponentDto moduleReloaded = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY"); + assertThat(moduleReloaded.name()).isEqualTo("New module name"); + assertThat(moduleReloaded.description()).isEqualTo("New module description"); + } + + @Test + public void update_module_uuid_when_moving_a_module() throws Exception { + ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey("PROJECT_KEY").setName("Project"); + dbClient.componentDao().insert(session, project); + ComponentDto moduleB = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_B").setName("Module B"); + dbClient.componentDao().insert(session, moduleB); + ComponentDto directory = ComponentTesting.newDirectory(moduleB, "src/main/java/dir").setUuid("CDEF").setKey("MODULE_B:src/main/java/dir"); + ComponentDto file = ComponentTesting.newFileDto(moduleB, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java").setKey("MODULE_B:src/main/java/dir/Foo.java"); + dbClient.componentDao().insert(session, directory, file); + session.commit(); + + File reportDir = temp.newFolder(); + BatchReportWriter writer = new BatchReportWriter(reportDir); + writer.writeMetadata(BatchReport.Metadata.newBuilder() + .setRootComponentRef(1) + .build()); + + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(1) + .setType(Constants.ComponentType.PROJECT) + .setKey("PROJECT_KEY") + .setName("Project") + .addChildRef(2) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(2) + .setType(Constants.ComponentType.MODULE) + .setKey("MODULE_A") + .setName("Module A") + .addChildRef(3) + .build()); + // Module B is now a sub module of module A + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(3) + .setType(Constants.ComponentType.MODULE) + .setKey("MODULE_B") + .setName("Module B") + .addChildRef(4) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(4) + .setType(Constants.ComponentType.DIRECTORY) + .setPath("src/main/java/dir") + .addChildRef(5) + .build()); + writer.writeComponent(BatchReport.Component.newBuilder() + .setRef(5) + .setType(Constants.ComponentType.FILE) + .setPath("src/main/java/dir/Foo.java") + .build()); + + sut.execute(new ComputationContext(new BatchReportReader(reportDir), project)); + + assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5); + + ComponentDto moduleA = dbClient.componentDao().selectNullableByKey(session, "MODULE_A"); + assertThat(moduleA).isNotNull(); + + ComponentDto moduleBReloaded = dbClient.componentDao().selectNullableByKey(session, "MODULE_B"); + assertThat(moduleBReloaded).isNotNull(); + assertThat(moduleBReloaded.uuid()).isEqualTo(moduleB.uuid()); + assertThat(moduleBReloaded.moduleUuid()).isEqualTo(moduleA.uuid()); + assertThat(moduleBReloaded.moduleUuidPath()).isEqualTo(moduleA.moduleUuidPath() + moduleBReloaded.uuid() + "."); + assertThat(moduleBReloaded.projectUuid()).isEqualTo(project.uuid()); + assertThat(moduleBReloaded.parentProjectId()).isEqualTo(moduleA.getId()); + + ComponentDto directoryReloaded = dbClient.componentDao().selectNullableByKey(session, "MODULE_B:src/main/java/dir"); + assertThat(directoryReloaded).isNotNull(); + assertThat(directoryReloaded.uuid()).isEqualTo(directory.uuid()); + assertThat(directoryReloaded.moduleUuid()).isEqualTo(moduleBReloaded.uuid()); + assertThat(directoryReloaded.moduleUuidPath()).isEqualTo(moduleBReloaded.moduleUuidPath()); + assertThat(directoryReloaded.projectUuid()).isEqualTo(project.uuid()); + assertThat(directoryReloaded.parentProjectId()).isEqualTo(moduleBReloaded.getId()); + + ComponentDto fileReloaded = dbClient.componentDao().selectNullableByKey(session, "MODULE_B:src/main/java/dir/Foo.java"); + assertThat(fileReloaded).isNotNull(); + assertThat(fileReloaded.uuid()).isEqualTo(file.uuid()); + assertThat(fileReloaded.moduleUuid()).isEqualTo(moduleBReloaded.uuid()); + assertThat(fileReloaded.moduleUuidPath()).isEqualTo(moduleBReloaded.moduleUuidPath()); + assertThat(fileReloaded.projectUuid()).isEqualTo(project.uuid()); + assertThat(fileReloaded.parentProjectId()).isEqualTo(moduleBReloaded.getId()); + } + +} diff --git a/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/find_project_uuids.xml b/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/find_project_uuids.xml deleted file mode 100644 index fbf078c8a27..00000000000 --- a/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/find_project_uuids.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/insert-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/insert-result.xml index 98615e2214e..bf39c3a305b 100644 --- a/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/insert-result.xml +++ b/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/insert-result.xml @@ -4,7 +4,7 @@ name="RequestContext.java" long_name="org.struts.RequestContext" uuid="GHIJ" project_uuid="ABCD" module_uuid="EFGH" module_uuid_path=".ABCD.EFGH." qualifier="FIL" scope="FIL" language="java" path="src/org/struts/RequestContext.java" root_id="3" - description="[null]" enabled="[true]" copy_resource_id="5" person_id="[null]" + description="description" enabled="[true]" copy_resource_id="5" person_id="[null]" authorization_updated_at="123456789" created_at="2014-06-18" /> diff --git a/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/update-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/update-result.xml new file mode 100644 index 00000000000..8b0e8390a61 --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/update-result.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/update.xml b/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/update.xml new file mode 100644 index 00000000000..bf39c3a305b --- /dev/null +++ b/server/sonar-server/src/test/resources/org/sonar/server/component/db/ComponentDaoTest/update.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java b/sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java index 5c934b98490..93a2feb82ee 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java +++ b/sonar-core/src/main/java/org/sonar/core/component/ComponentDto.java @@ -49,6 +49,7 @@ public class ComponentDto implements Component { private String name; private String longName; private String language; + private String description; private boolean enabled = true; private Date createdAt; @@ -185,6 +186,16 @@ public class ComponentDto implements Component { return this; } + @CheckForNull + public String description() { + return description; + } + + public ComponentDto setDescription(@Nullable String description) { + this.description = description; + return this; + } + @CheckForNull public Long parentProjectId() { return parentProjectId; diff --git a/sonar-core/src/main/java/org/sonar/core/component/db/ComponentMapper.java b/sonar-core/src/main/java/org/sonar/core/component/db/ComponentMapper.java index 643c34ddc19..be3f2b12412 100644 --- a/sonar-core/src/main/java/org/sonar/core/component/db/ComponentMapper.java +++ b/sonar-core/src/main/java/org/sonar/core/component/db/ComponentMapper.java @@ -93,6 +93,11 @@ public interface ComponentMapper { */ List selectUuidsForQualifiers(@Param("qualifiers") String... qualifiers); + /** + * Return all components of a project + */ + List selectComponentsFromProjectUuid(@Param("projectUuid") String projectUuid); + /** * Return technical projects from a view or a sub-view */ @@ -100,8 +105,6 @@ public interface ComponentMapper { long countById(long id); - void insert(ComponentDto rule); - List selectProvisionedProjects(Map parameters, RowBounds rowBounds); int countProvisionedProjects(Map parameters); @@ -109,4 +112,8 @@ public interface ComponentMapper { List selectGhostProjects(Map parameters, RowBounds rowBounds); long countGhostProjects(Map parameters); + + void insert(ComponentDto componentDto); + + void update(ComponentDto componentDto); } diff --git a/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml b/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml index 54e3ffd9754..f7690f358a0 100644 --- a/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml +++ b/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml @@ -12,6 +12,7 @@ p.deprecated_kee as deprecatedKey, p.name as name, p.long_name as longName, + p.description as description, p.qualifier as qualifier, p.scope as scope, p.language as language, @@ -212,16 +213,14 @@ - - (kee, deprecated_kee, uuid, project_uuid, module_uuid, module_uuid_path, name, long_name, qualifier, scope, language, root_id, path, copy_resource_id, enabled, - created_at, authorization_updated_at) - - - - insert into projects - values (#{kee}, #{deprecatedKey}, #{uuid}, #{projectUuid}, #{moduleUuid}, #{moduleUuidPath}, #{name}, #{longName}, #{qualifier}, #{scope}, - #{language}, #{parentProjectId}, #{path}, #{copyResourceId}, #{enabled}, #{createdAt}, #{authorizationUpdatedAt}) - +