From 4bb6852a79f8f615f928dae0122a8f82ac170ad2 Mon Sep 17 00:00:00 2001 From: Jamal Kaabi-Mofrad Date: Thu, 2 Jun 2016 21:42:19 +0000 Subject: [PATCH] Merged API-STRIKES-BACK (5.2.0) to HEAD (5.2) 126567 jvonka: Node Associations - further updates - for child assocs, do not expose assoc child qname (nominally like file/folder for primary child assoc) - additional api tests (+ve & -ve) for peer assocs & secondary child assocs - RA-745, RA-920, RA-921, RA-930, RA-742, RA-918, RA-919 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@127579 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/public-rest-context.xml | 1 + .../org/alfresco/rest/api/impl/NodesImpl.java | 4 +- .../alfresco/rest/api/model/AssocChild.java | 17 +- .../rest/api/nodes/AbstractNodeRelation.java | 35 ++- .../rest/api/nodes/NodeParentsRelation.java | 17 +- .../nodes/NodeSecondaryChildrenRelation.java | 91 ++++---- .../rest/api/nodes/NodeTargetsRelation.java | 44 +++- .../api/tests/NodeAssociationsApiTest.java | 213 ++++++++++++------ .../api/tests/client/data/Association.java | 11 - 9 files changed, 257 insertions(+), 176 deletions(-) diff --git a/config/alfresco/public-rest-context.xml b/config/alfresco/public-rest-context.xml index 1b0a4aba4d..6d4810f6b4 100644 --- a/config/alfresco/public-rest-context.xml +++ b/config/alfresco/public-rest-context.xml @@ -137,6 +137,7 @@ + diff --git a/source/java/org/alfresco/rest/api/impl/NodesImpl.java b/source/java/org/alfresco/rest/api/impl/NodesImpl.java index be4a133f73..7ee02cbfd2 100644 --- a/source/java/org/alfresco/rest/api/impl/NodesImpl.java +++ b/source/java/org/alfresco/rest/api/impl/NodesImpl.java @@ -915,8 +915,8 @@ public class NodesImpl implements Nodes AssocChild childAssoc = new AssocChild( parentAssocRef.getTypeQName().toPrefixString(namespaceService), - parentAssocRef.isPrimary(), - parentAssocRef.getQName().toPrefixString(namespaceService)); + parentAssocRef.isPrimary()); + node.setAssociation(childAssoc); } diff --git a/source/java/org/alfresco/rest/api/model/AssocChild.java b/source/java/org/alfresco/rest/api/model/AssocChild.java index 9d980e0cdc..c102a31e44 100644 --- a/source/java/org/alfresco/rest/api/model/AssocChild.java +++ b/source/java/org/alfresco/rest/api/model/AssocChild.java @@ -24,37 +24,24 @@ package org.alfresco.rest.api.model; public class AssocChild extends Assoc { private String childId; - private String prefixAssocChildQName; private Boolean isPrimaryParent; public AssocChild() { } - public AssocChild(String prefixAssocTypeQName, boolean isPrimaryParent, String prefixAssocChildQName) + public AssocChild(String prefixAssocTypeQName, boolean isPrimaryParent) { super(prefixAssocTypeQName); - this.prefixAssocChildQName = prefixAssocChildQName; this.isPrimaryParent = isPrimaryParent; } - public AssocChild(String childId, String prefixAssocTypeQName, String prefixAssocNameQName) + public AssocChild(String childId, String prefixAssocTypeQName) { super(prefixAssocTypeQName); this.childId = childId; - this.prefixAssocChildQName = prefixAssocNameQName; - } - - public String getChildQName() - { - return prefixAssocChildQName; - } - - public void setChildQName(String prefixAssocChildQName) - { - this.prefixAssocChildQName = prefixAssocChildQName; } public Boolean getIsPrimaryParent() diff --git a/source/java/org/alfresco/rest/api/nodes/AbstractNodeRelation.java b/source/java/org/alfresco/rest/api/nodes/AbstractNodeRelation.java index 21d1f479b0..11d9dd55c1 100644 --- a/source/java/org/alfresco/rest/api/nodes/AbstractNodeRelation.java +++ b/source/java/org/alfresco/rest/api/nodes/AbstractNodeRelation.java @@ -36,6 +36,7 @@ import org.alfresco.rest.framework.resource.parameters.where.Query; import org.alfresco.rest.framework.resource.parameters.where.QueryHelper; import org.alfresco.rest.workflow.api.impl.MapBasedQueryWalker; import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.AssociationExistsException; import org.alfresco.service.cmr.repository.AssociationRef; import org.alfresco.service.cmr.repository.NodeRef; @@ -70,6 +71,7 @@ public class AbstractNodeRelation implements InitializingBean protected ServiceRegistry sr; protected NodeService nodeService; protected NamespaceService namespaceService; + protected DictionaryService dictionaryService; protected Nodes nodes; public void setNodes(Nodes nodes) @@ -90,21 +92,42 @@ public class AbstractNodeRelation implements InitializingBean this.nodeService = sr.getNodeService(); this.namespaceService = sr.getNamespaceService(); + this.dictionaryService = sr.getDictionaryService(); } - protected QName getAssocType(String prefixAssocTypeStr, boolean mandatory) + protected QName getAssocType(String prefixAssocTypeStr) { - if (mandatory && ((prefixAssocTypeStr == null) || prefixAssocTypeStr.isEmpty())) + return getAssocType(prefixAssocTypeStr, true, true); + } + + protected QName getAssocType(String prefixAssocTypeStr, boolean mandatory, boolean validate) + { + QName assocType = null; + + if ((prefixAssocTypeStr != null) && (! prefixAssocTypeStr.isEmpty())) + { + assocType = QName.createQName(prefixAssocTypeStr, namespaceService); + + if (validate) + { + if (dictionaryService.getAssociation(assocType) == null) + { + throw new InvalidArgumentException("Unknown filter assocType: "+prefixAssocTypeStr); + } + + } + } + else if (mandatory) { throw new InvalidArgumentException("Missing "+PARAM_ASSOC_TYPE); } - return QName.createQName(prefixAssocTypeStr, namespaceService); + return assocType; } protected QNamePattern getAssocTypeFromWhereElseAll(Parameters parameters) { - QNamePattern assocTypeQNameParam = RegexQNamePattern.MATCH_ALL; + QNamePattern assocTypeQNamePattern = RegexQNamePattern.MATCH_ALL; Query q = parameters.getQuery(); if (q != null) @@ -115,10 +138,10 @@ public class AbstractNodeRelation implements InitializingBean String assocTypeQNameStr = propertyWalker.getProperty(PARAM_ASSOC_TYPE, WhereClauseParser.EQUALS, String.class); if (assocTypeQNameStr != null) { - assocTypeQNameParam = getAssocType(assocTypeQNameStr, true); + assocTypeQNamePattern = getAssocType(assocTypeQNameStr); } } - return assocTypeQNameParam; + return assocTypeQNamePattern; } } diff --git a/source/java/org/alfresco/rest/api/nodes/NodeParentsRelation.java b/source/java/org/alfresco/rest/api/nodes/NodeParentsRelation.java index 819d9eada9..b1128752b8 100644 --- a/source/java/org/alfresco/rest/api/nodes/NodeParentsRelation.java +++ b/source/java/org/alfresco/rest/api/nodes/NodeParentsRelation.java @@ -41,20 +41,19 @@ import java.util.Map; /** * Node Parents * - * List node's parent(s) - primary & also secondary, if any - based on (parent ->) child associations - * * @author janv */ @RelationshipResource(name = "parents", entityResource = NodesEntityResource.class, title = "Node Parents") public class NodeParentsRelation extends AbstractNodeRelation implements RelationshipResourceAction.Read { /** - * List parents + * List child node's parent(s) based on (parent ->) child associations. + * Returns primary parent & also secondary parents, if any. * * @param childNodeId String id of child node */ @Override - @WebApiDescription(title = "Return a paged list of parent nodes based on child assocs") + @WebApiDescription(title = "Return a list of parent nodes based on child assocs") public CollectionWithPagingInfo readAll(String childNodeId, Parameters parameters) { NodeRef childNodeRef = nodes.validateOrLookupNode(childNodeId, null); @@ -84,7 +83,6 @@ public class NodeParentsRelation extends AbstractNodeRelation implements Relatio Node node = nodes.getFolderOrDocument(assocRef.getParentRef(), null, null, includeParam, mapUserInfo); QName assocTypeQName = assocRef.getTypeQName(); - QName assocChildQName = assocRef.getQName(); String assocType = qnameMap.get(assocTypeQName); if (assocType == null) @@ -93,14 +91,7 @@ public class NodeParentsRelation extends AbstractNodeRelation implements Relatio qnameMap.put(assocTypeQName, assocType); } - String childQNameStr = qnameMap.get(assocChildQName); - if (childQNameStr == null) - { - childQNameStr = assocChildQName.toPrefixString(namespaceService); - qnameMap.put(assocChildQName, childQNameStr); - } - - node.setAssociation(new AssocChild(assocType, assocRef.isPrimary(), childQNameStr)); + node.setAssociation(new AssocChild(assocType, assocRef.isPrimary())); collection.add(node); } diff --git a/source/java/org/alfresco/rest/api/nodes/NodeSecondaryChildrenRelation.java b/source/java/org/alfresco/rest/api/nodes/NodeSecondaryChildrenRelation.java index 6317a64e8a..7ff6403f5e 100644 --- a/source/java/org/alfresco/rest/api/nodes/NodeSecondaryChildrenRelation.java +++ b/source/java/org/alfresco/rest/api/nodes/NodeSecondaryChildrenRelation.java @@ -18,11 +18,13 @@ */ package org.alfresco.rest.api.nodes; +import org.alfresco.model.ContentModel; import org.alfresco.rest.api.model.AssocChild; import org.alfresco.rest.api.model.Node; import org.alfresco.rest.api.model.UserInfo; import org.alfresco.rest.framework.WebApiDescription; import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException; +import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.resource.RelationshipResource; import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction; @@ -33,6 +35,7 @@ import org.alfresco.service.cmr.repository.AssociationExistsException; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QNamePattern; import org.alfresco.service.namespace.RegexQNamePattern; @@ -106,15 +109,7 @@ public class NodeSecondaryChildrenRelation extends AbstractNodeRelation implemen qnameMap.put(assocTypeQName, assocType); } - QName assocChildQName = assocRef.getQName(); - String childQNameStr = qnameMap.get(assocChildQName); - if (childQNameStr == null) - { - childQNameStr = assocChildQName.toPrefixString(namespaceService); - qnameMap.put(assocChildQName, childQNameStr); - } - - node.setAssociation(new AssocChild(assocType, assocRef.isPrimary(), childQNameStr)); + node.setAssociation(new AssocChild(assocType, assocRef.isPrimary())); collection.add(node); } @@ -134,20 +129,16 @@ public class NodeSecondaryChildrenRelation extends AbstractNodeRelation implemen for (AssocChild assoc : entity) { - QName assocTypeQName = getAssocType(assoc.getAssocType(), true); - - String childQNameStr = assoc.getChildQName(); - if ((childQNameStr == null) || childQNameStr.isEmpty()) - { - throw new InvalidArgumentException("Missing childQName"); - } - - QName childQName = QName.createQName(childQNameStr, namespaceService); + QName assocTypeQName = getAssocType(assoc.getAssocType()); try { NodeRef childNodeRef = nodes.validateNode(assoc.getChildId()); - nodeService.addChild(parentNodeRef, childNodeRef, assocTypeQName, childQName); + + String nodeName = (String)nodeService.getProperty(childNodeRef, ContentModel.PROP_NAME); + QName assocChildQName = QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createValidLocalName(nodeName)); + + nodeService.addChild(parentNodeRef, childNodeRef, assocTypeQName, assocChildQName); } catch (AssociationExistsException aee) { @@ -170,41 +161,53 @@ public class NodeSecondaryChildrenRelation extends AbstractNodeRelation implemen NodeRef parentNodeRef = nodes.validateNode(parentNodeId); NodeRef childNodeRef = nodes.validateNode(childNodeId); - QName assocTypeQName = getAssocType(parameters.getParameter("assocType"), false); + String assocTypeStr = parameters.getParameter(PARAM_ASSOC_TYPE); + QName assocTypeQName = getAssocType(assocTypeStr, false, true); - String childQNameStr = parameters.getParameter("childQName"); - QName childQName = null; - if ((childQNameStr != null) && (!childQNameStr.isEmpty())) - { - childQName = QName.createQName(childQNameStr, namespaceService); - } + List assocRefs = nodeService.getChildAssocs(parentNodeRef); - if (assocTypeQName != null) + boolean found = false; + + for (ChildAssociationRef assocRef : assocRefs) { - if (childQName != null) + if (! assocRef.getChildRef().equals(childNodeRef)) { - ChildAssociationRef assocRef = new ChildAssociationRef(assocTypeQName, parentNodeRef, childQName, childNodeRef); - nodeService.removeSecondaryChildAssociation(assocRef); + continue; + } + + if (assocTypeQName != null) + { + if (assocTypeQName.equals(assocRef.getTypeQName())) + { + if (assocRef.isPrimary()) + { + throw new InvalidArgumentException("Cannot use secondary-children to delete primary assoc: " + +parentNodeId+","+assocTypeStr+","+childNodeId); + } + + boolean existed = nodeService.removeSecondaryChildAssociation(assocRef); + if (existed) + { + found = true; + } + } } else { - throw new InvalidArgumentException("Missing childQName (in addition to assocType)"); - } - } - else if (childQName != null) - { - throw new InvalidArgumentException("Missing assocType (in addition to childQName)"); - } - else - { - List assocRefs = nodeService.getChildAssocs(parentNodeRef); - for (ChildAssociationRef assocRef : assocRefs) - { - if (assocRef.getChildRef().equals(childNodeRef) && (! assocRef.isPrimary())) + if (! assocRef.isPrimary()) { - nodeService.removeSecondaryChildAssociation(assocRef); + boolean existed = nodeService.removeSecondaryChildAssociation(assocRef); + if (existed) + { + found = true; + } } } } + + if (! found) + { + throw new EntityNotFoundException(parentNodeId+","+assocTypeStr+","+childNodeId); + } } } diff --git a/source/java/org/alfresco/rest/api/nodes/NodeTargetsRelation.java b/source/java/org/alfresco/rest/api/nodes/NodeTargetsRelation.java index dd711d8741..886af02443 100644 --- a/source/java/org/alfresco/rest/api/nodes/NodeTargetsRelation.java +++ b/source/java/org/alfresco/rest/api/nodes/NodeTargetsRelation.java @@ -24,6 +24,8 @@ import org.alfresco.rest.api.model.Node; import org.alfresco.rest.api.model.UserInfo; import org.alfresco.rest.framework.WebApiDescription; import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException; +import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; +import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.resource.RelationshipResource; import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; @@ -108,17 +110,25 @@ public class NodeTargetsRelation extends AbstractNodeRelation implements for (AssocTarget assoc : entity) { - QName assocTypeQName = getAssocType(assoc.getAssocType(), true); + String assocTypeStr = assoc.getAssocType(); + QName assocTypeQName = getAssocType(assocTypeStr); + + String targetNodeId = assoc.getTargetId(); try { - NodeRef tgtNodeRef = nodes.validateNode(assoc.getTargetId()); + NodeRef tgtNodeRef = nodes.validateNode(targetNodeId); nodeService.createAssociation(srcNodeRef, tgtNodeRef, assocTypeQName); } catch (AssociationExistsException aee) { throw new ConstraintViolatedException(aee.getMessage()); } + catch (IllegalArgumentException iae) + { + // note: for now, we assume it is invalid assocType - alternatively, we could attempt to pre-validate via dictionary.getAssociation + throw new InvalidArgumentException(sourceNodeId+","+assocTypeStr+","+targetNodeId); + } result.add(assoc); } @@ -133,21 +143,31 @@ public class NodeTargetsRelation extends AbstractNodeRelation implements NodeRef tgtNodeRef = nodes.validateNode(targetNodeId); String assocTypeStr = parameters.getParameter(PARAM_ASSOC_TYPE); - if ((assocTypeStr != null) && (! assocTypeStr.isEmpty())) + QNamePattern assocTypeQName = getAssocType(assocTypeStr, false, true); + + if (assocTypeQName == null) { - QName assocTypeQName = QName.createQName(assocTypeStr, namespaceService); - nodeService.removeAssociation(srcNodeRef, tgtNodeRef, assocTypeQName); + assocTypeQName = RegexQNamePattern.MATCH_ALL; } - else + + // note: even if assocType is provided, we currently don't use nodeService.removeAssociation(srcNodeRef, tgtNodeRef, assocTypeQName); + // since silent it returns void even if nothing deleted, where as we return 404 + + boolean found = false; + + List assocRefs = nodeService.getTargetAssocs(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, sourceNodeId), assocTypeQName); + for (AssociationRef assocRef : assocRefs) { - List assocRefs = nodeService.getTargetAssocs(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, sourceNodeId), RegexQNamePattern.MATCH_ALL); - for (AssociationRef assocRef : assocRefs) + if (assocRef.getTargetRef().equals(tgtNodeRef)) { - if (assocRef.getTargetRef().equals(tgtNodeRef)) - { - nodeService.removeAssociation(srcNodeRef, tgtNodeRef, assocRef.getTypeQName()); - } + nodeService.removeAssociation(srcNodeRef, tgtNodeRef, assocRef.getTypeQName()); + found = true; } } + + if (! found) + { + throw new EntityNotFoundException(sourceNodeId+","+assocTypeStr+","+targetNodeId); + } } } diff --git a/source/test-java/org/alfresco/rest/api/tests/NodeAssociationsApiTest.java b/source/test-java/org/alfresco/rest/api/tests/NodeAssociationsApiTest.java index 0efc1e8ad5..04578ea03c 100644 --- a/source/test-java/org/alfresco/rest/api/tests/NodeAssociationsApiTest.java +++ b/source/test-java/org/alfresco/rest/api/tests/NodeAssociationsApiTest.java @@ -21,19 +21,12 @@ package org.alfresco.rest.api.tests; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.rest.api.Nodes; -import org.alfresco.rest.api.Queries; import org.alfresco.rest.api.model.AssocChild; import org.alfresco.rest.api.model.AssocTarget; import org.alfresco.rest.api.tests.client.HttpResponse; -import org.alfresco.rest.api.tests.client.PublicApiClient; import org.alfresco.rest.api.tests.client.PublicApiClient.Paging; -import org.alfresco.rest.api.tests.client.RequestContext; import org.alfresco.rest.api.tests.client.data.Association; -import org.alfresco.rest.api.tests.client.data.ContentInfo; -import org.alfresco.rest.api.tests.client.data.Document; -import org.alfresco.rest.api.tests.client.data.Folder; import org.alfresco.rest.api.tests.client.data.Node; -import org.alfresco.rest.api.tests.client.data.Tag; import org.alfresco.rest.api.tests.util.RestApiUtil; import org.alfresco.service.cmr.security.MutableAuthenticationService; import org.alfresco.service.cmr.security.PersonService; @@ -44,12 +37,10 @@ import org.junit.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.UUID; import static org.alfresco.rest.api.tests.util.RestApiUtil.toJsonAsStringNonNull; import static org.junit.Assert.*; @@ -100,9 +91,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest private static final String ASPECT_CM_PREFERENCES = "cm:preferences"; private static final String ASSOC_TYPE_CM_PREFERENCE_IMAGE = "cm:preferenceImage"; - private static final String PARAM_CHILD_NAME = "childQName"; - - private String user1; private String user2; @@ -220,10 +208,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest Paging paging = getPaging(0, 100); - // -ve test - unauthenticated - belts-and-braces ;-) - getAll(getNodeTargetsUrl(f1Id), null, paging, null, 401); - getAll(getNodeSourcesUrl(f1Id), null, paging, null, 401); - // empty lists - before response = getAll(getNodeTargetsUrl(o1Id), user1, paging, null, 200); @@ -242,13 +226,9 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); assertEquals(0, nodes.size()); - // -ve test - unauthenticated - belts-and-braces ;-) - AssocTarget tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_REFERENCES); - post(getNodeTargetsUrl(o1Id), null, toJsonAsStringNonNull(tgt), 401); - // create two assocs in one direction (from src to tgt) - tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_REFERENCES); + AssocTarget tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_REFERENCES); post(getNodeTargetsUrl(o1Id), user1, toJsonAsStringNonNull(tgt), 201); tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_PARTS); @@ -311,7 +291,7 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest assertEquals(o2Id, nodes.get(0).getId()); assertEquals(ASSOC_TYPE_CM_REFERENCES, nodes.get(0).getAssociation().getAssocType()); - params = new HashMap<>(); + params = new HashMap<>(1); params.put("where", "(assocType='"+ASSOC_TYPE_CM_PARTS+"')"); response = getAll(getNodeTargetsUrl(o2Id), user1, paging, params, 200); @@ -326,10 +306,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest assertEquals(o1Id, nodes.get(0).getId()); assertEquals(ASSOC_TYPE_CM_PARTS, nodes.get(0).getAssociation().getAssocType()); - - // -ve test - unauthenticated - belts-and-braces ;-) - delete(getNodeTargetsUrl(o1Id), null, o2Id, 401); - // remove assocs - specific type - in one direction params = new HashMap<>(2); params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_REFERENCES); @@ -393,18 +369,74 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest assertEquals(0, nodes.size()); - // -ve test - model integrity - tgt = new AssocTarget(f2Id, ASSOC_TYPE_CM_REFERENCES); - post(getNodeTargetsUrl(o1Id), user1, toJsonAsStringNonNull(tgt), 422); + // + // -ve tests - add assoc + // - // -ve test - duplicate assoc - tgt = new AssocTarget(o1Id, ASSOC_TYPE_CM_REFERENCES); - post(getNodeTargetsUrl(o2Id), user1, toJsonAsStringNonNull(tgt), 201); - post(getNodeTargetsUrl(o2Id), user1, toJsonAsStringNonNull(tgt), 409); + { + // -ve test - unauthenticated - belts-and-braces ;-) + tgt = new AssocTarget(o2Id, ASSOC_TYPE_CM_REFERENCES); + post(getNodeTargetsUrl(o1Id), null, toJsonAsStringNonNull(tgt), 401); - // TODO some more negative tests - // 400s - eg. invalid qname - // 404s - eg. unknown src, tgt, assoc of given type + // -ve test - model integrity + tgt = new AssocTarget(f2Id, ASSOC_TYPE_CM_REFERENCES); + post(getNodeTargetsUrl(o1Id), user1, toJsonAsStringNonNull(tgt), 422); + + // -ve test - duplicate assoc + tgt = new AssocTarget(o1Id, ASSOC_TYPE_CM_REFERENCES); + post(getNodeTargetsUrl(o2Id), user1, toJsonAsStringNonNull(tgt), 201); + post(getNodeTargetsUrl(o2Id), user1, toJsonAsStringNonNull(tgt), 409); + + tgt = new AssocTarget(o1Id, "cm:unknowntype"); + post(getNodeTargetsUrl(o2Id), user1, toJsonAsStringNonNull(tgt), 400); + } + + // + // -ve test - list assocs + // + + { + // -ve test - unauthenticated - belts-and-braces ;-) + getAll(getNodeTargetsUrl(f1Id), null, paging, null, 401); + getAll(getNodeSourcesUrl(f1Id), null, paging, null, 401); + + getAll(getNodeTargetsUrl(UUID.randomUUID().toString()), user1, paging, null, 404); + getAll(getNodeSourcesUrl(UUID.randomUUID().toString()), user1, paging, null, 404); + + params = new HashMap<>(1); + params.put("where", "(assocType='cm:unknownassoctype')"); + + getAll(getNodeTargetsUrl(o1Id), user1, paging, params, 400); + getAll(getNodeSourcesUrl(o1Id), user1, paging, params, 400); + + // TODO paging - in-built sort order ? + } + + + // + // -ve test - remove assoc(s) + // + + { + // -ve test - unauthenticated - belts-and-braces ;-) + delete(getNodeTargetsUrl(o1Id), null, o2Id, 401); + + delete(getNodeTargetsUrl(UUID.randomUUID().toString()), user1, o2Id, null, 404); + delete(getNodeTargetsUrl(o1Id), user1, UUID.randomUUID().toString(), null, 404); + + // -ve test -nothing to delete - for any assoc type + delete(getNodeTargetsUrl(o1Id), user1, o2Id, null, 404); + + // -ve test - nothing to delete - for given assoc type + params = new HashMap<>(2); + params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_REFERENCES); + delete(getNodeTargetsUrl(o1Id), user1, o2Id, params, 404); + + // -ve test - unknown assoc type + params = new HashMap<>(2); + params.put(PARAM_ASSOC_TYPE, "cm:unknowntype"); + delete(getNodeTargetsUrl(o1Id), user1, o2Id, params, 400); + } } finally { @@ -469,10 +501,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest Paging paging = getPaging(0, 100); - // -ve test - unauthenticated - belts-and-braces ;-) - getAll(getNodeSecondaryChildrenUrl(f1Id), null, paging, null, 401); - getAll(getNodeParentsUrl(o2Id), null, paging, null, 401); - // lists - before response = getAll(getNodeSecondaryChildrenUrl(f1Id), user1, paging, null, 200); @@ -485,22 +513,14 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest assertEquals(1, nodes.size()); assertEquals(f2Id, nodes.get(0).getId()); assertEquals(ASSOC_TYPE_CM_CONTAINS, nodes.get(0).getAssociation().getAssocType()); - assertEquals("cm:"+o2Name, nodes.get(0).getAssociation().getChildQName()); assertTrue(nodes.get(0).getAssociation().getIsPrimaryParent()); - String o2SecChildName = "cm:o2SecChildName"; - - // -ve test - unauthenticated - belts-and-braces ;-) - AssocChild secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS, o2SecChildName); - post(getNodeSecondaryChildrenUrl(f1Id), null, toJsonAsStringNonNull(secChild), 401); - - // create secondary child assoc - secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS, o2SecChildName); + AssocChild secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS); post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 201); // create ano' secondary child assoc (different type) between the same two nodes - secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_PREFERENCE_IMAGE, o2SecChildName); + secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_PREFERENCE_IMAGE); post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 201); @@ -520,7 +540,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest i++; } assertEquals(o2Id, node.getId()); - assertEquals(o2SecChildName, nodeAssoc.getChildQName()); assertFalse(nodeAssoc.getIsPrimaryParent()); } assertEquals(2, i); @@ -536,7 +555,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest if (nodeId.equals(f2Id)) { assertEquals(ASSOC_TYPE_CM_CONTAINS, nodeAssoc.getAssocType()); - assertEquals("cm:"+o2Name, nodeAssoc.getChildQName()); assertTrue(nodeAssoc.getIsPrimaryParent()); i++; } @@ -550,7 +568,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest { i++; } - assertEquals(o2SecChildName, nodeAssoc.getChildQName()); assertFalse(nodeAssoc.getIsPrimaryParent()); } } @@ -577,14 +594,12 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest if (nodeId.equals(f2Id)) { assertEquals(ASSOC_TYPE_CM_CONTAINS, nodeAssoc.getAssocType()); - assertEquals("cm:"+o2Name, nodeAssoc.getChildQName()); assertTrue(nodeAssoc.getIsPrimaryParent()); i++; } else if (nodeId.equals(f1Id)) { assertEquals(ASSOC_TYPE_CM_CONTAINS, nodeAssoc.getAssocType()); - assertEquals(o2SecChildName, nodeAssoc.getChildQName()); assertFalse(nodeAssoc.getIsPrimaryParent()); i++; } @@ -611,10 +626,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest params = new HashMap<>(2); params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_CONTAINS); - params.put(PARAM_CHILD_NAME, o2SecChildName); - - // -ve test - unauthenticated - belts-and-braces ;-) - delete(getNodeSecondaryChildrenUrl(f1Id), null, o2Id, params, 401); // remove one secondary child assoc delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, params, 204); @@ -629,7 +640,6 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest params = new HashMap<>(2); params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_PREFERENCE_IMAGE); - params.put(PARAM_CHILD_NAME, o2SecChildName); // remove other secondary child assoc delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, params, 204); @@ -642,26 +652,83 @@ public class NodeAssociationsApiTest extends AbstractBaseApiTest nodes = RestApiUtil.parseRestApiEntries(response.getJsonResponse(), Node.class); assertEquals(1, nodes.size()); - // TODO test delete of multiple secondary child assocs (if assoc type is not specified) + // TODO +ve test delete of multiple secondary child assocs (if assoc type is not specified) + // + // -ve tests - add assoc + // - // -ve test - model integrity - secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS, o2SecChildName); - post(getNodeSecondaryChildrenUrl(o1Id), user1, toJsonAsStringNonNull(secChild), 422); + { + // -ve test - unauthenticated - belts-and-braces ;-) + secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS); + post(getNodeSecondaryChildrenUrl(f1Id), null, toJsonAsStringNonNull(secChild), 401); - // -ve test - duplicate assoc - secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS, o2SecChildName); - post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 201); - post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 409); + // -ve test - model integrity + secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS); + post(getNodeSecondaryChildrenUrl(o1Id), user1, toJsonAsStringNonNull(secChild), 422); - // TODO some more negative tests - // 400s - eg. invalid qname - // 404s - eg. unknown src, tgt, assoc of given type + // -ve test - duplicate assoc + secChild = new AssocChild(o2Id, ASSOC_TYPE_CM_CONTAINS); + post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 201); + post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 409); + delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, null, 204); // cleanup + + secChild = new AssocChild(o2Id, "cm:unknowntype"); + post(getNodeSecondaryChildrenUrl(f1Id), user1, toJsonAsStringNonNull(secChild), 400); + } + + // + // -ve test - list assocs + // + + { + // -ve test - unauthenticated - belts-and-braces ;-) + getAll(getNodeSecondaryChildrenUrl(f1Id), null, paging, null, 401); + getAll(getNodeParentsUrl(o2Id), null, paging, null, 401); + + getAll(getNodeSecondaryChildrenUrl(UUID.randomUUID().toString()), user1, paging, null, 404); + getAll(getNodeParentsUrl(UUID.randomUUID().toString()), user1, paging, null, 404); + + params = new HashMap<>(1); + params.put("where", "(assocType='cm:unknownassoctype')"); + + getAll(getNodeSecondaryChildrenUrl(o1Id), user1, paging, params, 400); + getAll(getNodeParentsUrl(o1Id), user1, paging, params, 400); + + // TODO paging - in-built sort order ? + } + + // + // -ve test - remove assoc(s) + // + + { + // unauthenticated - belts-and-braces ;-) + delete(getNodeSecondaryChildrenUrl(f1Id), null, o2Id, null, 401); + + delete(getNodeSecondaryChildrenUrl(UUID.randomUUID().toString()), user1, o2Id, null, 404); + delete(getNodeSecondaryChildrenUrl(f1Id), user1, UUID.randomUUID().toString(), null, 404); + + // nothing to delete - for any assoc type + delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, null, 404); + + // nothing to delete - for given assoc type + params = new HashMap<>(2); + params.put(PARAM_ASSOC_TYPE, ASSOC_TYPE_CM_PREFERENCE_IMAGE); + delete(getNodeSecondaryChildrenUrl(f1Id), user1, o2Id, params, 404); + + // unknown assoc type + params = new HashMap<>(2); + params.put(PARAM_ASSOC_TYPE, "cm:unknowntype"); + delete(getNodeSecondaryChildrenUrl(o1Id), user1, o2Id, params, 400); + + // TODO 400 - try to delete primary assoc using /secondary-children + } } finally { // some cleanup - Map params = Collections.singletonMap("permanent", "true"); + Map params = Collections.singletonMap(Nodes.PARAM_PERMANENT, "true"); delete(URL_NODES, user1, f1Id, params, 204); delete(URL_NODES, user1, f2Id, params, 204); } diff --git a/source/test-java/org/alfresco/rest/api/tests/client/data/Association.java b/source/test-java/org/alfresco/rest/api/tests/client/data/Association.java index 8dc917fe10..a8c8fb671f 100644 --- a/source/test-java/org/alfresco/rest/api/tests/client/data/Association.java +++ b/source/test-java/org/alfresco/rest/api/tests/client/data/Association.java @@ -34,19 +34,8 @@ public class Association } // child assoc - private String prefixAssocChildQName; private Boolean isPrimaryParent; - public String getChildQName() - { - return prefixAssocChildQName; - } - - public void setChildQName(String prefixAssocChildQName) - { - this.prefixAssocChildQName = prefixAssocChildQName; - } - public Boolean getIsPrimaryParent() { return isPrimaryParent;