Implement update and delete for repository

This commit is contained in:
René Pfeuffer
2018-07-05 10:42:09 +02:00
parent 68e196d576
commit c2effbe9c5
6 changed files with 113 additions and 6 deletions

View File

@@ -16,6 +16,7 @@ public class MapperModule extends AbstractModule {
bind(GroupCollectionToDtoMapper.class); bind(GroupCollectionToDtoMapper.class);
bind(RepositoryToRepositoryDtoMapper.class).to(Mappers.getMapper(RepositoryToRepositoryDtoMapper.class).getClass()); bind(RepositoryToRepositoryDtoMapper.class).to(Mappers.getMapper(RepositoryToRepositoryDtoMapper.class).getClass());
bind(RepositoryDtoToRepositoryMapper.class).to(Mappers.getMapper(RepositoryDtoToRepositoryMapper.class).getClass());
bind(UriInfoStore.class).in(ServletScopes.REQUEST); bind(UriInfoStore.class).in(ServletScopes.REQUEST);
} }

View File

@@ -0,0 +1,18 @@
package sonia.scm.api.v2.resources;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import sonia.scm.repository.Repository;
@Mapper
public abstract class RepositoryDtoToRepositoryMapper {
@Mapping(target = "creationDate", ignore = true)
@Mapping(target = "lastModified", ignore = true)
@Mapping(target = "id", ignore = true)
@Mapping(target = "publicReadable", ignore = true)
@Mapping(target = "healthCheckFailures", ignore = true)
@Mapping(target = "permissions", ignore = true)
public abstract Repository map(RepositoryDto repositoryDto);
}

View File

@@ -21,6 +21,7 @@ import javax.ws.rs.core.Response;
public class RepositoryResource { public class RepositoryResource {
private final RepositoryToRepositoryDtoMapper repositoryToDtoMapper; private final RepositoryToRepositoryDtoMapper repositoryToDtoMapper;
private final RepositoryDtoToRepositoryMapper dtoToRepositoryMapper;
private final RepositoryManager manager; private final RepositoryManager manager;
private final SingleResourceManagerAdapter<Repository, RepositoryDto, RepositoryException> adapter; private final SingleResourceManagerAdapter<Repository, RepositoryDto, RepositoryException> adapter;
@@ -33,11 +34,12 @@ public class RepositoryResource {
@Inject @Inject
public RepositoryResource( public RepositoryResource(
RepositoryToRepositoryDtoMapper repositoryToDtoMapper, RepositoryToRepositoryDtoMapper repositoryToDtoMapper,
RepositoryManager manager, RepositoryDtoToRepositoryMapper dtoToRepositoryMapper, RepositoryManager manager,
Provider<TagRootResource> tagRootResource, Provider<TagRootResource> tagRootResource,
Provider<BranchRootResource> branchRootResource, Provider<BranchRootResource> branchRootResource,
Provider<ChangesetRootResource> changesetRootResource, Provider<ChangesetRootResource> changesetRootResource,
Provider<SourceRootResource> sourceRootResource, Provider<PermissionRootResource> permissionRootResource) { Provider<SourceRootResource> sourceRootResource, Provider<PermissionRootResource> permissionRootResource) {
this.dtoToRepositoryMapper = dtoToRepositoryMapper;
this.manager = manager; this.manager = manager;
this.repositoryToDtoMapper = repositoryToDtoMapper; this.repositoryToDtoMapper = repositoryToDtoMapper;
this.adapter = new SingleResourceManagerAdapter<>(manager); this.adapter = new SingleResourceManagerAdapter<>(manager);
@@ -65,14 +67,25 @@ public class RepositoryResource {
@DELETE @DELETE
@Path("") @Path("")
@StatusCodes({
@ResponseCode(code = 204, condition = "delete success or nothing to delete"),
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"repository\" privilege"),
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(TypeHint.NO_CONTENT.class)
public Response delete(@PathParam("namespace") String namespace, @PathParam("name") String name) { public Response delete(@PathParam("namespace") String namespace, @PathParam("name") String name) {
throw new UnsupportedOperationException(); return adapter.delete(() -> manager.getByNamespace(namespace, name));
} }
@PUT @PUT
@Path("") @Path("")
public Response update(@PathParam("namespace") String namespace, @PathParam("name") String name) { public Response update(@PathParam("namespace") String namespace, @PathParam("name") String name, RepositoryDto repositoryDto) {
throw new UnsupportedOperationException(); return adapter.update(() -> manager.getByNamespace(namespace, name), existing -> {
Repository repository = dtoToRepositoryMapper.map(repositoryDto);
repository.setId(existing.getId());
return repository;
});
} }
@Path("tags/") @Path("tags/")

View File

@@ -60,6 +60,11 @@ class SingleResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
return update(getId(existingModelObject), changedModelObject); return update(getId(existingModelObject), changedModelObject);
} }
public Response delete(Supplier<MODEL_OBJECT> reader) {
MODEL_OBJECT existingModelObject = reader.get();
return delete(existingModelObject.getId());
}
@Override @Override
protected GenericEntity<Collection<MODEL_OBJECT>> createGenericEntity(Collection<MODEL_OBJECT> modelObjects) { protected GenericEntity<Collection<MODEL_OBJECT>> createGenericEntity(Collection<MODEL_OBJECT> modelObjects) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();

View File

@@ -2,6 +2,7 @@ package sonia.scm.api.v2.resources;
import com.github.sdorra.shiro.ShiroRule; import com.github.sdorra.shiro.ShiroRule;
import com.github.sdorra.shiro.SubjectAware; import com.github.sdorra.shiro.SubjectAware;
import com.google.common.io.Resources;
import org.jboss.resteasy.core.Dispatcher; import org.jboss.resteasy.core.Dispatcher;
import org.jboss.resteasy.mock.MockDispatcherFactory; import org.jboss.resteasy.mock.MockDispatcherFactory;
import org.jboss.resteasy.mock.MockHttpRequest; import org.jboss.resteasy.mock.MockHttpRequest;
@@ -14,17 +15,23 @@ import org.mockito.Mock;
import sonia.scm.PageResult; import sonia.scm.PageResult;
import sonia.scm.repository.Repository; import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryManager; import sonia.scm.repository.RepositoryManager;
import sonia.scm.web.VndMediaType;
import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND; 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; import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks; import static org.mockito.MockitoAnnotations.initMocks;
@@ -48,11 +55,13 @@ public class RepositoryRootResourceTest {
@InjectMocks @InjectMocks
private RepositoryToRepositoryDtoMapperImpl repositoryToDtoMapper; private RepositoryToRepositoryDtoMapperImpl repositoryToDtoMapper;
@InjectMocks
private RepositoryDtoToRepositoryMapperImpl dtoToRepositoryMapper;
@Before @Before
public void prepareEnvironment() { public void prepareEnvironment() {
initMocks(this); initMocks(this);
RepositoryResource repositoryResource = new RepositoryResource(repositoryToDtoMapper, repositoryManager, null, null, null, null, null); RepositoryResource repositoryResource = new RepositoryResource(repositoryToDtoMapper, dtoToRepositoryMapper, repositoryManager, null, null, null, null, null);
RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks); RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks);
RepositoryCollectionResource repositoryCollectionResource = new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper); RepositoryCollectionResource repositoryCollectionResource = new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper);
RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(repositoryResource), MockProvider.of(repositoryCollectionResource)); RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(repositoryResource), MockProvider.of(repositoryCollectionResource));
@@ -98,6 +107,57 @@ public class RepositoryRootResourceTest {
assertTrue(response.getContentAsString().contains("\"name\":\"repo\"")); assertTrue(response.getContentAsString().contains("\"name\":\"repo\""));
} }
@Test
public void shouldHandleUpdateForNotExistingRepository() throws URISyntaxException, IOException {
URL url = Resources.getResource("sonia/scm/api/v2/repository-test-update.json");
byte[] repository = Resources.toByteArray(url);
MockHttpRequest request = MockHttpRequest
.put("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo")
.contentType(VndMediaType.REPOSITORY)
.content(repository);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(SC_NOT_FOUND, response.getStatus());
}
@Test
public void shouldHandleUpdateForExistingRepository() throws Exception {
mockRepository("space", "repo");
URL url = Resources.getResource("sonia/scm/api/v2/repository-test-update.json");
byte[] repository = Resources.toByteArray(url);
MockHttpRequest request = MockHttpRequest
.put("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo")
.contentType(VndMediaType.REPOSITORY)
.content(repository);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(SC_NO_CONTENT, response.getStatus());
verify(repositoryManager).modify(anyObject());
}
@Test
public void shouldHandleDeleteForExistingRepository() throws Exception {
mockRepository("space", "repo");
URL url = Resources.getResource("sonia/scm/api/v2/repository-test-update.json");
byte[] repository = Resources.toByteArray(url);
MockHttpRequest request = MockHttpRequest.delete("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertEquals(SC_NO_CONTENT, response.getStatus());
verify(repositoryManager).delete(anyObject());
}
private PageResult<Repository> createSingletonPageResult(Repository repository) { private PageResult<Repository> createSingletonPageResult(Repository repository) {
return new PageResult<>(singletonList(repository), 0); return new PageResult<>(singletonList(repository), 0);
} }
@@ -106,8 +166,10 @@ public class RepositoryRootResourceTest {
Repository repository = new Repository(); Repository repository = new Repository();
repository.setNamespace(namespace); repository.setNamespace(namespace);
repository.setName(name); repository.setName(name);
repository.setId("id"); String id = namespace + "-" + name;
repository.setId(id);
when(repositoryManager.getByNamespace(namespace, name)).thenReturn(repository); when(repositoryManager.getByNamespace(namespace, name)).thenReturn(repository);
when(repositoryManager.get(id)).thenReturn(repository);
return repository; return repository;
} }
} }

View File

@@ -0,0 +1,8 @@
{
"contact": "none@example.com",
"description": "Test repository",
"namespace": "space",
"name": "repo",
"archived": false,
"type": "git"
}