Commit 789dc7ea authored by kzangeli's avatar kzangeli
Browse files

test(csr): accept either attributeNames or the deprecated pair in registration diffs



A RegistrationInfo's registered attributes may be returned either as the single
attributeNames list or as the deprecated propertyNames/relationshipNames pair —
both are valid GET /csourceRegistrations output, since a broker need not store the
property/relationship split. Before diffing, fold any pair into attributeNames on
both expected and actual (on copies). Real attribute-name differences still surface
(different/missing names change the attributeNames set); entity comparisons are
untouched. Lets the existing old-pair expectation fixtures pass against a broker
that emits attributeNames, without changing the fixtures.

Co-Authored-By: default avatarClaude Opus 4.8 (1M context) <noreply@anthropic.com>
parent 1194f78a
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
import copy
from re import compile
from dataclasses import dataclass
from typing import Any
@@ -83,6 +84,33 @@ class SystemGeneratedTemporalPropertyOperator(BaseOperatorPlus):
        return obj


# A RegistrationInfo (an information[] element) may express its registered
# attributes either as the deprecated propertyNames/relationshipNames pair or as
# the single attributeNames list — both are valid GET /csourceRegistrations
# output, since a broker need not store the property/relationship split. To
# accept whichever representation the broker returns, the deprecated pair is
# folded into attributeNames on BOTH sides before diffing (see
# canonicalise_registration_attribute_names). A genuinely different attribute
# name still produces a different attributeNames set, so real diffs are kept.
def canonicalise_registration_attribute_names(obj):
    """Recursively fold any propertyNames/relationshipNames into a single
    attributeNames, in place. Only dicts carrying the deprecated pair are
    touched; an attributeNames-only object is left as-is (list order is handled
    by DeepDiff's ignore_order)."""
    if isinstance(obj, list):
        for item in obj:
            canonicalise_registration_attribute_names(item)
    elif isinstance(obj, dict):
        if 'propertyNames' in obj or 'relationshipNames' in obj:
            merged = list(obj.get('attributeNames') or [])
            merged += list(obj.pop('propertyNames', None) or [])
            merged += list(obj.pop('relationshipNames', None) or [])
            obj['attributeNames'] = merged
        for value in obj.values():
            canonicalise_registration_attribute_names(value)
    return obj


def compare_func(x, y, level=None):
    try:
        return x['id'] == y['id']
@@ -105,6 +133,12 @@ def compare_dictionaries_ignoring_keys(expected, actual, exclude_regex_paths, ig
    broker-computed Additional Members inside 'notification'). 0 restores per-key diffs.
    """

    # Accept either the deprecated propertyNames/relationshipNames pair or the
    # single attributeNames list in RegistrationInfo — fold both sides to
    # attributeNames before diffing (on copies, so caller data is untouched).
    expected = canonicalise_registration_attribute_names(copy.deepcopy(expected))
    actual = canonicalise_registration_attribute_names(copy.deepcopy(actual))

    if group_by is not None and ignore_core_context_version:
        res = DeepDiff(expected, actual, exclude_regex_paths=exclude_regex_paths, ignore_order=True, verbose_level=1,
                       threshold_to_diff_deeper=0,