From 37efdb2b09390ad426c40cac1270981ec8ecc622 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Sun, 7 Apr 2024 00:09:26 +0200 Subject: [PATCH 01/27] Extract and extend constraint check test cases --- .../01-MoveNodes_ConstraintChecks.feature | 225 ++++++++++++++++++ .../08-NodeMove/MoveNodeAggregate.feature | 155 ------------ 2 files changed, 225 insertions(+), 155 deletions(-) create mode 100644 Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/01-MoveNodes_ConstraintChecks.feature diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/01-MoveNodes_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/01-MoveNodes_ConstraintChecks.feature new file mode 100644 index 00000000000..26377560926 --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/01-MoveNodes_ConstraintChecks.feature @@ -0,0 +1,225 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Move node to a new parent / within the current parent before a sibling / to the end of the sibling list + + As a user of the CR I want to move a node to a new parent / within the current parent before a sibling / to the end of the sibling list, + without affecting other nodes in the node aggregate. + + These are the base test cases for the NodeAggregateCommandHandler to block invalid commands + + + Background: + Given using the following content dimensions: + | Identifier | Values | Generalizations | + | example | general, source, spec | spec->source->general | + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:Document': [] + 'Neos.ContentRepository.Testing:Content': + constraints: + nodeTypes: + '*': true + 'Neos.ContentRepository.Testing:Document': false + 'Neos.ContentRepository.Testing:DocumentWithTetheredChildNode': + childNodes: + tethered: + type: 'Neos.ContentRepository.Testing:Content' + constraints: + nodeTypes: + '*': true + 'Neos.ContentRepository.Testing:Content': false + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The live workspace" | + | newContentStreamId | "cs-identifier" | + And I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And the graph projection is fully up to date + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + And the graph projection is fully up to date + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | tetheredDescendantNodeAggregateIds | + | sir-david-nodenborough | {"example": "source"} | Neos.ContentRepository.Testing:DocumentWithTetheredChildNode | lady-eleonode-rootford | document | {"tethered": "nodewyn-tetherton"} | + | sir-nodeward-nodington-iii | {"example": "source"} | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | esquire | {} | + | anthony-destinode | {"example": "spec"} | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | target-document | {} | + + Scenario: Try to move a node in a non-existing workspace: + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | workspaceName | "non-existing" | + | nodeAggregateId | "sir-david-nodenborough" | + | dimensionSpacePoint | {"example": "source"} | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" + + Scenario: Try to move a node in a workspace whose content stream is closed: + When the command CloseContentStream is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | dimensionSpacePoint | {"example": "source"} | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "ContentStreamIsClosed" + + Scenario: Try to move a non-existing node aggregate: + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "i-do-not-exist" | + | dimensionSpacePoint | {"example": "source"} | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" + + Scenario: Try to move a root node aggregate: + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | dimensionSpacePoint | {"example": "source"} | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateIsRoot" + + Scenario: Try to move a node of a tethered node aggregate: + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "nodewyn-tetherton" | + | dimensionSpacePoint | {"example": "source"} | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateIsTethered" + + Scenario: Try to move a node in a non-existing dimension space point: + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | dimensionSpacePoint | {"example": "nope"} | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "DimensionSpacePointNotFound" + + Scenario: Try to move a node in a dimension space point the aggregate does not cover + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | dimensionSpacePoint | {"example": "general"} | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateDoesCurrentlyNotCoverDimensionSpacePoint" + + Scenario: Try to move a node to a non-existing parent + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | newParentNodeAggregateId | "non-existing-parent-identifier" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" + + Scenario: Using the scatter strategy, try to move a node to a new, existing parent in a dimension space point the new parent does not cover + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "anthony-destinode" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateDoesCurrentlyNotCoverDimensionSpacePointSet" + + Scenario: Using the gatherSpecializations strategy, try to move a node to a new, existing parent in a dimension space point with a specialization the new parent does not cover + # reduce coverage of the target + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + Then the last command should have thrown an exception of type "NodeAggregateDoesCurrentlyNotCoverDimensionSpacePointSet" + + Scenario: Using the gatherAll strategy, try to move a node to a new, existing parent in a dimension space point with a generalization the new parent does not cover + # increase coverage of the source + Given the command CreateNodeVariant is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | sourceOrigin | {"example": "source"} | + | targetOrigin | {"example": "general"} | + And the graph projection is fully up to date + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherAll" | + Then the last command should have thrown an exception of type "NodeAggregateDoesCurrentlyNotCoverDimensionSpacePointSet" + + Scenario: Try to move a node to a parent that already has a child node of the same name + Given the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | + | nody-mc-nodeface | {"example": "source"} | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | document | + + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "lady-eleonode-rootford" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" + + Scenario: Try to move a node to a parent whose node type does not allow child nodes of the node's type + Given the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | + | nody-mc-nodeface | {"example": "source"} | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | other-document | + + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "nodewyn-tetherton" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeConstraintException" + + Scenario: Try to move a node to a parent whose parent's node type does not allow grand child nodes of the node's type + Given the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | + | nody-mc-nodeface | {"example": "source"} | Neos.ContentRepository.Testing:Content | lady-eleonode-rootford | content | + + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "nodewyn-tetherton" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeConstraintException" + + Scenario: Try to move existing node to a non-existing preceding sibling + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "i-do-not-exist" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" + + Scenario: Try to move existing node to a non-existing succeeding sibling + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "i-do-not-exist" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" + + Scenario: Try to move a node to one of its children + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "sir-david-nodenborough" | + | newParentNodeAggregateId | "nodewyn-tetherton" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateIsDescendant" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate.feature index 5dd2d441fa8..7401c2829fa 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate.feature @@ -80,95 +80,6 @@ Feature: Move node to a new parent / within the current parent before a sibling | nodeAggregateClassification | "regular" | And the graph projection is fully up to date - Scenario: Try to move a node in a non-existing workspace: - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | workspaceName | "non-existing" | - | nodeAggregateId | "sir-david-nodenborough" | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "ContentStreamDoesNotExistYet" - - Scenario: Try to move a node in a workspace whose content stream is closed: - When the command CloseContentStream is executed with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | nodeAggregateId | "sir-david-nodenborough" | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "ContentStreamIsClosed" - - Scenario: Try to move a node of a non-existing node aggregate: - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | nodeAggregateId | "i-do-not-exist" | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" - - Scenario: Try to move a node of a root node aggregate: - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | nodeAggregateId | "lady-eleonode-rootford" | - | dimensionSpacePoint | {"market":"DE", "language":"de"} | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeAggregateIsRoot" - - Scenario: Try to move a node of a tethered node aggregate: - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | nodeAggregateId | "nodewyn-tetherton" | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeAggregateIsTethered" - - Scenario: Try to move a node in a non-existing dimension space point: - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | nodeAggregateId | "sir-david-nodenborough" | - | dimensionSpacePoint | {"market": "nope", "language": "neither"} | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "DimensionSpacePointNotFound" - - Scenario: Try to move a node in a dimension space point the aggregate does not cover - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | nodeAggregateId | "sir-david-nodenborough" | - | dimensionSpacePoint | {"market": "DE", "language": "fr"} | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeAggregateDoesCurrentlyNotCoverDimensionSpacePoint" - - Scenario: Try to move existing node to a non-existing parent - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "sir-david-nodenborough" | - | newParentNodeAggregateId | "non-existing-parent-identifier" | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" - - Scenario: Try to move a node to a parent that already has a child node of the same name - Given the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"market": "DE", "language": "de"} | - | coveredDimensionSpacePoints | [{"market": "DE", "language": "de"}, {"market": "DE", "language": "gsw"}, {"market": "CH", "language": "de"}, {"market": "CH", "language": "gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "document" | - | nodeAggregateClassification | "regular" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "nody-mc-nodeface" | - | newParentNodeAggregateId | "lady-eleonode-rootford" | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" Scenario: Move a node that has no name Given the event NodeAggregateWithNodeWasCreated was published with payload: @@ -193,70 +104,4 @@ Feature: Move node to a new parent / within the current parent before a sibling And I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE","language":"de"} - Scenario: Try to move a node to a parent whose node type does not allow child nodes of the node's type - Given the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"market": "DE", "language": "de"} | - | coveredDimensionSpacePoints | [{"market": "DE", "language": "de"}, {"market": "DE", "language": "gsw"}, {"market": "CH", "language": "de"}, {"market": "CH", "language": "gsw"}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "other-document" | - | nodeAggregateClassification | "regular" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "nody-mc-nodeface" | - | newParentNodeAggregateId | "nodewyn-tetherton" | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeConstraintException" - - Scenario: Try to move a node to a parent whose parent's node type does not allow grand child nodes of the node's type - Given the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Content" | - | originDimensionSpacePoint | {"market": "DE", "language": "de"} | - | coveredDimensionSpacePoints | [{"market": "DE", "language": "de"}, {"market": "DE", "language": "gsw"}, {"market": "CH", "language": "de"}, {"market": "CH", "language": "gsw"}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "content" | - | nodeAggregateClassification | "regular" | - And the graph projection is fully up to date - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "nody-mc-nodeface" | - | newParentNodeAggregateId | "nodewyn-tetherton" | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeConstraintException" - - Scenario: Try to move existing node to a non-existing succeeding sibling - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "sir-david-nodenborough" | - | newSucceedingSiblingNodeAggregateId | "i-do-not-exist" | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" - - Scenario: Try to move existing node to a non-existing preceding sibling - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "sir-david-nodenborough" | - | newPrecedingSiblingNodeAggregateId | "i-do-not-exist" | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" - Scenario: Try to move a node to one of its children - When the command MoveNodeAggregate is executed with payload and exceptions are caught: - | Key | Value | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "sir-david-nodenborough" | - | newParentNodeAggregateId | "nodewyn-tetherton" | - | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeAggregateIsDescendant" From a61000358f1aabe6b8fd8da3df115e5ccbf6b6e1 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Sun, 7 Apr 2024 00:31:02 +0200 Subject: [PATCH 02/27] Refactor MoveNodeAggregate - new parent test suite from events to commands --- ...odeAggregate_NewParent_Dimensions.feature} | 145 ++++++------------ .../08-NodeMove/MoveNodeAggregate.feature | 107 ------------- 2 files changed, 47 insertions(+), 205 deletions(-) rename Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/{MoveNodeAggregate_NewParent_Dimensions.feature => 02-MoveNodeAggregate_NewParent_Dimensions.feature} (69%) delete mode 100644 Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate.feature diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NewParent_Dimensions.feature similarity index 69% rename from Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NewParent_Dimensions.feature rename to Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NewParent_Dimensions.feature index e2791f32b28..16fa582f5af 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NewParent_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NewParent_Dimensions.feature @@ -25,88 +25,26 @@ Feature: Move a node with content dimensions | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in the active content stream of workspace "live" + And I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "document" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "anthony-destinode" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "child-document-a" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "berta-destinode" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "child-document-b" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "carl-destinode" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "child-document-c" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "esquire" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "sir-nodeward-nodington-iii" | - | nodeName | "child-document-n" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "lady-abigail-nodenborough" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "document2" | - | nodeAggregateClassification | "regular" | And the graph projection is fully up to date + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | + | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | document | + | anthony-destinode | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | child-document-a | + | berta-destinode | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | child-document-b | + | carl-destinode | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | child-document-c | + | sir-nodeward-nodington-iii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | esquire | + | nody-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | child-document-n | + | lady-abigail-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | document2 | Scenario: Move a complete node aggregate to a new parent before the first of its new siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | "anthony-destinode" | And the graph projection is fully up to date @@ -122,18 +60,16 @@ Feature: Move a node with content dimensions | cs-identifier;carl-destinode;{"language": "mul"} | Scenario: Move a complete node aggregate to a new parent before the first of its new siblings - which does not exist in all variants - Given the event NodeAggregateWasRemoved was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "anthony-destinode" | - | affectedOccupiedDimensionSpacePoints | [] | - | affectedCoveredDimensionSpacePoints | [{"language": "gsw"}] | + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "anthony-destinode" | + | coveredDimensionSpacePoint | {"language": "gsw"} | + | nodeVariantSelectionStrategy | "allSpecializations" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | "anthony-destinode" | | relationDistributionStrategy | "gatherAll" | @@ -179,18 +115,16 @@ Feature: Move a node with content dimensions | cs-identifier;carl-destinode;{"language": "mul"} | Scenario: Move a complete node aggregate to a new parent before one of its siblings - which does not exist in all variants - Given the event NodeAggregateWasRemoved was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "berta-destinode" | - | affectedOccupiedDimensionSpacePoints | [] | - | affectedCoveredDimensionSpacePoints | [{"language": "gsw"}] | + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "berta-destinode" | + | coveredDimensionSpacePoint | {"language": "gsw"} | + | nodeVariantSelectionStrategy | "allSpecializations" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | "berta-destinode" | And the graph projection is fully up to date @@ -217,12 +151,11 @@ Feature: Move a node with content dimensions | cs-identifier;carl-destinode;{"language": "mul"} | Scenario: Move a complete node aggregate to a new parent after another of its new siblings - which does not exist in all variants - Given the event NodeAggregateWasRemoved was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "carl-destinode" | - | affectedOccupiedDimensionSpacePoints | [] | - | affectedCoveredDimensionSpacePoints | [{"language": "gsw"}] | + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "carl-destinode" | + | coveredDimensionSpacePoint | {"language": "gsw"} | + | nodeVariantSelectionStrategy | "allSpecializations" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: @@ -254,12 +187,11 @@ Feature: Move a node with content dimensions And I expect this node to have no succeeding siblings Scenario: Move a complete node aggregate to a new parent after the last of its new siblings - with a predecessor which does not exist in all variants - Given the event NodeAggregateWasRemoved was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "carl-destinode" | - | affectedOccupiedDimensionSpacePoints | [] | - | affectedCoveredDimensionSpacePoints | [{"language": "gsw"}] | + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "carl-destinode" | + | coveredDimensionSpacePoint | {"language": "gsw"} | + | nodeVariantSelectionStrategy | "allSpecializations" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: @@ -430,3 +362,20 @@ Feature: Move a node with content dimensions And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;berta-destinode;{"language": "mul"} | + + Scenario: Move a node that has no name + Given the command CreateNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface-ii" | + | nodeTypeName | "Neos.ContentRepository.Testing:Document" | + | parentNodeAggregateId | "sir-david-nodenborough" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface-ii" | + | newParentNodeAggregateId | "lady-eleonode-rootford" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} + And I expect node aggregate identifier "nody-mc-nodeface-ii" to lead to node cs-identifier;nody-mc-nodeface-ii;{"language": "mul"} diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate.feature deleted file mode 100644 index 7401c2829fa..00000000000 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate.feature +++ /dev/null @@ -1,107 +0,0 @@ -@contentrepository @adapters=DoctrineDBAL -Feature: Move node to a new parent / within the current parent before a sibling / to the end of the sibling list - - As a user of the CR I want to move a node to a new parent / within the current parent before a sibling / to the end of the sibling list, - without affecting other nodes in the node aggregate. - - These are the base test cases for the NodeAggregateCommandHandler to block invalid commands - - Content Structure: - - lady-eleonode-rootford (Neos.ContentRepository:Root) - - sir-david-nodenborough (Neos.ContentRepository.Testing:DocumentWithTetheredChildNode) - - "tethered" nodewyn-tetherton (Neos.ContentRepository.Testing:Content) - - sir-nodeward-nodington-iii (Neos.ContentRepository.Testing:Document) - - Background: - Given using the following content dimensions: - | Identifier | Values | Generalizations | - | market | DE, CH | CH->DE | - | language | de, gsw, fr | gsw->de | - And using the following node types: - """yaml - 'Neos.ContentRepository.Testing:Document': [] - 'Neos.ContentRepository.Testing:Content': - constraints: - nodeTypes: - '*': true - 'Neos.ContentRepository.Testing:Document': false - 'Neos.ContentRepository.Testing:DocumentWithTetheredChildNode': - childNodes: - tethered: - type: 'Neos.ContentRepository.Testing:Content' - constraints: - nodeTypes: - '*': true - 'Neos.ContentRepository.Testing:Content': false - """ - And using identifier "default", I define a content repository - And I am in content repository "default" - And the command CreateRootWorkspace is executed with payload: - | Key | Value | - | workspaceName | "live" | - | workspaceTitle | "Live" | - | workspaceDescription | "The live workspace" | - | newContentStreamId | "cs-identifier" | - And I am in the active content stream of workspace "live" - And the graph projection is fully up to date - And the command CreateRootNodeAggregateWithNode is executed with payload: - | Key | Value | - | nodeAggregateId | "lady-eleonode-rootford" | - | nodeTypeName | "Neos.ContentRepository:Root" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | nodeTypeName | "Neos.ContentRepository.Testing:DocumentWithTetheredChildNode" | - | originDimensionSpacePoint | {"market":"DE", "language":"de"} | - | coveredDimensionSpacePoints | [{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "document" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nodewyn-tetherton" | - | nodeTypeName | "Neos.ContentRepository.Testing:Content" | - | originDimensionSpacePoint | {"market":"DE", "language":"de"} | - | coveredDimensionSpacePoints | [{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "tethered" | - | nodeAggregateClassification | "tethered" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"market":"DE", "language":"de"} | - | coveredDimensionSpacePoints | [{"market":"DE", "language":"de"},{"market":"DE", "language":"gsw"},{"market":"CH", "language":"de"},{"market":"CH", "language":"gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "esquire" | - | nodeAggregateClassification | "regular" | - And the graph projection is fully up to date - - - Scenario: Move a node that has no name - Given the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"market": "DE", "language": "de"} | - | coveredDimensionSpacePoints | [{"market": "DE", "language": "de"}, {"market": "DE", "language": "gsw"}, {"market": "CH", "language": "de"}, {"market": "CH", "language": "gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeAggregateClassification | "regular" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | dimensionSpacePoint | {"market": "DE", "language": "de"} | - | nodeAggregateId | "nody-mc-nodeface" | - | newParentNodeAggregateId | "lady-eleonode-rootford" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"market": "DE", "language": "de"} - And I expect node aggregate identifier "nody-mc-nodeface" to lead to node cs-identifier;nody-mc-nodeface;{"market":"DE","language":"de"} - - - From 63e6813e0ab034ce89300624c59b051c9eb2ed97 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 8 Apr 2024 00:44:33 +0200 Subject: [PATCH 03/27] WIP Add extensive (failing) test suite for MoveNode without a new parent --- ...deAggregate_NoNewParent_Dimensions.feature | 2224 +++++++++++++++++ ...odeAggregate_NewParent_Dimensions.feature} | 0 ...deAggregate_NoNewParent_Dimensions.feature | 573 ----- 3 files changed, 2224 insertions(+), 573 deletions(-) create mode 100644 Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NoNewParent_Dimensions.feature rename Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/{02-MoveNodeAggregate_NewParent_Dimensions.feature => 03-MoveNodeAggregate_NewParent_Dimensions.feature} (100%) delete mode 100644 Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NoNewParent_Dimensions.feature diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NoNewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NoNewParent_Dimensions.feature new file mode 100644 index 00000000000..bf97db53f9a --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NoNewParent_Dimensions.feature @@ -0,0 +1,2224 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Move a node with content dimensions + + As a user of the CR I want to move a node + - before the first of its siblings + - between two of its siblings + - after the last of its siblings + + These are the test cases for moving nodes with content dimensions being involved, which is a lot more fun! + + Background: + Given using the following content dimensions: + | Identifier | Values | Generalizations | + | example | general, source, peer, spec | spec->source->general, peer->general | + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:Document': [] + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The live workspace" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | + | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | document | + | eldest-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | child-document-a | + | elder-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | child-document-b | + | nody-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | child-document-n | + | younger-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | child-document-c | + | youngest-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | child-document-d | + + # Test cases for the gatherAll strategy + + Scenario: Move a complete node aggregate before the first of its siblings + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate before the first of its siblings, which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate before a siblings which is partially the first + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate before one of its siblings, which is not the first + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate before one of its siblings, which is not the first and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "elder-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate before one of its siblings, which is the last and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "youngest-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate after the last of its siblings + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + Scenario: Move a complete node aggregate after the last of its siblings, which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + Scenario: Move a complete node aggregate after one of its siblings, which is partially the last + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate after one of its siblings, which is not the last + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate after one of its siblings, which is not the last and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "younger-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate after one of its siblings, which is the first and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + # Test cases for the gatherSpecializations strategy + + Scenario: Move a node and its specialization variants before the first of its siblings + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a node and its specialization variants before the first of its siblings, which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a node and its specialization variants before a siblings which is partially the first + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a node and its specialization variants before one of its siblings, which is not the first + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a node and its specialization variants before one of its siblings, which is not the first and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "elder-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a node and its specialization variants before one of its siblings, which is the last and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "youngest-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a node and its specialization variants after the last of its siblings + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a node and its specialization variants after the last of its siblings, which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a node and its specialization variants after one of its siblings, which is partially the last + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a node and its specialization variants after one of its siblings, which is not the last + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a node and its specialization variants after one of its siblings, which is not the last and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "younger-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a node and its specialization variants after one of its siblings, which is the first and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + # Test cases for the scatter strategy + + Scenario: Move a single node before the first of its siblings + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a single node before the first of its siblings, which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a single node before a siblings which is partially the first + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a single node before one of its siblings, which is not the first + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a single node before one of its siblings, which is not the first and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "elder-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a single node before one of its siblings, which is the last and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "youngest-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a single node after the last of its siblings + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a single node after the last of its siblings, which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a single node after one of its siblings, which is partially the last + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a single node after one of its siblings, which is not the last + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a single node after one of its siblings, which is not the last and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "younger-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a single node after one of its siblings, which is the first and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no succeeding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature similarity index 100% rename from Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NewParent_Dimensions.feature rename to Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NoNewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NoNewParent_Dimensions.feature deleted file mode 100644 index fa4d0a3467f..00000000000 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregate_NoNewParent_Dimensions.feature +++ /dev/null @@ -1,573 +0,0 @@ -@contentrepository @adapters=DoctrineDBAL -Feature: Move a node with content dimensions - - As a user of the CR I want to move a node - - before the first of its siblings - - between two of its siblings - - after the last of its siblings - - These are the test cases for moving nodes with content dimensions being involved, which is a lot more fun! - - Background: - Given using the following content dimensions: - | Identifier | Values | Generalizations | - | language | mul, de, en, gsw | gsw->de->mul, en->mul | - And using the following node types: - """yaml - 'Neos.ContentRepository.Testing:Document': [] - """ - And using identifier "default", I define a content repository - And I am in content repository "default" - And the command CreateRootWorkspace is executed with payload: - | Key | Value | - | workspaceName | "live" | - | workspaceTitle | "Live" | - | workspaceDescription | "The live workspace" | - | newContentStreamId | "cs-identifier" | - And the graph projection is fully up to date - And I am in the active content stream of workspace "live" - And the command CreateRootNodeAggregateWithNode is executed with payload: - | Key | Value | - | nodeAggregateId | "lady-eleonode-rootford" | - | nodeTypeName | "Neos.ContentRepository:Root" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "document" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "anthony-destinode" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "child-document-a" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "berta-destinode" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "child-document-b" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "child-document-n" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "carl-destinode" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "child-document-c" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {"language": "mul"} | - | coveredDimensionSpacePoints | [{"language": "mul"}, {"language": "de"}, {"language": "en"}, {"language": "gsw"}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "esquire" | - | nodeAggregateClassification | "regular" | - And the graph projection is fully up to date - - Scenario: Move a complete node aggregate before the first of its siblings - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | "anthony-destinode" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have no preceding siblings - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | - - Scenario: Move a complete node aggregate before the first of its siblings - which does not exist in all variants - Given the event NodeAggregateWasRemoved was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "anthony-destinode" | - | affectedOccupiedDimensionSpacePoints | [] | - | affectedCoveredDimensionSpacePoints | [{"language": "gsw"}] | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | "anthony-destinode" | - | relationDistributionStrategy | "gatherAll" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have no preceding siblings - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | - - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have no preceding siblings - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | - - Scenario: Move a complete node aggregate before another of its siblings - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | "berta-destinode" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | - - Scenario: Move a complete node aggregate before another of its siblings - which does not exist in all variants - Given the event NodeAggregateWasRemoved was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "berta-destinode" | - | affectedOccupiedDimensionSpacePoints | [] | - | affectedCoveredDimensionSpacePoints | [{"language": "gsw"}] | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | "berta-destinode" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | - - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - - Scenario: Move a complete node aggregate after another of its siblings - which does not exist in all variants - Given the event NodeAggregateWasRemoved was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "carl-destinode" | - | affectedOccupiedDimensionSpacePoints | [] | - | affectedCoveredDimensionSpacePoints | [{"language": "gsw"}] | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | - | newParentNodeAggregateId | null | - | newPrecedingSiblingNodeAggregateId | "berta-destinode" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have no succeeding siblings - - Scenario: Move a complete node aggregate after the last of its siblings - with a predecessor which does not exist in all variants - Given the event NodeAggregateWasRemoved was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "carl-destinode" | - | affectedOccupiedDimensionSpacePoints | [] | - | affectedCoveredDimensionSpacePoints | [{"language": "gsw"}] | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have no succeeding siblings - - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have no succeeding siblings - - Scenario: Move a single node before the first of its siblings - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | - | newSucceedingSiblingNodeAggregateId | "anthony-destinode" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have no preceding siblings - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | - - When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - - Scenario: Move a single node between two of its siblings - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | - | newSucceedingSiblingNodeAggregateId | "berta-destinode" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | - - When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - - Scenario: Move a single node to the end of its siblings - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have no succeeding siblings - - When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - - Scenario: Move a node and its specializations before the first of its siblings - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "de"} | - | newSucceedingSiblingNodeAggregateId | "anthony-destinode" | - | relationDistributionStrategy | "gatherSpecializations" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - - When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have no preceding siblings - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | - - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have no preceding siblings - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | - - Scenario: Move a node and its specializations between two of its siblings - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "de"} | - | newSucceedingSiblingNodeAggregateId | "berta-destinode" | - | relationDistributionStrategy | "gatherSpecializations" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - - When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | - - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | - - Scenario: Move a node and its specializations to the end of its siblings - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "de"} | - | relationDistributionStrategy | "gatherSpecializations" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - - When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have no succeeding siblings - - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have no succeeding siblings - - Scenario: Trigger position update in DBAL graph - Given I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - # distance i to x: 128 - Given the following CreateNodeAggregateWithNode commands are executed: - | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | - | lady-nodette-nodington-i | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-i | - | lady-nodette-nodington-x | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-x | - | lady-nodette-nodington-ix | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-ix | - | lady-nodette-nodington-viii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-viii | - | lady-nodette-nodington-vii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-vii | - | lady-nodette-nodington-vi | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-vi | - | lady-nodette-nodington-v | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-v | - | lady-nodette-nodington-iv | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-iv | - | lady-nodette-nodington-iii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-iii | - | lady-nodette-nodington-ii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-ii | - # distance ii to x: 64 - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "lady-nodette-nodington-ii" | - | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | - And the graph projection is fully up to date - # distance iii to x: 32 - And the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "lady-nodette-nodington-iii" | - | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | - And the graph projection is fully up to date - # distance iv to x: 16 - And the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "lady-nodette-nodington-iv" | - | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | - And the graph projection is fully up to date - # distance v to x: 8 - And the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "lady-nodette-nodington-v" | - | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | - And the graph projection is fully up to date - # distance vi to x: 4 - And the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "lady-nodette-nodington-vi" | - | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | - And the graph projection is fully up to date - # distance vii to x: 2 - And the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "lady-nodette-nodington-vii" | - | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | - And the graph projection is fully up to date - # distance viii to x: 1 -> reorder -> 128 - And the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "lady-nodette-nodington-viii" | - | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | - And the graph projection is fully up to date - # distance ix to x: 64 after reorder - And the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "lady-nodette-nodington-ix" | - | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | - And the graph projection is fully up to date - - Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} - And I expect this node to have the following child nodes: - | Name | NodeDiscriminator | - | document | cs-identifier;sir-david-nodenborough;{"language": "mul"} | - | esquire | cs-identifier;sir-nodeward-nodington-iii;{"language": "mul"} | - | nodington-i | cs-identifier;lady-nodette-nodington-i;{"language": "mul"} | - | nodington-ii | cs-identifier;lady-nodette-nodington-ii;{"language": "mul"} | - | nodington-iii | cs-identifier;lady-nodette-nodington-iii;{"language": "mul"} | - | nodington-iv | cs-identifier;lady-nodette-nodington-iv;{"language": "mul"} | - | nodington-v | cs-identifier;lady-nodette-nodington-v;{"language": "mul"} | - | nodington-vi | cs-identifier;lady-nodette-nodington-vi;{"language": "mul"} | - | nodington-vii | cs-identifier;lady-nodette-nodington-vii;{"language": "mul"} | - | nodington-viii | cs-identifier;lady-nodette-nodington-viii;{"language": "mul"} | - | nodington-ix | cs-identifier;lady-nodette-nodington-ix;{"language": "mul"} | - | nodington-x | cs-identifier;lady-nodette-nodington-x;{"language": "mul"} | - - From 6ca7fc2b3e5178a11e13fc0e1b9aa1bee06cac9b Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 8 Apr 2024 00:44:57 +0200 Subject: [PATCH 04/27] Move SiblingPositions test cases to DoctrineDbal adapter --- .../Projection/SiblingPositions.feature | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/SiblingPositions.feature diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/SiblingPositions.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/SiblingPositions.feature new file mode 100644 index 00000000000..f8a1f8d864f --- /dev/null +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/SiblingPositions.feature @@ -0,0 +1,111 @@ +@contentrepository +Feature: Sibling positions are properly resolved + + In the general DBAL adapter, hierarchy relations are sorted by an integer field. It defaults to a distance of 128, + which is reduced each time a node is inserted between two siblings. Once the number becomes uneven, the siblings positions are recalculated. + These are the test cases for this behavior. + + Background: + Given using the following content dimensions: + | Identifier | Values | Generalizations | + | example | general, source, peer, spec | spec->source->general, peer->general | + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:Document': [] + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The live workspace" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | + | sir-nodeward-nodington-iii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | esquire | + | lady-nodette-nodington-i | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-i | + | lady-nodette-nodington-x | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-x | + | lady-nodette-nodington-ix | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-ix | + | lady-nodette-nodington-viii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-viii | + | lady-nodette-nodington-vii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-vii | + | lady-nodette-nodington-vi | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-vi | + | lady-nodette-nodington-v | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-v | + | lady-nodette-nodington-iv | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-iv | + | lady-nodette-nodington-iii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-iii | + | lady-nodette-nodington-ii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | nodington-ii | + + + Scenario: Trigger position update in DBAL graph + Given I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + # distance i to x: 128 + # distance ii to x: 64 + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-nodette-nodington-ii" | + | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | + And the graph projection is fully up to date + # distance iii to x: 32 + And the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-nodette-nodington-iii" | + | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | + And the graph projection is fully up to date + # distance iv to x: 16 + And the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-nodette-nodington-iv" | + | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | + And the graph projection is fully up to date + # distance v to x: 8 + And the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-nodette-nodington-v" | + | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | + And the graph projection is fully up to date + # distance vi to x: 4 + And the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-nodette-nodington-vi" | + | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | + And the graph projection is fully up to date + # distance vii to x: 2 + And the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-nodette-nodington-vii" | + | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | + And the graph projection is fully up to date + # distance viii to x: 1 -> reorder -> 128 + And the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-nodette-nodington-viii" | + | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | + And the graph projection is fully up to date + # distance ix to x: 64 after reorder + And the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-nodette-nodington-ix" | + | newSucceedingSiblingNodeAggregateId | "lady-nodette-nodington-x" | + And the graph projection is fully up to date + + Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} + And I expect this node to have the following child nodes: + | Name | NodeDiscriminator | + | document | cs-identifier;sir-david-nodenborough;{"example": "general"} | + | esquire | cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} | + | nodington-i | cs-identifier;lady-nodette-nodington-i;{"example": "general"} | + | nodington-ii | cs-identifier;lady-nodette-nodington-ii;{"example": "general"} | + | nodington-iii | cs-identifier;lady-nodette-nodington-iii;{"example": "general"} | + | nodington-iv | cs-identifier;lady-nodette-nodington-iv;{"example": "general"} | + | nodington-v | cs-identifier;lady-nodette-nodington-v;{"example": "general"} | + | nodington-vi | cs-identifier;lady-nodette-nodington-vi;{"example": "general"} | + | nodington-vii | cs-identifier;lady-nodette-nodington-vii;{"example": "general"} | + | nodington-viii | cs-identifier;lady-nodette-nodington-viii;{"example": "general"} | + | nodington-ix | cs-identifier;lady-nodette-nodington-ix;{"example": "general"} | + | nodington-x | cs-identifier;lady-nodette-nodington-x;{"example": "general"} | From eb44fa38a6dc51ae6b4787df19262a48b59021b3 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Wed, 10 Apr 2024 00:14:55 +0200 Subject: [PATCH 05/27] WIP: Introduce comprehensive test suite for moving to a new parent ... without prior distribution of siblings among different parents --- ...NodeAggregate_NewParent_Dimensions.feature | 2344 +++++++++++++++-- ...egate_ImplicitNewParent_Dimensions.feature | 5 + 2 files changed, 2167 insertions(+), 182 deletions(-) create mode 100644 Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ImplicitNewParent_Dimensions.feature diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature index 16fa582f5af..4595c23e481 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature @@ -10,8 +10,8 @@ Feature: Move a node with content dimensions Background: Given using the following content dimensions: - | Identifier | Values | Generalizations | - | language | mul, de, en, gsw | gsw->de->mul, en->mul | + | Identifier | Values | Generalizations | + | language | general, source, peer, gsw | gsw->source->general, peer->general | And using the following node types: """yaml 'Neos.ContentRepository.Testing:Document': [] @@ -25,100 +25,267 @@ Feature: Move a node with content dimensions | workspaceDescription | "The live workspace" | | newContentStreamId | "cs-identifier" | And the graph projection is fully up to date - And I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} + And I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And the command CreateRootNodeAggregateWithNode is executed with payload: | Key | Value | | nodeAggregateId | "lady-eleonode-rootford" | | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date And the following CreateNodeAggregateWithNode commands are executed: - | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | - | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | document | - | anthony-destinode | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | child-document-a | - | berta-destinode | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | child-document-b | - | carl-destinode | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | child-document-c | - | sir-nodeward-nodington-iii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | esquire | - | nody-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | child-document-n | - | lady-abigail-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | document2 | + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | + | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | parent-document | + | eldest-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | eldest-document | + | elder-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | elder-document | + | younger-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | younger-document | + | youngest-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | youngest-document | + | sir-nodeward-nodington-iii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | esquire | + | source-elder-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | elder-document | + | nody-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | document | + | source-younger-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | younger-document | + | bustling-mc-nodeface | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | bustling-document | + + # Test cases for the gatherAll strategy Scenario: Move a complete node aggregate to a new parent before the first of its new siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | | newParentNodeAggregateId | "sir-david-nodenborough" | - | newSucceedingSiblingNodeAggregateId | "anthony-destinode" | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have no preceding siblings And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | Scenario: Move a complete node aggregate to a new parent before the first of its new siblings - which does not exist in all variants Given the command RemoveNodeAggregate is executed with payload: | Key | Value | - | nodeAggregateId | "anthony-destinode" | - | coveredDimensionSpacePoint | {"language": "gsw"} | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | | nodeVariantSelectionStrategy | "allSpecializations" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | | newParentNodeAggregateId | "sir-david-nodenborough" | - | newSucceedingSiblingNodeAggregateId | "anthony-destinode" | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have no preceding siblings And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before a siblings which is partially the first + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have no preceding siblings And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent before one of its new siblings + Scenario: Move a complete node aggregate to a new parent before one of its new siblings, which is not the first When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | + | dimensionSpacePoint | {"example": "general"} | | newParentNodeAggregateId | "sir-david-nodenborough" | - | newSucceedingSiblingNodeAggregateId | "berta-destinode" | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent before one of its siblings - which does not exist in all variants + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before one of its siblings, which is not the first and does not exist in all variants Given the command RemoveNodeAggregate is executed with payload: | Key | Value | - | nodeAggregateId | "berta-destinode" | - | coveredDimensionSpacePoint | {"language": "gsw"} | + | nodeAggregateId | "elder-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | | nodeVariantSelectionStrategy | "allSpecializations" | And the graph projection is fully up to date @@ -126,242 +293,2055 @@ Feature: Move a node with content dimensions | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | | newParentNodeAggregateId | "sir-david-nodenborough" | - | newSucceedingSiblingNodeAggregateId | "berta-destinode" | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent after another of its new siblings - which does not exist in all variants + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before one of its siblings, which is the last and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "youngest-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after the last of its siblings + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + Scenario: Move a complete node aggregate to a new parent after the last of its siblings, which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is partially the last + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is not the last + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is not the last and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "younger-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is the first and does not exist in all variants Given the command RemoveNodeAggregate is executed with payload: | Key | Value | - | nodeAggregateId | "carl-destinode" | - | coveredDimensionSpacePoint | {"language": "gsw"} | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | | nodeVariantSelectionStrategy | "allSpecializations" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | + | dimensionSpacePoint | {"example": "source"} | | newParentNodeAggregateId | "sir-david-nodenborough" | - | newPrecedingSiblingNodeAggregateId | "berta-destinode" | + | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | - And I expect this node to have no succeeding siblings + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent after the last of its new siblings - with a predecessor which does not exist in all variants + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + # Test cases for the gatherSpecializations strategy + + Scenario: Move a complete node aggregate to a new parent before the first of its new siblings + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before the first of its new siblings - which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before a siblings which is partially the first Given the command RemoveNodeAggregate is executed with payload: | Key | Value | - | nodeAggregateId | "carl-destinode" | - | coveredDimensionSpacePoint | {"language": "gsw"} | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | | nodeVariantSelectionStrategy | "allSpecializations" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before one of its new siblings, which is not the first + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "general"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before one of its siblings, which is not the first and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "elder-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before one of its siblings, which is the last and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "youngest-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after the last of its siblings + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after the last of its siblings, which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is partially the last + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is not the last + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is not the last and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "younger-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is the first and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + # Test cases for the scatter strategy + + Scenario: Move a complete node aggregate to a new parent before the first of its new siblings + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before the first of its new siblings - which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before a siblings which is partially the first + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before one of its new siblings, which is not the first + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "general"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before one of its siblings, which is not the first and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "elder-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent before one of its siblings, which is the last and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "youngest-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after the last of its siblings + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after the last of its siblings, which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is partially the last + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "youngest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is not the last + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is not the last and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "younger-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is the first and does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + # Legacy test cases + + Scenario: Move a complete node aggregate to a new parent after another of its new siblings - which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "younger-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "general"} | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "elder-mc-nodeface" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings + + Scenario: Move a complete node aggregate to a new parent after the last of its new siblings - with a predecessor which does not exist in all variants + Given the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "younger-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "general"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | null | And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have no succeeding siblings - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have no succeeding siblings Scenario: Move a single node in a node aggregate to a new parent after the last of its new siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "de"} | + | dimensionSpacePoint | {"example": "source"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | null | | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have no preceding siblings And I expect this node to have no succeeding siblings - When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have no succeeding siblings Scenario: Move a node and its specializations in a node aggregate to a new parent after the last of its new siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "de"} | + | dimensionSpacePoint | {"example": "source"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | null | | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have no preceding siblings And I expect this node to have no succeeding siblings - When I am in the active content stream of workspace "live" and dimension space point {"language": "de"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have no succeeding siblings - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;anthony-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have no succeeding siblings Scenario: Move a complete node aggregate to a new parent between siblings with different parents in other variants Given the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "berta-destinode" | - | dimensionSpacePoint | {"language": "gsw"} | - | newParentNodeAggregateId | "lady-abigail-nodenborough" | - | newSucceedingSiblingNodeAggregateId | null | - | relationDistributionStrategy | "scatter" | + | Key | Value | + | nodeAggregateId | "elder-mc-nodeface" | + | dimensionSpacePoint | {"example": "spec"} | + | newParentNodeAggregateId | "bustling-mc-nodeface" | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | + | dimensionSpacePoint | {"example": "general"} | | newParentNodeAggregateId | "sir-david-nodenborough" | - | newPrecedingSiblingNodeAggregateId | "anthony-destinode" | - | newSucceedingSiblingNodeAggregateId | "berta-destinode" | + | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | # An explicitly given parent node aggregate identifier should overrule given sibling identifiers - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;carl-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | Scenario: Move a complete node aggregate between siblings with different parents in other variants (without explicit new parent) Given the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "berta-destinode" | - | dimensionSpacePoint | {"language": "gsw"} | - | newParentNodeAggregateId | "lady-abigail-nodenborough" | - | newSucceedingSiblingNodeAggregateId | null | - | relationDistributionStrategy | "scatter" | + | Key | Value | + | nodeAggregateId | "elder-mc-nodeface" | + | dimensionSpacePoint | {"example": "spec"} | + | newParentNodeAggregateId | "bustling-mc-nodeface" | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"language": "mul"} | - | newPrecedingSiblingNodeAggregateId | "anthony-destinode" | - | newSucceedingSiblingNodeAggregateId | "berta-destinode" | - | relationDistributionStrategy | "gatherAll" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "general"} | + | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;anthony-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | - | cs-identifier;carl-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"language": "gsw"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "document2/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"language": "mul"} - And I expect this node to be a child of node cs-identifier;lady-abigail-nodenborough;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "bustling-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;bustling-mc-nodeface;{"example": "general"} And I expect this node to have no preceding siblings And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;berta-destinode;{"language": "mul"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | Scenario: Move a node that has no name Given the command CreateNodeAggregateWithNode is executed with payload: @@ -377,5 +2357,5 @@ Feature: Move a node with content dimensions | newParentNodeAggregateId | "lady-eleonode-rootford" | | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"language": "mul"} - And I expect node aggregate identifier "nody-mc-nodeface-ii" to lead to node cs-identifier;nody-mc-nodeface-ii;{"language": "mul"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And I expect node aggregate identifier "nody-mc-nodeface-ii" to lead to node cs-identifier;nody-mc-nodeface-ii;{"example": "general"} diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ImplicitNewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ImplicitNewParent_Dimensions.feature new file mode 100644 index 00000000000..1ea51857ef9 --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ImplicitNewParent_Dimensions.feature @@ -0,0 +1,5 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Move a node with content dimensions + + As a user of the CR, when I move a node to new siblings and they belong to another parent (completely or in variants), + I expect them to be ignored. From c7e2d792bc31a068db5f5e46056e16cc2f777762 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Sat, 13 Apr 2024 23:23:18 +0200 Subject: [PATCH 06/27] Introduce more comprehensive MoveNode test suite --- .../src/Domain/Projection/NodeRecord.php | 1 - .../01-MoveNodes_ConstraintChecks.feature | 106 +- ...NodeAggregate_NewParent_Dimensions.feature | 215 +- ...egate_ImplicitNewParent_Dimensions.feature | 5 - ...oveNodeAggregate_ScatteredChildren.feature | 271 ++ .../05-MoveNodeAggregate_SubtreeTags.feature | 2790 +++++++++++++++++ .../06-AdditionalConstraintChecks.feature | 6 + ...oveNodeAggregateWithoutDimensions.feature} | 0 ...eringDisableStateWithoutDimensions.feature | 343 -- .../Projection/ContentGraph/NodeTags.php | 4 +- .../Features/Bootstrap/ProjectedNodeTrait.php | 22 + 11 files changed, 3192 insertions(+), 571 deletions(-) delete mode 100644 Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ImplicitNewParent_Dimensions.feature create mode 100644 Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ScatteredChildren.feature create mode 100644 Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/05-MoveNodeAggregate_SubtreeTags.feature create mode 100644 Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/06-AdditionalConstraintChecks.feature rename Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/{MoveNodeAggregateWithoutDimensions.feature => 07-MoveNodeAggregateWithoutDimensions.feature} (100%) delete mode 100644 Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateConsideringDisableStateWithoutDimensions.feature diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/NodeRecord.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/NodeRecord.php index fbc75314807..f9bfb9f6d7d 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/NodeRecord.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/NodeRecord.php @@ -15,7 +15,6 @@ namespace Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use Doctrine\DBAL\Types\Types; use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Repository\DimensionSpacePointsRepository; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\SerializedPropertyValues; diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/01-MoveNodes_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/01-MoveNodes_ConstraintChecks.feature index 26377560926..34dabe37aa4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/01-MoveNodes_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/01-MoveNodes_ConstraintChecks.feature @@ -44,10 +44,12 @@ Feature: Move node to a new parent / within the current parent before a sibling | nodeTypeName | "Neos.ContentRepository:Root" | And the graph projection is fully up to date And the following CreateNodeAggregateWithNode commands are executed: - | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | tetheredDescendantNodeAggregateIds | - | sir-david-nodenborough | {"example": "source"} | Neos.ContentRepository.Testing:DocumentWithTetheredChildNode | lady-eleonode-rootford | document | {"tethered": "nodewyn-tetherton"} | - | sir-nodeward-nodington-iii | {"example": "source"} | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | esquire | {} | - | anthony-destinode | {"example": "spec"} | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | target-document | {} | + | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | tetheredDescendantNodeAggregateIds | + | sir-david-nodenborough | {"example": "source"} | Neos.ContentRepository.Testing:DocumentWithTetheredChildNode | lady-eleonode-rootford | document | {"tethered": "nodewyn-tetherton"} | + | nodimus-mediocre | {"example": "source"} | Neos.ContentRepository.Testing:Document | nodewyn-tetherton | grandchild-document | {} | + | sir-nodeward-nodington-iii | {"example": "source"} | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | esquire | {} | + | anthony-destinode | {"example": "spec"} | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | target-document | {} | + | lady-abigail-nodenborough | {"example": "spec"} | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | child-target-document | {} | Scenario: Try to move a node in a non-existing workspace: When the command MoveNodeAggregate is executed with payload and exceptions are caught: @@ -158,7 +160,7 @@ Feature: Move node to a new parent / within the current parent before a sibling | relationDistributionStrategy | "gatherAll" | Then the last command should have thrown an exception of type "NodeAggregateDoesCurrentlyNotCoverDimensionSpacePointSet" - Scenario: Try to move a node to a parent that already has a child node of the same name + Scenario: Using the scatter strategy, try to move a node to a parent that already has a child node of the same name Given the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | | nody-mc-nodeface | {"example": "source"} | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | document | @@ -171,6 +173,46 @@ Feature: Move node to a new parent / within the current parent before a sibling | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" + Scenario: Using the gatherSpecializations strategy, try to move a node to a parent that already has a child node of the same name in a specialization + Given the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | + | nody-mc-nodeface | {"example": "source"} | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | target-document | + + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "lady-eleonode-rootford" | + | relationDistributionStrategy | "gatherSpecializations" | + Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" + + Scenario: Using the gatherAll strategy, try to move a node to a parent that already has a child node of the same name in a generalization + Given the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | + | rival-destinode | {"example": "general"} | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | target-document | + | nody-mc-nodeface | {"example": "source"} | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | target-document | + # Remove the node with the conflicting name in all variants except the generalization + And the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "rival-destinode" | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + And the command RemoveNodeAggregate is executed with payload: + | Key | Value | + | coveredDimensionSpacePoint | {"example": "peer"} | + | nodeAggregateId | "rival-destinode" | + | nodeVariantSelectionStrategy | "allSpecializations" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherAll" | + Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" + Scenario: Try to move a node to a parent whose node type does not allow child nodes of the node's type Given the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | @@ -184,7 +226,7 @@ Feature: Move node to a new parent / within the current parent before a sibling | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeConstraintException" - Scenario: Try to move a node to a parent whose parent's node type does not allow grand child nodes of the node's type + Scenario: Using the scatter strategy, try to move a node to a parent whose parent's node type does not allow grand child nodes of the node's type Given the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | | nody-mc-nodeface | {"example": "source"} | Neos.ContentRepository.Testing:Content | lady-eleonode-rootford | content | @@ -197,6 +239,11 @@ Feature: Move node to a new parent / within the current parent before a sibling | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeConstraintException" + # Hint: One might come to the conclusion that we also have to check the other strategies. + # The cases would be that the new parent is partially moved to a new grandparent which then imposes different constraints. + # Yet these grandparent constraints are only imposed on the children of their tethered children, but the latter by definition cannot be moved. + # Thus the preconditions for these test cases cannot be established because the needed commands would fail. + Scenario: Try to move existing node to a non-existing preceding sibling When the command MoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | @@ -206,6 +253,25 @@ Feature: Move node to a new parent / within the current parent before a sibling | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" + Scenario: Try to move existing node after a node which is not a sibling + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "sir-david-nodenborough" | + | newPrecedingSiblingNodeAggregateId | "lady-abigail-nodenborough" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateIsNoSibling" + + Scenario: Try to move existing node after a node which is not a child of the new parent + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "sir-david-nodenborough" | + | newParentNodeAggregateId | "anthony-destinode" | + | newPrecedingSiblingNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateIsNoSibling" + Scenario: Try to move existing node to a non-existing succeeding sibling When the command MoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | @@ -215,6 +281,25 @@ Feature: Move node to a new parent / within the current parent before a sibling | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeAggregateCurrentlyDoesNotExist" + Scenario: Try to move existing node before a node which is not a sibling + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "sir-david-nodenborough" | + | newSucceedingSiblingNodeAggregateId | "lady-abigail-nodenborough" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateIsNoSibling" + + Scenario: Try to move existing node before a node which is not a child of the new parent + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "sir-david-nodenborough" | + | newParentNodeAggregateId | "anthony-destinode" | + | newSucceedingSiblingNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateIsNoSibling" + Scenario: Try to move a node to one of its children When the command MoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | @@ -223,3 +308,12 @@ Feature: Move node to a new parent / within the current parent before a sibling | newParentNodeAggregateId | "nodewyn-tetherton" | | relationDistributionStrategy | "scatter" | Then the last command should have thrown an exception of type "NodeAggregateIsDescendant" + + Scenario: Try to move a node to one of its grandchildren + When the command MoveNodeAggregate is executed with payload and exceptions are caught: + | Key | Value | + | dimensionSpacePoint | {"example": "source"} | + | nodeAggregateId | "sir-david-nodenborough" | + | newParentNodeAggregateId | "nodimus-mediocre" | + | relationDistributionStrategy | "scatter" | + Then the last command should have thrown an exception of type "NodeAggregateIsDescendant" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature index 4595c23e481..d3ffa539ad9 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature @@ -2128,220 +2128,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - # Legacy test cases - - Scenario: Move a complete node aggregate to a new parent after another of its new siblings - which does not exist in all variants - Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "younger-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "spec"} | - | nodeVariantSelectionStrategy | "allSpecializations" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "general"} | - | newParentNodeAggregateId | "sir-david-nodenborough" | - | newPrecedingSiblingNodeAggregateId | "elder-mc-nodeface" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have no succeeding siblings - - Scenario: Move a complete node aggregate to a new parent after the last of its new siblings - with a predecessor which does not exist in all variants - Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "younger-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "spec"} | - | nodeVariantSelectionStrategy | "allSpecializations" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "general"} | - | newParentNodeAggregateId | "sir-david-nodenborough" | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have no succeeding siblings - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have no succeeding siblings - - Scenario: Move a single node in a node aggregate to a new parent after the last of its new siblings - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | "sir-david-nodenborough" | - | newSucceedingSiblingNodeAggregateId | null | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} - And I expect this node to have no preceding siblings - And I expect this node to have no succeeding siblings - - When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have no succeeding siblings - - Scenario: Move a node and its specializations in a node aggregate to a new parent after the last of its new siblings - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | "sir-david-nodenborough" | - | newSucceedingSiblingNodeAggregateId | null | - | relationDistributionStrategy | "gatherSpecializations" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} - And I expect this node to have no preceding siblings - And I expect this node to have no succeeding siblings - - When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have no succeeding siblings - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have no succeeding siblings - - Scenario: Move a complete node aggregate to a new parent between siblings with different parents in other variants - Given the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "elder-mc-nodeface" | - | dimensionSpacePoint | {"example": "spec"} | - | newParentNodeAggregateId | "bustling-mc-nodeface" | - | newSucceedingSiblingNodeAggregateId | null | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "general"} | - | newParentNodeAggregateId | "sir-david-nodenborough" | - | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | - | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | - | relationDistributionStrategy | "gatherAll" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - - # An explicitly given parent node aggregate identifier should overrule given sibling identifiers - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - - Scenario: Move a complete node aggregate between siblings with different parents in other variants (without explicit new parent) - Given the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "elder-mc-nodeface" | - | dimensionSpacePoint | {"example": "spec"} | - | newParentNodeAggregateId | "bustling-mc-nodeface" | - | newSucceedingSiblingNodeAggregateId | null | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "general"} | - | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | - | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | - | relationDistributionStrategy | "gatherAll" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "bustling-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;bustling-mc-nodeface;{"example": "general"} - And I expect this node to have no preceding siblings - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | + # Other test cases Scenario: Move a node that has no name Given the command CreateNodeAggregateWithNode is executed with payload: diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ImplicitNewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ImplicitNewParent_Dimensions.feature deleted file mode 100644 index 1ea51857ef9..00000000000 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ImplicitNewParent_Dimensions.feature +++ /dev/null @@ -1,5 +0,0 @@ -@contentrepository @adapters=DoctrineDBAL -Feature: Move a node with content dimensions - - As a user of the CR, when I move a node to new siblings and they belong to another parent (completely or in variants), - I expect them to be ignored. diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ScatteredChildren.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ScatteredChildren.feature new file mode 100644 index 00000000000..e8c00aec5fe --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ScatteredChildren.feature @@ -0,0 +1,271 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Move a node with content dimensions + + As a user of the CR, when I move a node to a new parent, where that parent or requested siblings have been scattered, + I expect scattered parents to be considered and scattered siblings to be ignored. + The other way around, if a scattered node is moved, the variants are to be gathered again as specified in the command. + + Background: + Given using the following content dimensions: + | Identifier | Values | Generalizations | + | example | general, source, peer, spec | spec->source->general, peer->general | + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:Document': [] + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The live workspace" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | + | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | parent-document | + | elder-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | elder-document | + | nody-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | document | + | younger-mc-nodeface | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | younger-document | + | sir-nodeward-nodington-iii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | esquire | + | nodimus-mediocre | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | esquire-child | + | elder-destinode | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | elder-target-document | + | bustling-destinode | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | bustling-target-document | + | younger-destinode | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | younger-target-document | + | elder-child-destinode | Neos.ContentRepository.Testing:Document | nodimus-mediocre | elder-child-target-document | + | younger-child-destinode | Neos.ContentRepository.Testing:Document | nodimus-mediocre | younger-child-target-document | + + Scenario: Scatter a node aggregate by moving a specialization variant to a different parent. Then move another node to the node's parent as a new sibling + Given the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "bustling-destinode" | + | dimensionSpacePoint | {"example": "spec"} | + | newParentNodeAggregateId | "nodimus-mediocre" | + | newSucceedingSiblingNodeAggregateId | "younger-child-destinode" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | newSucceedingSiblingNodeAggregateIde | "bustling-destinode" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-destinode;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;bustling-destinode;{"example": "general"} | + | cs-identifier;younger-destinode;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-destinode;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-destinode;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + + Scenario: Scatter a node aggregate by moving a specialization variant to a different parent. Then move another node to the scattered node as a new child + Given the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "bustling-destinode" | + | dimensionSpacePoint | {"example": "spec"} | + | newParentNodeAggregateId | "nodimus-mediocre" | + | newSucceedingSiblingNodeAggregateId | "younger-child-destinode" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "bustling-destinode" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/bustling-target-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;bustling-destinode;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/bustling-target-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;bustling-destinode;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + + Scenario: Scatter a node aggregate by moving a specialization variant to a different parent. Then move both variants to a new succeeding sibling only present as sibling in the general one + Given the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "bustling-destinode" | + | dimensionSpacePoint | {"example": "spec"} | + | newParentNodeAggregateId | "nodimus-mediocre" | + | newSucceedingSiblingNodeAggregateId | "younger-child-destinode" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "bustling-destinode" | + | dimensionSpacePoint | {"example": "source"} | + | newSucceedingSiblingNodeAggregateId | "younger-destinode" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "bustling-destinode" and node path "esquire/bustling-target-document" to lead to node cs-identifier;bustling-destinode;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-destinode;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-destinode;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "bustling-destinode" and node path "esquire/esquire-child/bustling-target-document" to lead to node cs-identifier;bustling-destinode;{"example": "general"} + And I expect this node to be a child of node cs-identifier;nodimus-mediocre;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-child-destinode;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-child-destinode;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "bustling-destinode" and node path "esquire/esquire-child/bustling-target-document" to lead to node cs-identifier;bustling-destinode;{"example": "general"} + And I expect this node to be a child of node cs-identifier;nodimus-mediocre;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have no succeeding siblings + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "bustling-destinode" and node path "esquire/bustling-target-document" to lead to node cs-identifier;bustling-destinode;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-destinode;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-destinode;{"example": "general"} | + + Scenario: Scatter a node aggregate by moving a specialization variant to a different parent. Then let a sibling variant follow suit and move the sibling before the node in both variants. + Given the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "bustling-destinode" | + | dimensionSpacePoint | {"example": "spec"} | + | newParentNodeAggregateId | "nodimus-mediocre" | + | newSucceedingSiblingNodeAggregateId | "younger-child-destinode" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + And the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "elder-destinode" | + | dimensionSpacePoint | {"example": "spec"} | + | newParentNodeAggregateId | "nodimus-mediocre" | + | newPrecedingSiblingNodeAggregateId | "bustling-destinode" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "elder-destinode" | + | dimensionSpacePoint | {"example": "source"} | + | newSucceedingSiblingNodeAggregateId | "bustling-destinode" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "elder-destinode" and node path "esquire/elder-target-document" to lead to node cs-identifier;elder-destinode;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;bustling-destinode;{"example": "general"} | + | cs-identifier;younger-destinode;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "elder-destinode" and node path "esquire/esquire-child/elder-target-document" to lead to node cs-identifier;elder-destinode;{"example": "general"} + And I expect this node to be a child of node cs-identifier;nodimus-mediocre;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-child-destinode;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;bustling-destinode;{"example": "general"} | + | cs-identifier;younger-child-destinode;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "elder-destinode" and node path "esquire/esquire-child/elder-target-document" to lead to node cs-identifier;elder-destinode;{"example": "general"} + And I expect this node to be a child of node cs-identifier;nodimus-mediocre;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-child-destinode;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-child-destinode;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "elder-destinode" and node path "esquire/elder-target-document" to lead to node cs-identifier;elder-destinode;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} + And I expect this node to have no preceding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;bustling-destinode;{"example": "general"} | + | cs-identifier;younger-destinode;{"example": "general"} | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/05-MoveNodeAggregate_SubtreeTags.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/05-MoveNodeAggregate_SubtreeTags.feature new file mode 100644 index 00000000000..2c6641c53b4 --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/05-MoveNodeAggregate_SubtreeTags.feature @@ -0,0 +1,2790 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Move a node aggregate into and out of a tagged parent + + As a user of the CR I want to move a node that + - is untagged + - tags itself (partially or completely) + - is tagged by one of its ancestors (partially or completely) + + to a new parent that + - is untagged (except when the source is untagged too, which is covered by the other move test cases) + - tags itself, same or differently than the source (partially or completely) + - is tagged by one of its ancestors, same or differently than the source (partially or completely) + + Background: + Given using the following content dimensions: + | Identifier | Values | Generalizations | + | example | general, source, peer, spec | spec->source->general, peer->general | + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:Document': [] + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The live workspace" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | parentNodeAggregateId | nodeTypeName | nodeName | + | sir-david-nodenborough | lady-eleonode-rootford | Neos.ContentRepository.Testing:Document | parent-document | + | nody-mc-nodeface | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | document | + | nodimus-mediocre | nody-mc-nodeface | Neos.ContentRepository.Testing:Document | child-document | + | sir-nodeward-nodington-iii | lady-eleonode-rootford | Neos.ContentRepository.Testing:Document | esquire | + | nodimus-prime | sir-nodeward-nodington-iii | Neos.ContentRepository.Testing:Document | esquire-child | + + # move untagged to self-tagging + + Scenario: Move an untagged node to a new parent that tags itself + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move an untagged node to a new parent that tags itself partially + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + # move untagged to tagged + + Scenario: Move an untagged node to a new parent that is tagged by its ancestors + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move an untagged node to a new parent that is partially tagged by its ancestors + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + # move tagging to untagged + + Scenario: Move a node that tags itself to a new, untagged parent + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself partially to a new, untagged parent + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + # move tagging to tagging + + Scenario: Move a node that tags itself to a new parent that tags the same + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself to a new parent that tags the same, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself partially to a new parent that tags the same + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself partially to a new parent that tags the same, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself to a new parent that tags differently + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1,tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1,tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself to a new parent that tags differently, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1,tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself partially to a new parent that tags differently + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1,tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself partially to a new parent that tags differently, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1,tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + # move tagging to tagged + + Scenario: Move a node that tags itself to a new parent that is tagged the same + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself to a new parent that is tagged the same, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself partially to a new parent that is tagged the same + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself partially to a new parent that is tagged the same, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself to a new parent that is tagged differently + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1,tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1,tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself to a new parent that is tagged differently, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1,tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself partially to a new parent that tags differently + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1,tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a node that tags itself partially to a new parent that is tagged differently, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1,tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + # move tagged to untagged + + Scenario: Move a tagged node to a new, untagged parent + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a partially tagged node to a new, untagged parent + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + # move tagged to tagging + + Scenario: Move a tagged node to a new parent that tags the same + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nodimus-prime" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime,{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a tagged node to a new parent that tags the same, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nodimus-prime" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "tag1" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a partially tagged node to a new parent that tags the same + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nodimus-prime" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a partially tagged node to a new parent that tags the same, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nodimus-prime" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a tagged node to a new parent that tags differently + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nodimus-prime" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a tagged node to a new parent that tags differently, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nodimus-prime" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-devid-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a partially tagged node to a new parent that tags differently + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nodimus-prime" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a partially tagged node to a new parent that tags differently, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "nodimus-prime" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + # move tagged to tagged + + Scenario: Move a tagged node to a new parent that is tagged the same + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a tagged node to a new parent that is tagged the same, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a partially tagged node to a new parent that is tagged the same + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a partially tagged node to a new parent that is tagged the same, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag1" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a tagged node to a new parent that is tagged differently + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a tagged node to a new parent that is tagged differently, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a partially tagged node to a new parent that is tagged differently + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + Scenario: Move a partially tagged node to a new parent that is tagged differently, partially + + Given the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-david-nodenborough" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag1" | + And the graph projection is fully up to date + + And the command TagSubtree is executed with payload: + | Key | Value | + | nodeAggregateId | "sir-nodeward-nodington-iii" | + | coveredDimensionSpacePoint | {"example": "spec"} | + | nodeVariantSelectionStrategy | "allSpecializations" | + | tag | "tag2" | + And the graph projection is fully up to date + + When the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "nodimus-prime" | + | relationDistributionStrategy | "gatherSpecializations" | + And the graph projection is fully up to date + + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "tag2" + + When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" + + And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} + And I expect this node to tag with "" + And I expect this node to be tagged with "" diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/06-AdditionalConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/06-AdditionalConstraintChecks.feature new file mode 100644 index 00000000000..c513bd266d4 --- /dev/null +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/06-AdditionalConstraintChecks.feature @@ -0,0 +1,6 @@ +@contentrepository @adapters=DoctrineDBAL +Feature: Additional constraint checks after move node capabilities are introduced + + Scenario: Scatter a named node aggregate among different parents, then try to create a new node with the same name under one of the new parents + + Scenario: Scatter a node aggregate among different parents, then try to create a new child node of a type prohibited by one of the grandparents diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateWithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/07-MoveNodeAggregateWithoutDimensions.feature similarity index 100% rename from Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateWithoutDimensions.feature rename to Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/07-MoveNodeAggregateWithoutDimensions.feature diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateConsideringDisableStateWithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateConsideringDisableStateWithoutDimensions.feature deleted file mode 100644 index e8f664d3ec1..00000000000 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/MoveNodeAggregateConsideringDisableStateWithoutDimensions.feature +++ /dev/null @@ -1,343 +0,0 @@ -@contentrepository @adapters=DoctrineDBAL -Feature: Move a node aggregate considering disable state but without content dimensions - - As a user of the CR I want to move a node that - - is disabled by one of its ancestors - - disables itself - - disables any of its descendants - - is enabled - - to a new parent that - - is enabled - - disables itself - - is disabled by one of its ancestors - - These are the test cases without content dimensions being involved - - Background: - Given using no content dimensions - And using the following node types: - """yaml - 'Neos.ContentRepository.Testing:Document': [] - """ - And using identifier "default", I define a content repository - And I am in content repository "default" - And the command CreateRootWorkspace is executed with payload: - | Key | Value | - | workspaceName | "live" | - | workspaceTitle | "Live" | - | workspaceDescription | "The live workspace" | - | newContentStreamId | "cs-identifier" | - And the graph projection is fully up to date - And I am in the active content stream of workspace "live" - And the command CreateRootNodeAggregateWithNode is executed with payload: - | Key | Value | - | nodeAggregateId | "lady-eleonode-rootford" | - | nodeTypeName | "Neos.ContentRepository:Root" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {} | - | coveredDimensionSpacePoints | [{}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "document" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {} | - | coveredDimensionSpacePoints | [{}] | - | parentNodeAggregateId | "sir-david-nodenborough" | - | nodeName | "child-document" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {} | - | coveredDimensionSpacePoints | [{}] | - | parentNodeAggregateId | "lady-eleonode-rootford" | - | nodeName | "esquire" | - | nodeAggregateClassification | "regular" | - And the event NodeAggregateWithNodeWasCreated was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nodimus-prime" | - | nodeTypeName | "Neos.ContentRepository.Testing:Document" | - | originDimensionSpacePoint | {} | - | coveredDimensionSpacePoints | [{}] | - | parentNodeAggregateId | "sir-nodeward-nodington-iii" | - | nodeName | "esquire-child" | - | nodeAggregateClassification | "regular" | - And the graph projection is fully up to date - - Scenario: Move a node disabled by one of its ancestors to a new parent that is enabled - Given the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {} | - | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - - # node aggregate occupation and coverage is not relevant without dimensions and thus not tested - - And I am in the active content stream of workspace "live" and dimension space point {} - And VisibilityConstraints are set to "frontend" - And I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/child-document" to lead to node cs-identifier;nody-mc-nodeface;{} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{} - - Scenario: Move a node disabled by itself to a new parent that is enabled - Given the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {} | - | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - And I am in the active content stream of workspace "live" and dimension space point {} - And VisibilityConstraints are set to "frontend" - - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/child-document" to lead to no node - - Scenario: Move a node that disables one of its descendants to a new parent that is enabled - Given the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "sir-david-nodenborough" | - | dimensionSpacePoint | {} | - | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - And I am in the active content stream of workspace "live" and dimension space point {} - And VisibilityConstraints are set to "frontend" - - Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/document" to lead to no node - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document/child-document" to lead to no node - - Scenario: Move a node that is disabled by one of its ancestors to a new parent that disables itself - Given the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - And the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {} | - | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - And I am in the active content stream of workspace "live" and dimension space point {} - And VisibilityConstraints are set to "frontend" - - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/child-document" to lead to no node - - Scenario: Move a node that is disabled by itself to a new parent that disables itself - Given the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - And the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "sir-david-nodenborough" | - | dimensionSpacePoint | {} | - | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - And I am in the active content stream of workspace "live" and dimension space point {} - And VisibilityConstraints are set to "frontend" - - Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/document" to lead to no node - - Scenario: Move a node that is enabled to a new parent that disables itself - Given the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "sir-david-nodenborough" | - | dimensionSpacePoint | {} | - | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - And I am in the active content stream of workspace "live" and dimension space point {} - And VisibilityConstraints are set to "frontend" - - Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/document" to lead to no node - - Scenario: Move a node that disables any of its descendants to a new parent that disables itself - Given the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - And the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "sir-david-nodenborough" | - | dimensionSpacePoint | {} | - | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - And I am in the active content stream of workspace "live" and dimension space point {} - And VisibilityConstraints are set to "frontend" - - Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/document" to lead to no node - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document/child-document" to lead to no node - - Scenario: Move a node that is disabled by one of its ancestors to a new parent that is disabled by one of its ancestors - Given the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - And the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {} | - | newParentNodeAggregateId | "nodimus-prime" | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - And I am in the active content stream of workspace "live" and dimension space point {} - And VisibilityConstraints are set to "frontend" - - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/child-document" to lead to no node - - Scenario: Move a node that is disabled by itself to a new parent that is disabled by one of its ancestors - Given the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - And the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "sir-david-nodenborough" | - | dimensionSpacePoint | {} | - | newParentNodeAggregateId | "nodimus-prime" | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - And I am in the active content stream of workspace "live" and dimension space point {} - And VisibilityConstraints are set to "frontend" - - Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/esquire-child/document" to lead to no node - - Scenario: Move a node that disables any of its descendants to a new parent that is disabled by one of its ancestors - Given the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - And the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "sir-david-nodenborough" | - | dimensionSpacePoint | {} | - | newParentNodeAggregateId | "nodimus-prime" | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - And I am in the active content stream of workspace "live" and dimension space point {} - And VisibilityConstraints are set to "frontend" - - Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/esquire-child/document" to lead to no node - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document/child-document" to lead to no node - - Scenario: Move a node that is enabled to a new parent that is disabled by one of its ancestors - Given the event SubtreeWasTagged was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-nodeward-nodington-iii" | - | affectedDimensionSpacePoints | [{}] | - | tag | "disabled" | - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "sir-david-nodenborough" | - | dimensionSpacePoint | {} | - | newParentNodeAggregateId | "nodimus-prime" | - | newSucceedingSiblingNodeAggregateId | null | - And the graph projection is fully up to date - And I am in the active content stream of workspace "live" and dimension space point {} - And VisibilityConstraints are set to "frontend" - - Then I expect node aggregate identifier "sir-david-nodenborough" and node path "esquire/esquire-child/document" to lead to no node diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeTags.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeTags.php index 8317643ab22..d53233c328a 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeTags.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeTags.php @@ -33,8 +33,8 @@ final readonly class NodeTags implements \IteratorAggregate, \Countable, \JsonSerializable { private function __construct( - private SubtreeTags $tags, - private SubtreeTags $inheritedTags, + public SubtreeTags $tags, + public SubtreeTags $inheritedTags, ) { } diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php index 0be5327d92b..85cea48b444 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php @@ -650,6 +650,28 @@ public function iExpectThisNodeToHaveTheFollowingSucceedingSiblings(TableNode $e }); } + /** + * @Then /^I expect this node to tag with "(.*)"$/ + * @param string $tagList the comma-separated list of tag names + */ + public function iExpectThisNodeToTagWith(string $tagList): void + { + $this->assertOnCurrentNode(function (Node $currentNode) use ($tagList) { + $currentNode->tags->tags->toStringArray() === explode(',', $tagList); + }); + } + + /** + * @Then /^I expect this node to be tagged with "(.*)"$/ + * @param string $tagList the comma-separated list of tag names + */ + public function iExpectThisNodeToBeTaggedWith(string $tagList): void + { + $this->assertOnCurrentNode(function (Node $currentNode) use ($tagList) { + $currentNode->tags->inheritedTags->toStringArray() === explode(',', $tagList); + }); + } + /** * @Then /^I expect this node to have no succeeding siblings$/ */ From 658044528470917ba29106f5f49a2ce6325ffccb Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Sat, 13 Apr 2024 23:35:20 +0200 Subject: [PATCH 07/27] Add creation constraint checks after node move --- .../06-AdditionalConstraintChecks.feature | 75 ++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/06-AdditionalConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/06-AdditionalConstraintChecks.feature index c513bd266d4..a3ecd838bde 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/06-AdditionalConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/06-AdditionalConstraintChecks.feature @@ -1,6 +1,79 @@ @contentrepository @adapters=DoctrineDBAL Feature: Additional constraint checks after move node capabilities are introduced + Background: + Given using the following content dimensions: + | Identifier | Values | Generalizations | + | example | general, source, peer, spec | spec->source->general, peer->general | + And using the following node types: + """yaml + 'Neos.ContentRepository.Testing:Document': [] + """ + And using identifier "default", I define a content repository + And I am in content repository "default" + And the command CreateRootWorkspace is executed with payload: + | Key | Value | + | workspaceName | "live" | + | workspaceTitle | "Live" | + | workspaceDescription | "The live workspace" | + | newContentStreamId | "cs-identifier" | + And the graph projection is fully up to date + And I am in the active content stream of workspace "live" and dimension space point {"example": "general"} + And the command CreateRootNodeAggregateWithNode is executed with payload: + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | + And the following CreateNodeAggregateWithNode commands are executed: + | nodeAggregateId | nodeTypeName | parentNodeAggregateId | nodeName | + | sir-david-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | parent-document | + | lady-abigail-nodenborough | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | other-parent-document | + | sir-nodeward-nodington-iii | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | esquire | + | general-nodesworth | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | general-document | + | bustling-mc-nodeface | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | document | + Scenario: Scatter a named node aggregate among different parents, then try to create a new node with the same name under one of the new parents + Given the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "bustling-mc-nodeface" | + | dimensionSpacePoint | {"example": "spec"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + And the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "bustling-mc-nodeface" | + | dimensionSpacePoint | {"example": "peer"} | + | newParentNodeAggregateId | "lady-abigail-nodenborough" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + And the command MoveNodeAggregate is executed with payload: + | Key | Value | + | nodeAggregateId | "bustling-mc-nodeface" | + | dimensionSpacePoint | {"example": "general"} | + | newParentNodeAggregateId | "general-nodesworth" | + | relationDistributionStrategy | "scatter" | + And the graph projection is fully up to date + + When the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:Document" | + | parentNodeAggregateId | "sir-nodeward-nodington-iii" | + | nodeName | "document" | + Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" + When the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:Document" | + | parentNodeAggregateId | "lady-abigail-nodenborough" | + | nodeName | "document" | + Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" + When the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | nodeTypeName | "Neos.ContentRepository.Testing:Document" | + | parentNodeAggregateId | "general-nodesworth" | + | nodeName | "document" | + Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" + - Scenario: Scatter a node aggregate among different parents, then try to create a new child node of a type prohibited by one of the grandparents From bddda1cf65c67198b7afac5151df90eb3c96e6fd Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Sun, 14 Apr 2024 10:03:07 +0200 Subject: [PATCH 08/27] Enforce additional sibling constraint checks on MoveNode --- .../01-MoveNodes_ConstraintChecks.feature | 22 +++--- .../Feature/Common/ConstraintChecks.php | 67 +++++++++++++++++++ .../Classes/Feature/NodeMove/NodeMove.php | 66 ++++++++++++++++-- .../Classes/Projection/ContentGraph/Nodes.php | 11 +++ 4 files changed, 151 insertions(+), 15 deletions(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/01-MoveNodes_ConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/01-MoveNodes_ConstraintChecks.feature index 34dabe37aa4..47ae7031caf 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/01-MoveNodes_ConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/01-MoveNodes_ConstraintChecks.feature @@ -9,8 +9,8 @@ Feature: Move node to a new parent / within the current parent before a sibling Background: Given using the following content dimensions: - | Identifier | Values | Generalizations | - | example | general, source, spec | spec->source->general | + | Identifier | Values | Generalizations | + | example | general, source, spec, peer | spec->source->general, peer->general | And using the following node types: """yaml 'Neos.ContentRepository.Testing:Document': [] @@ -46,10 +46,12 @@ Feature: Move node to a new parent / within the current parent before a sibling And the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | tetheredDescendantNodeAggregateIds | | sir-david-nodenborough | {"example": "source"} | Neos.ContentRepository.Testing:DocumentWithTetheredChildNode | lady-eleonode-rootford | document | {"tethered": "nodewyn-tetherton"} | - | nodimus-mediocre | {"example": "source"} | Neos.ContentRepository.Testing:Document | nodewyn-tetherton | grandchild-document | {} | | sir-nodeward-nodington-iii | {"example": "source"} | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | esquire | {} | | anthony-destinode | {"example": "spec"} | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | target-document | {} | | lady-abigail-nodenborough | {"example": "spec"} | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | child-target-document | {} | + | nodimus-prime | {"example": "source"} | Neos.ContentRepository.Testing:Document | sir-david-nodenborough | child-document | {} | + | nodimus-mediocre | {"example": "source"} | Neos.ContentRepository.Testing:Document | nodimus-prime | grandchild-document | {} | + | general-nodesworth | {"example": "general"} | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | general-document | {} | Scenario: Try to move a node in a non-existing workspace: When the command MoveNodeAggregate is executed with payload and exceptions are caught: @@ -189,8 +191,8 @@ Feature: Move node to a new parent / within the current parent before a sibling Scenario: Using the gatherAll strategy, try to move a node to a parent that already has a child node of the same name in a generalization Given the following CreateNodeAggregateWithNode commands are executed: | nodeAggregateId | originDimensionSpacePoint | nodeTypeName | parentNodeAggregateId | nodeName | - | rival-destinode | {"example": "general"} | Neos.ContentRepository.Testing:Document | lady-eleonode-rootford | target-document | - | nody-mc-nodeface | {"example": "source"} | Neos.ContentRepository.Testing:Document | sir-nodeward-nodington-iii | target-document | + | rival-destinode | {"example": "general"} | Neos.ContentRepository.Testing:Document | general-nodesworth | target-document | + | nody-mc-nodeface | {"example": "source"} | Neos.ContentRepository.Testing:Document | nodimus-prime | target-document | # Remove the node with the conflicting name in all variants except the generalization And the command RemoveNodeAggregate is executed with payload: | Key | Value | @@ -209,7 +211,7 @@ Feature: Move node to a new parent / within the current parent before a sibling | Key | Value | | dimensionSpacePoint | {"example": "source"} | | nodeAggregateId | "nody-mc-nodeface" | - | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | newParentNodeAggregateId | "general-nodesworth" | | relationDistributionStrategy | "gatherAll" | Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" @@ -265,12 +267,12 @@ Feature: Move node to a new parent / within the current parent before a sibling Scenario: Try to move existing node after a node which is not a child of the new parent When the command MoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | - | dimensionSpacePoint | {"example": "source"} | + | dimensionSpacePoint | {"example": "spec"} | | nodeAggregateId | "sir-david-nodenborough" | | newParentNodeAggregateId | "anthony-destinode" | | newPrecedingSiblingNodeAggregateId | "sir-nodeward-nodington-iii" | | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeAggregateIsNoSibling" + Then the last command should have thrown an exception of type "NodeAggregateIsNoChild" Scenario: Try to move existing node to a non-existing succeeding sibling When the command MoveNodeAggregate is executed with payload and exceptions are caught: @@ -293,12 +295,12 @@ Feature: Move node to a new parent / within the current parent before a sibling Scenario: Try to move existing node before a node which is not a child of the new parent When the command MoveNodeAggregate is executed with payload and exceptions are caught: | Key | Value | - | dimensionSpacePoint | {"example": "source"} | + | dimensionSpacePoint | {"example": "spec"} | | nodeAggregateId | "sir-david-nodenborough" | | newParentNodeAggregateId | "anthony-destinode" | | newSucceedingSiblingNodeAggregateId | "sir-nodeward-nodington-iii" | | relationDistributionStrategy | "scatter" | - Then the last command should have thrown an exception of type "NodeAggregateIsNoSibling" + Then the last command should have thrown an exception of type "NodeAggregateIsNoChild" Scenario: Try to move a node to one of its children When the command MoveNodeAggregate is executed with payload and exceptions are caught: diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php index b4e665910d4..f8bf6372262 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php @@ -27,7 +27,11 @@ use Neos\ContentRepository\Core\NodeType\NodeType; use Neos\ContentRepository\Core\NodeType\NodeTypeManager; use Neos\ContentRepository\Core\NodeType\NodeTypeName; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindPrecedingSiblingNodesFilter; +use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindSucceedingSiblingNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; +use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamIsClosed; use Neos\ContentRepository\Core\SharedModel\Exception\DimensionSpacePointIsNotYetOccupied; @@ -36,6 +40,8 @@ use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateDoesCurrentlyNotCoverDimensionSpacePoint; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateDoesCurrentlyNotCoverDimensionSpacePointSet; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateIsDescendant; +use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateIsNoChild; +use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateIsNoSibling; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateIsRoot; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateIsTethered; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregatesTypeIsAmbiguous; @@ -557,6 +563,67 @@ protected function requireNodeAggregateToNotBeDescendant( } } + /** + * @throws NodeAggregateIsNoSibling + */ + protected function requireNodeAggregateToBeSibling( + ContentStreamId $contentStreamId, + NodeAggregateId $referenceNodeAggregateId, + NodeAggregateId $siblingNodeAggregateId, + DimensionSpacePoint $dimensionSpacePoint, + ContentRepository $contentRepository, + ): void { + $succeedingSiblings = $contentRepository->getContentGraph()->getSubgraph( + $contentStreamId, + $dimensionSpacePoint, + VisibilityConstraints::withoutRestrictions() + )->findSucceedingSiblingNodes($referenceNodeAggregateId, FindSucceedingSiblingNodesFilter::create()); + if ($succeedingSiblings->getIds()->contain($siblingNodeAggregateId)) { + return; + } + + $precedingSiblings = $contentRepository->getContentGraph()->getSubgraph( + $contentStreamId, + $dimensionSpacePoint, + VisibilityConstraints::withoutRestrictions() + )->findPrecedingSiblingNodes($referenceNodeAggregateId, FindPrecedingSiblingNodesFilter::create()); + if ($precedingSiblings->getIds()->contain($siblingNodeAggregateId)) { + return; + } + + throw NodeAggregateIsNoSibling::butWasExpectedToBeInDimensionSpacePoint( + $siblingNodeAggregateId, + $referenceNodeAggregateId, + $dimensionSpacePoint + ); + } + + /** + * @throws NodeAggregateIsNoChild + */ + protected function requireNodeAggregateToBeChild( + ContentStreamId $contentStreamId, + NodeAggregateId $childNodeAggregateId, + NodeAggregateId $parentNodeAggregateId, + DimensionSpacePoint $dimensionSpacePoint, + ContentRepository $contentRepository, + ): void { + $childNodes = $contentRepository->getContentGraph()->getSubgraph( + $contentStreamId, + $dimensionSpacePoint, + VisibilityConstraints::withoutRestrictions() + )->findChildNodes($parentNodeAggregateId, FindChildNodesFilter::create()); + if ($childNodes->getIds()->contain($childNodeAggregateId)) { + return; + } + + throw NodeAggregateIsNoChild::butWasExpectedToBeInDimensionSpacePoint( + $childNodeAggregateId, + $parentNodeAggregateId, + $dimensionSpacePoint + ); + } + /** * @throws NodeNameIsAlreadyOccupied */ diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php index 9290dfdb872..21f63678cc8 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php @@ -16,6 +16,7 @@ use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\DimensionSpace; +use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; use Neos\ContentRepository\Core\DimensionSpace\Exception\DimensionSpacePointNotFound; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; @@ -43,6 +44,8 @@ use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateCurrentlyDoesNotExist; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateIsDescendant; +use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateIsNoChild; +use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateIsNoSibling; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregatesTypeIsAmbiguous; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; @@ -62,13 +65,30 @@ abstract protected function requireProjectedNodeAggregate( ContentRepository $contentRepository ): NodeAggregate; + abstract protected function requireNodeAggregateToBeSibling( + ContentStreamId $contentStreamId, + NodeAggregateId $referenceNodeAggregateId, + NodeAggregateId $siblingNodeAggregateId, + DimensionSpacePoint $dimensionSpacePoint, + ContentRepository $contentRepository, + ): void; + + abstract protected function requireNodeAggregateToBeChild( + ContentStreamId $contentStreamId, + NodeAggregateId $childNodeAggregateId, + NodeAggregateId $parentNodAggregateId, + DimensionSpacePoint $dimensionSpacePoint, + ContentRepository $contentRepository, + ): void; + /** - * @return EventsToPublish * @throws ContentStreamDoesNotExistYet * @throws NodeAggregatesTypeIsAmbiguous * @throws NodeAggregateCurrentlyDoesNotExist * @throws DimensionSpacePointNotFound * @throws NodeAggregateIsDescendant + * @throws NodeAggregateIsNoSibling + * @throws NodeAggregateIsNoChild */ private function handleMoveNodeAggregate( MoveNodeAggregate $command, @@ -101,17 +121,19 @@ private function handleMoveNodeAggregate( $contentRepository ); - $this->requireNodeNameToBeUncovered( + $newParentNodeAggregate = $this->requireProjectedNodeAggregate( $contentStreamId, - $nodeAggregate->nodeName, $command->newParentNodeAggregateId, - $affectedDimensionSpacePoints, $contentRepository ); - $newParentNodeAggregate = $this->requireProjectedNodeAggregate( + $this->requireNodeNameToBeUncovered( $contentStreamId, + $nodeAggregate->nodeName, $command->newParentNodeAggregateId, + // We need to check all covered DSPs of the parent node aggregate to prevent siblings + // with different node aggregate IDs but the same name + $newParentNodeAggregate->coveredDimensionSpacePoints, $contentRepository ); @@ -134,6 +156,23 @@ private function handleMoveNodeAggregate( $command->newPrecedingSiblingNodeAggregateId, $contentRepository ); + if ($command->newParentNodeAggregateId) { + $this->requireNodeAggregateToBeChild( + $contentStreamId, + $command->newPrecedingSiblingNodeAggregateId, + $command->newParentNodeAggregateId, + $command->dimensionSpacePoint, + $contentRepository + ); + } else { + $this->requireNodeAggregateToBeSibling( + $contentStreamId, + $command->nodeAggregateId, + $command->newPrecedingSiblingNodeAggregateId, + $command->dimensionSpacePoint, + $contentRepository + ); + } } if ($command->newSucceedingSiblingNodeAggregateId) { $this->requireProjectedNodeAggregate( @@ -141,6 +180,23 @@ private function handleMoveNodeAggregate( $command->newSucceedingSiblingNodeAggregateId, $contentRepository ); + if ($command->newParentNodeAggregateId) { + $this->requireNodeAggregateToBeChild( + $contentStreamId, + $command->newSucceedingSiblingNodeAggregateId, + $command->newParentNodeAggregateId, + $command->dimensionSpacePoint, + $contentRepository + ); + } else { + $this->requireNodeAggregateToBeSibling( + $contentStreamId, + $command->nodeAggregateId, + $command->newSucceedingSiblingNodeAggregateId, + $command->dimensionSpacePoint, + $contentRepository + ); + } } /** @var OriginNodeMoveMapping[] $originNodeMoveMappings */ diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php index 1ea87139400..461ab934305 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php @@ -14,6 +14,9 @@ namespace Neos\ContentRepository\Core\Projection\ContentGraph; +use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; +use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateIds; + /** * An immutable, type-safe collection of Node objects * @@ -194,4 +197,12 @@ public function nextAll(Node $referenceNode): self return new self(array_slice($this->nodes, $referenceNodeIndex + 1)); } + + public function getIds(): NodeAggregateIds + { + return NodeAggregateIds::create(...array_map( + fn (Node $node): NodeAggregateId => $node->nodeAggregateId, + $this->nodes + )); + } } From e82d47f667c06791beebcaa187180fe95acb1f71 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Sun, 14 Apr 2024 13:24:27 +0200 Subject: [PATCH 09/27] WIP: Refactor NodeAggregateWasMoved to use InterdimensionalSiblings --- .../Domain/Projection/Feature/NodeMove.php | 165 ++++----- .../NodeMove/Dto/CoverageNodeMoveMapping.php | 75 ---- .../NodeMove/Dto/CoverageNodeMoveMappings.php | 88 ----- .../NodeMove/Dto/OriginNodeMoveMapping.php | 46 --- .../NodeMove/Dto/OriginNodeMoveMappings.php | 89 ----- .../Dto/ParentNodeMoveDestination.php | 87 ----- .../SucceedingSiblingNodeMoveDestination.php | 99 ----- .../NodeMove/Event/NodeAggregateWasMoved.php | 100 ++--- .../Classes/Feature/NodeMove/NodeMove.php | 341 +++++------------- .../Exception/NodeAggregateIsNoChild.php | 41 +++ .../Exception/NodeAggregateIsNoSibling.php | 38 ++ .../Classes/NodeDataToEventsProcessor.php | 28 +- .../Adjustment/TetheredNodeAdjustments.php | 45 +-- .../CatchUpHook/RouterCacheHook.php | 26 +- .../Projection/DocumentUriPathProjection.php | 54 +-- .../ChangeProjection.php | 29 +- 16 files changed, 374 insertions(+), 977 deletions(-) delete mode 100644 Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/CoverageNodeMoveMapping.php delete mode 100644 Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/CoverageNodeMoveMappings.php delete mode 100644 Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/OriginNodeMoveMapping.php delete mode 100644 Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/OriginNodeMoveMappings.php delete mode 100644 Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/ParentNodeMoveDestination.php delete mode 100644 Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/SucceedingSiblingNodeMoveDestination.php create mode 100644 Neos.ContentRepository.Core/Classes/SharedModel/Exception/NodeAggregateIsNoChild.php create mode 100644 Neos.ContentRepository.Core/Classes/SharedModel/Exception/NodeAggregateIsNoSibling.php diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php index f779ad9ff64..3cf3a3e1387 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php @@ -6,17 +6,14 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\DBALException; -use Doctrine\DBAL\Driver\Exception; use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection\EventCouldNotBeAppliedToContentGraph; use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection\HierarchyRelation; use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Projection\NodeRecord; use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Repository\ProjectionContentGraph; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; +use Neos\ContentRepository\Core\Feature\Common\InterdimensionalSibling; use Neos\ContentRepository\Core\Feature\NodeMove\Command\MoveNodeAggregate; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\CoverageNodeMoveMapping; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\ParentNodeMoveDestination; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\SucceedingSiblingNodeMoveDestination; use Neos\ContentRepository\Core\Feature\NodeMove\Event\NodeAggregateWasMoved; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; @@ -39,44 +36,37 @@ abstract protected function getTableNamePrefix(): string; private function whenNodeAggregateWasMoved(NodeAggregateWasMoved $event): void { $this->transactional(function () use ($event) { - foreach ($event->nodeMoveMappings as $moveNodeMapping) { - // for each materialized node in the DB which we want to adjust, we have one MoveNodeMapping. - $nodeToBeMoved = $this->getProjectionContentGraph()->findNodeByIds( + foreach ($event->succeedingSiblingsForCoverage as $succeedingSiblingForCoverage) { + $nodeToBeMoved = $this->getProjectionContentGraph()->findNodeInAggregate( $event->contentStreamId, $event->nodeAggregateId, - $moveNodeMapping->movedNodeOrigin + $succeedingSiblingForCoverage->dimensionSpacePoint ); if (is_null($nodeToBeMoved)) { throw EventCouldNotBeAppliedToContentGraph::becauseTheSourceNodeIsMissing(get_class($event)); } - foreach ($moveNodeMapping->newLocations as $newLocation) { - assert($newLocation instanceof CoverageNodeMoveMapping); - - $affectedDimensionSpacePoints = new DimensionSpacePointSet([ - $newLocation->coveredDimensionSpacePoint - ]); - - // do the move (depending on how the move target is specified) - $newParentNodeAggregateId = match ($newLocation->destination::class) { - SucceedingSiblingNodeMoveDestination::class => $this->moveNodeBeforeSucceedingSibling( - $event->contentStreamId, - $nodeToBeMoved, - $newLocation->coveredDimensionSpacePoint, - $newLocation->destination - ), - ParentNodeMoveDestination::class => $newLocation->destination->nodeAggregateId, - }; - if ($newLocation->destination instanceof ParentNodeMoveDestination) { - $this->moveNodeIntoParent( - $event->contentStreamId, - $nodeToBeMoved, - $newLocation->coveredDimensionSpacePoint, - $newLocation->destination - ); - } - $this->moveSubtreeTags($event->contentStreamId, $event->nodeAggregateId, $newParentNodeAggregateId, $newLocation->coveredDimensionSpacePoint); + if ($event->newParentNodeAggregateId) { + $this->moveNodeIntoParent( + $event->contentStreamId, + $nodeToBeMoved, + $event->newParentNodeAggregateId, + $succeedingSiblingForCoverage + ); + $this->moveSubtreeTags( + $event->contentStreamId, + $event->nodeAggregateId, + $event->newParentNodeAggregateId, + $succeedingSiblingForCoverage->dimensionSpacePoint + ); + } else { + $this->moveNodeBeforeSucceedingSibling( + $event->contentStreamId, + $nodeToBeMoved, + $succeedingSiblingForCoverage, + ); + // subtree tags stay the same if the parent doesn't change } } }); @@ -84,90 +74,72 @@ private function whenNodeAggregateWasMoved(NodeAggregateWasMoved $event): void /** * This helper is responsible for moving a single incoming HierarchyRelation of $nodeToBeMoved - * to a new location. $coveredDimensionSpacePointWhereMoveShouldHappen specifies which incoming HierarchyRelation - * should be moved. + * to a new location without changing the parent. $succeedingSiblingForCoverage specifies + * which incoming HierarchyRelation should be moved and where exactly. * * The move target is given as $succeedingSiblingNodeMoveTarget. This also specifies the new parent node. * @throws \Exception - * @throws Exception - * @return NodeAggregateId the PARENT's NodeAggregateId */ private function moveNodeBeforeSucceedingSibling( ContentStreamId $contentStreamId, NodeRecord $nodeToBeMoved, - DimensionSpacePoint $coveredDimensionSpacePointWhereMoveShouldHappen, - SucceedingSiblingNodeMoveDestination $succeedingSiblingNodeMoveDestination, - ): NodeAggregateId { + InterdimensionalSibling $succeedingSiblingForCoverage, + ): void { $projectionContentGraph = $this->getProjectionContentGraph(); // find the single ingoing hierarchy relation which we want to move $ingoingHierarchyRelation = $this->findIngoingHierarchyRelationToBeMoved( $nodeToBeMoved, $contentStreamId, - $coveredDimensionSpacePointWhereMoveShouldHappen + $succeedingSiblingForCoverage->dimensionSpacePoint ); - // find the new succeeding sibling NodeRecord; and the new parent NodeRecord (which is the - // succeeding sibling's parent). We need these records because we'll use their RelationAnchorPoints - // later. - $newSucceedingSibling = $projectionContentGraph->findNodeByIds( - $contentStreamId, - $succeedingSiblingNodeMoveDestination->nodeAggregateId, - $succeedingSiblingNodeMoveDestination->originDimensionSpacePoint - ); - if ($newSucceedingSibling === null) { - throw EventCouldNotBeAppliedToContentGraph::becauseTheTargetSucceedingSiblingNodeIsMissing( - MoveNodeAggregate::class - ); - } - - $newParent = $projectionContentGraph->findNodeByIds( - $contentStreamId, - $succeedingSiblingNodeMoveDestination->parentNodeAggregateId, - $succeedingSiblingNodeMoveDestination->parentOriginDimensionSpacePoint, - ); - if ($newParent === null) { - // this should NEVER happen; because this would mean $newSucceedingSibling - // wouldn't have a parent => invariant violation. - throw EventCouldNotBeAppliedToContentGraph::becauseTheTargetSucceedingSiblingNodesParentIsMissing( - MoveNodeAggregate::class + $newSucceedingSibling = null; + if ($succeedingSiblingForCoverage->nodeAggregateId) { + // find the new succeeding sibling NodeRecord; We need this records because we'll use its RelationAnchorPoint later. + $newSucceedingSibling = $projectionContentGraph->findNodeInAggregate( + $contentStreamId, + $succeedingSiblingForCoverage->nodeAggregateId, + $succeedingSiblingForCoverage->dimensionSpacePoint ); + if ($newSucceedingSibling === null) { + throw EventCouldNotBeAppliedToContentGraph::becauseTheTargetSucceedingSiblingNodeIsMissing( + MoveNodeAggregate::class + ); + } } - // assign new position + // fetch... $newPosition = $this->getRelationPosition( - $newParent->relationAnchorPoint, + $ingoingHierarchyRelation->parentNodeAnchor, null, - $newSucceedingSibling->relationAnchorPoint, + $newSucceedingSibling?->relationAnchorPoint, $contentStreamId, - $coveredDimensionSpacePointWhereMoveShouldHappen + $succeedingSiblingForCoverage->dimensionSpacePoint ); - // this is the actual move - $ingoingHierarchyRelation->assignNewParentNode( - $newParent->relationAnchorPoint, + // ...and assign the new position + $ingoingHierarchyRelation->assignNewPosition( $newPosition, $this->getDatabaseConnection(), $this->getTableNamePrefix() ); - - return $newParent->nodeAggregateId; } /** * This helper is responsible for moving a single incoming HierarchyRelation of $nodeToBeMoved - * to a new location. $coveredDimensionSpacePointWhereMoveShouldHappen specifies which incoming HierarchyRelation - * should be moved. + * to a new location including a change of parent. $succeedingSiblingForCoverage specifies + * which incoming HierarchyRelation should be moved and where exactly. * - * The move target is given as $parentNodeMoveTarget. We always move to the END of the children list of the - * given parent. + * The move target is given as $parentNodeAggregateId and $succeedingSiblingForCoverage. + * We always move to parent after the succeeding sibling if given (or to the end) * @throws DBALException */ private function moveNodeIntoParent( ContentStreamId $contentStreamId, NodeRecord $nodeToBeMoved, - DimensionSpacePoint $coveredDimensionSpacePointWhereMoveShouldHappen, - ParentNodeMoveDestination $parentNodeMoveDestination + NodeAggregateId $parentNodeAggregateId, + InterdimensionalSibling $succeedingSiblingForCoverage, ): void { $projectionContentGraph = $this->getProjectionContentGraph(); @@ -175,15 +147,14 @@ private function moveNodeIntoParent( $ingoingHierarchyRelation = $this->findIngoingHierarchyRelationToBeMoved( $nodeToBeMoved, $contentStreamId, - $coveredDimensionSpacePointWhereMoveShouldHappen + $succeedingSiblingForCoverage->dimensionSpacePoint ); - // find the new parent NodeRecord (specified by $parentNodeMoveTarget). - // We need this record because we'll use its RelationAnchorPoints later. - $newParent = $projectionContentGraph->findNodeByIds( + // find the new parent NodeRecord; We need this record because we'll use its RelationAnchorPoints later. + $newParent = $projectionContentGraph->findNodeInAggregate( $contentStreamId, - $parentNodeMoveDestination->nodeAggregateId, - $parentNodeMoveDestination->originDimensionSpacePoint + $parentNodeAggregateId, + $succeedingSiblingForCoverage->dimensionSpacePoint ); if ($newParent === null) { throw EventCouldNotBeAppliedToContentGraph::becauseTheTargetParentNodeIsMissing( @@ -191,14 +162,28 @@ private function moveNodeIntoParent( ); } + $newSucceedingSibling = null; + if ($succeedingSiblingForCoverage->nodeAggregateId) { + // find the new succeeding sibling NodeRecord; We need this record because we'll use its RelationAnchorPoint later. + $newSucceedingSibling = $projectionContentGraph->findNodeInAggregate( + $contentStreamId, + $succeedingSiblingForCoverage->nodeAggregateId, + $succeedingSiblingForCoverage->dimensionSpacePoint + ); + if ($newSucceedingSibling === null) { + throw EventCouldNotBeAppliedToContentGraph::becauseTheTargetSucceedingSiblingNodeIsMissing( + MoveNodeAggregate::class + ); + } + } + // assign new position $newPosition = $this->getRelationPosition( $newParent->relationAnchorPoint, null, - // move to end of children - null, + $newSucceedingSibling?->relationAnchorPoint, $contentStreamId, - $coveredDimensionSpacePointWhereMoveShouldHappen + $succeedingSiblingForCoverage->dimensionSpacePoint ); // this is the actual move diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/CoverageNodeMoveMapping.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/CoverageNodeMoveMapping.php deleted file mode 100644 index 47273e8118d..00000000000 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/CoverageNodeMoveMapping.php +++ /dev/null @@ -1,75 +0,0 @@ - $array - */ - public static function fromArray(array $array): self - { - if (!empty($array['newSucceedingSibling'])) { - return new self( - DimensionSpacePoint::fromArray($array['coveredDimensionSpacePoint']), - SucceedingSiblingNodeMoveDestination::fromArray($array['newSucceedingSibling']), - ); - } elseif (!empty($array['newParent'])) { - return new self( - DimensionSpacePoint::fromArray($array['coveredDimensionSpacePoint']), - ParentNodeMoveDestination::fromArray($array['newParent']), - ); - } else { - throw new \RuntimeException('!!!'); - } - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - if ($this->destination instanceof SucceedingSiblingNodeMoveDestination) { - return [ - 'coveredDimensionSpacePoint' => $this->coveredDimensionSpacePoint, - 'newSucceedingSibling' => $this->destination - ]; - } elseif ($this->destination instanceof ParentNodeMoveDestination) { - return [ - 'coveredDimensionSpacePoint' => $this->coveredDimensionSpacePoint, - 'newParent' => $this->destination - ]; - } else { - throw new \RuntimeException('!!!'); - } - } -} diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/CoverageNodeMoveMappings.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/CoverageNodeMoveMappings.php deleted file mode 100644 index 18b426add1b..00000000000 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/CoverageNodeMoveMappings.php +++ /dev/null @@ -1,88 +0,0 @@ - - * @api DTO of {@see NodeAggregateWasMoved} event - */ -final class CoverageNodeMoveMappings implements \IteratorAggregate, \Countable, \JsonSerializable -{ - /** - * @var array - */ - private array $mappings; - - /** - * @param array $values - */ - private function __construct(array $values) - { - $this->mappings = $values; - } - - /** - * @param array|CoverageNodeMoveMapping> $mappings - */ - public static function fromArray(array $mappings): self - { - $processedMappings = []; - foreach ($mappings as $mapping) { - if (is_array($mapping)) { - $processedMappings[] = CoverageNodeMoveMapping::fromArray($mapping); - } elseif ($mapping instanceof CoverageNodeMoveMapping) { - $processedMappings[] = $mapping; - } else { - /** @var mixed $mapping */ - throw new \InvalidArgumentException( - sprintf( - 'Invalid NodeMoveMapping. Expected instance of %s, got: %s', - CoverageNodeMoveMapping::class, - is_object($mapping) ? get_class($mapping) : gettype($mapping) - ), - 1547811318 - ); - } - } - return new self($processedMappings); - } - - public static function create(CoverageNodeMoveMapping ...$coverageNodeMoveMappings): self - { - return new self(array_values($coverageNodeMoveMappings)); - } - - - /** - * @return \Traversable - */ - public function getIterator(): \Traversable - { - yield from $this->mappings; - } - - public function count(): int - { - return count($this->mappings); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - return $this->mappings; - } -} diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/OriginNodeMoveMapping.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/OriginNodeMoveMapping.php deleted file mode 100644 index 14bd2a5952b..00000000000 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/OriginNodeMoveMapping.php +++ /dev/null @@ -1,46 +0,0 @@ - $array - */ - public static function fromArray(array $array): self - { - return new self( - OriginDimensionSpacePoint::fromArray($array['movedNodeOrigin']), - CoverageNodeMoveMappings::fromArray($array['newLocations']), - ); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - return [ - 'movedNodeOrigin' => $this->movedNodeOrigin, - 'newLocations' => $this->newLocations, - ]; - } -} diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/OriginNodeMoveMappings.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/OriginNodeMoveMappings.php deleted file mode 100644 index b7fa09da0eb..00000000000 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/OriginNodeMoveMappings.php +++ /dev/null @@ -1,89 +0,0 @@ - - * @api DTO of {@see NodeAggregateWasMoved} event - */ -final class OriginNodeMoveMappings implements \IteratorAggregate, \Countable, \JsonSerializable -{ - /** - * @var array - */ - private array $mappings; - - /** - * @param array $values - */ - private function __construct(array $values) - { - $this->mappings = $values; - } - - /** - * @param array|OriginNodeMoveMapping> $mappings - */ - public static function fromArray(array $mappings): self - { - $processedMappings = []; - foreach ($mappings as $mapping) { - if (is_array($mapping)) { - $processedMappings[] = OriginNodeMoveMapping::fromArray($mapping); - } elseif ($mapping instanceof OriginNodeMoveMapping) { - $processedMappings[] = $mapping; - } else { - /** @var mixed $mapping */ - throw new \InvalidArgumentException( - sprintf( - 'Invalid NodeMoveMapping. Expected instance of %s, got: %s', - OriginNodeMoveMapping::class, - is_object($mapping) ? get_class($mapping) : gettype($mapping) - ), - 1547811318 - ); - } - } - return new self($processedMappings); - } - - public static function create(OriginNodeMoveMapping ...$originNodeMoveMappings): self - { - return new self(array_values($originNodeMoveMappings)); - } - - /** - * @return \Traversable - */ - public function getIterator(): \Traversable - { - yield from $this->mappings; - } - - public function count(): int - { - return count($this->mappings); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - return $this->mappings; - } -} diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/ParentNodeMoveDestination.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/ParentNodeMoveDestination.php deleted file mode 100644 index bfcbf872d10..00000000000 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/ParentNodeMoveDestination.php +++ /dev/null @@ -1,87 +0,0 @@ - `ParentNodeMoveDestination(node1)` - * - * - you want to move the node INTO another node. - * ``` - * - node1 - * - node2 <-- source: we want to move this node - * - node3 - * - <-- destination - * ``` - * => `ParentNodeMoveDestination(node3)` - * - * For all other cases, use {@see SucceedingSiblingNodeMoveDestination}. - * - * @api DTO of {@see NodeAggregateWasMoved} event - */ -final readonly class ParentNodeMoveDestination implements \JsonSerializable -{ - private function __construct( - public NodeAggregateId $nodeAggregateId, - public OriginDimensionSpacePoint $originDimensionSpacePoint - ) { - } - - public static function create( - NodeAggregateId $nodeAggregateId, - OriginDimensionSpacePoint $originDimensionSpacePoint - ): self { - return new self($nodeAggregateId, $originDimensionSpacePoint); - } - - /** - * @param array $array - */ - public static function fromArray(array $array): self - { - return new self( - NodeAggregateId::fromString($array['nodeAggregateId']), - OriginDimensionSpacePoint::fromArray($array['originDimensionSpacePoint']) - ); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - return [ - 'nodeAggregateId' => $this->nodeAggregateId, - 'originDimensionSpacePoint' => $this->originDimensionSpacePoint, - ]; - } - - public function toJson(): string - { - return json_encode($this, JSON_THROW_ON_ERROR); - } -} diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/SucceedingSiblingNodeMoveDestination.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/SucceedingSiblingNodeMoveDestination.php deleted file mode 100644 index 182f1e80de2..00000000000 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Dto/SucceedingSiblingNodeMoveDestination.php +++ /dev/null @@ -1,99 +0,0 @@ - `SucceedingSiblingNodeMoveDestination(node1)` - * - * - move nodes to a different parent, and before a specific sibling. - * ``` - * - node1 - * - <-- destination - * - node2 - * - node3 <-- source: we want to move this node - * ``` - * => `SucceedingSiblingNodeMoveDestination(node2)` - * - * @api DTO of {@see NodeAggregateWasMoved} event - */ -final readonly class SucceedingSiblingNodeMoveDestination implements \JsonSerializable -{ - private function __construct( - public NodeAggregateId $nodeAggregateId, - public OriginDimensionSpacePoint $originDimensionSpacePoint, - public NodeAggregateId $parentNodeAggregateId, - public OriginDimensionSpacePoint $parentOriginDimensionSpacePoint - ) { - } - - public static function create( - NodeAggregateId $nodeAggregateId, - OriginDimensionSpacePoint $originDimensionSpacePoint, - NodeAggregateId $parentNodeAggregateId, - OriginDimensionSpacePoint $parentOriginDimensionSpacePoint - ): self { - return new self( - $nodeAggregateId, - $originDimensionSpacePoint, - $parentNodeAggregateId, - $parentOriginDimensionSpacePoint - ); - } - - /** - * @param array $array - */ - public static function fromArray(array $array): self - { - return new self( - NodeAggregateId::fromString($array['nodeAggregateId']), - OriginDimensionSpacePoint::fromArray($array['originDimensionSpacePoint']), - NodeAggregateId::fromString($array['parentNodeAggregateId']), - OriginDimensionSpacePoint::fromArray($array['parentOriginDimensionSpacePoint']) - ); - } - - /** - * @return array - */ - public function jsonSerialize(): array - { - return [ - 'nodeAggregateId' => $this->nodeAggregateId, - 'originDimensionSpacePoint' => $this->originDimensionSpacePoint, - 'parentNodeAggregateId' => $this->parentNodeAggregateId, - 'parentOriginDimensionSpacePoint' => $this->parentOriginDimensionSpacePoint, - ]; - } - - public function toJson(): string - { - return json_encode($this, JSON_THROW_ON_ERROR); - } -} diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Event/NodeAggregateWasMoved.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Event/NodeAggregateWasMoved.php index a25538eef87..6bf52b0cf76 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Event/NodeAggregateWasMoved.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/Event/NodeAggregateWasMoved.php @@ -4,17 +4,17 @@ namespace Neos\ContentRepository\Core\Feature\NodeMove\Event; +use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\EventStore\EventInterface; use Neos\ContentRepository\Core\Feature\Common\EmbedsContentStreamAndNodeAggregateId; +use Neos\ContentRepository\Core\Feature\Common\InterdimensionalSibling; +use Neos\ContentRepository\Core\Feature\Common\InterdimensionalSiblings; use Neos\ContentRepository\Core\Feature\Common\PublishableToOtherContentStreamsInterface; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\OriginNodeMoveMappings; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\ParentNodeMoveDestination; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\SucceedingSiblingNodeMoveDestination; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; /** - * A node aggregate was moved in a content stream as defined in the node move mappings. + * A node aggregate was moved in a content stream * * We always move a node aggregate identified by a NodeAggregateId (in a given ContentStreamId); or * parts of the NodeAggregate. @@ -22,49 +22,29 @@ * The inner structure of the event is rather complicated, that's why the following picture shows it: * * ``` - *┌───────────────────────────┐ - *│ NodeAggregateWasMoved │ - *│-> contains NodeAggregateId│ - *└─────────┬─────────────────┘ + *┌───────────────────────────────────┐ + *│ NodeAggregateWasMoved │ + *│-> contains NodeAggregateId │ + *│-> contains parent NodeAggregateId │ + *└─────────┬─────────────────────────┘ * │ - * │ ┌────────────────────────────────────────────────┐ - * │ │ OriginNodeMoveMapping │ - * │ *│ -> contains OriginDimensionSpacePoint │ - * └───▶ │ - * │ (1 per OriginDimensionSpacePoint to be moved) │ - * └──────┬─────────────────────────────────────────┘ - * │ - * │ ┌───────────────────────────────────┐ - * │ │ CoverageNodeMoveMapping │ ┌─────────────────────────────┐ - * │ *│ -> coveredDimensionSpacePoint │ │ NoveMoveDestination │ - * └───▶ │ │ │ - * │ ?newSucceedingSibling, ?newParent ├───▶ nodeAggregateId │ - * │ (exactly one must be set) │ │ originDimensionSpacePoint │ - * │ │ └─────────────────────────────┘ - * │ (1 per coveredDimensionSpacePoint │ - * │ to be moved - for each edge in │ - * └───────────────────────────────────┘ + * │ ┌────────────────────────────────────────────────────┐ + * │ │ InterdimensionalSibling │ + * │ │ -> contains DimensionSpacePoint │ + * │ *│ -> contains succeeding sibling NodeAggregateId │ + * └───▶ │ + * │ (1 per affected dimension space point) │ + * └────────────────────────────────────────────────────┘ * ``` * * - We move some parts of a single NodeAggregate (`NodeAggregateWasMoved`). - * - For each OriginDimensionSpacePoint (where a materialized Node exists which should be moved), - * an `OriginNodeMoveMapping` exists. - * - For each Node which we want to move, we need to specify where the *incoming edges* of the node - * should be (if they should be moved). For each of these, a `CoverageNodeMoveMapping` exists. - * - * ## Specifying the Target of a Move inside `CoverageNodeMoveMapping` - * - * For a given `DimensionSpacePoint`, we specify the target node of the move as follows: - * - * - for *succeeding siblings* (see {@see SucceedingSiblingNodeMoveDestination}), we specify the - * newSucceedingSibling ID and its OriginDimensionSpacePoint; and additionally its parent ID - * and OriginDimensionSpacePoint. The parent is strictly redundant, but can ease projection - * implementer's lives. - * - * HINT: The parent is ALWAYS specified, so it is also specified *if it did not change*. - * - * - If you want to move something at the END of a children list (or as the first child, when no child - * exists yet), you specify `newParent` via {@see ParentNodeMoveDestination}. + * - If given, a single parent NodeAggregateId is provided and to be used for all affected DimensionSpacePoints. + * Else, no new parent will be set for any on the variants. + * - For each affected DimensionSpacePoint, an optional succeeding sibling is provided. + * -- If a single node is to be moved to the end, the succeeding sibling NodeAggregateId is null + * -- If a single node is to be moved to the start, the previous first sibling is to be set as succeeding sibling + * -- If a single node is not to be moved at all, e.g. if no siblings can be determined, it is considered unaffected + * and it (its DSP respectively) is not part of the InterdimensionalSibling collection * * @api events are the persistence-API of the content repository */ @@ -76,7 +56,8 @@ public function __construct( public ContentStreamId $contentStreamId, public NodeAggregateId $nodeAggregateId, - public OriginNodeMoveMappings $nodeMoveMappings, + public ?NodeAggregateId $newParentNodeAggregateId, + public InterdimensionalSiblings $succeedingSiblingsForCoverage, ) { } @@ -95,16 +76,43 @@ public function createCopyForContentStream(ContentStreamId $targetContentStreamI return new self( $targetContentStreamId, $this->nodeAggregateId, - $this->nodeMoveMappings, + $this->newParentNodeAggregateId, + $this->succeedingSiblingsForCoverage, ); } public static function fromArray(array $values): self { + if (array_key_exists('nodeMoveMappings', $values)) { + $newParentNodeAggregateId = null; + $succeedingSiblings = []; + foreach ($values['nodeMoveMappings'] as $nodeMoveMapping) { + // we don't care about origins anymore + foreach ($nodeMoveMapping['newLocations'] as $newLocation) { + if (array_key_exists('newParent', $newLocation)) { + $newParentNodeAggregateId = NodeAggregateId::fromString($newLocation['newParent']); + } + $succeedingSiblings[] = new InterdimensionalSibling( + DimensionSpacePoint::fromArray($newLocation['coveredDimensionSpacePoint']), + ($newLocation['newSucceedingSibling'] ?? null) + ? NodeAggregateId::fromString($newLocation['newSucceedingSibling']) + : null + ); + } + } + $succeedingSiblingsForCoverage = new InterdimensionalSiblings(...$succeedingSiblings); + } else { + $newParentNodeAggregateId = $values['newParentNodeAggregateId'] === null + ? null + : NodeAggregateId::fromString($values['newParentNodeAggregateId']); + $succeedingSiblingsForCoverage = InterdimensionalSiblings::fromArray($values['succeedingSiblingsForCoverage']); + } + return new self( ContentStreamId::fromString($values['contentStreamId']), NodeAggregateId::fromString($values['nodeAggregateId']), - OriginNodeMoveMappings::fromArray($values['nodeMoveMappings']), + $newParentNodeAggregateId, + $succeedingSiblingsForCoverage, ); } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php index 21f63678cc8..15e173d89c0 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php @@ -19,27 +19,19 @@ use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePointSet; use Neos\ContentRepository\Core\DimensionSpace\Exception\DimensionSpacePointNotFound; -use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\EventStore\Events; use Neos\ContentRepository\Core\EventStore\EventsToPublish; +use Neos\ContentRepository\Core\Feature\Common\InterdimensionalSibling; +use Neos\ContentRepository\Core\Feature\Common\InterdimensionalSiblings; use Neos\ContentRepository\Core\Feature\Common\NodeAggregateEventPublisher; use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; use Neos\ContentRepository\Core\Feature\NodeMove\Command\MoveNodeAggregate; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\CoverageNodeMoveMapping; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\CoverageNodeMoveMappings; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\OriginNodeMoveMapping; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\OriginNodeMoveMappings; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\ParentNodeMoveDestination; use Neos\ContentRepository\Core\Feature\NodeMove\Dto\RelationDistributionStrategy; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\SucceedingSiblingNodeMoveDestination; use Neos\ContentRepository\Core\Feature\NodeMove\Event\NodeAggregateWasMoved; -use Neos\ContentRepository\Core\Projection\ContentGraph\ContentSubgraphInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindPrecedingSiblingNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindSucceedingSiblingNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\Pagination\Pagination; -use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; -use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; use Neos\ContentRepository\Core\SharedModel\Exception\ContentStreamDoesNotExistYet; use Neos\ContentRepository\Core\SharedModel\Exception\NodeAggregateCurrentlyDoesNotExist; @@ -199,29 +191,20 @@ private function handleMoveNodeAggregate( } } - /** @var OriginNodeMoveMapping[] $originNodeMoveMappings */ - $originNodeMoveMappings = []; - foreach ($nodeAggregate->occupiedDimensionSpacePoints as $movedNodeOrigin) { - $originNodeMoveMappings[] = new OriginNodeMoveMapping( - $movedNodeOrigin, - $this->resolveCoverageNodeMoveMappings( - $contentStreamId, - $nodeAggregate, - $command->newParentNodeAggregateId, - $command->newPrecedingSiblingNodeAggregateId, - $command->newSucceedingSiblingNodeAggregateId, - $movedNodeOrigin, - $affectedDimensionSpacePoints, - $contentRepository - ) - ); - } - $events = Events::with( new NodeAggregateWasMoved( $contentStreamId, $command->nodeAggregateId, - OriginNodeMoveMappings::create(...$originNodeMoveMappings) + $command->newParentNodeAggregateId, + $this->resolveInterdimensionalSiblingsForMove( + $contentStreamId, + $command->dimensionSpacePoint, + $affectedDimensionSpacePoints, + $command->newSucceedingSiblingNodeAggregateId, + $command->newPrecedingSiblingNodeAggregateId, + $command->newParentNodeAggregateId !== null, + $contentRepository + ) ) ); @@ -239,43 +222,6 @@ private function handleMoveNodeAggregate( ); } - /** - * Resolves the new parents on a per-dimension-space-point basis - * - * If no parent node aggregate is defined, it will be resolved from the already evaluated new succeeding siblings. - * - * @todo move to content graph for more efficient calculation, if possible - */ - private function resolveNewParentAssignments( - /** The content stream the move operation is performed in */ - ContentStreamId $contentStreamId, - /** The parent node aggregate's id*/ - NodeAggregateId $parentId, - DimensionSpace\DimensionSpacePoint $coveredDimensionSpacePoint, - ContentRepository $contentRepository - ): CoverageNodeMoveMapping { - $contentSubgraph = $contentRepository->getContentGraph()->getSubgraph( - $contentStreamId, - $coveredDimensionSpacePoint, - VisibilityConstraints::withoutRestrictions() - ); - $parentNode = $contentSubgraph->findNodeById($parentId); - if ($parentNode === null) { - throw new \InvalidArgumentException( - 'Parent ' . $parentId->value . ' not found in subgraph ' . json_encode($contentSubgraph), - 1667596931 - ); - } - - return CoverageNodeMoveMapping::createForNewParent( - $coveredDimensionSpacePoint, - ParentNodeMoveDestination::create( - $parentId, - $parentNode->originDimensionSpacePoint - ) - ); - } - private function resolveAffectedDimensionSpacePointSet( NodeAggregate $nodeAggregate, Dto\RelationDistributionStrategy $relationDistributionStrategy, @@ -292,204 +238,111 @@ private function resolveAffectedDimensionSpacePointSet( }; } - private function findSibling( - ContentSubgraphInterface $contentSubgraph, - ?NodeAggregateId $parentId, - NodeAggregateId $siblingId - ): ?Node { - $siblingCandidate = $contentSubgraph->findNodeById($siblingId); - if ($parentId && $siblingCandidate) { - // If a parent node aggregate is explicitly given, all siblings must have this parent - $parent = $contentSubgraph->findParentNode($siblingId); - if (is_null($parent)) { - throw new \InvalidArgumentException( - 'Parent ' . $parentId->value . ' not found in subgraph ' . json_encode($contentSubgraph), - 1645366837 - ); - } - if ($parent->nodeAggregateId->equals($parentId)) { - return $siblingCandidate; - } - } else { - return $siblingCandidate; - } - - return null; - } - - private function resolveSucceedingSiblingFromOriginSiblings( - NodeAggregateId $nodeAggregateId, - ?NodeAggregateId $parentId, - ?NodeAggregateId $precedingSiblingId, - ?NodeAggregateId $succeedingSiblingId, - ContentSubgraphInterface $currentContentSubgraph, - ContentSubgraphInterface $originContentSubgraph - ): ?Node { - $succeedingSibling = null; - $precedingSiblingCandidates = iterator_to_array( - $precedingSiblingId - ? $originContentSubgraph->findPrecedingSiblingNodes($precedingSiblingId, FindPrecedingSiblingNodesFilter::create()) - : Nodes::createEmpty() - ); - $succeedingSiblingCandidates = iterator_to_array( - $succeedingSiblingId - ? $originContentSubgraph->findSucceedingSiblingNodes( - $succeedingSiblingId, - FindSucceedingSiblingNodesFilter::create() - ) - : Nodes::createEmpty() - ); - /* @var $precedingSiblingCandidates Node[] */ - /* @var $succeedingSiblingCandidates Node[] */ - $maximumIndex = max(count($succeedingSiblingCandidates), count($precedingSiblingCandidates)); - for ($i = 0; $i < $maximumIndex; $i++) { - // try successors of same distance first - if (isset($succeedingSiblingCandidates[$i])) { - if ($succeedingSiblingCandidates[$i]->nodeAggregateId->equals($nodeAggregateId)) { - \array_splice($succeedingSiblingCandidates, $i, 1); - } - $succeedingSibling = $this->findSibling( - $currentContentSubgraph, - $parentId, - $succeedingSiblingCandidates[$i]->nodeAggregateId - ); - if ($succeedingSibling) { - break; - } - } - if (isset($precedingSiblingCandidates[$i])) { - /** @var NodeAggregateId $precedingSiblingId can only be the case if not null */ - if ($precedingSiblingCandidates[$i]->nodeAggregateId->equals($nodeAggregateId)) { - \array_splice($precedingSiblingCandidates, $i, 1); - } - $precedingSibling = $this->findSibling( - $currentContentSubgraph, - $parentId, - $precedingSiblingCandidates[$i]->nodeAggregateId - ); - if ($precedingSibling) { - $alternateSucceedingSiblings = $currentContentSubgraph->findSucceedingSiblingNodes( - $precedingSiblingId, - FindSucceedingSiblingNodesFilter::create(pagination: Pagination::fromLimitAndOffset(1, 0)), - ); - if (count($alternateSucceedingSiblings) > 0) { - $succeedingSibling = $alternateSucceedingSiblings->first(); - break; - } - } - } - } - - return $succeedingSibling; - } - - private function resolveCoverageNodeMoveMappings( - /** The content stream the move operation is performed in */ + /** + * @param bool $completeSet Whether unresolvable siblings should be added as null or not at all + * True when a new parent is set, which will result of the node being added at the end + * False when no new parent is set, which will result in the node not being moved + */ + private function resolveInterdimensionalSiblingsForMove( ContentStreamId $contentStreamId, - /** The node aggregate to be moved */ - NodeAggregate $nodeAggregate, - /** The parent node aggregate id, has precedence over siblings when in doubt */ - ?NodeAggregateId $parentId, - /** The planned preceding sibling's node aggregate id */ - ?NodeAggregateId $precedingSiblingId, - /** The planned succeeding sibling's node aggregate id */ - ?NodeAggregateId $succeedingSiblingId, - /** A dimension space point occupied by the node aggregate to be moved */ - OriginDimensionSpacePoint $originDimensionSpacePoint, - /** The dimension space points affected by the move operation */ + DimensionSpacePoint $selectedDimensionSpacePoint, DimensionSpacePointSet $affectedDimensionSpacePoints, - ContentRepository $contentRepository - ): CoverageNodeMoveMappings { - /** @var CoverageNodeMoveMapping[] $coverageNodeMoveMappings */ - $coverageNodeMoveMappings = []; - - $visibilityConstraints = VisibilityConstraints::withoutRestrictions(); - $originContentSubgraph = $contentRepository->getContentGraph()->getSubgraph( + ?NodeAggregateId $succeedingSiblingId, + ?NodeAggregateId $precedingSiblingId, + bool $completeSet, + ContentRepository $contentRepository, + ): InterdimensionalSiblings { + $selectedSubgraph = $contentRepository->getContentGraph()->getSubgraph( $contentStreamId, - $originDimensionSpacePoint->toDimensionSpacePoint(), - $visibilityConstraints + $selectedDimensionSpacePoint, + VisibilityConstraints::withoutRestrictions() ); - foreach ( - $nodeAggregate->getCoverageByOccupant($originDimensionSpacePoint) - ->getIntersection($affectedDimensionSpacePoints) as $dimensionSpacePoint - ) { - $contentSubgraph = $contentRepository->getContentGraph()->getSubgraph( + $alternativeSucceedingSiblingIds = $succeedingSiblingId + ? $selectedSubgraph->findSucceedingSiblingNodes( + $succeedingSiblingId, + FindSucceedingSiblingNodesFilter::create() + )->getIds() + : null; + $alternativePrecedingSiblingIds = $precedingSiblingId + ? $selectedSubgraph->findPrecedingSiblingNodes( + $precedingSiblingId, + FindPrecedingSiblingNodesFilter::create() + )->getIds() + : null; + + $interdimensionalSiblings = []; + foreach ($affectedDimensionSpacePoints as $dimensionSpacePoint) { + $variantSubgraph = $contentRepository->getContentGraph()->getSubgraph( $contentStreamId, $dimensionSpacePoint, - $visibilityConstraints + VisibilityConstraints::withoutRestrictions() ); - - $succeedingSibling = $succeedingSiblingId - ? $this->findSibling($contentSubgraph, $parentId, $succeedingSiblingId) - : null; - if (!$succeedingSibling) { - $precedingSibling = $precedingSiblingId - ? $this->findSibling($contentSubgraph, $parentId, $precedingSiblingId) - : null; - if ($precedingSiblingId && $precedingSibling) { - $alternateSucceedingSiblings = $contentSubgraph->findSucceedingSiblingNodes( - $precedingSiblingId, - FindSucceedingSiblingNodesFilter::create(pagination: Pagination::fromLimitAndOffset(1, 0)), + if ($succeedingSiblingId) { + $variantSucceedingSibling = $variantSubgraph->findNodeById($succeedingSiblingId); + if ($variantSucceedingSibling) { + // a) happy path, the explicitly requested succeeding sibling also exists in this dimension space point + $interdimensionalSiblings[] = new InterdimensionalSibling( + $dimensionSpacePoint, + $variantSucceedingSibling->nodeAggregateId, ); - if (count($alternateSucceedingSiblings) > 0) { - $succeedingSibling = $alternateSucceedingSiblings->first(); + continue; + } + + // check the other siblings succeeding in the selected dimension space point + foreach ($alternativeSucceedingSiblingIds ?: [] as $alternativeSucceedingSiblingId) { + $alternativeVariantSucceedingSibling = $variantSubgraph->findNodeById($alternativeSucceedingSiblingId); + if (!$alternativeVariantSucceedingSibling) { + continue; } - } else { - $succeedingSibling = $this->resolveSucceedingSiblingFromOriginSiblings( - $nodeAggregate->nodeAggregateId, - $parentId, - $precedingSiblingId, - $succeedingSiblingId, - $contentSubgraph, - $originContentSubgraph + // b) one of the further succeeding sibling exists in this dimension space point + $interdimensionalSiblings[] = new InterdimensionalSibling( + $dimensionSpacePoint, + $alternativeVariantSucceedingSibling->nodeAggregateId, ); + continue 2; } } - if ($succeedingSibling) { - // for the event payload, we additionally need the parent of the succeeding sibling - $parentOfSucceedingSibling = $contentSubgraph->findParentNode($succeedingSibling->nodeAggregateId); - if ($parentOfSucceedingSibling === null) { - throw new \InvalidArgumentException( - 'Parent of succeeding sibling ' . $succeedingSibling->nodeAggregateId->value - . ' not found in subgraph ' . json_encode($contentSubgraph), - 1667817639 - ); + if ($precedingSiblingId) { + $variantPrecedingSiblingId = null; + $variantPrecedingSibling = $variantSubgraph->findNodeById($precedingSiblingId); + if ($variantPrecedingSibling) { + // c) happy path, the explicitly requested preceding sibling also exists in this dimension space point + $variantPrecedingSiblingId = $precedingSiblingId; + } elseif ($alternativePrecedingSiblingIds) { + // check the other siblings preceding in the selected dimension space point + foreach ($alternativePrecedingSiblingIds as $alternativePrecedingSiblingId) { + $alternativeVariantSucceedingSibling = $variantSubgraph->findNodeById($alternativePrecedingSiblingId); + if ($alternativeVariantSucceedingSibling) { + // d) one of the further preceding siblings exists in this dimension space point + $variantPrecedingSiblingId = $alternativePrecedingSiblingId; + break; + } + } } - $coverageNodeMoveMappings[] = CoverageNodeMoveMapping::createForNewSucceedingSibling( - $dimensionSpacePoint, - SucceedingSiblingNodeMoveDestination::create( - $succeedingSibling->nodeAggregateId, - $succeedingSibling->originDimensionSpacePoint, - $parentOfSucceedingSibling->nodeAggregateId, - $parentOfSucceedingSibling->originDimensionSpacePoint, - ) - ); - } else { - // preceding / succeeding siblings could not be resolved for a given covered DSP - // -> Fall back to resolving based on the parent - - if ($parentId === null) { - // if parent ID is not given, use the parent of the original node, because we want to move - // to the end of the sibling list. - $parentId = $contentSubgraph->findParentNode($nodeAggregate->nodeAggregateId)?->nodeAggregateId; - if ($parentId === null) { - throw new \InvalidArgumentException( - 'Parent ' . $parentId . ' not found in subgraph ' . json_encode($contentSubgraph), - 1667597013 - ); - } + if ($variantPrecedingSiblingId) { + $succeedingSibling = $variantSubgraph->findSucceedingSiblingNodes( + $variantPrecedingSiblingId, + FindSucceedingSiblingNodesFilter::create(pagination: Pagination::fromLimitAndOffset(1, 0)) + )->first(); + $interdimensionalSiblings[] = new InterdimensionalSibling( + $dimensionSpacePoint, + $succeedingSibling?->nodeAggregateId, + ); + continue; } - $coverageNodeMoveMappings[] = $this->resolveNewParentAssignments( - $contentStreamId, - $parentId, + } + + // e) fallback: if the set is to be completed, we add an empty sibling, otherwise we just don't + if ($completeSet) { + $interdimensionalSiblings[] = new InterdimensionalSibling( $dimensionSpacePoint, - $contentRepository + null, ); } } - return CoverageNodeMoveMappings::create(...$coverageNodeMoveMappings); + return new InterdimensionalSiblings(...$interdimensionalSiblings); } } diff --git a/Neos.ContentRepository.Core/Classes/SharedModel/Exception/NodeAggregateIsNoChild.php b/Neos.ContentRepository.Core/Classes/SharedModel/Exception/NodeAggregateIsNoChild.php new file mode 100644 index 00000000000..80807f60f97 --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/SharedModel/Exception/NodeAggregateIsNoChild.php @@ -0,0 +1,41 @@ +value + . '" is no child of node aggregate "' . $parentNodeAggregateId->value + . '" but was expected to be in dimension space point ' + . json_encode($dimensionSpacePoint, JSON_THROW_ON_ERROR), + 1713081351 + ); + } +} diff --git a/Neos.ContentRepository.Core/Classes/SharedModel/Exception/NodeAggregateIsNoSibling.php b/Neos.ContentRepository.Core/Classes/SharedModel/Exception/NodeAggregateIsNoSibling.php new file mode 100644 index 00000000000..9835d927baa --- /dev/null +++ b/Neos.ContentRepository.Core/Classes/SharedModel/Exception/NodeAggregateIsNoSibling.php @@ -0,0 +1,38 @@ +value + . '" is no sibling of node aggregate "' . $referenceNodeAggregateId->value + . '" but was expected to be in dimension space point ' + . json_encode($dimensionSpacePoint, JSON_THROW_ON_ERROR), + 1713081020 + ); + } +} diff --git a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php index a621f5309e2..9c699871490 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php +++ b/Neos.ContentRepository.LegacyNodeMigration/Classes/NodeDataToEventsProcessor.php @@ -15,15 +15,11 @@ use Neos\ContentRepository\Core\DimensionSpace\VariantType; use Neos\ContentRepository\Core\EventStore\EventInterface; use Neos\ContentRepository\Core\EventStore\EventNormalizer; +use Neos\ContentRepository\Core\Feature\Common\InterdimensionalSibling; use Neos\ContentRepository\Core\Feature\Common\InterdimensionalSiblings; use Neos\ContentRepository\Core\Feature\NodeCreation\Event\NodeAggregateWithNodeWasCreated; use Neos\ContentRepository\Core\Feature\NodeModification\Dto\PropertyValuesToWrite; use Neos\ContentRepository\Core\Feature\NodeModification\Event\NodePropertiesWereSet; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\CoverageNodeMoveMapping; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\CoverageNodeMoveMappings; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\OriginNodeMoveMapping; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\OriginNodeMoveMappings; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\SucceedingSiblingNodeMoveDestination; use Neos\ContentRepository\Core\Feature\NodeMove\Event\NodeAggregateWasMoved; use Neos\ContentRepository\Core\Feature\NodeReferencing\Dto\SerializedNodeReferences; use Neos\ContentRepository\Core\Feature\NodeReferencing\Event\NodeReferencesWereSet; @@ -475,23 +471,13 @@ private function createNodeVariant(NodeAggregateId $nodeAggregateId, OriginDimen $this->exportEvent(new NodeAggregateWasMoved( $this->contentStreamId, $nodeAggregateId, - OriginNodeMoveMappings::fromArray([ - new OriginNodeMoveMapping( - $originDimensionSpacePoint, - CoverageNodeMoveMappings::create( - CoverageNodeMoveMapping::createForNewSucceedingSibling( - $originDimensionSpacePoint->toDimensionSpacePoint(), - SucceedingSiblingNodeMoveDestination::create( - $parentNodeAggregate->nodeAggregateId, - $variantSourceOriginDimensionSpacePoint, - - $nodeAggregate->getVariant($variantSourceOriginDimensionSpacePoint)->parentNodeAggregateId, - $nodeAggregate->getVariant($variantSourceOriginDimensionSpacePoint)->originDimensionSpacePoint - ) - ) - ) + $parentNodeAggregate->nodeAggregateId, + new InterdimensionalSiblings( + new InterdimensionalSibling( + $originDimensionSpacePoint->toDimensionSpacePoint(), + null ) - ]) + ) )); } } diff --git a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php index fcdc1104af6..d0f0479a9ba 100644 --- a/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php +++ b/Neos.ContentRepository.StructureAdjustment/src/Adjustment/TetheredNodeAdjustments.php @@ -8,14 +8,11 @@ use Neos\ContentRepository\Core\DimensionSpace; use Neos\ContentRepository\Core\EventStore\Events; use Neos\ContentRepository\Core\EventStore\EventsToPublish; +use Neos\ContentRepository\Core\Feature\Common\InterdimensionalSibling; +use Neos\ContentRepository\Core\Feature\Common\InterdimensionalSiblings; use Neos\ContentRepository\Core\Feature\Common\NodeVariationInternals; use Neos\ContentRepository\Core\Feature\Common\TetheredNodeInternals; use Neos\ContentRepository\Core\Feature\ContentStreamEventStreamName; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\CoverageNodeMoveMapping; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\CoverageNodeMoveMappings; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\OriginNodeMoveMapping; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\OriginNodeMoveMappings; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\SucceedingSiblingNodeMoveDestination; use Neos\ContentRepository\Core\Feature\NodeMove\Event\NodeAggregateWasMoved; use Neos\ContentRepository\Core\Infrastructure\Property\PropertyConverter; use Neos\ContentRepository\Core\NodeType\NodeType; @@ -24,7 +21,6 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Filter\FindChildNodesFilter; use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\VisibilityConstraints; -use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; use Neos\ContentRepository\Core\SharedModel\Node\NodeName; use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; use Neos\EventStore\Model\EventStream\ExpectedVersion; @@ -166,8 +162,7 @@ function () use ($tetheredNodeAggregate) { . implode(', ', array_keys($actualTetheredChildNodes)), fn () => $this->reorderNodes( $nodeAggregate->contentStreamId, - $nodeAggregate->nodeAggregateId, - $originDimensionSpacePoint, + $nodeAggregate->getCoverageByOccupant($originDimensionSpacePoint), $actualTetheredChildNodes, array_keys($expectedTetheredNodes) ) @@ -224,8 +219,7 @@ protected function getPropertyConverter(): PropertyConverter */ private function reorderNodes( ContentStreamId $contentStreamId, - NodeAggregateId $parentNodeAggregateId, - DimensionSpace\OriginDimensionSpacePoint $originDimensionSpacePoint, + DimensionSpace\DimensionSpacePointSet $coverageByOrigin, array $actualTetheredChildNodes, array $expectedNodeOrdering ): EventsToPublish { @@ -235,33 +229,22 @@ private function reorderNodes( $succeedingSiblingNodeName = array_pop($expectedNodeOrdering); while ($nodeNameToMove = array_pop($expectedNodeOrdering)) { // let's move $nodeToMove before $succeedingNode. - /* @var $nodeToMove Node */ $nodeToMove = $actualTetheredChildNodes[$nodeNameToMove]; - /* @var $succeedingNode Node */ $succeedingNode = $actualTetheredChildNodes[$succeedingSiblingNodeName]; + $succeedingSiblingsForCoverage = []; + foreach ($coverageByOrigin as $coveredDimensionSpacePoint) { + $succeedingSiblingsForCoverage[] = new InterdimensionalSibling( + $coveredDimensionSpacePoint, + $succeedingNode->nodeAggregateId + ); + } + $events[] = new NodeAggregateWasMoved( $contentStreamId, $nodeToMove->nodeAggregateId, - OriginNodeMoveMappings::fromArray([ - new OriginNodeMoveMapping( - $nodeToMove->originDimensionSpacePoint, - CoverageNodeMoveMappings::create( - CoverageNodeMoveMapping::createForNewSucceedingSibling( - // TODO: I am not sure the next line is 100% correct. IMHO this must be the COVERED - // TODO: DimensionSpacePoint (though I am not sure whether we have that one now) - $nodeToMove->originDimensionSpacePoint->toDimensionSpacePoint(), - SucceedingSiblingNodeMoveDestination::create( - $succeedingNode->nodeAggregateId, - $succeedingNode->originDimensionSpacePoint, - // we only change the order, not the parent -> so we can simply use the parent here. - $parentNodeAggregateId, - $originDimensionSpacePoint - ) - ) - ) - ) - ]), + null, + new InterdimensionalSiblings(...$succeedingSiblingsForCoverage), ); // now, go one step left. diff --git a/Neos.Neos/Classes/FrontendRouting/CatchUpHook/RouterCacheHook.php b/Neos.Neos/Classes/FrontendRouting/CatchUpHook/RouterCacheHook.php index 3c82e38109e..3c57bc02c14 100644 --- a/Neos.Neos/Classes/FrontendRouting/CatchUpHook/RouterCacheHook.php +++ b/Neos.Neos/Classes/FrontendRouting/CatchUpHook/RouterCacheHook.php @@ -6,7 +6,6 @@ use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\EventStore\EventInterface; use Neos\ContentRepository\Core\Feature\NodeModification\Event\NodePropertiesWereSet; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\CoverageNodeMoveMapping; use Neos\ContentRepository\Core\Feature\NodeMove\Event\NodeAggregateWasMoved; use Neos\ContentRepository\Core\Feature\NodeRemoval\Event\NodeAggregateWasRemoved; use Neos\ContentRepository\Core\Feature\SubtreeTagging\Event\SubtreeWasTagged; @@ -140,21 +139,20 @@ private function onBeforeNodeAggregateWasMoved(NodeAggregateWasMoved $event): vo return; } - foreach ($event->nodeMoveMappings as $moveMapping) { - /* @var \Neos\ContentRepository\Core\Feature\NodeMove\Dto\OriginNodeMoveMapping $moveMapping */ - foreach ($moveMapping->newLocations as $newLocation) { - /* @var $newLocation CoverageNodeMoveMapping */ - $node = $this->findDocumentNodeInfoByIdAndDimensionSpacePoint($event->nodeAggregateId, $newLocation->coveredDimensionSpacePoint); - if (!$node) { - // node probably no document node, skip - continue; - } + foreach ($event->succeedingSiblingsForCoverage as $succeedingSiblingForCoverage) { + $node = $this->findDocumentNodeInfoByIdAndDimensionSpacePoint( + $event->nodeAggregateId, + $succeedingSiblingForCoverage->dimensionSpacePoint + ); + if (!$node) { + // node probably no document node, skip + continue; + } - $this->collectTagsToFlush($node); + $this->collectTagsToFlush($node); - $descendantsOfNode = $this->getState()->getDescendantsOfNode($node); - array_map($this->collectTagsToFlush(...), iterator_to_array($descendantsOfNode)); - } + $descendantsOfNode = $this->getState()->getDescendantsOfNode($node); + array_map($this->collectTagsToFlush(...), iterator_to_array($descendantsOfNode)); } } diff --git a/Neos.Neos/Classes/FrontendRouting/Projection/DocumentUriPathProjection.php b/Neos.Neos/Classes/FrontendRouting/Projection/DocumentUriPathProjection.php index c6e503d57c8..886983c9f30 100644 --- a/Neos.Neos/Classes/FrontendRouting/Projection/DocumentUriPathProjection.php +++ b/Neos.Neos/Classes/FrontendRouting/Projection/DocumentUriPathProjection.php @@ -15,9 +15,6 @@ use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Event\DimensionSpacePointWasMoved; use Neos\ContentRepository\Core\Feature\NodeCreation\Event\NodeAggregateWithNodeWasCreated; use Neos\ContentRepository\Core\Feature\NodeModification\Event\NodePropertiesWereSet; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\CoverageNodeMoveMapping; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\ParentNodeMoveDestination; -use Neos\ContentRepository\Core\Feature\NodeMove\Dto\SucceedingSiblingNodeMoveDestination; use Neos\ContentRepository\Core\Feature\NodeMove\Event\NodeAggregateWasMoved; use Neos\ContentRepository\Core\Feature\NodeRemoval\Event\NodeAggregateWasRemoved; use Neos\ContentRepository\Core\Feature\NodeTypeChange\Event\NodeAggregateTypeWasChanged; @@ -617,49 +614,36 @@ private function whenNodeAggregateWasMoved(NodeAggregateWasMoved $event): void return; } - foreach ($event->nodeMoveMappings as $moveMapping) { - /* @var \Neos\ContentRepository\Core\Feature\NodeMove\Dto\OriginNodeMoveMapping $moveMapping */ - foreach ($moveMapping->newLocations as $newLocation) { - /* @var $newLocation CoverageNodeMoveMapping */ - $node = $this->tryGetNode(fn () => $this->getState()->getByIdAndDimensionSpacePointHash( - $event->nodeAggregateId, - $newLocation->coveredDimensionSpacePoint->hash - )); - if (!$node) { - // node probably no document node, skip - continue; - } - - match ($newLocation->destination::class) { - SucceedingSiblingNodeMoveDestination::class => $this->moveNode( - /** @var SucceedingSiblingNodeMoveDestination $newLocation->destination */ - $node, - $newLocation->destination->parentNodeAggregateId, - $newLocation->destination->nodeAggregateId - ), - ParentNodeMoveDestination::class => $this->moveNode( - /** @var ParentNodeMoveDestination $newLocation->destination */ - $node, - $newLocation->destination->nodeAggregateId, - null - ), - }; - - $this->getState()->purgeCacheFor($node); + foreach ($event->succeedingSiblingsForCoverage as $succeedingSiblingForCoverage) { + $node = $this->tryGetNode(fn () => $this->getState()->getByIdAndDimensionSpacePointHash( + $event->nodeAggregateId, + $succeedingSiblingForCoverage->dimensionSpacePoint->hash + )); + if (!$node) { + // node probably no document node, skip + continue; } + + $this->moveNode( + $node, + $event->newParentNodeAggregateId, + $succeedingSiblingForCoverage->nodeAggregateId + ); + + $this->getState()->purgeCacheFor($node); } } private function moveNode( DocumentNodeInfo $node, - NodeAggregateId $newParentNodeAggregateId, + ?NodeAggregateId $newParentNodeAggregateId, ?NodeAggregateId $newSucceedingNodeAggregateId ): void { $this->disconnectNodeFromSiblings($node); - $this->connectNodeWithSiblings($node, $newParentNodeAggregateId, $newSucceedingNodeAggregateId); + $this->connectNodeWithSiblings($node, $newParentNodeAggregateId ?: $node->getParentNodeAggregateId(), $newSucceedingNodeAggregateId); - if ($newParentNodeAggregateId->equals($node->getParentNodeAggregateId())) { + if (!$newParentNodeAggregateId || $newParentNodeAggregateId->equals($node->getParentNodeAggregateId())) { return; } $newParentNode = $this->tryGetNode(fn () => $this->getState()->getByIdAndDimensionSpacePointHash( diff --git a/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php b/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php index fd67227a3de..6cbd8ffbb23 100644 --- a/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php +++ b/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php @@ -26,6 +26,7 @@ use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Event\DimensionSpacePointWasMoved; use Neos\ContentRepository\Core\Feature\NodeCreation\Event\NodeAggregateWithNodeWasCreated; use Neos\ContentRepository\Core\Feature\NodeModification\Event\NodePropertiesWereSet; +use Neos\ContentRepository\Core\Feature\NodeMove\Command\MoveNodeAggregate; use Neos\ContentRepository\Core\Feature\NodeMove\Event\NodeAggregateWasMoved; use Neos\ContentRepository\Core\Feature\NodeReferencing\Event\NodeReferencesWereSet; use Neos\ContentRepository\Core\Feature\NodeRemoval\Event\NodeAggregateWasRemoved; @@ -183,7 +184,7 @@ public function apply(EventInterface $event, EventEnvelope $eventEnvelope): void { match ($event::class) { RootWorkspaceWasCreated::class => $this->whenRootWorkspaceWasCreated($event), - NodeAggregateWasMoved::class => $this->whenNodeAggregateWasMoved($event), + NodeAggregateWasMoved::class => $this->whenNodeAggregateWasMoved($event, $eventEnvelope), NodePropertiesWereSet::class => $this->whenNodePropertiesWereSet($event), NodeReferencesWereSet::class => $this->whenNodeReferencesWereSet($event), NodeAggregateWithNodeWasCreated::class => $this->whenNodeAggregateWithNodeWasCreated($event), @@ -230,18 +231,22 @@ private function whenRootWorkspaceWasCreated(RootWorkspaceWasCreated $event): vo } } - private function whenNodeAggregateWasMoved(NodeAggregateWasMoved $event): void + private function whenNodeAggregateWasMoved(NodeAggregateWasMoved $event, EventEnvelope $eventEnvelope): void { - // WORKAROUND: we simply use the first MoveNodeMapping here to find the dimension space point - // @todo properly handle this - /* @var \Neos\ContentRepository\Core\Feature\NodeMove\Dto\OriginNodeMoveMapping[] $mapping */ - $mapping = iterator_to_array($event->nodeMoveMappings); - - $this->markAsMoved( - $event->getContentStreamId(), - $event->getNodeAggregateId(), - $mapping[0]->movedNodeOrigin - ); + // Changes reflect the editorial intention, not the effect as they are later published via commands + $metadata = $eventEnvelope->event->metadata?->value ?? []; + if (isset($metadata['commandPayload'])) { + $command = MoveNodeAggregate::fromArray($metadata['commandPayload']); + // WORKAROUND: we simply use the command's DSP here as the origin dimension space point. + // But this DSP is not necessarily occupied. + // @todo properly handle this by storing the necessary information in the projection + + $this->markAsMoved( + $event->getContentStreamId(), + $event->getNodeAggregateId(), + OriginDimensionSpacePoint::fromDimensionSpacePoint($command->dimensionSpacePoint) + ); + } } private function whenNodePropertiesWereSet(NodePropertiesWereSet $event): void From 13bcf438d2ebf644d6fbade81ef54ddd5b3d966c Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Sun, 14 Apr 2024 21:58:14 +0200 Subject: [PATCH 10/27] Fix sibling assignments to pass tests <3 --- ...deAggregate_NoNewParent_Dimensions.feature | 972 +++++++++--------- .../Classes/Feature/NodeMove/NodeMove.php | 30 +- 2 files changed, 493 insertions(+), 509 deletions(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NoNewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NoNewParent_Dimensions.feature index bf97db53f9a..906fe2c3ed7 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NoNewParent_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/02-MoveNodeAggregate_NoNewParent_Dimensions.feature @@ -51,6 +51,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 9 events to be published on stream "ContentStream:cs-identifier" + And event at index 8 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "eldest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -110,6 +118,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "eldest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -170,6 +186,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -226,6 +250,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 9 events to be published on stream "ContentStream:cs-identifier" + And event at index 8 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -291,6 +323,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "younger-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -355,6 +395,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -383,11 +431,13 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + # The given succeeding sibling cannot be resolved and since younger-mc-nodeface isn't given as a preceding sibling, nothing is done | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have no succeeding siblings When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} @@ -411,6 +461,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 9 events to be published on stream "ContentStream:cs-identifier" + And event at index 8 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -472,6 +530,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -532,6 +598,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -588,6 +662,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 9 events to be published on stream "ContentStream:cs-identifier" + And event at index 8 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -653,6 +735,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -717,6 +807,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -744,11 +842,13 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have no preceding siblings + And I expect this node to have the following preceding siblings: + # The given preceding sibling cannot be resolved and since elder-mc-nodeface isn't given as a succeeding sibling, nothing is done + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} @@ -775,6 +875,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 9 events to be published on stream "ContentStream:cs-identifier" + And event at index 8 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "eldest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -836,6 +944,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -898,6 +1014,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -954,6 +1078,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 9 events to be published on stream "ContentStream:cs-identifier" + And event at index 8 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -962,8 +1094,8 @@ Feature: Move a node with content dimensions | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} @@ -973,9 +1105,9 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} @@ -985,9 +1117,9 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} @@ -998,8 +1130,8 @@ Feature: Move a node with content dimensions | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | Scenario: Move a node and its specialization variants before one of its siblings, which is not the first and does not exist in all variants @@ -1019,6 +1151,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "younger-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -1027,8 +1167,8 @@ Feature: Move a node with content dimensions | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} @@ -1038,9 +1178,9 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} @@ -1050,8 +1190,8 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} @@ -1062,8 +1202,8 @@ Feature: Move a node with content dimensions | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | Scenario: Move a node and its specialization variants before one of its siblings, which is the last and does not exist in all variants @@ -1075,24 +1215,32 @@ Feature: Move a node with content dimensions And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | "youngest-mc-nodeface" | - | relationDistributionStrategy | "gatherSpecializations" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "youngest-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} @@ -1111,41 +1259,51 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: + # The given succeeding sibling cannot be resolved and since elder-mc-nodeface isn't given as a preceding sibling, nothing is done | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have no succeeding siblings + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | Scenario: Move a node and its specialization variants after the last of its siblings When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | null | - | relationDistributionStrategy | "gatherSpecializations" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 9 events to be published on stream "ContentStream:cs-identifier" + And event at index 8 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -1177,9 +1335,9 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -1194,21 +1352,29 @@ Feature: Move a node with content dimensions And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | null | - | relationDistributionStrategy | "gatherSpecializations" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | null | + | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -1239,9 +1405,9 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -1256,24 +1422,32 @@ Feature: Move a node with content dimensions And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | - | relationDistributionStrategy | "gatherSpecializations" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} @@ -1302,34 +1476,42 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | Scenario: Move a node and its specialization variants after one of its siblings, which is not the last When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | - | relationDistributionStrategy | "gatherSpecializations" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 9 events to be published on stream "ContentStream:cs-identifier" + And event at index 8 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} @@ -1360,12 +1542,12 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | Scenario: Move a node and its specialization variants after one of its siblings, which is not the last and does not exist in all variants @@ -1377,24 +1559,32 @@ Feature: Move a node with content dimensions And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | - | relationDistributionStrategy | "gatherSpecializations" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} @@ -1424,12 +1614,12 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | Scenario: Move a node and its specialization variants after one of its siblings, which is the first and does not exist in all variants @@ -1441,20 +1631,28 @@ Feature: Move a node with content dimensions And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | - | relationDistributionStrategy | "gatherSpecializations" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | @@ -1476,11 +1674,13 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have no preceding siblings - And I expect this node to have the following succeeding siblings: + And I expect this node to have the following preceding siblings: + # The given preceding sibling cannot be resolved and since elder-mc-nodeface isn't given as a succeeding sibling, nothing is done | NodeDiscriminator | | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} @@ -1488,7 +1688,7 @@ Feature: Move a node with content dimensions And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | @@ -1499,14 +1699,22 @@ Feature: Move a node with content dimensions Scenario: Move a single node before the first of its siblings When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | - | relationDistributionStrategy | "scatter" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | + | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 9 events to be published on stream "ContentStream:cs-identifier" + And event at index 8 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "eldest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -1533,9 +1741,9 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -1552,23 +1760,35 @@ Feature: Move a node with content dimensions | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - Scenario: Move a single node before the first of its siblings, which does not exist in all variants + # Scenario: Move a single node before the first of its siblings, which does not exist in all variants + # This scenario is invalid because the given succeeding sibling does not exist in the selected DSP. + # This constraint check is enforced by the command handler. + + Scenario: Move a single node before a siblings which is partially the first Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "eldest-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "source"} | - | nodeVariantSelectionStrategy | "allSpecializations" | + | Key | Value | + | nodeAggregateId | "eldest-mc-nodeface" | + | coveredDimensionSpacePoint | {"example": "source"} | + | nodeVariantSelectionStrategy | "allSpecializations" | And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | - | relationDistributionStrategy | "scatter" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -1595,8 +1815,8 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -1614,23 +1834,24 @@ Feature: Move a node with content dimensions | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - Scenario: Move a single node before a siblings which is partially the first - Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "eldest-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "source"} | - | nodeVariantSelectionStrategy | "allSpecializations" | - And the graph projection is fully up to date - + Scenario: Move a single node before one of its siblings, which is not the first When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | - | relationDistributionStrategy | "scatter" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | null | + | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 9 events to be published on stream "ContentStream:cs-identifier" + And event at index 8 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -1646,143 +1867,25 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have no preceding siblings - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - Scenario: Move a single node before one of its siblings, which is not the first - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - Scenario: Move a single node before one of its siblings, which is not the first and does not exist in all variants - Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "elder-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "source"} | - | nodeVariantSelectionStrategy | "allSpecializations" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} @@ -1792,72 +1895,18 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - Scenario: Move a single node before one of its siblings, which is the last and does not exist in all variants - Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "youngest-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "source"} | - | nodeVariantSelectionStrategy | "allSpecializations" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newSucceedingSiblingNodeAggregateId | "youngest-mc-nodeface" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have no succeeding siblings + # Scenario: Move a single node before one of its siblings, which is not the first and does not exist in all variants + # This scenario is invalid because the given succeeding sibling does not exist in the selected DSP. + # This constraint check is enforced by the command handler. - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + # Scenario: Move a single node before one of its siblings, which is the last and does not exist in all variants + # This scenario is invalid because the given succeeding sibling does not exist in the selected DSP. + # This constraint check is enforced by the command handler. Scenario: Move a single node after the last of its siblings When the command MoveNodeAggregate is executed with payload: @@ -1866,16 +1915,24 @@ Feature: Move a node with content dimensions | dimensionSpacePoint | {"example": "source"} | | newParentNodeAggregateId | null | | newSucceedingSiblingNodeAggregateId | null | - | relationDistributionStrategy | "scatter" | + | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 9 events to be published on stream "ContentStream:cs-identifier" + And event at index 8 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -1896,9 +1953,9 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -1908,9 +1965,9 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -1920,7 +1977,7 @@ Feature: Move a node with content dimensions Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "youngest-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "source"} | + | coveredDimensionSpacePoint | {"example": "source"} | | nodeVariantSelectionStrategy | "allSpecializations" | And the graph projection is fully up to date @@ -1930,16 +1987,24 @@ Feature: Move a node with content dimensions | dimensionSpacePoint | {"example": "source"} | | newParentNodeAggregateId | null | | newSucceedingSiblingNodeAggregateId | null | - | relationDistributionStrategy | "scatter" | + | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -1949,19 +2014,19 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have no succeeding siblings When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -1970,9 +2035,9 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -1982,7 +2047,7 @@ Feature: Move a node with content dimensions Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "youngest-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "source"} | + | coveredDimensionSpacePoint | {"example": "source"} | | nodeVariantSelectionStrategy | "allSpecializations" | And the graph projection is fully up to date @@ -1992,19 +2057,27 @@ Feature: Move a node with content dimensions | dimensionSpacePoint | {"example": "source"} | | newParentNodeAggregateId | null | | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | - | relationDistributionStrategy | "scatter" | + | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 10 events to be published on stream "ContentStream:cs-identifier" + And event at index 9 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} @@ -2021,9 +2094,9 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | @@ -2032,12 +2105,12 @@ Feature: Move a node with content dimensions And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | Scenario: Move a single node after one of its siblings, which is not the last @@ -2047,84 +2120,27 @@ Feature: Move a node with content dimensions | dimensionSpacePoint | {"example": "source"} | | newParentNodeAggregateId | null | | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | - | relationDistributionStrategy | "scatter" | + | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - Scenario: Move a single node after one of its siblings, which is not the last and does not exist in all variants - Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "younger-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "source"} | - | nodeVariantSelectionStrategy | "allSpecializations" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date + Then I expect exactly 9 events to be published on stream "ContentStream:cs-identifier" + And event at index 8 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "youngest-mc-nodeface"}] | When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} @@ -2132,6 +2148,7 @@ Feature: Move a node with content dimensions And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: @@ -2147,78 +2164,25 @@ Feature: Move a node with content dimensions | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - Scenario: Move a single node after one of its siblings, which is the first and does not exist in all variants - Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "eldest-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "source"} | - | nodeVariantSelectionStrategy | "allSpecializations" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | null | - | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have no succeeding siblings - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + # Scenario: Move a single node after one of its siblings, which is not the last and does not exist in all variants + # This scenario is invalid because the given succeeding sibling does not exist in the selected DSP. + # This constraint check is enforced by the command handler. - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} - And I expect node aggregate identifier "nody-mc-nodeface" and node path "document/child-document-n" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + # Scenario: Move a single node after one of its siblings, which is the first and does not exist in all variants + # This scenario is invalid because the given succeeding sibling does not exist in the selected DSP. + # This constraint check is enforced by the command handler. diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php index 15e173d89c0..d1b01efe4bc 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php @@ -200,9 +200,11 @@ private function handleMoveNodeAggregate( $contentStreamId, $command->dimensionSpacePoint, $affectedDimensionSpacePoints, + $command->nodeAggregateId, $command->newSucceedingSiblingNodeAggregateId, $command->newPrecedingSiblingNodeAggregateId, - $command->newParentNodeAggregateId !== null, + $command->newParentNodeAggregateId !== null + || $command->newSucceedingSiblingNodeAggregateId === null && $command->newPrecedingSiblingNodeAggregateId === null, $contentRepository ) ) @@ -241,12 +243,14 @@ private function resolveAffectedDimensionSpacePointSet( /** * @param bool $completeSet Whether unresolvable siblings should be added as null or not at all * True when a new parent is set, which will result of the node being added at the end + * True when no preceding sibling is given and the succeeding sibling is explicitly set to null, which will result of the node being added at the end * False when no new parent is set, which will result in the node not being moved */ private function resolveInterdimensionalSiblingsForMove( ContentStreamId $contentStreamId, DimensionSpacePoint $selectedDimensionSpacePoint, DimensionSpacePointSet $affectedDimensionSpacePoints, + NodeAggregateId $nodeAggregateId, ?NodeAggregateId $succeedingSiblingId, ?NodeAggregateId $precedingSiblingId, bool $completeSet, @@ -290,6 +294,10 @@ private function resolveInterdimensionalSiblingsForMove( // check the other siblings succeeding in the selected dimension space point foreach ($alternativeSucceedingSiblingIds ?: [] as $alternativeSucceedingSiblingId) { + // the node itself is no valid succeeding sibling + if ($alternativeSucceedingSiblingId->equals($nodeAggregateId)) { + continue; + } $alternativeVariantSucceedingSibling = $variantSubgraph->findNodeById($alternativeSucceedingSiblingId); if (!$alternativeVariantSucceedingSibling) { continue; @@ -312,6 +320,10 @@ private function resolveInterdimensionalSiblingsForMove( } elseif ($alternativePrecedingSiblingIds) { // check the other siblings preceding in the selected dimension space point foreach ($alternativePrecedingSiblingIds as $alternativePrecedingSiblingId) { + // the node itself is no valid preceding sibling + if ($alternativePrecedingSiblingId->equals($nodeAggregateId)) { + continue; + } $alternativeVariantSucceedingSibling = $variantSubgraph->findNodeById($alternativePrecedingSiblingId); if ($alternativeVariantSucceedingSibling) { // d) one of the further preceding siblings exists in this dimension space point @@ -322,13 +334,21 @@ private function resolveInterdimensionalSiblingsForMove( } if ($variantPrecedingSiblingId) { - $succeedingSibling = $variantSubgraph->findSucceedingSiblingNodes( + // we fetch two siblings because the first might be the to-be-moved node itself + $variantSucceedingSiblingIds = $variantSubgraph->findSucceedingSiblingNodes( $variantPrecedingSiblingId, - FindSucceedingSiblingNodesFilter::create(pagination: Pagination::fromLimitAndOffset(1, 0)) - )->first(); + FindSucceedingSiblingNodesFilter::create(pagination: Pagination::fromLimitAndOffset(2, 0)) + )->getIds(); + $relevantVariantSucceedingSiblingId = null; + foreach ($variantSucceedingSiblingIds as $variantSucceedingSiblingId) { + if (!$variantSucceedingSiblingId->equals($nodeAggregateId)) { + $relevantVariantSucceedingSiblingId = $variantSucceedingSiblingId; + break; + } + } $interdimensionalSiblings[] = new InterdimensionalSibling( $dimensionSpacePoint, - $succeedingSibling?->nodeAggregateId, + $relevantVariantSucceedingSiblingId, ); continue; } From dc4e7da2a9649b6554952a6fdc43e9f4882a7a42 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 15 Apr 2024 00:06:15 +0200 Subject: [PATCH 11/27] Extend and fix test cases for MoveNode to new parent --- ...NodeAggregate_NewParent_Dimensions.feature | 766 +++++++++--------- 1 file changed, 375 insertions(+), 391 deletions(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature index d3ffa539ad9..77a395b3f64 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/03-MoveNodeAggregate_NewParent_Dimensions.feature @@ -10,8 +10,8 @@ Feature: Move a node with content dimensions Background: Given using the following content dimensions: - | Identifier | Values | Generalizations | - | language | general, source, peer, gsw | gsw->source->general, peer->general | + | Identifier | Values | Generalizations | + | example | general, source, spec, peer | spec->source->general, peer->general | And using the following node types: """yaml 'Neos.ContentRepository.Testing:Document': [] @@ -56,6 +56,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 13 events to be published on stream "ContentStream:cs-identifier" + And event at index 12 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "eldest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -117,6 +125,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "eldest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -177,6 +193,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -233,6 +257,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 13 events to be published on stream "ContentStream:cs-identifier" + And event at index 12 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -296,6 +328,14 @@ Feature: Move a node with content dimensions | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "younger-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -360,6 +400,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": "youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -416,6 +464,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 13 events to be published on stream "ContentStream:cs-identifier" + And event at index 12 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -477,6 +533,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": null},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId": null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -537,6 +601,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId":"youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":null},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId":"youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -593,6 +665,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 13 events to be published on stream "ContentStream:cs-identifier" + And event at index 12 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId":"youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":"youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId":"youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -658,6 +738,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId":"youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":"youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId":"youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -722,6 +810,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherAll" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId":"elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":null},{"dimensionSpacePoint":{"example":"peer"},"nodeAggregateId":"elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -749,12 +845,13 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have no preceding siblings - And I expect this node to have the following succeeding siblings: + # The given preceding sibling cannot be resolved and since elder-mc-nodeface isn't given as a succeeding sibling, the node is moved at the end + And I expect this node to have the following preceding siblings: | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} And I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} @@ -770,7 +867,7 @@ Feature: Move a node with content dimensions # Test cases for the gatherSpecializations strategy - Scenario: Move a complete node aggregate to a new parent before the first of its new siblings + Scenario: Move a node and its specializations to a new parent before the first of its new siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | @@ -780,6 +877,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 13 events to be published on stream "ContentStream:cs-identifier" + And event at index 12 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "eldest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} @@ -814,7 +919,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -822,7 +927,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent before the first of its new siblings - which does not exist in all variants + Scenario: Move a node and its specializations to a new parent before the first of its new siblings - which does not exist in all variants Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "eldest-mc-nodeface" | @@ -839,9 +944,17 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "eldest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -872,7 +985,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -880,7 +993,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent before a siblings which is partially the first + Scenario: Move a node and its specializations to a new parent before a siblings which is partially the first Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "eldest-mc-nodeface" | @@ -897,9 +1010,17 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -931,7 +1052,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -939,19 +1060,27 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent before one of its new siblings, which is not the first + Scenario: Move a node and its specializations to a new parent before one of its new siblings, which is not the first When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "general"} | + | dimensionSpacePoint | {"example": "source"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 13 events to be published on stream "ContentStream:cs-identifier" + And event at index 12 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -985,7 +1114,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -993,7 +1122,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent before one of its siblings, which is not the first and does not exist in all variants + Scenario: Move a node and its specializations to a new parent before one of its siblings, which is not the first and does not exist in all variants Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "elder-mc-nodeface" | @@ -1004,13 +1133,23 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId": "elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId": "younger-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1043,7 +1182,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1051,7 +1190,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent before one of its siblings, which is the last and does not exist in all variants + Scenario: Move a node and its specializations to a new parent before one of its siblings, which is the last and does not exist in all variants Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "youngest-mc-nodeface" | @@ -1068,9 +1207,17 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1102,7 +1249,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1110,7 +1257,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent after the last of its siblings + Scenario: Move a node and its specializations to a new parent after the last of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | @@ -1120,9 +1267,17 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 13 events to be published on stream "ContentStream:cs-identifier" + And event at index 12 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":null},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1154,7 +1309,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1162,7 +1317,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent after the last of its siblings, which does not exist in all variants + Scenario: Move a node and its specializations to a new parent after the last of its siblings, which does not exist in all variants Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "youngest-mc-nodeface" | @@ -1179,9 +1334,17 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":null},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1212,7 +1375,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1220,7 +1383,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is partially the last + Scenario: Move a node and its specializations to a new parent after one of its siblings, which is partially the last Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "youngest-mc-nodeface" | @@ -1237,9 +1400,17 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1271,7 +1442,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1279,7 +1450,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is not the last + Scenario: Move a node and its specializations to a new parent after one of its siblings, which is not the last When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | @@ -1289,9 +1460,17 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 13 events to be published on stream "ContentStream:cs-identifier" + And event at index 12 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":"youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1325,7 +1504,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1333,7 +1512,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is not the last and does not exist in all variants + Scenario: Move a node and its specializations to a new parent after one of its siblings, which is not the last and does not exist in all variants Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "younger-mc-nodeface" | @@ -1350,9 +1529,17 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"youngest-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":"youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1385,7 +1572,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1393,7 +1580,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is the first and does not exist in all variants + Scenario: Move a node and its specializations to a new parent after one of its siblings, which is the first and does not exist in all variants Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "eldest-mc-nodeface" | @@ -1410,9 +1597,17 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"elder-mc-nodeface"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1435,16 +1630,17 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have no preceding siblings - And I expect this node to have the following succeeding siblings: + And I expect this node to have the following preceding siblings: + # The given preceding sibling cannot be resolved and since elder-mc-nodeface isn't given as a succeeding sibling, the node is moved to the end | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1454,7 +1650,7 @@ Feature: Move a node with content dimensions # Test cases for the scatter strategy - Scenario: Move a complete node aggregate to a new parent before the first of its new siblings + Scenario: Move a single node to a new parent before the first of its new siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | @@ -1464,6 +1660,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 13 events to be published on stream "ContentStream:cs-identifier" + And event at index 12 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"eldest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} @@ -1487,7 +1691,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1497,55 +1701,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - - Scenario: Move a complete node aggregate to a new parent before the first of its new siblings - which does not exist in all variants - Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "eldest-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "spec"} | - | nodeVariantSelectionStrategy | "allSpecializations" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | "sir-david-nodenborough" | - | newSucceedingSiblingNodeAggregateId | "eldest-mc-nodeface" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have no preceding siblings - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1553,17 +1709,11 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + # Scenario: Move a single node to a new parent before the first of its new siblings - which does not exist in all variants + # This scenario is invalid because the given succeeding sibling does not exist in the selected DSP. + # This constraint check is enforced by the command handler. - Scenario: Move a complete node aggregate to a new parent before a siblings which is partially the first + Scenario: Move a single node to a new parent before a siblings which is partially the first Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "eldest-mc-nodeface" | @@ -1574,15 +1724,23 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | + | dimensionSpacePoint | {"example": "spec"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":"elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1591,50 +1749,8 @@ Feature: Move a node with content dimensions | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - - Scenario: Move a complete node aggregate to a new parent before one of its new siblings, which is not the first - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "general"} | - | newParentNodeAggregateId | "sir-david-nodenborough" | - | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1642,31 +1758,19 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + And I expect this node to have no preceding siblings And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1674,24 +1778,27 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent before one of its siblings, which is not the first and does not exist in all variants - Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "elder-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "spec"} | - | nodeVariantSelectionStrategy | "allSpecializations" | - And the graph projection is fully up to date - + Scenario: Move a single node to a new parent before one of its new siblings, which is not the first When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | "elder-mc-nodeface" | + | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 13 events to be published on stream "ContentStream:cs-identifier" + And event at index 12 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"elder-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1713,7 +1820,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1723,34 +1830,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - - Scenario: Move a complete node aggregate to a new parent before one of its siblings, which is the last and does not exist in all variants - Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "youngest-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "spec"} | - | nodeVariantSelectionStrategy | "allSpecializations" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | "sir-david-nodenborough" | - | newSucceedingSiblingNodeAggregateId | "youngest-mc-nodeface" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1758,39 +1838,15 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + # Scenario: Move a single node to a new parent before one of its siblings, which is not the first and does not exist in all variants + # This scenario is invalid because the given succeeding sibling does not exist in the selected DSP. + # This constraint check is enforced by the command handler. - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + # Scenario: Move a single node to a new parent before one of its siblings, which is the last and does not exist in all variants + # This scenario is invalid because the given succeeding sibling does not exist in the selected DSP. + # This constraint check is enforced by the command handler. - Scenario: Move a complete node aggregate to a new parent after the last of its siblings + Scenario: Move a single node to a new parent after the last of its siblings When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | @@ -1800,9 +1856,17 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 13 events to be published on stream "ContentStream:cs-identifier" + And event at index 12 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1823,7 +1887,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1833,7 +1897,7 @@ Feature: Move a node with content dimensions When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1841,7 +1905,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent after the last of its siblings, which does not exist in all variants + Scenario: Move a single node to a new parent after the last of its siblings, which does not exist in all variants Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "youngest-mc-nodeface" | @@ -1852,15 +1916,23 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | + | dimensionSpacePoint | {"example": "spec"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newSucceedingSiblingNodeAggregateId | null | | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1869,29 +1941,28 @@ Feature: Move a node with content dimensions | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have no succeeding siblings - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1899,7 +1970,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is partially the last + Scenario: Move a single node to a new parent after one of its siblings, which is partially the last Given the command RemoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "youngest-mc-nodeface" | @@ -1910,15 +1981,23 @@ Feature: Move a node with content dimensions When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | + | dimensionSpacePoint | {"example": "spec"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1927,50 +2006,8 @@ Feature: Move a node with content dimensions | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - - Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is not the last - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | "sir-david-nodenborough" | - | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -1978,7 +2015,7 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: @@ -1986,23 +2023,11 @@ Feature: Move a node with content dimensions | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;elder-mc-nodeface;{"example": "general"} | | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + And I expect this node to have no succeeding siblings When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -2010,26 +2035,27 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is not the last and does not exist in all variants - Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "younger-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "spec"} | - | nodeVariantSelectionStrategy | "allSpecializations" | - And the graph projection is fully up to date - + Scenario: Move a single node to a new parent after one of its siblings, which is not the last When the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | + | dimensionSpacePoint | {"example": "spec"} | | newParentNodeAggregateId | "sir-david-nodenborough" | | newPrecedingSiblingNodeAggregateId | "younger-mc-nodeface" | | relationDistributionStrategy | "scatter" | And the graph projection is fully up to date + Then I expect exactly 13 events to be published on stream "ContentStream:cs-identifier" + And event at index 12 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-david-nodenborough" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":"youngest-mc-nodeface"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -2038,57 +2064,8 @@ Feature: Move a node with content dimensions | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - - Scenario: Move a complete node aggregate to a new parent after one of its siblings, which is the first and does not exist in all variants - Given the command RemoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "eldest-mc-nodeface" | - | coveredDimensionSpacePoint | {"example": "spec"} | - | nodeVariantSelectionStrategy | "allSpecializations" | - And the graph projection is fully up to date - - When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | "sir-david-nodenborough" | - | newPrecedingSiblingNodeAggregateId | "eldest-mc-nodeface" | - | relationDistributionStrategy | "scatter" | - And the graph projection is fully up to date - - When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -2096,31 +2073,21 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;eldest-mc-nodeface;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;younger-mc-nodeface;{"example": "general"} | + | cs-identifier;elder-mc-nodeface;{"example": "general"} | + | cs-identifier;eldest-mc-nodeface;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | - | cs-identifier;elder-mc-nodeface;{"example": "general"} | - | cs-identifier;younger-mc-nodeface;{"example": "general"} | | cs-identifier;youngest-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} - And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | - And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} - And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: | NodeDiscriminator | | cs-identifier;source-elder-mc-nodeface;{"example": "general"} | @@ -2128,6 +2095,14 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;source-younger-mc-nodeface;{"example": "general"} | + # Scenario: Move a single node to a new parent after one of its siblings, which is not the last and does not exist in all variants + # This scenario is invalid because the given succeeding sibling does not exist in the selected DSP. + # This constraint check is enforced by the command handler. + + # Scenario: Move a single node to a new parent after one of its siblings, which is the first and does not exist in all variants + # This scenario is invalid because the given succeeding sibling does not exist in the selected DSP. + # This constraint check is enforced by the command handler. + # Other test cases Scenario: Move a node that has no name @@ -2143,6 +2118,15 @@ Feature: Move a node with content dimensions | nodeAggregateId | "nody-mc-nodeface-ii" | | newParentNodeAggregateId | "lady-eleonode-rootford" | | relationDistributionStrategy | "scatter" | + + Then I expect exactly 14 events to be published on stream "ContentStream:cs-identifier" + And event at index 13 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface-ii" | + | newParentNodeAggregateId | "lady-eleonode-rootford" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"general"},"nodeAggregateId":null}] | + And the graph projection is fully up to date When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} And I expect node aggregate identifier "nody-mc-nodeface-ii" to lead to node cs-identifier;nody-mc-nodeface-ii;{"example": "general"} From c013cc36b2189204e7a109de54ac895638219da5 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 15 Apr 2024 21:47:22 +0200 Subject: [PATCH 12/27] Properly validate siblings --- ...oveNodeAggregate_ScatteredChildren.feature | 107 +++++++++++++----- .../Classes/Feature/NodeMove/NodeMove.php | 20 +++- 2 files changed, 95 insertions(+), 32 deletions(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ScatteredChildren.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ScatteredChildren.feature index e8c00aec5fe..151909239af 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ScatteredChildren.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/04-MoveNodeAggregate_ScatteredChildren.feature @@ -52,14 +52,22 @@ Feature: Move a node with content dimensions And the graph projection is fully up to date When the command MoveNodeAggregate is executed with payload: - | Key | Value | - | nodeAggregateId | "nody-mc-nodeface" | - | dimensionSpacePoint | {"example": "source"} | - | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | - | newSucceedingSiblingNodeAggregateIde | "bustling-destinode" | - | relationDistributionStrategy | "gatherSpecializations" | + | Key | Value | + | nodeAggregateId | "nody-mc-nodeface" | + | dimensionSpacePoint | {"example": "source"} | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | newSucceedingSiblingNodeAggregateId | "bustling-destinode" | + | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 15 events to be published on stream "ContentStream:cs-identifier" + And event at index 14 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"bustling-destinode"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":"younger-destinode"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -74,8 +82,9 @@ Feature: Move a node with content dimensions Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-destinode;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-destinode;{"example": "general"} | + | cs-identifier;nodimus-mediocre;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;bustling-destinode;{"example": "general"} | @@ -85,8 +94,9 @@ Feature: Move a node with content dimensions Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-destinode;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-destinode;{"example": "general"} | + | cs-identifier;nodimus-mediocre;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-destinode;{"example": "general"} | @@ -119,6 +129,14 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 15 events to be published on stream "ContentStream:cs-identifier" + And event at index 14 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "bustling-destinode" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":null},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":null}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example": "general"} @@ -165,21 +183,41 @@ Feature: Move a node with content dimensions | Key | Value | | nodeAggregateId | "bustling-destinode" | | dimensionSpacePoint | {"example": "source"} | - | newSucceedingSiblingNodeAggregateId | "younger-destinode" | + | newSucceedingSiblingNodeAggregateId | "elder-destinode" | | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 15 events to be published on stream "ContentStream:cs-identifier" + And event at index 14 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "bustling-destinode" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"elder-destinode"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "bustling-destinode" and node path "esquire/bustling-target-document" to lead to node cs-identifier;bustling-destinode;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-destinode;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-destinode;{"example": "general"} | + | cs-identifier;nodimus-mediocre;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-destinode;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} + Then I expect node aggregate identifier "bustling-destinode" and node path "esquire/bustling-target-document" to lead to node cs-identifier;bustling-destinode;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;nodimus-mediocre;{"example": "general"} | + And I expect this node to have the following succeeding siblings: + | NodeDiscriminator | + | cs-identifier;elder-destinode;{"example": "general"} | + | cs-identifier;younger-destinode;{"example": "general"} | + + When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "bustling-destinode" and node path "esquire/esquire-child/bustling-target-document" to lead to node cs-identifier;bustling-destinode;{"example": "general"} And I expect this node to be a child of node cs-identifier;nodimus-mediocre;{"example": "general"} And I expect this node to have the following preceding siblings: @@ -189,23 +227,19 @@ Feature: Move a node with content dimensions | NodeDiscriminator | | cs-identifier;younger-child-destinode;{"example": "general"} | - When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "bustling-destinode" and node path "esquire/esquire-child/bustling-target-document" to lead to node cs-identifier;bustling-destinode;{"example": "general"} - And I expect this node to be a child of node cs-identifier;nodimus-mediocre;{"example": "general"} - And I expect this node to have no preceding siblings - And I expect this node to have no succeeding siblings - When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "bustling-destinode" and node path "esquire/bustling-target-document" to lead to node cs-identifier;bustling-destinode;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-destinode;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;elder-destinode;{"example": "general"} | + | cs-identifier;nodimus-mediocre;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;younger-destinode;{"example": "general"} | Scenario: Scatter a node aggregate by moving a specialization variant to a different parent. Then let a sibling variant follow suit and move the sibling before the node in both variants. + # We expect to be the node to be the sibling's succeeding sibling in both variants across parents Given the command MoveNodeAggregate is executed with payload: | Key | Value | | nodeAggregateId | "bustling-destinode" | @@ -231,25 +265,35 @@ Feature: Move a node with content dimensions | relationDistributionStrategy | "gatherSpecializations" | And the graph projection is fully up to date + Then I expect exactly 16 events to be published on stream "ContentStream:cs-identifier" + And event at index 15 is of type "NodeAggregateWasMoved" with payload: + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "elder-destinode" | + | newParentNodeAggregateId | null | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"example":"source"},"nodeAggregateId":"bustling-destinode"},{"dimensionSpacePoint":{"example":"spec"},"nodeAggregateId":"bustling-destinode"}] | + When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "elder-destinode" and node path "esquire/elder-target-document" to lead to node cs-identifier;elder-destinode;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} - And I expect this node to have no preceding siblings + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;nodimus-mediocre;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;bustling-destinode;{"example": "general"} | | cs-identifier;younger-destinode;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "elder-destinode" and node path "esquire/esquire-child/elder-target-document" to lead to node cs-identifier;elder-destinode;{"example": "general"} - And I expect this node to be a child of node cs-identifier;nodimus-mediocre;{"example": "general"} + Then I expect node aggregate identifier "elder-destinode" and node path "esquire/elder-target-document" to lead to node cs-identifier;elder-destinode;{"example": "general"} + And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} And I expect this node to have the following preceding siblings: - | NodeDiscriminator | - | cs-identifier;elder-child-destinode;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;nodimus-mediocre;{"example": "general"} | And I expect this node to have the following succeeding siblings: - | NodeDiscriminator | - | cs-identifier;bustling-destinode;{"example": "general"} | - | cs-identifier;younger-child-destinode;{"example": "general"} | + | NodeDiscriminator | + | cs-identifier;bustling-destinode;{"example": "general"} | + | cs-identifier;younger-destinode;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "elder-destinode" and node path "esquire/esquire-child/elder-target-document" to lead to node cs-identifier;elder-destinode;{"example": "general"} @@ -259,12 +303,15 @@ Feature: Move a node with content dimensions | cs-identifier;elder-child-destinode;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | + | cs-identifier;bustling-destinode;{"example": "general"} | | cs-identifier;younger-child-destinode;{"example": "general"} | When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "elder-destinode" and node path "esquire/elder-target-document" to lead to node cs-identifier;elder-destinode;{"example": "general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} - And I expect this node to have no preceding siblings + And I expect this node to have the following preceding siblings: + | NodeDiscriminator | + | cs-identifier;nodimus-mediocre;{"example": "general"} | And I expect this node to have the following succeeding siblings: | NodeDiscriminator | | cs-identifier;bustling-destinode;{"example": "general"} | diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php index d1b01efe4bc..52cbde78625 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php @@ -201,6 +201,7 @@ private function handleMoveNodeAggregate( $command->dimensionSpacePoint, $affectedDimensionSpacePoints, $command->nodeAggregateId, + $command->newParentNodeAggregateId, $command->newSucceedingSiblingNodeAggregateId, $command->newPrecedingSiblingNodeAggregateId, $command->newParentNodeAggregateId !== null @@ -241,6 +242,8 @@ private function resolveAffectedDimensionSpacePointSet( } /** + * @param ?NodeAggregateId $parentNodeAggregateId the parent node aggregate ID to validate variant siblings against. + * If no new parent is given, the siblings are validated against the parent of the to-be-moved node in the respective dimension space point. * @param bool $completeSet Whether unresolvable siblings should be added as null or not at all * True when a new parent is set, which will result of the node being added at the end * True when no preceding sibling is given and the succeeding sibling is explicitly set to null, which will result of the node being added at the end @@ -251,6 +254,7 @@ private function resolveInterdimensionalSiblingsForMove( DimensionSpacePoint $selectedDimensionSpacePoint, DimensionSpacePointSet $affectedDimensionSpacePoints, NodeAggregateId $nodeAggregateId, + ?NodeAggregateId $parentNodeAggregateId, ?NodeAggregateId $succeedingSiblingId, ?NodeAggregateId $precedingSiblingId, bool $completeSet, @@ -283,7 +287,9 @@ private function resolveInterdimensionalSiblingsForMove( ); if ($succeedingSiblingId) { $variantSucceedingSibling = $variantSubgraph->findNodeById($succeedingSiblingId); - if ($variantSucceedingSibling) { + $variantParentId = $parentNodeAggregateId ?: $variantSubgraph->findParentNode($nodeAggregateId)?->nodeAggregateId; + $siblingParent = $variantSubgraph->findParentNode($succeedingSiblingId); + if ($variantSucceedingSibling && $siblingParent && $variantParentId?->equals($siblingParent->nodeAggregateId)) { // a) happy path, the explicitly requested succeeding sibling also exists in this dimension space point $interdimensionalSiblings[] = new InterdimensionalSibling( $dimensionSpacePoint, @@ -302,6 +308,10 @@ private function resolveInterdimensionalSiblingsForMove( if (!$alternativeVariantSucceedingSibling) { continue; } + $siblingParent = $variantSubgraph->findParentNode($alternativeSucceedingSiblingId); + if (!$siblingParent || !$variantParentId?->equals($siblingParent->nodeAggregateId)) { + continue; + } // b) one of the further succeeding sibling exists in this dimension space point $interdimensionalSiblings[] = new InterdimensionalSibling( $dimensionSpacePoint, @@ -314,7 +324,9 @@ private function resolveInterdimensionalSiblingsForMove( if ($precedingSiblingId) { $variantPrecedingSiblingId = null; $variantPrecedingSibling = $variantSubgraph->findNodeById($precedingSiblingId); - if ($variantPrecedingSibling) { + $variantParentId = $parentNodeAggregateId ?: $variantSubgraph->findParentNode($nodeAggregateId)?->nodeAggregateId; + $siblingParent = $variantSubgraph->findParentNode($precedingSiblingId); + if ($variantPrecedingSibling && $siblingParent && $variantParentId->equals($siblingParent->nodeAggregateId)) { // c) happy path, the explicitly requested preceding sibling also exists in this dimension space point $variantPrecedingSiblingId = $precedingSiblingId; } elseif ($alternativePrecedingSiblingIds) { @@ -324,6 +336,10 @@ private function resolveInterdimensionalSiblingsForMove( if ($alternativePrecedingSiblingId->equals($nodeAggregateId)) { continue; } + $siblingParent = $variantSubgraph->findParentNode($alternativePrecedingSiblingId); + if (!$siblingParent || !$variantParentId->equals($siblingParent->nodeAggregateId)) { + continue; + } $alternativeVariantSucceedingSibling = $variantSubgraph->findNodeById($alternativePrecedingSiblingId); if ($alternativeVariantSucceedingSibling) { // d) one of the further preceding siblings exists in this dimension space point From 0bbc4ac40a894c646bf8f3f2d5d72f56a01f4d4d Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 15 Apr 2024 21:47:38 +0200 Subject: [PATCH 13/27] Fix NodeMove/SubtreeTags test suite --- .../05-MoveNodeAggregate_SubtreeTags.feature | 196 +++++++++--------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/05-MoveNodeAggregate_SubtreeTags.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/05-MoveNodeAggregate_SubtreeTags.feature index 2c6641c53b4..f38fdb6a08d 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/05-MoveNodeAggregate_SubtreeTags.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/05-MoveNodeAggregate_SubtreeTags.feature @@ -62,7 +62,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -95,7 +95,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -123,7 +123,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -156,7 +156,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -186,7 +186,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -197,7 +197,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" @@ -208,7 +208,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" @@ -219,7 +219,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -247,7 +247,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -258,7 +258,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -269,7 +269,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" @@ -280,7 +280,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -311,7 +311,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -321,30 +321,30 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -373,7 +373,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -383,30 +383,30 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -445,7 +445,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -455,30 +455,30 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag1" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag1" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -515,7 +515,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -525,30 +525,30 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag1" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -585,7 +585,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -595,30 +595,30 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag1" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -655,7 +655,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -665,30 +665,30 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag1" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -725,7 +725,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -735,30 +735,30 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag2" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag2" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -795,7 +795,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -805,30 +805,30 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag2" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -865,7 +865,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -875,30 +875,30 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag2" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag2" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -935,7 +935,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -945,30 +945,30 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag2" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -1228,7 +1228,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -1239,7 +1239,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag1" @@ -1250,7 +1250,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -1379,7 +1379,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag2" @@ -1427,7 +1427,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -1437,30 +1437,30 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag2" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "tag1" And I expect this node to be tagged with "tag2" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -1571,30 +1571,30 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -1633,23 +1633,23 @@ Feature: Move a node aggregate into and out of a tagged parent And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} - Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} + Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" - And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} + And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -1695,7 +1695,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -1706,7 +1706,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;nodimus-prime,{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" @@ -1728,7 +1728,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -1846,7 +1846,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" @@ -1857,7 +1857,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag1" @@ -2078,7 +2078,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-devid-nodenborough;{"example":"general"} + And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "" @@ -2629,7 +2629,7 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} + And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} And I expect this node to tag with "" And I expect this node to be tagged with "tag2" From a6e9b1d76a158368cf18a45e6772358aca4f21cb Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 15 Apr 2024 21:51:22 +0200 Subject: [PATCH 14/27] Expect proper exception --- .../08-NodeMove/06-AdditionalConstraintChecks.feature | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/06-AdditionalConstraintChecks.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/06-AdditionalConstraintChecks.feature index a3ecd838bde..a401fe2a00d 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/06-AdditionalConstraintChecks.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/06-AdditionalConstraintChecks.feature @@ -60,20 +60,20 @@ Feature: Additional constraint checks after move node capabilities are introduce | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | parentNodeAggregateId | "sir-nodeward-nodington-iii" | | nodeName | "document" | - Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" + Then the last command should have thrown an exception of type "NodeNameIsAlreadyOccupied" When the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | parentNodeAggregateId | "lady-abigail-nodenborough" | | nodeName | "document" | - Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" + Then the last command should have thrown an exception of type "NodeNameIsAlreadyOccupied" When the command CreateNodeAggregateWithNode is executed with payload and exceptions are caught: | Key | Value | | nodeAggregateId | "nody-mc-nodeface" | | nodeTypeName | "Neos.ContentRepository.Testing:Document" | | parentNodeAggregateId | "general-nodesworth" | | nodeName | "document" | - Then the last command should have thrown an exception of type "NodeNameIsAlreadyCovered" + Then the last command should have thrown an exception of type "NodeNameIsAlreadyOccupied" From 4961034ed297a3133ba04a3854e85ba01e7b11c2 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 15 Apr 2024 21:51:32 +0200 Subject: [PATCH 15/27] Adjust zero-dimensional test cases --- ...MoveNodeAggregateWithoutDimensions.feature | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/07-MoveNodeAggregateWithoutDimensions.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/07-MoveNodeAggregateWithoutDimensions.feature index 048a6738ceb..42efb17c2fa 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/07-MoveNodeAggregateWithoutDimensions.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/07-MoveNodeAggregateWithoutDimensions.feature @@ -26,9 +26,9 @@ Feature: Move a node without content dimensions And the graph projection is fully up to date And I am in the active content stream of workspace "live" And the command CreateRootNodeAggregateWithNode is executed with payload: - | Key | Value | - | nodeAggregateId | "lady-eleonode-rootford" | - | nodeTypeName | "Neos.ContentRepository:Root" | + | Key | Value | + | nodeAggregateId | "lady-eleonode-rootford" | + | nodeTypeName | "Neos.ContentRepository:Root" | And the event NodeAggregateWithNodeWasCreated was published with payload: | Key | Value | | contentStreamId | "cs-identifier" | @@ -151,10 +151,11 @@ Feature: Move a node without content dimensions Then I expect exactly 7 events to be published on stream "ContentStream:cs-identifier" And event at index 6 is of type "NodeAggregateWasMoved" with payload: - | Key | Expected | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | nodeMoveMappings | [{"movedNodeOrigin":[],"newLocations":[{"coveredDimensionSpacePoint": [], "newParent": {"nodeAggregateId":"sir-nodeward-nodington-iii","originDimensionSpacePoint":[]}}]}] | + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "sir-david-nodenborough" | + | newParentNodeAggregateId | "sir-nodeward-nodington-iii" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint": [],"nodeAggregateId":null}] | When the graph projection is fully up to date Then I expect the graph projection to consist of exactly 5 nodes @@ -197,10 +198,11 @@ Feature: Move a node without content dimensions | newSucceedingSiblingNodeAggregateId | "sir-nodeward-nodington-iii" | Then I expect exactly 6 events to be published on stream "ContentStream:cs-identifier" And event at index 5 is of type "NodeAggregateWasMoved" with payload: - | Key | Expected | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "nody-mc-nodeface" | - | nodeMoveMappings | [{"movedNodeOrigin":[],"newLocations":[{"coveredDimensionSpacePoint": [],"newSucceedingSibling":{"nodeAggregateId":"sir-nodeward-nodington-iii","originDimensionSpacePoint":[], "parentNodeAggregateId": "lady-eleonode-rootford", "parentOriginDimensionSpacePoint": []}}]}] | + | Key | Expected | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "nody-mc-nodeface" | + | newParentNodeAggregateId | "lady-eleonode-rootford" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint": [],"nodeAggregateId":"sir-nodeward-nodington-iii"}] | When the graph projection is fully up to date Then I expect the graph projection to consist of exactly 4 nodes From 38051db0fa3c2a8afb83eacf67b922cae4f7c482 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 15 Apr 2024 21:54:38 +0200 Subject: [PATCH 16/27] Pacify linter --- .../Classes/Feature/NodeMove/NodeMove.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php index 52cbde78625..3aa951e27d3 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php @@ -326,7 +326,7 @@ private function resolveInterdimensionalSiblingsForMove( $variantPrecedingSibling = $variantSubgraph->findNodeById($precedingSiblingId); $variantParentId = $parentNodeAggregateId ?: $variantSubgraph->findParentNode($nodeAggregateId)?->nodeAggregateId; $siblingParent = $variantSubgraph->findParentNode($precedingSiblingId); - if ($variantPrecedingSibling && $siblingParent && $variantParentId->equals($siblingParent->nodeAggregateId)) { + if ($variantPrecedingSibling && $siblingParent && $variantParentId?->equals($siblingParent->nodeAggregateId)) { // c) happy path, the explicitly requested preceding sibling also exists in this dimension space point $variantPrecedingSiblingId = $precedingSiblingId; } elseif ($alternativePrecedingSiblingIds) { @@ -337,7 +337,7 @@ private function resolveInterdimensionalSiblingsForMove( continue; } $siblingParent = $variantSubgraph->findParentNode($alternativePrecedingSiblingId); - if (!$siblingParent || !$variantParentId->equals($siblingParent->nodeAggregateId)) { + if (!$siblingParent || !$variantParentId?->equals($siblingParent->nodeAggregateId)) { continue; } $alternativeVariantSucceedingSibling = $variantSubgraph->findNodeById($alternativePrecedingSiblingId); From e6e67e62494fc19a6f9364ca5c3e62f5cd766c88 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 15 Apr 2024 22:21:09 +0200 Subject: [PATCH 17/27] Adjust other projection test cases --- .../Projection/SiblingPositions.feature | 1 - ...AreConnectedToARootNodePerSubgraph.feature | 9 ++--- .../Tests/Behavior/Features/Variants.feature | 34 +++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/SiblingPositions.feature b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/SiblingPositions.feature index f8a1f8d864f..704e7c58933 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/SiblingPositions.feature +++ b/Neos.ContentGraph.DoctrineDbalAdapter/Tests/Behavior/Features/Projection/SiblingPositions.feature @@ -97,7 +97,6 @@ Feature: Sibling positions are properly resolved Then I expect node aggregate identifier "lady-eleonode-rootford" to lead to node cs-identifier;lady-eleonode-rootford;{} And I expect this node to have the following child nodes: | Name | NodeDiscriminator | - | document | cs-identifier;sir-david-nodenborough;{"example": "general"} | | esquire | cs-identifier;sir-nodeward-nodington-iii;{"example": "general"} | | nodington-i | cs-identifier;lady-nodette-nodington-i;{"example": "general"} | | nodington-ii | cs-identifier;lady-nodette-nodington-ii;{"example": "general"} | diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesAreConnectedToARootNodePerSubgraph.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesAreConnectedToARootNodePerSubgraph.feature index 9dd34c4676b..d9c1c1604fc 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesAreConnectedToARootNodePerSubgraph.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/ProjectionIntegrityViolationDetection/AllNodesAreConnectedToARootNodePerSubgraph.feature @@ -52,10 +52,11 @@ Feature: Run projection integrity violation detection regarding root connection | nodeAggregateClassification | "regular" | And the graph projection is fully up to date And the event NodeAggregateWasMoved was published with payload: - | Key | Value | - | contentStreamId | "cs-identifier" | - | nodeAggregateId | "sir-david-nodenborough" | - | nodeMoveMappings | [{"movedNodeOrigin":{"language":"de"},"newLocations":[{"coveredDimensionSpacePoint": {"language":"de"},"newParent":{"nodeAggregateId":"nody-mc-nodeface","originDimensionSpacePoint":{"language":"de"}}}, {"coveredDimensionSpacePoint": {"language":"gsw"},"newParent":{"nodeAggregateId":"nody-mc-nodeface","originDimensionSpacePoint":{"language":"de"}}}]}] | + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "sir-david-nodenborough" | + | newParentNodeAggregateId | "nody-mc-nodeface" | + | succeedingSiblingsForCoverage | [{"dimensionSpacePoint":{"language":"de"},"nodeAggregateId": null},{"dimensionSpacePoint":{"language":"gsw"},"nodeAggregateId": null}] | And the graph projection is fully up to date And I run integrity violation detection # one error per subgraph diff --git a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Variants.feature b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Variants.feature index 00ed5bcfe98..693b379ce3b 100644 --- a/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Variants.feature +++ b/Neos.ContentRepository.LegacyNodeMigration/Tests/Behavior/Features/Variants.feature @@ -73,14 +73,14 @@ Feature: Migrating nodes with content dimensions | a1 | /sites/site/b/a1 | Some.Package:Thing | {"language": ["ch"]} | And I run the event migration Then I expect the following events to be exported - | Type | Payload | - | RootNodeAggregateWithNodeWasCreated | {} | - | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "site", "parentNodeAggregateId": "sites"} | - | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a", "parentNodeAggregateId": "site"} | - | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a1", "parentNodeAggregateId": "a", "originDimensionSpacePoint": {"language": "de"}, "succeedingSiblingsForCoverage": [{"dimensionSpacePoint":{"language": "de"},"nodeAggregateId":null},{"dimensionSpacePoint":{"language": "ch"},"nodeAggregateId":null}]} | - | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "b", "parentNodeAggregateId": "site"} | - | NodeSpecializationVariantWasCreated | {"nodeAggregateId": "a1", "sourceOrigin": {"language": "de"}, "specializationOrigin": {"language": "ch"}, "specializationSiblings": [{"dimensionSpacePoint":{"language": "ch"},"nodeAggregateId":null}]} | - | NodeAggregateWasMoved | {"nodeAggregateId": "a1", "nodeMoveMappings": [{"movedNodeOrigin":{"language":"ch"},"newLocations":[{"coveredDimensionSpacePoint":{"language":"ch"},"newSucceedingSibling":{"nodeAggregateId":"b","originDimensionSpacePoint":{"language":"de"},"parentNodeAggregateId":"a","parentOriginDimensionSpacePoint":{"language":"de"}}}]}]} | + | Type | Payload | + | RootNodeAggregateWithNodeWasCreated | {} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "site", "parentNodeAggregateId": "sites"} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a", "parentNodeAggregateId": "site"} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a1", "parentNodeAggregateId": "a", "originDimensionSpacePoint": {"language": "de"}, "succeedingSiblingsForCoverage": [{"dimensionSpacePoint":{"language": "de"},"nodeAggregateId":null},{"dimensionSpacePoint":{"language": "ch"},"nodeAggregateId":null}]} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "b", "parentNodeAggregateId": "site"} | + | NodeSpecializationVariantWasCreated | {"nodeAggregateId": "a1", "sourceOrigin": {"language": "de"}, "specializationOrigin": {"language": "ch"}, "specializationSiblings": [{"dimensionSpacePoint":{"language": "ch"},"nodeAggregateId":null}]} | + | NodeAggregateWasMoved | {"nodeAggregateId": "a1", "newParentNodeAggregateId": "b", "succeedingSiblingsForCoverage": [{"dimensionSpacePoint":{"language":"ch"},"nodeAggregateId":null}]} | Scenario: Node variant with different grand parent node (ancestor node was moved) - Note: There is only NodeAggregateWasMoved event for "a" and not for "a1" @@ -95,13 +95,13 @@ Feature: Migrating nodes with content dimensions | a1 | /sites/site/b/a/a1 | Some.Package:Thing | {"language": ["ch"]} | And I run the event migration Then I expect the following events to be exported - | Type | Payload | - | RootNodeAggregateWithNodeWasCreated | {} | - | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "site", "parentNodeAggregateId": "sites"} | - | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a", "parentNodeAggregateId": "site"} | - | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a1", "parentNodeAggregateId": "a", "originDimensionSpacePoint": {"language": "de"}, "succeedingSiblingsForCoverage": [{"dimensionSpacePoint":{"language": "de"},"nodeAggregateId":null}, {"dimensionSpacePoint":{"language": "ch"},"nodeAggregateId":null}]} | - | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "b", "parentNodeAggregateId": "site"} | - | NodeSpecializationVariantWasCreated | {"nodeAggregateId": "a", "sourceOrigin": {"language": "de"}, "specializationOrigin": {"language": "ch"}, "specializationSiblings": [{"dimensionSpacePoint":{"language": "ch"},"nodeAggregateId":null}]} | - | NodeAggregateWasMoved | {"nodeAggregateId": "a", "nodeMoveMappings": [{"movedNodeOrigin":{"language":"ch"},"newLocations":[{"coveredDimensionSpacePoint":{"language":"ch"},"newSucceedingSibling":{"nodeAggregateId":"b","originDimensionSpacePoint":{"language":"de"},"parentNodeAggregateId":"site","parentOriginDimensionSpacePoint":{"language":"de"}}}]}]} | - | NodeSpecializationVariantWasCreated | {"nodeAggregateId": "a1", "sourceOrigin": {"language": "de"}, "specializationOrigin": {"language": "ch"}, "specializationSiblings": [{"dimensionSpacePoint":{"language": "ch"},"nodeAggregateId":null}]} | + | Type | Payload | + | RootNodeAggregateWithNodeWasCreated | {} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "site", "parentNodeAggregateId": "sites"} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a", "parentNodeAggregateId": "site"} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "a1", "parentNodeAggregateId": "a", "originDimensionSpacePoint": {"language": "de"}, "succeedingSiblingsForCoverage": [{"dimensionSpacePoint":{"language": "de"},"nodeAggregateId":null}, {"dimensionSpacePoint":{"language": "ch"},"nodeAggregateId":null}]} | + | NodeAggregateWithNodeWasCreated | {"nodeAggregateId": "b", "parentNodeAggregateId": "site"} | + | NodeSpecializationVariantWasCreated | {"nodeAggregateId": "a", "sourceOrigin": {"language": "de"}, "specializationOrigin": {"language": "ch"}, "specializationSiblings": [{"dimensionSpacePoint":{"language": "ch"},"nodeAggregateId":null}]} | + | NodeAggregateWasMoved | {"nodeAggregateId": "a", "newParentNodeAggregateId": "b", "succeedingSiblingsForCoverage": [{"dimensionSpacePoint":{"language":"ch"},"nodeAggregateId":null}]} | + | NodeSpecializationVariantWasCreated | {"nodeAggregateId": "a1", "sourceOrigin": {"language": "de"}, "specializationOrigin": {"language": "ch"}, "specializationSiblings": [{"dimensionSpacePoint":{"language": "ch"},"nodeAggregateId":null}]} | From e94c1614914a232ad7fdf62ee783bc3e8f0a96bf Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Tue, 16 Apr 2024 18:30:05 +0200 Subject: [PATCH 18/27] make SubtreeTags private again --- .../Classes/Projection/ContentGraph/NodeTags.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeTags.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeTags.php index d53233c328a..8317643ab22 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeTags.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/NodeTags.php @@ -33,8 +33,8 @@ final readonly class NodeTags implements \IteratorAggregate, \Countable, \JsonSerializable { private function __construct( - public SubtreeTags $tags, - public SubtreeTags $inheritedTags, + private SubtreeTags $tags, + private SubtreeTags $inheritedTags, ) { } From 3c88de486c28fdc6f26d79e2b4b3026e24684ecc Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Tue, 16 Apr 2024 18:31:02 +0200 Subject: [PATCH 19/27] Streamline Nodes::getNodeAggregateIds naming --- .../Classes/Feature/Common/ConstraintChecks.php | 6 +++--- .../Classes/Feature/NodeMove/NodeMove.php | 6 +++--- .../Classes/Projection/ContentGraph/Nodes.php | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php index f8bf6372262..bfcb51b11c2 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php @@ -578,7 +578,7 @@ protected function requireNodeAggregateToBeSibling( $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() )->findSucceedingSiblingNodes($referenceNodeAggregateId, FindSucceedingSiblingNodesFilter::create()); - if ($succeedingSiblings->getIds()->contain($siblingNodeAggregateId)) { + if ($succeedingSiblings->getNodeAggregateIds()->contain($siblingNodeAggregateId)) { return; } @@ -587,7 +587,7 @@ protected function requireNodeAggregateToBeSibling( $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() )->findPrecedingSiblingNodes($referenceNodeAggregateId, FindPrecedingSiblingNodesFilter::create()); - if ($precedingSiblings->getIds()->contain($siblingNodeAggregateId)) { + if ($precedingSiblings->getNodeAggregateIds()->contain($siblingNodeAggregateId)) { return; } @@ -613,7 +613,7 @@ protected function requireNodeAggregateToBeChild( $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() )->findChildNodes($parentNodeAggregateId, FindChildNodesFilter::create()); - if ($childNodes->getIds()->contain($childNodeAggregateId)) { + if ($childNodes->getNodeAggregateIds()->contain($childNodeAggregateId)) { return; } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php index 3aa951e27d3..1f1e3266246 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php @@ -269,13 +269,13 @@ private function resolveInterdimensionalSiblingsForMove( ? $selectedSubgraph->findSucceedingSiblingNodes( $succeedingSiblingId, FindSucceedingSiblingNodesFilter::create() - )->getIds() + )->getNodeAggregateIds() : null; $alternativePrecedingSiblingIds = $precedingSiblingId ? $selectedSubgraph->findPrecedingSiblingNodes( $precedingSiblingId, FindPrecedingSiblingNodesFilter::create() - )->getIds() + )->getNodeAggregateIds() : null; $interdimensionalSiblings = []; @@ -354,7 +354,7 @@ private function resolveInterdimensionalSiblingsForMove( $variantSucceedingSiblingIds = $variantSubgraph->findSucceedingSiblingNodes( $variantPrecedingSiblingId, FindSucceedingSiblingNodesFilter::create(pagination: Pagination::fromLimitAndOffset(2, 0)) - )->getIds(); + )->getNodeAggregateIds(); $relevantVariantSucceedingSiblingId = null; foreach ($variantSucceedingSiblingIds as $variantSucceedingSiblingId) { if (!$variantSucceedingSiblingId->equals($nodeAggregateId)) { diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php index 461ab934305..43546e4b156 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php @@ -198,7 +198,7 @@ public function nextAll(Node $referenceNode): self return new self(array_slice($this->nodes, $referenceNodeIndex + 1)); } - public function getIds(): NodeAggregateIds + public function getNodeAggregateIds(): NodeAggregateIds { return NodeAggregateIds::create(...array_map( fn (Node $node): NodeAggregateId => $node->nodeAggregateId, From 333dcf676f35d0626754f4089c3107b80f8d9aa8 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Tue, 16 Apr 2024 18:31:54 +0200 Subject: [PATCH 20/27] Streamline exact tag check names --- .../05-MoveNodeAggregate_SubtreeTags.feature | 1280 ++++++++--------- .../Features/Bootstrap/ProjectedNodeTrait.php | 44 +- 2 files changed, 662 insertions(+), 662 deletions(-) diff --git a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/05-MoveNodeAggregate_SubtreeTags.feature b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/05-MoveNodeAggregate_SubtreeTags.feature index f38fdb6a08d..eb7d9ed22e4 100644 --- a/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/05-MoveNodeAggregate_SubtreeTags.feature +++ b/Neos.ContentRepository.BehavioralTests/Tests/Behavior/Features/08-NodeMove/05-MoveNodeAggregate_SubtreeTags.feature @@ -63,46 +63,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move an untagged node to a new parent that tags itself partially Given the command TagSubtree is executed with payload: @@ -124,46 +124,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" # move untagged to tagged @@ -187,46 +187,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move an untagged node to a new parent that is partially tagged by its ancestors Given the command TagSubtree is executed with payload: @@ -248,46 +248,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" # move tagging to untagged @@ -312,46 +312,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself partially to a new, untagged parent @@ -374,46 +374,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" # move tagging to tagging @@ -446,46 +446,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself to a new parent that tags the same, partially @@ -516,46 +516,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself partially to a new parent that tags the same @@ -586,46 +586,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself partially to a new parent that tags the same, partially @@ -656,46 +656,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself to a new parent that tags differently @@ -726,46 +726,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1,tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1,tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself to a new parent that tags differently, partially @@ -796,46 +796,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1,tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself partially to a new parent that tags differently @@ -866,46 +866,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1,tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself partially to a new parent that tags differently, partially @@ -936,46 +936,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1,tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" # move tagging to tagged @@ -1008,46 +1008,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself to a new parent that is tagged the same, partially @@ -1078,46 +1078,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself partially to a new parent that is tagged the same @@ -1148,46 +1148,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself partially to a new parent that is tagged the same, partially @@ -1218,46 +1218,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself to a new parent that is tagged differently @@ -1288,46 +1288,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1,tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1,tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself to a new parent that is tagged differently, partially @@ -1358,46 +1358,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1,tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself partially to a new parent that tags differently @@ -1428,46 +1428,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1,tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a node that tags itself partially to a new parent that is tagged differently, partially @@ -1498,46 +1498,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1,tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1,tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" # move tagged to untagged @@ -1562,46 +1562,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a partially tagged node to a new, untagged parent @@ -1624,46 +1624,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-nodeward-nodington-iii;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" # move tagged to tagging @@ -1696,46 +1696,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a tagged node to a new parent that tags the same, partially @@ -1766,46 +1766,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "tag1" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "tag1" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a partially tagged node to a new parent that tags the same @@ -1836,46 +1836,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a partially tagged node to a new parent that tags the same, partially @@ -1906,46 +1906,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a tagged node to a new parent that tags differently @@ -1976,46 +1976,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a tagged node to a new parent that tags differently, partially @@ -2046,46 +2046,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a partially tagged node to a new parent that tags differently @@ -2116,46 +2116,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a partially tagged node to a new parent that tags differently, partially @@ -2186,46 +2186,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" # move tagged to tagged @@ -2258,46 +2258,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a tagged node to a new parent that is tagged the same, partially @@ -2328,46 +2328,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a partially tagged node to a new parent that is tagged the same @@ -2398,46 +2398,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a partially tagged node to a new parent that is tagged the same, partially @@ -2468,46 +2468,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag1" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag1" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a tagged node to a new parent that is tagged differently @@ -2538,46 +2538,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a tagged node to a new parent that is tagged differently, partially @@ -2608,46 +2608,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a partially tagged node to a new parent that is tagged differently @@ -2678,46 +2678,46 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" Scenario: Move a partially tagged node to a new parent that is tagged differently, partially @@ -2748,43 +2748,43 @@ Feature: Move a node aggregate into and out of a tagged parent When I am in the active content stream of workspace "live" and dimension space point {"example": "general"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "source"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" When I am in the active content stream of workspace "live" and dimension space point {"example": "spec"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "esquire/esquire-child/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;nodimus-prime;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" And I expect node aggregate identifier "nodimus-mediocre" and node path "esquire/esquire-child/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "tag2" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "tag2" When I am in the active content stream of workspace "live" and dimension space point {"example": "peer"} Then I expect node aggregate identifier "nody-mc-nodeface" and node path "parent-document/document" to lead to node cs-identifier;nody-mc-nodeface;{"example":"general"} And I expect this node to be a child of node cs-identifier;sir-david-nodenborough;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" And I expect node aggregate identifier "nodimus-mediocre" and node path "parent-document/document/child-document" to lead to node cs-identifier;nodimus-mediocre;{"example":"general"} And I expect this node to be a child of node cs-identifier;nody-mc-nodeface;{"example":"general"} - And I expect this node to tag with "" - And I expect this node to be tagged with "" + And I expect this node to be exactly explicitly tagged "" + And I expect this node to exactly inherit the tags "" diff --git a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php index 85cea48b444..bee6d1ffec9 100644 --- a/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php +++ b/Neos.ContentRepository.TestSuite/Classes/Behavior/Features/Bootstrap/ProjectedNodeTrait.php @@ -241,6 +241,28 @@ public function iExpectTheNodeWithAggregateIdentifierToNotContainTheTag(string $ }); } + /** + * @Then /^I expect this node to be exactly explicitly tagged "(.*)"$/ + * @param string $tagList the comma-separated list of tag names + */ + public function iExpectThisNodeToBeExactlyExplicitlyTagged(string $tagList): void + { + $this->assertOnCurrentNode(function (Node $currentNode) use ($tagList) { + $currentNode->tags->withoutInherited()->toStringArray() === explode(',', $tagList); + }); + } + + /** + * @Then /^I expect this node to exactly inherit the tags "(.*)"$/ + * @param string $tagList the comma-separated list of tag names + */ + public function iExpectThisNodeToExactlyInheritTheTags(string $tagList): void + { + $this->assertOnCurrentNode(function (Node $currentNode) use ($tagList) { + $currentNode->tags->onlyInherited()->toStringArray() === explode(',', $tagList); + }); + } + protected function initializeCurrentNodeFromContentGraph(callable $query): void { $this->currentNode = $query($this->currentContentRepository->getContentGraph()); @@ -650,28 +672,6 @@ public function iExpectThisNodeToHaveTheFollowingSucceedingSiblings(TableNode $e }); } - /** - * @Then /^I expect this node to tag with "(.*)"$/ - * @param string $tagList the comma-separated list of tag names - */ - public function iExpectThisNodeToTagWith(string $tagList): void - { - $this->assertOnCurrentNode(function (Node $currentNode) use ($tagList) { - $currentNode->tags->tags->toStringArray() === explode(',', $tagList); - }); - } - - /** - * @Then /^I expect this node to be tagged with "(.*)"$/ - * @param string $tagList the comma-separated list of tag names - */ - public function iExpectThisNodeToBeTaggedWith(string $tagList): void - { - $this->assertOnCurrentNode(function (Node $currentNode) use ($tagList) { - $currentNode->tags->inheritedTags->toStringArray() === explode(',', $tagList); - }); - } - /** * @Then /^I expect this node to have no succeeding siblings$/ */ From 1427c1fe649f691bd96e0465be6fd7f88f9a64fc Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Tue, 16 Apr 2024 19:22:45 +0200 Subject: [PATCH 21/27] Use event instead of command DSP for ChangeProjection --- .../PendingChangesProjection/ChangeProjection.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php b/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php index 6cbd8ffbb23..250cf0e5ab5 100644 --- a/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php +++ b/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php @@ -21,12 +21,12 @@ use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Types; +use Neos\ContentRepository\Core\DimensionSpace\DimensionSpacePoint; use Neos\ContentRepository\Core\DimensionSpace\OriginDimensionSpacePoint; use Neos\ContentRepository\Core\EventStore\EventInterface; use Neos\ContentRepository\Core\Feature\DimensionSpaceAdjustment\Event\DimensionSpacePointWasMoved; use Neos\ContentRepository\Core\Feature\NodeCreation\Event\NodeAggregateWithNodeWasCreated; use Neos\ContentRepository\Core\Feature\NodeModification\Event\NodePropertiesWereSet; -use Neos\ContentRepository\Core\Feature\NodeMove\Command\MoveNodeAggregate; use Neos\ContentRepository\Core\Feature\NodeMove\Event\NodeAggregateWasMoved; use Neos\ContentRepository\Core\Feature\NodeReferencing\Event\NodeReferencesWereSet; use Neos\ContentRepository\Core\Feature\NodeRemoval\Event\NodeAggregateWasRemoved; @@ -233,18 +233,19 @@ private function whenRootWorkspaceWasCreated(RootWorkspaceWasCreated $event): vo private function whenNodeAggregateWasMoved(NodeAggregateWasMoved $event, EventEnvelope $eventEnvelope): void { - // Changes reflect the editorial intention, not the effect as they are later published via commands - $metadata = $eventEnvelope->event->metadata?->value ?? []; - if (isset($metadata['commandPayload'])) { - $command = MoveNodeAggregate::fromArray($metadata['commandPayload']); - // WORKAROUND: we simply use the command's DSP here as the origin dimension space point. + $affectedDimensionSpacePoints = iterator_to_array($event->succeedingSiblingsForCoverage->toDimensionSpacePointSet()); + $arbitraryDimensionSpacePoint = reset($affectedDimensionSpacePoints); + if ($arbitraryDimensionSpacePoint instanceof DimensionSpacePoint) { + // always the case due to constraint enforcement (at least one DSP is selected and must have a succeeding sibling or null) + + // WORKAROUND: we simply use the event's first DSP here as the origin dimension space point. // But this DSP is not necessarily occupied. // @todo properly handle this by storing the necessary information in the projection $this->markAsMoved( $event->getContentStreamId(), $event->getNodeAggregateId(), - OriginDimensionSpacePoint::fromDimensionSpacePoint($command->dimensionSpacePoint) + OriginDimensionSpacePoint::fromDimensionSpacePoint($arbitraryDimensionSpacePoint) ); } } From 0acaaf1b68e0fad4576bcd25f22e24cbabe36aa3 Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Fri, 26 Apr 2024 23:22:56 +0200 Subject: [PATCH 22/27] Introduce and use Nodes::map --- .../Classes/Feature/Common/ConstraintChecks.php | 6 +++--- .../Classes/Feature/NodeMove/NodeMove.php | 6 +++--- .../Classes/Projection/ContentGraph/Nodes.php | 14 +++++++++++--- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php index bfcb51b11c2..2ee3b0f4bf2 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php @@ -578,7 +578,7 @@ protected function requireNodeAggregateToBeSibling( $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() )->findSucceedingSiblingNodes($referenceNodeAggregateId, FindSucceedingSiblingNodesFilter::create()); - if ($succeedingSiblings->getNodeAggregateIds()->contain($siblingNodeAggregateId)) { + if ($succeedingSiblings->mapToNodeAggregateIds()->contain($siblingNodeAggregateId)) { return; } @@ -587,7 +587,7 @@ protected function requireNodeAggregateToBeSibling( $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() )->findPrecedingSiblingNodes($referenceNodeAggregateId, FindPrecedingSiblingNodesFilter::create()); - if ($precedingSiblings->getNodeAggregateIds()->contain($siblingNodeAggregateId)) { + if ($precedingSiblings->mapToNodeAggregateIds()->contain($siblingNodeAggregateId)) { return; } @@ -613,7 +613,7 @@ protected function requireNodeAggregateToBeChild( $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() )->findChildNodes($parentNodeAggregateId, FindChildNodesFilter::create()); - if ($childNodes->getNodeAggregateIds()->contain($childNodeAggregateId)) { + if ($childNodes->mapToNodeAggregateIds()->contain($childNodeAggregateId)) { return; } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php index 1f1e3266246..a93f5f0aa8a 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php @@ -269,13 +269,13 @@ private function resolveInterdimensionalSiblingsForMove( ? $selectedSubgraph->findSucceedingSiblingNodes( $succeedingSiblingId, FindSucceedingSiblingNodesFilter::create() - )->getNodeAggregateIds() + )->mapToNodeAggregateIds() : null; $alternativePrecedingSiblingIds = $precedingSiblingId ? $selectedSubgraph->findPrecedingSiblingNodes( $precedingSiblingId, FindPrecedingSiblingNodesFilter::create() - )->getNodeAggregateIds() + )->mapToNodeAggregateIds() : null; $interdimensionalSiblings = []; @@ -354,7 +354,7 @@ private function resolveInterdimensionalSiblingsForMove( $variantSucceedingSiblingIds = $variantSubgraph->findSucceedingSiblingNodes( $variantPrecedingSiblingId, FindSucceedingSiblingNodesFilter::create(pagination: Pagination::fromLimitAndOffset(2, 0)) - )->getNodeAggregateIds(); + )->mapToNodeAggregateIds(); $relevantVariantSucceedingSiblingId = null; foreach ($variantSucceedingSiblingIds as $variantSucceedingSiblingId) { if (!$variantSucceedingSiblingId->equals($nodeAggregateId)) { diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php index 43546e4b156..5cc25e8fd00 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php @@ -198,11 +198,19 @@ public function nextAll(Node $referenceNode): self return new self(array_slice($this->nodes, $referenceNodeIndex + 1)); } - public function getNodeAggregateIds(): NodeAggregateIds + /** + * @param \Closure(Node $node): mixed $callback + * @return array + */ + public function map(\Closure $callback): array + { + return array_map($callback, $this->nodes); + } + + public function mapToNodeAggregateIds(): NodeAggregateIds { - return NodeAggregateIds::create(...array_map( + return NodeAggregateIds::create(...$this->map( fn (Node $node): NodeAggregateId => $node->nodeAggregateId, - $this->nodes )); } } From 6318c7fd2fd7ba5d7283b2b9d9b0080c6ace6c6b Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 29 Apr 2024 23:32:00 +0200 Subject: [PATCH 23/27] Update Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php Co-authored-by: Wilhelm Behncke <2522299+grebaldi@users.noreply.github.com> --- Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php b/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php index 250cf0e5ab5..208828be296 100644 --- a/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php +++ b/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php @@ -184,7 +184,7 @@ public function apply(EventInterface $event, EventEnvelope $eventEnvelope): void { match ($event::class) { RootWorkspaceWasCreated::class => $this->whenRootWorkspaceWasCreated($event), - NodeAggregateWasMoved::class => $this->whenNodeAggregateWasMoved($event, $eventEnvelope), + NodeAggregateWasMoved::class => $this->whenNodeAggregateWasMoved($event), NodePropertiesWereSet::class => $this->whenNodePropertiesWereSet($event), NodeReferencesWereSet::class => $this->whenNodeReferencesWereSet($event), NodeAggregateWithNodeWasCreated::class => $this->whenNodeAggregateWithNodeWasCreated($event), From 5a7bcfd411eeaabd77b31e1ee99792e9c6ed7c4e Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 29 Apr 2024 23:32:21 +0200 Subject: [PATCH 24/27] Update Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php Co-authored-by: Wilhelm Behncke <2522299+grebaldi@users.noreply.github.com> --- Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php b/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php index 208828be296..a4568f635bf 100644 --- a/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php +++ b/Neos.Neos/Classes/PendingChangesProjection/ChangeProjection.php @@ -231,7 +231,7 @@ private function whenRootWorkspaceWasCreated(RootWorkspaceWasCreated $event): vo } } - private function whenNodeAggregateWasMoved(NodeAggregateWasMoved $event, EventEnvelope $eventEnvelope): void + private function whenNodeAggregateWasMoved(NodeAggregateWasMoved $event): void { $affectedDimensionSpacePoints = iterator_to_array($event->succeedingSiblingsForCoverage->toDimensionSpacePointSet()); $arbitraryDimensionSpacePoint = reset($affectedDimensionSpacePoints); From 839ea3aa2f804916b96d8e1427bbaba70808bd3d Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 29 Apr 2024 23:33:33 +0200 Subject: [PATCH 25/27] Update Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php Co-authored-by: Wilhelm Behncke <2522299+grebaldi@users.noreply.github.com> --- .../src/Domain/Projection/Feature/NodeMove.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php index 3cf3a3e1387..0c73276f779 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php @@ -96,7 +96,7 @@ private function moveNodeBeforeSucceedingSibling( $newSucceedingSibling = null; if ($succeedingSiblingForCoverage->nodeAggregateId) { - // find the new succeeding sibling NodeRecord; We need this records because we'll use its RelationAnchorPoint later. + // find the new succeeding sibling NodeRecord; We need this record because we'll use its RelationAnchorPoint later. $newSucceedingSibling = $projectionContentGraph->findNodeInAggregate( $contentStreamId, $succeedingSiblingForCoverage->nodeAggregateId, From 56cbfabd019415df8439a82768701f176e17ab9e Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Mon, 29 Apr 2024 23:34:06 +0200 Subject: [PATCH 26/27] Update Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php Co-authored-by: Wilhelm Behncke <2522299+grebaldi@users.noreply.github.com> --- .../Classes/Projection/ContentGraph/Nodes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php index 5cc25e8fd00..13fc62b379a 100644 --- a/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php +++ b/Neos.ContentRepository.Core/Classes/Projection/ContentGraph/Nodes.php @@ -207,7 +207,7 @@ public function map(\Closure $callback): array return array_map($callback, $this->nodes); } - public function mapToNodeAggregateIds(): NodeAggregateIds + public function toNodeAggregateIds(): NodeAggregateIds { return NodeAggregateIds::create(...$this->map( fn (Node $node): NodeAggregateId => $node->nodeAggregateId, From 77ffad48500da2a3f57fa97f912ecd32cc05e7bc Mon Sep 17 00:00:00 2001 From: Bernhard Schmitt Date: Tue, 30 Apr 2024 22:34:43 +0200 Subject: [PATCH 27/27] Adjust to comments --- .../src/Domain/Projection/Feature/NodeMove.php | 6 +++--- .../Classes/Feature/Common/ConstraintChecks.php | 6 +++--- .../Classes/Feature/NodeMove/NodeMove.php | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php index 0c73276f779..fbd88417383 100644 --- a/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php +++ b/Neos.ContentGraph.DoctrineDbalAdapter/src/Domain/Projection/Feature/NodeMove.php @@ -48,7 +48,7 @@ private function whenNodeAggregateWasMoved(NodeAggregateWasMoved $event): void } if ($event->newParentNodeAggregateId) { - $this->moveNodeIntoParent( + $this->moveNodeBeneathParent( $event->contentStreamId, $nodeToBeMoved, $event->newParentNodeAggregateId, @@ -132,10 +132,10 @@ private function moveNodeBeforeSucceedingSibling( * which incoming HierarchyRelation should be moved and where exactly. * * The move target is given as $parentNodeAggregateId and $succeedingSiblingForCoverage. - * We always move to parent after the succeeding sibling if given (or to the end) + * We always move beneath the parent before the succeeding sibling if given (or to the end) * @throws DBALException */ - private function moveNodeIntoParent( + private function moveNodeBeneathParent( ContentStreamId $contentStreamId, NodeRecord $nodeToBeMoved, NodeAggregateId $parentNodeAggregateId, diff --git a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php index 2ee3b0f4bf2..f83f1cf83ae 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php +++ b/Neos.ContentRepository.Core/Classes/Feature/Common/ConstraintChecks.php @@ -578,7 +578,7 @@ protected function requireNodeAggregateToBeSibling( $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() )->findSucceedingSiblingNodes($referenceNodeAggregateId, FindSucceedingSiblingNodesFilter::create()); - if ($succeedingSiblings->mapToNodeAggregateIds()->contain($siblingNodeAggregateId)) { + if ($succeedingSiblings->toNodeAggregateIds()->contain($siblingNodeAggregateId)) { return; } @@ -587,7 +587,7 @@ protected function requireNodeAggregateToBeSibling( $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() )->findPrecedingSiblingNodes($referenceNodeAggregateId, FindPrecedingSiblingNodesFilter::create()); - if ($precedingSiblings->mapToNodeAggregateIds()->contain($siblingNodeAggregateId)) { + if ($precedingSiblings->toNodeAggregateIds()->contain($siblingNodeAggregateId)) { return; } @@ -613,7 +613,7 @@ protected function requireNodeAggregateToBeChild( $dimensionSpacePoint, VisibilityConstraints::withoutRestrictions() )->findChildNodes($parentNodeAggregateId, FindChildNodesFilter::create()); - if ($childNodes->mapToNodeAggregateIds()->contain($childNodeAggregateId)) { + if ($childNodes->toNodeAggregateIds()->contain($childNodeAggregateId)) { return; } diff --git a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php index a93f5f0aa8a..b164a54d2a0 100644 --- a/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php +++ b/Neos.ContentRepository.Core/Classes/Feature/NodeMove/NodeMove.php @@ -269,13 +269,13 @@ private function resolveInterdimensionalSiblingsForMove( ? $selectedSubgraph->findSucceedingSiblingNodes( $succeedingSiblingId, FindSucceedingSiblingNodesFilter::create() - )->mapToNodeAggregateIds() + )->toNodeAggregateIds() : null; $alternativePrecedingSiblingIds = $precedingSiblingId ? $selectedSubgraph->findPrecedingSiblingNodes( $precedingSiblingId, FindPrecedingSiblingNodesFilter::create() - )->mapToNodeAggregateIds() + )->toNodeAggregateIds() : null; $interdimensionalSiblings = []; @@ -354,7 +354,7 @@ private function resolveInterdimensionalSiblingsForMove( $variantSucceedingSiblingIds = $variantSubgraph->findSucceedingSiblingNodes( $variantPrecedingSiblingId, FindSucceedingSiblingNodesFilter::create(pagination: Pagination::fromLimitAndOffset(2, 0)) - )->mapToNodeAggregateIds(); + )->toNodeAggregateIds(); $relevantVariantSucceedingSiblingId = null; foreach ($variantSucceedingSiblingIds as $variantSucceedingSiblingId) { if (!$variantSucceedingSiblingId->equals($nodeAggregateId)) {