package controllers;
import static org.fest.assertions.Assertions.assertThat;
import static play.test.Helpers.callAction;
import static play.test.Helpers.charset;
import static play.test.Helpers.contentAsBytes;
import static play.test.Helpers.contentAsString;
import static play.test.Helpers.contentType;
import static play.test.Helpers.header;
import static play.test.Helpers.status;
import static test.AorraTestUtils.asAdminUser;
import static test.AorraTestUtils.fileStore;
import static test.AorraTestUtils.injector;
import java.io.ByteArrayInputStream;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.jcr.Session;
import models.Flag;
import models.GroupManager;
import models.User;
import org.apache.commons.io.IOUtils;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.apache.jackrabbit.api.security.user.Group;
import org.junit.Test;
import play.api.mvc.AnyContentAsText;
import play.api.mvc.Call;
import play.libs.F;
import play.libs.Json;
import play.mvc.Http.Status;
import play.mvc.Result;
import play.test.CopiedFakeRequest;
import play.test.FakeRequest;
import service.filestore.FileStore;
import service.filestore.FileStore.Permission;
import service.filestore.FlagStore;
import service.filestore.FlagStore.FlagType;
import service.filestore.JsonBuilder;
import service.filestore.roles.Admin;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
public class FileStoreControllerTest {
@Test
public void routes() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
{
final Call call =
controllers.routes.FileStoreController.filestoreJson();
assertThat(call.method()).isEqualTo("GET");
assertThat(call.url()).isEqualTo("/filestore");
}
{
final String id = UUID.randomUUID().toString();
final Call call =
controllers.routes.FileStoreController.showFile(id);
assertThat(call.method()).isEqualTo("GET");
assertThat(call.url()).isEqualTo("/file/"+id);
}
{
final String id = UUID.randomUUID().toString();
final Call call =
controllers.routes.FileStoreController.modifyFile(id);
assertThat(call.method()).isEqualTo("PUT");
assertThat(call.url()).isEqualTo("/file/"+id);
}
{
final String id = UUID.randomUUID().toString();
final Call call =
controllers.routes.FileStoreController.showFolder(id);
assertThat(call.method()).isEqualTo("GET");
assertThat(call.url()).isEqualTo("/folder/"+id);
}
{
final String id = UUID.randomUUID().toString();
final Call call =
controllers.routes.FileStoreController.modifyFolder(id);
assertThat(call.method()).isEqualTo("PUT");
assertThat(call.url()).isEqualTo("/folder/"+id);
}
{
final String id = UUID.randomUUID().toString();
final Call call =
controllers.routes.FileStoreController.mkdir(id, "foo");
assertThat(call.method()).isEqualTo("POST");
assertThat(call.url()).isEqualTo("/folder/"+id+"/folders?mkdir=foo");
}
{
final String id = UUID.randomUUID().toString();
final Call call =
controllers.routes.FileStoreController.versionList(id);
assertThat(call.method()).isEqualTo("GET");
assertThat(call.url()).isEqualTo("/file/"+id+"/versions");
}
{
final String id = UUID.randomUUID().toString();
final Call call =
controllers.routes.FileStoreController.downloadFolder(id);
assertThat(call.method()).isEqualTo("GET");
assertThat(call.url()).isEqualTo("/folder/"+id+"/archive");
}
return session;
}
});
}
@Test
public void getFilestoreJSON() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final Result result = callAction(
controllers.routes.ref.FileStoreController.filestoreJson(),
newRequest);
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final String expectedContent = (new JsonBuilder())
.toJson(fileStore().getManager(session).getFolders())
.toString();
assertThat(contentAsString(result)).contains(expectedContent);
return session;
}
});
}
@Test
public void getFlagsJSON() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final FlagStore.Manager flm =
injector().getInstance(FlagStore.class).getManager(session);
final Flag flag =
flm.setFlag(FlagType.WATCH, fm.getRoot().getIdentifier(), user);
final Result result = callAction(
controllers.routes.ref.FileStoreController.flagsJson(
"watch"),
newRequest);
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final String expectedContent = (new JsonBuilder())
.toJson(flag)
.toString();
assertThat(contentAsString(result)).isEqualTo("["+expectedContent+"]");
return session;
}
});
}
@Test
public void getFlagJSON() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final FlagStore.Manager flm =
injector().getInstance(FlagStore.class).getManager(session);
final Flag flag =
flm.setFlag(FlagType.WATCH, fm.getRoot().getIdentifier(), user);
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.flagJson(
FlagStore.FlagType.WATCH.toString(),
flag.getId()),
newRequest);
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final String expectedContent = (new JsonBuilder())
.toJson(flag)
.toString();
assertThat(contentAsString(result)).isEqualTo(expectedContent);
}
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.flagJson(
FlagStore.FlagType.EDIT.toString(),
flag.getId()),
newRequest);
assertThat(status(result)).isEqualTo(404);
}
return session;
}
});
}
@Test
public void addFlag() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final FlagStore.Manager flm =
injector().getInstance(FlagStore.class).getManager(session);
{
final ObjectNode data = Json.newObject();
data.put("targetId", fm.getRoot().getIdentifier());
final Result result = callAction(
controllers.routes.ref.FileStoreController.addFlag(
FlagStore.FlagType.WATCH.toString()),
newRequest.withJsonBody(data));
assertThat(status(result)).isEqualTo(Status.BAD_REQUEST);
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
}
{
final ObjectNode data = Json.newObject();
data.put("targetId", fm.getRoot().getIdentifier());
data.put("userId", "somebodyelse");
final Result result = callAction(
controllers.routes.ref.FileStoreController.addFlag(
FlagStore.FlagType.WATCH.toString()),
newRequest.withJsonBody(data));
assertThat(status(result)).isEqualTo(Status.FORBIDDEN);
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
}
{
final ObjectNode data = Json.newObject();
data.put("targetId", fm.getRoot().getIdentifier());
data.put("userId", user.getId());
final Result result = callAction(
controllers.routes.ref.FileStoreController.addFlag(
FlagStore.FlagType.WATCH.toString()),
newRequest.withJsonBody(data));
assertThat(status(result)).isEqualTo(Status.CREATED);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final Flag flag =
flm.getFlag(FlagType.WATCH, fm.getRoot().getIdentifier(), user);
final String expectedContent = (new JsonBuilder())
.toJson(flag)
.toString();
assertThat(contentAsString(result)).isEqualTo(expectedContent);
}
return session;
}
});
}
@Test
public void deleteFlag() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final FlagStore.Manager flm =
injector().getInstance(FlagStore.class).getManager(session);
final Flag flag =
flm.setFlag(FlagType.WATCH, fm.getRoot().getIdentifier(), user);
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.deleteFlag(
FlagStore.FlagType.WATCH.toString(),
flag.getId()),
newRequest);
assertThat(status(result)).isEqualTo(Status.NO_CONTENT);
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
assertThat(flm.hasFlag(FlagType.WATCH,
fm.getRoot().getIdentifier(), user)).isFalse();
}
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.deleteFlag(
FlagStore.FlagType.WATCH.toString(),
flag.getId()),
newRequest);
assertThat(status(result)).isEqualTo(404);
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
}
return session;
}
});
}
@Test
public void getFolderHTML() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
for (String mime : new String[]{"text/html", "*/*"}) {
final Result result = callAction(
controllers.routes.ref.FileStoreController.showFolder(
fm.getRoot().getIdentifier()),
newRequest.withHeader("Accept", mime));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("text/html");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
}
return session;
}
});
}
@Test
public void getFileHTML() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final FileStore.File file =
fm.getRoot().createFile("test.txt", "text/plain",
new ByteArrayInputStream("Some content.".getBytes()));
for (String mime : new String[]{"text/html", "*/*"}) {
final Result result = callAction(
controllers.routes.ref.FileStoreController.showFile(
file.getIdentifier()),
newRequest.withHeader("Accept", mime));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("text/html");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
}
return session;
}
});
}
@Test
public void getFolderJSON() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
for (String mime : new String[]{"application/json", "text/javascript"}){
final Result result = callAction(
controllers.routes.ref.FileStoreController.showFolder(
fm.getRoot().getIdentifier()),
newRequest.withHeader("Accept", mime));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final String expectedContent = (new JsonBuilder())
.toJsonShallow(fm.getRoot(), false)
.toString();
assertThat(contentAsString(result)).contains(expectedContent);
}
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.showFolder(
(new UUID(0, 0)).toString()),
newRequest.withHeader("Accept", "application/json"));
assertThat(status(result)).isEqualTo(404);
}
return session;
}
});
}
@Test
public void getFileJSON() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
// Non-existent ID should yield 404
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.showFile(
UUID.randomUUID().toString()),
newRequest.withHeader("Accept", "application/json"));
assertThat(status(result)).isEqualTo(404);
}
// Should be a Bad Request if called on a folder
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.showFile(
fm.getRoot().getIdentifier()),
newRequest.withHeader("Accept", "application/json"));
assertThat(status(result)).isEqualTo(400);
}
final FileStore.File file =
fm.getRoot().createFile("test.txt", "text/plain",
new ByteArrayInputStream("Some content.".getBytes()));
for (String mime : new String[]{"application/json", "text/javascript"}){
final Result result = callAction(
controllers.routes.ref.FileStoreController.showFile(
file.getIdentifier()),
newRequest.withHeader("Accept", mime));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final String expectedContent = (new JsonBuilder())
.toJsonShallow(file)
.toString();
assertThat(contentAsString(result)).isEqualTo(expectedContent);
}
return session;
}
});
}
@Test
public void modifyFolder() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final FileStore.Folder folder = fm.getRoot().createFolder("first name");
// Modifying a folder with files inside provides a better test
folder.createFile("test.txt", "text/plain",
new ByteArrayInputStream("Some content.".getBytes()));
{
ObjectNode json = Json.newObject();
json.put("id", folder.getIdentifier());
json.put("name", "second name");
final Result result = callAction(
controllers.routes.ref.FileStoreController.modifyFolder(
folder.getIdentifier()),
newRequest.withJsonBody(json));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final FileStore.Folder expectedFolder = (FileStore.Folder)
fm.getFileOrFolder("/second name");
assertThat(expectedFolder).isNotNull();
final String expectedContent = (new JsonBuilder())
.toJsonShallow(expectedFolder, false)
.toString();
assertThat(contentAsString(result)).isEqualTo(expectedContent);
}
// folder move test
{
final FileStore.Folder newfolder = fm.getRoot().createFolder("new folder");
ObjectNode json = Json.newObject();
json.put("id", folder.getIdentifier());
json.put("parent", newfolder.getIdentifier());
final Result result = callAction(
controllers.routes.ref.FileStoreController.modifyFolder(
folder.getIdentifier()),
newRequest.withJsonBody(json));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final FileStore.Folder expectedFolder = (FileStore.Folder)
fm.getFileOrFolder("/new folder/second name");
assertThat(expectedFolder).isNotNull();
final String expectedContent = (new JsonBuilder())
.toJsonShallow(expectedFolder, false)
.toString();
assertThat(contentAsString(result)).isEqualTo(expectedContent);
}
return session;
}
});
}
@Test
public void modifyFile() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final FileStore.File file =
fm.getRoot().createFile("test.txt", "text/plain",
new ByteArrayInputStream("Some content.".getBytes()));
assertThat(file.getVersions()).hasSize(1);
// file rename test
{
ObjectNode json = Json.newObject();
json.put("id", file.getIdentifier());
json.put("name", "renamed file.txt");
final Result result = callAction(
controllers.routes.ref.FileStoreController.modifyFile(
file.getIdentifier()),
newRequest.withJsonBody(json));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final FileStore.File expectedFile = (FileStore.File)
fm.getFileOrFolder("/renamed file.txt");
assertThat(expectedFile).isNotNull();
final String expectedContent = (new JsonBuilder())
.toJsonShallow(expectedFile)
.toString();
assertThat(contentAsString(result)).isEqualTo(expectedContent);
assertThat(file.getVersions()).hasSize(1);
}
// file move test
{
FileStore.Folder testFolder = fm.getRoot().createFolder("new folder");
ObjectNode json = Json.newObject();
json.put("id", file.getIdentifier());
json.put("parent", testFolder.getIdentifier());
final Result result = callAction(
controllers.routes.ref.FileStoreController.modifyFile(
file.getIdentifier()),
newRequest.withJsonBody(json));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final FileStore.File expectedFile = (FileStore.File)
fm.getFileOrFolder("/new folder/renamed file.txt");
assertThat(expectedFile).isNotNull();
final String expectedContent = (new JsonBuilder())
.toJsonShallow(expectedFile)
.toString();
assertThat(contentAsString(result)).isEqualTo(expectedContent);
assertThat(file.getVersions()).hasSize(1);
}
return session;
}
});
}
@Test
public void getFolderUnsupported() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final Result result = callAction(
controllers.routes.ref.FileStoreController.showFolder(
fm.getRoot().getIdentifier()),
newRequest.withHeader("Accept", "text/plain"));
assertThat(status(result)).isEqualTo(Status.UNSUPPORTED_MEDIA_TYPE);
return session;
}
});
}
@Test
public void getFileUnsupported() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final Result result = callAction(
controllers.routes.ref.FileStoreController.showFile(
fm.getRoot().getIdentifier()),
newRequest.withHeader("Accept", "text/plain"));
assertThat(status(result)).isEqualTo(Status.UNSUPPORTED_MEDIA_TYPE);
return session;
}
});
}
@Test
public void getVersionListJSON() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.versionList(
fm.getRoot().getIdentifier()),
newRequest.withHeader("Accept", "application/json"));
assertThat(status(result)).isEqualTo(400);
}
{
final FileStore.File file =
fm.getRoot().createFile("test.txt", "text/plain",
new ByteArrayInputStream("Some content.".getBytes()));
final Result result = callAction(
controllers.routes.ref.FileStoreController.versionList(
file.getIdentifier()),
newRequest.withHeader("Accept", "application/json"));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result)).isEqualTo("max-age=0, must-revalidate");
final FileStore.File firstVersion = file.getVersions().first();
for (JsonNode version : Json.parse(contentAsString(result))) {
assertThat(version.has("id")).isTrue();
assertThat(version.get("id").asText()).isEqualTo(
firstVersion.getIdentifier());
assertThat(version.has("name")).isTrue();
assertThat(version.get("name").asText()).isEqualTo(
firstVersion.getName());
assertThat(version.has("author")).isFalse();
assertThat(version.has("timestamp")).isTrue();
}
}
return session;
}
});
}
@Test
public void createFile() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
// Check bad request behaviour
{
JsonNode emptyJson = JsonNodeFactory.instance.objectNode();
ObjectNode missingParent = JsonNodeFactory.instance.objectNode();
missingParent.put("name", "test.txt");
ObjectNode missingName = JsonNodeFactory.instance.objectNode();
missingName.put("parent", fm.getRoot().getIdentifier());
assertThat(status(sendJson(newRequest,emptyJson))).isEqualTo(400);
assertThat(status(sendJson(newRequest,missingParent))).isEqualTo(400);
assertThat(status(sendJson(newRequest,missingName))).isEqualTo(400);
}
// Check good request behaviour
{
ObjectNode missingMime = JsonNodeFactory.instance.objectNode();
missingMime.put("name", "missingMime.txt");
missingMime.put("parent", fm.getRoot().getIdentifier());
Result result = sendJson(newRequest, missingMime);
assertThat(status(result)).isEqualTo(201);
JsonNode json = Json.parse(contentAsString(result));
assertThat(json.has("id")).isTrue();
assertThat(json.has("name")).isTrue();
assertThat(json.get("name").asText()).isEqualTo("missingMime.txt");
assertThat(json.has("mime")).isTrue();
assertThat(json.get("mime").asText()).isEqualTo("text/plain");
assertThat(json.has("parent")).isTrue();
}
{
ObjectNode includingMime = JsonNodeFactory.instance.objectNode();
includingMime.put("name", "includingMime.png");
includingMime.put("mime", "text/html");
includingMime.put("parent", fm.getRoot().getIdentifier());
Result result = sendJson(newRequest, includingMime);
assertThat(status(result)).isEqualTo(201);
JsonNode json = Json.parse(contentAsString(result));
assertThat(json.has("id")).isTrue();
assertThat(json.has("name")).isTrue();
assertThat(json.get("name").asText()).isEqualTo("includingMime.png");
assertThat(json.has("mime")).isTrue();
assertThat(json.get("mime").asText()).isEqualTo("text/html");
assertThat(json.has("parent")).isTrue();
}
return session;
}
private Result sendJson(FakeRequest newRequest, JsonNode json) {
return callAction(
controllers.routes.ref.FileStoreController.createFile(),
newRequest.withJsonBody(json));
}
});
}
@Test
public void uploadToFolder() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
{
// Check bad request behaviour
final Result result = callAction(
controllers.routes.ref.FileStoreController.uploadToFolder(
fm.getRoot().getIdentifier()),
newRequest.withHeader("Accept", "application/json"));
assertThat(status(result)).isEqualTo(400);
}
{
// Good request
final Result result = callAction(
controllers.routes.ref.FileStoreController.uploadToFolder(
fm.getRoot().getIdentifier()),
newRequest.withHeader("Accept", "application/json")
.withBody(
test.AorraScalaHelper.testMultipartFormBody(
"test.txt", "Some content.", "text/plain")));
assertThat(status(result)).isEqualTo(201);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
fm.getRoot().reload();
final Set<FileStore.File> files = fm.getRoot().getFiles();
assertThat(files).hasSize(1);
final FileStore.File file = files.iterator().next();
assertThat(file.getMimeType()).isEqualTo("text/plain");
assertThat(IOUtils.toString(file.getData()))
.isEqualTo("Some content.");
assertThat(contentAsString(result))
.isEqualTo((new JsonBuilder()).toJsonShallow(file).toString());
}
{
// Check we can't overwrite files with this method
final Result result = callAction(
controllers.routes.ref.FileStoreController.uploadToFolder(
fm.getRoot().getIdentifier()),
newRequest.withHeader("Accept", "application/json")
.withBody(
test.AorraScalaHelper.testMultipartFormBody(
"test.txt", "Some content.", "text/plain")));
assertThat(status(result)).isEqualTo(403);
}
fm.getRoot().createFolder("README");
{
// Check we can't overwrite files with this method
final Result result = callAction(
controllers.routes.ref.FileStoreController.uploadToFolder(
fm.getRoot().getIdentifier()),
newRequest.withHeader("Accept", "application/json")
.withBody(
test.AorraScalaHelper.testMultipartFormBody(
"README", "Some content.", "text/plain")));
assertThat(status(result)).isEqualTo(403);
}
return session;
}
});
}
/**
* Flash-based uploads will never have correct mime-types, so we should
* attempt to autodetect the mime-type.
*/
@Test
public void uploadToFolderMimeTypeDetection() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.uploadToFolder(
fm.getRoot().getIdentifier()),
newRequest.withHeader("Accept", "application/json")
.withBody(
test.AorraScalaHelper.testMultipartFormBody(
"test.txt",
"Some content.", "application/octet-stream")));
assertThat(status(result)).isEqualTo(201);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
fm.getRoot().reload();
final FileStore.File file = (FileStore.File)
fm.getFileOrFolder("test.txt");
assertThat(file).isNotNull();
assertThat(file.getMimeType()).isEqualTo("text/plain");
assertThat(IOUtils.toString(file.getData()))
.isEqualTo("Some content.");
assertThat(contentAsString(result))
.isEqualTo((new JsonBuilder()).toJsonShallow(file).toString());
}
{
// When all else fails => application/octet-stream
final Result result = callAction(
controllers.routes.ref.FileStoreController.uploadToFolder(
fm.getRoot().getIdentifier()),
newRequest.withHeader("Accept", "application/json")
.withBody(
test.AorraScalaHelper.testMultipartFormBody(
"test",
new byte[] { 0, 127, -92},
"application/octet-stream")));
assertThat(status(result)).isEqualTo(201);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
fm.getRoot().reload();
final FileStore.File file = (FileStore.File)
fm.getFileOrFolder("test");
assertThat(file).isNotNull();
assertThat(file.getMimeType()).isEqualTo("application/octet-stream");
assertThat(IOUtils.toByteArray(file.getData()))
.isEqualTo(new byte[] { 0, 127, -92});
assertThat(contentAsString(result))
.isEqualTo((new JsonBuilder()).toJsonShallow(file).toString());
}
return session;
}
});
}
@Test
public void updateFile() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final FileStore.File file =
fm.getRoot().createFile("test.txt", "text/plain",
new ByteArrayInputStream("Some content.".getBytes()));
{
// Try without body
final Result result = callAction(
controllers.routes.ref.FileStoreController.updateFile(
file.getIdentifier()),
newRequest.withHeader("Accept", "application/json"));
// Should return 400 Bad Request
assertThat(status(result)).isEqualTo(400);
}
{
// Updating with multipart form body
final Result result = callAction(
controllers.routes.ref.FileStoreController.updateFile(
file.getIdentifier()),
newRequest.withHeader("Accept", "application/json")
.withBody(
test.AorraScalaHelper.testMultipartFormBody(
"test.txt",
"New content.", "text/plain")));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
fm.getRoot().reload();
final Set<FileStore.File> files = fm.getRoot().getFiles();
assertThat(files).hasSize(1);
final FileStore.File updatedFile = files.iterator().next();
assertThat(IOUtils.toString(updatedFile.getData()))
.isEqualTo("New content.");
assertThat(contentAsString(result)).isEqualTo(
(new JsonBuilder()).toJsonShallow(updatedFile).toString());
}
{
// Updating with simple body
final Result result = callAction(
controllers.routes.ref.FileStoreController.updateFile(
file.getIdentifier()),
newRequest.withHeader("Accept", "application/json")
.withHeader("Content-Type", "text/plain")
.withBody(new AnyContentAsText("Newer content.")));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
fm.getRoot().reload();
final Set<FileStore.File> files = fm.getRoot().getFiles();
assertThat(files).hasSize(1);
final FileStore.File updatedFile = files.iterator().next();
assertThat(IOUtils.toString(updatedFile.getData()))
.isEqualTo("Newer content.");
assertThat(contentAsString(result)).isEqualTo(
(new JsonBuilder()).toJsonShallow(updatedFile).toString());
}
return session;
}
});
}
@Test
public void deleteVersion() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final FileStore.File file =
fm.getRoot().createFile("test.txt", "text/plain",
new ByteArrayInputStream("Some content.".getBytes()));
file.update("text/plain",
new ByteArrayInputStream("Some more content.".getBytes()));
assertThat(file.getVersions()).hasSize(2);
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.deleteVersion(
file.getIdentifier(), "1.1"),
newRequest.withHeader("Accept", "application/json"));
assertThat(status(result)).isEqualTo(204);
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
assertThat(file.getVersions()).hasSize(1);
}
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.deleteVersion(
file.getIdentifier(), "1.1"),
newRequest.withHeader("Accept", "application/json"));
assertThat(status(result)).isEqualTo(404);
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
}
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.deleteVersion(
file.getIdentifier(), "1.0"),
newRequest.withHeader("Accept", "application/json"));
assertThat(status(result)).isEqualTo(403);
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
assertThat(file.getVersions()).hasSize(1);
}
return session;
}
});
}
@Test
public void deleteFile() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final FileStore.File file =
fm.getRoot().createFile("test.txt", "text/plain",
new ByteArrayInputStream("Some content.".getBytes()));
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.delete(
file.getIdentifier()),
newRequest.withHeader("Accept", "application/json"));
assertThat(status(result)).isEqualTo(204);
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
}
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.delete(
file.getIdentifier()),
newRequest.withHeader("Accept", "application/json"));
assertThat(status(result)).isEqualTo(404);
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
}
// Check that this operation is outright forbidden without admin
final Set<Group> userGroups =
(new GroupManager(session)).memberships(user.getJackrabbitUserId());
for (final Group g : userGroups) {
Admin.getInstance(session).getGroup().removeMember(g);
}
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.delete(
file.getIdentifier()),
newRequest.withHeader("Accept", "application/json"));
assertThat(status(result)).isEqualTo(403);
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
}
return session;
}
});
}
@Test
public void mkdir() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final JsonBuilder jb = new JsonBuilder();
final FileStore.Manager fm = fileStore().getManager(session);
assertThat(fm.getFileOrFolder("/foo/bar")).isNull();
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.mkdir(
fm.getRoot().getIdentifier(), "foo/bar"),
newRequest);
assertThat(status(result)).isEqualTo(201);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final ArrayNode json = JsonNodeFactory.instance.arrayNode();
for (final String path : new String[]{"/foo", "/foo/bar"}) {
final FileStore.Folder folder = (FileStore.Folder)
fm.getFileOrFolder(path);
assertThat(folder).isNotNull();
json.add(jb.toJsonShallow(folder, false));
}
assertThat(contentAsString(result)).isEqualTo(json.toString());
}
// Attempt to create folder when one already exists
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.mkdir(
fm.getRoot().getIdentifier(), "foo/bar"),
newRequest);
assertThat(status(result)).isEqualTo(400);
}
return session;
}
});
}
/**
* Test to ensure creating deep folder structures is efficient enough.
*/
@Test
public void mkdirPerformance() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
FileStore.Folder parentFolder = fm.getRoot();
final List<Long> runtimes = Lists.newLinkedList();
for (final Integer i : ContiguousSet.create(
Range.closed(1, 50), DiscreteDomain.integers())) {
final String name = i.toString();
assertThat(parentFolder.getFileOrFolder(name)).isNull();
final long requestMillis = System.currentTimeMillis();
final Result result = callAction(
controllers.routes.ref.FileStoreController.mkdir(
parentFolder.getIdentifier(), name),
newRequest);
// Request must complete in 10 seconds
assertThat(status(result)).isEqualTo(201);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
parentFolder.reload();
final FileStore.Folder folder = (FileStore.Folder)
parentFolder.getFileOrFolder(name);
assertThat(folder).isNotNull();
final String folderJson = (new JsonBuilder())
.toJsonShallow(folder, false)
.toString();
assertThat(contentAsString(result)).isEqualTo("["+folderJson+"]");
final long deltaMillis = System.currentTimeMillis() - requestMillis;
runtimes.add(deltaMillis);
parentFolder = folder;
}
// Check runtime is increasing close to linearly
final double allowedRelativeIncrease = 1.20;
final DescriptiveStatistics stats = new DescriptiveStatistics();
Long previousMs = null;
for (Long ms : runtimes) {
if (previousMs != null) {
// Percentage increase
stats.addValue(1.0 * ms / previousMs);
}
previousMs = ms;
}
assertThat(stats.getMean()).isLessThan(allowedRelativeIncrease);
return session;
}
});
}
@Test
public void downloadFile() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FakeRequest copiedFakeRequest = copy(newRequest);
final FileStore.Manager fm = fileStore().getManager(session);
final FileStore.File file =
fm.getRoot().createFile("test file", "text/plain",
new ByteArrayInputStream("Some content.".getBytes()));
// Aliases should redirect
for (String versionName : new String[]{"1.0", "latest"}) {
final Result result = callAction(
controllers.routes.ref.FileStoreController.downloadFile(
file.getIdentifier(),
versionName),
newRequest.withHeader("Accept", "text/plain"));
assertThat(status(result)).isEqualTo(303);
assertThat(header("Location", result)).isEqualTo(
controllers.routes.FileStoreController.downloadFile(
file.getIdentifier(),
file.getVersions().first().getIdentifier()).url());
}
// UUID should send content
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.downloadFile(
file.getIdentifier(),
file.getVersions().first().getIdentifier()),
newRequest.withHeader("Accept", "text/plain"));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("text/plain");
assertThat(header("ETag", result))
.isEqualTo(file.getDigest().substring(0, 16));
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=604800, private");
assertThat(header("Last-Modified", result)).isNotNull();
assertThat(header("Content-Disposition", result))
.startsWith("attachment; filename=\"test file");
assertThat(header("Content-Disposition", result))
.endsWith(".txt");
// ETag & Last Modified tests
for (String[] headerData : new String[][]{
new String[]{"If-None-Match", header("ETag", result)},
new String[]{"If-Modified-Since", header("Last-Modified", result)}
}){
final Result notModifiedResult = callAction(
controllers.routes.ref.FileStoreController.downloadFile(
file.getIdentifier(),
file.getVersions().first().getIdentifier()),
newRequest.withHeader("Accept", "text/plain")
.withHeader(headerData[0], headerData[1]));
assertThat(status(notModifiedResult)).isEqualTo(304);
}
}
// Test extension with unknown mime type
{
file.update("application/vnd.somethingijustmadeup",
new ByteArrayInputStream("Some content.".getBytes()));
final Result result = callAction(
controllers.routes.ref.FileStoreController.downloadFile(
file.getIdentifier(),
file.getVersions().first().getIdentifier()),
copy(copiedFakeRequest));
assertThat(status(result)).isEqualTo(200);
assertThat(header("Content-Disposition", result))
.endsWith("test%20file");
}
// Test extension when mime type is satisfactory
{
file.update("text/plain",
new ByteArrayInputStream("Some content.".getBytes()));
file.rename("test.text");
final Result result = callAction(
controllers.routes.ref.FileStoreController.downloadFile(
file.getIdentifier(),
file.getVersions().first().getIdentifier()),
copy(copiedFakeRequest));
assertThat(status(result)).isEqualTo(200);
assertThat(header("Content-Disposition", result))
.endsWith(".text");
}
{
final String notFoundId = UUID.randomUUID().toString();
for (String versionString : new String[]{"1.0", "latest"}) {
final Result defaultResult = callAction(
controllers.routes.ref.FileStoreController.downloadFile(
notFoundId,
versionString),
newRequest.withHeader("Accept", "*/*"));
assertThat(status(defaultResult)).isEqualTo(404);
assertThat(contentType(defaultResult)).isEqualTo("text/plain");
assertThat(contentAsString(defaultResult)).isEqualTo(
IOUtils.toString(
getClass().getResourceAsStream("/notfound/not_found.txt")));
final Result pngResult = callAction(
controllers.routes.ref.FileStoreController.downloadFile(
notFoundId,
versionString),
newRequest.withHeader("Accept", "image/png,image/*,*/*;q=0.5"));
assertThat(status(pngResult)).isEqualTo(404);
assertThat(contentType(pngResult)).isEqualTo("image/png");
assertThat(contentAsBytes(pngResult)).isEqualTo(
IOUtils.toByteArray(
getClass().getResourceAsStream("/notfound/not_found.png")));
}
}
return session;
}
private FakeRequest copy(FakeRequest req) {
return new CopiedFakeRequest(req);
}
});
}
@Test
public void downloadFolder() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final FileStore.Folder folder =
fm.getRoot().createFolder("Test Folder");
folder.createFile("test.txt", "text/plain",
new ByteArrayInputStream("Some content.".getBytes()));
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.downloadFolder(
folder.getIdentifier()),
newRequest);
assertThat(status(result)).isEqualTo(200);
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
assertThat(header("Content-Disposition", result))
.isEqualTo("attachment; filename=\"Test Folder.zip\";"
+ " filename*=UTF-8''Test%20Folder.zip");
// File result is async
//assertThat(result.getWrappedResult()).isInstanceOf(
// play.api.mvc.AsyncResult.class);
}
return session;
}
});
}
@Test
public void fileTextSummary() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final FileStore.File file =
fm.getRoot().createFile("test.txt", "text/plain",
new ByteArrayInputStream("Some content.".getBytes()));
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.fileTextSummary(
file.getIdentifier(),
"1.0"),
newRequest.withHeader("Accept", "text/plain"));
assertThat(status(result)).isEqualTo(200);
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
assertThat(contentAsString(result)).contains("Some content.");
}
return session;
}
});
}
@Test
public void groupPermissionsJSON() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
final Result result = callAction(
controllers.routes.ref.FileStoreController.groupPermissionList(
fm.getRoot().getIdentifier()),
newRequest);
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
assertThat(contentAsString(result)).contains("testgroup");
return session;
}
});
}
@Test
public void groupPermissionJSON() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.groupPermission(
fm.getRoot().getIdentifier(),
"testgroup"),
newRequest);
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final JsonNode json = Json.parse(contentAsString(result));
assertThat(json.get("name").asText()).isEqualTo("testgroup");
assertThat(json.get("access").asText()).isEqualTo("RW");
}
{
final Result result = callAction(
controllers.routes.ref.FileStoreController.groupPermission(
fm.getRoot().getIdentifier(),
"doesnotexist"),
newRequest);
assertThat(status(result)).isEqualTo(404);
}
return session;
}
});
}
@Test
public void permissionUpdateJSON() {
asAdminUser(new F.Function3<Session, User, FakeRequest, Session>() {
@Override
public Session apply(
final Session session,
final User user,
final FakeRequest newRequest) throws Throwable {
final FileStore.Manager fm = fileStore().getManager(session);
{
final ObjectNode data = Json.newObject();
data.put("name", "testgroup");
data.put("access", "RO");
final Result result = callAction(
controllers.routes.ref.FileStoreController.permissionUpdate(
fm.getRoot().getIdentifier()),
newRequest.withJsonBody(data));
assertThat(status(result)).isEqualTo(200);
assertThat(contentType(result)).isEqualTo("application/json");
assertThat(charset(result)).isEqualTo("utf-8");
assertThat(header("Cache-Control", result))
.isEqualTo("max-age=0, must-revalidate");
final JsonNode json = Json.parse(contentAsString(result));
assertThat(json.get("name").asText()).isEqualTo("testgroup");
assertThat(json.get("access").asText()).isEqualTo("RO");
// Check change was actually made
Map<String, Permission> perms = fm.getRoot().getGroupPermissions();
assertThat(perms.get("testgroup")).isEqualTo(Permission.RO);
}
return session;
}
});
}
}