#8771 Merged Permission endpoints

This commit is contained in:
Mohamed Karray
2018-08-21 10:35:39 +02:00
24 changed files with 855 additions and 444 deletions

View File

@@ -305,7 +305,7 @@
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>

View File

@@ -33,24 +33,19 @@
package sonia.scm.repository.api;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.spi.CatCommand;
import sonia.scm.repository.spi.CatCommandRequest;
import sonia.scm.util.IOUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
@@ -110,19 +105,27 @@ public final class CatCommandBuilder
*
* @param outputStream output stream for the content
* @param path file path
*
* @return {@code this}
*
* @throws IOException
* @throws RepositoryException
*/
public CatCommandBuilder retriveContent(OutputStream outputStream,
String path)
throws IOException, RepositoryException
{
public void retriveContent(OutputStream outputStream, String path) throws IOException, RepositoryException {
getCatResult(outputStream, path);
}
return this;
/**
* Returns an output stream with the file content.
*
* @param path file path
*/
public InputStream getStream(String path) throws IOException, RepositoryException {
Preconditions.checkArgument(!Strings.isNullOrEmpty(path),
"path is required");
CatCommandRequest requestClone = request.clone();
requestClone.setPath(path);
logger.debug("create cat stream for {}", requestClone);
return catCommand.getCatResultStream(requestClone);
}
//~--- get methods ----------------------------------------------------------

View File

@@ -33,13 +33,10 @@
package sonia.scm.repository.spi;
//~--- non-JDK imports --------------------------------------------------------
import sonia.scm.repository.RepositoryException;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
@@ -47,19 +44,9 @@ import java.io.OutputStream;
* @author Sebastian Sdorra
* @since 1.17
*/
public interface CatCommand
{
public interface CatCommand {
/**
* Method description
*
*
* @param request
* @param output
*
* @throws IOException
* @throws RepositoryException
*/
public void getCatResult(CatCommandRequest request, OutputStream output)
throws IOException, RepositoryException;
void getCatResult(CatCommandRequest request, OutputStream output) throws IOException, RepositoryException;
InputStream getCatResultStream(CatCommandRequest request) throws IOException, RepositoryException;
}

View File

@@ -0,0 +1,67 @@
package sonia.scm.it;
import org.apache.http.HttpStatus;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.io.IOException;
import java.util.Collection;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assume.assumeFalse;
import static sonia.scm.it.RestUtil.given;
import static sonia.scm.it.ScmTypes.availableScmTypes;
@RunWith(Parameterized.class)
public class RepositoryAccessITCase {
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
private final String repositoryType;
private RepositoryUtil repositoryUtil;
public RepositoryAccessITCase(String repositoryType) {
this.repositoryType = repositoryType;
}
@Parameterized.Parameters(name = "{0}")
public static Collection<String> createParameters() {
return availableScmTypes();
}
@Before
public void initClient() throws IOException {
TestData.createDefault();
repositoryUtil = new RepositoryUtil(repositoryType, tempFolder.getRoot());
}
@Test
public void shouldFindBranches() throws IOException {
assumeFalse("There are no branches for SVN", repositoryType.equals("svn"));
repositoryUtil.createAndCommitFile("a.txt", "a");
String branchesUrl = given()
.when()
.get(TestData.getDefaultRepositoryUrl(repositoryType))
.then()
.statusCode(HttpStatus.SC_OK)
.extract()
.path("_links.branches.href");
Object branchName = given()
.when()
.get(branchesUrl)
.then()
.statusCode(HttpStatus.SC_OK)
.extract()
.path("_embedded.branches[0].name");
assertNotNull(branchName);
}
}

View File

@@ -0,0 +1,62 @@
package sonia.scm.it;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import org.apache.http.HttpStatus;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.Person;
import sonia.scm.repository.client.api.ClientCommand;
import sonia.scm.repository.client.api.RepositoryClient;
import sonia.scm.repository.client.api.RepositoryClientFactory;
import sonia.scm.web.VndMediaType;
import java.io.File;
import java.io.IOException;
import static sonia.scm.it.RestUtil.ADMIN_PASSWORD;
import static sonia.scm.it.RestUtil.ADMIN_USERNAME;
import static sonia.scm.it.RestUtil.given;
public class RepositoryUtil {
private static final RepositoryClientFactory REPOSITORY_CLIENT_FACTORY = new RepositoryClientFactory();
private final RepositoryClient repositoryClient;
private final File folder;
RepositoryUtil(String repositoryType, File folder) throws IOException {
this.repositoryClient = createRepositoryClient(repositoryType, folder);
this.folder = folder;
}
static RepositoryClient createRepositoryClient(String repositoryType, File folder) throws IOException {
String httpProtocolUrl = given(VndMediaType.REPOSITORY)
.when()
.get(TestData.getDefaultRepositoryUrl(repositoryType))
.then()
.statusCode(HttpStatus.SC_OK)
.extract()
.path("_links.httpProtocol.href");
return REPOSITORY_CLIENT_FACTORY.create(repositoryType, httpProtocolUrl, ADMIN_USERNAME, ADMIN_PASSWORD, folder);
}
void createAndCommitFile(String fileName, String content) throws IOException {
Files.write(content, new File(folder, fileName), Charsets.UTF_8);
repositoryClient.getAddCommand().add(fileName);
commit("added " + fileName);
}
Changeset commit(String message) throws IOException {
Changeset changeset = repositoryClient.getCommitCommand().commit(
new Person("scmadmin", "scmadmin@scm-manager.org"), message
);
if (repositoryClient.isCommandSupported(ClientCommand.PUSH)) {
repositoryClient.getPushCommand().push();
}
return changeset;
}
}

View File

@@ -16,10 +16,18 @@ public class RestUtil {
return REST_BASE_URL.resolve(path);
}
public static final String ADMIN_USERNAME = "scmadmin";
public static final String ADMIN_PASSWORD = "scmadmin";
public static RequestSpecification given(String mediaType) {
return RestAssured.given()
.contentType(mediaType)
.accept(mediaType)
.auth().preemptive().basic("scmadmin", "scmadmin");
.auth().preemptive().basic(ADMIN_USERNAME, ADMIN_PASSWORD);
}
public static RequestSpecification given() {
return RestAssured.given()
.auth().preemptive().basic(ADMIN_USERNAME, ADMIN_PASSWORD);
}
}

View File

@@ -32,158 +32,133 @@
package sonia.scm.repository.spi;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.base.Strings;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.GitUtil;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.util.Util;
//~--- JDK imports ------------------------------------------------------------
import java.io.Closeable;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
*
* @author Sebastian Sdorra
*/
public class GitCatCommand extends AbstractGitCommand implements CatCommand
{
/**
* the logger for GitCatCommand
*/
private static final Logger logger =
LoggerFactory.getLogger(GitCatCommand.class);
public class GitCatCommand extends AbstractGitCommand implements CatCommand {
//~--- constructors ---------------------------------------------------------
private static final Logger logger = LoggerFactory.getLogger(GitCatCommand.class);
/**
* Constructs ...
*
*
*
* @param context
* @param repository
*/
public GitCatCommand(GitContext context,
sonia.scm.repository.Repository repository)
{
public GitCatCommand(GitContext context, sonia.scm.repository.Repository repository) {
super(context, repository);
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param request
* @param output
*
* @throws IOException
* @throws RepositoryException
*/
@Override
public void getCatResult(CatCommandRequest request, OutputStream output)
throws IOException, RepositoryException
{
public void getCatResult(CatCommandRequest request, OutputStream output) throws IOException, RepositoryException {
logger.debug("try to read content for {}", request);
org.eclipse.jgit.lib.Repository repo = open();
ObjectId revId = getCommitOrDefault(repo, request.getRevision());
getContent(repo, revId, request.getPath(), output);
try (ClosableObjectLoaderContainer closableObjectLoaderContainer = getLoader(request)) {
closableObjectLoaderContainer.objectLoader.copyTo(output);
}
}
/**
* Method description
*
*
*
* @param repo
* @param revId
* @param path
* @param output
*
*
* @throws IOException
* @throws RepositoryException
*/
void getContent(org.eclipse.jgit.lib.Repository repo, ObjectId revId,
String path, OutputStream output)
throws IOException, RepositoryException
{
TreeWalk treeWalk = null;
RevWalk revWalk = null;
@Override
public InputStream getCatResultStream(CatCommandRequest request) throws IOException, RepositoryException {
logger.debug("try to read content for {}", request);
return new InputStreamWrapper(getLoader(request));
}
try
{
treeWalk = new TreeWalk(repo);
void getContent(org.eclipse.jgit.lib.Repository repo, ObjectId revId, String path, OutputStream output) throws IOException, RepositoryException {
try (ClosableObjectLoaderContainer closableObjectLoaderContainer = getLoader(repo, revId, path)) {
closableObjectLoaderContainer.objectLoader.copyTo(output);
}
}
private ClosableObjectLoaderContainer getLoader(CatCommandRequest request) throws IOException, RepositoryException {
org.eclipse.jgit.lib.Repository repo = open();
ObjectId revId = getCommitOrDefault(repo, request.getRevision());
return getLoader(repo, revId, request.getPath());
}
private ClosableObjectLoaderContainer getLoader(Repository repo, ObjectId revId, String path) throws IOException, RepositoryException {
TreeWalk treeWalk = new TreeWalk(repo);
treeWalk.setRecursive(Util.nonNull(path).contains("/"));
if (logger.isDebugEnabled())
{
logger.debug("load content for {} at {}", path, revId.name());
RevWalk revWalk = new RevWalk(repo);
RevCommit entry = null;
try {
entry = revWalk.parseCommit(revId);
} catch (MissingObjectException e) {
throw new RevisionNotFoundException(revId.getName());
}
revWalk = new RevWalk(repo);
RevCommit entry = revWalk.parseCommit(revId);
RevTree revTree = entry.getTree();
if (revTree != null)
{
if (revTree != null) {
treeWalk.addTree(revTree);
}
else
{
} else {
logger.error("could not find tree for {}", revId.name());
}
treeWalk.setFilter(PathFilter.create(path));
if (treeWalk.next())
{
// Path exists
if (treeWalk.getFileMode(0).getObjectType() == Constants.OBJ_BLOB)
{
if (treeWalk.next() && treeWalk.getFileMode(0).getObjectType() == Constants.OBJ_BLOB) {
ObjectId blobId = treeWalk.getObjectId(0);
ObjectLoader loader = repo.open(blobId);
loader.copyTo(output);
return new ClosableObjectLoaderContainer(loader, treeWalk, revWalk);
} else {
throw new PathNotFoundException(path);
}
}
else
{
// Not a blob, its something else (tree, gitlink)
throw new PathNotFoundException(path);
private static class ClosableObjectLoaderContainer implements Closeable {
private final ObjectLoader objectLoader;
private final TreeWalk treeWalk;
private final RevWalk revWalk;
private ClosableObjectLoaderContainer(ObjectLoader objectLoader, TreeWalk treeWalk, RevWalk revWalk) {
this.objectLoader = objectLoader;
this.treeWalk = treeWalk;
this.revWalk = revWalk;
}
}
else
{
throw new PathNotFoundException(path);
}
}
finally
{
@Override
public void close() {
GitUtil.release(revWalk);
GitUtil.release(treeWalk);
}
}
private static class InputStreamWrapper extends FilterInputStream {
private final ClosableObjectLoaderContainer container;
private InputStreamWrapper(ClosableObjectLoaderContainer container) throws IOException {
super(container.objectLoader.openStream());
this.container = container;
}
@Override
public void close() throws IOException {
try {
super.close();
} finally {
container.close();
}
}
}
}

View File

@@ -32,19 +32,17 @@
package sonia.scm.repository.spi;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Test;
import sonia.scm.repository.GitConstants;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RepositoryException;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import sonia.scm.repository.RevisionNotFoundException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import sonia.scm.repository.GitConstants;
import java.io.InputStream;
import static org.junit.Assert.assertEquals;
/**
* Unit tests for {@link GitCatCommand}.
@@ -53,15 +51,8 @@ import sonia.scm.repository.GitConstants;
*
* @author Sebastian Sdorra
*/
public class GitCatCommandTest extends AbstractGitCommandTestBase
{
public class GitCatCommandTest extends AbstractGitCommandTestBase {
/**
* Tests cat command with default branch.
*
* @throws IOException
* @throws RepositoryException
*/
@Test
public void testDefaultBranch() throws IOException, RepositoryException {
// without default branch, the repository head should be used
@@ -75,16 +66,8 @@ public class GitCatCommandTest extends AbstractGitCommandTestBase
assertEquals("a and b", execute(request));
}
/**
* Method description
*
*
* @throws IOException
* @throws RepositoryException
*/
@Test
public void testCat() throws IOException, RepositoryException
{
public void testCat() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("a.txt");
@@ -92,36 +75,46 @@ public class GitCatCommandTest extends AbstractGitCommandTestBase
assertEquals("a and b", execute(request));
}
/**
* Method description
*
*
* @throws IOException
* @throws RepositoryException
*/
@Test
public void testSimpleCat() throws IOException, RepositoryException
{
public void testSimpleCat() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("b.txt");
assertEquals("b", execute(request));
}
/**
* Method description
*
*
* @param request
*
* @return
*
* @throws IOException
* @throws RepositoryException
*/
private String execute(CatCommandRequest request)
throws IOException, RepositoryException
{
@Test(expected = PathNotFoundException.class)
public void testUnknownFile() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("unknown");
execute(request);
}
@Test(expected = RevisionNotFoundException.class)
public void testUnknownRevision() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setRevision("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
request.setPath("a.txt");
execute(request);
}
@Test
public void testSimpleStream() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("b.txt");
InputStream catResultStream = new GitCatCommand(createContext(), repository).getCatResultStream(request);
assertEquals('b', catResultStream.read());
assertEquals('\n', catResultStream.read());
assertEquals(-1, catResultStream.read());
catResultStream.close();
}
private String execute(CatCommandRequest request) throws IOException, RepositoryException {
String content = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();

View File

@@ -33,71 +33,44 @@
package sonia.scm.repository.spi;
//~--- non-JDK imports --------------------------------------------------------
import com.aragost.javahg.commands.ExecutionException;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryException;
import sonia.scm.web.HgUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
*
* @author Sebastian Sdorra
*/
public class HgCatCommand extends AbstractCommand implements CatCommand
{
public class HgCatCommand extends AbstractCommand implements CatCommand {
/**
* Constructs ...
*
*
* @param context
* @param repository
*/
HgCatCommand(HgCommandContext context, Repository repository)
{
HgCatCommand(HgCommandContext context, Repository repository) {
super(context, repository);
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param request
* @param output
*
* @throws IOException
* @throws RepositoryException
*/
@Override
public void getCatResult(CatCommandRequest request, OutputStream output)
throws IOException, RepositoryException
{
public void getCatResult(CatCommandRequest request, OutputStream output) throws IOException, RepositoryException {
InputStream input = getCatResultStream(request);
try {
ByteStreams.copy(input, output);
} finally {
Closeables.close(input, true);
}
}
@Override
public InputStream getCatResultStream(CatCommandRequest request) throws IOException, RepositoryException {
com.aragost.javahg.commands.CatCommand cmd =
com.aragost.javahg.commands.CatCommand.on(open());
cmd.rev(HgUtil.getRevision(request.getRevision()));
InputStream input = null;
try
{
input = cmd.execute(request.getPath());
ByteStreams.copy(input, output);
}
finally
{
Closeables.close(input, true);
try {
return cmd.execute(request.getPath());
} catch (ExecutionException e) {
throw new RepositoryException(e);
}
}
}

View File

@@ -33,36 +33,19 @@
package sonia.scm.repository.spi;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Test;
import sonia.scm.repository.RepositoryException;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
*
* @author Sebastian Sdorra
*/
public class HgCatCommandTest extends AbstractHgCommandTestBase
{
import static org.junit.Assert.assertEquals;
public class HgCatCommandTest extends AbstractHgCommandTestBase {
/**
* Method description
*
*
* @throws IOException
* @throws RepositoryException
*/
@Test
public void testCat() throws IOException, RepositoryException
{
public void testCat() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("a.txt");
@@ -70,48 +53,48 @@ public class HgCatCommandTest extends AbstractHgCommandTestBase
assertEquals("a", execute(request));
}
/**
* Method description
*
*
* @throws IOException
* @throws RepositoryException
*/
@Test
public void testSimpleCat() throws IOException, RepositoryException
{
public void testSimpleCat() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("b.txt");
assertEquals("b", execute(request));
}
/**
* Method description
*
*
* @param request
*
* @return
*
* @throws IOException
* @throws RepositoryException
*/
private String execute(CatCommandRequest request)
throws IOException, RepositoryException
{
String content = null;
@Test(expected = RepositoryException.class)
public void testUnknownFile() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("unknown");
execute(request);
}
@Test(expected = RepositoryException.class)
public void testUnknownRevision() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setRevision("abc");
request.setPath("a.txt");
execute(request);
}
@Test
public void testSimpleStream() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("b.txt");
InputStream catResultStream = new HgCatCommand(cmdContext, repository).getCatResultStream(request);
assertEquals('b', catResultStream.read());
assertEquals('\n', catResultStream.read());
assertEquals(-1, catResultStream.read());
catResultStream.close();
}
private String execute(CatCommandRequest request) throws IOException, RepositoryException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
new HgCatCommand(cmdContext, repository).getCatResult(request, baos);
}
finally
{
content = baos.toString().trim();
}
return content;
return baos.toString().trim();
}
}

View File

@@ -37,22 +37,26 @@ package sonia.scm.repository.spi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNProperties;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.admin.SVNLookClient;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.SvnUtil;
//~--- JDK imports ------------------------------------------------------------
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
//~--- JDK imports ------------------------------------------------------------
/**
*
* @author Sebastian Sdorra
@@ -120,6 +124,16 @@ public class SvnCatCommand extends AbstractSvnCommand implements CatCommand
}
}
@Override
public InputStream getCatResultStream(CatCommandRequest request) throws IOException, RepositoryException {
// There seems to be no method creating an input stream as a result, so
// we have no other possibility then to copy the content into a buffer and
// stream it from there.
ByteArrayOutputStream output = new ByteArrayOutputStream();
getCatResult(request, output);
return new ByteArrayInputStream(output.toByteArray());
}
/**
* Method description
*
@@ -146,6 +160,17 @@ public class SvnCatCommand extends AbstractSvnCommand implements CatCommand
}
catch (SVNException ex)
{
handleSvnException(request, ex);
}
}
private void handleSvnException(CatCommandRequest request, SVNException ex) throws RepositoryException {
int svnErrorCode = ex.getErrorMessage().getErrorCode().getCode();
if (SVNErrorCode.FS_NOT_FOUND.getCode() == svnErrorCode) {
throw new PathNotFoundException(request.getPath());
} else if (SVNErrorCode.FS_NO_SUCH_REVISION.getCode() == svnErrorCode) {
throw new RevisionNotFoundException(request.getRevision());
} else {
throw new RepositoryException("could not get content from revision", ex);
}
}

View File

@@ -32,36 +32,23 @@
package sonia.scm.repository.spi;
//~--- non-JDK imports --------------------------------------------------------
import org.junit.Test;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RepositoryException;
import static org.junit.Assert.*;
//~--- JDK imports ------------------------------------------------------------
import sonia.scm.repository.RevisionNotFoundException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
*
* @author Sebastian Sdorra
*/
public class SvnCatCommandTest extends AbstractSvnCommandTestBase
{
import static org.junit.Assert.assertEquals;
//~--- JDK imports ------------------------------------------------------------
public class SvnCatCommandTest extends AbstractSvnCommandTestBase {
/**
* Method description
*
*
* @throws IOException
* @throws RepositoryException
*/
@Test
public void testCat() throws IOException, RepositoryException
{
public void testCat() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("a.txt");
@@ -69,36 +56,50 @@ public class SvnCatCommandTest extends AbstractSvnCommandTestBase
assertEquals("a", execute(request));
}
/**
* Method description
*
*
* @throws IOException
* @throws RepositoryException
*/
@Test
public void testSimpleCat() throws IOException, RepositoryException
{
public void testSimpleCat() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("c/d.txt");
assertEquals("d", execute(request));
}
/**
* Method description
*
*
* @param request
*
* @return
*
* @throws IOException
* @throws RepositoryException
*/
private String execute(CatCommandRequest request)
throws IOException, RepositoryException
{
@Test(expected = PathNotFoundException.class)
public void testUnknownFile() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("unknown");
request.setRevision("1");
execute(request);
}
@Test(expected = RevisionNotFoundException.class)
public void testUnknownRevision() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("a.txt");
request.setRevision("42");
execute(request);
}
@Test
public void testSimpleStream() throws IOException, RepositoryException {
CatCommandRequest request = new CatCommandRequest();
request.setPath("a.txt");
request.setRevision("1");
InputStream catResultStream = new SvnCatCommand(createContext(), repository).getCatResultStream(request);
assertEquals('a', catResultStream.read());
assertEquals('\n', catResultStream.read());
assertEquals(-1, catResultStream.read());
catResultStream.close();
}
private String execute(CatCommandRequest request) throws IOException, RepositoryException {
String content = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();

View File

@@ -227,6 +227,17 @@
<version>${mustache.version}</version>
</dependency>
<dependency>
<groupId>com.github.sdorra</groupId>
<artifactId>spotter-core</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>1.18</version>
</dependency>
<!-- test scope -->
<dependency>

View File

@@ -35,26 +35,20 @@ package sonia.scm.api.rest.resources;
//~--- non-JDK imports --------------------------------------------------------
import com.google.common.io.Closeables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.api.CatCommandBuilder;
import sonia.scm.repository.api.RepositoryService;
//~--- JDK imports ------------------------------------------------------------
import java.io.IOException;
import java.io.OutputStream;
import sonia.scm.util.IOUtil;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import sonia.scm.util.IOUtil;
import java.io.IOException;
import java.io.OutputStream;
/**
*

View File

@@ -0,0 +1,154 @@
package sonia.scm.api.v2.resources;
import com.github.sdorra.spotter.ContentType;
import com.github.sdorra.spotter.ContentTypes;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RepositoryException;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
import sonia.scm.util.IOUtil;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.HEAD;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.StreamingOutput;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
public class ContentResource {
private static final Logger LOG = LoggerFactory.getLogger(ContentResource.class);
private static final int HEAD_BUFFER_SIZE = 1024;
private final RepositoryServiceFactory serviceFactory;
@Inject
public ContentResource(RepositoryServiceFactory serviceFactory) {
this.serviceFactory = serviceFactory;
}
/**
* Returns the content of a file for the given revision in the repository. The content type depends on the file
* content and can be discovered calling <code>HEAD</code> on the same URL. If a programming languge could be
* recognized, this will be given in the header <code>Language</code>.
*
* @param namespace the namespace of the repository
* @param name the name of the repository
* @param revision the revision
* @param path The path of the file
*
*/
@GET
@Path("{revision}/{path: .*}")
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
@ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to read the repository"),
@ResponseCode(code = 404, condition = "not found, no repository with the specified name available in the namespace"),
@ResponseCode(code = 500, condition = "internal server error")
})
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision, @PathParam("path") String path) {
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
StreamingOutput stream = createStreamingOutput(namespace, name, revision, path, repositoryService);
Response.ResponseBuilder responseBuilder = Response.ok(stream);
return createContentHeader(namespace, name, revision, path, repositoryService, responseBuilder);
} catch (RepositoryNotFoundException e) {
LOG.debug("path '{}' not found in repository {}/{}", path, namespace, name, e);
return Response.status(Status.NOT_FOUND).build();
}
}
private StreamingOutput createStreamingOutput(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision, @PathParam("path") String path, RepositoryService repositoryService) {
return os -> {
try {
repositoryService.getCatCommand().setRevision(revision).retriveContent(os, path);
os.close();
} catch (PathNotFoundException e) {
LOG.debug("path '{}' not found in repository {}/{}", path, namespace, name, e);
throw new WebApplicationException(Status.NOT_FOUND);
} catch (RepositoryException e) {
LOG.info("error reading repository resource {} from {}/{}", path, namespace, name, e);
throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
}
};
}
/**
* Returns the content type and the programming language (if it can be detected) of a file for the given revision in
* the repository. The programming language will be given in the header <code>Language</code>.
*
* @param namespace the namespace of the repository
* @param name the name of the repository
* @param revision the revision
* @param path The path of the file
*
*/
@HEAD
@Path("{revision}/{path: .*}")
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
@ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to read the repository"),
@ResponseCode(code = 404, condition = "not found, no repository with the specified name available in the namespace"),
@ResponseCode(code = 500, condition = "internal server error")
})
public Response metadata(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision, @PathParam("path") String path) {
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
Response.ResponseBuilder responseBuilder = Response.ok();
return createContentHeader(namespace, name, revision, path, repositoryService, responseBuilder);
} catch (RepositoryNotFoundException e) {
LOG.debug("path '{}' not found in repository {}/{}", path, namespace, name, e);
return Response.status(Status.NOT_FOUND).build();
}
}
private Response createContentHeader(String namespace, String name, String revision, String path, RepositoryService repositoryService, Response.ResponseBuilder responseBuilder) {
try {
appendContentHeader(path, getHead(revision, path, repositoryService), responseBuilder);
} catch (PathNotFoundException e) {
LOG.debug("path '{}' not found in repository {}/{}", path, namespace, name, e);
return Response.status(Status.NOT_FOUND).build();
} catch (RevisionNotFoundException e) {
LOG.debug("revision '{}' not found in repository {}/{}", revision, namespace, name, e);
return Response.status(Status.NOT_FOUND).build();
} catch (IOException | RepositoryException e) {
LOG.info("error reading repository resource {} from {}/{}", path, namespace, name, e);
return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
}
return responseBuilder.build();
}
private void appendContentHeader(String path, byte[] head, Response.ResponseBuilder responseBuilder) {
ContentType contentType = ContentTypes.detect(path, head);
responseBuilder.header("Content-Type", contentType.getRaw());
contentType.getLanguage().ifPresent(language -> responseBuilder.header("Language", language));
}
private byte[] getHead(String revision, String path, RepositoryService repositoryService) throws IOException, RepositoryException {
InputStream stream = repositoryService.getCatCommand().setRevision(revision).getStream(path);
try {
byte[] buffer = new byte[HEAD_BUFFER_SIZE];
int length = stream.read(buffer);
if (length < buffer.length) {
return Arrays.copyOf(buffer, length);
} else {
return buffer;
}
} finally {
IOUtil.close(stream);
}
}
}

View File

@@ -35,6 +35,7 @@ public class RepositoryResource {
private final Provider<BranchRootResource> branchRootResource;
private final Provider<ChangesetRootResource> changesetRootResource;
private final Provider<SourceRootResource> sourceRootResource;
private final Provider<ContentResource> contentResource;
private final Provider<PermissionRootResource> permissionRootResource;
@Inject
@@ -44,7 +45,7 @@ public class RepositoryResource {
Provider<TagRootResource> tagRootResource,
Provider<BranchRootResource> branchRootResource,
Provider<ChangesetRootResource> changesetRootResource,
Provider<SourceRootResource> sourceRootResource, Provider<PermissionRootResource> permissionRootResource) {
Provider<SourceRootResource> sourceRootResource, Provider<ContentResource> contentResource, Provider<PermissionRootResource> permissionRootResource) {
this.dtoToRepositoryMapper = dtoToRepositoryMapper;
this.manager = manager;
this.repositoryToDtoMapper = repositoryToDtoMapper;
@@ -53,6 +54,7 @@ public class RepositoryResource {
this.branchRootResource = branchRootResource;
this.changesetRootResource = changesetRootResource;
this.sourceRootResource = sourceRootResource;
this.contentResource = contentResource;
this.permissionRootResource = permissionRootResource;
}
@@ -151,6 +153,11 @@ public class RepositoryResource {
return sourceRootResource.get();
}
@Path("content/")
public ContentResource content() {
return contentResource.get();
}
@Path("permissions/")
public PermissionRootResource permissions() {
return permissionRootResource.get();

View File

@@ -45,7 +45,7 @@ public class BranchRootResourceTest {
public void prepareEnvironment() throws Exception {
BranchCollectionToDtoMapper branchCollectionToDtoMapper = new BranchCollectionToDtoMapper(branchToDtoMapper, resourceLinks);
BranchRootResource branchRootResource = new BranchRootResource(serviceFactory, branchToDtoMapper, branchCollectionToDtoMapper);
RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(new RepositoryResource(null, null, null, null, MockProvider.of(branchRootResource), null, null, null)), null);
RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(new RepositoryResource(null, null, null, null, MockProvider.of(branchRootResource), null, null, null, null)), null);
dispatcher.getRegistry().addSingletonResource(repositoryRootResource);
when(serviceFactory.create(new NamespaceAndName("space", "repo"))).thenReturn(service);

View File

@@ -0,0 +1,186 @@
package sonia.scm.api.v2.resources;
import com.google.common.io.Resources;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.PathNotFoundException;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.api.CatCommandBuilder;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.AdditionalMatchers.not;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class ContentResourceTest {
private static final String NAMESPACE = "space";
private static final String REPO_NAME = "name";
private static final String REV = "rev";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private RepositoryServiceFactory repositoryServiceFactory;
@InjectMocks
private ContentResource contentResource;
private CatCommandBuilder catCommand;
@Before
public void initService() throws Exception {
NamespaceAndName existingNamespaceAndName = new NamespaceAndName(NAMESPACE, REPO_NAME);
RepositoryService repositoryService = repositoryServiceFactory.create(existingNamespaceAndName);
catCommand = repositoryService.getCatCommand();
when(catCommand.setRevision(REV)).thenReturn(catCommand);
// defaults for unknown things
doThrow(new RepositoryNotFoundException("x")).when(repositoryServiceFactory).create(not(eq(existingNamespaceAndName)));
doThrow(new PathNotFoundException("x")).when(catCommand).getStream(any());
}
@Test
public void shouldReadSimpleFile() throws Exception {
mockContent("file", "Hello".getBytes());
Response response = contentResource.get(NAMESPACE, REPO_NAME, REV, "file");
assertEquals(200, response.getStatus());
ByteArrayOutputStream baos = readOutputStream(response);
assertEquals("Hello", baos.toString());
}
@Test
public void shouldHandleMissingFile() {
Response response = contentResource.get(NAMESPACE, REPO_NAME, REV, "doesNotExist");
assertEquals(404, response.getStatus());
}
@Test
public void shouldHandleMissingRepository() {
Response response = contentResource.get("no", "repo", REV, "anything");
assertEquals(404, response.getStatus());
}
@Test
public void shouldRecognizeTikaSourceCode() throws Exception {
mockContentFromResource("SomeGoCode.go");
Response response = contentResource.get(NAMESPACE, REPO_NAME, REV, "SomeGoCode.go");
assertEquals(200, response.getStatus());
assertEquals("GO", response.getHeaderString("Language"));
assertEquals("text/x-go", response.getHeaderString("Content-Type"));
}
@Test
public void shouldRecognizeSpecialSourceCode() throws Exception {
mockContentFromResource("Dockerfile");
Response response = contentResource.get(NAMESPACE, REPO_NAME, REV, "Dockerfile");
assertEquals(200, response.getStatus());
assertEquals("DOCKERFILE", response.getHeaderString("Language"));
assertEquals("text/plain", response.getHeaderString("Content-Type"));
}
@Test
public void shouldRecognizeShebangSourceCode() throws Exception {
mockContentFromResource("someScript.sh");
Response response = contentResource.get(NAMESPACE, REPO_NAME, REV, "someScript.sh");
assertEquals(200, response.getStatus());
assertEquals("PYTHON", response.getHeaderString("Language"));
assertEquals("application/x-sh", response.getHeaderString("Content-Type"));
}
@Test
public void shouldHandleRandomByteFile() throws Exception {
mockContentFromResource("JustBytes");
Response response = contentResource.get(NAMESPACE, REPO_NAME, REV, "JustBytes");
assertEquals(200, response.getStatus());
assertFalse(response.getHeaders().containsKey("Language"));
assertEquals("application/octet-stream", response.getHeaderString("Content-Type"));
}
@Test
public void shouldNotReadCompleteFileForHead() throws Exception {
FailingAfterSomeBytesStream stream = new FailingAfterSomeBytesStream();
doAnswer(invocation -> stream).when(catCommand).getStream(eq("readHeadOnly"));
Response response = contentResource.metadata(NAMESPACE, REPO_NAME, REV, "readHeadOnly");
assertEquals(200, response.getStatus());
assertEquals("application/octet-stream", response.getHeaderString("Content-Type"));
assertTrue("stream has to be closed after reading head", stream.isClosed());
}
private void mockContentFromResource(String fileName) throws Exception {
URL url = Resources.getResource(fileName);
mockContent(fileName, Resources.toByteArray(url));
}
private void mockContent(String path, byte[] content) throws Exception {
doAnswer(invocation -> {
OutputStream outputStream = (OutputStream) invocation.getArguments()[0];
outputStream.write(content);
outputStream.close();
return null;
}).when(catCommand).retriveContent(any(), eq(path));
doAnswer(invocation -> new ByteArrayInputStream(content)).when(catCommand).getStream(eq(path));
}
private ByteArrayOutputStream readOutputStream(Response response) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
((StreamingOutput) response.getEntity()).write(baos);
return baos;
}
private static class FailingAfterSomeBytesStream extends InputStream {
private int bytesRead = 0;
private boolean closed = false;
@Override
public int read() {
if (++bytesRead > 1024) {
fail("read too many bytes");
}
return 0;
}
@Override
public void close() throws IOException {
closed = true;
}
public boolean isClosed() {
return closed;
}
}
}

View File

@@ -53,11 +53,9 @@ import static org.mockito.MockitoAnnotations.initMocks;
@RunWith(MockitoJUnitRunner.Silent.class)
@Slf4j
public class PermissionRootResourceTest {
public static final String REPOSITORY_NAMESPACE = "repo_namespace";
public static final String REPOSITORY_NAME = "repo";
private static final String REPOSITORY_NAMESPACE = "repo_namespace";
private static final String REPOSITORY_NAME = "repo";
private static final String PERMISSION_NAME = "perm";
private static final String PATH_OF_ALL_PERMISSIONS = REPOSITORY_NAMESPACE + "/" + REPOSITORY_NAME + "/permissions/";
private static final String PATH_OF_ONE_PERMISSION = PATH_OF_ALL_PERMISSIONS + PERMISSION_NAME;
private static final String PERMISSION_TEST_PAYLOAD = "{ \"name\" : \"permission_name\", \"type\" : \"READ\" }";
@@ -93,7 +91,6 @@ public class PermissionRootResourceTest {
.content(PERMISSION_TEST_PAYLOAD)
.path(PATH_OF_ONE_PERMISSION);
private final Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
@Rule
@@ -102,7 +99,6 @@ public class PermissionRootResourceTest {
@Mock
private RepositoryManager repositoryManager;
private final URI baseUri = URI.create("/");
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
@@ -112,17 +108,15 @@ public class PermissionRootResourceTest {
@InjectMocks
private PermissionDtoToPermissionMapperImpl permissionDtoToPermissionMapper;
private PermissionRootResource permissionRootResource;
@BeforeEach
@Before
public void prepareEnvironment() {
initMocks(this);
permissionRootResource = spy(new PermissionRootResource(permissionDtoToPermissionMapper, permissionToPermissionDtoMapper, resourceLinks, repositoryManager));
RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider
.of(new RepositoryResource(null, null, null, null, null, null, null, MockProvider.of(permissionRootResource))), null);
.of(new RepositoryResource(null, null, null, null, null, null, null,null, MockProvider.of(permissionRootResource))), null);
dispatcher.getRegistry().addSingletonResource(repositoryRootResource);
dispatcher.getProviderFactory().registerProvider(RepositoryNotFoundExceptionMapper.class);
dispatcher.getProviderFactory().registerProvider(PermissionNotFoundExceptionMapper.class);
@@ -130,31 +124,49 @@ public class PermissionRootResourceTest {
dispatcher.getProviderFactory().registerProvider(AuthorizationExceptionMapper.class);
}
@TestFactory
@DisplayName("test endpoints on missing repository and user is Admin")
Stream<DynamicTest> missedRepositoryTestFactory() {
return createDynamicTestsToAssertResponses(
requestGETAllPermissions.expectedResponseStatus(404),
requestGETPermission.expectedResponseStatus(404),
requestPOSTPermission.expectedResponseStatus(404),
requestDELETEPermission.expectedResponseStatus(404),
requestPUTPermission.expectedResponseStatus(404));
}
@TestFactory
@DisplayName("test endpoints on missing permission and user is Admin")
Stream<DynamicTest> missedPermissionTestFactory() {
authorizedUserHasARepository();
return createDynamicTestsToAssertResponses(
requestGETPermission.expectedResponseStatus(404),
requestPOSTPermission.expectedResponseStatus(201),
requestGETAllPermissions.expectedResponseStatus(200),
requestDELETEPermission.expectedResponseStatus(204),
requestPUTPermission.expectedResponseStatus(404));
}
@TestFactory
@DisplayName("test endpoints on missing permission and user is not Admin")
Stream<DynamicTest> missedPermissionUserForbiddenTestFactory() {
Repository mockRepository = mock(Repository.class);
when(mockRepository.getId()).thenReturn(REPOSITORY_NAME);
doThrow(AuthorizationException.class).when(permissionRootResource).checkUserPermitted(mockRepository);
when(repositoryManager.get(any(NamespaceAndName.class))).thenReturn(mockRepository);
return createDynamicTestsToAssertResponses(
requestGETPermission.expectedResponseStatus(401),
requestPOSTPermission.expectedResponseStatus(401),
requestGETAllPermissions.expectedResponseStatus(401),
requestDELETEPermission.expectedResponseStatus(401),
requestPUTPermission.expectedResponseStatus(401));
}
@Test
public void shouldGetAllPermissions() {
authorizedUserHasARepositoryWithPermissions(TEST_PERMISSIONS);
assertExpectedRequest(requestGETAllPermissions
.expectedResponseStatus(200)
.responseValidator((response) -> {
String body = response.getContentAsString();
ObjectMapper mapper = new ObjectMapper();
try {
List<PermissionDto> actualPermissionDtos = mapper.readValue(body, new TypeReference<List<PermissionDto>>() {
});
assertThat(actualPermissionDtos)
.as("response payload match permission object models")
.hasSize(TEST_PERMISSIONS.size())
.usingRecursiveFieldByFieldElementComparator()
.containsExactlyInAnyOrder(getExpectedPermissionDtos(TEST_PERMISSIONS))
;
} catch (IOException e) {
fail();
assertGettingExpectedPermissions(ImmutableList.copyOf(TEST_PERMISSIONS));
}
})
);
}
@Test
public void shouldGetPermissionByName() {
@@ -179,7 +191,6 @@ public class PermissionRootResourceTest {
);
}
@Test
public void shouldGetCreatedPermissions() {
authorizedUserHasARepositoryWithPermissions(TEST_PERMISSIONS);
@@ -207,7 +218,6 @@ public class PermissionRootResourceTest {
);
}
@Test
public void shouldGetUpdatedPermissions() {
authorizedUserHasARepositoryWithPermissions(TEST_PERMISSIONS);
@@ -287,7 +297,6 @@ public class PermissionRootResourceTest {
);
}
private PermissionDto[] getExpectedPermissionDtos(ArrayList<Permission> permissions) {
return permissions
.stream()
@@ -309,30 +318,6 @@ public class PermissionRootResourceTest {
return result;
}
@TestFactory
@DisplayName("test endpoints on missing repository and user is Admin")
Stream<DynamicTest> missedRepositoryTestFactory() {
return createDynamicTestsToAssertResponses(
requestGETAllPermissions.expectedResponseStatus(404),
requestGETPermission.expectedResponseStatus(404),
requestPOSTPermission.expectedResponseStatus(404),
requestDELETEPermission.expectedResponseStatus(404),
requestPUTPermission.expectedResponseStatus(404));
}
@TestFactory
@DisplayName("test endpoints on missing permission and user is Admin")
Stream<DynamicTest> missedPermissionTestFactory() {
authorizedUserHasARepository();
return createDynamicTestsToAssertResponses(
requestGETPermission.expectedResponseStatus(404),
requestPOSTPermission.expectedResponseStatus(201),
requestGETAllPermissions.expectedResponseStatus(200),
requestDELETEPermission.expectedResponseStatus(204),
requestPUTPermission.expectedResponseStatus(404));
}
private Repository authorizedUserHasARepository() {
Repository mockRepository = mock(Repository.class);
when(mockRepository.getId()).thenReturn(REPOSITORY_NAME);
@@ -347,25 +332,7 @@ public class PermissionRootResourceTest {
when(authorizedUserHasARepository().getPermissions()).thenReturn(permissions);
}
@TestFactory
@DisplayName("test endpoints on missing permission and user is not Admin")
Stream<DynamicTest> missedPermissionUserForbiddenTestFactory() {
Repository mockRepository = mock(Repository.class);
when(mockRepository.getId()).thenReturn(REPOSITORY_NAME);
doThrow(AuthorizationException.class).when(permissionRootResource).checkUserPermitted(mockRepository);
when(repositoryManager.get(any(NamespaceAndName.class))).thenReturn(mockRepository);
return createDynamicTestsToAssertResponses(
requestGETPermission.expectedResponseStatus(401),
requestPOSTPermission.expectedResponseStatus(401),
requestGETAllPermissions.expectedResponseStatus(401),
requestDELETEPermission.expectedResponseStatus(401),
requestPUTPermission.expectedResponseStatus(401));
}
private Stream<DynamicTest> createDynamicTestsToAssertResponses(ExpectedRequest... expectedRequests) {
return Stream.of(expectedRequests)
.map(entry -> dynamicTest("the endpoint " + entry.description + " should return the status code " + entry.expectedResponseStatus, () -> assertExpectedRequest(entry)));
}

View File

@@ -74,7 +74,7 @@ public class RepositoryRootResourceTest {
@Before
public void prepareEnvironment() {
initMocks(this);
RepositoryResource repositoryResource = new RepositoryResource(repositoryToDtoMapper, dtoToRepositoryMapper, repositoryManager, null, null, null, null, null);
RepositoryResource repositoryResource = new RepositoryResource(repositoryToDtoMapper, dtoToRepositoryMapper, repositoryManager, null, null, null, null, null, null);
RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks);
RepositoryCollectionResource repositoryCollectionResource = new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper, dtoToRepositoryMapper, resourceLinks);
RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(repositoryResource), MockProvider.of(repositoryCollectionResource));

View File

@@ -0,0 +1,8 @@
FROM ubuntu
COPY nothing /nowhere
RUN apt-get update
EXEC shutdhown -h now

Binary file not shown.

View File

@@ -0,0 +1 @@
package resources

View File

@@ -0,0 +1,6 @@
#!/usr/bin/python
for f in * ; do
ls $f
done