diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java index 5b9c7a916e..9f2709cb43 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/SourceRootResource.java @@ -33,13 +33,23 @@ public class SourceRootResource { @Produces(VndMediaType.SOURCE) @Path("{revision : (\\w+)?}") public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision) { + return getSource(namespace, name, "/", revision); + } + @GET + @Produces(VndMediaType.SOURCE) + @Path("{revision}/{path: .*}") + public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision, @PathParam("path") String path) { + return getSource(namespace, name, path, revision); + } + + private Response getSource(String namespace, String repoName, String path, String revision) { BrowserResult browserResult; Response response; - NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name); + NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, repoName); try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) { BrowseCommandBuilder browseCommand = repositoryService.getBrowseCommand(); - browseCommand.setPath("/"); + browseCommand.setPath(path); if (revision != null && !revision.isEmpty()) { browseCommand.setRevision(revision); } @@ -58,10 +68,4 @@ public class SourceRootResource { } return response; } - - @GET - @Path("{revision}/{path: .*}") - public Response get() { - throw new UnsupportedOperationException(); - } } diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java new file mode 100644 index 0000000000..d4e2ea03b9 --- /dev/null +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/SourceRootResourceTest.java @@ -0,0 +1,155 @@ +package sonia.scm.api.v2.resources; + +import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.mock.MockDispatcherFactory; +import org.jboss.resteasy.mock.MockHttpRequest; +import org.jboss.resteasy.mock.MockHttpResponse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import sonia.scm.repository.*; +import sonia.scm.repository.api.BrowseCommandBuilder; +import sonia.scm.repository.api.RepositoryService; +import sonia.scm.repository.api.RepositoryServiceFactory; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + + +@RunWith(MockitoJUnitRunner.Silent.class) +public class SourceRootResourceTest { + + private final Dispatcher dispatcher = MockDispatcherFactory.createDispatcher(); + private final URI baseUri = URI.create("/"); + private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri); + + @Mock + private RepositoryServiceFactory serviceFactory; + @Mock + private RepositoryService service; + @Mock + private BrowseCommandBuilder browseCommandBuilder; + + @Mock + private FileObjectMapper fileObjectMapper; + + @InjectMocks + private BrowserResultMapper browserResultMapper; + + + @Before + public void prepareEnvironment() throws Exception { + when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service); + when(service.getBrowseCommand()).thenReturn(browseCommandBuilder); + + FileObjectDto dto = new FileObjectDto(); + dto.setName("name"); + dto.setLength(1024); + + when(fileObjectMapper.map(any(FileObject.class), any(NamespaceAndName.class), anyString())).thenReturn(dto); + SourceRootResource sourceRootResource = new SourceRootResource(serviceFactory, browserResultMapper); + RepositoryRootResource repositoryRootResource = + new RepositoryRootResource(MockProvider.of(new RepositoryResource(null, + null, + null, + null, + null, + null, + MockProvider.of(sourceRootResource), + null)), + null); + + dispatcher.getRegistry().addSingletonResource(repositoryRootResource); + } + + @Test + public void shouldReturnSources() throws URISyntaxException, IOException, RepositoryException { + BrowserResult result = createBrowserResult(); + when(browseCommandBuilder.getBrowserResult()).thenReturn(result); + MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/sources"); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + assertThat(response.getStatus()).isEqualTo(200); + assertThat(response.getContentAsString()).contains("\"revision\":\"revision\""); + assertThat(response.getContentAsString()).contains("\"tag\":\"tag\""); + assertThat(response.getContentAsString()).contains("\"branch\":\"branch\""); + assertThat(response.getContentAsString()).contains("\"files\":"); + } + + @Test + public void shouldReturn404IfRepoNotFound() throws URISyntaxException, RepositoryNotFoundException { + when(serviceFactory.create(new NamespaceAndName("idont", "exist"))).thenThrow(RepositoryNotFoundException.class); + MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "idont/exist/sources"); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + assertThat(response.getStatus()).isEqualTo(404); + } + + @Test + public void shouldGetResultForSingleFile() throws URISyntaxException, IOException, RepositoryException { + BrowserResult browserResult = new BrowserResult(); + browserResult.setBranch("abc"); + browserResult.setRevision("revision"); + browserResult.setTag("tag"); + FileObject fileObject = new FileObject(); + fileObject.setName("File Object!"); + + browserResult.setFiles(Arrays.asList(fileObject)); + + when(browseCommandBuilder.getBrowserResult()).thenReturn(browserResult); + MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/sources/revision/fileabc"); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + assertThat(response.getStatus()).isEqualTo(200); + assertThat(response.getContentAsString()).contains("\"revision\":\"revision\""); + } + + @Test + public void shouldGet404ForSingleFileIfRepoNotFound() throws URISyntaxException, RepositoryException { + when(serviceFactory.create(new NamespaceAndName("idont", "exist"))).thenThrow(RepositoryNotFoundException.class); + + MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "idont/exist/sources/revision/fileabc"); + MockHttpResponse response = new MockHttpResponse(); + + dispatcher.invoke(request, response); + assertThat(response.getStatus()).isEqualTo(404); + } + + private BrowserResult createBrowserResult() { + return new BrowserResult("revision", "tag", "branch", createFileObjects()); + } + + private List createFileObjects() { + FileObject fileObject1 = new FileObject(); + fileObject1.setName("FO 1"); + fileObject1.setDirectory(false); + fileObject1.setDescription("File object 1"); + fileObject1.setPath("/foo/bar/fo1"); + fileObject1.setLength(1024L); + fileObject1.setLastModified(0L); + + FileObject fileObject2 = new FileObject(); + fileObject2.setName("FO 2"); + fileObject2.setDirectory(true); + fileObject2.setDescription("File object 2"); + fileObject2.setPath("/foo/bar/fo2"); + fileObject2.setLength(4096L); + fileObject2.setLastModified(1234L); + + return Arrays.asList(fileObject1, fileObject2); + } +}