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 0ba30bad518de009c726022295d40fb95f158498..d8d877edc01e462c5947a7e0ad0f965676fef9de 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 c0d03906f7768112107496c943a7c120db020512..1a9849a824c9b8fc82de973ca707bdf59116fdb1 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 a699ee496703eabfad0b72a4200a3f0acfda25e8..edec715129779b611e46cbbcfd8badbd359fed7e 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 28df0620dde31a7fb46e2b7c1063775f2a8d7513..856408f5535f6e4cc0883ebe8fe849681b3050d4 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/data/temporalEntities/expectations/vehicle-temporal-representation-property-020-19.jsonld b/data/temporalEntities/expectations/vehicle-temporal-representation-property-020-19.jsonld index 9fc087f374d78c877438c2284db77e5c3c4e5612..c31ad083a0e3c7503091cbeb846471b316657014 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 cb89cccc0dff58899402711b9aa4e3b296ec9c73..9e8d8d8134fe4b7c9bc6416afc0e641301d822c0 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/data/temporalEntities/expectations/vehicle-temporal-representation-update.jsonld b/data/temporalEntities/expectations/vehicle-temporal-representation-update.jsonld index 33fb63cd0ec4099b3aeb49fb3740eefed9581557..c6f8de92be203fa864ccc3e4dd7e7c6aa09f61d0 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 50417d0d9ed842c484c57b911fbd007b17b2d9cc..6078c9d2e96a6471b234324ed06008b41f88fd44 100644 --- a/testsuite-doubts.md +++ b/testsuite-doubts.md @@ -2667,3 +2667,80 @@ 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", "…" ]` +## 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). +## 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).