You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by kw...@apache.org on 2022/06/09 17:53:32 UTC

[jackrabbit-filevault] 01/01: JCRVLT-598 introduce new IdConflictPolicy.LEGACY which restores the pre-3.5.2 behaviour

This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch bugfix/JCRVLT-598
in repository https://gitbox.apache.org/repos/asf/jackrabbit-filevault.git

commit c946fba8572366b99e83ceffc958011ff26add69
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Thu Jun 9 19:53:25 2022 +0200

    JCRVLT-598 introduce new IdConflictPolicy.LEGACY which restores the
    pre-3.5.2 behaviour
    
    WIP
---
 src/site/markdown/referenceablenodes.md            |  4 +-
 .../jackrabbit/vault/fs/api/IdConflictPolicy.java  |  4 +-
 .../vault/fs/impl/io/DocViewImporter.java          | 56 ++++++++++---
 .../ReferenceableIdentifiersImportIT.java          | 95 ++++++++++++++--------
 .../tmp/differentparentconflicts/.content.xml      |  4 +
 .../{ => differentparentconflicts}/duplicate.xml   |  2 -
 .../referenceable.xml                              |  2 -
 .../tmp/{ => sameparentconflicts}/duplicate.xml    |  5 --
 .../{ => sameparentconflicts}/referenceable.xml    |  5 --
 9 files changed, 114 insertions(+), 63 deletions(-)

diff --git a/src/site/markdown/referenceablenodes.md b/src/site/markdown/referenceablenodes.md
index 0fe1a256..a8c49cc3 100644
--- a/src/site/markdown/referenceablenodes.md
+++ b/src/site/markdown/referenceablenodes.md
@@ -26,7 +26,7 @@ The import behavior depends on the used FileVault version.
 
 ## Import behavior prior FileVault 3.5.2
 
-The ids of referenceable nodes are only kept during import when a node with the same name does not yet exist in the repository. For existing nodes the ids are never updated with the value from the package. They either get a new id or keep their old one (in case the old node was already a referenceable node). In case of conflicts with nodes at a different path, the existing conflicting node is [removed][5] but all its references are kept (i.e. they point to a different path after the import).
+The ids of referenceable nodes are only kept during import when a node with the same name does not yet exist in the repository. For existing nodes the ids are never updated with the value from the package. They either get a new id or keep their old one (in case the old node was already a referenceable node). In case of conflicts with nodes which are not siblings (i.e. don't share their direct parent node) the newly imported node gets a new UUID, on case of conflicts among siblings the ex [...]
 
 ## Import behavior since FileVault 3.5.2
 
@@ -34,7 +34,7 @@ Since version 3.5.2 ([JCRVLT-551](https://issues.apache.org/jira/browse/JCRVLT-5
 
 ### Id Conflict Policies
 
-The import behavior of packages with conflicting ids can be tweaked with `ImportOptions.setIdConflictPolicy(...)`. For further details refer to its [javadoc][3]. The old behavior can be achieved with `IdConflictPolicy.FORCE_REMOVE_CONFLICTING_ID`.
+The import behavior of packages with conflicting ids can be tweaked with `ImportOptions.setIdConflictPolicy(...)` per package or the default can be overridden in the [OSGi Configuration](config.html). For further details refer to the [JavaDoc][3]. The old behavior can be achieved with `IdConflictPolicy.LEGACY`.
 
 [1]: https://s.apache.org/jcr-2.0-spec/3_Repository_Model.html#3.8%20Referenceable%20Nodes
 [2]: https://s.apache.org/jcr-2.0-spec/3_Repository_Model.html#3.8.2%20Referential%20Integrity
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/api/IdConflictPolicy.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/api/IdConflictPolicy.java
index 83abb3af..29b9df0f 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/api/IdConflictPolicy.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/api/IdConflictPolicy.java
@@ -25,5 +25,7 @@ public enum IdConflictPolicy {
     CREATE_NEW_ID,
     /** Remove the node with the conflicting id along with its references (even if outside the filters). This goes beyond {@link ImportUUIDBehavior#IMPORT_UUID_COLLISION_REMOVE_EXISTING}, as it also does not only resolve UUID collisions but also replacements of referenceable nodes with different ids.
      * Use with care, as this may remove references outside the filter. */
-    FORCE_REMOVE_CONFLICTING_ID
+    FORCE_REMOVE_CONFLICTING_ID,
+    /** Assign the newly imported conflicting node a new id in case the conflicting existing node does not have the same parent (i.e. is a sibling), otherwise remove the existing node with the conflicting id but keep its references */
+    LEGACY
 }
diff --git a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewImporter.java b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewImporter.java
index 98e76635..b7904665 100644
--- a/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewImporter.java
+++ b/vault-core/src/main/java/org/apache/jackrabbit/vault/fs/impl/io/DocViewImporter.java
@@ -65,6 +65,8 @@ import org.apache.jackrabbit.util.Text;
 import org.apache.jackrabbit.vault.fs.api.Artifact;
 import org.apache.jackrabbit.vault.fs.api.ArtifactType;
 import org.apache.jackrabbit.vault.fs.api.IdConflictPolicy;
+import org.apache.jackrabbit.vault.fs.api.ImportInfo.Info;
+import org.apache.jackrabbit.vault.fs.api.ImportInfo.Type;
 import org.apache.jackrabbit.vault.fs.api.ImportMode;
 import org.apache.jackrabbit.vault.fs.api.ItemFilterSet;
 import org.apache.jackrabbit.vault.fs.api.NodeNameList;
@@ -141,7 +143,7 @@ public class DocViewImporter implements DocViewParserHandler {
     private final Session session;
 
     /**
-     * final import information
+     * final import information (initially empty)
      */
     private ImportInfoImpl importInfo = new ImportInfoImpl();
 
@@ -819,6 +821,7 @@ public class DocViewImporter implements DocViewParserHandler {
     private StackElement addNode(DocViewNode2 docViewNode) throws RepositoryException, IOException {
         final Node currentNode = stack.getNode();
 
+        Collection<DocViewProperty2> preprocessedProperties = new LinkedList<>(docViewNode.getProperties());
         Node existingNode = null;
         if (NameConstants.ROOT.equals(docViewNode.getName())) {
             // special case for root node update
@@ -828,7 +831,7 @@ public class DocViewImporter implements DocViewParserHandler {
                 existingNode = currentNode.getNode(docViewNode.getName().toString());
             }
             Optional<String> identifier = docViewNode.getIdentifier();
-            if (identifier.isPresent() && idConflictPolicy == IdConflictPolicy.FAIL) {
+            if (identifier.isPresent()) {
                 try {
                     // does uuid already exist in the repo?
                     Node sameIdNode = session.getNodeByIdentifier(identifier.get());
@@ -836,15 +839,45 @@ public class DocViewImporter implements DocViewParserHandler {
                     if (existingNode != null && existingNode.getPath().equals(sameIdNode.getPath())) {
                         log.debug("Node with existing identifier {} at {} is being updated without modifying its uuid", docViewNode.getIdentifier(), existingNode.getPath());
                     } else {
-                        // uuid found in path covered by filter
-                        if (isIncluded(sameIdNode, 0)) {
-                            log.warn("Node identifier {} for to-be imported node {}/{} already taken by {}, trying to release it.", docViewNode.getIdentifier(), currentNode.getPath(), docViewNode.getName(), sameIdNode.getPath());
-                            removeReferences(sameIdNode);
-                            session.removeItem(sameIdNode.getPath());
-                            existingNode = null;
-                        } else {
-                            // uuid found in path not-covered by filter
-                            throw new ReferentialIntegrityException("UUID " + docViewNode.getIdentifier() + " already taken by node " + sameIdNode.getPath());
+                        // TODO: add common logging which includes the conflict policy
+                        if (idConflictPolicy == IdConflictPolicy.FAIL) {
+                            // uuid found in path covered by filter
+                            if (isIncluded(sameIdNode, 0)) {
+                                Info sameIdNodeInfo = importInfo.getInfo(sameIdNode.getPath());
+                                // is the conflicting node part of the package (i.e. the package contained duplicate uuids)
+                                if (sameIdNodeInfo != null && sameIdNodeInfo.getType() != Type.DEL) {
+                                    throw new ReferentialIntegrityException("UUID " + docViewNode.getIdentifier() + " already taken by node " + sameIdNode.getPath() + " from the same package");
+                                } else {
+                                    log.warn("Node identifier {} for to-be imported node {}/{} already taken by {}, trying to release it.", docViewNode.getIdentifier(), currentNode.getPath(), docViewNode.getName(), sameIdNode.getPath());
+                                    removeReferences(sameIdNode);
+                                    String sameIdNodePath = sameIdNode.getPath();
+                                    session.removeItem(sameIdNodePath);
+                                    log.warn("Node {} and its references removed", sameIdNodePath);
+                                }
+                                existingNode = null;
+                            } else {
+                                // uuid found in path not-covered by filter
+                                throw new ReferentialIntegrityException("UUID " + docViewNode.getIdentifier() + " already taken by node " + sameIdNode.getPath());
+                            }
+                        } else if (idConflictPolicy == IdConflictPolicy.LEGACY) {
+                            // is the conflicting node a sibling
+                            if (sameIdNode.getParent().isSame(currentNode)) {
+                                log.warn("Node identifier {} for to-be imported node {}/{} already taken by {}, trying to release it.", docViewNode.getIdentifier(), currentNode.getPath(), docViewNode.getName(), sameIdNode.getPath());
+                                // TODO: check if this is really the case for pre 3.5.2 and if it makes a difference if the conflict is part of the package or not
+                                removeReferences(sameIdNode);
+                                String sameIdNodePath = sameIdNode.getPath();
+                                session.removeItem(sameIdNodePath);
+                                log.warn("Node {} and its references removed", sameIdNodePath);
+                            } else {
+                                log.warn("Packaged node at {} is referenceable and collides with existing node at {}. Will create new UUID for the former.",
+                                        currentNode.getPath() + "/" + npResolver.getJCRName(docViewNode.getName()),
+                                        sameIdNode.getPath());
+                                preprocessedProperties.removeIf(p -> p.getName().equals(NameConstants.JCR_UUID));
+                                preprocessedProperties.removeIf(p -> p.getName().equals(NameConstants.JCR_BASEVERSION));
+                                preprocessedProperties.removeIf(p -> p.getName().equals(NameConstants.JCR_PREDECESSORS));
+                                preprocessedProperties.removeIf(p -> p.getName().equals(NameConstants.JCR_SUCCESSORS));
+                                preprocessedProperties.removeIf(p -> p.getName().equals(NameConstants.JCR_VERSIONHISTORY));
+                            }
                         }
                     }
                 } catch (ItemNotFoundException e) {
@@ -854,7 +887,6 @@ public class DocViewImporter implements DocViewParserHandler {
         }
 
         // check if new node needs to be checked in
-        Collection<DocViewProperty2> preprocessedProperties = new LinkedList<>(docViewNode.getProperties());
         preprocessedProperties.removeIf(p -> p.getName().equals(NameConstants.JCR_ISCHECKEDOUT));
         boolean isCheckedIn = "false".equals(docViewNode.getPropertyValue(NameConstants.JCR_ISCHECKEDOUT).orElse("true"));
 
diff --git a/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/ReferenceableIdentifiersImportIT.java b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/ReferenceableIdentifiersImportIT.java
index 35cecffa..a80adabe 100644
--- a/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/ReferenceableIdentifiersImportIT.java
+++ b/vault-core/src/test/java/org/apache/jackrabbit/vault/packaging/integration/ReferenceableIdentifiersImportIT.java
@@ -19,11 +19,15 @@ package org.apache.jackrabbit.vault.packaging.integration;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
 
 import javax.jcr.Node;
 import javax.jcr.PathNotFoundException;
@@ -295,15 +299,16 @@ public class ReferenceableIdentifiersImportIT extends IntegrationTestBase {
 
     @Test
     public void testImportDupPolicyFail() throws RepositoryException, IOException, PackageException {
+        // TODO: this is supposed to fail the installation
         testImportDup(IdConflictPolicy.FAIL);
-        Node referenceableNode = getNodeOrNull("/tmp/referenceable");
-        Node duplicateNode = getNodeOrNull("/tmp/duplicate");
+        Node referenceableNode = getNodeOrNull("/tmp/differentparentconflicts/referenceable/child");
+        Node duplicateNode = getNodeOrNull("/tmp/differentparentconflicts/duplicate/child");
         if (duplicateNode == null && referenceableNode != null) {
             assertTrue(referenceableNode.isNodeType(JcrConstants.MIX_REFERENCEABLE));
-            assertEquals(referenceableNode.getIdentifier(), UUID_REFERENCEABLE);
+            assertEquals(referenceableNode.getIdentifier(), UUID_REFERENCEABLE_CHILD);
         } else if (duplicateNode != null && referenceableNode == null) {
             assertTrue(duplicateNode.isNodeType(JcrConstants.MIX_REFERENCEABLE));
-            assertEquals(duplicateNode.getIdentifier(), UUID_REFERENCEABLE);
+            assertEquals(duplicateNode.getIdentifier(), UUID_REFERENCEABLE_CHILD);
         } else {
             fail("both nodes imported");
         }
@@ -312,51 +317,73 @@ public class ReferenceableIdentifiersImportIT extends IntegrationTestBase {
     @Test
     public void testImportDupPolicyCreateNewId() throws RepositoryException, IOException, PackageException {
         testImportDup(IdConflictPolicy.CREATE_NEW_ID);
-        Node referenceableNode = getNodeOrNull("/tmp/referenceable");
-        Node duplicateNode = getNodeOrNull("/tmp/duplicate");
-        if (duplicateNode == null) {
-            fail("'duplicate' not imported");
-        } else if (referenceableNode == null) {
-            fail("'referencable' not imported");
+        Node referenceableNode = getNodeOrNull("/tmp/differentparentconflicts/referenceable/child");
+        Node duplicateNode = getNodeOrNull("/tmp/differentparentconflicts/duplicate/child");
+        assertNotNull("'duplicate' not imported", duplicateNode);
+        assertNotNull("'referencable' not imported", referenceableNode);
+        assertTrue(referenceableNode.isNodeType(JcrConstants.MIX_REFERENCEABLE));
+        String refref = referenceableNode.getIdentifier();
+        assertTrue(duplicateNode.isNodeType(JcrConstants.MIX_REFERENCEABLE));
+        String dupref = duplicateNode.getIdentifier();
+        assertNotEquals("identifiers should be different", refref, dupref);
+
+        // For this test, Jackrabbit and Oak behave differently; for now, we
+        // just observe the behavior (and the test ensures, that it doesn't
+        // change without us noticing)
+        if (isOak()) {
+            assertTrue("identifiers should be new", !UUID_REFERENCEABLE_CHILD.equals(refref) && !UUID_REFERENCEABLE_CHILD.equals(dupref));
         } else {
-            assertTrue(referenceableNode.isNodeType(JcrConstants.MIX_REFERENCEABLE));
-            String refref = referenceableNode.getIdentifier();
-            assertTrue(duplicateNode.isNodeType(JcrConstants.MIX_REFERENCEABLE));
-            String dupref = duplicateNode.getIdentifier();
-            assertNotEquals("identifiers should be different", refref, dupref);
-
-            // For this test, Jackrabbit and Oak behave differently; for now, we
-            // just observe the behavior (and the test ensures, that it doesn't
-            // change without us noticing)
-            if (isOak()) {
-                assertTrue("identifiers should be new", !UUID_REFERENCEABLE.equals(refref) && !UUID_REFERENCEABLE.equals(dupref));
-            } else {
-                int newUUIDs = 0;
-                if (!UUID_REFERENCEABLE.equals(refref)) {
-                    newUUIDs += 1;
-                }
-                if (!UUID_REFERENCEABLE.equals(dupref)) {
-                    newUUIDs += 1;
-                }
-                assertEquals("for Jackrabbit classic, exactly one changed UUID was expected", 1, newUUIDs);
+            int newUUIDs = 0;
+            if (!UUID_REFERENCEABLE_CHILD.equals(refref)) {
+                newUUIDs += 1;
             }
+            if (!UUID_REFERENCEABLE_CHILD.equals(dupref)) {
+                newUUIDs += 1;
+            }
+            assertEquals("for Jackrabbit classic, exactly one changed UUID was expected", 1, newUUIDs);
         }
     }
 
     @Test
     public void testImportDupPolicyForceRemove() throws RepositoryException, IOException, PackageException {
         testImportDup(IdConflictPolicy.FORCE_REMOVE_CONFLICTING_ID);
-        Node referenceableNode = getNodeOrNull("/tmp/referenceable");
-        Node duplicateNode = getNodeOrNull("/tmp/duplicate");
+        Node referenceableNode = getNodeOrNull("/tmp/differentparentconflicts/referenceable/child");
+        Node duplicateNode = getNodeOrNull("/tmp/differentparentconflicts/duplicate/child");
+        if (duplicateNode == null && referenceableNode != null) {
+            assertTrue(referenceableNode.isNodeType(JcrConstants.MIX_REFERENCEABLE));
+            assertEquals(UUID_REFERENCEABLE_CHILD, referenceableNode.getIdentifier());
+        } else if (duplicateNode != null && referenceableNode == null) {
+            assertTrue(duplicateNode.isNodeType(JcrConstants.MIX_REFERENCEABLE));
+            assertEquals(UUID_REFERENCEABLE_CHILD, duplicateNode.getIdentifier());
+        } else {
+            fail("both nodes imported");
+        }
+    }
+
+    @Test
+    public void testImportDupPolicyLegacy() throws RepositoryException, IOException, PackageException {
+        testImportDup(IdConflictPolicy.LEGACY);
+        // behaviour for same parent conflicts: remove the conflicting one (i.e. the first one), but keep references
+        Node referenceableNode = getNodeOrNull("/tmp/sameparentconflicts/referenceable");
+        Node duplicateNode = getNodeOrNull("/tmp/sameparentconflicts/duplicate");
         if (duplicateNode == null && referenceableNode != null) {
             assertTrue(referenceableNode.isNodeType(JcrConstants.MIX_REFERENCEABLE));
-            assertEquals(referenceableNode.getIdentifier(), UUID_REFERENCEABLE);
+            assertEquals(UUID_REFERENCEABLE, referenceableNode.getIdentifier());
         } else if (duplicateNode != null && referenceableNode == null) {
             assertTrue(duplicateNode.isNodeType(JcrConstants.MIX_REFERENCEABLE));
-            assertEquals(duplicateNode.getIdentifier(), UUID_REFERENCEABLE);
+            assertEquals(UUID_REFERENCEABLE, duplicateNode.getIdentifier());
         } else {
             fail("both nodes imported");
         }
+        // behaviour for non-sibling conflicts: assign the new one a new UUID
+        referenceableNode = getNodeOrNull("/tmp/differentparentconflicts/referenceable/child");
+        duplicateNode = getNodeOrNull("/tmp/differentparentconflicts/duplicate/child");
+        assertNotNull(referenceableNode);
+        assertNotNull(duplicateNode);
+        assertTrue(referenceableNode.isNodeType(JcrConstants.MIX_REFERENCEABLE));
+        Set<String> uuids = new HashSet<>(Arrays.asList(referenceableNode.getIdentifier(), duplicateNode.getIdentifier()));
+        assertTrue(uuids.contains(UUID_REFERENCEABLE_CHILD)); // one must have kept the old id
+        assertEquals(2, uuids.size());
     }
 
     private Node getNodeOrNull(String path) throws RepositoryException {
diff --git a/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/differentparentconflicts/.content.xml b/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/differentparentconflicts/.content.xml
new file mode 100644
index 00000000..54084a82
--- /dev/null
+++ b/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/differentparentconflicts/.content.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
+    jcr:mixinTypes="[rep:AccessControllable]"
+    jcr:primaryType="sling:Folder"/>
diff --git a/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/duplicate.xml b/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/differentparentconflicts/duplicate.xml
similarity index 82%
copy from vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/duplicate.xml
copy to vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/differentparentconflicts/duplicate.xml
index 2d1995cd..99fbb46b 100644
--- a/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/duplicate.xml
+++ b/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/differentparentconflicts/duplicate.xml
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:vlt="http://www.day.com/jcr/vault/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
-    jcr:mixinTypes="[mix:referenceable,vlt:FullCoverage]"
     jcr:primaryType="sling:Folder"
-    jcr:uuid="352c89a4-304f-4b87-9bed-e09275597df1"
     someproperty="somevalue">
     <child
         jcr:mixinTypes="[mix:referenceable]"
diff --git a/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/referenceable.xml b/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/differentparentconflicts/referenceable.xml
similarity index 82%
copy from vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/referenceable.xml
copy to vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/differentparentconflicts/referenceable.xml
index 2d1995cd..99fbb46b 100644
--- a/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/referenceable.xml
+++ b/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/differentparentconflicts/referenceable.xml
@@ -1,8 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:vlt="http://www.day.com/jcr/vault/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:mix="http://www.jcp.org/jcr/mix/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
-    jcr:mixinTypes="[mix:referenceable,vlt:FullCoverage]"
     jcr:primaryType="sling:Folder"
-    jcr:uuid="352c89a4-304f-4b87-9bed-e09275597df1"
     someproperty="somevalue">
     <child
         jcr:mixinTypes="[mix:referenceable]"
diff --git a/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/duplicate.xml b/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/sameparentconflicts/duplicate.xml
similarity index 70%
rename from vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/duplicate.xml
rename to vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/sameparentconflicts/duplicate.xml
index 2d1995cd..9ed6059f 100644
--- a/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/duplicate.xml
+++ b/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/sameparentconflicts/duplicate.xml
@@ -4,9 +4,4 @@
     jcr:primaryType="sling:Folder"
     jcr:uuid="352c89a4-304f-4b87-9bed-e09275597df1"
     someproperty="somevalue">
-    <child
-        jcr:mixinTypes="[mix:referenceable]"
-        jcr:primaryType="nt:unstructured"
-        jcr:uuid="a201bd6b-25b9-4255-b7db-6fc4c3ddb32d"
-        someproperty="somevalue"/>
 </jcr:root>
diff --git a/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/referenceable.xml b/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/sameparentconflicts/referenceable.xml
similarity index 70%
rename from vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/referenceable.xml
rename to vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/sameparentconflicts/referenceable.xml
index 2d1995cd..9ed6059f 100644
--- a/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/referenceable.xml
+++ b/vault-core/src/test/resources/test-packages/referenceable-dup.zip/jcr_root/tmp/sameparentconflicts/referenceable.xml
@@ -4,9 +4,4 @@
     jcr:primaryType="sling:Folder"
     jcr:uuid="352c89a4-304f-4b87-9bed-e09275597df1"
     someproperty="somevalue">
-    <child
-        jcr:mixinTypes="[mix:referenceable]"
-        jcr:primaryType="nt:unstructured"
-        jcr:uuid="a201bd6b-25b9-4255-b7db-6fc4c3ddb32d"
-        someproperty="somevalue"/>
 </jcr:root>