Commit 53aee391 authored by kzangeli's avatar kzangeli
Browse files

fix: temporal pagination tests follow TS 104-176 clause 6.4.7.3

The 020_13 / 020_14 / 021_15 / 021_16 families tested the old
GS CIM 009 v1.x clause 6.3.10 binding: 206 Partial Content +
Content-Range, with a broker-wide total instance cap cut at attribute
boundaries. TS 104-176 clause 6.4.7.3 replaces that mechanism
entirely:

- status is always 200; page pointers are Link header link-values
  with rel="intervalafter" (the page holding LATER Attribute
  timestamps) and rel="intervalbefore" (EARLIER) — note the
  relations are time-oriented, so they swap sides between ascending
  (firstN) and descending (lastN) pagination
- the page limit applies per Attribute: firstN (ascending), lastN
  (descending), offsetN to select the page
- there is no total cap and no attribute-boundary cut: unsynchronized
  attributes paginate independently (020_14 now asserts exactly that)

New keywords: Check Temporal Pagination Link / ... Link Absent
(AssertionUtils); firstN/offsetN plumbed through the temporal
consumption keywords. 021_16 drives pagination through temporalQ.lastN
in the POST query body (new fixture entity-operations-paginated-query).

Also covered: firstN+lastN together is contradictory → 400.

021_03 and 020_05 needed no changes — they already expected 200 and
fail only against brokers still implementing the v1.x binding.
parent 59eca008
Loading
Loading
Loading
Loading
+82 −126
Original line number Diff line number Diff line
*** Settings ***
Documentation       Check temporal pagination is applied when querying the temporal evolution of entities
Documentation       Check that temporal pagination (TS 104-176, clause 6.4.7.3) is applied when querying the temporal evolution of entities

Resource            ${EXECDIR}/resources/ApiUtils/Common.resource
Resource            ${EXECDIR}/resources/ApiUtils/TemporalContextInformationConsumption.resource
@@ -9,7 +9,7 @@ Resource ${EXECDIR}/resources/JsonUtils.resource

Suite Setup         Setup Initial Entities
Suite Teardown      Delete Initial Entities
Test Template       Retrieve Temporal Entities
Test Template       Query Temporal Entities With Pagination


*** Variables ***
@@ -17,49 +17,67 @@ ${first_vehicle_payload_file}= pagination/2020-01-vehicule-temporal-represe
${second_vehicle_payload_file}=     2020-09-vehicle-temporal-representation.jsonld
${timeBefore}=                      2019-01-01T01:01:00Z
${timeAfter}=                       2021-01-01T01:01:00Z
${lrt}=                             least recent timestamp
${mrt}=                             most recent timestamp


*** Test Cases ***
021_15_01 Retrieve The Entity With lastN And Timerel Before
    [Tags]    te-retrieve    5_7_4    6_3_10    since_v1.5.1
    lastN=${20}    expectedSize=20    timerel=before    timeAt=${timeAfter}    expectedRangeStart=${timeAfter}    expectedRangeEnd=${lrt}
021_15_02 Retrieve The Entity With lastN And Timerel Between
    [Tags]    te-retrieve    5_7_4    6_3_10    since_v1.5.1
    lastN=${20}    timerel=between    timeAt=${timeBefore}    endTimeAt=${timeAfter}    expectedRangeStart=${timeAfter}    expectedRangeEnd=${lrt}
021_15_03 Retrieve The Entity With lastN And Timerel After
    [Tags]    te-retrieve    5_7_4    6_3_10    since_v1.5.1
    lastN=${20}    expectedSize=20    timerel=after    timeAt=${timeBefore}    expectedRangeStart=${mrt}    expectedRangeEnd=${lrt}
021_15_04 Retrieve The Entity With Timerel Before
    [Tags]    te-retrieve    5_7_4    6_3_10    since_v1.5.1
    timerel=before    expectedSize=*    timeAt=${timeAfter}    expectedRangeEnd=${mrt}
021_15_05 Retrieve The Entity With Timerel Between
    [Tags]    te-retrieve    5_7_4    6_3_10    since_v1.5.1
    timerel=between    timeAt=${timeBefore}    endTimeAt=${timeAfter}    expectedRangeStart=${timeBefore}    expectedRangeEnd=${mrt}
021_15_06 Retrieve The Entity With Timerel After
    [Tags]    te-retrieve    5_7_4    6_3_10    since_v1.5.1
    timerel=after    timeAt=${timeBefore}    expectedRangeStart=${timeBefore}    expectedRangeEnd=${mrt}
021_15_07 Retrieve The Entity With temporalValues And Timerel After
    [Tags]    te-retrieve    5_7_4    6_3_10    since_v1.5.1
    representation=temporalValues    timerel=after    timeAt=${timeBefore}    expectedRangeStart=${timeBefore}    expectedRangeEnd=${mrt}
021_15_08 Retrieve The Entity With temporalValues, lastN And Timerel Between
    [Tags]    te-retrieve    5_7_4    6_3_10    since_v1.5.1
    representation=temporalValues    lastN=${20}    timerel=between    timeAt=${timeBefore}    endTimeAt=${timeAfter}    expectedRangeStart=${timeAfter}    expectedRangeEnd=${lrt}
021_15_01 Query With lastN Smaller Than The Available Instances
    [Documentation]    lastN paginates in descending order; the deeper page holds EARLIER timestamps → rel="intervalbefore"
    [Tags]    te-query    5_7_4    6_4_7_3    since_v1.9.1
    lastN=${5}    timerel=between    timeAt=${timeBefore}    endTimeAt=${timeAfter}
    ...    maxInstances=5    expectBeforeOffset=5

021_15_02 Query The Second Page With lastN And offsetN
    [Documentation]    A middle page carries both pointers
    [Tags]    te-query    5_7_4    6_4_7_3    since_v1.9.1
    lastN=${5}    offsetN=${5}    timerel=between    timeAt=${timeBefore}    endTimeAt=${timeAfter}
    ...    maxInstances=5    expectBeforeOffset=10    expectAfterOffset=0

021_15_03 Query With firstN
    [Documentation]    firstN paginates in ascending order; the deeper page holds LATER timestamps → rel="intervalafter"
    [Tags]    te-query    5_7_4    6_4_7_3    since_v1.9.1
    firstN=${5}    timerel=after    timeAt=${timeBefore}
    ...    maxInstances=5    expectAfterOffset=5

021_15_04 Query The Last Page With firstN And offsetN
    [Documentation]    Past the largest attribute's instance count only the backward pointer remains
    [Tags]    te-query    5_7_4    6_4_7_3    since_v1.9.1
    firstN=${5}    offsetN=${18}    timerel=after    timeAt=${timeBefore}
    ...    maxInstances=2    expectBeforeOffset=13

021_15_05 Query With lastN Covering All Instances
    [Documentation]    Nothing remains beyond the page — no pagination pointers
    [Tags]    te-query    5_7_4    6_4_7_3    since_v1.9.1
    lastN=${20}    timerel=after    timeAt=${timeBefore}
    ...    maxInstances=20

021_15_06 Query With temporalValues And lastN
    [Documentation]    Pagination pointers are representation-independent
    [Tags]    te-query    5_7_4    6_4_7_3    since_v1.9.1
    representation=temporalValues    lastN=${5}    timerel=after    timeAt=${timeBefore}
    ...    expectBeforeOffset=5

021_15_07 Query With Both firstN And lastN
    [Documentation]    Ascending and descending pagination at once is contradictory
    [Tags]    te-query    5_7_4    6_4_7_3    since_v1.9.1
    firstN=${5}    lastN=${5}    timerel=after    timeAt=${timeBefore}
    ...    expectedStatus=400


*** Keywords ***
Retrieve Temporal Entities
    [Documentation]    Check temporal pagination behavior on multiple entity endpoint
Query Temporal Entities With Pagination
    [Documentation]    Query the temporal evolution of entities and check the § 6.4.7.3 pagination behaviour
    [Arguments]
    ...    ${representation}=${EMPTY}
    ...    ${timerel}=${EMPTY}
    ...    ${timeAt}=${EMPTY}
    ...    ${endTimeAt}=${EMPTY}
    ...    ${lastN}=${EMPTY}
    ...    ${expectedRangeStart}=${EMPTY}
    ...    ${expectedRangeEnd}=${EMPTY}
    ...    ${expectedSize}=${EMPTY}
    ...    ${firstN}=${EMPTY}
    ...    ${offsetN}=${EMPTY}
    ...    ${maxInstances}=${EMPTY}
    ...    ${expectAfterOffset}=${EMPTY}
    ...    ${expectBeforeOffset}=${EMPTY}
    ...    ${expectedStatus}=200
    ${entity_types_to_be_retrieved}=    Catenate    SEPARATOR=,    Vehicle

    ${response}=    Query Temporal Representation Of Entities
@@ -70,50 +88,41 @@ Retrieve Temporal Entities
    ...    timeAt=${timeAt}
    ...    endTimeAt=${endTimeAt}
    ...    lastN=${lastN}
    Check Response Status Code    206    ${response.status_code}

    ${contentRange}=    Get Regexp Matches
    ...    ${response.headers}[Content-Range]
    ...    ([a-zA-Z\-]+) (.*-.*-.*)-(.*-.*-.*)\/(.*)
    ...    1
    ...    2
    ...    3
    ...    4
    ${unit}=    Set Variable    ${contentRange}[0][0]
    ${rangeStart}=    Convert Date    ${contentRange}[0][1]
    ${rangeEnd}=    Convert Date    ${contentRange}[0][2]
    ${size}=    Set Variable    ${contentRange}[0][3]

    Check Content Range Part Equal    ${unit}    date-time

    IF    $expectedRangeStart != ''
        IF    $expectedRangeStart == $lrt
            ${expectedRangeStart}=    Get Least Recent Timestamp From Vehicles    ${response.json()}
        ELSE IF    $expectedRangeStart == $mrt
            ${expectedRangeStart}=    Get Most Recent Timestamp From Vehicles    ${response.json()}
        ELSE
            ${expectedRangeStart}=    Convert Date    ${expectedRangeStart}
        END
        Check Content Range Part Equal    ${expectedRangeStart}    ${rangeStart}
    ...    firstN=${firstN}
    ...    offsetN=${offsetN}

    Check Response Status Code    ${expectedStatus}    ${response.status_code}
    IF    '${expectedStatus}' != '200'    RETURN

    IF    '${maxInstances}' != '' and '${representation}' == ''
        Check Max Instances Per Attribute    ${response.json()}    ${maxInstances}
    END

    IF    $expectedRangeEnd != ''
        IF    $expectedRangeEnd == $lrt
            ${expectedRangeEnd}=    Get Least Recent Timestamp From Vehicles
            ...    ${response.json()}
            ...    ${representation}
        ELSE IF    $expectedRangeEnd == $mrt
            ${expectedRangeEnd}=    Get Most Recent Timestamp From Vehicles
            ...    ${response.json()}
            ...    ${representation}
    IF    '${expectAfterOffset}' != ''
        Check Temporal Pagination Link    ${response.headers}    intervalafter    ${expectAfterOffset}
    ELSE
            ${expectedRangeEnd}=    Convert Date    ${expectedRangeEnd}
        Check Temporal Pagination Link Absent    ${response.headers}    intervalafter
    END
        Check Content Range Part Equal    ${expectedRangeEnd}    ${rangeEnd}

    IF    '${expectBeforeOffset}' != ''
        Check Temporal Pagination Link    ${response.headers}    intervalbefore    ${expectBeforeOffset}
    ELSE
        Check Temporal Pagination Link Absent    ${response.headers}    intervalbefore
    END

    IF    $expectedSize != ''
        Check Content Range Part Equal    ${expectedSize}    ${size}
Check Max Instances Per Attribute
    [Documentation]    Every Attribute of every returned Entity carries at most the page-limit number of instances
    [Arguments]    ${body}    ${maxInstances}
    FOR    ${entity}    IN    @{body}
        FOR    ${key}    ${value}    IN    &{entity}
            IF    $key in ('id', 'type', '@context')    CONTINUE
            ${isList}=    Evaluate    isinstance($value, list)
            IF    ${isList}
                ${length}=    Get Length    ${value}
                Should Be True    ${length} <= ${maxInstances}
                ...    attribute ${key} has ${length} instances, page limit is ${maxInstances}
            END
        END
    END

Setup Initial Entities
@@ -135,56 +144,3 @@ Setup Initial Entities
Delete Initial Entities
    Delete Temporal Representation Of Entity    ${first_temporal_entity_representation_id}
    Delete Temporal Representation Of Entity    ${second_temporal_entity_representation_id}

Get Least Recent Timestamp From Vehicles
    [Arguments]    ${body}    ${representation}=${EMPTY}

    ${attributeList}=    Get Attribute List From Vehicle Body    ${body}    ${representation}

    ${leastRecentTimestamp}=    Convert Date    ${timeAfter}
    FOR    ${attribute}    IN    @{attributeList}
        IF    $representation == 'temporalValues'
            ${attributeTime}=    Convert Date    ${attribute}[1]
        ELSE
            ${attributeTime}=    Convert Date    ${attribute}[observedAt]
        END

        IF    $leastRecentTimestamp >= $attributeTime
            ${leastRecentTimestamp}=    Set Variable    ${attributeTime}
        END
    END
    RETURN    ${leastRecentTimestamp}

Get Most Recent Timestamp From Vehicles
    [Arguments]    ${body}    ${representation}=${EMPTY}
    ${attributeList}=    Get Attribute List From Vehicle Body    ${body}    ${representation}

    ${mostRecentTimestamp}=    Convert Date    ${timeBefore}
    FOR    ${attribute}    IN    @{attributeList}
        IF    $representation == 'temporalValues'
            ${attributeTime}=    Convert Date    ${attribute}[1]
        ELSE
            ${attributeTime}=    Convert Date    ${attribute}[observedAt]
        END
        IF    $mostRecentTimestamp <= $attributeTime
            ${mostRecentTimestamp}=    Set Variable    ${attributeTime}
        END
    END
    RETURN    ${mostRecentTimestamp}

Get Attribute List From Vehicle Body
    [Arguments]    ${body}    ${representation}=${EMPTY}
    IF    $representation == 'temporalValues'
        ${attributeList}=    Combine Lists
        ...    ${body}[0][speed][values]
        ...    ${body}[0][fuelLevel][values]
        ...    ${body}[1][speed][values]
        ...    ${body}[1][fuelLevel][values]
    ELSE
        ${attributeList}=    Combine Lists
        ...    ${body}[0][speed]
        ...    ${body}[0][fuelLevel]
        ...    ${body}[1][speed]
        ...    ${body}[1][fuelLevel]
    END
    RETURN    ${attributeList}
+8 −15
Original line number Diff line number Diff line
*** Settings ***
Documentation       Check temporal pagination is applied when querying the temporal evolution of entities via POST
Documentation       Check that temporal pagination (TS 104-176, clause 6.4.7.3) is applied when querying the temporal evolution of entities via POST

Resource            ${EXECDIR}/resources/ApiUtils/Common.resource
Resource            ${EXECDIR}/resources/ApiUtils/TemporalContextInformationConsumption.resource
@@ -19,31 +19,24 @@ ${second_vehicle_payload_file}= 2020-09-vehicle-temporal-representation.json

*** Test Cases ***    PAYLOAD_FILE
021_16_01 Retrieve The Entities Via Post
    [Tags]    te-retrieve    5_7_3    6_3_10    since_v1.5.1
    entity-operations-before-query.jsonld
    [Tags]    te-retrieve    5_7_3    6_4_7_3    since_v1.9.1
    entity-operations-paginated-query.jsonld


*** Keywords ***
Retrieve Temporal Entities Via Post
    [Documentation]    Check that temporal pagination is triggered on the post temporal query
    [Documentation]    Check that temporal pagination (TS 104-176, clause 6.4.7.3) is triggered on the post temporal query
    [Arguments]    ${payload_file}

    ${response}=    Query Temporal Representation Of Entities Via Post
    ...    query_file_name=${payload_file}
    ...    context=${ngsild_test_suite_context}

    Check Response Status Code    206    ${response.status_code}
    Check Response Status Code    200    ${response.status_code}

    ${contentRange}=    Get Regexp Matches
    ...    ${response.headers}[Content-Range]
    ...    ([a-zA-Z\-]+) (.*-.*-.*)-(.*-.*-.*)\/(.*)
    ...    1
    ...    2
    ...    3
    ...    4
    ${unit}=    Set Variable    ${contentRange}[0][0]

    Check Content Range Part Equal    ${unit}    date-time
    # temporalQ.lastN=5 against a 20-instance fixture: instances remain
    # beyond the page in descending order → rel="intervalbefore" pointer.
    Check Temporal Pagination Link    ${response.headers}    intervalbefore    5

Setup Initial Entities
    ${first_temporal_entity_representation_id}=    Generate Random Vehicle Entity Id
+85 −123

File changed.

Preview size limit exceeded, changes collapsed.

+18 −10
Original line number Diff line number Diff line
*** Settings ***
Documentation       Check that the time range cut before the second attribute to avoid missing data in content-range
Documentation       Check that unsynchronized attributes paginate independently (TS 104-176, clause 6.4.7.3: the page limit applies per Attribute)

Resource            ${EXECDIR}/resources/ApiUtils/Common.resource
Resource            ${EXECDIR}/resources/ApiUtils/TemporalContextInformationConsumption.resource
@@ -19,29 +19,37 @@ ${timeAfter}= 2021-01-01T01:01:00Z


*** Test Cases ***
020_14_01 Retrieve An Entity With 60 Instances Of Unsynchronized Attributes
    [Tags]    te-retrieve    5_7_3    6_3_10    since_v1.5.1
    timerel=after    timeAt=${timeBefore}    emptyAttr=fuelLevel
020_14_02 Retrieve The Entity With lastN
    [Tags]    te-retrieve    5_7_3    6_3_10    since_v1.5.1
    lastN=${100}    timerel=before    timeAt=${timeAfter}    emptyAttr=speed
020_14_01 Retrieve An Entity With Unsynchronized Attributes And firstN
    [Documentation]    Both attributes return their own first page even though their time ranges do not overlap
    [Tags]    te-retrieve    5_7_3    6_4_7_3    since_v1.9.1
    firstN=${30}    timerel=after    timeAt=${timeBefore}    expectedInstances=30
020_14_02 Retrieve An Entity With Unsynchronized Attributes And lastN
    [Documentation]    Both attributes return their own last page even though their time ranges do not overlap
    [Tags]    te-retrieve    5_7_3    6_4_7_3    since_v1.9.1
    lastN=${30}    timerel=before    timeAt=${timeAfter}    expectedInstances=30


*** Keywords ***
Retrieve Temporal Entity
    [Documentation]    Check that the time range cut before the second attribute
    [Documentation]    Check that the per-attribute page limit applies to each unsynchronized attribute independently
    [Arguments]
    ...    ${timerel}
    ...    ${timeAt}
    ...    ${emptyAttr}
    ...    ${expectedInstances}
    ...    ${lastN}=${EMPTY}
    ...    ${firstN}=${EMPTY}
    ${response}=    Retrieve Temporal Representation Of Entity
    ...    temporal_entity_representation_id=${temporal_entity_representation_id}
    ...    context=${ngsild_test_suite_context}
    ...    timerel=${timerel}
    ...    timeAt=${timeAt}
    ...    lastN=${lastN}
    Check Data Is Empty    ${response.json()}[${emptyAttr}]
    ...    firstN=${firstN}
    Check Response Status Code    200    ${response.status_code}
    ${speedCount}=    Get Length    ${response.json()}[speed]
    ${fuelCount}=    Get Length    ${response.json()}[fuelLevel]
    Should Be Equal As Integers    ${speedCount}    ${expectedInstances}
    Should Be Equal As Integers    ${fuelCount}    ${expectedInstances}

Create Temporal Entity
    ${temporal_entity_representation_id}=    Generate Random Vehicle Entity Id
+11 −0
Original line number Diff line number Diff line
{
    "type": "Query",
    "entities": [{
        "type": "Vehicle"
    }],
    "temporalQ": {
       "timerel":"before",
       "timeAt":"2020-08-02T12:05:00Z",
       "lastN": 5
    }
}
Loading