package uk.ac.ox.zoo.seeg.abraid.mp.modelwrapper.web;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.io.FileUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.kubek2k.springockito.annotations.ReplaceWithMock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import uk.ac.ox.zoo.seeg.abraid.mp.modelwrapper.config.run.ExecutionRunConfiguration;
import uk.ac.ox.zoo.seeg.abraid.mp.modelwrapper.config.run.RunConfiguration;
import uk.ac.ox.zoo.seeg.abraid.mp.modelwrapper.config.run.RunConfigurationFactory;
import uk.ac.ox.zoo.seeg.abraid.mp.modelwrapper.model.ModelRunner;
import uk.ac.ox.zoo.seeg.abraid.mp.testutils.SpringockitoWebContextLoader;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Integration test for the model run ModelWrapper controller.
* Copyright (c) 2014 University of Oxford
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = SpringockitoWebContextLoader.class, locations = {
"file:ModelWrapper/web/WEB-INF/abraid-servlet-beans.xml",
"file:ModelWrapper/web/WEB-INF/applicationContext.xml"
})
@WebAppConfiguration("file:ModelWrapper/web")
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class ModelRunControllerIntegrationTest extends BaseWebIntegrationTests {
@Rule
public TemporaryFolder testFolder = new TemporaryFolder(); ///CHECKSTYLE:SUPPRESS VisibilityModifier
private MockMvc mockMvc;
@ReplaceWithMock
@Autowired
private ModelRunner modelRunner;
@ReplaceWithMock
@Autowired
private RunConfigurationFactory runConfigurationFactory;
@Autowired
private WebApplicationContext webApplicationContext;
@Before
public void setup() {
// Setup Spring test in standalone mode
this.mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.build();
}
@Test
public void canTriggerNewRunWithValidContent() throws Exception {
String runName = "foo_2014-04-24-10-50-27_cd0efc75-42d3-4d96-94b4-287e28fbcdac";
setUpExpectedRunName(runName);
this.mockMvc
.perform(buildPost(buildZip("{\"disease\":{\"id\":1,\"name\":\"foo\",\"abbreviation\":\"f\"},\"runName\":\"" + runName + "\"}")))
.andExpect(status().isOk())
.andExpect(content().string("{}"));
}
@Test
public void runRejectsRequestWithNoContent() throws Exception {
this.mockMvc
.perform(buildPost(new byte[0]))
.andExpect(status().isBadRequest());
}
private MockHttpServletRequestBuilder buildPost(byte[] body) {
MockMultipartFile file = new MockMultipartFile("file", body);
return fileUpload("/api/model/run").file(file);
}
@Test
public void runRejectsRequestWithInvalidContent() throws Exception {
this.mockMvc
.perform(buildPost(buildZip("{\"disease\":{\"id\":1,\"name\":\"foo\",\"abbreviation\":\"f\"}}")))
.andExpect(status().isBadRequest())
.andExpect(content().string("{\"errorText\":\"Run data must be provided and be valid.\"}"));
}
@Test
public void runPageOnlyAcceptsPOST() throws Exception {
String runName = "run1234";
setUpExpectedRunName(runName);
this.mockMvc.perform(createRequest(HttpMethod.GET)).andExpect(status().isMethodNotAllowed());
this.mockMvc.perform(buildPost(buildZip("{\"disease\":{\"id\":1,\"name\":\"foo\",\"abbreviation\":\"f\"},\"runName\":\"" + runName + "\"}"))).andExpect(status().isOk());
this.mockMvc.perform(createRequest(HttpMethod.PUT)).andExpect(status().isMethodNotAllowed());
this.mockMvc.perform(createRequest(HttpMethod.DELETE)).andExpect(status().isMethodNotAllowed());
this.mockMvc.perform(createRequest(HttpMethod.PATCH)).andExpect(status().isMethodNotAllowed());
}
private String setUpExpectedRunName(String runName) throws ConfigurationException, IOException {
RunConfiguration runConfiguration = mock(RunConfiguration.class);
when(runConfiguration.getRunName()).thenReturn(runName);
when(runConfiguration.getExecutionConfig()).thenReturn(mock(ExecutionRunConfiguration.class));
when(runConfiguration.getWorkingDirectoryPath()).thenReturn(Paths.get(testFolder.getRoot().toString(), runName));
when(runConfigurationFactory.createDefaultConfiguration(runName))
.thenReturn(runConfiguration);
return runName;
}
private MockHttpServletRequestBuilder createRequest(HttpMethod method) throws IOException, ZipException {
return request(method, "/api/model/run")
.contentType(MediaType.MULTIPART_FORM_DATA);
}
private byte[] buildZip(String content) throws IOException, ZipException {
File dir = testFolder.newFolder();
FileUtils.writeStringToFile(Paths.get(dir.getAbsolutePath(), "metadata.json").toFile(), content);
File zipFile = testFolder.newFile();
Files.delete(zipFile.toPath());
ZipFile zip = new ZipFile(zipFile);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setIncludeRootFolder(false);
zip.createZipFileFromFolder(dir, zipParameters, false, 0);
return FileUtils.readFileToByteArray(zipFile);
}
}