ATS-702 Test implementation Imagemagick+HttpRequest

Added implementation for the above for the AIO controller.
Added a separate for imagemagick that includes all tests from the original ImageMagickControllerTest.java. Was getting a pathing error on Windows when trying to use the inheritance. Added the inheritance method as a POC separately..
This commit is contained in:
David Edwards
2020-04-07 09:15:57 +01:00
parent 0c5a0c70b1
commit cbcc203e89
5 changed files with 481 additions and 20 deletions

View File

@@ -59,9 +59,9 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@Controller @Controller
public class AIOController extends AbstractTransformerController public class AllInOneController extends AbstractTransformerController
{ {
private static final Logger logger = LoggerFactory.getLogger(AIOController.class); private static final Logger logger = LoggerFactory.getLogger(AllInOneController.class);
//TODO Should these be moved to the AbstractTransformerController or are they present in the transform.client? They are used by most controllers... //TODO Should these be moved to the AbstractTransformerController or are they present in the transform.client? They are used by most controllers...
private static final String SOURCE_ENCODING = "sourceEncoding"; private static final String SOURCE_ENCODING = "sourceEncoding";

View File

@@ -29,11 +29,6 @@ package org.alfresco.transformer;
import org.alfresco.transform.client.model.config.TransformConfig; import org.alfresco.transform.client.model.config.TransformConfig;
import org.alfresco.transform.client.registry.TransformServiceRegistry; import org.alfresco.transform.client.registry.TransformServiceRegistry;
import org.alfresco.transformer.transformers.AllInOneTransformer; import org.alfresco.transformer.transformers.AllInOneTransformer;
import org.alfresco.transformer.transformers.ImageMagickAdapter;
import org.alfresco.transformer.transformers.LibreOfficeAdapter;
import org.alfresco.transformer.transformers.MiscAdapter;
import org.alfresco.transformer.transformers.PdfRendererAdapter;
import org.alfresco.transformer.transformers.TikaAdapter;
import org.alfresco.transformer.transformers.Transformer; import org.alfresco.transformer.transformers.Transformer;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
@@ -42,19 +37,13 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary; import org.springframework.context.annotation.Primary;
@Configuration @Configuration
public class AIOCustomConfig public class AllInOneCustomConfig
{ {
@Bean("AllInOneTransformer") @Bean("AllInOneTransformer")
public Transformer aioTransformer() throws Exception public Transformer aioTransformer()
{ {
AllInOneTransformer aioTransformer = new AllInOneTransformer(); return new AllInOneTransformer();
aioTransformer.registerTransformer(new MiscAdapter());
aioTransformer.registerTransformer(new TikaAdapter());
aioTransformer.registerTransformer(new ImageMagickAdapter());
aioTransformer.registerTransformer(new LibreOfficeAdapter());
aioTransformer.registerTransformer(new PdfRendererAdapter());
return aioTransformer;
} }
/** /**
@@ -67,6 +56,7 @@ public class AIOCustomConfig
{ {
return new TransformRegistryImpl() return new TransformRegistryImpl()
{ {
@Autowired @Autowired
@Qualifier("AllInOneTransformer") @Qualifier("AllInOneTransformer")
Transformer transformer; Transformer transformer;

View File

@@ -0,0 +1,52 @@
/*
* #%L
* Alfresco Transform Core
* %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.transformer;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class AllInOneControllerHttpRequestTest extends AbstractHttpRequestTest
{
@Override
protected String getTransformerName()
{
return "All in One Transformer";
}
@Override
protected String getSourceExtension()
{
// Currently using same extension as ImageMagick tests
return "jpg";
}
}

View File

@@ -0,0 +1,419 @@
/*
* #%L
* Alfresco Transform Core
* %%
* Copyright (C) 2005 - 2020 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.transformer;
import static org.alfresco.transformer.executors.RuntimeExec.ExecutionResult;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;
import static org.springframework.http.HttpHeaders.ACCEPT;
import static org.springframework.http.HttpHeaders.CONTENT_DISPOSITION;
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.OK;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.http.MediaType.IMAGE_PNG_VALUE;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.util.StringUtils.getFilenameExtension;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.alfresco.transformer.transformers.AllInOneTransformer;
import org.alfresco.transformer.transformers.ImageMagickAdapter;
import org.alfresco.transformer.transformers.Transformer;
import org.alfresco.transform.client.model.TransformReply;
import org.alfresco.transform.client.model.TransformRequest;
import org.alfresco.transformer.executors.ImageMagickCommandExecutor;
import org.alfresco.transformer.executors.RuntimeExec;
import org.alfresco.transformer.model.FileRefEntity;
import org.alfresco.transformer.model.FileRefResponse;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.stubbing.Answer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@RunWith(SpringRunner.class)
@WebMvcTest(AllInOneController.class)
@Import(AllInOneCustomConfig.class)
public class AllInOneControllerImageMagickTest extends AbstractTransformerControllerTest
{
@Mock
private ExecutionResult mockExecutionResult;
@Mock
private RuntimeExec mockTransformCommand;
@Mock
private RuntimeExec mockCheckCommand;
private ImageMagickCommandExecutor commandExecutor = new ImageMagickCommandExecutor();
static ImageMagickAdapter adapter;
@Autowired
AllInOneTransformer transformer;
@SpyBean
AllInOneController controller;
@BeforeClass
public static void beforeClass() throws Exception
{
adapter = new ImageMagickAdapter();
}
@Before @SuppressWarnings("unchecked")
public void before() throws IOException
{
ReflectionTestUtils.setField(commandExecutor, "transformCommand", mockTransformCommand);
ReflectionTestUtils.setField(commandExecutor, "checkCommand", mockCheckCommand);
ReflectionTestUtils.setField(adapter, "commandExecutor", commandExecutor);
//Need to wire in the mocked adpater into the controller...
if (ReflectionTestUtils.getField(transformer,"transformerTransformMapping") instanceof Map)
{
Map<String,Transformer> transformers = (Map<String,Transformer>)ReflectionTestUtils.getField(transformer,"transformerTransformMapping");
transformers.replace("imagemagick", adapter);
ReflectionTestUtils.setField(transformer, "transformerTransformMapping", transformers);
}
//when(transformer.getTransformer("imagemagick")).thenReturn(adapter);
ReflectionTestUtils.setField(controller, "transformer",transformer);
mockTransformCommand("jpg", "png", "image/jpg", true);
}
@Override
protected AbstractTransformerController getController()
{
return this.controller;
}
@Override
protected void mockTransformCommand(String sourceExtension,
String targetExtension, String sourceMimetype,
boolean readTargetFileBytes) throws IOException
{
this.sourceExtension = sourceExtension;
this.targetExtension = targetExtension;
this.sourceMimetype = sourceMimetype;
expectedOptions = null;
expectedSourceSuffix = null;
expectedSourceFileBytes = readTestFile(sourceExtension);
expectedTargetFileBytes = readTargetFileBytes ? readTestFile(targetExtension) : null;
sourceFile = new MockMultipartFile("file", "quick." + sourceExtension, sourceMimetype,
expectedSourceFileBytes);
when(mockTransformCommand.execute(any(), anyLong())).thenAnswer(
(Answer<RuntimeExec.ExecutionResult>) invocation -> {
Map<String, String> actualProperties = invocation.getArgument(0);
assertEquals("There should be 3 properties", 3, actualProperties.size());
String actualOptions = actualProperties.get("options");
String actualSource = actualProperties.get("source");
String actualTarget = actualProperties.get("target");
String actualTargetExtension = getFilenameExtension(actualTarget);
assertNotNull(actualSource);
assertNotNull(actualTarget);
if (expectedSourceSuffix != null)
{
assertTrue(
"The source file \"" + actualSource + "\" should have ended in \"" + expectedSourceSuffix + "\"",
actualSource.endsWith(expectedSourceSuffix));
actualSource = actualSource.substring(0,
actualSource.length() - expectedSourceSuffix.length());
}
assertNotNull(actualOptions);
if (expectedOptions != null)
{
assertEquals("expectedOptions", expectedOptions, actualOptions);
}
Long actualTimeout = invocation.getArgument(1);
assertNotNull(actualTimeout);
if (expectedTimeout != null)
{
assertEquals("expectedTimeout", expectedTimeout, actualTimeout);
}
// Copy a test file into the target file location if it exists
int i = actualTarget.lastIndexOf('_');
if (i >= 0)
{
String testFilename = actualTarget.substring(i + 1);
File testFile = getTestFile(testFilename, false);
File targetFile = new File(actualTarget);
generateTargetFileFromResourceFile(actualTargetExtension, testFile,
targetFile);
}
// Check the supplied source file has not been changed.
byte[] actualSourceFileBytes = Files.readAllBytes(new File(actualSource).toPath());
assertTrue("Source file is not the same",
Arrays.equals(expectedSourceFileBytes, actualSourceFileBytes));
return mockExecutionResult;
});
when(mockExecutionResult.getExitValue()).thenReturn(0);
when(mockExecutionResult.getStdErr()).thenReturn("STDERROR");
when(mockExecutionResult.getStdOut()).thenReturn("STDOUT");
}
@Test
public void cropGravityGoodTest() throws Exception
{
for (String value : new String[]{"North", "NorthEast", "East", "SouthEast", "South", "SouthWest", "West", "NorthWest", "Center"})
{
expectedOptions = "-gravity " + value + " +repage";
mockMvc
.perform(MockMvcRequestBuilders
.multipart("/transform")
.file(sourceFile)
.param("targetExtension", targetExtension)
.param("cropGravity", value))
.andExpect(status().is(OK.value()))
.andExpect(content().bytes(expectedTargetFileBytes))
.andExpect(header().string("Content-Disposition",
"attachment; filename*= UTF-8''quick." + targetExtension));
}
}
@Test
public void cropGravityBadTest() throws Exception
{
mockMvc
.perform(MockMvcRequestBuilders
.multipart("/transform")
.file(sourceFile)
.param("targetExtension", targetExtension)
.param("cropGravity", "badValue"))
.andExpect(status().is(BAD_REQUEST.value()));
}
@Test
public void optionsTest() throws Exception
{
expectedOptions = "-alpha remove -gravity SouthEast -crop 123x456%+90+12 +repage -thumbnail 321x654%!";
expectedSourceSuffix = "[2-3]";
mockMvc
.perform(MockMvcRequestBuilders
.multipart("/transform")
.file(sourceFile)
.param("targetExtension", targetExtension)
.param("startPage", "2")
.param("endPage", "3")
.param("alphaRemove", "true")
.param("autoOrient", "false")
.param("cropGravity", "SouthEast")
.param("cropWidth", "123")
.param("cropHeight", "456")
.param("cropPercentage", "true")
.param("cropXOffset", "90")
.param("cropYOffset", "12")
.param("thumbnail", "true")
.param("resizeWidth", "321")
.param("resizeHeight", "654")
.param("resizePercentage", "true")
.param("allowEnlargement", "true")
.param("maintainAspectRatio", "false"))
.andExpect(status().is(OK.value()))
.andExpect(content().bytes(expectedTargetFileBytes))
.andExpect(header().string("Content-Disposition",
"attachment; filename*= UTF-8''quick." + targetExtension));
}
@Test
public void optionsNegateBooleansTest() throws Exception
{
expectedOptions = "-auto-orient -gravity SouthEast -crop 123x456+90+12 +repage -resize 321x654>";
expectedSourceSuffix = "[2-3]";
mockMvc
.perform(MockMvcRequestBuilders
.multipart("/transform")
.file(sourceFile)
.param("targetExtension", targetExtension)
.param("startPage", "2")
.param("endPage", "3")
.param("alphaRemove", "false")
.param("autoOrient", "true")
.param("cropGravity", "SouthEast")
.param("cropWidth", "123")
.param("cropHeight", "456")
.param("cropPercentage", "false")
.param("cropXOffset", "90")
.param("cropYOffset", "12")
.param("thumbnail", "false")
.param("resizeWidth", "321")
.param("resizeHeight", "654")
.param("resizePercentage", "false")
.param("allowEnlargement", "false")
.param("maintainAspectRatio", "true"))
.andExpect(status().is(OK.value()))
.andExpect(content().bytes(expectedTargetFileBytes))
.andExpect(header().string("Content-Disposition",
"attachment; filename*= UTF-8''quick." + targetExtension));
}
@Test
public void deprecatedCommandOptionsTest() throws Exception
{
// Example of why the commandOptions parameter is a bad idea.
expectedOptions = "( horrible command / ); -resize 321x654>";
mockMvc
.perform(MockMvcRequestBuilders
.multipart("/transform")
.file(sourceFile)
.param("targetExtension", targetExtension)
.param("thumbnail", "false")
.param("resizeWidth", "321")
.param("resizeHeight", "654")
.param("commandOptions", "( horrible command / );"))
.andExpect(status().is(OK.value()))
.andExpect(content().bytes(expectedTargetFileBytes))
.andExpect(header().string("Content-Disposition",
"attachment; filename*= UTF-8''quick." + targetExtension));
}
@Override
protected void updateTransformRequestWithSpecificOptions(TransformRequest transformRequest)
{
transformRequest.setSourceExtension("png");
transformRequest.setTargetExtension("png");
transformRequest.setSourceMediaType(IMAGE_PNG_VALUE);
transformRequest.setTargetMediaType(IMAGE_PNG_VALUE);
}
@Test
public void badExitCodeTest() throws Exception
{
when(mockExecutionResult.getExitValue()).thenReturn(1);
mockMvc.perform(mockMvcRequest("/transform", sourceFile, "targetExtension", "xxx"))
.andExpect(status().is(BAD_REQUEST.value()))
.andExpect(
status().reason(containsString("Transformer exit code was not 0: \nSTDERR")));
}
@Test
public void testPojoTransform() throws Exception
{
// Files
String sourceFileRef = UUID.randomUUID().toString();
File sourceFile = getTestFile("quick." + sourceExtension, true);
String targetFileRef = UUID.randomUUID().toString();
// Transformation Request POJO
TransformRequest transformRequest = new TransformRequest();
transformRequest.setRequestId("1");
transformRequest.setSchema(1);
transformRequest.setClientData("Alfresco Digital Business Platform");
transformRequest.setTransformRequestOptions(new HashMap<>());
transformRequest.setSourceReference(sourceFileRef);
transformRequest.setSourceExtension(sourceExtension);
transformRequest.setSourceSize(sourceFile.length());
transformRequest.setTargetExtension(targetExtension);
// HTTP Request
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_DISPOSITION, "attachment; filename=quick." + sourceExtension);
ResponseEntity<Resource> response = new ResponseEntity<>(new FileSystemResource(
sourceFile), headers, OK);
when(alfrescoSharedFileStoreClient.retrieveFile(sourceFileRef)).thenReturn(response);
when(alfrescoSharedFileStoreClient.saveFile(any()))
.thenReturn(new FileRefResponse(new FileRefEntity(targetFileRef)));
when(mockExecutionResult.getExitValue()).thenReturn(0);
// Update the Transformation Request with any specific params before sending it
updateTransformRequestWithSpecificOptions(transformRequest);
// Serialize and call the transformer
String tr = objectMapper.writeValueAsString(transformRequest);
String transformationReplyAsString = mockMvc
.perform(MockMvcRequestBuilders
.post("/transform")
.header(ACCEPT, APPLICATION_JSON_VALUE)
.header(CONTENT_TYPE, APPLICATION_JSON_VALUE)
.content(tr))
.andExpect(status().is(CREATED.value()))
.andReturn().getResponse().getContentAsString();
TransformReply transformReply = objectMapper.readValue(transformationReplyAsString,
TransformReply.class);
// Assert the reply
assertEquals(transformRequest.getRequestId(), transformReply.getRequestId());
assertEquals(transformRequest.getClientData(), transformReply.getClientData());
assertEquals(transformRequest.getSchema(), transformReply.getSchema());
}
@Test
public void emptyTest()
{
controller.info();
}
}

View File

@@ -38,13 +38,13 @@ import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@WebMvcTest(AIOController.class) @WebMvcTest(AllInOneController.class)
@Import(AIOCustomConfig.class) @Import(AllInOneCustomConfig.class)
public class AIOControllerTest //extends AbstractTransformerControllerTest public class AllInOneControllerTest //extends AbstractTransformerControllerTest
{ {
@Autowired @Autowired
AIOController aioController; AllInOneController aioController;
//@Override //@Override
protected void mockTransformCommand(String sourceExtension, String targetExtension, String sourceMimetype, protected void mockTransformCommand(String sourceExtension, String targetExtension, String sourceMimetype,