Commit 6807150c authored by Piotr Gawron's avatar Piotr Gawron
Browse files

documentation of uploading complex project from zip

parent 3003782d
......@@ -45,6 +45,22 @@ import lcsb.mapviewer.services.utils.CreateProjectParams;
@Service
public class ProjectRestImpl extends BaseRestImpl {
public static enum ZipEntryFileType {
MAP,
OVERLAY,
IMAGE,
GLYPH;
public static ZipEntryFileType getType(String entryType) {
for (ZipEntryFileType type : ZipEntryFileType.values()) {
if (type.name().equals(entryType)) {
return type;
}
}
return null;
}
}
/**
* Default class logger.
*/
......@@ -425,7 +441,10 @@ public class ProjectRestImpl extends BaseRestImpl {
ZipEntryFile entry = null;
String entryType = (String) data.get("zip-entries[" + fileIndex + "][_type]").get(0);
String filename = (String) data.get("zip-entries[" + fileIndex + "][_filename]").get(0);
if ("MAP".equalsIgnoreCase(entryType)) {
ZipEntryFileType type = ZipEntryFileType.getType(entryType);
switch (type) {
case MAP:
String submodelTypeKey = "zip-entries[" + fileIndex + "][_data][type][id]";
String rootKey = "zip-entries[" + fileIndex + "][_data][root]";
String mappingKey = "zip-entries[" + fileIndex + "][_data][mapping]";
......@@ -438,15 +457,19 @@ public class ProjectRestImpl extends BaseRestImpl {
Boolean mapping = getBoolValue(data.get(mappingKey), false);
entry = new ModelZipEntryFile(filename, name, root, mapping, mapType);
} else if ("OVERLAY".equalsIgnoreCase(entryType)) {
String name = (String) data.get("zip-entries[" + fileIndex + "][_data][name]").get(0);
break;
case OVERLAY:
name = (String) data.get("zip-entries[" + fileIndex + "][_data][name]").get(0);
String description = (String) data.get("zip-entries[" + fileIndex + "][_data][description]").get(0);
entry = new LayoutZipEntryFile(filename, name, description);
} else if ("IMAGE".equalsIgnoreCase(entryType)) {
break;
case IMAGE:
entry = new ImageZipEntryFile(filename);
} else if ("GLYPH".equalsIgnoreCase(entryType)) {
break;
case GLYPH:
entry = new GlyphZipEntryFile(filename);
} else {
break;
default:
throw new QueryException("Unknown entry type: " + entryType);
}
fileIndex++;
......
......@@ -14,6 +14,8 @@ import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.servlet.Filter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.LogEvent;
import org.junit.*;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -55,6 +57,8 @@ import lcsb.mapviewer.web.config.SpringWebConfig;
@ContextConfiguration(classes = SpringWebConfig.class)
abstract public class ControllerIntegrationTest {
Logger logger = LogManager.getLogger();
@Rule
public JUnitRestDocumentation jUnitRestDocumentation = new JUnitRestDocumentation();
......@@ -107,11 +111,11 @@ abstract public class ControllerIntegrationTest {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.addFilter(springSecurityFilterChain)
.apply(documentationConfiguration(this.jUnitRestDocumentation)
.uris().withHost("minerva-dev.lcsb.uni.lu").withPort(80))
.apply(documentationConfiguration(this.jUnitRestDocumentation)
.operationPreprocessors()
.withResponseDefaults(Preprocessors.prettyPrint()))
.withResponseDefaults(Preprocessors.prettyPrint())
.and()
.uris().withHost("minerva-dev.lcsb.uni.lu").withPort(80))
.build();
executorService = Executors.newFixedThreadPool(1);
......@@ -256,16 +260,20 @@ abstract public class ControllerIntegrationTest {
return project;
}
protected UploadedFileEntry createFile(String content, User user) {
protected UploadedFileEntry createFile(byte[] content, User user) {
UploadedFileEntry file = new UploadedFileEntry();
file.setFileContent(content.getBytes());
file.setFileContent(content);
file.setOriginalFileName("test_file");
file.setLength(content.getBytes().length);
file.setLength(content.length);
file.setOwner(user);
fileDao.add(file);
return file;
}
protected UploadedFileEntry createFile(String content, User user) {
return createFile(content.getBytes(), user);
}
/**
* Executes lambda function in new thread with separate hibernate session. The
* function returns type <T> which can be void.
......@@ -305,6 +313,10 @@ abstract public class ControllerIntegrationTest {
}
protected UploadedFileEntry createFileInSeparateThread(String content, User user) throws Exception {
return createFileInSeparateThread(content.getBytes(), user);
}
protected UploadedFileEntry createFileInSeparateThread(byte[] content, User user) throws Exception {
return callInSeparateThread(() -> {
return createFile(content, user);
});
......@@ -314,9 +326,13 @@ abstract public class ControllerIntegrationTest {
Project project;
do {
project = projectDao.getProjectByProjectId(projectId);
if (project == null) {
logger.warn("Project doesn't exist: " + projectId);
break;
}
projectDao.evict(project);
Thread.sleep(100);
} while (project.getStatus() != ProjectStatus.DONE);
} while (project.getStatus() != ProjectStatus.DONE && project.getStatus() != ProjectStatus.FAIL);
}
public void removeProjectInSeparateThread(Project project) throws Exception {
......
......@@ -7,7 +7,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.*;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.message.BasicNameValuePair;
......@@ -19,11 +19,15 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.restdocs.request.ParameterDescriptor;
import org.springframework.restdocs.request.RequestParametersSnippet;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.RequestBuilder;
import lcsb.mapviewer.api.projects.ProjectRestImpl;
import lcsb.mapviewer.model.cache.UploadedFileEntry;
import lcsb.mapviewer.model.graphics.MapCanvasType;
import lcsb.mapviewer.model.map.model.SubmodelType;
import lcsb.mapviewer.model.user.User;
import lcsb.mapviewer.services.interfaces.IUserService;
......@@ -80,52 +84,79 @@ public class ProjectControllerIntegrationTestWithoutTransaction extends Controll
mockMvc.perform(request).andExpect(status().is2xxSuccessful())
.andDo(document("projects/project_data/create_simple",
pathParameters(parameterWithName("projectId").description("project identifier")),
requestParameters(
parameterWithName("projectId")
.description("project identifier"),
parameterWithName("file-id")
.description("identifier of the file that should be used to create project"),
parameterWithName("parser")
.description("class of the parser that should be used for parsing the file. Available options: "
+ snippets.getParsers()),
parameterWithName("cache")
.description("should the data from external sources be cached after project was created")
.optional(),
parameterWithName("description")
.description("description of the project")
.optional(),
parameterWithName("notify-email")
.description("email address that should be when something change in the project")
.optional(),
parameterWithName("disease")
.description("disease associated with the project (MESH id)")
.optional(),
parameterWithName("name")
.description("name of the project")
.optional(),
parameterWithName("organism")
.description("organism associated with the project (TAXONOMY id)")
.optional(),
parameterWithName("sbgn")
.description("should the map be visualized in sbgn-like way")
.optional(),
parameterWithName("semantic-zoom")
.description("should custom semantic zooming be enabled")
.optional(),
parameterWithName("version")
.description("version of the project")
.optional(),
parameterWithName("mapCanvasType")
.description("type of map canvas engine to be used when visualizing map. Available options: "
+ snippets.getOptionsAsString(MapCanvasType.class))
.optional(),
parameterWithName("annotate")
.description("should the project be automatically annotated")
.optional(),
parameterWithName("verify-annotations")
.description("should the annotations be verified")
.optional()),
createProjectRequestSnippet(),
snippets.getProjectSnippet()));
} finally {
callInSeparateThread(() -> {
try {
waitForProjectToFinishLoading(TEST_PROJECT);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
});
removeProjectInSeparateThread(TEST_PROJECT);
}
}
@Test
public void addComplexProjectAsCurator() throws Exception {
User admin = userService.getUserByLogin(BUILT_IN_ADMIN_LOGIN);
try {
UploadedFileEntry fileEntry = createFileInSeparateThread(
Files.readAllBytes(Paths.get("./src/test/resources/complex_model_with_submaps.zip")), admin);
String body = EntityUtils.toString(new UrlEncodedFormEntity(Arrays.asList(
new BasicNameValuePair("projectId", TEST_PROJECT),
new BasicNameValuePair("file-id", String.valueOf(fileEntry.getId())),
new BasicNameValuePair("mapCanvasType", "OPEN_LAYERS"),
new BasicNameValuePair("parser",
"lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser"),
new BasicNameValuePair("zip-entries[0][_type]", "MAP"),
new BasicNameValuePair("zip-entries[0][_filename]", "main.xml"),
new BasicNameValuePair("zip-entries[0][_data][root]", "true"),
new BasicNameValuePair("zip-entries[0][_data][name]", "main"),
new BasicNameValuePair("zip-entries[0][_data][type][id]", "UNKNOWN"),
new BasicNameValuePair("zip-entries[1][_type]", "MAP"),
new BasicNameValuePair("zip-entries[1][_filename]", "submaps/mapping.xml"),
new BasicNameValuePair("zip-entries[1][_data][root]", "false"),
new BasicNameValuePair("zip-entries[1][_data][name]", "mapping"),
new BasicNameValuePair("zip-entries[1][_data][type][id]", "UNKNOWN"),
new BasicNameValuePair("zip-entries[2][_type]", "MAP"),
new BasicNameValuePair("zip-entries[2][_filename]", "submaps/s1.xml"),
new BasicNameValuePair("zip-entries[2][_data][root]", "false"),
new BasicNameValuePair("zip-entries[2][_data][name]", "s1"),
new BasicNameValuePair("zip-entries[2][_data][type][id]", "UNKNOWN"),
new BasicNameValuePair("zip-entries[3][_type]", "MAP"),
new BasicNameValuePair("zip-entries[3][_filename]", "submaps/s2.xml"),
new BasicNameValuePair("zip-entries[3][_data][root]", "false"),
new BasicNameValuePair("zip-entries[3][_data][name]", "s2"),
new BasicNameValuePair("zip-entries[3][_data][type][id]", "UNKNOWN"),
new BasicNameValuePair("zip-entries[4][_type]", "MAP"),
new BasicNameValuePair("zip-entries[4][_filename]", "submaps/s3.xml"),
new BasicNameValuePair("zip-entries[4][_data][root]", "false"),
new BasicNameValuePair("zip-entries[4][_data][name]", "s3"),
new BasicNameValuePair("zip-entries[4][_data][type][id]", "UNKNOWN")
)));
RequestBuilder request = post("/projects/{projectId}/", TEST_PROJECT)
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.content(body)
.session(createSession(BUILT_IN_ADMIN_LOGIN, BUILT_IN_ADMIN_PASSWORD));
mockMvc.perform(request).andExpect(status().is2xxSuccessful())
.andDo(document("projects/project_data/create_zip",
pathParameters(parameterWithName("projectId").description("project identifier")),
createProjectRequestSnippet(),
snippets.getProjectSnippet()));
} finally {
......@@ -141,6 +172,83 @@ public class ProjectControllerIntegrationTestWithoutTransaction extends Controll
}
}
private RequestParametersSnippet createProjectRequestSnippet() {
return requestParameters(
parameterWithName("projectId")
.description("project identifier"),
parameterWithName("file-id")
.description("identifier of the file that should be used to create project"),
parameterWithName("parser")
.description("class of the parser that should be used for parsing the file. Available options: "
+ snippets.getParsers()),
parameterWithName("cache")
.description("should the data from external sources be cached after project was created")
.optional(),
parameterWithName("description")
.description("description of the project")
.optional(),
parameterWithName("notify-email")
.description("email address that should be when something change in the project")
.optional(),
parameterWithName("disease")
.description("disease associated with the project (MESH id)")
.optional(),
parameterWithName("name")
.description("name of the project")
.optional(),
parameterWithName("organism")
.description("organism associated with the project (TAXONOMY id)")
.optional(),
parameterWithName("sbgn")
.description("should the map be visualized in sbgn-like way")
.optional(),
parameterWithName("semantic-zoom")
.description("should custom semantic zooming be enabled")
.optional(),
parameterWithName("version")
.description("version of the project")
.optional(),
parameterWithName("mapCanvasType")
.description("type of map canvas engine to be used when visualizing map. Available options: "
+ snippets.getOptionsAsString(MapCanvasType.class))
.optional(),
parameterWithName("annotate")
.description("should the project be automatically annotated")
.optional(),
parameterWithName("verify-annotations")
.description("should the annotations be verified")
.optional(),
parameterWithName("zip-entries")
.description(
"array of parameters describing each file in the zipped input file, file-index is number starting from 0")
.optional()
)
.and(createArrayParameters("zip-entries[{number}][_filename]", "name of the file"))
.and(createArrayParameters("zip-entries[{number}][_type]",
"type of the file. Possible values: "
+ snippets.getOptionsAsString(ProjectRestImpl.ZipEntryFileType.class)))
.and(createArrayParameters("zip-entries[{number}][_data][name]", "name of the map/name of the overlay"))
.and(createArrayParameters("zip-entries[{number}][_data][mapping]",
"for submaps - is this map a mapping file (true/false)"))
.and(createArrayParameters("zip-entries[{number}][_data][root]",
"for submaps - is this map a root map (true/false)"))
.and(createArrayParameters("zip-entries[{number}][_data][type][id]",
"for submaps defines type of the connection. Possible values: "
+ snippets.getOptionsAsString(SubmodelType.class)))
.and(createArrayParameters("zip-entries[{number}][_data][description]",
"for overlays - description of the overlay"));
}
private List<ParameterDescriptor> createArrayParameters(String name, String description) {
List<ParameterDescriptor> result = new ArrayList<>();
result.add(parameterWithName(name).description(description).optional());
for (int i = 0; i < 10; i++) {
result.add(parameterWithName(name.replace("{number}", i + "")).description(description).optional().ignored());
}
return result;
}
@Test
public void addInvalidProject() throws Exception {
User admin = userService.getUserByLogin(BUILT_IN_ADMIN_LOGIN);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment