From 36297ca9dece59ea6832bcab82c91fbcdfa8ed48 Mon Sep 17 00:00:00 2001 From: kzangeli Date: Fri, 5 Jun 2026 11:00:38 +0200 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20020=5F19/020=5F20=20=E2=80=94=20dele?= =?UTF-8?q?ted=20scope=20is=20the=20NGSI-LD=20Null,=20not=20an=20empty=20a?= =?UTF-8?q?rray?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TS 104-175 § 4.18's Scope ABNF states that the literal string "urn:ngsi-ld:null" shall be only used and only appear in case of deleted scopes; § 5.3.2.5's temporal deletion rule likewise substitutes the NGSI-LD Null. The two expectation fixtures instead encoded the deleted scope instance as an empty array ([]), which the grammar cannot produce. - vehicle-temporal-representation-property-020-19.jsonld: "value": [] → "value": "urn:ngsi-ld:null" (normalized) - vehicle-temporal-representation-property-020-20.jsonld: [[], ts] → ["urn:ngsi-ld:null", ts] (temporalValues pair) Analysis recorded as testsuite-doubts.md #91. --- ...oral-representation-property-020-19.jsonld | 2 +- ...oral-representation-property-020-20.jsonld | 2 +- testsuite-doubts.md | 34 +++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/data/temporalEntities/expectations/vehicle-temporal-representation-property-020-19.jsonld b/data/temporalEntities/expectations/vehicle-temporal-representation-property-020-19.jsonld index 9fc087f3..c31ad083 100644 --- a/data/temporalEntities/expectations/vehicle-temporal-representation-property-020-19.jsonld +++ b/data/temporalEntities/expectations/vehicle-temporal-representation-property-020-19.jsonld @@ -4,7 +4,7 @@ "scope": [ { "type": "Property", - "value": [], + "value": "urn:ngsi-ld:null", "deletedAt": "2024-12-19T08:43:32.422444Z" } ] diff --git a/data/temporalEntities/expectations/vehicle-temporal-representation-property-020-20.jsonld b/data/temporalEntities/expectations/vehicle-temporal-representation-property-020-20.jsonld index cb89cccc..9e8d8d81 100644 --- a/data/temporalEntities/expectations/vehicle-temporal-representation-property-020-20.jsonld +++ b/data/temporalEntities/expectations/vehicle-temporal-representation-property-020-20.jsonld @@ -5,7 +5,7 @@ "type": "Property", "values": [ [ - [], + "urn:ngsi-ld:null", "2024-12-19T08:48:50.936936Z" ] ] diff --git a/testsuite-doubts.md b/testsuite-doubts.md index 50417d0d..01513f8d 100644 --- a/testsuite-doubts.md +++ b/testsuite-doubts.md @@ -2667,3 +2667,37 @@ doesn't match the URL id. `$.id` with the actual `${entity_id}` before PATCHing. Or omit the `id` from the fragment entirely (PATCH attrs doesn't need it). + + +## 91. `020_19_01` / `020_20_01` — deleted-scope expectations encode the NGSI-LD Null as `[]` + +**Hit:** with the deletedAt-tombstone setup of [[#87]] in place, both scope +tests still fail on the expectation fixtures +(`vehicle-temporal-representation-property-020-19.jsonld` / +`…-020-20.jsonld`), which represent the deleted scope instance as an empty +array: + +```json +{ "type": "Property", "value": [], "deletedAt": "…" } (020-19, normalized) +[ [], "2024-12-19T08:48:50.936936Z" ] (020-20, temporalValues pair) +``` + +**Spec:** TS 104-175 § 4.18 defines the Scope grammar in ABNF and states that +the special string `"urn:ngsi-ld:null"` (the NGSI-LD Null) "shall be **only** +used and **only** appear in case of **deleted scopes**" — i.e. a deleted scope +is represented by that string, and nothing else may represent it: + +```abnf +Scope = [%x2F] ScopeLevel *(%x2F ScopeLevel) +Scope =/ "urn:ngsi-ld:null" ; the literal string "urn:ngsi-ld:null" +``` + +An empty array is not derivable from the grammar at all (and § 5.3.2.5's +deletion rule for temporal instances likewise substitutes the NGSI-LD Null, +never an empty container). + +**Fix:** in both expectation fixtures, replace the empty-array scope value +with the string `"urn:ngsi-ld:null"`: + +- 020-19 (normalized): `"value": "urn:ngsi-ld:null"` +- 020-20 (temporalValues): `[ "urn:ngsi-ld:null", "…" ]` -- GitLab From b0316b5efe955362c4edd5b42112f3e351de9bd3 Mon Sep 17 00:00:00 2001 From: kzangeli Date: Fri, 5 Jun 2026 13:56:45 +0200 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20020=5F17-020=5F20=20teardown=20?= =?UTF-8?q?=E2=80=94=20delete=20the=20current-state=20twin=20as=20well?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The #9 setup fix pairs each temporal test's POST /temporal/entities with a current-state Create Entity, but the teardown removed only the temporal representation. The surviving current-state Vehicles (eight across the four suites) pollute every later unpinned type=Vehicle query: all nine D011_* tests plus D001_01_inc/D001_02_inc/ D001_03_03_inc assert an exact URI set against their mock's single entity and fail with 'Lengths are different: 1 != 9' in full-suite runs (they pass in isolation). Each leaked entity id in output.xml traces back to 020_17_01..03 / 020_18_01..03 / 020_19_01 / 020_20_01. Teardown now calls Delete Entity before Delete Temporal Representation Of Entity — that order also purges the deletion's own tombstone rows from the temporal store. Analysis recorded as testsuite-doubts.md #93. --- .../020_17.robot | 4 ++++ .../020_18.robot | 4 ++++ .../020_19.robot | 4 ++++ .../020_20.robot | 4 ++++ testsuite-doubts.md | 23 +++++++++++++++++++ 5 files changed, 39 insertions(+) diff --git a/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_17.robot b/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_17.robot index 0ba30bad..d8d877ed 100644 --- a/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_17.robot +++ b/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_17.robot @@ -63,4 +63,8 @@ Create Temporal Entity Set Suite Variable ${temporal_entity_representation_id} Delete Initial Temporal Entity + # The setup mirrors the temporal entity on the current-state side (see + # testsuite-doubts.md #9) — remove that twin too, or it pollutes every + # later type=Vehicle query (exact-set assertions in the dist-ops tests). + Delete Entity ${temporal_entity_representation_id} Delete Temporal Representation Of Entity ${temporal_entity_representation_id} diff --git a/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_18.robot b/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_18.robot index c0d03906..1a9849a8 100644 --- a/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_18.robot +++ b/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_18.robot @@ -66,4 +66,8 @@ Create Temporal Entity Set Suite Variable ${temporal_entity_representation_id} Delete Initial Temporal Entity + # The setup mirrors the temporal entity on the current-state side (see + # testsuite-doubts.md #9) — remove that twin too, or it pollutes every + # later type=Vehicle query (exact-set assertions in the dist-ops tests). + Delete Entity ${temporal_entity_representation_id} Delete Temporal Representation Of Entity ${temporal_entity_representation_id} diff --git a/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_19.robot b/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_19.robot index a699ee49..edec7151 100644 --- a/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_19.robot +++ b/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_19.robot @@ -57,4 +57,8 @@ Create Temporal Entity Set Suite Variable ${temporal_entity_representation_id} Delete Initial Temporal Entity + # The setup mirrors the temporal entity on the current-state side (see + # testsuite-doubts.md #9) — remove that twin too, or it pollutes every + # later type=Vehicle query (exact-set assertions in the dist-ops tests). + Delete Entity ${temporal_entity_representation_id} Delete Temporal Representation Of Entity ${temporal_entity_representation_id} diff --git a/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_20.robot b/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_20.robot index 28df0620..856408f5 100644 --- a/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_20.robot +++ b/TP/NGSI-LD/ContextInformation/Consumption/TemporalEntity/RetrieveTemporalEvolutionOfEntity/020_20.robot @@ -58,4 +58,8 @@ Create Temporal Entity Set Suite Variable ${temporal_entity_representation_id} Delete Initial Temporal Entity + # The setup mirrors the temporal entity on the current-state side (see + # testsuite-doubts.md #9) — remove that twin too, or it pollutes every + # later type=Vehicle query (exact-set assertions in the dist-ops tests). + Delete Entity ${temporal_entity_representation_id} Delete Temporal Representation Of Entity ${temporal_entity_representation_id} diff --git a/testsuite-doubts.md b/testsuite-doubts.md index 01513f8d..1d10774e 100644 --- a/testsuite-doubts.md +++ b/testsuite-doubts.md @@ -2701,3 +2701,26 @@ with the string `"urn:ngsi-ld:null"`: - 020-19 (normalized): `"value": "urn:ngsi-ld:null"` - 020-20 (temporalValues): `[ "urn:ngsi-ld:null", "…" ]` +## 93. `020_17`–`020_20` teardown leaks the current-state twin — 12 dist-ops tests fail by contamination + +**Hit (full-suite runs only):** all nine `D011_*` query tests plus +`D001_01_inc` / `D001_02_inc` / `D001_03_03_inc` fail with +`Lengths are different: 1 != 9` (or downstream variants: +`KeyError: 'brandName'`, `No value found for path $.speed`). In isolation +they all pass. + +**Analysis:** the [[#9]] setup fix paired each `020_17`–`020_20` temporal +test's `POST /temporal/entities` with a current-state `Create Entity` (so +the `DELETE /entities/{id}/attrs/{name}` under test has a target). But +`Delete Initial Temporal Entity` tears down only the temporal +representation — the current-state twin survives. Eight Vehicles (one per +test case across the four suites) accumulate in the broker and surface in +every later unpinned `type=Vehicle` query; the dist-ops tests assert an +exact URI set against the mock's single entity, so they see 9 where they +expect 1. Verified by tracing each leaked entity id in the robot +`output.xml` back to its creating test: 020_17_01..03, 020_18_01..03, +020_19_01, 020_20_01. + +**Fix:** teardown deletes the current-state entity too — `Delete Entity` +before `Delete Temporal Representation Of Entity` (that order also purges +the deletion's own tombstone rows from the temporal store). -- GitLab From 54cc34dd75e1bbc9e632b4cb34562fe4935907e2 Mon Sep 17 00:00:00 2001 From: kzangeli Date: Fri, 5 Jun 2026 14:12:09 +0200 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20008=5F01=20=E2=80=94=20a=20second=20?= =?UTF-8?q?temporal=20POST=20appends,=20it=20does=20not=20overwrite?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The expectation reused the update payload verbatim, assuming the second POST /temporal/entities replaced instances sharing an observedAt and deduplicated identical ones — current-state update semantics applied to the Temporal Evolution. Per TS 104-175 § 5.6.11.4 the provided Attribute instances 'shall be added to the existing Temporal Representation': instance identity is the system-generated instanceId, never observedAt, and the evolution is append-only. The expectation now carries the full union: speed 120@12:03 + 121@12:03 + 80@12:05 x2 + 100@12:07, fuelLevel 67 x2 + 53 x2 + 40 + 40@datasetId. Analysis recorded as testsuite-doubts.md #94. --- ...icle-temporal-representation-update.jsonld | 22 ++++++++++++++++++- testsuite-doubts.md | 20 +++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/data/temporalEntities/expectations/vehicle-temporal-representation-update.jsonld b/data/temporalEntities/expectations/vehicle-temporal-representation-update.jsonld index 33fb63cd..c6f8de92 100644 --- a/data/temporalEntities/expectations/vehicle-temporal-representation-update.jsonld +++ b/data/temporalEntities/expectations/vehicle-temporal-representation-update.jsonld @@ -2,6 +2,11 @@ "id":"urn:ngsi-ld:Vehicle:randomUUID", "type":"Vehicle", "speed":[ + { + "type":"Property", + "value":120, + "observedAt":"2020-09-01T12:03:00Z" + }, { "type":"Property", "value":121, @@ -12,6 +17,11 @@ "value":80, "observedAt":"2020-09-01T12:05:00Z" }, + { + "type":"Property", + "value":80, + "observedAt":"2020-09-01T12:05:00Z" + }, { "type":"Property", "value":100, @@ -24,6 +34,16 @@ "value":67, "observedAt":"2020-09-01T12:03:00Z" }, + { + "type":"Property", + "value":67, + "observedAt":"2020-09-01T12:03:00Z" + }, + { + "type":"Property", + "value":53, + "observedAt":"2020-09-01T13:05:00Z" + }, { "type":"Property", "value":53, @@ -44,4 +64,4 @@ "@context":[ "https://forge.etsi.org/rep/cim/ngsi-ld-test-suite/-/raw/develop/resources/jsonld-contexts/ngsi-ld-test-suite-compound.jsonld" ] - } \ No newline at end of file + } diff --git a/testsuite-doubts.md b/testsuite-doubts.md index 1d10774e..6078c9d2 100644 --- a/testsuite-doubts.md +++ b/testsuite-doubts.md @@ -2724,3 +2724,23 @@ expect 1. Verified by tracing each leaked entity id in the robot **Fix:** teardown deletes the current-state entity too — `Delete Entity` before `Delete Temporal Representation Of Entity` (that order also purges the deletion's own tombstone rows from the temporal store). +## 94. `008_01_01` — expectation assumes a second temporal POST overwrites same-observedAt instances + +**Hit:** `Item root['speed'][1] added to iterable` (and friends) — the broker +returns more Attribute instances than the expectation contains. + +**Analysis:** the test POSTs `/temporal/entities` twice for the same entity: +the create payload (`speed` 120@12:03, 80@12:05) and an "update" payload +(`speed` 121@12:03, 80@12:05, 100@12:07). The expectation file is the update +payload itself — i.e. it assumes the second POST *replaced* the instances +sharing an `observedAt` (120@12:03 → 121@12:03) and deduplicated the +identical ones (80@12:05). That is current-state update semantics applied to +the Temporal Evolution. Per TS 104-175 § 5.6.11.4, when the entity already +exists, the provided Attribute instances "shall be **added** to the existing +Temporal Representation" — instance identity is the system-generated +`instanceId`, never `observedAt`, and the evolution is append-only. A +conforming broker therefore returns the union: 5 `speed` instances +(120@12:03, 121@12:03, 80@12:05 ×2, 100@12:07) and 6 `fuelLevel` instances. + +**Fix:** the expectation now carries the full union (including the duplicate +same-value/same-observedAt instances, which exist as distinct `instanceId`s). -- GitLab