3 * Copyright (C) 2009-2020 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.component;
22 import com.google.common.collect.ImmutableSet;
23 import org.junit.Rule;
24 import org.junit.Test;
25 import org.junit.rules.ExpectedException;
26 import org.sonar.api.utils.System2;
27 import org.sonar.api.web.UserRole;
28 import org.sonar.db.DbClient;
29 import org.sonar.db.DbSession;
30 import org.sonar.db.DbTester;
31 import org.sonar.db.component.ComponentDbTester;
32 import org.sonar.db.component.ComponentDto;
33 import org.sonar.db.component.ComponentTesting;
34 import org.sonar.server.es.ProjectIndexer;
35 import org.sonar.server.es.TestProjectIndexers;
36 import org.sonar.server.exceptions.BadRequestException;
37 import org.sonar.server.exceptions.ForbiddenException;
38 import org.sonar.server.project.Project;
39 import org.sonar.server.project.ProjectLifeCycleListeners;
40 import org.sonar.server.project.RekeyedProject;
41 import org.sonar.server.tester.UserSessionRule;
43 import static java.util.Collections.emptyList;
44 import static org.assertj.core.api.Assertions.assertThat;
45 import static org.mockito.Mockito.mock;
46 import static org.mockito.Mockito.verify;
47 import static org.sonar.db.component.ComponentTesting.newFileDto;
48 import static org.sonar.db.component.ComponentTesting.newModuleDto;
50 public class ComponentServiceUpdateKeyTest {
52 private System2 system2 = System2.INSTANCE;
55 public UserSessionRule userSession = UserSessionRule.standalone();
57 public ExpectedException expectedException = ExpectedException.none();
59 public DbTester db = DbTester.create(system2);
61 private ComponentDbTester componentDb = new ComponentDbTester(db);
62 private DbClient dbClient = db.getDbClient();
63 private DbSession dbSession = db.getSession();
64 private TestProjectIndexers projectIndexers = new TestProjectIndexers();
65 private ProjectLifeCycleListeners projectLifeCycleListeners = mock(ProjectLifeCycleListeners.class);
66 private ComponentService underTest = new ComponentService(dbClient, userSession, projectIndexers, projectLifeCycleListeners);
69 public void update_project_key() {
70 ComponentDto project = insertSampleProject();
71 ComponentDto file = componentDb.insertComponent(ComponentTesting.newFileDto(project, null).setDbKey("sample:root:src/File.xoo"));
72 ComponentDto inactiveFile = componentDb.insertComponent(ComponentTesting.newFileDto(project, null).setDbKey("sample:root:src/InactiveFile.xoo").setEnabled(false));
76 logInAsProjectAdministrator(project);
77 underTest.updateKey(dbSession, componentDb.getProjectDto(project), "sample2:root");
80 // Check project key has been updated
81 assertThat(db.getDbClient().componentDao().selectByKey(dbSession, project.getDbKey())).isEmpty();
82 assertThat(db.getDbClient().componentDao().selectByKey(dbSession, "sample2:root")).isNotNull();
84 // Check file key has been updated
85 assertThat(db.getDbClient().componentDao().selectByKey(dbSession, file.getDbKey())).isEmpty();
86 assertThat(db.getDbClient().componentDao().selectByKey(dbSession, "sample2:root:src/File.xoo")).isNotNull();
87 assertThat(db.getDbClient().componentDao().selectByKey(dbSession, "sample2:root:src/InactiveFile.xoo")).isNotNull();
89 assertThat(dbClient.componentDao().selectByKey(dbSession, inactiveFile.getDbKey())).isEmpty();
91 assertThat(projectIndexers.hasBeenCalled(project.uuid(), ProjectIndexer.Cause.PROJECT_KEY_UPDATE)).isTrue();
95 public void update_provisioned_project_key() {
96 ComponentDto provisionedProject = insertProject("provisionedProject");
100 logInAsProjectAdministrator(provisionedProject);
101 underTest.updateKey(dbSession, componentDb.getProjectDto(provisionedProject), "provisionedProject2");
104 assertComponentKeyHasBeenUpdated(provisionedProject.getDbKey(), "provisionedProject2");
105 assertThat(projectIndexers.hasBeenCalled(provisionedProject.uuid(), ProjectIndexer.Cause.PROJECT_KEY_UPDATE)).isTrue();
109 public void fail_to_update_project_key_without_admin_permission() {
110 expectedException.expect(ForbiddenException.class);
112 ComponentDto project = insertSampleProject();
113 userSession.logIn("john").addProjectPermission(UserRole.USER, project);
115 underTest.updateKey(dbSession, componentDb.getProjectDto(project), "sample2:root");
119 public void fail_if_old_key_and_new_key_are_the_same() {
120 ComponentDto project = insertSampleProject();
121 ComponentDto anotherProject = componentDb.insertPrivateProject();
122 logInAsProjectAdministrator(project);
124 expectedException.expect(IllegalArgumentException.class);
125 expectedException.expectMessage("Impossible to update key: a component with key \"" + anotherProject.getDbKey() + "\" already exists.");
127 underTest.updateKey(dbSession, componentDb.getProjectDto(project), anotherProject.getDbKey());
131 public void fail_if_new_key_is_empty() {
132 ComponentDto project = insertSampleProject();
133 logInAsProjectAdministrator(project);
135 expectedException.expect(BadRequestException.class);
136 expectedException.expectMessage("Malformed key for ''. It cannot be empty nor contain whitespaces.");
138 underTest.updateKey(dbSession, componentDb.getProjectDto(project), "");
142 public void fail_if_new_key_is_invalid() {
143 ComponentDto project = insertSampleProject();
144 logInAsProjectAdministrator(project);
146 expectedException.expect(BadRequestException.class);
147 expectedException.expectMessage("Malformed key for 'sample root'. It cannot be empty nor contain whitespaces.");
149 underTest.updateKey(dbSession, componentDb.getProjectDto(project), "sample root");
153 public void bulk_update_key() {
154 ComponentDto project = componentDb.insertPublicProject(db.organizations().insert(), c -> c.setDbKey("my_project"));
155 ComponentDto module = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:root:module"));
156 ComponentDto inactiveModule = componentDb.insertComponent(newModuleDto(project).setDbKey("my_project:root:inactive_module").setEnabled(false));
157 ComponentDto file = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/File.xoo"));
158 ComponentDto inactiveFile = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/InactiveFile.xoo").setEnabled(false));
160 underTest.bulkUpdateKey(dbSession, componentDb.getProjectDto(project), "my_", "your_");
162 assertComponentKeyUpdated(project.getDbKey(), "your_project");
163 assertComponentKeyUpdated(module.getDbKey(), "your_project:root:module");
164 assertComponentKeyUpdated(file.getDbKey(), "your_project:root:module:src/File.xoo");
165 assertComponentKeyUpdated(inactiveModule.getDbKey(), "your_project:root:inactive_module");
166 assertComponentKeyUpdated(inactiveFile.getDbKey(), "your_project:root:module:src/InactiveFile.xoo");
167 verify(projectLifeCycleListeners).onProjectsRekeyed(ImmutableSet.of(
168 new RekeyedProject(new Project(project.uuid(), "your_project", project.name(), project.uuid(), emptyList()), "my_project")));
172 public void bulk_update_key_with_branch_and_pr() {
173 ComponentDto project = componentDb.insertPublicProject(db.organizations().insert(), c -> c.setDbKey("my_project"));
174 ComponentDto branch = componentDb.insertProjectBranch(project);
175 ComponentDto module = componentDb.insertComponent(newModuleDto(branch).setDbKey("my_project:root:module"));
176 ComponentDto file = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/File.xoo"));
178 underTest.bulkUpdateKey(dbSession, componentDb.getProjectDto(project), "my_", "your_");
180 assertComponentKeyUpdated(project.getDbKey(), "your_project");
181 assertComponentKeyUpdated(module.getDbKey(), "your_project:root:module");
182 assertComponentKeyUpdated(file.getDbKey(), "your_project:root:module:src/File.xoo");
183 verify(projectLifeCycleListeners).onProjectsRekeyed(ImmutableSet.of(
184 new RekeyedProject(new Project(project.uuid(), "your_project", project.name(), project.uuid(), emptyList()), "my_project")));
187 private void assertComponentKeyUpdated(String oldKey, String newKey) {
188 assertThat(dbClient.componentDao().selectByKey(dbSession, oldKey)).isEmpty();
189 assertThat(dbClient.componentDao().selectByKey(dbSession, newKey)).isPresent();
192 private ComponentDto insertSampleProject() {
193 return insertProject("sample:root");
196 private ComponentDto insertProject(String key) {
197 return componentDb.insertPrivateProject(db.organizations().insert(), c -> c.setDbKey(key));
200 private void assertComponentKeyHasBeenUpdated(String oldKey, String newKey) {
201 assertThat(dbClient.componentDao().selectByKey(dbSession, oldKey)).isEmpty();
202 assertThat(dbClient.componentDao().selectByKey(dbSession, newKey)).isPresent();
205 private void logInAsProjectAdministrator(ComponentDto provisionedProject) {
206 userSession.logIn("john").addProjectPermission(UserRole.ADMIN, provisionedProject);