From: Julien Lancelot Date: Wed, 1 Oct 2014 17:19:58 +0000 (+0200) Subject: SONAR-5663 Reindex issues when renaming a project Key X-Git-Tag: 5.0-RC1~848 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=dd9b60a85b5cb8e76ca29759fb93fc16219b4133;p=sonarqube.git SONAR-5663 Reindex issues when renaming a project Key --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java new file mode 100644 index 00000000000..534ae2f4689 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentService.java @@ -0,0 +1,131 @@ +/* + * 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.component; + +import com.google.common.collect.ImmutableMap; +import org.sonar.api.ServerComponent; +import org.sonar.api.web.UserRole; +import org.sonar.core.component.ComponentDto; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.preview.PreviewCache; +import org.sonar.core.resource.ResourceKeyUpdaterDao; +import org.sonar.server.db.DbClient; +import org.sonar.server.permission.InternalPermissionService; +import org.sonar.server.user.UserSession; + +import javax.annotation.CheckForNull; + +import java.util.Date; + +public class ComponentService implements ServerComponent { + + private final DbClient dbClient; + + private final ResourceKeyUpdaterDao resourceKeyUpdaterDao; + private final InternalPermissionService permissionService; + private final PreviewCache previewCache; + + public ComponentService(DbClient dbClient, ResourceKeyUpdaterDao resourceKeyUpdaterDao, InternalPermissionService permissionService, PreviewCache previewCache) { + this.dbClient = dbClient; + this.resourceKeyUpdaterDao = resourceKeyUpdaterDao; + this.permissionService = permissionService; + this.previewCache = previewCache; + } + + public ComponentDto getByKey(String key) { + DbSession session = dbClient.openSession(false); + try { + return dbClient.componentDao().getByKey(session, key); + } finally { + session.close(); + } + } + + @CheckForNull + public ComponentDto getNullableByKey(String key) { + DbSession session = dbClient.openSession(false); + try { + return dbClient.componentDao().getNullableByKey(session, key); + } finally { + session.close(); + } + } + + public ComponentDto getByKey(DbSession session, String key) { + return dbClient.componentDao().getByKey(session, key); + } + + public void updateKey(String projectOrModuleKey, String newKey) { + UserSession.get().checkComponentPermission(UserRole.ADMIN, projectOrModuleKey); + + DbSession session = dbClient.openSession(false); + try { + ComponentDto projectOrModule = getByKey(projectOrModuleKey); + ComponentDto oldRootProject = dbClient.componentDao().getRootProjectByKey(projectOrModuleKey, session); + + resourceKeyUpdaterDao.updateKey(projectOrModule.getId(), newKey); + session.commit(); + + ComponentDto newRootProject = dbClient.componentDao().getRootProjectByKey(newKey, session); + updateIssuesIndex(session, oldRootProject.key(), newRootProject.key()); + + previewCache.reportResourceModification(newRootProject.key()); + + session.commit(); + } finally { + session.close(); + } + } + + public void bulkUpdateKey(String projectKey, String stringToReplace, String replacementString) { + UserSession.get().checkProjectPermission(UserRole.ADMIN, projectKey); + + DbSession session = dbClient.openSession(false); + try { + ComponentDto project = getByKey(projectKey); + + resourceKeyUpdaterDao.bulkUpdateKey(project.getId(), stringToReplace, replacementString); + session.commit(); + + ComponentDto newProject = dbClient.componentDao().getById(project.getId(), session); + updateIssuesIndex(session, projectKey, newProject.key()); + + previewCache.reportResourceModification(newProject.key()); + + session.commit(); + } finally { + session.close(); + } + } + + private void updateIssuesIndex(DbSession session, String oldKey, String newKey) { + // Remove permission on old project key + permissionService.synchronizePermissions(session, oldKey); + + // Add permission on new project key + permissionService.synchronizePermissions(session, newKey); + + // Reindex issues on new project key + dbClient.issueDao().synchronizeAfter(session, new Date(0), + ImmutableMap.of("project", newKey)); + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java b/server/sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java index 94de74f57e4..de8be6e9791 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java @@ -43,12 +43,14 @@ public class DefaultRubyComponentService implements RubyComponentService { private final ResourceDao resourceDao; private final DefaultComponentFinder finder; private final ResourceIndexerDao resourceIndexerDao; + private final ComponentService componentService; private final I18n i18n; - public DefaultRubyComponentService(ResourceDao resourceDao, DefaultComponentFinder finder, ResourceIndexerDao resourceIndexerDao, I18n i18n) { + public DefaultRubyComponentService(ResourceDao resourceDao, DefaultComponentFinder finder, ResourceIndexerDao resourceIndexerDao, ComponentService componentService, I18n i18n) { this.resourceDao = resourceDao; this.finder = finder; this.resourceIndexerDao = resourceIndexerDao; + this.componentService = componentService; this.i18n = i18n; } @@ -114,6 +116,14 @@ public class DefaultRubyComponentService implements RubyComponentService { return resourceDao.selectProvisionedProjects(query.qualifiers()); } + public void updateKey(String projectOrModuleKey, String newKey) { + componentService.updateKey(projectOrModuleKey, newKey); + } + + public void bulkUpdateKey(String projectKey, String stringToReplace, String replacementString) { + componentService.bulkUpdateKey(projectKey, stringToReplace, replacementString); + } + static ComponentQuery toQuery(Map props) { ComponentQuery.Builder builder = ComponentQuery.builder() .keys(RubyUtils.toStrings(props.get("keys"))) diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java index a765263734e..b55ff650787 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java @@ -79,6 +79,7 @@ import org.sonar.server.authentication.ws.AuthenticationWs; import org.sonar.server.batch.*; import org.sonar.server.charts.ChartFactory; import org.sonar.server.component.ComponentCleanerService; +import org.sonar.server.component.ComponentService; import org.sonar.server.component.DefaultComponentFinder; import org.sonar.server.component.DefaultRubyComponentService; import org.sonar.server.component.db.ComponentDao; @@ -474,6 +475,7 @@ class ServerComponents { // components pico.addSingleton(DefaultComponentFinder.class); pico.addSingleton(DefaultRubyComponentService.class); + pico.addSingleton(ComponentService.class); pico.addSingleton(ComponentDao.class); pico.addSingleton(ResourcesWs.class); pico.addSingleton(ComponentsWs.class); diff --git a/server/sonar-server/src/test/java/org/sonar/server/batch/UploadReportActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/batch/UploadReportActionMediumTest.java index adfc9545ece..f0cc57a8ab9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/batch/UploadReportActionMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/batch/UploadReportActionMediumTest.java @@ -170,7 +170,7 @@ public class UploadReportActionMediumTest { .setProjectId_unit_test_only(project.getId()) .setKey("MyComponent"); db.componentDao().insert(session, resource); - db.snapshotDao().insert(session, SnapshotTesting.createForComponent(resource)); + db.snapshotDao().insert(session, SnapshotTesting.createForComponent(resource, project)); RuleDto rule = RuleTesting.newXooX1(); tester.get(RuleDao.class).insert(session, rule); @@ -218,7 +218,7 @@ public class UploadReportActionMediumTest { .setProjectId_unit_test_only(project.getId()) .setKey("MyComponent"); db.componentDao().insert(session, resource); - db.snapshotDao().insert(session, SnapshotTesting.createForComponent(resource)); + db.snapshotDao().insert(session, SnapshotTesting.createForComponent(resource, project)); RuleDto rule = RuleTesting.newXooX1(); tester.get(RuleDao.class).insert(session, rule); diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceMediumTest.java new file mode 100644 index 00000000000..9415fd8e9d5 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentServiceMediumTest.java @@ -0,0 +1,242 @@ +/* + * 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.component; + +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.sonar.api.security.DefaultGroups; +import org.sonar.api.web.UserRole; +import org.sonar.core.component.ComponentDto; +import org.sonar.core.issue.db.IssueDto; +import org.sonar.core.permission.PermissionFacade; +import org.sonar.core.persistence.DbSession; +import org.sonar.core.rule.RuleDto; +import org.sonar.server.component.db.ComponentDao; +import org.sonar.server.component.db.SnapshotDao; +import org.sonar.server.db.DbClient; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.issue.IssueQuery; +import org.sonar.server.issue.IssueTesting; +import org.sonar.server.issue.index.IssueAuthorizationIndex; +import org.sonar.server.issue.index.IssueIndex; +import org.sonar.server.rule.RuleTesting; +import org.sonar.server.rule.db.RuleDao; +import org.sonar.server.search.IndexClient; +import org.sonar.server.search.QueryContext; +import org.sonar.server.tester.ServerTester; +import org.sonar.server.user.MockUserSession; + +import java.util.Date; + +import static org.fest.assertions.Assertions.assertThat; + +public class ComponentServiceMediumTest { + + @ClassRule + public static ServerTester tester = new ServerTester(); + + DbClient db; + IndexClient indexClient; + DbSession session; + + ComponentService service; + + ComponentDto project; + RuleDto rule; + + @Before + public void setUp() throws Exception { + tester.clearDbAndIndexes(); + db = tester.get(DbClient.class); + indexClient = tester.get(IndexClient.class); + session = db.openSession(false); + service = tester.get(ComponentService.class); + + project = ComponentTesting.newProjectDto().setKey("sample:root"); + tester.get(ComponentDao.class).insert(session, project); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForProject(project)); + + // project can be seen by anyone + tester.get(PermissionFacade.class).insertGroupPermission(project.getId(), DefaultGroups.ANYONE, UserRole.USER, session); + db.issueAuthorizationDao().synchronizeAfter(session, new Date(0)); + + rule = RuleTesting.newXooX1(); + tester.get(RuleDao.class).insert(session, rule); + + session.commit(); + } + + @After + public void after() { + session.close(); + } + + @Test + public void get_by_key() throws Exception { + assertThat(service.getByKey(project.getKey())).isNotNull(); + } + + @Test + public void get_nullable_by_key() throws Exception { + assertThat(service.getNullableByKey(project.getKey())).isNotNull(); + assertThat(service.getNullableByKey("unknown")).isNull(); + } + + @Test + public void update_project_key() throws Exception { + ComponentDto file = ComponentTesting.newFileDto(project).setKey("sample:root:src/File.xoo"); + tester.get(ComponentDao.class).insert(session, file); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(file, project)); + + IssueDto issue = IssueTesting.newDto(rule, file, project); + db.issueDao().insert(session, issue); + + session.commit(); + + MockUserSession.set().setLogin("john").addComponentPermission(UserRole.ADMIN, project.key(), project.key()); + service.updateKey(project.key(), "sample2:root"); + session.commit(); + + // Check project key has been updated + assertThat(service.getNullableByKey(project.key())).isNull(); + assertThat(service.getNullableByKey("sample2:root")).isNotNull(); + + // Check file key has been updated + assertThat(service.getNullableByKey(file.key())).isNull(); + assertThat(service.getNullableByKey("sample2:root:src/File.xoo")).isNotNull(); + + // Check issue have been updated + assertThat(tester.get(IssueIndex.class).getNullableByKey(issue.getKey()).componentKey()).isEqualTo("sample2:root:src/File.xoo"); + assertThat(tester.get(IssueIndex.class).getNullableByKey(issue.getKey()).projectKey()).isEqualTo("sample2:root"); + + // Check that no new issue has been added + assertThat(tester.get(IssueIndex.class).search(IssueQuery.builder().build(), new QueryContext()).getTotal()).isEqualTo(1); + + // Check Issue Authorization index + assertThat(tester.get(IssueAuthorizationIndex.class).getNullableByKey(project.getKey())).isNull(); + assertThat(tester.get(IssueAuthorizationIndex.class).getNullableByKey("sample2:root")).isNotNull(); + + // Check dry run cache have been updated + assertThat(db.propertiesDao().selectProjectProperties("sample2:root", session)).hasSize(1); + } + + @Test + public void update_module_key() throws Exception { + ComponentDto module = ComponentTesting.newModuleDto(project).setKey("sample:root:module"); + tester.get(ComponentDao.class).insert(session, module); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(module, project)); + + ComponentDto file = ComponentTesting.newFileDto(module).setKey("sample:root:module:src/File.xoo"); + tester.get(ComponentDao.class).insert(session, file); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(file, project)); + + IssueDto issue = IssueTesting.newDto(rule, file, project); + db.issueDao().insert(session, issue); + + session.commit(); + + MockUserSession.set().setLogin("john").addComponentPermission(UserRole.ADMIN, project.key(), module.key()); + service.updateKey(module.key(), "sample:root2:module"); + session.commit(); + + // Project key has not changed + assertThat(service.getNullableByKey(project.key())).isNotNull(); + + // Check module key has been updated + assertThat(service.getNullableByKey(module.key())).isNull(); + assertThat(service.getNullableByKey("sample:root2:module")).isNotNull(); + + // Check file key has been updated + assertThat(service.getNullableByKey(file.key())).isNull(); + assertThat(service.getNullableByKey("sample:root2:module:src/File.xoo")).isNotNull(); + + // Check issue have been updated + assertThat(tester.get(IssueIndex.class).getNullableByKey(issue.getKey()).componentKey()).isEqualTo("sample:root2:module:src/File.xoo"); + assertThat(tester.get(IssueIndex.class).getNullableByKey(issue.getKey()).projectKey()).isEqualTo(project.key()); + + // Check Issue Authorization index + assertThat(tester.get(IssueAuthorizationIndex.class).getNullableByKey(project.getKey())).isNotNull(); + + // Check dry run cache have been updated -> on a module it's the project cache that is updated + assertThat(db.propertiesDao().selectProjectProperties(project.key(), session)).hasSize(1); + } + + @Test(expected = ForbiddenException.class) + public void fail_to_update_project_key_without_admin_permission() throws Exception { + MockUserSession.set().setLogin("john").addComponentPermission(UserRole.USER, project.key(), project.key()); + service.updateKey(project.key(), "sample2:root"); + } + + @Test + public void bulk_update_project_key() throws Exception { + ComponentDto module = ComponentTesting.newModuleDto(project).setKey("sample:root:module"); + tester.get(ComponentDao.class).insert(session, module); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(module, project)); + + ComponentDto file = ComponentTesting.newFileDto(module).setKey("sample:root:module:src/File.xoo"); + tester.get(ComponentDao.class).insert(session, file); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(file, project)); + + IssueDto issue = IssueTesting.newDto(rule, file, project); + db.issueDao().insert(session, issue); + + session.commit(); + + MockUserSession.set().setLogin("john").addProjectPermissions(UserRole.ADMIN, project.key()); + service.bulkUpdateKey("sample:root", "sample", "sample2"); + session.commit(); + + // Check project key has been updated + assertThat(service.getNullableByKey(project.key())).isNull(); + assertThat(service.getNullableByKey("sample2:root")).isNotNull(); + + // Check module key has been updated + assertThat(service.getNullableByKey(module.key())).isNull(); + assertThat(service.getNullableByKey("sample2:root:module")).isNotNull(); + + // Check file key has been updated + assertThat(service.getNullableByKey(file.key())).isNull(); + assertThat(service.getNullableByKey("sample2:root:module:src/File.xoo")).isNotNull(); + + // Check issue have been updated + assertThat(tester.get(IssueIndex.class).getNullableByKey(issue.getKey()).componentKey()).isEqualTo("sample2:root:module:src/File.xoo"); + assertThat(tester.get(IssueIndex.class).getNullableByKey(issue.getKey()).projectKey()).isEqualTo("sample2:root"); + + // Check that no new issue has been added + assertThat(tester.get(IssueIndex.class).search(IssueQuery.builder().build(), new QueryContext()).getTotal()).isEqualTo(1); + + // Check Issue Authorization index + assertThat(tester.get(IssueAuthorizationIndex.class).getNullableByKey(project.getKey())).isNull(); + assertThat(tester.get(IssueAuthorizationIndex.class).getNullableByKey("sample2:root")).isNotNull(); + + // Check dry run cache have been updated + assertThat(db.propertiesDao().selectProjectProperties("sample2:root", session)).hasSize(1); + } + + @Test(expected = ForbiddenException.class) + public void fail_to_bulk_update_project_key_without_admin_permission() throws Exception { + MockUserSession.set().setLogin("john").addProjectPermissions(UserRole.USER, project.key()); + service.bulkUpdateKey("sample:root", "sample", "sample2"); + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java index 493ca99d789..d729e8329e9 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java @@ -45,7 +45,7 @@ public class ComponentTesting { .setName("Module") .setLongName("Module") .setSubProjectId(subProjectOrProject.getId()) - .setScope(Scopes.FILE) + .setScope(Scopes.PROJECT) .setQualifier(Qualifiers.MODULE) .setPath("module") .setLanguage(null) diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/DefaultRubyComponentServiceTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/DefaultRubyComponentServiceTest.java index 4acd2671ed2..28e52b6217a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/DefaultRubyComponentServiceTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/DefaultRubyComponentServiceTest.java @@ -42,26 +42,26 @@ import static com.google.common.collect.Maps.newHashMap; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyListOf; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; public class DefaultRubyComponentServiceTest { - private ResourceDao resourceDao; - private DefaultComponentFinder finder; - private ResourceIndexerDao resourceIndexerDao; - private I18n i18n; - private DefaultRubyComponentService componentService; + ResourceDao resourceDao; + DefaultComponentFinder finder; + ResourceIndexerDao resourceIndexerDao; + ComponentService componentService; + I18n i18n; + + DefaultRubyComponentService service; @Before public void before() { resourceDao = mock(ResourceDao.class); finder = mock(DefaultComponentFinder.class); resourceIndexerDao = mock(ResourceIndexerDao.class); + componentService = mock(ComponentService.class); i18n = mock(I18n.class); - componentService = new DefaultRubyComponentService(resourceDao, finder, resourceIndexerDao, i18n); + service = new DefaultRubyComponentService(resourceDao, finder, resourceIndexerDao, componentService, i18n); } @Test @@ -69,7 +69,7 @@ public class DefaultRubyComponentServiceTest { Component component = mock(Component.class); when(resourceDao.findByKey("struts")).thenReturn(component); - assertThat(componentService.findByKey("struts")).isEqualTo(component); + assertThat(service.findByKey("struts")).isEqualTo(component); } @Test @@ -82,7 +82,7 @@ public class DefaultRubyComponentServiceTest { when(component.getId()).thenReturn(componentId); when(resourceDao.findByKey(componentKey)).thenReturn(null).thenReturn(component); - componentService.createComponent(componentKey, componentName, qualifier); + service.createComponent(componentKey, componentName, qualifier); ArgumentCaptor resourceCaptor = ArgumentCaptor.forClass(ResourceDto.class); verify(resourceDao).insertOrUpdate(resourceCaptor.capture()); @@ -103,7 +103,7 @@ public class DefaultRubyComponentServiceTest { String qualifier = Qualifiers.PROJECT; when(resourceDao.findByKey(componentKey)).thenReturn(null); - componentService.createComponent(componentKey, componentName, qualifier); + service.createComponent(componentKey, componentName, qualifier); } @Test(expected = BadRequestException.class) @@ -113,19 +113,19 @@ public class DefaultRubyComponentServiceTest { String qualifier = Qualifiers.PROJECT; when(resourceDao.findByKey(componentKey)).thenReturn(mock(ComponentDto.class)); - componentService.createComponent(componentKey, componentName, qualifier); + service.createComponent(componentKey, componentName, qualifier); } @Test(expected = BadRequestException.class) public void should_throw_if_malformed_key1() { - componentService.createComponent("1234", "New Project", Qualifiers.PROJECT); + service.createComponent("1234", "New Project", Qualifiers.PROJECT); } @Test(expected = NotFoundException.class) public void should_throw_if_updating_unknown_component() { final long componentId = 1234l; when(resourceDao.getResource(componentId)).thenReturn(null); - componentService.updateComponent(componentId, "key", "name"); + service.updateComponent(componentId, "key", "name"); } @Test @@ -137,7 +137,7 @@ public class DefaultRubyComponentServiceTest { when(resourceDao.getResource(componentId)).thenReturn(resource); when(resource.setKey(newKey)).thenReturn(resource); when(resource.setName(newName)).thenReturn(resource); - componentService.updateComponent(componentId, newKey, newName); + service.updateComponent(componentId, newKey, newName); verify(resource).setKey(newKey); verify(resource).setName(newName); verify(resourceDao).insertOrUpdate(resource); @@ -150,7 +150,7 @@ public class DefaultRubyComponentServiceTest { final String newName = "newName"; ResourceDto resource = mock(ResourceDto.class); when(resourceDao.getResource(componentId)).thenReturn(resource); - componentService.updateComponent(componentId, newKey, newName); + service.updateComponent(componentId, newKey, newName); } @Test @@ -166,7 +166,7 @@ public class DefaultRubyComponentServiceTest { map.put("sort", "NAME"); map.put("asc", true); - componentService.find(map); + service.find(map); verify(resourceDao).selectProjectsByQualifiers(anyListOf(String.class)); verify(finder).find(any(ComponentQuery.class), anyListOf(Component.class)); } @@ -184,7 +184,7 @@ public class DefaultRubyComponentServiceTest { map.put("sort", "NAME"); map.put("asc", true); - componentService.findWithUncompleteProjects(map); + service.findWithUncompleteProjects(map); verify(resourceDao).selectProjectsIncludingNotCompletedOnesByQualifiers(anyListOf(String.class)); verify(finder).find(any(ComponentQuery.class), anyListOf(Component.class)); } @@ -202,7 +202,7 @@ public class DefaultRubyComponentServiceTest { map.put("sort", "NAME"); map.put("asc", true); - componentService.findGhostsProjects(map); + service.findGhostsProjects(map); verify(resourceDao).selectGhostsProjects(anyListOf(String.class)); verify(finder).find(any(ComponentQuery.class), anyListOf(Component.class)); } @@ -214,7 +214,7 @@ public class DefaultRubyComponentServiceTest { Map map = newHashMap(); map.put("qualifiers", qualifiers); - componentService.findProvisionedProjects(map); + service.findProvisionedProjects(map); verify(resourceDao).selectProvisionedProjects(anyListOf(String.class)); } @@ -255,4 +255,16 @@ public class DefaultRubyComponentServiceTest { assertThat(query.sort()).isEqualTo(ComponentQuery.SORT_BY_NAME); assertThat(query.asc()).isTrue(); } + + @Test + public void update_key() { + service.updateKey("oldKey", "newKey"); + verify(componentService).updateKey("oldKey", "newKey"); + } + + @Test + public void bulk_update_key() { + service.bulkUpdateKey("oldKey", "old", "new"); + verify(componentService).bulkUpdateKey("oldKey", "old", "new"); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/SnapshotTesting.java b/server/sonar-server/src/test/java/org/sonar/server/component/SnapshotTesting.java index 1ec6081f08d..845728744e5 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/component/SnapshotTesting.java +++ b/server/sonar-server/src/test/java/org/sonar/server/component/SnapshotTesting.java @@ -25,10 +25,20 @@ import org.sonar.core.component.SnapshotDto; public class SnapshotTesting { - public static SnapshotDto createForComponent(ComponentDto component) { + /** + * When project is null, that means that the component is a project + */ + public static SnapshotDto createForComponent(ComponentDto component, ComponentDto project) { return new SnapshotDto() .setResourceId(component.getId()) - .setRootProjectId(component.subProjectId()) + .setRootProjectId(project.getId()) + .setLast(true); + } + + public static SnapshotDto createForProject(ComponentDto project) { + return new SnapshotDto() + .setResourceId(project.getId()) + .setRootProjectId(project.getId()) .setLast(true); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceMediumTest.java index dc59a5187a4..d21e8100baa 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueBulkChangeServiceMediumTest.java @@ -91,14 +91,14 @@ public class IssueBulkChangeServiceMediumTest { .setQualifier(Qualifiers.PROJECT) .setScope(Scopes.PROJECT); tester.get(ComponentDao.class).insert(session, project); - tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(project)); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForProject(project)); file = new ComponentDto() .setSubProjectId(project.getId()) .setKey("MyComponent") .setLongName("My Component"); tester.get(ComponentDao.class).insert(session, file); - tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(file)); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(file, project)); // project can be seen by anyone tester.get(PermissionFacade.class).insertGroupPermission(project.getId(), DefaultGroups.ANYONE, UserRole.USER, session); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java index c2fe8dddf1d..b935d1fe797 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/IssueServiceMediumTest.java @@ -96,14 +96,14 @@ public class IssueServiceMediumTest { .setQualifier(Qualifiers.PROJECT) .setScope(Scopes.PROJECT); tester.get(ComponentDao.class).insert(session, project); - tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(project)); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForProject(project)); file = new ComponentDto() .setSubProjectId(project.getId()) .setKey("MyComponent") .setLongName("My Component"); tester.get(ComponentDao.class).insert(session, file); - tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(file)); + tester.get(SnapshotDao.class).insert(session, SnapshotTesting.createForComponent(file, project)); // project can be seen by anyone tester.get(PermissionFacade.class).insertGroupPermission(project.getId(), DefaultGroups.ANYONE, UserRole.USER, session); diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java index 00ac616f8b3..823f7ae17f8 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/index/IssueIndexMediumTest.java @@ -639,7 +639,7 @@ public class IssueIndexMediumTest { .setSubProjectId(project.getId()) .setKey("MyComponent"); db.componentDao().insert(session, resource); - db.snapshotDao().insert(session, SnapshotTesting.createForComponent(resource)); + db.snapshotDao().insert(session, SnapshotTesting.createForComponent(resource, project)); List issueKeys = newArrayList(); for (int i = 0; i < numberOfIssues; i++) { diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java index 4ba6aef26d4..2416470c478 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/issue/ws/SearchActionMediumTest.java @@ -84,7 +84,7 @@ public class SearchActionMediumTest { project = new ComponentDto() .setKey("MyProject"); db.componentDao().insert(session, project); - db.snapshotDao().insert(session, SnapshotTesting.createForComponent(project)); + db.snapshotDao().insert(session, SnapshotTesting.createForProject(project)); // project can be seen by anyone tester.get(PermissionFacade.class).insertGroupPermission(project.getId(), DefaultGroups.ANYONE, UserRole.USER, session); @@ -94,7 +94,7 @@ public class SearchActionMediumTest { .setKey("MyComponent") .setSubProjectId(project.getId()); db.componentDao().insert(session, file); - db.snapshotDao().insert(session, SnapshotTesting.createForComponent(file)); + db.snapshotDao().insert(session, SnapshotTesting.createForComponent(file, project)); UserDto john = new UserDto().setLogin("john").setName("John").setEmail("john@email.com"); db.userDao().insert(session, john); @@ -266,7 +266,7 @@ public class SearchActionMediumTest { .setKey("ProjectHavingModule") .setScope("PRJ"); db.componentDao().insert(session, project); - db.snapshotDao().insert(session, SnapshotTesting.createForComponent(project)); + db.snapshotDao().insert(session, SnapshotTesting.createForProject(project)); // project can be seen by anyone tester.get(PermissionFacade.class).insertGroupPermission(project.getId(), DefaultGroups.ANYONE, UserRole.USER, session); @@ -277,14 +277,14 @@ public class SearchActionMediumTest { .setScope("PRJ") .setSubProjectId(project.getId()); db.componentDao().insert(session, module); - db.snapshotDao().insert(session, SnapshotTesting.createForComponent(module)); + db.snapshotDao().insert(session, SnapshotTesting.createForComponent(module, project)); ComponentDto file = new ComponentDto() .setKey("FileLinkedToModule") .setScope("FIL") .setSubProjectId(module.getId()); db.componentDao().insert(session, file); - db.snapshotDao().insert(session, SnapshotTesting.createForComponent(file)); + db.snapshotDao().insert(session, SnapshotTesting.createForComponent(file, project)); IssueDto issue = IssueTesting.newDto(rule, file, project); db.issueDao().insert(session, issue); diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/BackendCleanupMediumTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/BackendCleanupMediumTest.java index 4afc1f1c786..d7ebf51e461 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/BackendCleanupMediumTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/BackendCleanupMediumTest.java @@ -77,13 +77,13 @@ public class BackendCleanupMediumTest { project = new ComponentDto() .setKey("MyProject"); tester.get(ComponentDao.class).insert(session, project); - db.snapshotDao().insert(session, SnapshotTesting.createForComponent(project)); + db.snapshotDao().insert(session, SnapshotTesting.createForProject(project)); file = new ComponentDto() .setProjectId_unit_test_only(project.getId()) .setKey("MyComponent"); tester.get(ComponentDao.class).insert(session, file); - db.snapshotDao().insert(session, SnapshotTesting.createForComponent(file)); + db.snapshotDao().insert(session, SnapshotTesting.createForComponent(file, project)); // project can be seen by anyone tester.get(PermissionFacade.class).insertGroupPermission(project.getId(), DefaultGroups.ANYONE, UserRole.USER, session); diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_controller.rb index 150b37a3e7e..09148fc3bec 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_controller.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_controller.rb @@ -164,13 +164,9 @@ class ProjectController < ApplicationController elsif Project.by_key(new_key) flash[:error] = message('update_key.cant_update_x_because_resource_already_exist_with_key_x', :params => [project.key, new_key]) else - begin - java_facade.updateResourceKey(project.id, new_key) - reportProjectModification(project.id) + call_backend do + Internal.component_api.updateKey(project.key, new_key) flash[:notice] = message('update_key.key_updated') - rescue Exception => e - flash[:error] = message('update_key.error_occured_while_renaming_key_of_x', - :params => [project.key, Api::Utils.exception_message(e, :backtrace => false)]) end end @@ -207,13 +203,9 @@ class ProjectController < ApplicationController replacement_string = params[:replacement_string].strip unless string_to_replace.blank? || replacement_string.blank? - begin - java_facade.bulkUpdateKey(project.id, string_to_replace, replacement_string) - reportProjectModification(project.id) + call_backend do + Internal.component_api.bulkUpdateKey(project.key, string_to_replace, replacement_string) flash[:notice] = message('update_key.key_updated') - rescue Exception => e - flash[:error] = message('update_key.error_occured_while_renaming_key_of_x', - :params => [project.key, Api::Utils.exception_message(e, :backtrace => false)]) end end