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.io.FileUtils;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile;
import uk.ac.ox.zoo.seeg.abraid.mp.common.dto.json.AbraidJsonObjectMapper;
import uk.ac.ox.zoo.seeg.abraid.mp.common.dto.json.JsonModelDisease;
import uk.ac.ox.zoo.seeg.abraid.mp.common.dto.json.JsonModelRun;
import uk.ac.ox.zoo.seeg.abraid.mp.common.dto.json.JsonModelRunResponse;
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.ModelOutputHandlerWebService;
import uk.ac.ox.zoo.seeg.abraid.mp.modelwrapper.model.ModelRunnerAsyncWrapperImpl;
import uk.ac.ox.zoo.seeg.abraid.mp.modelwrapper.model.ModelStatusReporter;
import uk.ac.ox.zoo.seeg.abraid.mp.modelwrapper.web.api.ModelRunController;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
/**
* Tests for ModelRunController.
* Copyright (c) 2014 University of Oxford
*/
public class ModelRunControllerTest {
@Rule
public TemporaryFolder testFolder = new TemporaryFolder(); ///CHECKSTYLE:SUPPRESS VisibilityModifier
@Test
public void startRunDoesNotAcceptNull() {
// Arrange
AbraidJsonObjectMapper objectMapper = mock(AbraidJsonObjectMapper.class);
ModelRunController target = new ModelRunController(mock(RunConfigurationFactory.class), mock(ModelRunnerAsyncWrapperImpl.class), mock(ModelOutputHandlerWebService.class), objectMapper);
// Act
ResponseEntity result = target.startRun(null);
// Assert
assertResponseEntity(result, "Run data must be provided and be valid.", HttpStatus.BAD_REQUEST);
}
@Test
public void startRunAcceptsModelDataAndTriggersRun() throws Exception {
// Arrange
AbraidJsonObjectMapper objectMapper = mock(AbraidJsonObjectMapper.class);
String runName = "foo_2014-04-24-10-50-27_cd0efc75-42d3-4d96-94b4-287e28fbcdac";
RunConfigurationFactory mockFactory = mock(RunConfigurationFactory.class);
RunConfiguration mockConf = mock(RunConfiguration.class);
ModelRunnerAsyncWrapperImpl mockRunner = mock(ModelRunnerAsyncWrapperImpl.class);
when(mockConf.getRunName()).thenReturn(runName);
when(mockConf.getExecutionConfig()).thenReturn(mock(ExecutionRunConfiguration.class));
File workspace = Paths.get(testFolder.getRoot().toString(), runName).toFile();
when(mockConf.getWorkingDirectoryPath()).thenReturn(workspace.toPath());
when(mockFactory.createDefaultConfiguration(anyString())).thenReturn(mockConf);
ModelRunController target = new ModelRunController(mockFactory, mockRunner, mock(ModelOutputHandlerWebService.class), objectMapper);
when(objectMapper.readValue(eq("metadata"), eq(JsonModelRun.class))).thenReturn(new JsonModelRun(new JsonModelDisease(1, true, "foo", "foo"), runName));
// Act
ResponseEntity result = target.startRun(fakeData());
// Assert
// start model correctly
verify(mockRunner).startModel(eq(mockConf), any(ModelStatusReporter.class));
// extracted zip content correctly
assertThat(Paths.get(workspace.toString(), "r", "a").toFile()).exists();
assertThat(Paths.get(workspace.toString(), "r", "a").toFile()).hasContent("c1");
assertThat(Paths.get(workspace.toString(), "a", "c", "b").toFile()).exists();
assertThat(Paths.get(workspace.toString(), "a", "c", "b").toFile()).hasContent("c2");
// give correct result
assertResponseEntity(result, null, HttpStatus.OK);
}
@Test
public void startRunHandlesExceptions() throws IOException, ZipException {
// Arrange
AbraidJsonObjectMapper objectMapper = mock(AbraidJsonObjectMapper.class);
ModelRunController target = new ModelRunController(null, null, null, objectMapper);
when(objectMapper.readValue(eq("metadata"), eq(JsonModelRun.class))).thenReturn(new JsonModelRun(new JsonModelDisease(1, true, "foo", "foo"), "name"));
// Act
ResponseEntity result = target.startRun(fakeData());
// Assert
assertResponseEntity(result, "Could not start model run. See server logs for more details.",
HttpStatus.INTERNAL_SERVER_ERROR);
}
private void assertResponseEntity(ResponseEntity response,
String expectedErrorText,
HttpStatus expectedStatus) {
assertThat(response.getStatusCode()).isEqualTo(expectedStatus);
assertThat(response.getBody()).isInstanceOf(JsonModelRunResponse.class);
JsonModelRunResponse responseBody = (JsonModelRunResponse) response.getBody();
assertThat(responseBody.getErrorText()).isEqualTo(expectedErrorText);
}
private MockMultipartFile fakeData() throws IOException, ZipException {
File file = testFolder.newFile();
Files.delete(file.toPath());
ZipFile zipFile = new ZipFile(file);
File dir = testFolder.newFolder();
File metadata = Paths.get(dir.getAbsolutePath(), "metadata.json").toFile();
FileUtils.writeStringToFile(metadata, "metadata");
// Add some random files
File c1 = Paths.get(dir.getAbsolutePath(), "r", "a").toFile();
File c2 = Paths.get(dir.getAbsolutePath(), "a", "c", "b").toFile();
FileUtils.writeStringToFile(c1, "c1");
FileUtils.writeStringToFile(c2, "c2");
//Zip
ZipParameters zipParameters = new ZipParameters();
zipParameters.setIncludeRootFolder(false);
zipFile.createZipFileFromFolder(dir, zipParameters, false, 0);
MockMultipartFile mock = new MockMultipartFile("file", Files.newInputStream(zipFile.getFile().toPath()));
return mock;
}
}