fix(046_22_08, 034_05_01): the NGSI-LD Null in a deletion notification and in an update

Two Test Cases that get the NGSI-LD Null wrong.

  • 046_22_08: name has three instances in building-multi-instances-attributes (the default one and two datasetIds), and all three are deleted. TS 104-175 clause 10.5.7: a deleted Attribute that needs a datasetId is notified as a JSON object whose value is urn:ngsi-ld:null - one per instance. So name is an Array of three such objects; the TC read it as one object and failed inside Robot (list indices must be integers). It now checks the three instances.
  • 034_05_01: expiresAt is removed with the NGSI-LD Null "urn:ngsi-ld:null". TS 104-175 clause 8.4.2: a Fragment member whose value is an NGSI-LD Null deletes the target member. The fixture sent a JSON null, which JSON-LD expansion drops before the update, so the update did nothing.

2 Test Cases. Both fail on develop and pass with this MR.

Merge request reports

Loading
+8 −5
Changes for TP/NGSI-LD/ContextInformation/Subscription/SubscriptionNotificationBehaviour/046_22_08.robot: 8 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@ Test Teardown Delete Initial Subscription And Entity
*** Variables ***
${subscription_payload_file_path}=      subscriptions/subscription-building-entities-attributeDeleted-specific-attribute-normalized.jsonld
${building_filename}=                   building-multi-instances-attributes.jsonld
${entity_expectation_file_path}=        entity-deleted-name-attribute-instance-normalized.json


*** Test Cases ***
@@ -36,10 +35,14 @@ ${entity_expectation_file_path}= entity-deleted-name-attribute-instance-n
    Should be Equal    ${subscription_id}    ${notification}[subscriptionId]
    Length Should Be    ${notification}[data]    ${1}
    Should be Equal    ${entity_id}    ${notification}[data][0][id]
    Check JSON Value In Response Body
    ...    json_path_expr=['name']['value']
    ...    value_to_check=urn:ngsi-ld:null
    ...    response_body=${notification}[data][0]

    # name has three instances in building-multi-instances-attributes (the default one and two datasetIds), and
    # deleteAll=true deletes all three: the notification carries name as an Array with an NGSI-LD Null per deleted
    # instance (TS 104 175 clause 10.5.7)
    Check Notification Containing Deleted Attribute Instances
    ...    name
    ...    ${{[None, 'urn:ngsi-ld:Dataset:french-name', 'urn:ngsi-ld:Dataset:german-name']}}
    ...    ${notification}


*** Keywords ***
+9 −5
Changes for TP/NGSI-LD/ContextSource/Registration/UpdateContextSourceRegistration/034_05.robot: 9 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -12,17 +12,16 @@ Test Teardown Delete Updated Context Source Registration
Test Template       Update A Context Source


*** Test Cases ***    FILENAME    UPDATE_FILENAME
*** Test Cases ***    UPDATE_FILENAME
034_05_01 Update A Context Source Registration To Never Expire
    [Tags]    csr-update    core_12_2_3
    context-source-registration-with-expiration.jsonld    context-source-registration-null-expiresAt.json
    context-source-registration-null-expiresAt.json


*** Keywords ***
Update A Context Source
    [Documentation]    Check that one can update a context source registration by id
    [Arguments]    ${filename}    ${update_filename}
    Set Test Variable    ${filename}
    [Arguments]    ${update_filename}
    ${fragment}=    Load JSON From File    ${EXECDIR}/data/csourceRegistrations/fragments/${update_filename}
    ${registration_update_fragment}=    Update Value To JSON    ${fragment}    $.id    ${registration_id}
    ${response}=    Update Context Source Registration With Return
@@ -44,8 +43,13 @@ Initialize the Test Case
    ${registration_id}=    Generate Random CSR Id
    Set Test Variable    ${registration_id}
    ${payload}=    Load JSON From File
    ...    ${EXECDIR}/data/csourceRegistrations/context-source-registration.jsonld
    ...    ${EXECDIR}/data/csourceRegistrations/context-source-registration-with-expiration.jsonld
    ${registration_payload}=    Update Value To JSON    ${payload}    $..id    ${registration_id}
    Set Test Variable    ${registration_payload}
    ${response}=    Create Context Source Registration With Return    ${registration_payload}
    Check Response Status Code    201    ${response.status_code}
    # The update under test deletes expiresAt: it has to be there before it
    ${response}=    Retrieve Context Source Registration
    ...    context_source_registration_id=${registration_id}
    Dictionary Should Contain Key    ${response.json()}    expiresAt
    ...    msg=the registration was created with an expiresAt, the broker does not return it
+1 −1
Changes for data/csourceRegistrations/fragments/context-source-registration-null-expiresAt.json: 1 added line, 1 removed line.
Original line number Diff line number Diff line
{
   "expiresAt": null
   "expiresAt": "urn:ngsi-ld:null"
}
 No newline at end of file
+16 −0
Changes for doc/analysis/checks.py: 16 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -152,6 +152,8 @@ class Checks:
                Checks.check_notification_containing_entity_element,
            'Check Notification Containing Entities Elements':
                Checks.check_notification_containing_entities_elements,
            'Check Notification Containing Deleted Attribute Instances':
                Checks.check_notification_containing_deleted_attribute_instances,
            'Check Notification Containing GeoJSON FeatureCollection':
                Checks.check_notification_containing_geojson_featurecollection,
            'Check Body With Alternatives':
@@ -446,6 +448,10 @@ class Checks:
                'params': ['filename', 'notification'],
                'position': [0, 1]
            },
            'Check Notification Containing Deleted Attribute Instances': {
                'params': ['attribute_name', 'expected_dataset_ids', 'notification'],
                'position': [0, 1, 2]
            },
            'Check Notification Containing GeoJSON FeatureCollection': {
                'params': ['filename', 'notification'],
                'position': [0, 1]
@@ -1183,6 +1189,16 @@ class Checks:
        else:
            raise Exception(f"ERROR, Expected 'filename' and 'notification' but received: '{kwargs}'")

    @staticmethod
    def check_notification_containing_deleted_attribute_instances(kwargs: list) -> str:
        if 'attribute_name' in kwargs and 'expected_dataset_ids' in kwargs and 'notification' in kwargs:
            return (f"Notification containing the Attribute '{kwargs['attribute_name']}' with one instance "
                    f"set to urn:ngsi-ld:null per deleted instance, with datasetIds set to "
                    f"{kwargs['expected_dataset_ids']}")
        else:
            raise Exception(f"ERROR, Expected 'attribute_name', 'expected_dataset_ids' and 'notification' "
                            f"but received: '{kwargs}'")

    @staticmethod
    def check_notification_containing_geojson_featurecollection(kwargs: list) -> str:
        if 'filename' in kwargs and 'notification' in kwargs:
+18 −0
Changes for resources/AssertionUtils.resource: 18 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -506,6 +506,24 @@ Check Notification Containing Entities Elements
    ...    group_by=id
    Should Be Empty    ${comparison_result}    msg=${comparison_result.pretty()}

Check Notification Containing Deleted Attribute Instances
    [Documentation]    The notification of the deletion of every instance of a multi-instance Attribute carries the
    ...    Attribute as an Array with one instance per deleted instance, each with value urn:ngsi-ld:null and the
    ...    datasetId of the deleted instance (none for the default instance) - TS 104 175 clause 10.5.7
    [Arguments]    ${attribute_name}    ${expected_dataset_ids}    ${notification}
    ${deleted_instances}=    Set Variable    ${notification}[data][0][${attribute_name}]
    Should Be True    isinstance($deleted_instances, list)
    ...    msg=${attribute_name} should be an Array with one NGSI-LD Null instance per deleted datasetId
    ${dataset_ids}=    Create List
    FOR    ${instance}    IN    @{deleted_instances}
        Should Be Equal    ${instance}[value]    urn:ngsi-ld:null
        Append To List    ${dataset_ids}    ${instance.get('datasetId')}
    END
    # The default instance has no datasetId (None), which does not sort with strings: ignore_order=True cannot be used
    ${dataset_ids}=    Evaluate    sorted($dataset_ids, key=str)
    ${expected_dataset_ids}=    Evaluate    sorted($expected_dataset_ids, key=str)
    Lists Should Be Equal    ${dataset_ids}    ${expected_dataset_ids}

Check Notification Containing GeoJSON FeatureCollection
    [Arguments]    ${filename}    ${notification}
    ${expected_feature_collection}=    Load JSON From File
Loading