167 lines
7.4 KiB
Gherkin
167 lines
7.4 KiB
Gherkin
@phase1 @domain @repository @resource_dag
|
|
Feature: Resource DAG Linking and Discovery
|
|
As a system operator managing resource hierarchies
|
|
I want to link resources in a directed acyclic graph
|
|
So that parent-child relationships are enforced with type safety
|
|
|
|
Background:
|
|
Given a clean resource DAG database
|
|
And a resource type repository for DAG tests
|
|
And a resource repository for DAG tests
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# link_child / unlink_child basic operations
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@dag_link
|
|
Scenario: Link a child resource to a parent
|
|
Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
|
|
And a DAG child type "dag/child-type"
|
|
And a DAG resource "P1" typed "dag/parent-type"
|
|
And a DAG resource "C1" typed "dag/child-type"
|
|
When DAG child "C1" is linked to parent "P1"
|
|
Then the DAG link should succeed without error
|
|
And DAG children of "P1" should include "C1"
|
|
|
|
@dag_unlink
|
|
Scenario: Unlink a child resource from a parent
|
|
Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
|
|
And a DAG child type "dag/child-type"
|
|
And a DAG resource "P1" typed "dag/parent-type"
|
|
And a DAG resource "C1" typed "dag/child-type"
|
|
And DAG child "C1" is already linked to parent "P1"
|
|
When DAG child "C1" is unlinked from parent "P1"
|
|
Then the DAG unlink should succeed without error
|
|
And DAG children of "P1" should be empty
|
|
|
|
@dag_link @error_handling
|
|
Scenario: Linking a non-existent parent raises an error
|
|
Given a DAG child type "dag/child-type"
|
|
And a DAG resource "C1" typed "dag/child-type"
|
|
When DAG linking child "C1" to missing parent "MISSING_ID_00000000000000"
|
|
Then a DAG ResourceNotFoundRepoError should be raised
|
|
|
|
@dag_link @error_handling
|
|
Scenario: Linking a non-existent child raises an error
|
|
Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
|
|
And a DAG resource "P1" typed "dag/parent-type"
|
|
When DAG linking missing child "MISSING_ID_00000000000000" to parent "P1"
|
|
Then a DAG ResourceNotFoundRepoError should be raised
|
|
|
|
@dag_link @error_handling
|
|
Scenario: Duplicate link raises an error
|
|
Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
|
|
And a DAG child type "dag/child-type"
|
|
And a DAG resource "P1" typed "dag/parent-type"
|
|
And a DAG resource "C1" typed "dag/child-type"
|
|
And DAG child "C1" is already linked to parent "P1"
|
|
When DAG child "C1" is linked to parent "P1" again
|
|
Then a DAG DuplicateResourceLinkError should be raised
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Cycle detection
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@dag_cycle
|
|
Scenario: Self-link is rejected
|
|
Given a DAG parent type "dag/parent-type" allowing children '["dag/parent-type"]'
|
|
And a DAG resource "P1" typed "dag/parent-type"
|
|
When DAG resource "P1" is linked to itself
|
|
Then a DAG CycleDetectedError should be raised
|
|
|
|
@dag_cycle
|
|
Scenario: Direct cycle A->B->A is rejected
|
|
Given a DAG parent type "dag/parent-type" allowing children '["dag/parent-type"]'
|
|
And a DAG resource "A" typed "dag/parent-type"
|
|
And a DAG resource "B" typed "dag/parent-type"
|
|
And DAG child "B" is already linked to parent "A"
|
|
When DAG child "A" is linked to parent "B"
|
|
Then a DAG CycleDetectedError should be raised
|
|
|
|
@dag_cycle
|
|
Scenario: Transitive cycle A->B->C->A is rejected
|
|
Given a DAG parent type "dag/parent-type" allowing children '["dag/parent-type"]'
|
|
And a DAG resource "A" typed "dag/parent-type"
|
|
And a DAG resource "B" typed "dag/parent-type"
|
|
And a DAG resource "C" typed "dag/parent-type"
|
|
And DAG child "B" is already linked to parent "A"
|
|
And DAG child "C" is already linked to parent "B"
|
|
When DAG child "A" is linked to parent "C"
|
|
Then a DAG CycleDetectedError should be raised
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Type compatibility enforcement
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@dag_type_compat
|
|
Scenario: Linking incompatible types is rejected
|
|
Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
|
|
And a DAG child type "dag/other-type"
|
|
And a DAG resource "P1" typed "dag/parent-type"
|
|
And a DAG resource "C1" typed "dag/other-type"
|
|
When DAG child "C1" is linked to parent "P1"
|
|
Then a DAG TypeIncompatibleError should be raised
|
|
|
|
@dag_type_compat
|
|
Scenario: Linking compatible types succeeds
|
|
Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
|
|
And a DAG child type "dag/child-type"
|
|
And a DAG resource "P1" typed "dag/parent-type"
|
|
And a DAG resource "C1" typed "dag/child-type"
|
|
When DAG child "C1" is linked to parent "P1"
|
|
Then the DAG link should succeed without error
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# auto_discover_children
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@dag_auto_discover
|
|
Scenario: Auto-discover creates child resources per type rules
|
|
Given a DAG parent type "dag/discover-parent" with auto-discovery for "dag/discover-child"
|
|
And a DAG child type "dag/discover-child"
|
|
And a DAG resource "P1" typed "dag/discover-parent"
|
|
When DAG auto_discover_children is called for "P1"
|
|
Then at least 1 DAG child should be created
|
|
And DAG created children should be typed "dag/discover-child"
|
|
And DAG created children should be linked to "P1"
|
|
|
|
@dag_auto_discover
|
|
Scenario: Auto-discover with no rules creates nothing
|
|
Given a DAG parent type "dag/no-disc-parent" without auto-discovery
|
|
And a DAG resource "P1" typed "dag/no-disc-parent"
|
|
When DAG auto_discover_children is called for "P1"
|
|
Then 0 DAG children should be created
|
|
|
|
@dag_auto_discover @error_handling
|
|
Scenario: Auto-discover for non-existent resource raises error
|
|
When DAG auto_discover_children is called for missing "MISSING_ID_00000000000000"
|
|
Then a DAG ResourceNotFoundRepoError should be raised
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Tree traversal
|
|
# ---------------------------------------------------------------------------
|
|
|
|
@dag_traversal
|
|
Scenario: Get children returns all direct children
|
|
Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
|
|
And a DAG child type "dag/child-type"
|
|
And a DAG resource "P1" typed "dag/parent-type"
|
|
And a DAG resource "C1" typed "dag/child-type"
|
|
And a DAG resource "C2" typed "dag/child-type"
|
|
And DAG child "C1" is already linked to parent "P1"
|
|
And DAG child "C2" is already linked to parent "P1"
|
|
When DAG children of "P1" are retrieved
|
|
Then 2 DAG children should be returned
|
|
|
|
@dag_traversal
|
|
Scenario: Get parents returns all direct parents
|
|
Given a DAG parent type "dag/parent-type" allowing children '["dag/child-type"]'
|
|
And a DAG child type "dag/child-type"
|
|
And a DAG resource "P1" typed "dag/parent-type"
|
|
And a DAG resource "P2" typed "dag/parent-type"
|
|
And a DAG resource "C1" typed "dag/child-type"
|
|
And DAG child "C1" is already linked to parent "P1"
|
|
And DAG child "C1" is already linked to parent "P2"
|
|
When DAG parents of "C1" are retrieved
|
|
Then 2 DAG parents should be returned
|