import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
+import java.util.function.BiConsumer;
import java.util.function.Function;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
+import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.resources.Qualifiers;
import org.sonar.db.Dao;
});
// and then proceed with the batch UPDATE at once
- runBatchUpdateForAllResources(resources, projectOldKey, newKey, mapper);
+ runBatchUpdateForAllResources(resources, projectOldKey, newKey, mapper, (resource, oldKey) -> {
+ });
}
public static void checkIsProjectOrModule(ComponentDto component) {
return key.replace(stringToReplace, replacementString);
}
- public void bulkUpdateKey(DbSession session, String projectUuid, String stringToReplace, String replacementString) {
+ public Set<RekeyedResource> bulkUpdateKey(DbSession session, String projectUuid, String stringToReplace, String replacementString,
+ Predicate<RekeyedResource> rekeyedResourceFilter) {
ComponentKeyUpdaterMapper mapper = session.getMapper(ComponentKeyUpdaterMapper.class);
// must SELECT first everything
Set<ResourceDto> modules = collectAllModules(projectUuid, stringToReplace, mapper, true);
allResourcesByModuleMap.put(module, mapper.selectProjectResources(module.getUuid()));
}
+ Set<RekeyedResource> rekeyedResources = new HashSet<>();
// and then proceed with the batch UPDATE at once
for (ResourceDto module : modules) {
String oldModuleKey = module.getKey();
String newModuleKey = computeNewKey(oldModuleKey, stringToReplace, replacementString);
Collection<ResourceDto> resources = Lists.newArrayList(module);
resources.addAll(allResourcesByModuleMap.get(module));
- runBatchUpdateForAllResources(resources, oldModuleKey, newModuleKey, mapper);
+ runBatchUpdateForAllResources(resources, oldModuleKey, newModuleKey, mapper,
+ (resource, oldKey) -> {
+ RekeyedResource rekeyedResource = new RekeyedResource(resource, oldKey);
+ if (rekeyedResourceFilter.test(rekeyedResource)) {
+ rekeyedResources.add(rekeyedResource);
+ }
+ });
}
+ return rekeyedResources;
}
private static String branchBaseKey(String key) {
return key;
}
- private static void runBatchUpdateForAllResources(Collection<ResourceDto> resources, String oldKey, String newKey, ComponentKeyUpdaterMapper mapper) {
+ private static void runBatchUpdateForAllResources(Collection<ResourceDto> resources, String oldKey, String newKey, ComponentKeyUpdaterMapper mapper,
+ @Nullable BiConsumer<ResourceDto, String> consumer) {
for (ResourceDto resource : resources) {
String oldResourceKey = resource.getKey();
String newResourceKey = newKey + oldResourceKey.substring(oldKey.length(), oldResourceKey.length());
resource.setDeprecatedKey(newResourceDeprecatedKey);
}
mapper.update(resource);
+ if (consumer != null) {
+ consumer.accept(resource, oldResourceKey);
+ }
+ }
+ }
+
+ public static final class RekeyedResource {
+ private final ResourceDto resource;
+ private final String oldKey;
+
+ public RekeyedResource(ResourceDto resource, String oldKey) {
+ this.resource = resource;
+ this.oldKey = oldKey;
+ }
+
+ public ResourceDto getResource() {
+ return resource;
+ }
+
+ public String getOldKey() {
+ return oldKey;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ RekeyedResource that = (RekeyedResource) o;
+ return Objects.equals(resource.getUuid(), that.resource.getUuid());
+ }
+
+ @Override
+ public int hashCode() {
+ return resource.getUuid().hashCode();
}
}
import com.google.common.base.Strings;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentKeyUpdaterDao.RekeyedResource;
import org.sonar.db.organization.OrganizationDto;
import static com.google.common.collect.Lists.newArrayList;
ComponentDto project = db.components().insertMainBranch();
ComponentDto branch = db.components().insertProjectBranch(project);
ComponentDto module = db.components().insertComponent(prefixDbKeyWithKey(newModuleDto(branch), project.getKey()));
- db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey()));
- db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey()));
+ ComponentDto file1 = db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey()));
+ ComponentDto file2 = db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey()));
int branchComponentCount = 4;
String oldProjectKey = project.getKey();
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldBranchKey)).hasSize(branchComponentCount);
String newProjectKey = "newKey";
- String newBranchKey = ComponentDto.generateBranchKey(newProjectKey, branch.getBranch());
- underTest.bulkUpdateKey(dbSession, project.uuid(), oldProjectKey, newProjectKey);
+ Set<RekeyedResource> rekeyedResources = underTest.bulkUpdateKey(dbSession, project.uuid(), oldProjectKey, newProjectKey, a -> true);
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldProjectKey)).isEmpty();
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldBranchKey)).isEmpty();
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, newProjectKey)).hasSize(1);
+ String newBranchKey = ComponentDto.generateBranchKey(newProjectKey, branch.getBranch());
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, newBranchKey)).hasSize(branchComponentCount);
db.select(dbSession, "select kee from projects")
.forEach(map -> map.values().forEach(k -> assertThat(k.toString()).startsWith(newProjectKey)));
+
+ assertThat(rekeyedResources)
+ .extracting(t -> t.getResource().getUuid())
+ .containsOnly(project.uuid(), branch.uuid(), module.uuid(), file1.uuid(), file2.uuid());
+ assertThat(rekeyedResources)
+ .extracting(t -> t.getResource().getKey())
+ .allMatch(t -> t.startsWith(newProjectKey));
+ assertThat(rekeyedResources)
+ .extracting(RekeyedResource::getOldKey)
+ .allMatch(t -> t.startsWith(oldProjectKey));
}
@Test
ComponentDto branch = db.components().insertProjectBranch(project, b -> b.setKey("branch/with/slash"));
String newKey = "newKey";
- underTest.bulkUpdateKey(dbSession, project.uuid(), project.getKey(), newKey);
+ underTest.bulkUpdateKey(dbSession, project.uuid(), project.getKey(), newKey, t -> true);
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, newKey)).hasSize(1);
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, ComponentDto.generateBranchKey(newKey, branch.getBranch()))).hasSize(1);
ComponentDto project = db.components().insertMainBranch();
ComponentDto pullRequest = db.components().insertProjectBranch(project, b -> b.setBranchType(PULL_REQUEST));
ComponentDto module = db.components().insertComponent(prefixDbKeyWithKey(newModuleDto(pullRequest), project.getKey()));
- db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey()));
- db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey()));
+ ComponentDto file1 = db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey()));
+ ComponentDto file2 = db.components().insertComponent(prefixDbKeyWithKey(newFileDto(module), module.getKey()));
int branchComponentCount = 4;
String oldProjectKey = project.getKey();
String newProjectKey = "newKey";
String newPullRequestKey = ComponentDto.generatePullRequestKey(newProjectKey, pullRequest.getPullRequest());
- underTest.bulkUpdateKey(dbSession, project.uuid(), oldProjectKey, newProjectKey);
+ Set<RekeyedResource> rekeyedResources = underTest.bulkUpdateKey(dbSession, project.uuid(), oldProjectKey, newProjectKey, t -> true);
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldProjectKey)).isEmpty();
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, oldPullRequestKey)).isEmpty();
assertThat(dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, newPullRequestKey)).hasSize(branchComponentCount);
db.select(dbSession, "select kee from projects")
.forEach(map -> map.values().forEach(k -> assertThat(k.toString()).startsWith(newProjectKey)));
+
+ assertThat(rekeyedResources)
+ .extracting(t -> t.getResource().getUuid())
+ .containsOnly(project.uuid(), pullRequest.uuid(), module.uuid(), file1.uuid(), file2.uuid());
+ assertThat(rekeyedResources)
+ .extracting(t -> t.getResource().getKey())
+ .allMatch(t -> t.startsWith(newProjectKey));
+ assertThat(rekeyedResources)
+ .extracting(RekeyedResource::getOldKey)
+ .allMatch(t -> t.startsWith(oldProjectKey));
}
private ComponentDto prefixDbKeyWithKey(ComponentDto componentDto, String key) {
db.components().insertComponent(newModuleDto(project).setDbKey("my_project:module"));
db.components().insertComponent(newModuleDto(project).setDbKey("my_project:inactive_module").setEnabled(false));
- underTest.bulkUpdateKey(dbSession, "A", "my_", "your_");
+ Set<RekeyedResource> rekeyedResources = underTest.bulkUpdateKey(dbSession, "A", "my_", "your_", doNotReturnAnyRekeyedResource());
List<ComponentDto> result = dbClient.componentDao().selectAllComponentsFromProjectKey(dbSession, "your_project");
assertThat(result)
public void shouldBulkUpdateKey() {
db.prepareDbUnit(getClass(), "shared.xml");
- underTest.bulkUpdateKey(dbSession, "A", "org.struts", "org.apache.struts");
+ underTest.bulkUpdateKey(dbSession, "A", "org.struts", "org.apache.struts", doNotReturnAnyRekeyedResource());
dbSession.commit();
db.assertDbUnit(getClass(), "shouldBulkUpdateKey-result.xml", "projects");
public void shouldBulkUpdateKeyOnOnlyOneSubmodule() {
db.prepareDbUnit(getClass(), "shared.xml");
- underTest.bulkUpdateKey(dbSession, "A", "struts-ui", "struts-web");
+ underTest.bulkUpdateKey(dbSession, "A", "struts-ui", "struts-web", doNotReturnAnyRekeyedResource());
dbSession.commit();
db.assertDbUnit(getClass(), "shouldBulkUpdateKeyOnOnlyOneSubmodule-result.xml", "projects");
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Impossible to update key: a component with key \"foo:struts-core\" already exists.");
- underTest.bulkUpdateKey(dbSession, "A", "org.struts", "foo");
+ underTest.bulkUpdateKey(dbSession, "A", "org.struts", "foo", doNotReturnAnyRekeyedResource());
dbSession.commit();
}
public void shouldNotUpdateAllSubmodules() {
db.prepareDbUnit(getClass(), "shouldNotUpdateAllSubmodules.xml");
- underTest.bulkUpdateKey(dbSession, "A", "org.struts", "org.apache.struts");
+ underTest.bulkUpdateKey(dbSession, "A", "org.struts", "org.apache.struts", doNotReturnAnyRekeyedResource());
dbSession.commit();
db.assertDbUnit(getClass(), "shouldNotUpdateAllSubmodules-result.xml", "projects");
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Malformed key for 'my?project?key'. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.");
- underTest.bulkUpdateKey(dbSession, project.uuid(), project.getDbKey(), "my?project?key");
+ underTest.bulkUpdateKey(dbSession, project.uuid(), project.getDbKey(), "my?project?key", doNotReturnAnyRekeyedResource());
}
@Test
assertThat(computeNewKey("my_project", "my_", "your_")).isEqualTo("your_project");
assertThat(computeNewKey("my_project", "my_", "$()_")).isEqualTo("$()_project");
}
+
+ private Predicate<RekeyedResource> doNotReturnAnyRekeyedResource() {
+ return a -> false;
+ }
}
*/
package org.sonar.server.component;
+import java.util.Set;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.Scopes;
import org.sonar.api.server.ServerSide;
import org.sonar.api.web.UserRole;
+import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentKeyUpdaterDao;
+import org.sonar.db.component.ResourceDto;
import org.sonar.server.es.ProjectIndexer;
import org.sonar.server.es.ProjectIndexers;
import org.sonar.server.project.Project;
import org.sonar.server.project.RekeyedProject;
import org.sonar.server.user.UserSession;
+import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static org.sonar.core.component.ComponentKeys.isValidModuleKey;
import static org.sonar.db.component.ComponentKeyUpdaterDao.checkIsProjectOrModule;
checkProjectOrModuleKeyFormat(newKey);
dbClient.componentKeyUpdaterDao().updateKey(dbSession, projectOrModule.uuid(), newKey);
projectIndexers.commitAndIndex(dbSession, singletonList(projectOrModule), ProjectIndexer.Cause.PROJECT_KEY_UPDATE);
- if (projectOrModule.isRootProject() && projectOrModule.getMainBranchProjectUuid() == null) {
+ if (isMainProject(projectOrModule)) {
Project newProject = new Project(projectOrModule.uuid(), newKey, projectOrModule.name(), projectOrModule.description());
- projectLifeCycleListeners.onProjectRekeyed(new RekeyedProject(newProject, projectOrModule.getDbKey()));
+ projectLifeCycleListeners.onProjectsRekeyed(singleton(new RekeyedProject(newProject, projectOrModule.getDbKey())));
}
}
+ private static boolean isMainProject(ComponentDto projectOrModule) {
+ return projectOrModule.isRootProject() && projectOrModule.getMainBranchProjectUuid() == null;
+ }
+
public void bulkUpdateKey(DbSession dbSession, ComponentDto projectOrModule, String stringToReplace, String replacementString) {
- dbClient.componentKeyUpdaterDao().bulkUpdateKey(dbSession, projectOrModule.uuid(), stringToReplace, replacementString);
+ Set<ComponentKeyUpdaterDao.RekeyedResource> rekeyedProjects = dbClient.componentKeyUpdaterDao().bulkUpdateKey(
+ dbSession, projectOrModule.uuid(), stringToReplace, replacementString,
+ ComponentService::isMainProject);
projectIndexers.commitAndIndex(dbSession, singletonList(projectOrModule), ProjectIndexer.Cause.PROJECT_KEY_UPDATE);
+ if (!rekeyedProjects.isEmpty()) {
+ projectLifeCycleListeners.onProjectsRekeyed(rekeyedProjects.stream()
+ .map(ComponentService::toRekeyedProject)
+ .collect(MoreCollectors.toSet(rekeyedProjects.size())));
+ }
+ }
+
+ private static boolean isMainProject(ComponentKeyUpdaterDao.RekeyedResource rekeyedResource) {
+ ResourceDto resource = rekeyedResource.getResource();
+ String resourceKey = resource.getKey();
+ return Scopes.PROJECT.equals(resource.getScope())
+ && Qualifiers.PROJECT.equals(resource.getQualifier())
+ && !resourceKey.contains(ComponentDto.BRANCH_KEY_SEPARATOR)
+ && !resourceKey.contains(ComponentDto.PULL_REQUEST_SEPARATOR);
+ }
+
+ private static RekeyedProject toRekeyedProject(ComponentKeyUpdaterDao.RekeyedResource rekeyedResource) {
+ ResourceDto resource = rekeyedResource.getResource();
+ Project project = new Project(resource.getUuid(), resource.getKey(), resource.getName(), resource.getDescription());
+ return new RekeyedProject(project, rekeyedResource.getOldKey());
}
private static void checkProjectOrModuleKeyFormat(String key) {
void onProjectsDeleted(Set<Project> projects);
/**
- * This method is called after the specified project's key has been modified.
+ * This method is called after the specified projects' keys have been modified.
*/
- void onProjectRekeyed(RekeyedProject rekeyedProject);
+ void onProjectsRekeyed(Set<RekeyedProject> rekeyedProjects);
}
/**
* This method is called after the specified project's key has been changed and will call method
- * {@link ProjectLifeCycleListener#onProjectRekeyed(RekeyedProject) onProjectRekeyed(RekeyedProject)} of all known
+ * {@link ProjectLifeCycleListener#onProjectsRekeyed(Set) onProjectsRekeyed(Set)} of all known
* {@link ProjectLifeCycleListener} implementations.
* <p>
* This method ensures all {@link ProjectLifeCycleListener} implementations are called, even if one or more of
* them fail with an exception.
*/
- void onProjectRekeyed(RekeyedProject rekeyedProject);
+ void onProjectsRekeyed(Set<RekeyedProject> rekeyedProjects);
}
}
@Override
- public void onProjectRekeyed(RekeyedProject rekeyedProject) {
- checkNotNull(rekeyedProject, "rekeyedProject can't be null");
+ public void onProjectsRekeyed(Set<RekeyedProject> rekeyedProjects) {
+ checkNotNull(rekeyedProjects, "rekeyedProjects can't be null");
+ if (rekeyedProjects.isEmpty()) {
+ return;
+ }
Arrays.stream(listeners)
- .forEach(safelyCallListener(listener -> listener.onProjectRekeyed(rekeyedProject)));
+ .forEach(safelyCallListener(listener -> listener.onProjectsRekeyed(rekeyedProjects)));
}
private static Consumer<ProjectLifeCycleListener> safelyCallListener(Consumer<ProjectLifeCycleListener> task) {
*/
package org.sonar.server.component;
+import com.google.common.collect.ImmutableSet;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.server.es.TestProjectIndexers;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.project.Project;
import org.sonar.server.project.ProjectLifeCycleListeners;
+import org.sonar.server.project.RekeyedProject;
import org.sonar.server.tester.UserSessionRule;
import static org.assertj.guava.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.sonar.db.component.ComponentTesting.newFileDto;
import static org.sonar.db.component.ComponentTesting.newModuleDto;
assertComponentKeyUpdated(file.getDbKey(), "your_project:root:module:src/File.xoo");
assertComponentKeyUpdated(inactiveModule.getDbKey(), "your_project:root:inactive_module");
assertComponentKeyUpdated(inactiveFile.getDbKey(), "your_project:root:module:src/InactiveFile.xoo");
+ verify(projectLifeCycleListeners).onProjectsRekeyed(ImmutableSet.of(
+ new RekeyedProject(new Project(project.uuid(), "your_project", project.name(), project.uuid()), "my_project")
+ ));
+ }
+
+ @Test
+ public void bulk_update_key_with_branch_and_pr() {
+ ComponentDto project = componentDb.insertComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert()).setDbKey("my_project"));
+ ComponentDto branch = componentDb.insertProjectBranch(project);
+ ComponentDto module = componentDb.insertComponent(newModuleDto(branch).setDbKey("my_project:root:module"));
+ ComponentDto file = componentDb.insertComponent(newFileDto(module, null).setDbKey("my_project:root:module:src/File.xoo"));
+
+ underTest.bulkUpdateKey(dbSession, project, "my_", "your_");
+
+ assertComponentKeyUpdated(project.getDbKey(), "your_project");
+ assertComponentKeyUpdated(module.getDbKey(), "your_project:root:module");
+ assertComponentKeyUpdated(file.getDbKey(), "your_project:root:module:src/File.xoo");
+ verify(projectLifeCycleListeners).onProjectsRekeyed(ImmutableSet.of(
+ new RekeyedProject(new Project(project.uuid(), "your_project", project.name(), project.uuid()), "my_project")
+ ));
}
private void assertComponentKeyUpdated(String oldKey, String newKey) {
{IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> newUniqueProject()).collect(MoreCollectors.toSet())}
};
}
+ // SDSDS
+
+ @Test
+ public void onProjectsRekeyed_throws_NPE_if_set_is_null() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("rekeyedProjects can't be null");
+
+ underTestWithListeners.onProjectsRekeyed(null);
+ }
+
+ @Test
+ public void onProjectsRekeyed_throws_NPE_if_set_is_null_even_if_no_listeners() {
+ expectedException.expect(NullPointerException.class);
+ expectedException.expectMessage("rekeyedProjects can't be null");
+
+ underTestNoListeners.onProjectsRekeyed(null);
+ }
+
+ @Test
+ public void onProjectsRekeyed_has_no_effect_if_set_is_empty() {
+ underTestNoListeners.onProjectsRekeyed(Collections.emptySet());
+
+ underTestWithListeners.onProjectsRekeyed(Collections.emptySet());
+ verifyZeroInteractions(listener1, listener2, listener3);
+ }
+
+ @Test
+ @UseDataProvider("oneOrManyRekeyedProjects")
+ public void onProjectsRekeyed_does_not_fail_if_there_is_no_listener(Set<RekeyedProject> projects) {
+ underTestNoListeners.onProjectsRekeyed(projects);
+ }
+
+ @Test
+ @UseDataProvider("oneOrManyRekeyedProjects")
+ public void onProjectsRekeyed_calls_all_listeners_in_order_of_addition_to_constructor(Set<RekeyedProject> projects) {
+ InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
+
+ underTestWithListeners.onProjectsRekeyed(projects);
+
+ inOrder.verify(listener1).onProjectsRekeyed(same(projects));
+ inOrder.verify(listener2).onProjectsRekeyed(same(projects));
+ inOrder.verify(listener3).onProjectsRekeyed(same(projects));
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ @UseDataProvider("oneOrManyRekeyedProjects")
+ public void onProjectsRekeyed_calls_all_listeners_even_if_one_throws_an_Exception(Set<RekeyedProject> projects) {
+ InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
+ doThrow(new RuntimeException("Faking listener2 throwing an exception"))
+ .when(listener2)
+ .onProjectsRekeyed(any());
+
+ underTestWithListeners.onProjectsRekeyed(projects);
+
+ inOrder.verify(listener1).onProjectsRekeyed(same(projects));
+ inOrder.verify(listener2).onProjectsRekeyed(same(projects));
+ inOrder.verify(listener3).onProjectsRekeyed(same(projects));
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ @UseDataProvider("oneOrManyRekeyedProjects")
+ public void onProjectsRekeyed_calls_all_listeners_even_if_one_throws_an_Error(Set<RekeyedProject> projects) {
+ InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
+ doThrow(new Error("Faking listener2 throwing an Error"))
+ .when(listener2)
+ .onProjectsRekeyed(any());
+
+ underTestWithListeners.onProjectsRekeyed(projects);
+
+ inOrder.verify(listener1).onProjectsRekeyed(same(projects));
+ inOrder.verify(listener2).onProjectsRekeyed(same(projects));
+ inOrder.verify(listener3).onProjectsRekeyed(same(projects));
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @DataProvider
+ public static Object[][] oneOrManyRekeyedProjects() {
+ return new Object[][] {
+ {singleton(newUniqueRekeyedProject())},
+ {IntStream.range(0, 1 + new Random().nextInt(10)).mapToObj(i -> newUniqueRekeyedProject()).collect(MoreCollectors.toSet())}
+ };
+ }
private static int counter = 3_989;
int base = counter++;
return new Project(base + "_uuid", base + "_key", base + "_name");
}
+
+ private static RekeyedProject newUniqueRekeyedProject() {
+ int base = counter++;
+ Project project = new Project(base + "_uuid", base + "_key", base + "_name");
+ return new RekeyedProject(project, base + "_old_key");
+ }
}
import org.sonar.server.es.ProjectIndexersImpl;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.project.ProjectLifeCycleListenersImpl;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
public UserSessionRule userSessionRule = UserSessionRule.standalone();
private DbClient dbClient = db.getDbClient();
private ProjectIndexers projectIndexers = new ProjectIndexersImpl();
- private ComponentService componentService = new ComponentService(dbClient, userSessionRule, projectIndexers);
+ private ComponentService componentService = new ComponentService(dbClient, userSessionRule, projectIndexers, new ProjectLifeCycleListenersImpl());
private WsActionTester ws = new WsActionTester(new UpdateKeyAction(dbClient, componentService));
@Test