HXENG-64 refactor ATS (#657)

Refactor to clean up packages in the t-model and to introduce a simpler to implement t-engine base.

The new t-engines (tika, imagemagick, libreoffice, pdfrenderer, misc, aio, aspose) and t-router may be used in combination with older components as the API between the content Repo and between components has not changed. As far as possible the same artifacts are created (the -boot projects no longer exist). They may be used with older ACS repo versions.

The main changes to look for are:
* The introduction of TransformEngine and CustomTransformer interfaces to be implemented.
* The removal in t-engines and t-router of the Controller, Application, test template page, Controller tests and application config, as this is all now done by the t-engine base package.
* The t-router now extends the t-engine base, which also reduced the amount of duplicate code.
* The t-engine base provides the test page, which includes drop downs of known transform options. The t-router is able to use pipeline and failover transformers. This was not possible to do previously as the router had no test UI.
* Resources including licenses are automatically included in the all-in-one t-engine, from the individual t-engines. They just need to be added as dependencies in the pom. 
* The ugly code in the all-in-one t-engine and misc t-engine to pick transformers has gone, as they are now just selected by the transformRegistry.
* The way t-engines respond to http or message queue transform requests has been combined (eliminates the similar but different code that existed before).
* The t-engine base now uses InputStream and OutputStream rather than Files by default. As a result it will be simpler to avoid writing content to a temporary location.
* A number of the Tika and Misc CustomTransforms no longer use Files.
* The original t-engine base still exists so customers can continue to create custom t-engines the way they have done previously. the project has just been moved into a folder called deprecated.
* The folder structure has changed. The long "alfresco-transform-..." names have given way to shorter easier to read and type names.
* The t-engine project structure now has a single project rather than two. 
* The previous config values still exist, but there are now a new set for config values for in files with names that don't misleadingly imply they only contain pipeline of routing information. 
* The concept of 'routing' has much less emphasis in class names as the code just uses the transformRegistry. 
* TransformerConfig may now be read as json or yaml. The restrictions about what could be specified in yaml has gone.
* T-engines and t-router may use transform config from files. Previously it was just the t-router.
* The POC code to do with graphs of possible routes has been removed.
* All master branch changes have been merged in.
* The concept of a single transform request which results in multiple responses (e.g. images from a video) has been added to the core processing of requests in the t-engine base.
* Many SonarCloud linter fixes.
This commit is contained in:
Alan Davis
2022-09-14 13:40:19 +01:00
committed by GitHub
parent ea83ef9ebc
commit babe26b0ba
652 changed files with 19479 additions and 18195 deletions

View File

@@ -0,0 +1,195 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2022 - 2022 Alfresco Software Limited
* %%
* This program 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.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.common;
import org.junit.jupiter.api.Test;
import java.util.StringJoiner;
import static org.alfresco.transform.common.RepositoryClientData.CLIENT_DATA_SEPARATOR;
import static org.alfresco.transform.common.RepositoryClientData.DEBUG;
import static org.alfresco.transform.common.RepositoryClientData.DEBUG_SEPARATOR;
import static org.alfresco.transform.common.RepositoryClientData.REPO_ID;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class RepositoryClientDataTest
{
RepositoryClientData repositoryClientData;
@Test
void AcsClientDataWithDebugTest()
{
repositoryClientData = RepositoryClientData.builder()
.withRepoId("ACS1234")
.withRenditionName("renditionName")
.withRequestId("e123")
.withDebug()
.build();
String clientData = repositoryClientData.toString();
assertEquals("ACS1234", repositoryClientData.getAcsVersion());
assertEquals("renditionName", repositoryClientData.getRenditionName());
assertEquals("e123", repositoryClientData.getRequestId());
assertTrue(repositoryClientData.isDebugRequested());
assertEquals(clientData, repositoryClientData.toString());
}
@Test
void AcsClientDataWithoutDebugTest()
{
String clientData = new StringJoiner(CLIENT_DATA_SEPARATOR)
.add(REPO_ID + "ACS1234")
.add("1")
.add("renditionName")
.add("3")
.add("4")
.add("5")
.add("54321")
.add("7")
.add("8")
.add("9")
.toString();
repositoryClientData = new RepositoryClientData(clientData);
assertEquals("ACS1234", repositoryClientData.getAcsVersion());
assertEquals("renditionName", repositoryClientData.getRenditionName());
assertEquals("54321", repositoryClientData.getRequestId());
assertFalse(repositoryClientData.isDebugRequested());
assertEquals(clientData, repositoryClientData.toString());
}
@Test
void noLeadingRepoTest()
{
String clientData = new StringJoiner(CLIENT_DATA_SEPARATOR)
.add("ACS1234")
.add("1")
.add("renditionName")
.add("3")
.add("4")
.add("5")
.add("54321")
.add("7")
.add("8")
.add("9")
.toString();
repositoryClientData = new RepositoryClientData(clientData);
assertEquals("", repositoryClientData.getAcsVersion());
assertEquals("", repositoryClientData.getRenditionName());
assertEquals("", repositoryClientData.getRequestId());
assertFalse(repositoryClientData.isDebugRequested());
assertEquals(clientData, repositoryClientData.toString());
}
@Test
void tooFewElementsTest()
{
String clientData = new StringJoiner(CLIENT_DATA_SEPARATOR)
.add(REPO_ID + "ACS1234")
.add("1")
.add("renditionName")
.add("3")
.add("4")
.add("5")
.add("54321")
.add("7")
.add("8")
.toString();
repositoryClientData = new RepositoryClientData(clientData);
assertEquals("", repositoryClientData.getAcsVersion());
assertEquals("", repositoryClientData.getRenditionName());
assertEquals("", repositoryClientData.getRequestId());
assertFalse(repositoryClientData.isDebugRequested());
assertEquals(clientData, repositoryClientData.toString());
}
@Test
void tooManyElementsTest()
{
String clientData = new StringJoiner(CLIENT_DATA_SEPARATOR)
.add(REPO_ID + "ACS1234")
.add("1")
.add("renditionName")
.add("3")
.add("4")
.add("5")
.add("54321")
.add("7")
.add("8")
.add(DEBUG)
.add("10")
.toString();
repositoryClientData = new RepositoryClientData(clientData);
assertEquals("", repositoryClientData.getAcsVersion());
assertEquals("", repositoryClientData.getRenditionName());
assertEquals("", repositoryClientData.getRequestId());
assertFalse(repositoryClientData.isDebugRequested());
assertEquals(clientData, repositoryClientData.toString());
}
@Test
void nullClientDataTest()
{
repositoryClientData = new RepositoryClientData(null);
assertEquals(null, repositoryClientData.toString());
}
@Test
void noElementsClientDataTest()
{
String clientData = "There are no CLIENT_DATA_SEPARATOR chars";
repositoryClientData = new RepositoryClientData(clientData);
assertEquals(clientData, repositoryClientData.toString());
}
@Test
void debugTest()
{
String clientData = new StringJoiner(CLIENT_DATA_SEPARATOR)
.add(REPO_ID + "ACS1234")
.add("1")
.add("2")
.add("3")
.add("4")
.add("5")
.add("6")
.add("7")
.add("8")
.add(DEBUG)
.toString();
repositoryClientData = new RepositoryClientData(clientData);
assertEquals(clientData, repositoryClientData.toString());
repositoryClientData.appendDebug("Some debug");
assertEquals(clientData+DEBUG_SEPARATOR+"Some debug",
repositoryClientData.toString());
repositoryClientData.appendDebug("Some other debug");
assertEquals(clientData+DEBUG_SEPARATOR+"Some debug"+DEBUG_SEPARATOR+"Some other debug",
repositoryClientData.toString());
}
}

View File

@@ -0,0 +1,323 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This program 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.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.common;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import com.google.common.collect.ImmutableMap;
import org.alfresco.transform.client.model.InternalContext;
import org.alfresco.transform.client.model.TransformReply;
import org.alfresco.transform.client.model.TransformRequest;
import org.alfresco.transform.messages.TransformStack;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.slf4j.LoggerFactory;
import java.util.StringJoiner;
import static org.alfresco.transform.common.Mimetype.MIMETYPE_TEXT_PLAIN;
import static org.alfresco.transform.common.Mimetype.MIMETYPE_WORD;
import static org.alfresco.transform.common.RepositoryClientData.DEBUG_SEPARATOR;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Tests TransformerDebug. AbstractRouterTest in the t-router contains more complete end to end tests. The tests in this
* class are a smoke test at the moment.
*/
class TransformerDebugTest
{
private static String MIMETYPE_PDF = "application/pdf";
TransformerDebug transformerDebug = new TransformerDebug();
private StringJoiner transformerDebugOutput = new StringJoiner("\n");
public String getTransformerDebugOutput()
{
return transformerDebugOutput.toString()
.replaceAll(" [\\d,]+ ms", " -- ms");
}
private void twoStepTransform(boolean isTRouter, boolean fail, Level logLevel, String renditionName,
long sourceSize)
{
transformerDebug.setIsTRouter(isTRouter);
monitorLogs(logLevel);
TransformRequest request = TransformRequest.builder()
.withSourceSize(sourceSize)
.withInternalContext(InternalContext.initialise(null))
.withClientData(RepositoryClientData.builder().withRenditionName(renditionName).build().toString())
.build();
TransformStack.setInitialSourceReference(request.getInternalContext(), "fileRef");
TransformReply reply = TransformReply.builder()
.withInternalContext(request.getInternalContext())
.build();
TransformStack.addTransformLevel(request.getInternalContext(),
TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
.withStep("wrapper", MIMETYPE_TEXT_PLAIN, MIMETYPE_PDF));
transformerDebug.pushTransform(request);
TransformStack.addTransformLevel(request.getInternalContext(),
TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
.withStep("transformer1", MIMETYPE_TEXT_PLAIN, MIMETYPE_WORD)
.withStep("transformer2", MIMETYPE_WORD, MIMETYPE_PDF));
transformerDebug.pushTransform(request);
transformerDebug.logOptions(request);
TransformStack.removeSuccessfulStep(reply, transformerDebug);
request.setTransformRequestOptions(ImmutableMap.of("k1", "v1", "k2","v2"));
transformerDebug.pushTransform(request);
transformerDebug.logOptions(request);
if (fail)
{
reply.setErrorDetails("Dummy error");
transformerDebug.logFailure(reply);
}
else
{
TransformStack.removeSuccessfulStep(reply, transformerDebug);
TransformStack.removeTransformLevel(reply.getInternalContext());
}
}
private void monitorLogs(Level logLevel)
{
Logger logger = (Logger)LoggerFactory.getLogger(TransformerDebug.class);
AppenderBase<ILoggingEvent> logAppender = new AppenderBase<>()
{
@Override
protected void append(ILoggingEvent iLoggingEvent)
{
transformerDebugOutput.add(iLoggingEvent.getMessage());
}
};
logAppender.setContext((LoggerContext)LoggerFactory.getILoggerFactory());
logger.setLevel(logLevel);
logger.addAppender(logAppender);
logAppender.start();
}
@Test
void testRouterTwoStepTransform()
{
twoStepTransform(true, false, Level.DEBUG, "", 1234L);
Assertions.assertEquals("" +
"1 txt pdf 1.2 KB wrapper\n" +
"1.1 txt doc transformer1\n" +
"1.2 doc pdf transformer2\n" +
"1.2 k1=\"v1\"\n" +
"1.2 k2=\"v2\"\n" +
"1 Finished in -- ms",
getTransformerDebugOutput());
}
@Test
void testRouterTwoStepTransformWithTrace()
{
twoStepTransform(true, false, Level.TRACE, "", 1234L);
// With trace there are "Finished" lines for nested transforms, like a T-Engine's debug but still without
// the size and rendition name
Assertions.assertEquals("" +
"1 txt pdf 1.2 KB wrapper\n" +
"1.1 txt doc transformer1\n" +
"1.1 Finished in -- ms\n" +
"1.2 doc pdf transformer2\n" +
"1.2 k1=\"v1\"\n" +
"1.2 k2=\"v2\"\n" +
"1.2 Finished in -- ms\n" +
"1 Finished in -- ms",
getTransformerDebugOutput());
}
@Test
void testEngineTwoStepTransform()
{
twoStepTransform(false, false, Level.DEBUG, "", 1234L);
// Note the first and last lines would only ever be logged on the router, but the expected data includes
// the extra "Finished" lines, sizes and renditions (if set in client data).
Assertions.assertEquals("" +
"1 txt pdf 1.2 KB wrapper\n" +
"1.1 txt doc 1.2 KB transformer1\n" +
"1.1 Finished in -- ms\n" +
"1.2 doc pdf 1.2 KB transformer2\n" +
"1.2 k1=\"v1\"\n" +
"1.2 k2=\"v2\"\n" +
"1.2 Finished in -- ms\n" +
"1 Finished in -- ms",
getTransformerDebugOutput());
}
@Test
void testRouterTwoStepTransformWithFailure()
{
twoStepTransform(true, true, Level.DEBUG, "", 1234L);
Assertions.assertEquals("" +
"1 txt pdf 1.2 KB wrapper\n" +
"1.1 txt doc transformer1\n" +
"1.2 doc pdf transformer2\n" +
"1.2 k1=\"v1\"\n" +
"1.2 k2=\"v2\"\n" +
"1.2 Dummy error",
getTransformerDebugOutput());
}
@Test
void testRenditionName()
{
twoStepTransform(true, false, Level.DEBUG, "renditionName", 1234L);
Assertions.assertEquals("" +
"1 txt pdf 1.2 KB -- renditionName -- wrapper\n" +
"1.1 txt doc transformer1\n" +
"1.2 doc pdf transformer2\n" +
"1.2 k1=\"v1\"\n" +
"1.2 k2=\"v2\"\n" +
"1 Finished in -- ms",
getTransformerDebugOutput());
}
@Test
void testMetadataExtract()
{
twoStepTransform(true, false, Level.DEBUG, "transform:alfresco-metadata-extract", 1234L);
Assertions.assertEquals("" +
"1 txt pdf 1.2 KB -- metadataExtract -- wrapper\n" +
"1.1 txt doc transformer1\n" +
"1.2 doc pdf transformer2\n" +
"1.2 k1=\"v1\"\n" +
"1.2 k2=\"v2\"\n" +
"1 Finished in -- ms",
getTransformerDebugOutput());
}
@Test
void testMetadataEmbed()
{
twoStepTransform(true, false, Level.DEBUG, "transform:alfresco-metadata-embed", 1234L);
Assertions.assertEquals("" +
"1 txt pdf 1.2 KB -- metadataEmbed -- wrapper\n" +
"1.1 txt doc transformer1\n" +
"1.2 doc pdf transformer2\n" +
"1.2 k1=\"v1\"\n" +
"1.2 k2=\"v2\"\n" +
"1 Finished in -- ms",
getTransformerDebugOutput());
}
@Test
void testSourceSize1Byte()
{
twoStepTransform(true, false, Level.DEBUG, "", 1);
Assertions.assertEquals("" +
"1 txt pdf 1 byte wrapper\n" +
"1.1 txt doc transformer1\n" +
"1.2 doc pdf transformer2\n" +
"1.2 k1=\"v1\"\n" +
"1.2 k2=\"v2\"\n" +
"1 Finished in -- ms",
getTransformerDebugOutput());
}
@Test
void testSourceSize23TB()
{
twoStepTransform(true, false, Level.DEBUG, "", 23L*1024*1024*1024*1024);
Assertions.assertEquals("" +
"1 txt pdf 23 TB wrapper\n" +
"1.1 txt doc transformer1\n" +
"1.2 doc pdf transformer2\n" +
"1.2 k1=\"v1\"\n" +
"1.2 k2=\"v2\"\n" +
"1 Finished in -- ms",
getTransformerDebugOutput());
}
@Test
void testLogFailureOnTEngine()
{
monitorLogs(Level.TRACE);
String origClientData = RepositoryClientData.builder().build().toString();
TransformReply reply = TransformReply.builder()
.withInternalContext(InternalContext.initialise(null))
.withErrorDetails("T-Request was null - a major error")
.withClientData(origClientData)
.build();
transformerDebug.setIsTRouter(false);
transformerDebug.logFailure(reply);
String expectedDebug = " T-Request was null - a major error";
Assertions.assertEquals(expectedDebug, getTransformerDebugOutput());
assertEquals(origClientData, reply.getClientData());
}
@Test
void testLogFailureOnTRouter()
{
monitorLogs(Level.TRACE);
String origClientData = RepositoryClientData.builder().withDebug().build().toString();
TransformReply reply = TransformReply.builder()
.withInternalContext(InternalContext.initialise(null))
.withErrorDetails("T-Request was null - a major error")
.withClientData(origClientData)
.build();
transformerDebug.setIsTRouter(true);
transformerDebug.logFailure(reply);
String expectedDebug = " T-Request was null - a major error";
String expectedClientData = origClientData+DEBUG_SEPARATOR+expectedDebug;
Assertions.assertEquals(expectedDebug, getTransformerDebugOutput());
assertEquals(expectedClientData, reply.getClientData());
}
@Test
void tesGetOptionAndValue()
{
String sixtyChars = "12345678 10 345678 20 345678 30 345678 40 345678 50 abcdefgh";
String sixtyOneChars = "12345678 10 345678 20 345678 30 345678 40 345678 50 abcd12345";
String expected = "12345678 10 345678 20 345678 30 345678 40 345678 50 ...12345";
assertEquals("ref key=\"value\"",
transformerDebug.getOptionAndValue("ref", "key", "value"));
assertEquals("ref key=\""+sixtyChars+"\"",
transformerDebug.getOptionAndValue("ref", "key", sixtyChars));
assertEquals("ref key=\""+expected+"\"",
transformerDebug.getOptionAndValue("ref", "key", sixtyOneChars));
}
}

View File

@@ -0,0 +1,50 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This program 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.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.config;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CoreFunctionTest
{
@Test
void isSupported()
{
assertTrue(CoreFunction.HTTP.isSupported("0.1"));
assertTrue(CoreFunction.HTTP.isSupported("2.5.6"));
assertFalse(CoreFunction.HTTP.isSupported("100000"));
assertFalse(CoreFunction.ACTIVE_MQ.isSupported("0.1"));
assertTrue(CoreFunction.ACTIVE_MQ.isSupported("2.5"));
assertFalse(CoreFunction.DIRECT_ACCESS_URL.isSupported(null));
assertFalse(CoreFunction.DIRECT_ACCESS_URL.isSupported(""));
assertFalse(CoreFunction.DIRECT_ACCESS_URL.isSupported("2.5"));
assertFalse(CoreFunction.DIRECT_ACCESS_URL.isSupported("2.5.6"));
assertTrue(CoreFunction.DIRECT_ACCESS_URL.isSupported("2.5.7-SNAPSHOT"));
assertTrue(CoreFunction.DIRECT_ACCESS_URL.isSupported("2.5.7-A4-SNAPSHOT"));
assertTrue(CoreFunction.DIRECT_ACCESS_URL.isSupported("2.5.7"));
assertTrue(CoreFunction.DIRECT_ACCESS_URL.isSupported("2.6"));
assertTrue(CoreFunction.DIRECT_ACCESS_URL.isSupported("999999"));
}
}

View File

@@ -0,0 +1,226 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This program 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.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.config;
import com.google.common.collect.ImmutableList;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.alfresco.transform.common.RequestParamMap.CONFIG_VERSION_DEFAULT;
import static org.alfresco.transform.common.RequestParamMap.DIRECT_ACCESS_URL;
import static org.alfresco.transform.config.CoreFunction.standardizeCoreVersion;
import static org.alfresco.transform.config.CoreVersionDecorator.CONFIG_VERSION_INCLUDES_CORE_VERSION;
import static org.alfresco.transform.config.CoreVersionDecorator.setCoreVersionOnMultiStepTransformers;
import static org.alfresco.transform.config.CoreVersionDecorator.setCoreVersionOnSingleStepTransformers;
import static org.alfresco.transform.config.CoreVersionDecorator.setOrClearCoreVersion;
import static org.junit.jupiter.api.Assertions.*;
class CoreVersionDecoratorTest
{
private static final int CONFIG_VERSION_ORIGINAL = Integer.valueOf(CONFIG_VERSION_DEFAULT);
private static final String SOME_NAME = "optionName";
public static final Set<TransformOption> SOME_OPTIONS = Set.of(new TransformOptionValue(false, "someOption"));
private static final Set<TransformOption> DIRECT_ACCESS_URL_OPTION = Set.of(new TransformOptionValue(false, DIRECT_ACCESS_URL));
private final Map<String, Set<TransformOption>> TRANSFORM_OPTIONS_WITHOUT_DIRECT_ACCESS_URL = new HashMap<>();
private final Map<String, Set<TransformOption>> TRANSFORM_OPTIONS_WITH_DIRECT_ACCESS_URL = new HashMap<>();
{
TRANSFORM_OPTIONS_WITHOUT_DIRECT_ACCESS_URL.put(SOME_NAME, SOME_OPTIONS);
TRANSFORM_OPTIONS_WITH_DIRECT_ACCESS_URL.put(SOME_NAME, SOME_OPTIONS);
TRANSFORM_OPTIONS_WITH_DIRECT_ACCESS_URL.put(DIRECT_ACCESS_URL, DIRECT_ACCESS_URL_OPTION);
}
private TransformConfig newTransformConfig(String version1, String version2, String version3, String version4, String version5,
boolean hasDirectAccessUrls, boolean multiStepHaveDirectAccessUrls)
{
HashSet<String> transformOptions1 = new HashSet<>();
HashSet<String> transformOptions2 = new HashSet<>(transformOptions1);
transformOptions2.add(SOME_NAME);
HashSet<String> transformOptions3 = new HashSet<>(transformOptions1);
HashSet<String> transformOptions4 = new HashSet<>(transformOptions1);
transformOptions4.addAll(transformOptions2);
HashSet<String> transformOptions5 = new HashSet<>(transformOptions1);
transformOptions5.addAll(transformOptions2);
transformOptions5.addAll(transformOptions3);
if (hasDirectAccessUrls)
{
transformOptions1.add(DIRECT_ACCESS_URL);
transformOptions2.add(DIRECT_ACCESS_URL);
transformOptions3.add(DIRECT_ACCESS_URL);
}
if (multiStepHaveDirectAccessUrls)
{
transformOptions4.add(DIRECT_ACCESS_URL);
transformOptions5.add(DIRECT_ACCESS_URL);
}
return TransformConfig.builder()
.withTransformOptions(hasDirectAccessUrls ? TRANSFORM_OPTIONS_WITH_DIRECT_ACCESS_URL : TRANSFORM_OPTIONS_WITHOUT_DIRECT_ACCESS_URL)
.withTransformers(ImmutableList.of(
Transformer.builder()
.withTransformerName("transformer1")
.withCoreVersion(version1)
.withTransformOptions(transformOptions1)
.build(),
Transformer.builder()
.withTransformerName("transformer2")
.withCoreVersion(version2)
.withTransformOptions(transformOptions2)
.build(),
Transformer.builder()
.withTransformerName("transformer3")
.withCoreVersion(version3)
.withTransformOptions(transformOptions3)
.build(),
Transformer.builder()
.withTransformerName("pipeline4")
.withCoreVersion(version4)
.withTransformerPipeline(List.of(
new TransformStep("transformer1", "mimetype/c"),
new TransformStep("transformer2", null)))
.withTransformOptions(transformOptions4)
.build(),
Transformer.builder()
.withTransformerName("failover5")
.withCoreVersion(version5)
.withTransformerFailover(List.of("transformer1", "transformer2", "transformer3"))
.withTransformOptions(transformOptions5)
.build()))
.build();
}
@Test
void setCoreVersionOnSingleStepTransformersTest()
{
TransformConfig transformConfigReadFormTEngineJson = newTransformConfig(
null, null, null, null, null,
false, false);
setCoreVersionOnSingleStepTransformers(transformConfigReadFormTEngineJson, "2.3.1");
assertEquals(newTransformConfig("2.3.1", "2.3.1", "2.3.1", null, null,
false, false), transformConfigReadFormTEngineJson);
// Now with Direct Access URLs
transformConfigReadFormTEngineJson = newTransformConfig(
null, null, null, null, null,
false, false);
setCoreVersionOnSingleStepTransformers(transformConfigReadFormTEngineJson, "2.5.7");
assertEquals(newTransformConfig("2.5.7", "2.5.7", "2.5.7", null, null,
true, false), transformConfigReadFormTEngineJson);
}
@Test
void setCoreVersionOnMultiStepTransformersTest()
{
// All source T-Engines provide a coreVersion and have had the coreVersion added
TransformConfig decoratedSingleStepTransformConfig = newTransformConfig(
"2.1", "2.2", "1.2.3", null, null,
false, false);
setCoreVersionOnMultiStepTransformers(decoratedSingleStepTransformConfig.getTransformOptions(),
decoratedSingleStepTransformConfig.getTransformers());
assertEquals(newTransformConfig("2.1", "2.2", "1.2.3", "2.1", "1.2.3",
false, false), decoratedSingleStepTransformConfig);
// Some source T-Engines are pre coreVersion
decoratedSingleStepTransformConfig = newTransformConfig(
"2.1", null, null, null, null,
false, false);
setCoreVersionOnMultiStepTransformers(decoratedSingleStepTransformConfig.getTransformOptions(),
decoratedSingleStepTransformConfig.getTransformers());
assertEquals(newTransformConfig("2.1", null, null, null, null,
false, false), decoratedSingleStepTransformConfig);
// Now with Direct Access URLs
decoratedSingleStepTransformConfig = newTransformConfig("2.5.7", "2.5.7", "2.5.7", null, null,
true, false);
setCoreVersionOnMultiStepTransformers(decoratedSingleStepTransformConfig.getTransformOptions(),
decoratedSingleStepTransformConfig.getTransformers());
assertEquals(newTransformConfig("2.5.7", "2.5.7", "2.5.7", "2.5.7", "2.5.7",
true, true), decoratedSingleStepTransformConfig);
}
@Test
void setOrClearCoreVersionTest()
{
// All source T-Engines provide a coreVersion
TransformConfig transformConfigWithCoreVersion = newTransformConfig(
"2.1", "2.2", "1.2.3", "2.1", "1.2.3",
false, false);
assertEquals(newTransformConfig(null, null, null, null, null,
false, false),
setOrClearCoreVersion(transformConfigWithCoreVersion, CONFIG_VERSION_ORIGINAL));
assertEquals(newTransformConfig("2.1", "2.2", "1.2.3", "2.1", "1.2.3",
false, false),
setOrClearCoreVersion(transformConfigWithCoreVersion, CONFIG_VERSION_INCLUDES_CORE_VERSION));
assertEquals(newTransformConfig("2.1", "2.2", "1.2.3", "2.1", "1.2.3",
false, false),
setOrClearCoreVersion(transformConfigWithCoreVersion, CONFIG_VERSION_INCLUDES_CORE_VERSION+100));
// Some source T-Engines are pre coreVersion
TransformConfig transformConfigWithoutCoreVersion = newTransformConfig(
null, null, null, null, null,
false, false);
assertEquals(newTransformConfig(null, null, null, null, null,
false, false),
setOrClearCoreVersion(transformConfigWithoutCoreVersion, CONFIG_VERSION_ORIGINAL));
assertEquals(newTransformConfig(null, null, null, null, null,
false, false),
setOrClearCoreVersion(transformConfigWithoutCoreVersion, CONFIG_VERSION_INCLUDES_CORE_VERSION));
// Now with Direct Access URLs
transformConfigWithCoreVersion = newTransformConfig(
"2.5.7", "2.5.7", "2.5.7", "2.5.7", "2.5.7",
true, true);
assertEquals(newTransformConfig(null, null, null, null, null,
false, false),
setOrClearCoreVersion(transformConfigWithCoreVersion, CONFIG_VERSION_ORIGINAL));
assertEquals(newTransformConfig("2.5.7", "2.5.7", "2.5.7", "2.5.7", "2.5.7",
true, true),
setOrClearCoreVersion(transformConfigWithCoreVersion, CONFIG_VERSION_INCLUDES_CORE_VERSION));
}
@Test
void standardizeCoreVersionTest()
{
assertEquals("2.5.7", standardizeCoreVersion("2.5.7"));
assertEquals("2.5.7", standardizeCoreVersion("2.5.7-SNAPSHOT"));
assertEquals("2", standardizeCoreVersion("2"));
assertEquals("2.5.7", standardizeCoreVersion("2.5.7-A-SNAPSHOT"));
}
}

View File

@@ -0,0 +1,300 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2015 - 2022 Alfresco Software Limited
* %%
* This program 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.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.config.reader;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ImmutableMap;
import org.alfresco.transform.config.TransformConfig;
import org.alfresco.transform.config.TransformOption;
import org.alfresco.transform.config.TransformOptionGroup;
import org.alfresco.transform.config.TransformOptionValue;
import org.alfresco.transform.config.Transformer;
import org.alfresco.transform.config.SupportedSourceAndTarget;
import org.alfresco.transform.config.TransformStep;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
public class TransformConfigReaderJsonTest
{
@Test
public void testEmptyRoutesFile() throws Exception
{
final Resource resource = new ClassPathResource("config/sample1.json");
final TransformConfigReader loader = TransformConfigReaderFactory.create(resource);
TransformConfig transformConfig = loader.load();
final List<Transformer> transformers = transformConfig.getTransformers();
assertNotNull(transformers);
assertEquals(Collections.emptyList(), transformers);
}
@Test
public void testMixedRoutesFile() throws Exception
{
final List<Transformer> expected = prepareSample2();
final Resource resource = new ClassPathResource("config/sample2.json");
final TransformConfigReader loader = TransformConfigReaderFactory.create(resource);
TransformConfig transformConfig = loader.load();
final List<Transformer> transformers = transformConfig.getTransformers();
assertNotNull(transformers);
assertEquals(expected.size(), transformers.size());
assertTrue(expected.containsAll(transformers));
}
private List<Transformer> prepareSample2()
{
return List.of(
Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("image/gif")
.withTargetMediaType("image/gif")
.build()
))
.withTransformOptions(ImmutableSet.of("imageMagickOptions"))
.build(),
Transformer.builder()
.withTransformerName("IMAGEMAGICK")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("image/gif")
.withTargetMediaType("image/gif")
.build()
))
.withTransformOptions(ImmutableSet.of("imageMagickOptions"))
.build(),
Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/msword")
.withTargetMediaType("application/pdf")
.withMaxSourceSizeBytes(18874368L)
.build()
))
.build(),
Transformer.builder()
.withTransformerName("PDF_RENDERER")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/vnd.ms-powerpoint")
.withTargetMediaType("application/pdf")
.withPriority(55)
.withMaxSourceSizeBytes(50331648L)
.build()
))
.build(),
Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/mediawiki")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/css")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/html")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/x-javascript")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/dita+xml")
.withTargetMediaType("text/plain")
.build()
))
.withTransformOptions(ImmutableSet.of("stringOptions"))
.build(),
Transformer.builder()
.withTransformerName("officeToImageViaPdf")
.withTransformerPipeline(ImmutableList.of(
new TransformStep("libreoffice", "application/pdf"),
new TransformStep("pdfToImageViaPng", null)
))
.withTransformOptions(ImmutableSet.of(
"pdfRendererOptions",
"imageMagickOptions"
))
.build(),
Transformer.builder()
.withTransformerName("textToImageViaPdf")
.withTransformerPipeline(ImmutableList.of(
new TransformStep("libreoffice", "application/pdf"),
new TransformStep("pdfToImageViaPng", null)
))
.withTransformOptions(ImmutableSet.of(
"pdfRendererOptions",
"imageMagickOptions"
))
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/gif")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/jpeg")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/tiff")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/png")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/gif")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/jpeg")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/tiff")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/png")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/gif")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/jpeg")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/tiff")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/png")
.build()
))
.withTransformOptions(ImmutableSet.of(
"pdfRendererOptions",
"imageMagickOptions"
))
.build()
);
}
@Test
public void testRouteFileWithTransformOptions() throws Exception
{
final List<Transformer> expected = prepareSample5Transformers();
Map<String, Set<TransformOption>> expectedOptions = prepareSample5Options();
final Resource resource = new ClassPathResource("config/sample5.json");
final TransformConfigReader loader = TransformConfigReaderFactory.create(resource);
TransformConfig transformConfig = loader.load();
final List<Transformer> transformers = transformConfig.getTransformers();
Map<String, Set<TransformOption>> transformOptions = transformConfig.getTransformOptions();
assertNotNull(transformers);
assertEquals(expected.size(), transformers.size());
assertTrue(expected.containsAll(transformers));
assertEquals(expectedOptions, transformOptions);
}
private List<Transformer> prepareSample5Transformers()
{
return List.of(
Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("image/gif")
.withTargetMediaType("image/gif")
.build()
))
.withTransformOptions(ImmutableSet.of("imageMagickOptions"))
.build()
);
}
public static Map<String, Set<TransformOption>> prepareSample5Options()
{
return ImmutableMap.of(
"imageMagickOptions", ImmutableSet.of(
new TransformOptionValue(false, "alphaRemove"),
new TransformOptionValue(false, "autoOrient"),
new TransformOptionValue(false, "startPage"),
new TransformOptionValue(false, "endPage"),
new TransformOptionGroup(false, ImmutableSet.of(
new TransformOptionValue(false, "cropGravity"),
new TransformOptionValue(false, "cropWidth"),
new TransformOptionValue(false, "cropHeight"),
new TransformOptionValue(false, "cropPercentage"),
new TransformOptionValue(false, "cropXOffset"),
new TransformOptionValue(false, "cropYOffset")
)),
new TransformOptionGroup(false, ImmutableSet.of(
new TransformOptionValue(false, "thumbnail"),
new TransformOptionValue(false, "resizeHeight"),
new TransformOptionValue(false, "resizeWidth"),
new TransformOptionValue(false, "resizePercentage"),
new TransformOptionValue(false, "allowEnlargement"),
new TransformOptionValue(false, "maintainAspectRatio")
)))
);
}
}

View File

@@ -0,0 +1,245 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2015 - 2022 Alfresco Software Limited
* %%
* This program 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.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.config.reader;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.transform.config.TransformConfig;
import org.alfresco.transform.config.TransformOption;
import org.alfresco.transform.config.Transformer;
import org.alfresco.transform.config.SupportedSourceAndTarget;
import org.alfresco.transform.config.TransformStep;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
public class TransformConfigReaderYamlTest
{
@Test
public void testEmptyRoutesFile() throws Exception
{
final Resource resource = new ClassPathResource("config/sample3.yaml");
final TransformConfigReader loader = TransformConfigReaderFactory.create(resource);
TransformConfig transformConfig = loader.load();
final List<Transformer> transformers = transformConfig.getTransformers();
assertNotNull(transformers);
assertEquals(Collections.emptyList(), transformers);
}
@Test
public void testMixedRoutesFile() throws Exception
{
final List<Transformer> expected = prepareSample4();
Map<String, Set<TransformOption>> expectedOptions = TransformConfigReaderJsonTest.prepareSample5Options();
final Resource resource = new ClassPathResource("config/sample4.yaml");
final TransformConfigReader loader = TransformConfigReaderFactory.create(resource);
TransformConfig transformConfig = loader.load();
final List<Transformer> transformers = transformConfig.getTransformers();
Map<String, Set<TransformOption>> transformOptions = transformConfig.getTransformOptions();
assertNotNull(transformers);
assertEquals(expected.size(), transformers.size());
assertTrue(expected.containsAll(transformers));
assertEquals(expectedOptions, transformOptions);
}
private List<Transformer> prepareSample4()
{
var result = new ArrayList<Transformer>();
result.add(Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("image/gif")
.withTargetMediaType("image/gif")
.build()
))
.withTransformOptions(ImmutableSet.of("imageMagickOptions"))
.build());
result.add(Transformer.builder()
.withTransformerName("IMAGEMAGICK")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("image/gif")
.withTargetMediaType("image/gif")
.build()
))
.withTransformOptions(ImmutableSet.of("imageMagickOptions"))
.build());
result.add(Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/msword")
.withTargetMediaType("application/pdf")
.withMaxSourceSizeBytes(18874368L)
.build()
))
.build());
result.add(Transformer.builder()
.withTransformerName("PDF_RENDERER")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/vnd.ms-powerpoint")
.withTargetMediaType("application/pdf")
.withPriority(55)
.withMaxSourceSizeBytes(50331648L)
.build()
))
.build());
result.add(Transformer.builder()
.withTransformerName("CORE_AIO")
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/mediawiki")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/css")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/html")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/x-javascript")
.withTargetMediaType("text/plain")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("application/dita+xml")
.withTargetMediaType("text/plain")
.build()
))
.withTransformOptions(ImmutableSet.of("stringOptions"))
.build());
result.add(Transformer.builder()
.withTransformerName("officeToImageViaPdf")
.withTransformerPipeline(ImmutableList.of(
new TransformStep("libreoffice", "application/pdf"),
new TransformStep("pdfToImageViaPng", null)
))
.withTransformOptions(ImmutableSet.of(
"pdfRendererOptions",
"imageMagickOptions"
))
.build());
result.add(Transformer.builder()
.withTransformerName("textToImageViaPdf")
.withTransformerPipeline(ImmutableList.of(
new TransformStep("libreoffice", "application/pdf"),
new TransformStep("pdfToImageViaPng", null)
))
.withTransformOptions(ImmutableSet.of(
"pdfRendererOptions",
"imageMagickOptions"
))
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/gif")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/jpeg")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/tiff")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/plain")
.withTargetMediaType("image/png")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/gif")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/jpeg")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/tiff")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/csv")
.withTargetMediaType("image/png")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/gif")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/jpeg")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/tiff")
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType("text/xml")
.withTargetMediaType("image/png")
.build()
))
.withTransformOptions(ImmutableSet.of(
"pdfRendererOptions",
"imageMagickOptions"
))
.build());
return result;
}
}

View File

@@ -0,0 +1,199 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This program 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.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.messages;
import static org.alfresco.transform.common.Mimetype.MIMETYPE_IMAGE_PNG;
import static org.alfresco.transform.common.Mimetype.MIMETYPE_PDF;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.UUID;
import org.alfresco.transform.client.model.TransformRequest;
import org.junit.jupiter.api.Test;
import org.springframework.validation.DirectFieldBindingResult;
import org.springframework.validation.Errors;
/**
* TransformRequestValidatorTest
* <p/>
* Unit test that checks the Transform request validation.
*/
public class TransformRequestValidatorTest
{
private TransformRequestValidator validator = new TransformRequestValidator();
@Test
public void testSupports()
{
assertTrue(validator.supports(TransformRequest.class));
}
@Test
public void testNullRequest()
{
Errors errors = new DirectFieldBindingResult(null, "request");
validator.validate(null, errors);
assertEquals(1, errors.getAllErrors().size());
assertEquals("request cannot be null",
errors.getAllErrors().iterator().next().getDefaultMessage());
}
@Test
public void testMissingId()
{
TransformRequest request = new TransformRequest();
Errors errors = new DirectFieldBindingResult(request, "request");
validator.validate(request, errors);
assertFalse(errors.getAllErrors().isEmpty());
assertEquals("requestId cannot be null or empty",
errors.getAllErrors().iterator().next().getDefaultMessage());
}
@Test
public void testMissingSourceSize()
{
TransformRequest request = new TransformRequest();
request.setRequestId(UUID.randomUUID().toString());
request.setSourceReference(UUID.randomUUID().toString());
Errors errors = new DirectFieldBindingResult(request, "request");
validator.validate(request, errors);
assertFalse(errors.getAllErrors().isEmpty());
assertEquals("sourceSize cannot be null or have its value smaller than 0",
errors.getAllErrors().iterator().next().getDefaultMessage());
}
@Test
public void testMissingSourceMediaType()
{
TransformRequest request = new TransformRequest();
request.setRequestId(UUID.randomUUID().toString());
request.setSourceReference(UUID.randomUUID().toString());
request.setSourceSize(32L);
Errors errors = new DirectFieldBindingResult(request, "request");
validator.validate(request, errors);
assertFalse(errors.getAllErrors().isEmpty());
assertEquals("sourceMediaType cannot be null or empty",
errors.getAllErrors().iterator().next().getDefaultMessage());
}
@Test
public void testMissingTargetMediaType()
{
TransformRequest request = new TransformRequest();
request.setRequestId(UUID.randomUUID().toString());
request.setSourceReference(UUID.randomUUID().toString());
request.setSourceSize(32L);
request.setSourceMediaType(MIMETYPE_PDF);
Errors errors = new DirectFieldBindingResult(request, "request");
validator.validate(request, errors);
assertFalse(errors.getAllErrors().isEmpty());
assertEquals("targetMediaType cannot be null or empty",
errors.getAllErrors().iterator().next().getDefaultMessage());
}
@Test
public void testMissingTargetExtension()
{
TransformRequest request = new TransformRequest();
request.setRequestId(UUID.randomUUID().toString());
request.setSourceReference(UUID.randomUUID().toString());
request.setSourceSize(32L);
request.setSourceMediaType(MIMETYPE_PDF);
request.setTargetMediaType(MIMETYPE_IMAGE_PNG);
Errors errors = new DirectFieldBindingResult(request, "request");
validator.validate(request, errors);
assertFalse(errors.getAllErrors().isEmpty());
assertEquals("targetExtension cannot be null or empty",
errors.getAllErrors().iterator().next().getDefaultMessage());
}
@Test
public void testMissingClientData()
{
TransformRequest request = new TransformRequest();
request.setRequestId(UUID.randomUUID().toString());
request.setSourceReference(UUID.randomUUID().toString());
request.setSourceSize(32L);
request.setSourceMediaType(MIMETYPE_PDF);
request.setTargetMediaType(MIMETYPE_IMAGE_PNG);
request.setTargetExtension("png");
Errors errors = new DirectFieldBindingResult(request, "request");
validator.validate(request, errors);
assertFalse(errors.getAllErrors().isEmpty());
assertEquals("clientData cannot be null or empty",
errors.getAllErrors().iterator().next().getDefaultMessage());
}
@Test
public void testMissingSchema()
{
TransformRequest request = new TransformRequest();
request.setRequestId(UUID.randomUUID().toString());
request.setSourceReference(UUID.randomUUID().toString());
request.setSourceSize(32L);
request.setSourceMediaType(MIMETYPE_PDF);
request.setTargetMediaType(MIMETYPE_IMAGE_PNG);
request.setTargetExtension("png");
request.setClientData("ACS");
request.setSchema(-1);
Errors errors = new DirectFieldBindingResult(request, "request");
validator.validate(request, errors);
assertFalse(errors.getAllErrors().isEmpty());
assertEquals("schema cannot be less than 0",
errors.getAllErrors().iterator().next().getDefaultMessage());
}
@Test
public void testCompleteTransformRequest()
{
TransformRequest request = new TransformRequest();
request.setRequestId(UUID.randomUUID().toString());
request.setSourceReference(UUID.randomUUID().toString());
request.setSourceSize(32L);
request.setSourceMediaType(MIMETYPE_PDF);
request.setTargetMediaType(MIMETYPE_IMAGE_PNG);
request.setTargetExtension("png");
request.setClientData("ACS");
Errors errors = new DirectFieldBindingResult(request, "request");
validator.validate(request, errors);
assertTrue(errors.getAllErrors().isEmpty());
}
}

View File

@@ -0,0 +1,566 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This program 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.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.messages;
import com.google.common.collect.ImmutableMap;
import org.alfresco.transform.client.model.InternalContext;
import org.alfresco.transform.client.model.MultiStep;
import org.alfresco.transform.client.model.TransformReply;
import org.alfresco.transform.common.TransformerDebug;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.UUID;
import static org.alfresco.transform.messages.TransformStack.OPTIONS_LEVEL;
import static org.alfresco.transform.messages.TransformStack.SEPARATOR;
import static org.alfresco.transform.messages.TransformStack.TOP_STACK_LEVEL;
import static org.alfresco.transform.messages.TransformStack.getInitialSourceReference;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.doReturn;
class TransformStackTest
{
private static long START = System.currentTimeMillis();
private static String STEP = SEPARATOR + "name" + SEPARATOR + "source" + SEPARATOR + "target";
@Mock
private TransformerDebug transformerDebug;
@Mock
private TransformReply reply;
// Note: If you change this also change AbstractRouterTest.testNestedTransform as they match
public static final ImmutableMap<String, TransformStack.LevelBuilder> TEST_LEVELS = ImmutableMap.of(
"top", TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
.withStep("pipeline 1-N", "type1", "typeN"),
"pipeline 1-N", TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
.withStep("transform1-2", "type1", "type2")
.withStep("pipeline 2-3", "type2", "type3")
.withStep("failover 3-N", "type3", "typeN"),
"pipeline 2-3", TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
.withStep("transform2-4", "type2", "type4")
.withStep("transform4-3", "type4", "type3"),
"failover 3-N", TransformStack.levelBuilder(TransformStack.FAILOVER_FLAG)
.withStep("transform3-Na", "type3", "typeN")
.withStep("transform3-Nb", "type3", "typeN")
.withStep("pipeline 3-Nc", "type3", "typeN"),
"pipeline 3-Nc", TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
.withStep("transform3-5", "type3", "type5")
.withStep("pipeline 5-N", "type5", "typeN"),
"pipeline 5-N", TransformStack.levelBuilder(TransformStack.PIPELINE_FLAG)
.withStep("transform5-6", "type5", "type6")
.withStep("transform6-N", "type6", "typeN"));
private final InternalContext internalContext = new InternalContext();
private final Map<String, String> options = ImmutableMap.of("key1", "value1", "key2", "", "key3", "value3");
private final String sourceReference = UUID.randomUUID().toString();
@BeforeEach
void setUp()
{
MockitoAnnotations.openMocks(this);
// Repeat what is done by Router.initialiseContextWhenReceivedByRouter
internalContext.setMultiStep(new MultiStep());
internalContext.getMultiStep().setTransformsToBeDone(new ArrayList<>());
TransformStack.setInitialTransformRequestOptions(internalContext, options);
TransformStack.setInitialSourceReference(internalContext, sourceReference);
doReturn(internalContext).when(reply).getInternalContext();
}
@Test
public void testOptions()
{
assertEquals(options, TransformStack.getInitialTransformRequestOptions(internalContext));
}
@Test
public void testOptionsEmpty()
{
ImmutableMap<String, String> options = ImmutableMap.of();
TransformStack.setInitialTransformRequestOptions(internalContext, options);
assertEquals(options, TransformStack.getInitialTransformRequestOptions(internalContext));
}
@Test
public void testOptionsEmptyLastValue()
{
ImmutableMap<String, String> options = ImmutableMap.of("key1", "value1", "key2", "");
TransformStack.setInitialTransformRequestOptions(internalContext, options);
assertEquals(options, TransformStack.getInitialTransformRequestOptions(internalContext));
}
@Test
public void testSourceReference()
{
assertEquals(sourceReference, getInitialSourceReference(internalContext));
}
@Test
public void testSourceReferenceNull()
{
TransformStack.setInitialSourceReference(internalContext, null);
assertEquals(null, getInitialSourceReference(internalContext));
}
@Test
public void testSourceReferenceBlank()
{
TransformStack.setInitialSourceReference(internalContext, "");
assertEquals("", getInitialSourceReference(internalContext));
}
@Test
public void testLevelBuilder()
{
assertEquals("P⏐1⏐0⏐0⏐pipeline 1-N⏐type1⏐typeN", TEST_LEVELS.get("top").build());
assertEquals("P⏐1⏐0⏐0⏐failover 3-N⏐type3⏐typeN⏐pipeline 2-3⏐type2⏐type3⏐transform1-2⏐type1⏐type2", TEST_LEVELS.get("pipeline 1-N").build());
assertEquals("F⏐1⏐0⏐0⏐pipeline 3-Nc⏐type3⏐typeN⏐transform3-Nb⏐type3⏐typeN⏐transform3-Na⏐type3⏐typeN", TEST_LEVELS.get("failover 3-N").build());
}
@Test
public void testAttemptedRetries()
{
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
assertEquals(0, TransformStack.getAttemptedRetries(internalContext));
TransformStack.incrementAttemptedRetries(internalContext);
assertEquals(1, TransformStack.getAttemptedRetries(internalContext));
TransformStack.incrementAttemptedRetries(internalContext);
assertEquals(2, TransformStack.getAttemptedRetries(internalContext));
TransformStack.resetAttemptedRetries(internalContext);
assertEquals(0, TransformStack.getAttemptedRetries(internalContext));
}
@Test
public void testReference()
{
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
assertEquals("1", TransformStack.getReference(internalContext));
TransformStack.setReference(internalContext, "123");
assertEquals("123", TransformStack.getReference(internalContext));
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("pipeline 1-N"));
assertEquals("123.1", TransformStack.getReference(internalContext));
TransformStack.incrementReference(internalContext);
assertEquals("123.2", TransformStack.getReference(internalContext));
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("pipeline 2-3"));
assertEquals("123.2.1", TransformStack.getReference(internalContext));
TransformStack.removeTransformLevel(internalContext);
TransformStack.incrementReference(internalContext);
assertEquals("123.3", TransformStack.getReference(internalContext));
TransformStack.removeTransformLevel(internalContext);
assertEquals("123", TransformStack.getReference(internalContext));
}
@Test
public void testSetReferenceInADummyTopLevelIfUnset()
{
// Used when creating a TransformRouterException prior to setting the reference
// Undo setup()
internalContext.getMultiStep().setTransformsToBeDone(new ArrayList<>());
TransformStack.setReferenceInADummyTopLevelIfUnset(internalContext, "23");
assertEquals("23", TransformStack.getReference(internalContext));
}
@Test
public void testReplicateWorkflowWithSuccess()
{
replicateWorkflowStepsPriorToFailureOrSuccess();
// Assume a successful transform, so successful there should be no more steps or levels after this
TransformStack.removeSuccessfulStep(reply, transformerDebug);
assertTrue(TransformStack.isFinished(internalContext));
}
@Test
// Tests the failure on a transform indirectly (it is a step in a pipeline) under a failover transformer.
public void testReplicateWorkflowWithFailure()
{
replicateWorkflowStepsPriorToFailureOrSuccess();
// Assume a transform failure. While loop should remove the 2 indirect pipeline levels
int removedLevels = 0;
while (!TransformStack.isParentAFailover(internalContext))
{
removedLevels++;
TransformStack.removeTransformLevel(internalContext);
}
Assertions.assertEquals(2, removedLevels);
assertTrue(TransformStack.isLastStepInTransformLevel(internalContext));
TransformStack.removeFailedStep(reply, transformerDebug); // Should remove the rest as failure was last step in failover
assertTrue(TransformStack.isFinished(internalContext));
}
// Replicates the sequence of TransformStack method calls for a workflow. Steps through each transform, with
// some failures in a failover transformer, before returning to allow the calling test method to either fail the
// next step or not.
private void replicateWorkflowStepsPriorToFailureOrSuccess()
{
// Initial transform request, so add a level
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
assertFalse(TransformStack.isFinished(internalContext));
TransformStack.Step step = TransformStack.currentStep(internalContext);
assertEquals("pipeline 1-N", step.getTransformerName());
assertEquals("type1", step.getSourceMediaType());
assertEquals("typeN", step.getTargetMediaType());
assertEquals(null, TransformStack.getParentName(internalContext));
assertFalse(TransformStack.isParentAFailover(internalContext));
// Because it is a pipeline, add a level
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("pipeline 1-N"));
assertFalse(TransformStack.isFinished(internalContext));
step = TransformStack.currentStep(internalContext);
assertEquals("transform1-2", step.getTransformerName());
assertEquals("type1", step.getSourceMediaType());
assertEquals("type2", step.getTargetMediaType());
assertEquals("pipeline 1-N", TransformStack.getParentName(internalContext));
assertFalse(TransformStack.isParentAFailover(internalContext));
// Assume a successful transform, so move on to next step add a level
TransformStack.removeSuccessfulStep(reply, transformerDebug);
assertFalse(TransformStack.isFinished(internalContext));
step = TransformStack.currentStep(internalContext);
assertEquals("pipeline 2-3", step.getTransformerName());
assertEquals("type2", step.getSourceMediaType());
assertEquals("type3", step.getTargetMediaType());
assertEquals("pipeline 1-N", TransformStack.getParentName(internalContext));
assertFalse(TransformStack.isParentAFailover(internalContext));
// Because it is a pipeline, add a level
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("pipeline 2-3"));
assertFalse(TransformStack.isFinished(internalContext));
step = TransformStack.currentStep(internalContext);
assertEquals("transform2-4", step.getTransformerName());
assertEquals("type2", step.getSourceMediaType());
assertEquals("type4", step.getTargetMediaType());
assertEquals("pipeline 2-3", TransformStack.getParentName(internalContext));
assertFalse(TransformStack.isParentAFailover(internalContext));
// Assume a successful transform, so move on to next step add a level
TransformStack.removeSuccessfulStep(reply, transformerDebug);
assertFalse(TransformStack.isFinished(internalContext));
step = TransformStack.currentStep(internalContext);
assertEquals("transform4-3", step.getTransformerName());
assertEquals("type4", step.getSourceMediaType());
assertEquals("type3", step.getTargetMediaType());
assertEquals("pipeline 2-3", TransformStack.getParentName(internalContext));
assertFalse(TransformStack.isParentAFailover(internalContext));
// Assume a successful transform, so move on to next step add a level
TransformStack.removeSuccessfulStep(reply, transformerDebug);
assertFalse(TransformStack.isFinished(internalContext));
step = TransformStack.currentStep(internalContext);
assertEquals("failover 3-N", step.getTransformerName());
assertEquals("type3", step.getSourceMediaType());
assertEquals("typeN", step.getTargetMediaType());
assertEquals("pipeline 1-N", TransformStack.getParentName(internalContext));
assertFalse(TransformStack.isParentAFailover(internalContext));
// Because it is a failover, add a level
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("failover 3-N"));
step = TransformStack.currentStep(internalContext);
assertEquals("transform3-Na", step.getTransformerName());
assertEquals("type3", step.getSourceMediaType());
assertEquals("typeN", step.getTargetMediaType());
assertEquals("failover 3-N", TransformStack.getParentName(internalContext));
assertTrue(TransformStack.isParentAFailover(internalContext));
// Assume 1st failover step fails
while (!TransformStack.isParentAFailover(internalContext))
{
TransformStack.removeTransformLevel(internalContext);
}
assertFalse(TransformStack.isLastStepInTransformLevel(internalContext));
TransformStack.removeFailedStep(reply, transformerDebug);
assertFalse(TransformStack.isFinished(internalContext));
step = TransformStack.currentStep(internalContext);
assertEquals("transform3-Nb", step.getTransformerName());
assertEquals("type3", step.getSourceMediaType());
assertEquals("typeN", step.getTargetMediaType());
assertEquals("failover 3-N", TransformStack.getParentName(internalContext));
assertTrue(TransformStack.isParentAFailover(internalContext));
// Assume 2nd failover step fails
while (!TransformStack.isParentAFailover(internalContext))
{
TransformStack.removeTransformLevel(internalContext);
}
assertFalse(TransformStack.isLastStepInTransformLevel(internalContext));
TransformStack.removeFailedStep(reply, transformerDebug);
assertFalse(TransformStack.isFinished(internalContext));
step = TransformStack.currentStep(internalContext);
assertEquals("pipeline 3-Nc", step.getTransformerName());
assertEquals("type3", step.getSourceMediaType());
assertEquals("typeN", step.getTargetMediaType());
assertEquals("failover 3-N", TransformStack.getParentName(internalContext));
assertTrue(TransformStack.isParentAFailover(internalContext));
// Because it is a pipeline, add a level
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("pipeline 3-Nc"));
assertFalse(TransformStack.isFinished(internalContext));
step = TransformStack.currentStep(internalContext);
assertEquals("transform3-5", step.getTransformerName());
assertEquals("type3", step.getSourceMediaType());
assertEquals("type5", step.getTargetMediaType());
assertEquals("pipeline 3-Nc", TransformStack.getParentName(internalContext));
assertFalse(TransformStack.isParentAFailover(internalContext));
// Assume a successful transform, so move on to next step add a level
TransformStack.removeSuccessfulStep(reply, transformerDebug);
assertFalse(TransformStack.isFinished(internalContext));
step = TransformStack.currentStep(internalContext);
assertEquals("pipeline 5-N", step.getTransformerName());
assertEquals("type5", step.getSourceMediaType());
assertEquals("typeN", step.getTargetMediaType());
assertEquals("pipeline 3-Nc", TransformStack.getParentName(internalContext));
assertFalse(TransformStack.isParentAFailover(internalContext));
// Because it is a pipeline, add a level
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("pipeline 5-N"));
assertFalse(TransformStack.isFinished(internalContext));
step = TransformStack.currentStep(internalContext);
assertEquals("transform5-6", step.getTransformerName());
assertEquals("type5", step.getSourceMediaType());
assertEquals("type6", step.getTargetMediaType());
assertEquals("pipeline 5-N", TransformStack.getParentName(internalContext));
assertFalse(TransformStack.isParentAFailover(internalContext));
// Assume a successful transform, so move on to next step add a level
TransformStack.removeSuccessfulStep(reply, transformerDebug);
assertFalse(TransformStack.isFinished(internalContext));
step = TransformStack.currentStep(internalContext);
assertEquals("transform6-N", step.getTransformerName());
assertEquals("type6", step.getSourceMediaType());
assertEquals("typeN", step.getTargetMediaType());
assertEquals("pipeline 5-N", TransformStack.getParentName(internalContext));
assertFalse(TransformStack.isParentAFailover(internalContext));
}
@Test
// Tests a workflow where all transforms are successful, using a loop.
public void testWorkflowWithLoop()
{
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
int transformStepCount = 0;
do
{
transformStepCount++;
TransformStack.Step step = TransformStack.currentStep(internalContext);
String transformerName = step.getTransformerName();
int depth = internalContext.getMultiStep().getTransformsToBeDone().size() - 2;
System.out.println(transformStepCount + " ".substring(0, depth*2+1) + transformerName);
TransformStack.LevelBuilder nextLevel = TEST_LEVELS.get(transformerName);
if (nextLevel == null)
{
TransformStack.removeSuccessfulStep(reply, transformerDebug);
}
else
{
TransformStack.addTransformLevel(internalContext, nextLevel);
}
if (transformStepCount >= 25)
{
Assertions.fail("Appear to be in an infinite loop");
}
} while (!TransformStack.isFinished(internalContext));
Assertions.assertEquals(7, transformStepCount);
}
@Test
public void testCheckStructureNoOptions()
{
internalContext.getMultiStep().setTransformsToBeDone(new ArrayList<>());
assertEquals("T-Reply InternalContext did not have the Stack set",
TransformStack.checkStructure(internalContext, "T-Reply"));
}
@Test
public void testCheckStructureNoSourceRef()
{
internalContext.getMultiStep().setTransformsToBeDone(new ArrayList<>());
TransformStack.setInitialTransformRequestOptions(internalContext, options);
assertEquals("T-Request InternalContext did not have the Stack set",
TransformStack.checkStructure(internalContext, "T-Request"));
}
@Test
public void testCheckStructureNoStack()
{
internalContext.getMultiStep().setTransformsToBeDone(new ArrayList<>());
TransformStack.setInitialTransformRequestOptions(internalContext, options);
TransformStack.setInitialSourceReference(internalContext, sourceReference);
assertEquals("T-something InternalContext did not have the Stack set",
TransformStack.checkStructure(internalContext, "T-something"));
}
@Test
public void testCheckStructureOptionsOk()
{
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
for (String value : Arrays.asList(
"",
"key1" + SEPARATOR + "value1",
"key1" + SEPARATOR + "value1" + SEPARATOR + "key2" + SEPARATOR + "value2"))
{
System.out.println("TransformOptions value: " + value);
internalContext.getMultiStep().getTransformsToBeDone().set(OPTIONS_LEVEL, value);
Assertions.assertNull(TransformStack.checkStructure(internalContext, "T-Reply"));
// call the getter just in case we have missed something
TransformStack.getInitialTransformRequestOptions(internalContext);
}
}
@Test
public void testCheckStructureOptionsBad()
{
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
for (String value : Arrays.asList(
null,
"noValue",
SEPARATOR + "noKey",
"key" + SEPARATOR + "value" + SEPARATOR + "noKey"))
{
System.out.println("TransformOptions value: " + value);
internalContext.getMultiStep().getTransformsToBeDone().set(OPTIONS_LEVEL, value);
assertEquals("T-Reply InternalContext did not have the TransformOptions set correctly",
TransformStack.checkStructure(internalContext, "T-Reply"));
}
}
@Test
public void testCheckStructureStackLevelsOk()
{
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
for (String value : Arrays.asList(
"P" + SEPARATOR + "20" + SEPARATOR + START + SEPARATOR + "1" + STEP,
"P" + SEPARATOR + "4" + SEPARATOR + "123" + SEPARATOR + "12" + STEP + STEP))
{
System.out.println("TransformLevel value: " + value);
internalContext.getMultiStep().getTransformsToBeDone().set(TOP_STACK_LEVEL, value);
Assertions.assertNull(TransformStack.checkStructure(internalContext, "T-Reply"));
// call a getter just in case we have missed something
TransformStack.currentStep(internalContext);
};
}
@Test
public void testCheckStructureStackLevelsOkWithLeadingE()
{
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
for (String value : Arrays.asList(
"P" + SEPARATOR + "e20" + SEPARATOR + START + SEPARATOR + "1" + STEP))
{
System.out.println("TransformLevel value: " + value);
internalContext.getMultiStep().getTransformsToBeDone().set(TOP_STACK_LEVEL, value);
Assertions.assertNull(TransformStack.checkStructure(internalContext, "T-Reply"));
};
}
@Test
public void testCheckStructureStackLevelsFailWithLeadingX()
{
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
for (String value : Arrays.asList(
"P" + SEPARATOR + "x20" + SEPARATOR + START + SEPARATOR + "1" + STEP))
{
System.out.println("TransformLevel value: " + value);
internalContext.getMultiStep().getTransformsToBeDone().set(TOP_STACK_LEVEL, value);
assertEquals("T-Reply InternalContext did not have levels set correctly",
TransformStack.checkStructure(internalContext, "T-Reply"));
};
}
@Test
public void testCheckStructureStackLevelsBad()
{
TransformStack.addTransformLevel(internalContext, TEST_LEVELS.get("top"));
String MAX_INT_PLUS_1 = BigInteger.valueOf(Integer.MAX_VALUE + 1).toString();
String MAX_LONG_PLUS_1 = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE).toString();
for (String value : Arrays.asList(
null,
"",
"F" + SEPARATOR + "12" + SEPARATOR + START + SEPARATOR + "2",
"F" + SEPARATOR + "-1" + SEPARATOR + START + SEPARATOR + "2" + STEP,
"F" + SEPARATOR + "1" + SEPARATOR + "-3" + SEPARATOR + "2" + STEP,
"F" + SEPARATOR + "1" + SEPARATOR + START + SEPARATOR + "-2" + STEP,
"F" + SEPARATOR + "a" + SEPARATOR + START + SEPARATOR + "-2" + STEP,
"F" + SEPARATOR + "1" + SEPARATOR + START + SEPARATOR + "b" + STEP,
"P" + SEPARATOR + "0" + SEPARATOR + START + SEPARATOR + "12" + SEPARATOR + "name",
"P" + SEPARATOR + "0" + SEPARATOR + START + SEPARATOR + "12" + SEPARATOR + "name" + SEPARATOR + "source",
"P" + SEPARATOR + "0" + SEPARATOR + START + SEPARATOR + "12" + SEPARATOR + "name" + SEPARATOR + "source" + SEPARATOR + "",
"P" + SEPARATOR + "0" + SEPARATOR + START + SEPARATOR + "12" + SEPARATOR + "name" + SEPARATOR + "" + SEPARATOR + "target",
"F" + SEPARATOR + MAX_INT_PLUS_1 + SEPARATOR + START + SEPARATOR + "2" + STEP,
"F" + SEPARATOR + "1" + SEPARATOR + MAX_LONG_PLUS_1 + SEPARATOR + "2" + STEP,
"F" + SEPARATOR + "1" + SEPARATOR + START + SEPARATOR + MAX_INT_PLUS_1 + STEP
))
{
System.out.println("TransformLevel value: " + value);
internalContext.getMultiStep().getTransformsToBeDone().set(TOP_STACK_LEVEL, value);
assertEquals("T-Reply InternalContext did not have levels set correctly",
TransformStack.checkStructure(internalContext, "T-Reply"));
};
}
}

View File

@@ -0,0 +1,88 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This program 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.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.registry;
import org.alfresco.transform.config.TransformOption;
import org.alfresco.transform.config.Transformer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Helper class for testing an {@link AbstractTransformRegistry}.
*/
public class FakeTransformRegistry extends AbstractTransformRegistry
{
private static final String READ_FROM_A = "readFromA";
private static final String BASE_URL_B = "baseUrlB";
private final TransformCache data = new TransformCache();
List<String> errorMessages = new ArrayList<>();
List<String> warnMessages = new ArrayList<>();
int registeredCount = 0;
int readFromACount = 0;
int baseUrlBCount = 0;
Map<Transformer, String> transformerBaseUrls = new HashMap<>();
@Override
protected void logError(String msg)
{
System.out.println(msg);
errorMessages.add(msg);
}
@Override
protected void logWarn(String msg)
{
System.out.println(msg);
warnMessages.add(msg);
}
@Override
public TransformCache getData()
{
return data;
}
@Override
protected void register(final Transformer transformer,
final Map<String, Set<TransformOption>> transformOptions, final String baseUrl,
final String readFrom)
{
super.register(transformer, transformOptions, baseUrl, readFrom);
registeredCount++;
if (READ_FROM_A.equals(readFrom))
{
readFromACount++;
}
if (BASE_URL_B.equals(baseUrl))
{
baseUrlBCount++;
}
transformerBaseUrls.put(transformer, baseUrl);
}
}

View File

@@ -0,0 +1,460 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This program 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.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.registry;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.alfresco.transform.config.AddSupported;
import org.alfresco.transform.config.SupportedDefaults;
import org.alfresco.transform.config.OverrideSupported;
import org.alfresco.transform.config.RemoveSupported;
import org.alfresco.transform.config.SupportedSourceAndTarget;
import org.alfresco.transform.config.TransformConfig;
import org.alfresco.transform.config.Transformer;
import org.junit.jupiter.api.Test;
import java.util.HashSet;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Tests the json elements: {@code removeTransformers}, {@code addSupported}, {@code removeSupported},
* {@code overrideSupported} and {@code supportedDefaults}.
*/
public class OverrideTransformConfigTests
{
private static final String READ_FROM_A = "readFromA";
private static final String READ_FROM_B = "readFromB";
private static final String BASE_URL_A = "baseUrlA";
private static final String BASE_URL_B = "baseUrlB";
private final SupportedSourceAndTarget supported_A2B = SupportedSourceAndTarget.builder()
.withSourceMediaType("mimetype/a")
.withTargetMediaType("mimetype/b")
.build();
private final SupportedSourceAndTarget supported_A2B__40 = SupportedSourceAndTarget.builder()
.withSourceMediaType("mimetype/a")
.withTargetMediaType("mimetype/b")
.withPriority(40)
.build();
private final SupportedSourceAndTarget supported_C2D = SupportedSourceAndTarget.builder()
.withSourceMediaType("mimetype/c")
.withTargetMediaType("mimetype/d")
.build();
private final SupportedSourceAndTarget supported_A2D_1234_44 = SupportedSourceAndTarget.builder()
.withSourceMediaType("mimetype/a")
.withTargetMediaType("mimetype/d")
.withMaxSourceSizeBytes(1234L)
.withPriority(44)
.build();
private final SupportedSourceAndTarget supported_X2Y_100_23 = SupportedSourceAndTarget.builder()
.withSourceMediaType("mimetype/x")
.withTargetMediaType("mimetype/y")
.withMaxSourceSizeBytes(100L)
.withPriority(23)
.build();
private final SupportedSourceAndTarget supported_X2Y_200 = SupportedSourceAndTarget.builder()
.withSourceMediaType("mimetype/x")
.withTargetMediaType("mimetype/y")
.withMaxSourceSizeBytes(200L)
.build();
private final TransformConfig transformConfig_A2B_X2Y_100_23 = TransformConfig.builder()
.withTransformers(ImmutableList.of(
Transformer.builder().withTransformerName("1")
.withSupportedSourceAndTargetList(new HashSet<>(Set.of(
supported_A2B,
supported_X2Y_100_23)))
.build()))
.build();
private final CombinedTransformConfig config = new CombinedTransformConfig();
private final FakeTransformRegistry registry = new FakeTransformRegistry();
@Test
public void testRemoveTransformers()
{
final Transformer transformer1 = Transformer.builder().withTransformerName("1").build();
final Transformer transformer2 = Transformer.builder().withTransformerName("2").build();
final Transformer transformer3 = Transformer.builder().withTransformerName("3").build();
final Transformer transformer4 = Transformer.builder().withTransformerName("4").build();
final TransformConfig firstConfig = TransformConfig.builder()
.withTransformers(ImmutableList.of(
transformer1,
transformer2,
transformer3,
transformer4))
.build();
final TransformConfig secondConfig = TransformConfig.builder()
.withTransformers(ImmutableList.of(
transformer2)) // Puts transform 2 back again
.withRemoveTransformers(ImmutableSet.of("2", "7", "3", "2", "5"))
.build();
config.addTransformConfig(firstConfig, READ_FROM_A, BASE_URL_A, registry);
TransformConfig resultConfig = config.buildTransformConfig();
assertEquals(4, resultConfig.getTransformers().size());
config.addTransformConfig(secondConfig, READ_FROM_B, BASE_URL_B, registry);
resultConfig = config.buildTransformConfig();
assertEquals(3, resultConfig.getTransformers().size());
String expected = "Unable to process \"removeTransformers\": [\"7\", \"5\"]. Read from readFromB";
assertEquals(1, registry.warnMessages.size());
assertEquals(expected, registry.warnMessages.get(0));
}
@Test
public void testSupportedDefaultsSet()
{
SupportedDefaults default_1A_100 = SupportedDefaults.builder()
.withTransformerName("1")
.withSourceMediaType("mimetype/a")
.withMaxSourceSizeBytes(100L)
.build();
SupportedDefaults default_1A_200 = SupportedDefaults.builder()
.withTransformerName("1")
.withSourceMediaType("mimetype/a")
.withMaxSourceSizeBytes(200L)
.build();
SupportedDefaults default_2A__45 = SupportedDefaults.builder()
.withTransformerName("2")
.withSourceMediaType("mimetype/a")
.withPriority(45)
.build();
SupportedDefaults default_3_400 = SupportedDefaults.builder()
.withTransformerName("3")
.withMaxSourceSizeBytes(400L)
.build();
SupportedDefaults default_B_400 = SupportedDefaults.builder()
.withSourceMediaType("mimetype/b")
.withMaxSourceSizeBytes(400L)
.build();
SupportedDefaults default_B_500 = SupportedDefaults.builder()
.withSourceMediaType("mimetype/b")
.withMaxSourceSizeBytes(500L)
.build();
SupportedDefaults default__600 = SupportedDefaults.builder()
.withMaxSourceSizeBytes(600L)
.build();
SupportedDefaults default___45 = SupportedDefaults.builder()
.withPriority(45)
.build();
SupportedDefaults default___50 = SupportedDefaults.builder()
.withPriority(50)
.build();
SupportedDefaults default__500_50 = SupportedDefaults.builder()
.withMaxSourceSizeBytes(500L)
.withPriority(50)
.build();
SupportedDefaults default__600_45 = SupportedDefaults.builder()
.withMaxSourceSizeBytes(600L)
.withPriority(45)
.build();
final TransformConfig firstConfig = TransformConfig.builder()
.build();
final TransformConfig secondConfig = TransformConfig.builder()
.withSupportedDefaults(ImmutableSet.of(
default_1A_100)) // 0: transformer and source media type default
.build();
final TransformConfig thirdConfig = TransformConfig.builder()
.withSupportedDefaults(ImmutableSet.of(
default_1A_200, // 0: transformer and source media type default
default_2A__45, // 0: transformer and source media type default
default_3_400, // 1: transformer default
default_B_400, // 2: source media type default
default_B_500, // 2: source media type default - overrides the previous value 400 defined in the same config
default__500_50, // 3: system wide default - totally overridden by the next lines.
default__600, // 3: system wide default
default___50, // 3: system wide default (combined with the other system default)
default___45)) // 3: system wide default - overrides the value 45 defined in the same config
.build();
final TransformConfig fourthConfig = TransformConfig.builder()
.withSupportedDefaults(ImmutableSet.of(
SupportedDefaults.builder() // 3: system wide default
.withMaxSourceSizeBytes(-1L)
.withPriority(45)
.build()))
.build();
final TransformConfig fifthConfig = TransformConfig.builder()
.withSupportedDefaults(ImmutableSet.of(
SupportedDefaults.builder() // 3: system wide default (reset to the default, so removed)
.withPriority(50)
.build(),
SupportedDefaults.builder() // Invalid as neither priority nor maxSourceSizeBytes are set
.withTransformerName("9")
.withSourceMediaType("mimetype/z")
.build()))
.build();
config.addTransformConfig(firstConfig, READ_FROM_A, BASE_URL_A, registry);
TransformConfig resultConfig = config.buildTransformConfig();
assertEquals(0, resultConfig.getSupportedDefaults().size());
config.addTransformConfig(secondConfig, READ_FROM_B, BASE_URL_B, registry);
resultConfig = config.buildTransformConfig();
assertEquals(ImmutableSet.of(
default_1A_100),
resultConfig.getSupportedDefaults());
config.addTransformConfig(thirdConfig, READ_FROM_B, BASE_URL_B, registry);
resultConfig = config.buildTransformConfig();
assertEquals(ImmutableSet.of(
default_1A_200, // overrides default_1A_100
default_2A__45,
default_3_400,
default_B_500,
default__600_45), // default__600 + default___45
resultConfig.getSupportedDefaults());
config.addTransformConfig(fourthConfig, READ_FROM_B, BASE_URL_B, registry);
resultConfig = config.buildTransformConfig();
assertEquals(5, resultConfig.getSupportedDefaults().size());
config.addTransformConfig(fifthConfig, READ_FROM_A, BASE_URL_A, registry);
resultConfig = config.buildTransformConfig();
assertEquals(4, resultConfig.getSupportedDefaults().size());
assertEquals(ImmutableSet.of(
default_1A_200, // overrides default_1A_100
default_2A__45,
default_3_400,
default_B_500), // default__600_45 removed as the system defaults have been reset to the defaults -1 and 50
resultConfig.getSupportedDefaults());
String expected = "Unable to process \"supportedDefaults\": [" +
"{\"transformerName\": \"9\", \"sourceMediaType\": \"mimetype/z\"}]. Read from readFromA";
assertEquals(1, registry.warnMessages.size());
assertEquals(expected, registry.warnMessages.get(0));
}
@Test
public void testRemoveSupported()
{
addTransformConfig_A2B_X2Y_100_23();
final TransformConfig secondConfig = TransformConfig.builder()
.withRemoveSupported(ImmutableSet.of(
RemoveSupported.builder()
.withTransformerName("1") // c -> d does not exist
.withSourceMediaType("mimetype/c")
.withTargetMediaType("mimetype/d")
.build(),
RemoveSupported.builder()
.withTransformerName("1")
.withSourceMediaType("mimetype/a")
.withTargetMediaType("mimetype/b")
.build(),
RemoveSupported.builder() // transformer does not exist
.withTransformerName("bad")
.withSourceMediaType("mimetype/a")
.withTargetMediaType("mimetype/d")
.build(),
RemoveSupported.builder() // transform name not set
.withSourceMediaType("mimetype/a")
.withTargetMediaType("mimetype/d")
.build(),
RemoveSupported.builder() // source type not set
.withTransformerName("1")
.withTargetMediaType("mimetype/d")
.build(),
RemoveSupported.builder() // target type not set
.withTransformerName("1")
.withSourceMediaType("mimetype/a")
.build()))
.build();
String expectedWarnMessage = "Unable to process \"removeSupported\": [" +
"{\"transformerName\": \"bad\", \"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/d\"}, " +
"{\"transformerName\": \"1\", \"sourceMediaType\": \"mimetype/a\"}, " +
"{\"transformerName\": \"1\", \"sourceMediaType\": \"mimetype/c\", \"targetMediaType\": \"mimetype/d\"}, " +
"{\"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/d\"}, " +
"{\"transformerName\": \"1\", \"targetMediaType\": \"mimetype/d\"}]. " +
"Read from readFromB";
ImmutableSet<SupportedSourceAndTarget> expectedSupported = ImmutableSet.of(supported_X2Y_100_23);
String expectedToString = "[" +
"{\"sourceMediaType\": \"mimetype/x\", \"targetMediaType\": \"mimetype/y\", \"maxSourceSizeBytes\": \"100\", \"priority\": \"23\"}" +
"]";
addTransformConfig(secondConfig, expectedWarnMessage, expectedSupported, expectedToString);
}
@Test
public void testAddSupported()
{
addTransformConfig_A2B_X2Y_100_23();
final TransformConfig secondConfig = TransformConfig.builder()
.withAddSupported(ImmutableSet.of(
AddSupported.builder()
.withTransformerName("1")
.withSourceMediaType("mimetype/c")
.withTargetMediaType("mimetype/d")
.build(),
AddSupported.builder() // duplicates original
.withTransformerName("1")
.withSourceMediaType("mimetype/a")
.withTargetMediaType("mimetype/b")
.withPriority(40)
.build(),
AddSupported.builder()
.withTransformerName("1")
.withSourceMediaType("mimetype/a")
.withTargetMediaType("mimetype/d")
.withPriority(44)
.withMaxSourceSizeBytes(1234)
.build(),
AddSupported.builder() // transformer does not exist
.withTransformerName("bad")
.withSourceMediaType("mimetype/a")
.withTargetMediaType("mimetype/d")
.build(),
AddSupported.builder() // transform name not set
.withSourceMediaType("mimetype/a")
.withTargetMediaType("mimetype/d")
.build(),
AddSupported.builder() // source type not set
.withTransformerName("1")
.withTargetMediaType("mimetype/d")
.build(),
AddSupported.builder() // target type not set
.withTransformerName("1")
.withSourceMediaType("mimetype/a")
.build()))
.build();
String expectedWarnMessage = "Unable to process \"addSupported\": [" +
"{\"transformerName\": \"1\", \"sourceMediaType\": \"mimetype/a\"}, " +
"{\"transformerName\": \"1\", \"targetMediaType\": \"mimetype/d\"}, " +
"{\"transformerName\": \"1\", \"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/b\", \"priority\": \"40\"}, " +
"{\"transformerName\": \"bad\", \"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/d\"}, " +
"{\"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/d\"}]. " +
"Read from readFromB";
ImmutableSet<SupportedSourceAndTarget> expectedSupported = ImmutableSet.of(
supported_A2B,
supported_C2D,
supported_X2Y_100_23,
supported_A2D_1234_44);
String expectedToString = "[" +
"{\"sourceMediaType\": \"mimetype/x\", \"targetMediaType\": \"mimetype/y\", \"maxSourceSizeBytes\": \"100\", \"priority\": \"23\"}, " +
"{\"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/d\", \"maxSourceSizeBytes\": \"1234\", \"priority\": \"44\"}, " +
"{\"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/b\"}, " + // priority and size should be missing (i.e. use defaults)
"{\"sourceMediaType\": \"mimetype/c\", \"targetMediaType\": \"mimetype/d\"}" +
"]";
addTransformConfig(secondConfig, expectedWarnMessage, expectedSupported, expectedToString);
}
@Test
public void testOverrideSupported()
{
addTransformConfig_A2B_X2Y_100_23();
final TransformConfig secondConfig = TransformConfig.builder()
.withOverrideSupported(ImmutableSet.of(
OverrideSupported.builder() // does not exist
.withTransformerName("1")
.withSourceMediaType("mimetype/c")
.withTargetMediaType("mimetype/d")
.build(),
OverrideSupported.builder() // size default -> 200 and priority default -> 100
.withTransformerName("1")
.withSourceMediaType("mimetype/a")
.withTargetMediaType("mimetype/b")
.withPriority(40)
.build(),
OverrideSupported.builder() // size 100 -> 200 and change priority to default
.withTransformerName("1")
.withSourceMediaType("mimetype/x")
.withTargetMediaType("mimetype/y")
.withMaxSourceSizeBytes(200)
.build(),
OverrideSupported.builder() // transformer does not exist
.withTransformerName("bad")
.withSourceMediaType("mimetype/a")
.withTargetMediaType("mimetype/d")
.build()))
// OverrideSupported values with missing fields are defaults, so no test values here
.build();
String expectedWarnMessage = "Unable to process \"overrideSupported\": [" +
"{\"transformerName\": \"1\", \"sourceMediaType\": \"mimetype/c\", \"targetMediaType\": \"mimetype/d\"}, " +
"{\"transformerName\": \"bad\", \"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/d\"}]. " +
"Read from readFromB";
ImmutableSet<SupportedSourceAndTarget> expectedSupported = ImmutableSet.of(
supported_X2Y_200,
supported_A2B__40);
String expectedToString = "[" +
"{\"sourceMediaType\": \"mimetype/a\", \"targetMediaType\": \"mimetype/b\", \"priority\": \"40\"}, " +
"{\"sourceMediaType\": \"mimetype/x\", \"targetMediaType\": \"mimetype/y\", \"maxSourceSizeBytes\": \"200\"}" +
"]";
addTransformConfig(secondConfig, expectedWarnMessage, expectedSupported, expectedToString);
}
private void addTransformConfig_A2B_X2Y_100_23()
{
config.addTransformConfig(transformConfig_A2B_X2Y_100_23, READ_FROM_A, BASE_URL_A, registry);
TransformConfig resultConfig = config.buildTransformConfig();
assertEquals(1, resultConfig.getTransformers().size());
assertEquals(2, resultConfig.getTransformers().get(0).getSupportedSourceAndTargetList().size());
}
private void addTransformConfig(TransformConfig secondConfig, String expectedWarnMessage,
Set<SupportedSourceAndTarget> expectedSupported, String expectedToString)
{
config.addTransformConfig(secondConfig, READ_FROM_B, BASE_URL_B, registry);
TransformConfig resultConfig = config.buildTransformConfig();
assertEquals(1, registry.warnMessages.size());
assertEquals(expectedWarnMessage, registry.warnMessages.get(0));
Set<SupportedSourceAndTarget> supportedSourceAndTargetList = resultConfig.getTransformers().get(0).getSupportedSourceAndTargetList();
assertTrue(supportedSourceAndTargetList.equals(expectedSupported));
assertEquals(expectedToString, supportedSourceAndTargetList.toString());
}
}

View File

@@ -0,0 +1,214 @@
/*
* #%L
* Alfresco Transform Core
* %%
* Copyright (C) 2005 - 2022 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.transform.registry;
import com.google.common.collect.ImmutableMap;
import org.alfresco.transform.exceptions.TransformException;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import static java.util.Arrays.asList;
import static java.util.Collections.emptySet;
import static org.alfresco.transform.common.RequestParamMap.SOURCE_ENCODING;
import static org.alfresco.transform.common.RequestParamMap.TIMEOUT;
import static org.alfresco.transform.registry.TransformRegistryHelper.retrieveTransformListBySize;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class TransformRegistryHelperTest
{
@Test
public void testListBySize()
{
// This test was inspired by a failure to pick libreoffice over textToPdf despite the fact libreoffice has a
// higher priority.
SupportedTransform libreoffice = new SupportedTransform("libreoffice", emptySet(), -1, 50);
SupportedTransform textToPdf = new SupportedTransform("textToPdf", emptySet(), 100,55);
assertOrder(asList(libreoffice, textToPdf), asList(libreoffice));
assertOrder(asList(textToPdf, libreoffice), asList(libreoffice));
// * If multiple transforms with the same priority can support the same size, the one with the highest size
// limit (or no limit) is used.
// * Transforms with a higher priority (lower numerically) are used up to their size limit in preference to
// lower priority transforms. These lower priority transforms will be used above that limit.
// * If there are multiple transforms with the same priority and size limit, the last one defined is used to
// allow extensions to override standard transforms.
// * In each of the above cases, it is possible for supplied transforms not to be returned from
// retrieveTransformListBySize as they will never be used. However this method is currently only used
// by (1) AbstractTransformRegistry.findTransformerName which filters out transformers that cannot support a
// given size and then uses the lowest element and (2) AbstractTransformRegistry.findMaxSize and gets the last
// element without filtering and returns its size limit. So there are opportunities to change the code so that
// it does not actually have to remove transformers that will not be used.
// Test transforms
SupportedTransform p45 = new SupportedTransform( "p45", emptySet(), -1, 45);
SupportedTransform p50 = new SupportedTransform( "p50", emptySet(), -1, 50);
SupportedTransform p55 = new SupportedTransform( "p55", emptySet(), -1, 55);
SupportedTransform s100p45 = new SupportedTransform("s100p45", emptySet(), 100, 45);
SupportedTransform s100p50 = new SupportedTransform("s100p50", emptySet(), 100, 50);
SupportedTransform s100p55 = new SupportedTransform("s100p55", emptySet(), 100, 55);
SupportedTransform s200p50 = new SupportedTransform("s200p50", emptySet(), 200, 50);
SupportedTransform s200p50b = new SupportedTransform("s200p50b", emptySet(), 200, 50);
SupportedTransform s200p55 = new SupportedTransform("s200p55", emptySet(), 200, 55);
SupportedTransform s300p45 = new SupportedTransform("s300p45", emptySet(), 300, 45);
SupportedTransform s300p50 = new SupportedTransform("s300p50", emptySet(), 300, 50);
SupportedTransform s300p55 = new SupportedTransform("s300p55", emptySet(), 300, 55);
// Just considers the priority
assertOrder(asList(p50), asList(p50));
assertOrder(asList(p45, p50), asList(p45));
assertOrder(asList(p50, p55), asList(p50));
assertOrder(asList(p50, p45), asList(p45));
assertOrder(asList(p45, p50, p55), asList(p45));
assertOrder(asList(p50, p55, p45), asList(p45));
assertOrder(asList(p50, p45, p55), asList(p45));
// Just considers the priority as the size limit is the same
assertOrder(asList(s100p45, s100p50, s100p55), asList(s100p45));
assertOrder(asList(s100p50, s100p45, s100p55), asList(s100p45));
// Just considers size as the priority is the same
assertOrder(asList(s100p50), asList(s100p50));
assertOrder(asList(s100p50, s200p50), asList(s200p50));
assertOrder(asList(s200p50, s100p50), asList(s200p50));
assertOrder(asList(s100p50, s200p50, s300p50), asList(s300p50));
assertOrder(asList(s200p50, s100p50, s300p50), asList(s300p50));
assertOrder(asList(s300p50, s200p50, s100p50), asList(s300p50));
// Just considers the order in which they were defined as the priority and size limit are the same.
assertOrder(asList(s200p50, s200p50b), asList(s200p50b));
assertOrder(asList(s200p50b, s200p50), asList(s200p50));
// Combinations of priority and a size limit (always set)
assertOrder(asList(s100p45, s100p50, s200p50, s200p55, s300p45, s300p50, s300p55), asList(s300p45));
assertOrder(asList(s200p50, s300p55, s300p45, s100p45, s100p50, s300p50, s200p55), asList(s300p45));
assertOrder(asList(s100p45, s200p50, s300p55), asList(s100p45, s200p50, s300p55));
assertOrder(asList(s200p50, s100p45, s300p55), asList(s100p45, s200p50, s300p55));
// Combinations of priority and a size limit or no size limit
assertOrder(asList(p45, s100p50, s200p50, s300p55), asList(p45));
assertOrder(asList(s100p50, s200p50, s300p55, p45), asList(p45));
assertOrder(asList(p55, s100p50, s200p50, s300p55), asList(s200p50, p55));
assertOrder(asList(p50, s100p50, s200p50, s300p55), asList(p50));
assertOrder(asList(s100p50, s200p50, s300p55, p50), asList(p50));
}
private void assertOrder(List<SupportedTransform> transformsInLoadOrder, List<SupportedTransform> expectedList)
{
AtomicInteger transformerCount = new AtomicInteger(0);
TransformCache data = new TransformCache();
transformsInLoadOrder.forEach(t->data.appendTransform("text/plain", "application/pdf", t,
"transformer"+transformerCount.getAndIncrement(), null));
List<SupportedTransform> supportedTransforms = retrieveTransformListBySize(data,
"text/plain", "application/pdf", null, null);
// Check the values used.
String transformerName = findTransformerName(supportedTransforms, 1);
long maxSize = findMaxSize(supportedTransforms);
String expectedTransformerName = expectedList.get(0).getName();
long expectedMaxSourceSizeBytes = findMaxSize(expectedList);
assertEquals(expectedList, supportedTransforms);
assertEquals(expectedTransformerName, transformerName);
assertEquals(expectedMaxSourceSizeBytes, maxSize);
// If the above two pass, we don't really need the following one, but if it is wrong it might indicate
// something is wrong, where the sourceSizeInBytes is not just 1.
assertEquals(expectedList, supportedTransforms);
}
// Similar to the method in AbstractTransformRegistry
private String findTransformerName(List<SupportedTransform> supportedTransforms, final long sourceSizeInBytes)
{
return supportedTransforms
.stream()
.filter(t -> t.getMaxSourceSizeBytes() == -1 ||
t.getMaxSourceSizeBytes() >= sourceSizeInBytes)
.findFirst()
.map(SupportedTransform::getName)
.orElse(null);
}
// Similar to the method in AbstractTransformRegistry
private long findMaxSize(List<SupportedTransform> supportedTransforms)
{
return supportedTransforms.isEmpty() ? 0 :
supportedTransforms.get(supportedTransforms.size() - 1).getMaxSourceSizeBytes();
}
@Test
public void buildTransformListSourceMimeTypeNullErrorTest()
{
TransformCache data = new TransformCache();
assertThrows(TransformException.class, () ->
{
retrieveTransformListBySize(data, null, "application/pdf", null, null);
});
}
@Test
public void buildTransformListTargetMimeTypeNullErrorTest()
{
TransformCache data = new TransformCache();
assertThrows(TransformException.class, () ->
{
retrieveTransformListBySize(data, "text/plain", null, null, null);
});
}
@Test
public void filterTimeoutTest()
{
// Almost identical to buildTransformListTargetMimeTypeNullErrorTest
TransformCache data = new TransformCache();
assertThrows(TransformException.class, () ->
{
retrieveTransformListBySize(data, "text/plain", null,
new HashMap<>(ImmutableMap.of(TIMEOUT, "1234")), null);
});
}
@Test
public void filterSourceEncodingTest()
{
// Almost identical to buildTransformListTargetMimeTypeNullErrorTest
TransformCache data = new TransformCache();
assertThrows(TransformException.class, () ->
{
retrieveTransformListBySize(data, "text/plain", null,
new HashMap<>(ImmutableMap.of(SOURCE_ENCODING, "UTF-8")), null);
});
}
}

View File

@@ -0,0 +1,667 @@
/*
* #%L
* Alfresco Transform Model
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This program 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.
*
* This program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
* #L%
*/
package org.alfresco.transform.registry;
import static java.util.Collections.emptyMap;
import static java.util.Collections.emptySet;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
import static org.alfresco.transform.registry.TransformRegistryHelper.addToPossibleTransformOptions;
import static org.alfresco.transform.registry.TransformRegistryHelper.optionsMatch;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ImmutableList;
import org.alfresco.transform.config.CoreFunction;
import org.alfresco.transform.config.SupportedSourceAndTarget;
import org.alfresco.transform.config.TransformConfig;
import org.alfresco.transform.config.TransformOption;
import org.alfresco.transform.config.TransformOptionGroup;
import org.alfresco.transform.config.TransformOptionValue;
import org.alfresco.transform.config.Transformer;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.google.common.collect.ImmutableSet;
/**
* Test the AbstractTransformRegistry, extended by both T-Engines and ACS repository, which need to
* read JSON config to understand what is supported.
*
* @author adavis
*/
public class TransformRegistryModelTest
{
protected static final String GIF = "image/gif";
protected static final String JPEG = "image/jpeg";
protected static final String PDF = "application/pdf";
protected static final String DOC = "application/msword";
protected static final String XLS = "application/vnd.ms-excel";
protected static final String PPT = "application/vnd.ms-powerpoint";
protected static final String MSG = "application/vnd.ms-outlook";
protected static final String TXT = "text/plain";
protected AbstractTransformRegistry registry;
protected Map<String, Set<TransformOption>> mapOfTransformOptions;
@BeforeEach
public void setUp() throws Exception
{
registry = buildTransformServiceRegistryImpl();
mapOfTransformOptions = new HashMap<>();
}
protected AbstractTransformRegistry buildTransformServiceRegistryImpl() throws Exception
{
return new AbstractTransformRegistry()
{
private TransformCache data = new TransformCache();
@Override
protected void logError(String msg)
{
System.out.println(msg);
}
@Override
protected void logWarn(String msg)
{
System.out.println(msg);
}
@Override
public TransformCache getData()
{
return data;
}
};
}
private void assertAddToPossibleOptions(final TransformOptionGroup transformOptionGroup,
final Set<String> actualOptionNames, final Set<String> expectedNameSet,
final Set<String> expectedRequiredSet)
{
final Map<String, Boolean> possibleTransformOptions = new HashMap<>();
addToPossibleTransformOptions(possibleTransformOptions, transformOptionGroup, true,
buildActualOptions(actualOptionNames));
assertEquals(expectedNameSet, possibleTransformOptions.keySet());
possibleTransformOptions.forEach((name, required) -> {
if (required)
{
assertTrue(expectedRequiredSet.contains(name));
}
else
{
assertFalse(expectedRequiredSet.contains(name));
}
});
}
// transformOptionNames are upper case if required.
private void assertOptionsMatch(final Set<String> actualOptionNames,
final Set<String> transformOptionNames, final String unsupportedMsg)
{
final Map<String, Boolean> transformOptions = transformOptionNames
.stream()
.collect(toMap(identity(), name -> name.toUpperCase().equals(name)));
boolean supported = optionsMatch(transformOptions, buildActualOptions(actualOptionNames));
if (isBlank(unsupportedMsg))
{
assertTrue(supported);
}
else
{
assertFalse(supported);
}
}
private void assertTransformOptions(Set<TransformOption> setOfTransformOptions) throws Exception
{
final Transformer transformer = new Transformer("name", singleton("testOptions"), set(
SupportedSourceAndTarget.builder()
.withSourceMediaType(DOC)
.withTargetMediaType(TXT)
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType(XLS)
.withTargetMediaType(TXT)
.withMaxSourceSizeBytes(1024000L)
.build()));
final TransformConfig transformConfig = TransformConfig
.builder()
.withTransformers(singletonList(transformer))
.withTransformOptions(singletonMap("testOptions", setOfTransformOptions))
.build();
registry = buildTransformServiceRegistryImpl();
CombinedTransformConfig.combineAndRegister(transformConfig, getClass().getName(), getBaseUrl(transformer), registry);
assertTrue(registry.isSupported(XLS, 1024, TXT, emptyMap(), null));
assertTrue(registry.isSupported(XLS, 1024000, TXT, null, null));
assertFalse(registry.isSupported(XLS, 1024001, TXT, emptyMap(), null));
assertTrue(registry.isSupported(DOC, 1024001, TXT, null, null));
}
protected String getBaseUrl(Transformer transformer)
{
return "xxx";
}
private void assertTransformerName(String sourceMimetype, long sourceSizeInBytes,
String targetMimetype, Map<String, String> actualOptions, String expectedTransformerName,
Transformer... transformers) throws Exception
{
buildAndPopulateRegistry(transformers);
String transformerName = registry.findTransformerName(sourceMimetype, sourceSizeInBytes,
targetMimetype, actualOptions, null);
assertEquals(expectedTransformerName, transformerName);
}
private void assertSupported(final Transformer transformer, final String sourceMimetype,
final long sourceSizeInBytes, final String targetMimetype,
final Map<String, String> actualOptions, final String unsupportedMsg) throws Exception
{
assertSupported(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions,
unsupportedMsg, transformer);
}
private void assertSupported(String sourceMimetype, long sourceSizeInBytes,
String targetMimetype, Map<String, String> actualOptions, String unsupportedMsg,
Transformer... transformers) throws Exception
{
buildAndPopulateRegistry(transformers);
assertSupported(sourceMimetype, sourceSizeInBytes, targetMimetype, actualOptions, null,
unsupportedMsg);
}
private void buildAndPopulateRegistry(Transformer[] transformers) throws Exception
{
registry = buildTransformServiceRegistryImpl();
TransformConfig transformConfig = TransformConfig.builder()
.withTransformers(Arrays.asList(transformers))
.withTransformOptions(mapOfTransformOptions)
.build();
CombinedTransformConfig.combineAndRegister(transformConfig, getClass().getName(), "---", registry);
}
protected void assertSupported(String sourceMimetype, long sourceSizeInBytes,
String targetMimetype, Map<String, String> actualOptions, String renditionName,
String unsupportedMsg)
{
boolean supported = registry.isSupported(sourceMimetype, sourceSizeInBytes, targetMimetype,
actualOptions, renditionName);
if (unsupportedMsg == null || unsupportedMsg.isEmpty())
{
assertTrue(supported);
}
else
{
assertFalse(supported);
}
}
private static Map<String, String> buildActualOptions(final Set<String> optionNames)
{
return optionNames
.stream()
.collect(toMap(identity(), name -> "value for " + name));
}
@Test
public void testOptionalGroups()
{
final TransformOptionGroup transformOptionGroup =
new TransformOptionGroup(true, set(
new TransformOptionValue(false, "1"),
new TransformOptionValue(true, "2"),
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "3.1"),
new TransformOptionValue(false, "3.2"),
new TransformOptionValue(false, "3.3"))),
new TransformOptionGroup(false, set( // OPTIONAL
new TransformOptionValue(false, "4.1"),
new TransformOptionValue(true, "4.2"),
new TransformOptionValue(false, "4.3")))));
assertAddToPossibleOptions(transformOptionGroup, emptySet(),
set("1", "2"), set("2"));
assertAddToPossibleOptions(transformOptionGroup, set("1"),
set("1", "2"), set("2"));
assertAddToPossibleOptions(transformOptionGroup, set("2"),
set("1", "2"), set("2"));
assertAddToPossibleOptions(transformOptionGroup, set("2", "3.2"),
set("1", "2", "3.1", "3.2", "3.3"), set("2"));
assertAddToPossibleOptions(transformOptionGroup, set("2", "4.1"),
set("1", "2", "4.1", "4.2", "4.3"), set("2", "4.2"));
assertAddToPossibleOptions(transformOptionGroup, set("2", "4.2"),
set("1", "2", "4.1", "4.2", "4.3"), set("2", "4.2"));
}
@Test
public void testRequiredGroup()
{
TransformOptionGroup transformOptionGroup =
new TransformOptionGroup(true, set(
new TransformOptionValue(false, "1"),
new TransformOptionValue(true, "2"),
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "3.1"),
new TransformOptionValue(false, "3.2"),
new TransformOptionValue(false, "3.3"))),
new TransformOptionGroup(true, set(
new TransformOptionValue(false, "4.1"),
new TransformOptionValue(true, "4.2"),
new TransformOptionValue(false, "4.3")))));
assertAddToPossibleOptions(transformOptionGroup, emptySet(),
set("1", "2", "4.1", "4.2", "4.3"), set("2", "4.2"));
assertAddToPossibleOptions(transformOptionGroup, set("1"),
set("1", "2", "4.1", "4.2", "4.3"), set("2", "4.2"));
assertAddToPossibleOptions(transformOptionGroup, set("2", "3.2"),
set("1", "2", "3.1", "3.2", "3.3", "4.1", "4.2", "4.3"), set("2", "4.2"));
assertAddToPossibleOptions(transformOptionGroup, set("2", "4.1"),
set("1", "2", "4.1", "4.2", "4.3"), set("2", "4.2"));
assertAddToPossibleOptions(transformOptionGroup, set("2", "4.2"),
set("1", "2", "4.1", "4.2", "4.3"), set("2", "4.2"));
}
@Test
public void testNestedGroups()
{
TransformOptionGroup transformOptionGroup =
new TransformOptionGroup(false, set(
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "1"),
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "1.2"),
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "1.2.3"))))))),
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "2"),
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "2.2"),
new TransformOptionGroup(false, set(
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "2.2.1.2"))))))))),
new TransformOptionGroup(false, set(
new TransformOptionValue(true, "3"),
new TransformOptionGroup(false, set(
new TransformOptionGroup(false, set(
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "3.1.1.2"))))))))),
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "4"),
new TransformOptionGroup(true, set(
new TransformOptionGroup(false, set(
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "4.1.1.2"))))))))),
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "5"),
new TransformOptionGroup(false, set(
new TransformOptionGroup(true, set(
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "5.1.1.2"))))))))),
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "6"),
new TransformOptionGroup(false, set(
new TransformOptionGroup(false, set(
new TransformOptionGroup(true, set(
new TransformOptionValue(false, "6.1.1.2"))))))))),
new TransformOptionGroup(false, set(
new TransformOptionValue(false, "7"),
new TransformOptionGroup(false, set(
new TransformOptionGroup(false, set(
new TransformOptionGroup(false, set(
new TransformOptionValue(true, "7.1.1.2")))))))))
));
assertAddToPossibleOptions(transformOptionGroup, emptySet(),
emptySet(), emptySet());
assertAddToPossibleOptions(transformOptionGroup, set("1"),
set("1"), emptySet());
assertAddToPossibleOptions(transformOptionGroup, set("1", "7"),
set("1", "7"), emptySet());
assertAddToPossibleOptions(transformOptionGroup, set("1", "7.1.1.2"),
set("1", "7", "7.1.1.2"), set("7.1.1.2"));
assertAddToPossibleOptions(transformOptionGroup, set("1", "6"),
set("1", "6"), emptySet());
assertAddToPossibleOptions(transformOptionGroup, set("1", "6.1.1.2"),
set("1", "6", "6.1.1.2"), emptySet());
assertAddToPossibleOptions(transformOptionGroup, set("1", "5"),
set("1", "5"), emptySet());
assertAddToPossibleOptions(transformOptionGroup, set("1", "5.1.1.2"),
set("1", "5", "5.1.1.2"), emptySet());
assertAddToPossibleOptions(transformOptionGroup, set("1", "4"),
set("1", "4"), emptySet());
assertAddToPossibleOptions(transformOptionGroup, set("1", "4.1.1.2"),
set("1", "4", "4.1.1.2"), emptySet());
assertAddToPossibleOptions(transformOptionGroup, set("1", "3"),
set("1", "3"), set("3"));
assertAddToPossibleOptions(transformOptionGroup, set("1", "3.1.1.2"),
set("1", "3", "3.1.1.2"), set("3"));
assertAddToPossibleOptions(transformOptionGroup, set("2"),
set("2"), emptySet());
assertAddToPossibleOptions(transformOptionGroup, set("2", "2.2"),
set("2", "2.2"), emptySet());
assertAddToPossibleOptions(transformOptionGroup, set("3"),
set("3"), set("3"));
assertAddToPossibleOptions(transformOptionGroup, set("3.1.1.2"),
set("3", "3.1.1.2"), set("3"));
}
@Test
public void testRegistryOptionsMatchMethod()
{
assertOptionsMatch(set("a"), set("a", "B", "c"), "required option B is missing");
assertOptionsMatch(emptySet(), set("a", "B", "c"), "required option B is missing");
assertOptionsMatch(set("B"), set("a", "B", "c"), null);
assertOptionsMatch(set("B", "c"), set("a", "B", "c"), null);
assertOptionsMatch(set("B", "a", "c"), set("a", "B", "c"), null);
assertOptionsMatch(set("B", "d"), set("a", "B", "c"), "there is an extra option d");
assertOptionsMatch(set("B", "c", "d"), set("a", "B", "c"), "there is an extra option d");
assertOptionsMatch(set("d"), set("a", "B", "c"),
"required option B is missing and there is an extra option d");
assertOptionsMatch(set("a"), set("a", "b", "c"), null);
assertOptionsMatch(emptySet(), set("a", "b", "c"), null);
assertOptionsMatch(set("a", "b", "c"), set("a", "b", "c"), null);
}
@Test
public void testNoActualOptions() throws Exception
{
assertTransformOptions(set(
new TransformOptionValue(false, "option1"),
new TransformOptionValue(false, "option2")));
}
@Test
public void testNoTransformOptions() throws Exception
{
assertTransformOptions(emptySet());
assertTransformOptions(null);
}
@Test
public void testSupported() throws Exception
{
mapOfTransformOptions.put("options1", set(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
new TransformOptionValue(false, "height")));
final Transformer transformer = new Transformer("name", singleton("options1"), set(
SupportedSourceAndTarget.builder()
.withSourceMediaType(DOC)
.withTargetMediaType(GIF)
.withMaxSourceSizeBytes(102400L)
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType(DOC)
.withTargetMediaType(JPEG)
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType(MSG)
.withTargetMediaType(GIF)
.build()));
assertSupported(transformer, DOC, 1024, GIF, emptyMap(), null);
assertSupported(transformer, DOC, 102400, GIF, emptyMap(), null);
assertSupported(transformer, DOC, 102401, GIF, emptyMap(), "source is too large");
assertSupported(transformer, DOC, 1024, JPEG, emptyMap(), null);
assertSupported(transformer, GIF, 1024, DOC, emptyMap(),
GIF + " is not a source of this transformer");
assertSupported(transformer, MSG, 1024, GIF, emptyMap(), null);
assertSupported(transformer, MSG, 1024, JPEG, emptyMap(),
MSG + " to " + JPEG + " is not supported by this transformer");
assertSupported(transformer, DOC, 1024, GIF, buildActualOptions(set("page", "width")),
null);
assertSupported(transformer, DOC, 1024, GIF,
buildActualOptions(set("page", "width", "startPage")), "startPage is not an option");
}
@Test
// renditionName used as the cache key, is an alias for a set of actualOptions and the target mimetype.
// The source mimetype may change.
public void testCache()
{
mapOfTransformOptions.put("options1", set(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
new TransformOptionValue(false, "height")));
final Transformer transformer = new Transformer("name", singleton("options1"), set(
SupportedSourceAndTarget.builder()
.withSourceMediaType(DOC)
.withTargetMediaType(GIF)
.withMaxSourceSizeBytes(102400L)
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType(MSG)
.withTargetMediaType(GIF)
.build()));
TransformConfig transformConfig = TransformConfig.builder()
.withTransformers(Collections.singletonList(transformer))
.withTransformOptions(mapOfTransformOptions)
.build();
CombinedTransformConfig.combineAndRegister(transformConfig, getClass().getName(), getBaseUrl(transformer), registry);
assertSupported(DOC, 1024, GIF, emptyMap(), "doclib", "");
assertSupported(MSG, 1024, GIF, emptyMap(), "doclib", "");
assertEquals(102400L, registry.findMaxSize(DOC, GIF, emptyMap(), "doclib"));
assertEquals(-1L, registry.findMaxSize(MSG, GIF, emptyMap(), "doclib"));
// check we are now using the cached value.
final SupportedTransform cachedSupportedTransform = new SupportedTransform("name1",
emptySet(), 999999L, 0);
registry.getData()
.retrieveCached("doclib", DOC)
.add(cachedSupportedTransform);
assertEquals(999999L, registry.findMaxSize(DOC, GIF, emptyMap(), "doclib"));
}
@Test
public void testTransformCacheGetTransforms() // Used in the Alfresco Repo tests
{
TransformConfig transformConfig = TransformConfig.builder()
.withTransformers(ImmutableList.of(new Transformer("transformer1", emptySet(), set(
SupportedSourceAndTarget.builder()
.withSourceMediaType(GIF)
.withTargetMediaType(PDF)
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType(GIF)
.withTargetMediaType(JPEG)
.build()))))
.build();
assertEquals(0, registry.getData().getTransforms().size());
assertEquals("", registry.getData().toString());
CombinedTransformConfig.combineAndRegister(transformConfig, "readFrom", "baseUrl", registry);
assertEquals(1, registry.getData().getTransforms().size());
assertEquals(2, registry.getData().getTransforms().get(GIF).size());
assertEquals("(transformers: 1 transforms: 2)", registry.getData().toString());
}
@Test
public void testGetTransformerName() throws Exception
{
Transformer t1 = newTransformer("transformer1", MSG, GIF, 100, 50);
Transformer t2 = newTransformer("transformer2", MSG, GIF, 200, 60);
Transformer t3 = newTransformer("transformer3", MSG, GIF, 200, 40);
Transformer t4 = newTransformer("transformer4", MSG, GIF, -1, 100);
Transformer t5 = newTransformer("transformer5", MSG, GIF, -1, 80);
// Select on size - priority is ignored
assertTransformerName(MSG, 100, GIF, emptyMap(), "transformer1", t1, t2);
assertTransformerName(MSG, 150, GIF, emptyMap(), "transformer2", t1, t2);
assertTransformerName(MSG, 250, GIF, emptyMap(), null, t1, t2);
// Select on priority - t1, t2 and t4 are discarded.
// t3 is a higher priority and has a larger size than t1 and t2.
// Similar story fo t4 with t5.
assertTransformerName(MSG, 100, GIF, emptyMap(), "transformer3", t1, t2, t3, t4, t5);
assertTransformerName(MSG, 200, GIF, emptyMap(), "transformer3", t1, t2, t3, t4, t5);
// Select on size and priority, t1 and t2 discarded
assertTransformerName(MSG, 200, GIF, emptyMap(), "transformer3", t1, t2, t3, t4);
assertTransformerName(MSG, 300, GIF, emptyMap(), "transformer4", t1, t2, t3, t4);
assertTransformerName(MSG, 300, GIF, emptyMap(), "transformer5", t1, t2, t3, t4, t5);
}
private Transformer newTransformer(String transformerName, String sourceMediaType, String targetMediaType,
long maxSourceSizeBytes, int priority)
{
return Transformer.builder().withTransformerName(transformerName)
.withSupportedSourceAndTargetList(ImmutableSet.of(
SupportedSourceAndTarget.builder()
.withSourceMediaType(sourceMediaType)
.withTargetMediaType(targetMediaType)
.withMaxSourceSizeBytes(maxSourceSizeBytes)
.withPriority(priority)
.build()))
.build();
}
@Test
public void testMultipleTransformers() throws Exception
{
mapOfTransformOptions.put("options1", set(
new TransformOptionValue(false, "page"),
new TransformOptionValue(false, "width"),
new TransformOptionValue(false, "height")));
mapOfTransformOptions.put("options2", set(
new TransformOptionValue(false, "opt1"),
new TransformOptionValue(false, "opt2")));
mapOfTransformOptions.put("options3", new HashSet<>(singletonList(
new TransformOptionValue(false, "opt1"))));
Transformer transformer1 = new Transformer("transformer1", singleton("options1"), set(
SupportedSourceAndTarget.builder()
.withSourceMediaType(DOC)
.withTargetMediaType(GIF)
.withMaxSourceSizeBytes(102400L)
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType(DOC)
.withTargetMediaType(JPEG)
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType(MSG)
.withTargetMediaType(GIF)
.build()));
Transformer transformer2 = new Transformer("transformer2", singleton("options2"), set(
SupportedSourceAndTarget.builder()
.withSourceMediaType(PDF)
.withTargetMediaType(GIF)
.build(),
SupportedSourceAndTarget.builder()
.withSourceMediaType(PPT)
.withTargetMediaType(JPEG)
.build()));
Transformer transformer3 = new Transformer("transformer3", singleton("options3"),
new HashSet(singletonList(SupportedSourceAndTarget.builder()
.withSourceMediaType(DOC)
.withTargetMediaType(GIF)
.build())));
assertSupported(DOC, 1024, GIF, emptyMap(), null, transformer1);
assertSupported(DOC, 1024, GIF, emptyMap(), null, transformer1, transformer2);
assertSupported(DOC, 1024, GIF, emptyMap(), null, transformer1, transformer2,
transformer3);
assertSupported(DOC, 102401, GIF, emptyMap(), "source is too large", transformer1);
assertSupported(DOC, 102401, GIF, emptyMap(), null, transformer1, transformer3);
assertSupported(PDF, 1024, GIF, emptyMap(), "Only transformer2 supports these mimetypes",
transformer1);
assertSupported(PDF, 1024, GIF, emptyMap(), null, transformer1, transformer2);
assertSupported(PDF, 1024, GIF, emptyMap(), null, transformer1, transformer2,
transformer3);
final Map<String, String> actualOptions = buildActualOptions(set("opt1"));
assertSupported(PDF, 1024, GIF, actualOptions, "Only transformer2/4 supports these options",
transformer1);
assertSupported(PDF, 1024, GIF, actualOptions, null, transformer1, transformer2);
assertSupported(PDF, 1024, GIF, actualOptions, null, transformer1, transformer2,
transformer3);
assertSupported(PDF, 1024, GIF, actualOptions,
"transformer4 supports opt1 but not the source mimetype ", transformer1, transformer3);
}
@SafeVarargs
private static <T> Set<T> set(T... elements)
{
if (elements == null || elements.length == 0)
{
return emptySet();
}
return ImmutableSet.copyOf(elements);
}
@Test
public void testIsSupportedCoreFunction() throws Exception
{
Transformer t1 = newTransformer("transformer1", MSG, GIF, 100, 50);
Transformer t2 = newTransformer("transformer2", MSG, GIF, 200, 60);
Transformer t3 = newTransformer("transformer3", MSG, GIF, 200, 40);
t2.setCoreVersion("1.0");
t3.setCoreVersion("2.5.7");
buildAndPopulateRegistry(new Transformer[] {t1, t2, t3});
assertTrue(registry.isSupported(CoreFunction.HTTP, "transformer1"));
assertTrue(registry.isSupported(CoreFunction.HTTP, "transformer2"));
assertTrue(registry.isSupported(CoreFunction.HTTP, "transformer3"));
assertFalse(registry.isSupported(CoreFunction.ACTIVE_MQ, "transformer1"));
assertTrue(registry.isSupported(CoreFunction.ACTIVE_MQ, "transformer2"));
assertTrue(registry.isSupported(CoreFunction.ACTIVE_MQ, "transformer3"));
assertFalse(registry.isSupported(CoreFunction.DIRECT_ACCESS_URL, "transformer1"));
assertFalse(registry.isSupported(CoreFunction.DIRECT_ACCESS_URL, "transformer2"));
assertTrue(registry.isSupported(CoreFunction.DIRECT_ACCESS_URL, "transformer3"));
}
}

View File

@@ -0,0 +1,3 @@
{
"transformers":[]
}

View File

@@ -0,0 +1,92 @@
{
"transformers": [
{
"transformerName": "CORE_AIO",
"supportedSourceAndTargetList": [
{"sourceMediaType": "image/gif", "targetMediaType": "image/gif" }
],
"transformOptions": [
"imageMagickOptions"
]
},
{
"transformerName": "IMAGEMAGICK",
"supportedSourceAndTargetList": [
{"sourceMediaType": "image/gif", "targetMediaType": "image/gif" }
],
"transformOptions": [
"imageMagickOptions"
]
},
{
"transformerName": "CORE_AIO",
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/msword", "maxSourceSizeBytes": 18874368, "targetMediaType": "application/pdf" }
]
},
{
"transformerName": "PDF_RENDERER",
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/vnd.ms-powerpoint", "maxSourceSizeBytes": 50331648, "priority": 55, "targetMediaType": "application/pdf" }
],
"transformOptions": [
]
},
{
"transformerName": "CORE_AIO",
"supportedSourceAndTargetList": [
{"sourceMediaType": "text/plain", "targetMediaType": "text/plain" },
{"sourceMediaType": "text/mediawiki", "targetMediaType": "text/plain" },
{"sourceMediaType": "text/css", "targetMediaType": "text/plain" },
{"sourceMediaType": "text/csv", "targetMediaType": "text/plain" },
{"sourceMediaType": "text/xml", "targetMediaType": "text/plain" },
{"sourceMediaType": "text/html", "targetMediaType": "text/plain" },
{"sourceMediaType": "application/x-javascript", "targetMediaType": "text/plain" },
{"sourceMediaType": "application/dita+xml", "targetMediaType": "text/plain" }
],
"transformOptions": [
"stringOptions"
]
},
{
"transformerName": "officeToImageViaPdf",
"transformerPipeline" : [
{"transformerName": "libreoffice", "targetMediaType": "application/pdf"},
{"transformerName": "pdfToImageViaPng"}
],
"supportedSourceAndTargetList": [
],
"transformOptions": [
"pdfRendererOptions",
"imageMagickOptions"
]
},
{
"transformerName": "textToImageViaPdf",
"transformerPipeline" : [
{"transformerName": "libreoffice", "targetMediaType": "application/pdf"},
{"transformerName": "pdfToImageViaPng"}
],
"supportedSourceAndTargetList": [
{"sourceMediaType": "text/plain", "targetMediaType": "image/gif" },
{"sourceMediaType": "text/plain", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "text/plain", "targetMediaType": "image/tiff"},
{"sourceMediaType": "text/plain", "targetMediaType": "image/png" },
{"sourceMediaType": "text/csv", "targetMediaType": "image/gif" },
{"sourceMediaType": "text/csv", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "text/csv", "targetMediaType": "image/tiff"},
{"sourceMediaType": "text/csv", "targetMediaType": "image/png" },
{"sourceMediaType": "text/xml", "targetMediaType": "image/gif" },
{"sourceMediaType": "text/xml", "targetMediaType": "image/jpeg"},
{"sourceMediaType": "text/xml", "targetMediaType": "image/tiff"},
{"sourceMediaType": "text/xml", "targetMediaType": "image/png" }
],
"transformOptions": [
"pdfRendererOptions",
"imageMagickOptions"
]
}
]
}

View File

@@ -0,0 +1,2 @@
---
transformers:

View File

@@ -0,0 +1,130 @@
---
transformOptions:
imageMagickOptions:
- value:
name: alphaRemove
- value:
name: autoOrient
- value:
name: startPage
- value:
name: endPage
- group:
transformOptions:
- value:
name: cropGravity
- value:
name: cropWidth
- value:
name: cropHeight
- value:
name: cropPercentage
- value:
name: cropXOffset
- value:
name: cropYOffset
- group:
transformOptions:
- value:
name: thumbnail
- value:
name: resizeHeight
- value:
name: resizeWidth
- value:
name: resizePercentage
- value:
name: allowEnlargement
- value:
name: maintainAspectRatio
transformers:
- transformerName: CORE_AIO
supportedSourceAndTargetList:
- sourceMediaType: image/gif
targetMediaType: image/gif
transformOptions:
- imageMagickOptions
- transformerName: IMAGEMAGICK
supportedSourceAndTargetList:
- sourceMediaType: image/gif
targetMediaType: image/gif
transformOptions:
- imageMagickOptions
- transformerName: PDF_RENDERER
supportedSourceAndTargetList:
- sourceMediaType: application/vnd.ms-powerpoint
targetMediaType: application/pdf
priority: 55
maxSourceSizeBytes: 50331648
transformOptions: []
- transformerName: CORE_AIO
supportedSourceAndTargetList:
- sourceMediaType: application/msword
targetMediaType: application/pdf
maxSourceSizeBytes: 18874368
- transformerName: CORE_AIO
supportedSourceAndTargetList:
- sourceMediaType: text/plain
targetMediaType: text/plain
- sourceMediaType: text/mediawiki
targetMediaType: text/plain
- sourceMediaType: text/css
targetMediaType: text/plain
- sourceMediaType: text/csv
targetMediaType: text/plain
- sourceMediaType: text/xml
targetMediaType: text/plain
- sourceMediaType: text/html
targetMediaType: text/plain
- sourceMediaType: application/x-javascript
targetMediaType: text/plain
- sourceMediaType: application/dita+xml
targetMediaType: text/plain
transformOptions:
- stringOptions
- transformerName: officeToImageViaPdf
transformerPipeline:
- transformerName: libreoffice
targetMediaType: application/pdf
- transformerName: pdfToImageViaPng
transformOptions:
- pdfRendererOptions
- imageMagickOptions
- transformerName: textToImageViaPdf
transformerPipeline:
- transformerName: libreoffice
targetMediaType: application/pdf
- transformerName: pdfToImageViaPng
supportedSourceAndTargetList:
- sourceMediaType: text/plain
targetMediaType: image/gif
- sourceMediaType: text/plain
targetMediaType: image/jpeg
- sourceMediaType: text/plain
targetMediaType: image/tiff
- sourceMediaType: text/plain
targetMediaType: image/png
- sourceMediaType: text/csv
targetMediaType: image/gif
- sourceMediaType: text/csv
targetMediaType: image/jpeg
- sourceMediaType: text/csv
targetMediaType: image/tiff
- sourceMediaType: text/csv
targetMediaType: image/png
- sourceMediaType: text/xml
targetMediaType: image/gif
- sourceMediaType: text/xml
targetMediaType: image/jpeg
- sourceMediaType: text/xml
targetMediaType: image/tiff
- sourceMediaType: text/xml
targetMediaType: image/png
transformOptions:
- pdfRendererOptions
- imageMagickOptions

View File

@@ -0,0 +1,37 @@
{
"transformOptions": {
"imageMagickOptions": [
{"value": {"name": "alphaRemove"}},
{"value": {"name": "autoOrient"}},
{"value": {"name": "startPage"}},
{"value": {"name": "endPage"}},
{"group": {"transformOptions": [
{"value": {"name": "cropGravity"}},
{"value": {"name": "cropWidth"}},
{"value": {"name": "cropHeight"}},
{"value": {"name": "cropPercentage"}},
{"value": {"name": "cropXOffset"}},
{"value": {"name": "cropYOffset"}}
]}},
{"group": {"transformOptions": [
{"value": {"name": "thumbnail"}},
{"value": {"name": "resizeHeight"}},
{"value": {"name": "resizeWidth"}},
{"value": {"name": "resizePercentage"}},
{"value": {"name": "allowEnlargement"}},
{"value": {"name": "maintainAspectRatio"}}
]}}
]
},
"transformers": [
{
"transformerName": "CORE_AIO",
"supportedSourceAndTargetList": [
{"sourceMediaType": "image/gif", "targetMediaType": "image/gif" }
],
"transformOptions": [
"imageMagickOptions"
]
}
]
}

View File

@@ -0,0 +1,22 @@
{
"transformOptions": {
"engineXOptions": [
{"value": {"name": "page"}},
{"value": {"name": "width"}},
{"group": {"transformOptions": [
{"value": {"name": "cropGravity"}}
]}}
]
},
"transformers": [
{
"transformerName": "engineX",
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/pdf", "targetMediaType": "image/png" }
],
"transformOptions": [
"engineXOptions"
]
}
]
}

View File

@@ -0,0 +1,10 @@
{
"transformOptions": {},
"transformers": [
{
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/pdf", "targetMediaType": "image/png" }
]
}
]
}

View File

@@ -0,0 +1,10 @@
{
"transformers": [
{
"transformerName": "engineX",
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/pdf", "targetMediaType": "image/png" }
]
}
]
}

View File

@@ -0,0 +1,26 @@
{
"transformOptions": {
"engineXOptions": [
{"value": {"name": "page"}},
{"value": {"name": "page"}},
{"value": {"name": "width"}},
{"group": {"transformOptions": [
{"value": {"name": "cropGravity"}}
]}}
]
},
"transformers": [
{
"transformerName": "engineX",
"supportedSourceAndTargetList": [
{"sourceMediaType": "application/pdf", "targetMediaType": "image/png" },
{"sourceMediaType": "application/pdf", "targetMediaType": "image/png" },
{"sourceMediaType": "application/pdf", "targetMediaType": "image/png" }
],
"transformOptions": [
"engineXOptions",
"engineXOptions"
]
}
]
}