Implementation and unit tests for RM-2481, RM-2482, RM-2483 and RM-2489.

This checkin adds behaviours for ensuring that classification aspect/properties are correclty copied between nodes and their renditions on the creation of new renditions, on the classification or reclassification of nodes with existing renditions.

To do this I needed what should be, in my opinion, a common Alfresco utility method - the ability to copy an aspect from one node to another (aspect meaning property group i.e. no assocs).
I've created that method and put it in CoreServicesExtras. It should really be moved to core.

+ review RM


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@110069 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Neil McErlean
2015-08-13 16:29:38 +00:00
parent 5e4ecae6e2
commit 3fceea8655
8 changed files with 519 additions and 4 deletions

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* 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/>.
*/
package org.alfresco.module.org_alfresco_module_rm.model.clf;
import static java.util.Arrays.asList;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import org.alfresco.model.RenditionModel;
import org.alfresco.module.org_alfresco_module_rm.classification.ContentClassificationService;
import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel;
import org.alfresco.module.org_alfresco_module_rm.model.clf.aspect.ClassifiedAspect;
import org.alfresco.module.org_alfresco_module_rm.test.util.MockAuthenticationUtilHelper;
import org.alfresco.module.org_alfresco_module_rm.util.AuthenticationUtil;
import org.alfresco.module.org_alfresco_module_rm.util.CoreServicesExtras;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
/**
* Unit tests for {@link ClassifiedRenditions}.
*
* @since 3.0.a
*/
public class ClassifiedRenditionsUnitTest implements ClassifiedContentModel
{
private static final NodeRef SOURCE_NODE = new NodeRef("node://ref/");
private static final NodeRef RENDITION_1 = new NodeRef("node://rendition1/");
private static final NodeRef RENDITION_2 = new NodeRef("node://rendition2/");
@InjectMocks ClassifiedAspect classifiedAspect;
@Mock AuthenticationUtil mockAuthenticationUtil;
@Mock ContentClassificationService mockContentClassificationService;
@Mock CoreServicesExtras mockCoreServicesExtras;
@Mock NodeService mockNodeService;
@Mock RenditionService mockRenditionService;
@Before
public void setUp()
{
initMocks(this);
MockAuthenticationUtilHelper.setup(mockAuthenticationUtil);
}
@Test public void newRenditionOfClassifiedNodeShouldItselfBeClassified()
{
when(mockRenditionService.getRenditions(eq(SOURCE_NODE)))
.thenReturn(asList(rendition(SOURCE_NODE, RENDITION_1), rendition(SOURCE_NODE, RENDITION_2)));
when(mockRenditionService.getSourceNode(eq(RENDITION_1))).thenReturn(rendition(SOURCE_NODE, RENDITION_1));
when(mockRenditionService.getSourceNode(eq(RENDITION_2))).thenReturn(rendition(SOURCE_NODE, RENDITION_2));
when(mockContentClassificationService.isClassified(eq(SOURCE_NODE))).thenReturn(true);
final ClassifiedRenditions behaviour = new ClassifiedRenditions();
behaviour.setAuthenticationUtil(mockAuthenticationUtil);
behaviour.setContentClassificationService(mockContentClassificationService);
behaviour.setCoreServicesExtras(mockCoreServicesExtras);
behaviour.setNodeService(mockNodeService);
behaviour.setRenditionService(mockRenditionService);
behaviour.onAddAspect(RENDITION_2, RenditionModel.ASPECT_RENDITION);
verify(mockCoreServicesExtras).copyAspect(eq(SOURCE_NODE), eq(RENDITION_2), eq(ClassifiedContentModel.ASPECT_CLASSIFIED));
}
/** Creates a mock Rendition ChildAssociationRef. */
private ChildAssociationRef rendition(NodeRef source, NodeRef rendition)
{
return new ChildAssociationRef(RenditionModel.ASSOC_RENDITION, source, RenditionModel.ASSOC_RENDITION, rendition);
}
}

View File

@@ -18,15 +18,29 @@
*/
package org.alfresco.module.org_alfresco_module_rm.model.clf.aspect;
import static java.util.Arrays.asList;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.RenditionModel;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationException.MissingDowngradeInstructions;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationLevel;
import org.alfresco.module.org_alfresco_module_rm.classification.ClassificationSchemeService;
import org.alfresco.module.org_alfresco_module_rm.classification.model.ClassifiedContentModel;
import org.alfresco.module.org_alfresco_module_rm.util.CoreServicesExtras;
import org.alfresco.service.cmr.rendition.RenditionService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
@@ -40,10 +54,17 @@ import org.mockito.Mock;
*/
public class ClassifiedAspectUnitTest implements ClassifiedContentModel
{
private static final NodeRef NODE_REF = new NodeRef("node://Ref/");
private static final NodeRef NODE_REF = new NodeRef("node://Ref/");
private static final NodeRef RENDITION_1 = new NodeRef("node://rendition1/");
private static final NodeRef RENDITION_2 = new NodeRef("node://rendition2/");
private static final ClassificationLevel TOP_SECRET = new ClassificationLevel("Top Secret", "Top Secret");
private static final ClassificationLevel SECRET = new ClassificationLevel("Secret", "Secret");
@InjectMocks ClassifiedAspect classifiedAspect;
@Mock NodeService mockNodeService;
@Mock ClassificationSchemeService mockClassificationSchemeService;
@Mock CoreServicesExtras mockCoreServicesExtras;
@Mock NodeService mockNodeService;
@Mock RenditionService mockRenditionService;
@Before
public void setUp()
@@ -103,11 +124,67 @@ public class ClassifiedAspectUnitTest implements ClassifiedContentModel
@Test(expected = MissingDowngradeInstructions.class)
public void testCheckConsistencyOfProperties_emptyStringsSupplied()
{
when(mockNodeService.hasAspect(NODE_REF, ASPECT_CLASSIFIED)).thenReturn(true);
for (NodeRef n : asList(NODE_REF, RENDITION_1, RENDITION_2))
{
when(mockNodeService.hasAspect(n, ASPECT_CLASSIFIED)).thenReturn(true);
}
when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_DATE)).thenReturn("");
when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_EVENT)).thenReturn("Event");
when(mockNodeService.getProperty(NODE_REF, PROP_DOWNGRADE_INSTRUCTIONS)).thenReturn("");
classifiedAspect.checkConsistencyOfProperties(NODE_REF);
}
/** Check that when a node is classified, its renditions are also classified. */
@Test public void classificationOfNodeShouldClassifyRenditions()
{
for (NodeRef n : asList(NODE_REF, RENDITION_1, RENDITION_2))
{
when(mockNodeService.hasAspect(n, ASPECT_CLASSIFIED)).thenReturn(true);
}
when(mockClassificationSchemeService.getClassificationLevelById(eq("Top Secret"))).thenReturn(TOP_SECRET);
when(mockClassificationSchemeService.getClassificationLevelById(eq("Secret"))).thenReturn(SECRET);
when(mockClassificationSchemeService.getReclassification(any(), any())).thenReturn(ClassificationSchemeService.Reclassification.DOWNGRADE);
when(mockRenditionService.getRenditions(eq(NODE_REF)))
.thenReturn(asList(rendition(NODE_REF, RENDITION_1), rendition(NODE_REF, RENDITION_2)));
classifiedAspect.onAddAspect(NODE_REF, ASPECT_CLASSIFIED);
for (NodeRef rendition : asList(RENDITION_1, RENDITION_2))
{
verify(mockCoreServicesExtras).copyAspect(eq(NODE_REF), eq(rendition), eq(ClassifiedContentModel.ASPECT_CLASSIFIED));
}
}
@Test public void reclassificationOfNodeShouldReclassifyRenditions()
{
for (NodeRef n : asList(NODE_REF, RENDITION_1, RENDITION_2))
{
when(mockNodeService.hasAspect(n, ASPECT_CLASSIFIED)).thenReturn(true);
}
when(mockClassificationSchemeService.getClassificationLevelById(eq("Top Secret"))).thenReturn(TOP_SECRET);
when(mockClassificationSchemeService.getClassificationLevelById(eq("Secret"))).thenReturn(SECRET);
when(mockClassificationSchemeService.getReclassification(any(), any())).thenReturn(ClassificationSchemeService.Reclassification.DOWNGRADE);
when(mockRenditionService.getRenditions(eq(NODE_REF)))
.thenReturn(asList(rendition(NODE_REF, RENDITION_1), rendition(NODE_REF, RENDITION_2)));
Map<QName, Serializable> oldProps = new HashMap<>();
oldProps.put(PROP_CLASSIFIED_BY, "userone");
oldProps.put(PROP_CURRENT_CLASSIFICATION, "Top Secret");
Map<QName, Serializable> newProps = new HashMap<>(oldProps);
newProps.put(PROP_CURRENT_CLASSIFICATION, "Secret");
classifiedAspect.onUpdateProperties(NODE_REF, oldProps, newProps);
for (NodeRef rendition : asList(RENDITION_1, RENDITION_2))
{
verify(mockCoreServicesExtras).copyAspect(eq(NODE_REF), eq(rendition), eq(ClassifiedContentModel.ASPECT_CLASSIFIED));
}
}
/** Creates a mock Rendition ChildAssociationRef. */
private ChildAssociationRef rendition(NodeRef source, NodeRef rendition)
{
return new ChildAssociationRef(RenditionModel.ASSOC_RENDITION, source, RenditionModel.ASSOC_RENDITION, rendition);
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* 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/>.
*/
package org.alfresco.module.org_alfresco_module_rm.util;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.mock;
import static org.alfresco.module.org_alfresco_module_rm.test.util.ExceptionUtils.expectedException;
import static org.junit.Assert.assertEquals;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryException;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName;
import org.junit.Before;
import org.junit.Test;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Unit tests for {@link CoreServicesExtras}.
*
* @author Neil Mc Erlean
* @since 3.0.a
*/
public class CoreServicesExtrasUnitTest
{
private CoreServicesExtras serviceExtras;
private final QName testAspect = QName.createQName("test", "aspect");
private final QName testProp1 = QName.createQName("test", "prop1");
private final QName testProp2 = QName.createQName("test", "prop2");
private final QName testProp3 = QName.createQName("test", "prop3");
private final NodeRef testNode1 = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "1");
private final NodeRef testNode2 = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "2");
@Before public void setUp()
{
serviceExtras = new CoreServicesExtras();
}
@Test public void copyingAnUnknownAspectShouldResultInAnException()
{
final DictionaryService mockDS = mock(DictionaryService.class);
when(mockDS.getAspect(any(QName.class))).thenReturn(null);
serviceExtras.setDictionaryService(mockDS);
expectedException(DictionaryException.class, () -> serviceExtras.copyAspect(testNode1, testNode2, testAspect));
}
@Test public void copyingAnAspectWithNoProperties()
{
final DictionaryService mockDS = mock(DictionaryService.class);
final NodeService mockNS = mock(NodeService.class);
final AspectDefinition mockAspect = mock(AspectDefinition.class);
when(mockAspect.getProperties()).thenReturn(Collections.emptyMap());
when(mockDS.getAspect(eq(testAspect))).thenReturn(mockAspect);
when(mockNS.getProperties(eq(testNode1))).thenReturn(Collections.emptyMap());
serviceExtras.setDictionaryService(mockDS);
serviceExtras.setNodeService(mockNS);
assertEquals(Collections.emptyMap(), serviceExtras.copyAspect(testNode1, testNode2, testAspect));
}
@Test public void copyingAnAspectWithProperties()
{
final DictionaryService mockDS = mock(DictionaryService.class);
final NodeService mockNS = mock(NodeService.class);
final AspectDefinition mockAspect = mock(AspectDefinition.class);
final Map<QName, PropertyDefinition> props = new HashMap<>();
final PropertyDefinition mockProp1 = mock(PropertyDefinition.class);
final PropertyDefinition mockProp2 = mock(PropertyDefinition.class);
props.put(testProp1, mockProp1);
props.put(testProp2, mockProp2);
when(mockAspect.getProperties()).thenReturn(props);
final Map<QName, Serializable> propVals = new HashMap<>();
propVals.put(testProp1, "one");
propVals.put(testProp2, "two");
propVals.put(testProp3, "three"); // Not defined on the aspect above.
when(mockDS.getAspect(eq(testAspect))).thenReturn(mockAspect);
when(mockNS.getProperties(eq(testNode1))).thenReturn(propVals);
serviceExtras.setDictionaryService(mockDS);
serviceExtras.setNodeService(mockNS);
Map<QName, Serializable> expected = new HashMap<>();
expected.put(testProp1, "one");
expected.put(testProp2, "two");
assertEquals(expected, serviceExtras.copyAspect(testNode1, testNode2, testAspect));
}
}