mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
* ContentMetadataExtracter (the Action service Executer): * Code refactored so that post processing of extracted properties can be called after a transform has taken place in an async call. Previously done in the same Thread. * The source size is passed to the metadataExtracterRegistry as this is needed to select the transform. * Passes the source nodeRef to the metadataExtractor, so that it is possible to update the correct node after the async transform call. * AbstractMappingMetadataExtracter (the base class for all extractors): * Post extract processing extracted into separate methods. * NodeRef made available to sub classes. * AsynchronousExtractor (new metadata extractor and embedder) that will use a T-Engine. * Set targetExtension in transform for metadata extract and embed requests to T-Engines in both LocalTransforms (community) and RenditionEventProducer (enterprise). * RenditionService2Impl (used to request and respond to async transform requests). * Add consumeExtractedMetadata and consumeEmbeddedMetadata methods, which handle the response, normally be calling AsynchronousExtractor. * Discovered that the JodConverterMetadataExtracter was superseded by the * TikaPoweredMetadataExtracter for all the types that it support in 6.0.1 and could have been deprecated at that time as part of REPO-2910. It will now be deprecated so that it can be removed in 7.0.0. Additional tests are being added to AsynchronousExtractorTest for overwritePolicy, enableStringTagging and carryAspectProperties in a separate PR, as these will cover tests at a likely to be removed when delete local extractors.
287 lines
12 KiB
Java
287 lines
12 KiB
Java
/*
|
|
* #%L
|
|
* Alfresco Repository
|
|
* %%
|
|
* Copyright (C) 2005 - 2020 Alfresco Software Limited
|
|
* %%
|
|
* This file is part of the Alfresco software.
|
|
* If the software was purchased under a paid Alfresco license, the terms of
|
|
* the paid license agreement will prevail. Otherwise, the software is
|
|
* provided under the following open source license terms:
|
|
*
|
|
* Alfresco is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Alfresco is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
|
* #L%
|
|
*/
|
|
package org.alfresco.repo.rendition2;
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import org.alfresco.model.ContentModel;
|
|
import org.alfresco.repo.content.metadata.AsynchronousExtractor;
|
|
import org.alfresco.repo.policy.BehaviourFilter;
|
|
import org.alfresco.repo.policy.PolicyComponent;
|
|
import org.alfresco.repo.rendition.RenditionPreventionRegistry;
|
|
import org.alfresco.repo.transaction.RetryingTransactionHelper;
|
|
import org.alfresco.repo.util.PostTxnCallbackScheduler;
|
|
import org.alfresco.service.cmr.repository.ContentData;
|
|
import org.alfresco.service.cmr.repository.ContentService;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
import org.alfresco.service.cmr.repository.NodeService;
|
|
import org.alfresco.service.cmr.rule.RuleService;
|
|
import org.alfresco.service.namespace.QName;
|
|
import org.alfresco.service.transaction.TransactionService;
|
|
import org.alfresco.transform.client.registry.TransformServiceRegistryImpl;
|
|
import org.junit.Before;
|
|
import org.junit.Test;
|
|
import org.junit.runner.RunWith;
|
|
import org.mockito.Mock;
|
|
|
|
import org.mockito.junit.MockitoJUnitRunner;
|
|
|
|
import java.io.IOException;
|
|
import java.util.Collections;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import static junit.framework.TestCase.assertTrue;
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.fail;
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.anyInt;
|
|
import static org.mockito.ArgumentMatchers.anyLong;
|
|
import static org.mockito.Mockito.*;
|
|
|
|
/**
|
|
* Tests the RenditionService2 in a Community context where we only have local transformers.
|
|
*
|
|
* Also see EnterpriseRenditionService2Test.
|
|
*
|
|
* @author adavis
|
|
*/
|
|
@RunWith(MockitoJUnitRunner.class)
|
|
public class RenditionService2Test
|
|
{
|
|
private static final ObjectMapper JSON_OBJECT_MAPPER = new ObjectMapper();;
|
|
|
|
private RenditionService2Impl renditionService2;
|
|
private RenditionDefinitionRegistry2Impl renditionDefinitionRegistry2;
|
|
|
|
@Mock private TransformClient transformClient;
|
|
@Mock private TransactionService transactionService;
|
|
@Mock private NodeService nodeService;
|
|
@Mock private ContentService contentService;
|
|
@Mock private RenditionPreventionRegistry renditionPreventionRegistry;
|
|
@Mock private ContentData contentData;
|
|
@Mock private PolicyComponent policyComponent;
|
|
@Mock private BehaviourFilter behaviourFilter;
|
|
@Mock private RuleService ruleService;
|
|
@Mock private TransformServiceRegistryImpl transformServiceRegistry;
|
|
@Mock private TransformReplyProvider transformReplyProvider;
|
|
@Mock private AsynchronousExtractor asynchronousExtractor;
|
|
|
|
private NodeRef nodeRef = new NodeRef("workspace://spacesStore/test-id");
|
|
private NodeRef nodeRefMissing = new NodeRef("workspace://spacesStore/bad-test-id");
|
|
private static final String TEST_RENDITION = "testRendition";
|
|
private static final String JPEG = "image/jpeg";
|
|
private String contentUrl = "test-content-url";
|
|
|
|
private static final String CLIENT_DATA = "some_clientData";
|
|
private static final String REPLY_QUEUE = "some_replyQueue";
|
|
private static final String REQUEST_ID = "some_requestId";
|
|
private static final TransformDefinition TEST_TRANSFORM = new TransformDefinition(JPEG, Collections.singletonMap("a", "A"), CLIENT_DATA, REPLY_QUEUE, REQUEST_ID);
|
|
private boolean failureCalled;
|
|
|
|
@Before
|
|
public void setup() throws Exception
|
|
{
|
|
renditionService2 = new RenditionService2Impl()
|
|
{
|
|
@Override
|
|
public void failure(NodeRef sourceNodeRef, RenditionDefinition2 renditionDefinition, int transformContentHashCode)
|
|
{
|
|
failureCalled = true;
|
|
}
|
|
};
|
|
renditionDefinitionRegistry2 = new RenditionDefinitionRegistry2Impl();
|
|
renditionDefinitionRegistry2.setTransformServiceRegistry(transformServiceRegistry);
|
|
renditionDefinitionRegistry2.setRenditionConfigDir("");
|
|
renditionDefinitionRegistry2.setTimeoutDefault("120000");
|
|
renditionDefinitionRegistry2.setJsonObjectMapper(JSON_OBJECT_MAPPER);
|
|
renditionDefinitionRegistry2.setCronExpression(null); // just read it once
|
|
|
|
when(nodeService.exists(nodeRef)).thenReturn(true);
|
|
when(nodeService.exists(nodeRefMissing)).thenReturn(false);
|
|
when(nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT)).thenReturn(contentData);
|
|
when(contentData.getContentUrl()).thenReturn(contentUrl);
|
|
|
|
doAnswer(invocation ->
|
|
{
|
|
Object[] args = invocation.getArguments();
|
|
NodeRef sourceNodeRef = (NodeRef) args[0];
|
|
RenditionDefinition2 renditionDefinition = (RenditionDefinition2) args[1];
|
|
int sourceContentHashCode = (int) args[3];
|
|
if (!(renditionDefinition instanceof TransformDefinition))
|
|
{
|
|
sourceContentHashCode += 1; // Change the hashcode so that we don't actually try to create a rendition.
|
|
}
|
|
renditionService2.consume(sourceNodeRef, null, renditionDefinition, sourceContentHashCode);
|
|
return null;
|
|
}).when(transformClient).transform(any(), any(), nullable(String.class), anyInt());
|
|
|
|
renditionService2.setTransactionService(transactionService);
|
|
renditionService2.setNodeService(nodeService);
|
|
renditionService2.setContentService(contentService);
|
|
renditionService2.setRenditionPreventionRegistry(renditionPreventionRegistry);
|
|
renditionService2.setRenditionDefinitionRegistry2(renditionDefinitionRegistry2);
|
|
renditionService2.setTransformClient(transformClient);
|
|
renditionService2.setPolicyComponent(policyComponent);
|
|
renditionService2.setBehaviourFilter(behaviourFilter);
|
|
renditionService2.setRuleService(ruleService);
|
|
renditionService2.setTransactionService(transactionService);
|
|
renditionService2.setRenditionRequestSheduler(new RenditionRequestSchedulerMock());
|
|
renditionService2.setTransformReplyProvider(transformReplyProvider);
|
|
renditionService2.setEnabled(true);
|
|
renditionService2.setThumbnailsEnabled(true);
|
|
renditionService2.setAsynchronousExtractor(asynchronousExtractor);
|
|
|
|
renditionDefinitionRegistry2.setRenditionConfigDir("alfresco/renditions/test");
|
|
renditionDefinitionRegistry2.afterPropertiesSet();
|
|
renditionService2.afterPropertiesSet();
|
|
|
|
Map<String, String> options = new HashMap<>();
|
|
options.put("width", "960");
|
|
options.put("height", "1024");
|
|
new RenditionDefinition2Impl(TEST_RENDITION, JPEG, options, true, renditionDefinitionRegistry2);
|
|
}
|
|
|
|
private class RenditionRequestSchedulerMock extends PostTxnCallbackScheduler
|
|
{
|
|
@Override
|
|
public void scheduleRendition(RetryingTransactionHelper.RetryingTransactionCallback callback, String uniqueId)
|
|
{
|
|
try
|
|
{
|
|
callback.execute();
|
|
}
|
|
catch (Throwable throwable)
|
|
{
|
|
throwable.printStackTrace();
|
|
fail("The rendition callback failed: " + throwable);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test(expected = RenditionService2Exception.class)
|
|
public void disabledForRenditions()
|
|
{
|
|
renditionService2.setEnabled(false);
|
|
renditionService2.render(nodeRef, TEST_RENDITION);
|
|
}
|
|
|
|
@Test(expected = RenditionService2Exception.class)
|
|
public void disabledForTransforms()
|
|
{
|
|
renditionService2.setEnabled(false);
|
|
renditionService2.transform(nodeRef, TEST_TRANSFORM);
|
|
}
|
|
|
|
@Test(expected = RenditionService2Exception.class)
|
|
public void thumbnailsDisabledForRenditions()
|
|
{
|
|
renditionService2.setThumbnailsEnabled(false);
|
|
renditionService2.render(nodeRef, TEST_RENDITION);
|
|
}
|
|
|
|
@Test(expected = IllegalArgumentException.class)
|
|
public void nodeRefDoesNotExistForRenditions()
|
|
{
|
|
renditionService2.render(nodeRefMissing, TEST_RENDITION);
|
|
}
|
|
|
|
@Test(expected = IllegalArgumentException.class)
|
|
public void nodeRefDoesNotExistForTransforms()
|
|
{
|
|
renditionService2.transform(nodeRefMissing, TEST_TRANSFORM);
|
|
}
|
|
|
|
@Test
|
|
public void useLocalTransformForRenditions()
|
|
{
|
|
renditionService2.render(nodeRef, TEST_RENDITION);
|
|
|
|
verify(transformClient, times(1)).transform(any(), any(), any(), anyInt());
|
|
verify(transformClient, times(1)).transform(any(), any(), nullable(String.class), anyInt());
|
|
verify(transformReplyProvider, times(0)).produceTransformEvent(any(), any(), any(), anyInt());
|
|
}
|
|
|
|
@Test
|
|
public void useLocalTransformForTransforms()
|
|
{
|
|
renditionService2.transform(nodeRef, TEST_TRANSFORM);
|
|
verify(transformClient, times(1)).transform(any(), any(), nullable(String.class), anyInt());
|
|
verify(transformReplyProvider, times(1)).produceTransformEvent(any(), any(), any(), anyInt());
|
|
|
|
}
|
|
|
|
@Test(expected = UnsupportedOperationException.class)
|
|
public void noTransformForRenditions()
|
|
{
|
|
doThrow(UnsupportedOperationException.class).when(transformClient).checkSupported(any(), any(), any(), anyLong(), any());
|
|
renditionService2.render(nodeRef, TEST_RENDITION);
|
|
}
|
|
|
|
@Test
|
|
public void noTransformForTransforms()
|
|
{
|
|
doThrow(UnsupportedOperationException.class).when(transformClient).checkSupported(any(), any(), any(), anyLong(), any());
|
|
renditionService2.transform(nodeRef, TEST_TRANSFORM);
|
|
assertTrue("failure() should be called with transform(...) if an unsupported transform rather than " +
|
|
"having UnsupportedOperationException thrown", failureCalled);
|
|
}
|
|
|
|
@Test(expected = RenditionService2PreventedException.class)
|
|
public void checkSourceNodeForRenditionPreventionClass()
|
|
{
|
|
when(renditionPreventionRegistry.isContentClassRegistered((QName)any())).thenReturn(true);
|
|
renditionService2.render(nodeRef, TEST_RENDITION);
|
|
}
|
|
|
|
@Test(expected = IllegalArgumentException.class)
|
|
public void noDefinitionRenditions()
|
|
{
|
|
renditionService2.render(nodeRef, "doesNotExist");
|
|
}
|
|
|
|
@Test
|
|
public void renditionDefinitionsExist() throws IOException
|
|
{
|
|
renditionDefinitionRegistry2.readConfig();
|
|
|
|
Set<String> renditionNames = renditionDefinitionRegistry2.getRenditionNames();
|
|
for (String name: new String[] {"medium", "doclib", "imgpreview", "avatar", "avatar32", "webpreview", "pdf"})
|
|
{
|
|
assertTrue("Expected rendition "+name, renditionNames.contains(name));
|
|
}
|
|
}
|
|
|
|
@Test()
|
|
public void overriddenRendition()
|
|
{
|
|
// Check the standard rendition doclib has been overridden by one in alfresco/renditions/test/overrideRendition.json
|
|
RenditionDefinition2 doclib = renditionDefinitionRegistry2.getRenditionDefinition("doclib");
|
|
String resizeWidth = doclib.getTransformOptions().get("resizeWidth");
|
|
assertEquals("doclib has not been overridden", "180", resizeWidth);
|
|
}
|
|
}
|