diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryRenamedEvent.java b/scm-core/src/main/java/sonia/scm/repository/ChangeNamespaceNotAllowedException.java similarity index 72% rename from scm-core/src/main/java/sonia/scm/repository/RepositoryRenamedEvent.java rename to scm-core/src/main/java/sonia/scm/repository/ChangeNamespaceNotAllowedException.java index 4c68b6b332..783761e5ff 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryRenamedEvent.java +++ b/scm-core/src/main/java/sonia/scm/repository/ChangeNamespaceNotAllowedException.java @@ -24,14 +24,19 @@ package sonia.scm.repository; -import sonia.scm.HandlerEventType; -import sonia.scm.event.AbstractHandlerEvent; -import sonia.scm.event.Event; +import sonia.scm.BadRequestException; +import sonia.scm.ContextEntry; -@Event -public class RepositoryRenamedEvent extends AbstractHandlerEvent { +public class ChangeNamespaceNotAllowedException extends BadRequestException { - public RepositoryRenamedEvent(HandlerEventType eventType, Repository item, Repository oldItem) { - super(eventType, item, oldItem); + public ChangeNamespaceNotAllowedException(Repository repository) { + super(ContextEntry.ContextBuilder.entity(repository).build(), "change of namespace is not allowed in current namespace strategy"); + } + + private static final String CODE = "ERS2vYb7U1"; + + @Override + public String getCode() { + return CODE; } } diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java index b05a8fd01f..7269b3517f 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryManager.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- @@ -38,18 +38,15 @@ import java.util.Collection; * This class is a singleton and is available via injection. * * @author Sebastian Sdorra - * * @apiviz.uses sonia.scm.repository.RepositoryHandler */ public interface RepositoryManager - extends TypeManager -{ + extends TypeManager { /** * Fire {@link RepositoryHookEvent} to the event bus. * * @param event hook event - * * @since 2.0.0 */ public void fireHookEvent(RepositoryHookEvent event); @@ -58,9 +55,7 @@ public interface RepositoryManager * Imports an existing {@link Repository}. * Note: This method should only be called from a {@link RepositoryHandler}. * - * * @param repository {@link Repository} to import - * * @throws IOException */ public void importRepository(Repository repository) throws IOException; @@ -71,10 +66,7 @@ public interface RepositoryManager * Returns a {@link Repository} by its namespace and name or * null if the {@link Repository} could not be found. * - * * @param namespaceAndName namespace and name of the {@link Repository} - * - * * @return {@link Repository} by its namespace and name or null * if the {@link Repository} could not be found */ @@ -83,7 +75,6 @@ public interface RepositoryManager /** * Returns all configured repository types. * - * * @return all configured repository types */ public Collection getConfiguredTypes(); @@ -91,11 +82,17 @@ public interface RepositoryManager /** * Returns a {@link RepositoryHandler} by the given type (hg, git, svn ...). * - * * @param type the type of the {@link RepositoryHandler} - * * @return {@link RepositoryHandler} by the given type */ @Override public RepositoryHandler getHandler(String type); + + /** + * @param repository the repository {@link Repository} + * @param newNameSpace the new repository namespace + * @param newName the new repository name + * @return {@link Repository} the renamed repository + */ + public Repository rename(Repository repository, String newNameSpace, String newName); } diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryManagerDecorator.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryManagerDecorator.java index fa45106ab9..fdb8dfc1a8 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryManagerDecorator.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryManagerDecorator.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- @@ -42,17 +42,14 @@ import java.util.Collection; */ public class RepositoryManagerDecorator extends ManagerDecorator - implements RepositoryManager -{ + implements RepositoryManager { /** * Constructs ... * - * * @param decorated */ - public RepositoryManagerDecorator(RepositoryManager decorated) - { + public RepositoryManagerDecorator(RepositoryManager decorated) { super(decorated); this.decorated = decorated; } @@ -63,8 +60,7 @@ public class RepositoryManagerDecorator * {@inheritDoc} */ @Override - public void fireHookEvent(RepositoryHookEvent event) - { + public void fireHookEvent(RepositoryHookEvent event) { decorated.fireHookEvent(event); } @@ -79,65 +75,66 @@ public class RepositoryManagerDecorator //~--- get methods ---------------------------------------------------------- @Override - public Repository get(NamespaceAndName namespaceAndName) - { + public Repository get(NamespaceAndName namespaceAndName) { return decorated.get(namespaceAndName); } /** * {@inheritDoc} * - * * @return */ @Override - public Collection getConfiguredTypes() - { + public Collection getConfiguredTypes() { return decorated.getConfiguredTypes(); } /** * Returns the decorated {@link RepositoryManager}. * - * * @return decorated {@link RepositoryManager} - * * @since 1.34 */ - public RepositoryManager getDecorated() - { + public RepositoryManager getDecorated() { return decorated; } /** * {@inheritDoc} * - * * @param type - * * @return */ @Override @SuppressWarnings("unchecked") - public RepositoryHandler getHandler(String type) - { + public RepositoryHandler getHandler(String type) { return decorated.getHandler(type); } /** * {@inheritDoc} * + * @return + */ + @Override + public Collection getTypes() { + return decorated.getTypes(); + } + + /** + * {@inheritDoc} * * @return */ @Override - public Collection getTypes() - { - return decorated.getTypes(); + public Repository rename(Repository repository, String newNamespace, String newName) { + return decorated.rename(repository, newNamespace, newName); } //~--- fields --------------------------------------------------------------- - /** Field description */ + /** + * Field description + */ private final RepositoryManager decorated; } diff --git a/scm-core/src/main/java/sonia/scm/repository/RepositoryModificationEvent.java b/scm-core/src/main/java/sonia/scm/repository/RepositoryModificationEvent.java index c61bbd2f03..8b199622d4 100644 --- a/scm-core/src/main/java/sonia/scm/repository/RepositoryModificationEvent.java +++ b/scm-core/src/main/java/sonia/scm/repository/RepositoryModificationEvent.java @@ -49,7 +49,7 @@ public final class RepositoryModificationEvent extends RepositoryEvent implement */ public RepositoryModificationEvent(HandlerEventType eventType, Repository item, Repository itemBeforeModification) { - super(eventType, item); + super(eventType, item, itemBeforeModification); this.itemBeforeModification = itemBeforeModification; } diff --git a/scm-ui/ui-webapp/src/repos/containers/EditRepo.tsx b/scm-ui/ui-webapp/src/repos/containers/EditRepo.tsx index a919423fa4..7b6a71b51c 100644 --- a/scm-ui/ui-webapp/src/repos/containers/EditRepo.tsx +++ b/scm-ui/ui-webapp/src/repos/containers/EditRepo.tsx @@ -116,4 +116,4 @@ const mapDispatchToProps = (dispatch: any) => { }; }; -export default compose(connect(mapStateToProps, mapDispatchToProps))(withRouter(EditRepo)); +export default compose(connect(mapStateToProps, mapDispatchToProps), withRouter)(EditRepo); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java index f551e08988..12cc362517 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/RepositoryResource.java @@ -24,19 +24,13 @@ package sonia.scm.api.v2.resources; -import com.google.common.base.Strings; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import sonia.scm.HandlerEventType; -import sonia.scm.config.ScmConfiguration; -import sonia.scm.event.ScmEventBus; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryManager; -import sonia.scm.repository.RepositoryPermissions; -import sonia.scm.repository.RepositoryRenamedEvent; import sonia.scm.web.VndMediaType; import javax.inject.Inject; @@ -65,22 +59,17 @@ public class RepositoryResource { private final RepositoryManager manager; private final SingleResourceManagerAdapter adapter; private final RepositoryBasedResourceProvider resourceProvider; - private final ScmConfiguration scmConfiguration; - private final ScmEventBus scmEventBus; @Inject public RepositoryResource( RepositoryToRepositoryDtoMapper repositoryToDtoMapper, RepositoryDtoToRepositoryMapper dtoToRepositoryMapper, RepositoryManager manager, - RepositoryBasedResourceProvider resourceProvider, - ScmConfiguration scmConfiguration, ScmEventBus scmEventBus) { + RepositoryBasedResourceProvider resourceProvider) { this.dtoToRepositoryMapper = dtoToRepositoryMapper; this.manager = manager; this.repositoryToDtoMapper = repositoryToDtoMapper; this.adapter = new SingleResourceManagerAdapter<>(manager, Repository.class); this.resourceProvider = resourceProvider; - this.scmConfiguration = scmConfiguration; - this.scmEventBus = scmEventBus; } /** @@ -210,48 +199,11 @@ public class RepositoryResource { )) @ApiResponse(responseCode = "500", description = "internal server error") public Response rename(@PathParam("namespace") String namespace, @PathParam("name") String name, @Valid RepositoryRenameDto renameDto) { - Supplier repoSupplier = loadBy(namespace, name); - Repository unchangedRepo = repoSupplier.get(); - Repository changedRepo = unchangedRepo.clone(); - - if (isRenameForbidden(unchangedRepo, renameDto)) { - return Response.status(403).build(); - } - - if (hasNamespaceOrNameNotChanged(unchangedRepo, renameDto)) { - return Response.status(400).build(); - } - - if (!Strings.isNullOrEmpty(renameDto.getName())) { - changedRepo.setName(renameDto.getName()); - } - if (!Strings.isNullOrEmpty(renameDto.getNamespace())) { - changedRepo.setNamespace(renameDto.getNamespace()); - } - - return adapter.update( - repoSupplier, - existing -> { - scmEventBus.post(new RepositoryRenamedEvent(HandlerEventType.MODIFY, changedRepo, unchangedRepo)); - return changedRepo; - }, - changed -> true, - r -> r.getNamespaceAndName().logString() - ); + Repository repository = loadBy(namespace, name).get(); + manager.rename(repository, renameDto.getNamespace(), renameDto.getName()); + return Response.status(204).build(); } - private boolean hasNamespaceOrNameNotChanged(Repository repo, @Valid RepositoryRenameDto renameDto) { - return repo.getName().equals(renameDto.getName()) - && repo.getNamespace().equals(renameDto.getNamespace()); - } - - private boolean isRenameForbidden(Repository repo, RepositoryRenameDto renameDto) { - return !scmConfiguration.getNamespaceStrategy().equals("CustomNamespaceStrategy") - && !repo.getNamespace().equals(renameDto.getNamespace()) - || !RepositoryPermissions.rename(repo).isPermitted(); - } - - private Repository processUpdate(RepositoryDto repositoryDto, Repository existing) { Repository changedRepository = dtoToRepositoryMapper.map(repositoryDto, existing.getId()); changedRepository.setPermissions(existing.getPermissions()); diff --git a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java index 285edc501f..db09d23e79 100644 --- a/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java +++ b/scm-webapp/src/main/java/sonia/scm/repository/DefaultRepositoryManager.java @@ -21,10 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository; import com.github.sdorra.ssp.PermissionActionCheck; +import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.inject.Inject; @@ -35,6 +36,7 @@ import org.slf4j.LoggerFactory; import sonia.scm.ConfigurationException; import sonia.scm.HandlerEventType; import sonia.scm.ManagerDaoAdapter; +import sonia.scm.NoChangesMadeException; import sonia.scm.NotFoundException; import sonia.scm.SCMContextProvider; import sonia.scm.Type; @@ -83,7 +85,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager { private final Provider namespaceStrategyProvider; private final ManagerDaoAdapter managerDaoAdapter; - @Inject public DefaultRepositoryManager(ScmConfiguration configuration, SCMContextProvider contextProvider, KeyGenerator keyGenerator, @@ -154,7 +155,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager { } @Override - public void delete(Repository repository){ + public void delete(Repository repository) { logger.info("delete repository {}/{} of type {}", repository.getNamespace(), repository.getName(), repository.getType()); managerDaoAdapter.delete( repository, @@ -179,7 +180,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager { } @Override - public void modify(Repository repository){ + public void modify(Repository repository) { logger.info("modify repository {}/{} of type {}", repository.getNamespace(), repository.getName(), repository.getType()); managerDaoAdapter.modify( @@ -243,6 +244,40 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager { return repository; } + public Repository rename(Repository repository, String newNamespace, String newName) { + + if (!configuration.getNamespaceStrategy().equals("CustomNamespaceStrategy") + && !repository.getNamespace().equals(newNamespace)) { + throw new ChangeNamespaceNotAllowedException(repository); + } + + if (hasNamespaceOrNameNotChanged(repository, newNamespace, newName)) { + throw new NoChangesMadeException(repository); + } + + Repository changedRepository = repository.clone(); + if (!Strings.isNullOrEmpty(newName)) { + changedRepository.setName(newName); + } + if (!Strings.isNullOrEmpty(newNamespace)) { + changedRepository.setNamespace(newNamespace); + } + + managerDaoAdapter.modify( + changedRepository, + RepositoryPermissions::rename, + notModified -> { + }, + notModified -> fireEvent(HandlerEventType.MODIFY, changedRepository, repository)); + + return changedRepository; + } + + private boolean hasNamespaceOrNameNotChanged(Repository repository, String newNamespace, String newName) { + return repository.getName().equals(newName) + && repository.getNamespace().equals(newNamespace); + } + @Override public Collection getAll(Predicate filter, Comparator comparator) { List repositories = Lists.newArrayList(); @@ -345,8 +380,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager { types.add(type); } - private RepositoryHandler getHandler(Repository repository) - { + private RepositoryHandler getHandler(Repository repository) { String type = repository.getType(); RepositoryHandler handler = handlerMap.get(type); diff --git a/scm-webapp/src/main/resources/locales/de/plugins.json b/scm-webapp/src/main/resources/locales/de/plugins.json index c6875c5f3b..eb9e390497 100644 --- a/scm-webapp/src/main/resources/locales/de/plugins.json +++ b/scm-webapp/src/main/resources/locales/de/plugins.json @@ -191,6 +191,10 @@ "displayName": "Es wurden keine Änderungen durchgeführt", "description": "Das Repository wurde nicht verändert. Daher konnte kein neuer Commit erzeugt werden. Womöglich werden Änderungen aufgrund einer .ignore-Datei Definition nicht berücksichtigt." }, + "ERS2vYb7U1": { + "displayName": "Änderung des Namespace nicht möglich", + "description": "Namespaces dürfen nur mit der Namespace Strategie \"Benutzerdefiniert\" verändert werden." + }, "4iRct4avG1": { "displayName": "Die Revisionen haben keinen gemeinsamen Ursprung", "description": "Die Historie der Revisionen hat keinen gemeinsamen Urspung und kann somit auch nicht gegen einen solchen verglichen werden." diff --git a/scm-webapp/src/main/resources/locales/en/plugins.json b/scm-webapp/src/main/resources/locales/en/plugins.json index 85e21aaaba..8a897f82ff 100644 --- a/scm-webapp/src/main/resources/locales/en/plugins.json +++ b/scm-webapp/src/main/resources/locales/en/plugins.json @@ -197,6 +197,10 @@ "displayName": "No changes were made", "description": "No changes were made to the files of the repository. Therefor no new commit could be created. Possibly changes cannot be applied due to an .ignore-File definition." }, + "ERS2vYb7U1": { + "displayName": "Illegal change of namespace", + "description": "Namespaces can only be changed if namespace strategy is \"custom\"." + }, "4iRct4avG1": { "displayName": "The revisions have unrelated histories", "description": "The revisions have unrelated histories. Therefor there is no common commit to compare with." diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java index 5c99939fc5..a6b34b3fc4 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryRootResourceTest.java @@ -27,7 +27,6 @@ package sonia.scm.api.v2.resources; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.common.io.Resources; -import com.google.inject.util.Providers; import org.apache.shiro.subject.SimplePrincipalCollection; import org.apache.shiro.subject.Subject; import org.jboss.resteasy.mock.MockHttpRequest; @@ -35,19 +34,16 @@ import org.jboss.resteasy.mock.MockHttpResponse; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.jupiter.api.Nested; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import sonia.scm.PageResult; import sonia.scm.config.ScmConfiguration; -import sonia.scm.event.ScmEventBus; import sonia.scm.repository.NamespaceAndName; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryInitializer; import sonia.scm.repository.RepositoryManager; -import sonia.scm.repository.RepositoryRenamedEvent; import sonia.scm.repository.api.RepositoryService; import sonia.scm.repository.api.RepositoryServiceFactory; import sonia.scm.user.User; @@ -66,7 +62,6 @@ import static java.util.Collections.singletonList; import static java.util.stream.Stream.of; import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; import static javax.servlet.http.HttpServletResponse.SC_CONFLICT; -import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN; import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT; import static javax.servlet.http.HttpServletResponse.SC_OK; @@ -109,9 +104,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { @Mock private RepositoryInitializer repositoryInitializer; @Mock - private ScmConfiguration scmConfiguration; - @Mock - private ScmEventBus scmEventBus; + private ScmConfiguration configuration; @Captor private ArgumentCaptor> filterCaptor; @@ -130,14 +123,11 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { super.repositoryToDtoMapper = repositoryToDtoMapper; super.dtoToRepositoryMapper = dtoToRepositoryMapper; super.manager = repositoryManager; - super.scmConfiguration = scmConfiguration; - super.scmEventBus = scmEventBus; RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks); super.repositoryCollectionResource = new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper, dtoToRepositoryMapper, resourceLinks, repositoryInitializer); dispatcher.addSingletonResource(getRepositoryRootResource()); when(serviceFactory.create(any(Repository.class))).thenReturn(service); when(scmPathInfoStore.get()).thenReturn(uriInfo); - when(scmConfiguration.getNamespaceStrategy()).thenReturn("CustomNamespaceStrategy"); when(uriInfo.getApiRestUri()).thenReturn(URI.create("/x/y")); SimplePrincipalCollection trillian = new SimplePrincipalCollection("trillian", REALM); trillian.add(new User("trillian"), REALM); @@ -164,6 +154,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { @Test public void shouldFindExistingRepository() throws URISyntaxException, UnsupportedEncodingException { mockRepository("space", "repo"); + when(configuration.getNamespaceStrategy()).thenReturn("CustomNamespaceStrategy"); MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo"); MockHttpResponse response = new MockHttpResponse(); @@ -178,6 +169,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { public void shouldGetAll() throws URISyntaxException, UnsupportedEncodingException { PageResult singletonPageResult = createSingletonPageResult(mockRepository("space", "repo")); when(repositoryManager.getPage(any(), any(), eq(0), eq(10))).thenReturn(singletonPageResult); + when(configuration.getNamespaceStrategy()).thenReturn("CustomNamespaceStrategy"); MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2); MockHttpResponse response = new MockHttpResponse(); @@ -192,6 +184,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { public void shouldCreateFilterForSearch() throws URISyntaxException { PageResult singletonPageResult = createSingletonPageResult(mockRepository("space", "repo")); when(repositoryManager.getPage(filterCaptor.capture(), any(), eq(0), eq(10))).thenReturn(singletonPageResult); + when(configuration.getNamespaceStrategy()).thenReturn("CustomNamespaceStrategy"); MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "?q=Rep"); MockHttpResponse response = new MockHttpResponse(); @@ -374,6 +367,7 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { public void shouldCreateArrayOfProtocolUrls() throws Exception { mockRepository("space", "repo"); when(service.getSupportedProtocols()).thenReturn(of(new MockScmProtocol("http", "http://"), new MockScmProtocol("ssh", "ssh://"))); + when(configuration.getNamespaceStrategy()).thenReturn("CustomNamespaceStrategy"); MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo"); MockHttpResponse response = new MockHttpResponse(); @@ -384,48 +378,12 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { assertTrue(response.getContentAsString().contains("\"protocol\":[{\"href\":\"http://\",\"name\":\"http\"},{\"href\":\"ssh://\",\"name\":\"ssh\"}]")); } - @Test - public void shouldNotRenameRepositoryNamespaceIfNamespaceStrategyIsNotCustom() throws Exception { - mockRepository("hitchhiker", "heart-of-gold"); - when(scmConfiguration.getNamespaceStrategy()).thenReturn("UsernameNamespaceStrategy"); - - URL url = Resources.getResource("sonia/scm/api/v2/rename-repo.json"); - byte[] repository = Resources.toByteArray(url); - - MockHttpRequest request = MockHttpRequest - .post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "hitchhiker/heart-of-gold/rename") - .contentType(VndMediaType.REPOSITORY) - .content(repository); - MockHttpResponse response = new MockHttpResponse(); - - dispatcher.invoke(request, response); - - assertEquals(SC_FORBIDDEN, response.getStatus()); - } - - @Test - public void shouldNotRenameRepositoryIfNamespaceAndNameDidNotChanged() throws Exception { - mockRepository("space", "x"); - when(scmConfiguration.getNamespaceStrategy()).thenReturn("CustomNamespaceStrategy"); - - URL url = Resources.getResource("sonia/scm/api/v2/rename-repo.json"); - byte[] repository = Resources.toByteArray(url); - - MockHttpRequest request = MockHttpRequest - .post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/x/rename") - .contentType(VndMediaType.REPOSITORY) - .content(repository); - MockHttpResponse response = new MockHttpResponse(); - - dispatcher.invoke(request, response); - - assertEquals(SC_BAD_REQUEST, response.getStatus()); - } - @Test public void shouldRenameRepository() throws Exception { - mockRepository("space", "repo"); - when(scmConfiguration.getNamespaceStrategy()).thenReturn("CustomNamespaceStrategy"); + String namespace = "space"; + String name = "repo"; + Repository repository1 = mockRepository(namespace, name); + when(manager.get(new NamespaceAndName(namespace, name))).thenReturn(repository1); URL url = Resources.getResource("sonia/scm/api/v2/rename-repo.json"); byte[] repository = Resources.toByteArray(url); @@ -439,31 +397,9 @@ public class RepositoryRootResourceTest extends RepositoryTestBase { dispatcher.invoke(request, response); assertEquals(SC_NO_CONTENT, response.getStatus()); - verify(repositoryManager).modify(any(Repository.class)); - verify(scmEventBus).post(any(RepositoryRenamedEvent.class)); + verify(repositoryManager).rename(repository1, "space", "x"); } - @Test - public void shouldRenameRepositoryNameIfNamespaceStrategyNotCustom() throws Exception { - mockRepository("space", "repo"); - when(scmConfiguration.getNamespaceStrategy()).thenReturn("UsernameNamespaceStrategy"); - - URL url = Resources.getResource("sonia/scm/api/v2/rename-repo.json"); - byte[] repository = Resources.toByteArray(url); - - MockHttpRequest request = MockHttpRequest - .post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/rename") - .contentType(VndMediaType.REPOSITORY) - .content(repository); - MockHttpResponse response = new MockHttpResponse(); - - dispatcher.invoke(request, response); - - assertEquals(SC_NO_CONTENT, response.getStatus()); - verify(repositoryManager).modify(any(Repository.class)); - } - - private PageResult createSingletonPageResult(Repository repository) { return new PageResult<>(singletonList(repository), 0); } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java index ee5d4b2c42..58ec1ffb86 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/RepositoryTestBase.java @@ -24,12 +24,9 @@ package sonia.scm.api.v2.resources; -import sonia.scm.config.ScmConfiguration; -import sonia.scm.event.ScmEventBus; import sonia.scm.repository.RepositoryManager; import static com.google.inject.util.Providers.of; -import static org.mockito.Mockito.mock; abstract class RepositoryTestBase { @@ -48,9 +45,6 @@ abstract class RepositoryTestBase { IncomingRootResource incomingRootResource; RepositoryCollectionResource repositoryCollectionResource; AnnotateResource annotateResource; - ScmConfiguration scmConfiguration; - ScmEventBus scmEventBus; - RepositoryRootResource getRepositoryRootResource() { RepositoryBasedResourceProvider repositoryBasedResourceProvider = new RepositoryBasedResourceProvider( @@ -70,8 +64,7 @@ abstract class RepositoryTestBase { repositoryToDtoMapper, dtoToRepositoryMapper, manager, - repositoryBasedResourceProvider, - scmConfiguration, scmEventBus)), + repositoryBasedResourceProvider)), of(repositoryCollectionResource)); } } diff --git a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java index f8c084f167..326b1f59e7 100644 --- a/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java +++ b/scm-webapp/src/test/java/sonia/scm/repository/DefaultRepositoryManagerTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - + package sonia.scm.repository; //~--- non-JDK imports -------------------------------------------------------- @@ -30,7 +30,6 @@ import com.github.legman.Subscribe; import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.SubjectAware; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; import com.google.inject.util.Providers; import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.util.ThreadContext; @@ -44,32 +43,46 @@ import sonia.scm.AlreadyExistsException; import sonia.scm.HandlerEventType; import sonia.scm.Manager; import sonia.scm.ManagerTestBase; +import sonia.scm.NoChangesMadeException; import sonia.scm.NotFoundException; import sonia.scm.SCMContext; import sonia.scm.config.ScmConfiguration; import sonia.scm.event.ScmEventBus; -import sonia.scm.io.DefaultFileSystem; import sonia.scm.repository.api.HookContext; import sonia.scm.repository.api.HookContextFactory; import sonia.scm.repository.api.HookFeature; import sonia.scm.repository.spi.HookContextProvider; -import sonia.scm.repository.xml.PathBasedRepositoryLocationResolver; -import sonia.scm.repository.xml.XmlRepositoryDAO; import sonia.scm.security.DefaultKeyGenerator; import sonia.scm.security.KeyGenerator; import sonia.scm.store.ConfigurationStoreFactory; -import sonia.scm.store.JAXBConfigurationStoreFactory; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.Stack; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; +import static java.util.Collections.emptySet; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.hasProperty; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; //~--- JDK imports ------------------------------------------------------------ @@ -83,447 +96,491 @@ import static org.mockito.Mockito.*; password = "secret", configuration = "classpath:sonia/scm/repository/shiro.ini" ) -public class DefaultRepositoryManagerTest {//extends ManagerTestBase { +public class DefaultRepositoryManagerTest extends ManagerTestBase { + + { + ThreadContext.unbindSubject(); + } + + @Rule + public ShiroRule shiro = new ShiroRule(); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private ScmConfiguration configuration; + + private String mockedNamespace = "default_namespace"; + + @Before + public void initContext() { + ((TempSCMContextProvider) SCMContext.getContext()).setBaseDirectory(temp); + } + + @Test + public void testCreate() { + Repository heartOfGold = createTestRepository(); + Repository dbRepo = manager.get(heartOfGold.getId()); + + assertNotNull(dbRepo); + assertRepositoriesEquals(dbRepo, heartOfGold); + } + + @SubjectAware( + username = "unpriv" + ) + @Test(expected = UnauthorizedException.class) + public void testCreateWithoutPrivileges() { + createTestRepository(); + } + + @Test + public void testCreateExisting() { + createTestRepository(); + thrown.expect(AlreadyExistsException.class); + createTestRepository(); + } + + @Test + public void testDelete() { + delete(manager, createTestRepository()); + } + + @SubjectAware( + username = "unpriv" + ) + @Test(expected = UnauthorizedException.class) + public void testDeleteWithoutPrivileges() { + delete(manager, createTestRepository()); + } + + @Test(expected = NotFoundException.class) + public void testDeleteNotFound() { + manager.delete(createRepositoryWithId()); + } + + @Test + public void testGet() { + Repository heartOfGold = createTestRepository(); + String id = heartOfGold.getId(); + String description = heartOfGold.getDescription(); + + assertNotNull(description); + + // test for reference + heartOfGold.setDescription("prototype ship"); + heartOfGold = manager.get(id); + assertNotNull(heartOfGold); + assertEquals(description, heartOfGold.getDescription()); + } + + @Test + @SubjectAware( + username = "crato" + ) + public void testGetWithoutRequiredPrivileges() { + Repository heartOfGold = RepositoryTestData.createHeartOfGold(); + manager.create(heartOfGold); + + thrown.expect(UnauthorizedException.class); + manager.get(heartOfGold.getId()); + } + + @Test + public void testGetAll() { + Repository heartOfGold = createTestRepository(); + Repository happyVerticalPeopleTransporter = createSecondTestRepository(); + boolean foundHeart = false; + boolean foundTransporter = false; + Collection repositories = manager.getAll(); + + assertNotNull(repositories); + assertFalse(repositories.isEmpty()); + assertTrue(repositories.size() >= 2); + + Repository heartReference = null; + + for (Repository repository : repositories) { + if (repository.getId().equals(heartOfGold.getId())) { + assertRepositoriesEquals(heartOfGold, repository); + foundHeart = true; + heartReference = repository; + } else if (repository.getId().equals(happyVerticalPeopleTransporter.getId())) { + assertRepositoriesEquals(happyVerticalPeopleTransporter, repository); + foundTransporter = true; + } + } + + assertTrue(foundHeart); + assertTrue(foundTransporter); + + // test for reference + assertNotSame(heartOfGold, heartReference); + heartReference.setDescription("prototype ship"); + assertFalse( + heartOfGold.getDescription().equals(heartReference.getDescription())); + } + + @Test + @SuppressWarnings("unchecked") + @SubjectAware(username = "dent") + public void testGetAllWithPermissionsForTwoOrThreeRepos() { + // mock key generator + KeyGenerator keyGenerator = mock(KeyGenerator.class); + Stack keys = new Stack<>(); + keys.push("rateotu"); + keys.push("p42"); + keys.push("hof"); + + when(keyGenerator.createKey()).then((InvocationOnMock invocation) -> { + return keys.pop(); + }); + + // create repository manager + RepositoryManager repositoryManager = createRepositoryManager(keyGenerator); + + // create first test repository + Repository heartOfGold = RepositoryTestData.createHeartOfGold(); + repositoryManager.create(heartOfGold); + assertEquals("hof", heartOfGold.getId()); + + // create second test repository + Repository puzzle42 = RepositoryTestData.create42Puzzle(); + repositoryManager.create(puzzle42); + assertEquals("p42", puzzle42.getId()); + + // create third test repository + Repository restaurant = RepositoryTestData.createRestaurantAtTheEndOfTheUniverse(); + repositoryManager.create(restaurant); + assertEquals("rateotu", restaurant.getId()); + + // assert returned repositories + Collection repositories = repositoryManager.getAll(); + assertEquals(2, repositories.size()); + assertThat(repositories, containsInAnyOrder( + hasProperty("id", is("p42")), + hasProperty("id", is("hof")) + ) + ); + } + + @Test + public void testEvents() { + RepositoryManager repoManager = createManager(); + repoManager.init(contextProvider); + TestListener listener = new TestListener(); + + ScmEventBus.getInstance().register(listener); + + Repository repository = RepositoryTestData.create42Puzzle(); + + repoManager.create(repository); + assertRepositoriesEquals(repository, listener.preRepository); + assertSame(HandlerEventType.BEFORE_CREATE, listener.preEvent); + assertRepositoriesEquals(repository, listener.postRepository); + assertSame(HandlerEventType.CREATE, listener.postEvent); + + repository.setDescription("changed description"); + repoManager.modify(repository); + assertRepositoriesEquals(repository, listener.preRepository); + assertSame(HandlerEventType.BEFORE_MODIFY, listener.preEvent); + assertRepositoriesEquals(repository, listener.postRepository); + assertSame(HandlerEventType.MODIFY, listener.postEvent); + + repoManager.delete(repository); + + assertRepositoriesEquals(repository, listener.preRepository); + assertSame(HandlerEventType.BEFORE_DELETE, listener.preEvent); + assertRepositoriesEquals(repository, listener.postRepository); + assertSame(HandlerEventType.DELETE, listener.postEvent); + } + + @Test + public void testModify() { + Repository heartOfGold = createTestRepository(); + + heartOfGold.setDescription("prototype ship"); + manager.modify(heartOfGold); + + Repository hearReference = manager.get(heartOfGold.getId()); + + assertNotNull(hearReference); + assertEquals(hearReference.getDescription(), "prototype ship"); + } + + @Test + @SubjectAware(username = "crato") + public void testModifyWithoutRequiredPermissions() { + Repository heartOfGold = RepositoryTestData.createHeartOfGold(); + manager.create(heartOfGold); + heartOfGold.setDescription("prototype ship"); + + thrown.expect(UnauthorizedException.class); + manager.modify(heartOfGold); + } + + @Test(expected = NotFoundException.class) + public void testModifyNotFound() { + manager.modify(createRepositoryWithId()); + } + + @Test + public void testRefresh() { + Repository heartOfGold = createTestRepository(); + String description = heartOfGold.getDescription(); + + heartOfGold.setDescription("prototype ship"); + manager.refresh(heartOfGold); + assertEquals(description, heartOfGold.getDescription()); + } + + @Test + @SubjectAware(username = "crato") + public void testRefreshWithoutRequiredPermissions() { + Repository heartOfGold = RepositoryTestData.createHeartOfGold(); + manager.create(heartOfGold); + heartOfGold.setDescription("prototype ship"); + + thrown.expect(UnauthorizedException.class); + manager.refresh(heartOfGold); + } + + @Test(expected = NotFoundException.class) + public void testRefreshNotFound() { + manager.refresh(createRepositoryWithId()); + } + + @Test + public void testRepositoryHook() { + CountingReceiveHook hook = new CountingReceiveHook(); + RepositoryManager repoManager = createManager(); + + ScmEventBus.getInstance().register(hook); + + assertEquals(0, hook.eventsReceived); + + Repository repository = createTestRepository(); + HookContext ctx = createHookContext(repository); + + repoManager.fireHookEvent(new RepositoryHookEvent(ctx, repository, + RepositoryHookType.POST_RECEIVE)); + assertEquals(1, hook.eventsReceived); + repoManager.fireHookEvent(new RepositoryHookEvent(ctx, repository, + RepositoryHookType.POST_RECEIVE)); + assertEquals(2, hook.eventsReceived); + } + + @Test + public void testNamespaceSet() { + RepositoryManager repoManager = createManager(); + Repository repository = spy(createTestRepository()); + repository.setName("Testrepo"); + repoManager.create(repository); + assertEquals("default_namespace", repository.getNamespace()); + } + + @Test + public void shouldSetNamespace() { + Repository repository = new Repository(null, "hg", null, "scm"); + manager.create(repository); + assertNotNull(repository.getId()); + assertNotNull(repository.getNamespace()); + } + + @Test + public void shouldThrowChangeNamespaceNotAllowedException() { + Repository repository = new Repository("1", "hg", "space", "x"); + RepositoryManager repoManager = createManager(); + thrown.expect(ChangeNamespaceNotAllowedException.class); + + repoManager.rename(repository, "hitchhiker", "heart-of-gold"); + } + + @Test + public void shouldThrowNoChangesMadeException() { + configuration.setNamespaceStrategy("CustomNamespaceStrategy"); + Repository repository = new Repository("1", "hg", "space", "x"); + RepositoryManager repoManager = createManager(); + + thrown.expect(NoChangesMadeException.class); + + repoManager.rename(repository, "space", "x"); + } + + @Test + public void shouldOnlyChangeRepositoryName() { + Repository repository = createTestRepository(); + RepositoryManager repoManager = (RepositoryManager) manager; + configuration.setNamespaceStrategy("UsernameNamespaceStrategy"); + + Repository changedRepo = repoManager.rename(repository, "default_namespace", "puzzle42"); + assertNotEquals(changedRepo.getName(), repository.getName()); + } + + @Test + public void shouldRenameRepositoryNamespaceAndName() { + Repository repository = createTestRepository(); + RepositoryManager repoManager = (RepositoryManager) manager; + configuration.setNamespaceStrategy("CustomNamespaceStrategy"); + + Repository changedRepo = repoManager.rename(repository, "hitchhiker", "puzzle42"); + assertNotEquals(changedRepo.getName(), repository.getName()); + assertNotEquals(changedRepo.getNamespace(), repository.getNamespace()); + } + + //~--- methods -------------------------------------------------------------- + + @Override + protected DefaultRepositoryManager createManager() { + return createRepositoryManager(new DefaultKeyGenerator()); + } + + private DefaultRepositoryManager createRepositoryManager(KeyGenerator keyGenerator) { + Set handlerSet = new HashSet<>(); + RepositoryDAO repositoryDAO = createRepositoryDaoMock(); + mock(ConfigurationStoreFactory.class); + handlerSet.add(createRepositoryHandler("dummy", "Dummy")); + handlerSet.add(createRepositoryHandler("git", "Git")); + handlerSet.add(createRepositoryHandler("hg", "Mercurial")); + handlerSet.add(createRepositoryHandler("svn", "SVN")); + + this.configuration = new ScmConfiguration(); + + NamespaceStrategy namespaceStrategy = mock(NamespaceStrategy.class); + when(namespaceStrategy.createNamespace(Mockito.any(Repository.class))).thenAnswer(invocation -> mockedNamespace); + + return new DefaultRepositoryManager(configuration, contextProvider, + keyGenerator, repositoryDAO, handlerSet, Providers.of(namespaceStrategy)); + } + + private RepositoryDAO createRepositoryDaoMock() { + Map repositoriesById = new HashMap<>(); + Map repositoriesByNamespaceAndName = new HashMap<>(); + RepositoryDAO mock = mock(RepositoryDAO.class); + doAnswer(invocation -> { + Repository repo = invocation.getArgument(0, Repository.class); + if (repositoriesById.containsKey(repo.getId()) || repositoriesByNamespaceAndName.containsKey(repo.getNamespaceAndName())) { + throw new AlreadyExistsException(repo); + } + Repository clone = repo.clone(); + repositoriesById.put(repo.getId(), clone); + repositoriesByNamespaceAndName.put(repo.getNamespaceAndName(), clone); + return null; + }).when(mock).add(any()); + doAnswer(invocation -> { + Repository repo = invocation.getArgument(0, Repository.class); + Repository clone = repo.clone(); + repositoriesById.put(repo.getId(), clone); + repositoriesByNamespaceAndName.put(repo.getNamespaceAndName(), clone); + return null; + }).when(mock).modify(any()); + when(mock.get(anyString())).thenAnswer(invocation -> repositoriesById.get(invocation.getArgument(0, String.class))); + when(mock.get(any(NamespaceAndName.class))).thenAnswer(invocation -> repositoriesByNamespaceAndName.get(invocation.getArgument(0, NamespaceAndName.class))); + when(mock.getAll()).thenAnswer(invocation -> repositoriesById.values()); + when(mock.contains(anyString())).thenAnswer(invocation -> repositoriesById.containsKey(invocation.getArgument(0, String.class))); + when(mock.contains(any(Repository.class))).thenAnswer(invocation -> repositoriesById.containsKey(invocation.getArgument(0, Repository.class).getId())); + doAnswer(invocation -> { + Repository repo = invocation.getArgument(0, Repository.class); + repositoriesById.remove(repo.getId()); + repositoriesByNamespaceAndName.remove(repo.getNamespaceAndName()); + return null; + }).when(mock).delete(any(Repository.class)); + return mock; + } + + private RepositoryHandler createRepositoryHandler(String name, String diplayName) { + RepositoryHandler handler = mock(RepositoryHandler.class); + when(handler.getType()).thenReturn(new RepositoryType(name, diplayName, emptySet())); + when(handler.isConfigured()).thenReturn(true); + return handler; + } + + private HookContext createHookContext(Repository repository) { + PreProcessorUtil ppu = mock(PreProcessorUtil.class); + HookContextProvider provider = mock(HookContextProvider.class); + Set features = ImmutableSet.of(); + + when(provider.getSupportedFeatures()).thenReturn(features); + + return new HookContextFactory(ppu).createContext(provider, repository); + } + + private void assertRepositoriesEquals(Repository repo, Repository other) { + assertEquals(repo.getId(), other.getId()); + assertEquals(repo.getName(), other.getName()); + assertEquals(repo.getDescription(), other.getDescription()); + assertEquals(repo.getContact(), other.getContact()); + assertEquals(repo.getCreationDate(), other.getCreationDate()); + assertEquals(repo.getLastModified(), other.getLastModified()); + } + + private Repository createRepository(Repository repository) { + manager.create(repository); + assertNotNull(repository.getId()); + assertNotNull(manager.get(repository.getId())); + assertTrue(repository.getCreationDate() > 0); + + return repository; + } + + private Repository createRepositoryWithId() { + Repository repository = RepositoryTestData.createHeartOfGold(); + repository.setId("abc"); + return repository; + } + + private Repository createSecondTestRepository() { + return createRepository( + RepositoryTestData.createHappyVerticalPeopleTransporter()); + } + + private Repository createTestRepository() { + return createRepository(RepositoryTestData.createHeartOfGold()); + } + + private void delete(Manager manager, Repository repository) { + + String id = repository.getId(); + + manager.delete(repository); + assertNull(manager.get(id)); + } + + private static class CountingReceiveHook { + + private int eventsReceived = 0; + + @Subscribe(async = false) + public void onEvent(PostReceiveRepositoryHookEvent event) { + eventsReceived++; + } + + @Subscribe(async = false) + public void onEvent(PreReceiveRepositoryHookEvent event) { + eventsReceived++; + } + } + + private class TestListener { + + private HandlerEventType postEvent; + + private Repository postRepository; + + private HandlerEventType preEvent; + + private Repository preRepository; + + @Subscribe(async = false) + public void onEvent(RepositoryEvent event) { + if (event.getEventType().isPost()) { + this.postRepository = event.getItem(); + this.postEvent = event.getEventType(); + } else if (event.getEventType().isPre()) { + this.preRepository = event.getItem(); + this.preEvent = event.getEventType(); + } + } + } -// { -// ThreadContext.unbindSubject(); -// } -// -// @Rule -// public ShiroRule shiro = new ShiroRule(); -// -// @Rule -// public ExpectedException thrown = ExpectedException.none(); -// -// private ScmConfiguration configuration; -// -// private String mockedNamespace = "default_namespace"; -// -// @Before -// public void initContext() { -// ((TempSCMContextProvider)SCMContext.getContext()).setBaseDirectory(temp); -// } -// -// @Test -// public void testCreate() { -// Repository heartOfGold = createTestRepository(); -// Repository dbRepo = manager.get(heartOfGold.getId()); -// -// assertNotNull(dbRepo); -// assertRepositoriesEquals(dbRepo, heartOfGold); -// } -// -// @SubjectAware( -// username = "unpriv" -// ) -// @Test(expected = UnauthorizedException.class) -// public void testCreateWithoutPrivileges() { -// createTestRepository(); -// } -// -// @Test -// public void testCreateExisting() { -// Repository testRepository = createTestRepository(); -// String expectedNamespaceAndName = testRepository.getNamespaceAndName().logString(); -// thrown.expect(AlreadyExistsException.class); -// thrown.expectMessage(expectedNamespaceAndName); -// createTestRepository(); -// } -// -// @Test -// public void testDelete() { -// delete(manager, createTestRepository()); -// } -// -// @SubjectAware( -// username = "unpriv" -// ) -// @Test(expected = UnauthorizedException.class) -// public void testDeleteWithoutPrivileges() { -// delete(manager, createTestRepository()); -// } -// -// @Test(expected = RepositoryIsNotArchivedException.class) -// public void testDeleteNonArchived() { -// configuration.setEnableRepositoryArchive(true); -// delete(manager, createTestRepository()); -// } -// -// @Test(expected = NotFoundException.class) -// public void testDeleteNotFound(){ -// manager.delete(createRepositoryWithId()); -// } -// -// @Test -// public void testDeleteWithEnabledArchive() { -// Repository repository = createTestRepository(); -// -// repository.setArchived(true); -// RepositoryManager drm = createRepositoryManager(true); -// drm.init(contextProvider); -// delete(drm, repository); -// } -// -// @Test -// public void testGet() { -// Repository heartOfGold = createTestRepository(); -// String id = heartOfGold.getId(); -// String description = heartOfGold.getDescription(); -// -// assertNotNull(description); -// -// // test for reference -// heartOfGold.setDescription("prototype ship"); -// heartOfGold = manager.get(id); -// assertNotNull(heartOfGold); -// assertEquals(description, heartOfGold.getDescription()); -// } -// -// @Test -// @SubjectAware( -// username = "crato" -// ) -// public void testGetWithoutRequiredPrivileges() { -// Repository heartOfGold = RepositoryTestData.createHeartOfGold(); -// manager.create(heartOfGold); -// -// thrown.expect(UnauthorizedException.class); -// manager.get(heartOfGold.getId()); -// } -// -// @Test -// public void testGetAll() { -// Repository heartOfGold = createTestRepository(); -// Repository happyVerticalPeopleTransporter = createSecondTestRepository(); -// boolean foundHeart = false; -// boolean foundTransporter = false; -// Collection repositories = manager.getAll(); -// -// assertNotNull(repositories); -// assertFalse(repositories.isEmpty()); -// assertTrue(repositories.size() >= 2); -// -// Repository heartReference = null; -// -// for (Repository repository : repositories) { -// if (repository.getId().equals(heartOfGold.getId())) { -// assertRepositoriesEquals(heartOfGold, repository); -// foundHeart = true; -// heartReference = repository; -// } -// else if (repository.getId().equals(happyVerticalPeopleTransporter.getId())) { -// assertRepositoriesEquals(happyVerticalPeopleTransporter, repository); -// foundTransporter = true; -// } -// } -// -// assertTrue(foundHeart); -// assertTrue(foundTransporter); -// -// // test for reference -// assertNotSame(heartOfGold, heartReference); -// heartReference.setDescription("prototype ship"); -// assertFalse( -// heartOfGold.getDescription().equals(heartReference.getDescription())); -// } -// -// @Test -// @SuppressWarnings("unchecked") -// @SubjectAware(username = "dent") -// public void testGetAllWithPermissionsForTwoOrThreeRepos() { -// // mock key generator -// KeyGenerator keyGenerator = mock(KeyGenerator.class); -// Stack keys = new Stack<>(); -// keys.push("rateotu"); -// keys.push("p42"); -// keys.push("hof"); -// -// when(keyGenerator.createKey()).then((InvocationOnMock invocation) -> { -// return keys.pop(); -// }); -// -// // create repository manager -// RepositoryManager repositoryManager = createRepositoryManager(false, keyGenerator); -// -// // create first test repository -// Repository heartOfGold = RepositoryTestData.createHeartOfGold(); -// repositoryManager.create(heartOfGold); -// assertEquals("hof", heartOfGold.getId()); -// -// // create second test repository -// Repository puzzle42 = RepositoryTestData.create42Puzzle(); -// repositoryManager.create(puzzle42); -// assertEquals("p42", puzzle42.getId()); -// -// // create third test repository -// Repository restaurant = RepositoryTestData.createRestaurantAtTheEndOfTheUniverse(); -// repositoryManager.create(restaurant); -// assertEquals("rateotu", restaurant.getId()); -// -// // assert returned repositories -// Collection repositories = repositoryManager.getAll(); -// assertEquals(2, repositories.size()); -// assertThat(repositories, containsInAnyOrder( -// hasProperty("id", is("p42")), -// hasProperty("id", is("hof")) -// ) -// ); -// } -// -// @Test -// public void testEvents() { -// RepositoryManager repoManager = createRepositoryManager(false); -// repoManager.init(contextProvider); -// TestListener listener = new TestListener(); -// -// ScmEventBus.getInstance().register(listener); -// -// Repository repository = RepositoryTestData.create42Puzzle(); -// -// repoManager.create(repository); -// assertRepositoriesEquals(repository, listener.preRepository); -// assertSame(HandlerEventType.BEFORE_CREATE, listener.preEvent); -// assertRepositoriesEquals(repository, listener.postRepository); -// assertSame(HandlerEventType.CREATE, listener.postEvent); -// -// repository.setDescription("changed description"); -// repoManager.modify(repository); -// assertRepositoriesEquals(repository, listener.preRepository); -// assertSame(HandlerEventType.BEFORE_MODIFY, listener.preEvent); -// assertRepositoriesEquals(repository, listener.postRepository); -// assertSame(HandlerEventType.MODIFY, listener.postEvent); -// -// repoManager.delete(repository); -// -// assertRepositoriesEquals(repository, listener.preRepository); -// assertSame(HandlerEventType.BEFORE_DELETE, listener.preEvent); -// assertRepositoriesEquals(repository, listener.postRepository); -// assertSame(HandlerEventType.DELETE, listener.postEvent); -// } -// -// @Test -// public void testModify() { -// Repository heartOfGold = createTestRepository(); -// -// heartOfGold.setDescription("prototype ship"); -// manager.modify(heartOfGold); -// -// Repository hearReference = manager.get(heartOfGold.getId()); -// -// assertNotNull(hearReference); -// assertEquals(hearReference.getDescription(), "prototype ship"); -// } -// -// @Test -// @SubjectAware(username = "crato") -// public void testModifyWithoutRequiredPermissions() { -// Repository heartOfGold = RepositoryTestData.createHeartOfGold(); -// manager.create(heartOfGold); -// heartOfGold.setDescription("prototype ship"); -// -// thrown.expect(UnauthorizedException.class); -// manager.modify(heartOfGold); -// } -// -// @Test(expected = NotFoundException.class) -// public void testModifyNotFound(){ -// manager.modify(createRepositoryWithId()); -// } -// -// @Test -// public void testRefresh() { -// Repository heartOfGold = createTestRepository(); -// String description = heartOfGold.getDescription(); -// -// heartOfGold.setDescription("prototype ship"); -// manager.refresh(heartOfGold); -// assertEquals(description, heartOfGold.getDescription()); -// } -// -// @Test -// @SubjectAware(username = "crato") -// public void testRefreshWithoutRequiredPermissions() { -// Repository heartOfGold = RepositoryTestData.createHeartOfGold(); -// manager.create(heartOfGold); -// heartOfGold.setDescription("prototype ship"); -// -// thrown.expect(UnauthorizedException.class); -// manager.refresh(heartOfGold); -// } -// -// @Test(expected = NotFoundException.class) -// public void testRefreshNotFound(){ -// manager.refresh(createRepositoryWithId()); -// } -// -// @Test -// public void testRepositoryHook() { -// CountingReceiveHook hook = new CountingReceiveHook(); -// RepositoryManager repoManager = createRepositoryManager(false); -// -// ScmEventBus.getInstance().register(hook); -// -// assertEquals(0, hook.eventsReceived); -// -// Repository repository = createTestRepository(); -// HookContext ctx = createHookContext(repository); -// -// repoManager.fireHookEvent(new RepositoryHookEvent(ctx, repository, -// RepositoryHookType.POST_RECEIVE)); -// assertEquals(1, hook.eventsReceived); -// repoManager.fireHookEvent(new RepositoryHookEvent(ctx, repository, -// RepositoryHookType.POST_RECEIVE)); -// assertEquals(2, hook.eventsReceived); -// } -// -// @Test -// public void testNamespaceSet() { -// RepositoryManager repoManager = createRepositoryManager(false); -// Repository repository = spy(createTestRepository()); -// repository.setName("Testrepo"); -// repoManager.create(repository); -// assertEquals("default_namespace", repository.getNamespace()); -// } -// -// @Test -// public void shouldSetNamespace() { -// Repository repository = new Repository(null, "hg", null, "scm"); -// manager.create(repository); -// assertNotNull(repository.getId()); -// assertNotNull(repository.getNamespace()); -// } -// -// //~--- methods -------------------------------------------------------------- -// -// @Override -// protected DefaultRepositoryManager createManager() { -// return createRepositoryManager(false); -// } -// -// private DefaultRepositoryManager createRepositoryManager(boolean archiveEnabled) { -// return createRepositoryManager(archiveEnabled, new DefaultKeyGenerator()); -// } -// -// private DefaultRepositoryManager createRepositoryManager(boolean archiveEnabled, KeyGenerator keyGenerator) { -// DefaultFileSystem fileSystem = new DefaultFileSystem(); -// Set handlerSet = new HashSet<>(); -// PathBasedRepositoryLocationResolver repositoryLocationResolver = mock(PathBasedRepositoryLocationResolver.class, RETURNS_DEEP_STUBS); -// when(repositoryLocationResolver.forClass(Path.class).getLocation(anyString())).thenReturn(Paths.get(".")); -// XmlRepositoryDAO repositoryDAO = new XmlRepositoryDAO(contextProvider, repositoryLocationResolver, fileSystem); -// ConfigurationStoreFactory factory = new JAXBConfigurationStoreFactory(contextProvider, repositoryLocationResolver); -// handlerSet.add(new DummyRepositoryHandler(factory, repositoryLocationResolver)); -// handlerSet.add(new DummyRepositoryHandler(factory, repositoryLocationResolver) { -// @Override -// public RepositoryType getType() { -// return new RepositoryType("hg", "Mercurial", Sets.newHashSet()); -// } -// }); -// handlerSet.add(new DummyRepositoryHandler(factory, repositoryLocationResolver) { -// @Override -// public RepositoryType getType() { -// return new RepositoryType("git", "Git", Sets.newHashSet()); -// } -// }); -// -// -// this.configuration = new ScmConfiguration(); -// -// configuration.setEnableRepositoryArchive(archiveEnabled); -// -// NamespaceStrategy namespaceStrategy = mock(NamespaceStrategy.class); -// when(namespaceStrategy.createNamespace(Mockito.any(Repository.class))).thenAnswer(invocation -> mockedNamespace); -// -// return new DefaultRepositoryManager(configuration, contextProvider, -// keyGenerator, repositoryDAO, handlerSet, Providers.of(namespaceStrategy)); -// } -// -// private HookContext createHookContext(Repository repository) { -// PreProcessorUtil ppu = mock(PreProcessorUtil.class); -// HookContextProvider provider = mock(HookContextProvider.class); -// Set features = ImmutableSet.of(); -// -// when(provider.getSupportedFeatures()).thenReturn(features); -// -// return new HookContextFactory(ppu).createContext(provider, repository); -// } -// -// private void assertRepositoriesEquals(Repository repo, Repository other) { -// assertEquals(repo.getId(), other.getId()); -// assertEquals(repo.getName(), other.getName()); -// assertEquals(repo.getDescription(), other.getDescription()); -// assertEquals(repo.getContact(), other.getContact()); -// assertEquals(repo.getCreationDate(), other.getCreationDate()); -// assertEquals(repo.getLastModified(), other.getLastModified()); -// } -// -// private Repository createRepository(Repository repository) { -// manager.create(repository); -// assertNotNull(repository.getId()); -// assertNotNull(manager.get(repository.getId())); -// assertTrue(repository.getCreationDate() > 0); -// -// return repository; -// } -// -// private Repository createRepositoryWithId() { -// Repository repository = RepositoryTestData.createHeartOfGold(); -// repository.setId("abc"); -// return repository; -// } -// -// private Repository createSecondTestRepository() { -// return createRepository( -// RepositoryTestData.createHappyVerticalPeopleTransporter()); -// } -// -// private Repository createTestRepository() { -// return createRepository(RepositoryTestData.createHeartOfGold()); -// } -// -// private void delete(Manager manager, Repository repository){ -// -// String id = repository.getId(); -// -// manager.delete(repository); -// assertNull(manager.get(id)); -// } -// -// private static class CountingReceiveHook { -// -// private int eventsReceived = 0; -// -// @Subscribe(async = false) -// public void onEvent(PostReceiveRepositoryHookEvent event) { -// eventsReceived++; -// } -// -// @Subscribe(async = false) -// public void onEvent(PreReceiveRepositoryHookEvent event) { -// eventsReceived++; -// } -// } -// -// private class TestListener { -// -// private HandlerEventType postEvent; -// -// private Repository postRepository; -// -// private HandlerEventType preEvent; -// -// private Repository preRepository; -// -// @Subscribe(async = false) -// public void onEvent(RepositoryEvent event) { -// if (event.getEventType().isPost()) { -// this.postRepository = event.getItem(); -// this.postEvent = event.getEventType(); -// } -// else if (event.getEventType().isPre()) { -// this.preRepository = event.getItem(); -// this.preEvent = event.getEventType(); -// } -// } -// } -// }