coraine functest coverage of the spec (TS 104-175)

What this file is — read this before the numbers. This is a test-coverage audit, not an implementation audit. Every spec statement in TS 104-175 was checked against the functional test suite and asked one question: does a test assert this? A [ ] means no test asserts it, not that the broker fails it — the vast majority of the entries below are behaviour that works and that the suite simply does not pin down. Each line names the gap in those terms ("no test sends…", "no batch-merge test asserts…"), which is what makes it actionable.

It is a working document: a to-write list for the test suite, kept in the open because untested behaviour is a real risk even when the behaviour is correct.

Generated from the spec-feature audit workflow (70 spec units) + make coverage baseline. COMPLETE.

Line-coverage baseline (2026-08-20, e8e6bb6)

  • make coverage DB=mongoc, 613/613 pass: Lines 80.7% (13374/16570) · Functions 93.7% (563/601) · Branches 60.8% (7806/12843) = the real target
  • make coverage (corDB), 563/563 pass: Lines 74.4% (10922/14674) · Functions 85.7% (480/560) · Branches 55.4% (6529/11795)
  • What the uncovered lines actually are, and what a ceiling without mocks looks like: coverage.md

Matrix: 2314 spec statements — 1051 asserted by a test, 373 partially, 890 unasserted; 245 high-priority

Legend: [ ] no test asserts it, [~] partially asserted. Tick as covered.

Coverage by area (spec statements / asserted / partial / unasserted)

  • entity-attr-CRUD: 357 / 150 / 54 / 153
  • temporal: 274 / 90 / 39 / 145
  • entity-maps: 160 / 22 / 45 / 93
  • consume: 172 / 90 / 16 / 66
  • discovery: 161 / 77 / 21 / 63
  • batch: 195 / 101 / 35 / 59
  • subscription: 187 / 98 / 31 / 58
  • registration: 147 / 76 / 18 / 53
  • distops: 136 / 60 / 32 / 44
  • snapshots: 116 / 55 / 18 / 43
  • context: 71 / 36 / 13 / 22
  • ordering: 28 / 5 / 5 / 18
  • query-filter: 90 / 59 / 17 / 14
  • pagination: 44 / 30 / 4 / 10
  • multi-attr-datasetId: 40 / 28 / 2 / 10
  • query-projection: 21 / 12 / 1 / 8
  • local-scope: 20 / 9 / 3 / 8
  • common-behaviour: 28 / 15 / 6 / 7
  • json-ld: 30 / 16 / 8 / 6
  • counting: 17 / 9 / 3 / 5
  • errors: 20 / 13 / 2 / 5

HIGH-priority gaps

batch (11)

  • [ ] [10.3.3] Invalid options value rejected — No test sends an invalid options value (e.g. options=garbage) to /entityOperations/upsert. url_param_format_options_validation.test only covers GET /entities options tokens (keyValues/temporalValues), not the replace/update options of upsert.
  • [ ] [10.3.3] Entity with attribute containing invalid value-object structure rejected per-entity — No upsert/batch test feeds a structurally-invalid attribute (Property without value, Relationship without object, malformed GeoProperty coords) to assert a per-entity BatchEntityError BadRequestData in a mixed batch.
  • [ ] [10.3.4] Distributed: CSR lacks batch update but supports Update Attributes -> per-entity forward — No test registers a CSR that supports Update Attributes (10.2.3) but NOT updateBatch and verifies the broker falls back to per-entity Update Attributes forwards.
  • [ ] [10.3.4] Distributed: noOverwrite + CSR supports Append Attributes -> per-entity append (overwrite disabled) — No test exercises the noOverwrite fallback to per-entity Append Attributes (10.2.4) when the CSR lacks updateBatch.
  • [ ] [10.3.4] Distributed: forwarded op error/timeout/unsupported surfaces in E (per clause 6.3.5) — The conflict test's header describes a 'Part B' (CSR declares updateBatch but endpoint unreachable -> Bad Gateway per id), but the RUN block stops at step 06 and never executes it; forward transport error/timeout into errors[] is unverified for batch update.
  • [ ] [10.3.5] Attribute name matching uses term expansion (short name vs expanded IRI) — No batch-merge test sends a short-name fragment attr (via Link/inline @context) and asserts it merges into the same expanded-IRI target attr (not a duplicate).
  • [ ] [10.3.5] Per-entity error: missing or invalid Entity id (URI) → BadRequestData (400) in E — No batch-merge test sends a member with a missing id or a non-URI id and asserts a BadRequestData BatchEntityError (step 07 'missing id' is actually a valid-but-nonexistent id → 404).
  • [ ] [10.3.5] Distributed: matching redirect CSR → forwarded; non-redirect CSR attrs removed — No batch-merge test exercises redirect-mode CSR fan-out (entity_batch_redirect_fanout covers upsert/update only, not merge).
  • [ ] [10.3.5] Distributed fallback: CSR supports single Merge Entity (not batch) → per-entity forward — No batch-merge test registers a CSR that declares single mergeEntity (not mergeBatch) and asserts per-entity individual Merge forwarding; conflict test only covers the neither-supported case.
  • [ ] [10.3.6] Distributed delete forwarded per-entity via Delete Entity when batch unsupported — No test registers a CSR with deleteEntity (but not deleteBatch) and verifies per-entity Delete Entity forwarding with S/E merge
  • [ ] [10.3.6] Redirect CSR not supporting any delete op yields Conflict errors — No redirect-mode CSR-without-delete-op test; the redirect-variant Conflict path is untested (only exclusive is in entity_batch_delete_distops_conflict.test)

common-behaviour (6)

  • [~] [8.4] Partial update at Entity level overwrites the whole attribute, dropping omitted sub-attributes — patch_entity_attrs.test exercises entity-level PATCH /attrs only on scalar Properties; no test PATCHes an attribute carrying a sub-attribute (e.g. {value:25,unitCode:CEL,observedAt:T1}) with a fragment that omits unitCode and asserts unitCode is REMOVED. The 8.4-02 vs 8.4-01 contrast (entity-level drops omitted sub-attrs while attr-level preserves them) is never directly asserted.
  • [ ] [8.4] Partial update: non-matching datasetId adds a new instance — No partial-update (PATCH /attrs) test sends a fragment with a datasetId that matches no existing instance and asserts it is ADDED as a new instance alongside the existing ones. patch_attrs_datasetid_instance_update only covers the matching-datasetId replace path.
  • [ ] [8.4] Partial update: deleting a specific datasetId instance via NGSI-LD Null — No partial-update test sends a urn:ngsi-ld:null fragment carrying a datasetId to delete only the matching-datasetId instance of a multi-instance attribute (datasetId-targeted null delete via PATCH /attrs body, per 10.2.7). DELETE ?datasetId= is covered in entity_attr_crud but that is the DELETE route, not null-in-PATCH-body.
  • [ ] [8.4] Merge patch recurses into a JSON object Property value (deep merge) — No merge-PATCH test recurses INTO a JSON/object Property value: e.g. address.value {street,city,country} merged with {street:new, country:urn:ngsi-ld:null} verifying street updated, country removed, city preserved (RFC 7396 deep merge inside a value object with nested null removal). json_literal_null_value only replaces a whole value, not a nested-key merge.
  • [ ] [8.4] Merge patch: non-matching datasetId adds a new instance — No merge-PATCH test sends a fragment with a datasetId matching no existing instance and asserts a new instance is ADDED. patch_entity_datasetid only patches the existing default and existing radar datasetId instances.
  • [ ] [8.4] Merge patch: deleting a specific datasetId instance via NGSI-LD Null — No merge-PATCH test sends a urn:ngsi-ld:null fragment carrying a datasetId to remove only the matching-datasetId instance of a multi-instance attribute while leaving the others (10.2.7 handling in merge).

consume (8)

  • [ ] [10.4.2] geometryProperty present but Accept not geo+json -> BadRequestData — No test sends geometryProperty with Accept: application/json (or ld+json) on a single-entity GET to assert HTTP 400 BadRequestData. geojson_response.test only uses geometryProperty with --out geojson (geo+json Accept).
  • [ ] [10.4.2] Type selector does not match -> ResourceNotFound — No test issues GET /entities/{id}?type= to confirm 404 ResourceNotFound when the type selector does not match the stored entity's type.
  • [ ] [10.4.2] attrs list present but entity has none of them -> ResourceNotFound — No test does GET /entities/{id}?attrs= to assert 404 ResourceNotFound. (pick=nonexistent->404 is tested in retrieve_entity_pick_omit but that is the pick member-list path, not the attrs projection path.)
  • [ ] [10.4.4] Missing/invalid Entity ID URI -> 400 BadRequestData — No GET attrs/{attr}/value test with a non-URI entity id asserting 400 BadRequestData.
  • [ ] [10.4.4] Entity not found -> 404 ResourceNotFound — GET value on an unknown entity returning 404 is not asserted (case 10 is a PUT 404, not GET); handler does return it.
  • [ ] [10.4.4] Attribute absent (default instance, no datasetId) -> 404 ResourceNotFound — No GET attrs/{absent-attr}/value test asserting 404 ResourceNotFound (case 10 covers PUT only).
  • [ ] [10.4.4] Attribute absent for specified datasetId -> 404 ResourceNotFound — Handler returns 404 'no matching datasetId' but no GET value?datasetId=... test exercises a non-matching datasetId.
  • [ ] [10.4.4] datasetId parameter selects a specific Attribute instance — datasetId filtering is implemented in getEntityAttrValue.c but no functest exercises GET value?datasetId=... selecting a specific instance.

context (9)

  • [ ] [13.2] Invalid JSON payload -> 400 InvalidRequest — No test POSTs a malformed/non-JSON body to /jsonldContexts to assert 400 InvalidRequest. The crud 'bad body' cases all send valid JSON.
  • [ ] [13.4] core param returns @context reference-URL array of two items — No test exercises GET /jsonldContexts/{id}?core=; the two-item reference-URL-array response is entirely untested.
  • [ ] [13.4] core param array element order/content (user URL + core URL) — No test asserts the returned array holds the requested user @context URL plus the core @context URL matching the requested major.minor version.
  • [ ] [13.4] details=true for unknown identifier returns ResourceNotFound — No test issues GET /jsonldContexts/{unknown-id}?details=true to confirm a 404 ResourceNotFound on the metadata path (existing 404 test is full-content path; crud step 11 is a DELETE).
  • [ ] [13.4] Both details and core present returns BadRequest — No test sends both details and core params together to confirm BadRequestData/400.
  • [ ] [13.4] core param not conforming to semantic version returns BadRequest — No test sends a malformed core value (non major.minor) to confirm BadRequestData/400.
  • [ ] [13.5] reload=true, Cached, download fails (unreachable URL) → re-download error (504 / LdContextNotAvailable) — No test does DELETE ?reload=true on a Cached entry whose original URL has become unreachable to assert the 504 Gateway Timeout / LdContextNotAvailable error (POST-of-unreachable-URL→504 in crud step 15 is a different operation).
  • [ ] [13.5] reload=true, Cached, downloaded @context invalid (8.2.3) → 504 / LdContextNotAvailable — No test re-downloads (via DELETE ?reload=true) a now-invalid @context to assert the validation failure maps to 504 / LdContextNotAvailable.
  • [ ] [13.5] On any reload error the existing @context is NOT removed (atomicity) — No reload-failure path exists in any test, so the 'entry stays intact after a failed reload' atomicity guarantee is unverified (would follow 13.5-12/13.5-13 with a subsequent GET ?details=true → 200 old content).

counting (1)

  • [ ] [7.5] Count = 0 when no entities match — No count=true query whose filters match nothing to assert 200 + empty [] + NGSILD-Results-Count: 0 (header present, value 0).

discovery (13)

  • [ ] [10.6.4] Type with multiple types per entity appears once per type — No test creates a multi-type entity (e.g. type ['Building','Residential']) and asserts GET /types?details=true emits a separate EntityType element for each type, both carrying that entity's attributes. create_entity_multi_type.test only checks entity GET, not the /types details array.
  • [ ] [10.6.4] Invalid details parameter value returns 400 BadRequestData — No test sends GET /types?details=maybe (non-boolean) and asserts 400 with ProblemDetails type BadRequestData. The only details-param validation test (jsonld_contexts_param_validation.test) targets /jsonldContexts, not /types.
  • [ ] [10.6.5] attributeTypes lists Relationship for a Relationship attribute — No /types/{type} response asserts attributeTypes containing "Relationship"; discovery_modes registers a relationship (ownedBy) but its attributeDetails entry is rendered as Property (CSR metadata loses the kind), and no real Relationship instance is exercised.
  • [ ] [10.6.5] attributeTypes lists GeoProperty for a GeoProperty attribute — No test creates a GeoProperty-bearing entity and asserts attributeTypes=["GeoProperty"] in GET /types/{type}.
  • [ ] [10.6.6] Empty attributeList when no entities exist — No test does GET /attributes against an empty system to assert 200 with attributeList: [] (empty array, well-formed AttributeList).
  • [ ] [10.6.6] Invalid JSON-LD @context -> 400 InvalidRequest / LdContextNotAvailable — No GET /attributes with a malformed/unreachable Link-header context asserting 400 InvalidRequest (or 503 LdContextNotAvailable).
  • [ ] [10.6.7] An attribute present on multiple entity types lists all those types in typeNames — No details=true test has a single attribute name on instances of two DIFFERENT entity types; in discovery_local both Vehicle entities share type so typeNames stays single-element. Add e.g. attr "speed" on a Vehicle and a Drone and assert typeNames=[Vehicle,Drone].
  • [ ] [10.6.7] Empty system yields an empty array with 200 OK — No test GETs /attributes?details=true against an empty broker to assert 200 with [] (the only empty-ish case, introspection_csr_empty_arrays, has CSR metadata so the array is non-empty).
  • [~] [10.6.7] Distributed: details aggregated across registered Context Sources — Distributed aggregation is covered for the AttributeList form (/attributes without details) in discovery_forward/local_param_distops_suppress, and CSR metadata flows into details=true in introspection_csr_empty_arrays, but no test exercises details=true with forwarding to a live CSR merging real instance typeNames across brokers.
  • [ ] [10.6.7] Distributed: same attribute from multiple sources merged into one element — No details=true test where the same attribute name is reported by both local instances and a CSR (or two CSRs) and the result is a single element with the union of typeNames.
  • [ ] [10.6.7] Invalid details parameter value → 400 Bad Request — No GET /attributes?details=foo (or non-boolean) asserting 400 BadRequestData. The only details=foo->400 test is on /jsonldContexts, not on /attributes (different code path).
  • [ ] [10.6.8] attributeTypes includes Relationship when a Relationship instance exists — No test asserts attributeTypes contains "Relationship". discovery_modes.test registers ownedBy via relationshipNames but its expected output shows attributeTypes:["Property"] (likely a broker bug never caught); a real Relationship-instance attribute should report Relationship.
  • [ ] [10.6.8] attributeTypes includes GeoProperty when a GeoProperty instance exists — No test creates an entity with a GeoProperty attribute and asserts GET /attributes/{attrId} reports attributeTypes containing "GeoProperty".

distops (8)

  • [ ] [9.5] accept triggers content-type conversion when aggregating responses — No test has a source reply in the accept-defined format and asserts the broker converts it to the format the initial requester expects in the aggregated answer.
  • [ ] [9.5] ngsildConformance triggers backwards-compatibility transform of forwarded payload — The 9.5.3 downgrade transform is only tested on the SUBSCRIPTION notification path. No test declares ngsildConformance in a CSR contextSourceInfo and asserts the FORWARDED request payload is downgraded.
  • [ ] [9.5] Broker rejects invalid NGSI-LD Entity data returned by a Context Source — No test has a Context Source return invalid NGSI-LD entity data and asserts the broker rejects/does-not-aggregate it (error surfaced rather than passed through).
  • [ ] [9.6] Query Temporal Evolution builds an Entity Map of matching identifiers — No test builds an EntityMap from a distributed GET /temporal/entities; troe_timescale_temporal_distop_query_inclusive.test does the temporal fan-out/merge but never engages entityMap=true / NGSILD-EntityMap. Add a distributed temporal query asserting a map with the matching ids is created.
  • [ ] [9.6] geoquery filter applied before adding Entity to a result page — No test binds a geoQ into an EntityMap and re-applies it at page render to drop a candidate. (geoQ exists only in entitymap_create_with_filter's header comment, not exercised.)
  • [ ] [9.6] Expired Entity Map triggers creation of a new one — No test references an expired map id and asserts a fresh broad fan-out + new map id (rather than reusing stale contents). expiresAt is only PATCHed/read, never aged out for reuse.
  • [ ] [9.6] Inaccessible / unknown Entity Map triggers creation of a new one — No test passes a non-existent/deleted entityMap= to a query and asserts the broker builds a new map and succeeds (not 404). entitymap_patch step 08 only covers PATCH of an unknown map -> 404.
  • [~] [9.6] Entity Map fixes the set of Entities for all subsequent requests based on it — count stays fixed at 2 in step 11 (snapshot count), but no test ADDS a new matching entity to a source after map creation and asserts the reused map does NOT return it (the explicit stable-snapshot assertion).

entity-attr-CRUD (49)

  • [ ] [10.2.2] first-level member value urn:ngsi-ld:null → 400 BadRequestData — No Create Entity test posts a first-level member equal to "urn:ngsi-ld:null" expecting 400; all urn:ngsi-ld:null tests exercise merge/patch DELETE semantics (merge_patch_null_sentinel.test, patch_entity*.test) where the sentinel is legal
  • [ ] [10.2.2] urn:ngsi-ld:null as Property value RHS → 400 BadRequestData — No Create Entity test sends a Property value RHS of "urn:ngsi-ld:null" expecting 400 BadRequestData (only merge/patch deletion tests use it, where it is valid)
  • [ ] [10.2.2] urn:ngsi-ld:null as Relationship object RHS → 400 BadRequestData — No Create Entity test sends a Relationship object RHS of "urn:ngsi-ld:null" expecting 400 (merge_patch_null_sentinel.test uses it only for patch-delete)
  • [ ] [10.2.3] Append new datasetId instance when datasetId not present — No Update-Attributes (PATCH /attrs) test supplies an attribute with a datasetId not matching any existing instance and verifies a new instance is appended alongside the existing ones. patch_attrs_datasetid only covers the matching-instance replace.
  • [ ] [10.2.3] Delete specific datasetId instance via NGSI-LD Null — No PATCH /attrs test deletes a single datasetId instance via urn:ngsi-ld:null (attr carrying matching datasetId + Null value) while leaving the default and other dataset instances intact.
  • [ ] [10.2.3] Exclusive/redirect reg does not support op, complete failure -> Conflict — No test where an exclusive/redirect CSR matches Update Attributes but lacks the updateAttrs operation and the whole update fails, asserting 409 Conflict.
  • [ ] [10.2.3] Exclusive/redirect reg does not support op, partial -> 207 — No test for the partial-success 207 case where an exclusive/redirect CSR doesn't support Update Attributes but some attributes succeed.
  • [ ] [10.2.4] createdAt preserved when default attribute overwritten — No append test requests sysAttrs to assert the attribute-level createdAt is unchanged after an overwrite-by-default POST /attrs; post_entity_attrs.test overwrites speed but never inspects createdAt
  • [ ] [10.2.4] Append datasetId instance when none with that datasetId exists — No POST /attrs append test supplies an attribute with a datasetId; patch_attrs_datasetid_instance_update covers PATCH (Update Attributes) only, not the Append operation
  • [ ] [10.2.4] Overwrite permitted replaces existing datasetId instance — No POST /attrs test overwrites an existing datasetId-matched instance with overwrite allowed (default)
  • [ ] [10.2.4] Multi-instance attribute: append new datasetId alongside existing default — No POST /attrs test appends a new datasetId instance and verifies it coexists with an existing default (or other-datasetId) instance of the same attribute
  • [ ] [10.2.4] Entity ID missing or not a valid URI -> 400 BadRequestData — url_parse step 09 uses a valid URL-as-id and gets 404; no POST /attrs test uses a non-URI entity id and asserts 400 BadRequestData (invalid-URI 400 is only tested for subscription/registration ids)
  • [ ] [10.2.4] Exclusive reg without Append support, complete failure -> 409 Conflict — No test exercises an exclusive registration that lacks appendAttrs support with a complete-failure append asserting 409 Conflict (the merge test uses redirect CSRs and 207, not exclusive 409)
  • [ ] [10.2.4] Redirect reg without Append support, complete failure -> 409 Conflict — No test exercises a redirect registration lacking appendAttrs support with complete failure asserting 409 Conflict
  • [ ] [10.2.4] Inclusive registrations: remaining matching data also forwarded — No POST /attrs append test exercises an inclusive registration where remaining data is both applied locally and forwarded (csource-reg-distops-loop-write-508 and patch-inclusive cover other ops)
  • [ ] [10.2.5] Update Relationship object — No test does a successful PATCH /entities/{id}/attrs/{rel} with a new 'object' on an existing Relationship (only the type-mismatch error path PATCHes object onto a Property). Add a happy-path Relationship object update via the single-attr route and verify the new object URI is queryable.
  • [ ] [10.2.5] Delete a sub-attribute via NGSI-LD Null — Sub-attribute deletion via urn:ngsi-ld:null is only tested through the Merge Entity route (merge_patch_subattr_null_sentinel.test, PATCH /entities/{id}), not via the Partial Attribute Update route (PATCH /attrs/{attr}). Add a PATCH /attrs/{attr} fragment setting an existing sub-attr to urn:ngsi-ld:null and assert it is removed.
  • [ ] [10.2.6] observedAt sub-attribute removed when not supplied (value-only + pre-existing observedAt) — No test verifies that a value-only set with no observedAt param removes a pre-existing observedAt sub-attribute (note: current impl delegates to patchEntityAttr/merge, which preserves sub-attrs, so this spec behaviour may be unimplemented — a test would expose it).
  • [ ] [10.2.6] Set on JsonProperty attribute (null allowed in JSON content) — No test sets a JsonProperty value via /value, and crucially none verifies the null-is-allowed exception for JsonProperty (impl special-cases isJsonProperty at putEntityAttrValue.c:140 — untested).
  • [ ] [10.2.6] Exclusive registration match forwards the payload for remote processing — No distributed-ops test forwards a Set Attribute Value (/value PUT) through an exclusive registration; forwarding is inherited from patchEntityAttr but unexercised on this route.
  • [ ] [10.2.6] Redirect registration match forwards the payload for remote processing — No distop test forwards PUT .../value through a redirect registration.
  • [ ] [10.2.6] Inclusive registration match also forwards the payload to matching endpoints — No distop test forwards PUT .../value through an inclusive registration.
  • [ ] [10.2.6] Invalid/absent Entity ID URI -> 400 BadRequestData — No test PUTs .../value with a malformed (non-URI) entity id expecting 400 BadRequestData on the value subresource.
  • [ ] [10.2.6] Target attribute is 'scope' -> 400 BadRequestData — impl rejects scope at putEntityAttrValue.c:96 but no test exercises PUT .../attrs/scope/value -> 400.
  • [ ] [10.2.6] Payload not valid JSON -> 400 InvalidRequest — No test sends a malformed-JSON body to PUT .../value expecting 400 InvalidRequest.
  • [ ] [10.2.6] Payload contains 'urn:ngsi-ld:null' -> 400 InvalidRequest — impl rejects the urn:ngsi-ld:null sentinel at putEntityAttrValue.c:144 (non-JsonProperty) but no test covers PUT .../value with that sentinel -> 400.
  • [ ] [10.2.6] Payload contains null (non-JsonProperty) -> 400 InvalidRequest — impl rejects a bare null body for non-JsonProperty at putEntityAttrValue.c:143 but no test covers PUT .../value --payload null -> 400.
  • [ ] [10.2.6] Unknown target Entity (no local entity, no matching registration) -> 404 ResourceNotFound — impl returns 404 for unknown entity at putEntityAttrValue.c:113 but no test PUTs .../value to a non-existent entity (entity_attr_value.test only covers non-existent attribute on an existing entity).
  • [ ] [10.2.7] Invalid Entity ID (not a valid URI) → BadRequestData (400) — No DELETE /attrs with a non-URI entity id asserting 400 BadRequestData.
  • [ ] [10.2.7] Exclusive/redirect registration match → operation forwarded to registration endpoint — The only exclusive/redirect DELETE-attr case is the loop-detection 508; no test shows a successful forward of Delete Attribute to a matched exclusive/redirect endpoint (non-temporal).
  • [ ] [10.2.8] Type selector mismatching the existing entity's type -> ResourceNotFound 404 — No test deletes /entities/{id}?type= for an entity that exists with a different type to assert 404 and that the entity is NOT removed. Spec-mandated behaviour of the type selector is unasserted.
  • [ ] [10.2.9] datasetId-matched instance deleted via NGSI-LD Null — No test sends urn:ngsi-ld:null on a fragment attribute carrying a datasetId that matches an existing multi-instance entry, asserting only that specific datasetId instance is deleted while siblings (default + other datasetIds) remain.
  • [ ] [10.2.9] datasetId not matched is appended as new instance — patch_entity_datasetid only merges into existing datasetId instances; no test PATCHes a fragment with a datasetId that does NOT exist on the target and asserts it is appended as a new multi-attribute instance alongside the existing ones.
  • [ ] [10.2.9] Missing or invalid Entity ID -> 400 BadRequestData — No PATCH /entities/{id} test uses a syntactically invalid (non-URI) entity id in the path and asserts 400 BadRequestData. patch_entity.test only covers a well-formed-but-nonexistent id (404) and the no-payload 411 case.
  • [ ] [10.2.10] Replace payload containing NGSI-LD Null -> error (Nulls not supported) — No replace test sends an NGSI-LD Null (urn:ngsi-ld:null) value in a PUT /entities/{id} body to confirm it is rejected (Replace does not support Null member-delete). Null-sentinel tests exist only for PATCH/merge paths.
  • [ ] [10.2.11] System-generated createdAt is preserved on replacement — entity_attr_timestamps_on_update only exercises PATCH (Partial Attribute Update); no test captures attr.createdAt before/after a PUT /attrs/{attrId} to assert it is preserved (and modifiedAt advanced).
  • [ ] [10.2.11] Invalid entity ID URI yields BadRequestData — No test PUTs /entities//attrs/{attrId} to assert 400 BadRequestData.
  • [ ] [10.2.11] Unknown target Entity yields ResourceNotFound — No test PUTs /attrs/{attrId} on a non-existent entity to assert 404 ResourceNotFound (entity_attr_crud only covers PATCH on a missing entity, step 13).
  • [ ] [10.2.11] Entity exists but does not contain target attribute (no datasetId) yields ResourceNotFound — No test PUTs /attrs/ on an existing entity to assert 404 ResourceNotFound (entity_attr_crud step 14 covers this only for PATCH).
  • [ ] [10.2.11] Entity exists but lacks the specified-datasetId instance yields ResourceNotFound — No test PUTs /attrs/{attrId} with a datasetId for which no instance exists to assert 404 ResourceNotFound.
  • [ ] [10.2.11] Invalid (unparseable) JSON payload yields InvalidRequest — No test sends unparseable JSON to PUT /attrs/{attrId} to assert 400 InvalidRequest (distinct from BadRequestData).
  • [ ] [10.2.11] Exclusive registration not supporting Replace Attribute yields Conflict — No test sets up an exclusive CSR whose operations exclude replaceAttrs and PUTs /attrs/{attrId} to assert 409 Conflict.
  • [ ] [10.2.11] Distributed operation error returns 207 Multi-Status with UpdateResult — No test makes a Replace Attribute PUT match a registration that returns an error and asserts a 207 Multi-Status UpdateResult body.
  • [ ] [10.2.12] Purge by id pattern (idPattern regex) — idPattern is implemented (purgeEntities.c filter.idPattern) and named in the 400 error message, but no test purges using idPattern.
  • [ ] [10.2.12] Purge filtered by NGSI-LD Query (q) over a Property value — q-filtered purge over a Property value is implemented (filter.qExpr) but never asserted; test comment mentions step 07 'q filter' but no such step exists.
  • [ ] [10.2.12] Purge filtered by q equality operator — No purge test exercises the q == operator.
  • [ ] [10.2.12] Purge filtered by NGSI-LD GeoQuery near/within/etc. — GeoQuery purge is implemented (filter.geoRel/geometry/coordinates) but no test purges with a geoquery.
  • [ ] [10.2.12] CSR matches but does not support purgeEntity, complete failure → 409 Conflict — No test where an exclusive/redirect CSR lacks purgeEntity op; implementation collects a Conflict into errors[] → 207 (not a bare 409), and this path is wholly untested.
  • [ ] [10.2.12] CSR does not support purgeEntity but some parts succeeded → partial success — No test exercises the 207 BatchOperationResult partial-success path (errors[] + success[]) for purge.

entity-maps (26)

  • [~] [14.2] Unknown entityMapId yields ResourceNotFound — 404 ResourceNotFound for an unknown id is only asserted on PATCH (step 08); there is no GET /entityMaps/{unknown-id} expecting 404 ResourceNotFound.
  • [ ] [14.3] Output-only fields in the fragment are ignored — Spec 14.3.4 says output-only fields shall be IGNORED, but this broker deliberately 400s on id/type/entityMap/linkedMaps (steps 04/05 assert the 400 reject, not silent ignore). No test asserts that a read-only field is ignored while writable fields still apply. Either add a test for the ignore semantics or document the deliberate divergence; current tests assert the opposite behaviour.
  • [ ] [14.3] Invalid (non-URI) EntityMap ID -> 400 BadRequestData — Step 08 uses a valid URI ('urn:NoSuch') yielding 404. No test sends a non-URI/invalid id to assert 400 BadRequestData.
  • [ ] [14.4] Successfully delete an existing Entity Map — No functest issues DELETE /entityMaps/{id} against a created map; success (204 No Content) path is untested though the broker implements it.
  • [ ] [14.4] Deleted Entity Map is actually removed from storage/memory — No test re-requests (GET) or re-deletes a deleted map to assert 404 ResourceNotFound after deletion.
  • [ ] [14.4] Entity Map ID is not a valid URI → BadRequestData (400) — No test deletes with a malformed/non-URI map ID; deleteEntityMap.c performs no URI validation (would yield 404 not 400), and nothing asserts this.
  • [ ] [14.4] Unknown / non-matching Entity Map ID → ResourceNotFound (404) — No test deletes a never-existed or already-deleted map ID to assert 404 ResourceNotFound with the correct ProblemDetails title.
  • [ ] [14.5] splitEntities flag explicit true → split-mode query — No EntityMap-create test sets splitEntities explicitly true to force the split-mode path (distributed entitymap tests all start brokers with --noSplitEntities).
  • [ ] [14.5] Split-mode local query restricts to id/type/idPattern only — No test exercises split-mode EntityMap creation to verify q/geo/scope/attr are NOT applied locally.
  • [ ] [14.5] Split-mode forwarding strips filters before forwarding — No test verifies q/geo/scope/attrs are stripped before forwarding in split-mode EntityMap creation.
  • [~] [14.5] ERROR: too-wide query → 400 BadRequestData — Too-wide rejection is asserted only on GET /entities, not on the /entityMaps create endpoint (GET/POST /entityMaps with no restriction -> 400 is untested).
  • [ ] [14.6] Create Entity Map for temporal query — success returns Entity Map + location — No test creates an EntityMap via the temporal query path; entityMap is explicitly NOT implemented for /temporal/entities (getEntitiesTemporal.c skips the entityMap param). Existing entitymap_*.test cover only the non-temporal /entityMaps + /entities?entityMap=true.
  • [ ] [14.6] Missing temporal query → 400 BadRequestData — troe_temporal_get_no_timerel asserts the OPPOSITE for single-entity GET (no timerel = return all). No test asserts 400 BadRequestData when timerel/timeAt is omitted on the multi-entity temporal create-entity-map query.
  • [ ] [14.6] Too-wide query: none of type/attrs/q/geoQ/local-scope provided → 400 — No test issues a temporal create-entity-map query lacking all restrictions to assert 400 BadRequestData (too wide).
  • [ ] [14.6] Attribute-name list with ONLY system attributes does NOT satisfy restriction → 400 — No test sends a temporal query whose only restriction is a system-attr-only attrs list to assert 400.
  • [ ] [14.6] NGSI-LD Query referencing ONLY system attributes does NOT satisfy restriction → 400 — No test sends a temporal q over only system attrs (as sole restriction) to assert 400.
  • [ ] [14.6] Invalid URI in Entity identifier list → 400 BadRequestData — temporal_create_errors covers POST-body id URI validation for entity creation, not an invalid id in the temporal query's id-list of the create-entity-map operation. No GET /temporal/entities?id= 400 assertion.
  • [ ] [14.6] Syntactically invalid q → 400 BadRequestData — No test sends a malformed q to the temporal query/entity-map operation to assert 400.
  • [ ] [14.6] Local Entity Map created from final result set S4 — No test verifies that a temporal EntityMap is built from the final filtered set; the operation is unimplemented for /temporal/entities.
  • [ ] [14.6] Distributed: forward to matching CSRs supporting createEntityMapQueryTemporal — Distributed temporal data queries forward to CSRs supporting queryTemporal (no-split federation only per source comment), but there is NO entity-map operation forwarded and NO createEntityMapQueryTemporal opt-in tested.
  • [ ] [14.6] Distributed split mode: filters stripped before forwarding — Source explicitly does NOT implement split mode for temporal (no entityMap, all filters forwarded verbatim). No test asserts filter-stripping before forwarding in split mode.
  • [ ] [14.6] Split mode local query returns all locally found entities meeting all conditions — Split mode is not implemented for the temporal path; no test of the split-mode local S4 branch for entity-map creation.
  • [ ] [14.6] Remote Entity Map merged: linkedMaps records CSR→EntityMap-Id — entitymap_linked_maps covers linkedMaps for the NON-temporal /entityMaps operation; no temporal entity-map merges remote maps into linkedMaps.
  • [ ] [14.6] Remote entity ids merged: entityMap records entityId→CSR — entityMap entityId→CSR mapping tested only for the non-temporal operation; not for the temporal create-entity-map.
  • [ ] [14.6] Local Entity Map stored and accessible by its identifier — Storage/retrieval-by-id is tested for non-temporal entity maps only; no temporal EntityMap is stored or GET-retrievable.
  • [ ] [14.6] Entity Map usable for paginating temporal evolution of included entities — No test creates a temporal EntityMap and then paginates the temporal evolution of its entities via the map id.

json-ld (4)

  • [~] [8.2] Invalid JSON payload body → 400 InvalidRequest — No test sends a SYNTACTICALLY malformed JSON document (trailing comma / unclosed brace / parse error) to assert 400 InvalidRequest. Existing 'InvalidRequest' cases are all valid JSON of the wrong shape (array instead of object) or missing fields, not a JSON parse failure.
  • [ ] [8.2] urn:ngsi-ld:null as RHS of Property 'value' → 400 BadRequestData — No test asserts that a Property value equal to the string 'urn:ngsi-ld:null' in a CREATE/REPLACE entity (outside merge/update fragments) is rejected with 400 BadRequestData. Only the ALLOWED merge-fragment direction is covered.
  • [ ] [8.2] urn:ngsi-ld:null as RHS of Relationship 'object' → 400 BadRequestData — No test asserts a Relationship object 'urn:ngsi-ld:null' in a CREATE/REPLACE entity is rejected 400 BadRequestData (only the merge-delete ALLOWED direction is tested).
  • [ ] [8.2] User @context containing JSON-LD Scoped Contexts → 400 BadRequestData — No test supplies a user @context that defines a term with a nested/scoped @context and asserts 400 BadRequestData. Scoped contexts are only mentioned in comments (context_embedded.test), never exercised.

local-scope (3)

  • [ ] [8.6] Subscription localOnly=true matches only locally stored Entities — No subscription test sets localOnly=true; no assertion that notifications are generated solely from local changes and not from distributed/remote source data.
  • [ ] [8.6] localOnly in RegistrationManagementInfo forces local scope when contacting the registered Source — No behavioral test that a CSR carrying management.localOnly makes the broker send a local scope (e.g. Via/local flag) to the registered source so it does not cascade into its own registry. Only validation of the field's type exists, not the forwarding behavior.
  • [ ] [8.6] ordering parameter requires local scope; otherwise BadRequestData (400) — No test uses the TS 104-175 'ordering' URL parameter; the broker/tests only have 'orderBy' (sort), whose distributed restriction test (troe_timescale_temporal_orderby_restrictions.test) returns 200 not a local-scope-required 400. The spec's ordering-requires-local-scope → BadRequestData(400) rule, and its acceptance under local scope, is unimplemented/untested.

multi-attr-datasetId (2)

  • [ ] [8.5] Conflicting entity-level expiresAt: missing in any version → removed from entity — No multi-source test where one Context Source version lacks entity-level expiresAt; should assert expiresAt is removed from the merged entity. distop_expires_at_propagate.test is single-source only.
  • [ ] [8.5] Conflicting entity-level expiresAt: all present → furthest-future wins — No multi-source test where all versions carry entity-level expiresAt asserting the merged entity takes the maximum (furthest-future) DateTime.

ordering (3)

  • [~] [7.6] orderBy by attribute path (dot-separated) addressing a sub-attribute / Property of Property — orderBy=name.createdAt is accepted (200) on the temporal endpoint but result set is empty, so the dot-path ordering result is never asserted. No /entities test verifies a dot-path sub-attribute actually drives the order.
  • [ ] [7.6] Sort by distance ascending from a Point (dist-asc + orderFrom) — No test uses orderBy=location;dist-asc&orderFrom=[lon,lat] to rank by nearest-first distance.
  • [ ] [7.6] Sort by distance descending from a Point (dist-desc + orderFrom) — No test uses orderBy=location;dist-desc&orderFrom=[lon,lat] for farthest-first ordering.

pagination (4)

  • [ ] [7.4] Pagination supported for Query Subscriptions — GET /subscriptions list exists (subscription_crud.test) but no test exercises limit/offset/count or asserts pagination Link headers on the subscription list
  • [ ] [7.4] Pagination supported for Query CSource Registration Subscriptions — no test paginates GET /csourceSubscriptions (no limit/offset/count or Link headers asserted on the csr-subscription list)
  • [ ] [7.4] Changing @context mid-pagination -> 400 BadRequestData — no test continues an entityMap pagination with a different @context (Link/Content-Type) expecting 400 BadRequestData
  • [ ] [7.4] Excessively large result set -> 403 TooManyResults — no test triggers the TooManyResults 403 ProblemDetails (type .../errors/TooManyResults); grep finds zero references

query-filter (4)

  • [ ] [7.2] q unequal with differing data types — No test asserts that q=attr!= MATCHES when the stored value and query value have different data types (e.g. string attr != number). Spec-mandated != semantics for type mismatch untested.
  • [ ] [7.2] q equality: scalar included in array target — No test stores a Property whose value is a scalar array (e.g. color value ["blue","red"]) and queries q=color=="red" to verify the scalar matches an element of the array target. ListProperty membership is covered but that is a distinct data type.
  • [ ] [7.2] q Relationship/ListRelationship with non-eq operator → not matching — No test verifies that a Relationship/ListRelationship combined with >, <, ~= etc. results in NO MATCH (not an HTTP error). Spec-mandated behaviour untested.
  • [ ] [7.2] q equality: differing data types → not matching — No == test asserts NO MATCH when the target value data type differs from the query-term value data type (e.g. q=numAttr=="5" string vs stored number).

query-projection (2)

  • [ ] [7.3] Linked-Entity projection term via Relationship (pick) — No test exercises ?pick=rel{attr} Linked-Entity projection; brace syntax appears only in q= linked filters. Add a test projecting attrs from a Relationship target object.
  • [ ] [7.3] AttrName grammar validation in projection term — No test rejects a malformed projection term (empty term, unbalanced LinkedEntityTerm braces, bad AttrName) with 400 BadRequestData. Only attrs+pick/omit mutual-exclusion 400 is covered.

registration (15)

  • [ ] [12.2] Register redirect mode — existing Entity already matches → 409 Conflict — No test seeds a local entity then registers a redirect-mode CSR overlapping it and asserts 409; creation-conflicts step 05 only tests redirect-vs-existing-exclusive-reg, not redirect-vs-local-entity
  • [ ] [12.2] Register redirect mode — endpoint+tenant match the broker itself → 409 Conflict — create-loop registers a redirect CSR whose endpoint is the broker's own port and gets 201 (only the later createEntity is 508); no test rejects the self-pointing redirect registration itself with 409 at registration time
  • [ ] [12.2] Update — target id missing or not a valid URI → 400 BadRequestData — No PATCH /csourceRegistrations/ test asserting 400 BadRequestData; all update tests use valid urn ids
  • [~] [12.2] Update — fragment violates 5.2.6.5.3 → 400 BadRequestData — delete_marker covers deleting mandatory endpoint/information via marker → 400, but no PATCH test supplies a malformed fragment field (e.g. invalid mode value, bad operations, bad expiresAt, malformed information shape) and asserts 400; the rich create-side field validators are not re-exercised on the update path
  • [ ] [12.2] Update exclusive mode — overlapping exclusive/redirect reg → 409 Conflict — No test PATCHes a registration to mode=exclusive (or changes its entity/attrs) such that it overlaps an existing exclusive/redirect reg and asserts 409; conflict re-checking on the update path is untested (only create-path conflicts in creation-conflicts.test)
  • [ ] [12.2] Update exclusive mode — existing Entity with overlapping attrs → 409 Conflict — No test updates a registration to exclusive overlapping an existing local entity and asserts 409 on the update path
  • [ ] [12.2] Update auxiliary mode — operations not in allowed set → 400 BadRequestData — No test PATCHes a registration to mode=auxiliary with a disallowed op (or adds a disallowed op to an existing auxiliary reg) and asserts 400; auxiliary-op validation is only tested on create
  • [ ] [12.4] geoQ matched against GeoProperty named in geoQ — No CSR-subscription test includes a geoQ matched against a CSR GeoProperty (match and non-match).
  • [ ] [12.4] No temporalQ → only CSRs without time intervals considered — No CSR-sub test exercising the no-temporalQ rule (latest-info CSRs only; CSRs with observation/managementInterval excluded).
  • [ ] [12.4] temporalQ present → only CSRs with specified time intervals considered — No CSR-sub test with a temporalQ that filters to interval-bearing CSRs only.
  • [ ] [12.4] temporalQ but relevant interval absent in CSR → no match — No CSR-sub test where a temporalQ finds no relevant interval in the CSR and therefore does not match.
  • [ ] [12.4] Context source filter (csf) matches CSR properties — No CSR-sub test includes a csf matched against CSR properties (match/non-match).
  • [ ] [12.4] Context source query (4.9) matches CSR properties — No CSR-sub test uses q over a CSR Property/Relationship/sub-attribute to filter matching CSRs (only entity-sub q syntax error is tested on the endpoint).
  • [ ] [12.4] Scope query matched against CSR scope property — No CSR-sub test with a scopeQ matched against a CSR scope property.
  • [ ] [12.4] q over CSR Property — No CSR-sub test uses q over a CSR Property to verify match/non-match filtering of CSRs.

snapshots (15)

  • [ ] [16.2] Final snapshotStatus = 'failure' otherwise — No test drives a snapshot where no query/temporal-query succeeds (e.g. a forwarded source that errors out) to verify snapshotStatus=failure.
  • [~] [16.2] BadRequestData when neither snapshotQueries nor snapshotTemporalQueries present — crud #01 posts '{}' but the 400 is triggered by missing/invalid type, not by absence of both query lists. No test sends a valid type=Snapshot document with both query lists absent to assert the dedicated BadRequestData.
  • [ ] [16.2] BadRequestData when a snapshotQueries Query contains a temporalQ element — No test places a temporalQ inside a snapshotQueries entry to verify the restriction yields 400.
  • [ ] [16.2] BadRequestData when a snapshotTemporalQueries Query lacks a temporalQ element — No test posts a snapshotTemporalQueries entry without a temporalQ element to verify the restriction yields 400.
  • [ ] [16.3] snapshotQueriesDetails not permitted in clone request body — No test POSTs a clone body containing snapshotQueriesDetails and asserts 400 BadRequestData.
  • [ ] [16.3] snapshotQueriesTemporalDetails not permitted in clone request body — No test POSTs a clone body containing snapshotQueriesTemporalDetails and asserts 400 BadRequestData.
  • [ ] [16.3] Snapshot data type/cardinality/restriction violation -> 400 BadRequestData — No clone-path test exercises a generic data-type/cardinality/restriction violation in the clone body expecting 400 BadRequestData (such validation is only tested on the create path, not /clone).
  • [ ] [16.3] Snapshot notification sent when endpoint member present — snapshot_notification.test header comment lists 'Clone WITH endpoint -> one notification' as steps 05/06, but the RUN/EXPECT body stops at delete (step 08); no clone-with-endpoint notification is actually exercised or asserted.
  • [ ] [16.4] snapshotStatus value "failure" is representable — No test produces snapshotStatus="failure" (nor resultStatus="failure"). Need a snapshot whose query execution(s) fail (e.g. distributed capture against an unreachable CSR endpoint) and a GET asserting snapshotStatus=failure.
  • [ ] [16.4] Invalid (non-URI) Snapshot Id raises BadRequestData — No test does GET /snapshots/{non-URI id} expecting 400 BadRequestData; only valid-URI unknown ids are tested (which return 404).
  • [ ] [16.5] Update endpoint — No test PATCHes the endpoint member onto an existing snapshot; endpoint is only set at creation time (snapshot_notification.test step 03). Add a PATCH {"endpoint":...} and verify it is applied (subsequent status notification reaches the new endpoint).
  • [ ] [16.5] Update receiverInfo — No test PATCHes receiverInfo onto an existing snapshot; receiverInfo is only set at creation (snapshot_notification.test step 03). Add a PATCH {"receiverInfo":[...]} and verify the new headers appear on a status notification.
  • [ ] [16.5] Output-only members in fragment are ignored — No test sends an output-only member (snapshotStatus, snapshotQueriesDetails, createdAt, modifiedAt, expiresAt, lastUsedAt, etc.) in a PATCH fragment to verify it is silently ignored (no error, value not applied).
  • [ ] [16.5] snapshotTemporalQueries must be omitted on update -> BadRequestData — snapshotQueries-on-PATCH→400 is tested but the analogous snapshotTemporalQueries-on-PATCH→400 guard is not; add a PATCH {snapshotTemporalQueries:[...]} expecting 400 BadRequestData.
  • [ ] [16.6] Invalid (non-URI) Snapshot id → 400 BadRequestData — No DELETE /snapshots/ test (e.g. 'not-a-uri' / 'no-colon'); the BadRequestData/Invalid-URI 400 path for snapshot delete is never asserted.

subscription (17)

  • [ ] [10.5.2] Auto-generate subscription id when not supplied — No subscription is ever POSTed without an id; subscription_crud step 03 claims 'auto-generated id' in its comment but the payload still carries an explicit urn:ngsi-ld:Subscription:S2. Need a create with no id asserting Location: /ngsi-ld/v1/subscriptions/REGEX(urn:ngsi-ld:Subscription:.*) and a follow-up GET on that id.
  • [~] [10.5.2] watchedAttributes present -> only those attributes trigger notifications — watchedAttributes is accepted and stored, but no test creates a sub with watchedAttributes=[X] and asserts a change to X fires while a change to a different (unwatched) attribute does NOT fire.
  • [ ] [10.5.2] watchedAttributes without subscribed entities -> subscribe to all entities having matching attrs — No test creates a sub with only watchedAttributes (no entities) and asserts that any entity carrying a matching attribute fires while one without it does not. subscription_crud S2 has both entities and watchedAttributes.
  • [ ] [10.5.3] Term to URI expansion of attribute names on update (clause 8.2.4) — No PATCH test supplies a non-core @context and asserts that short watchedAttributes/notification.attributes/q names are expanded to URIs on update; all PATCH fragments use core/default terms.
  • [ ] [10.5.3] isActive=true (no expiresAt) does NOT activate when prior status was expired — No test sets up an already-expired subscription and PATCHes isActive=true to assert status stays expired; the expired-vs-active rule of 10.5.3.4 is untested.
  • [ ] [10.5.3] isActive=false (no expiresAt) does NOT pause when prior status was expired — No test PATCHes isActive=false on an expired subscription to assert status stays expired (not paused).
  • [ ] [10.5.3] Only future expiresAt re-activates an expired subscription — No test takes an expired subscription, PATCHes only a future expiresAt, and asserts reactivation (status->active).
  • [ ] [10.5.3] Unknown subscription id raises ResourceNotFound — No test PATCHes a syntactically valid but non-existent subscription URI to assert 404 ResourceNotFound; crud only covers 404 on GET/DELETE of an unknown sub, not PATCH.
  • [ ] [10.5.5] Negative limit rejected with 400 BadRequestData — No test for GET /subscriptions?limit=-1 asserting 400 BadRequestData.
  • [ ] [10.5.5] Non-integer / malformed limit rejected with 400 BadRequestData — No test for GET /subscriptions?limit=abc asserting 400 BadRequestData.
  • [ ] [10.5.5] Negative offset rejected with 400 BadRequestData — No test for GET /subscriptions?offset=-1 asserting 400 BadRequestData.
  • [ ] [10.5.5] Non-integer / malformed offset rejected with 400 BadRequestData — No test for GET /subscriptions?offset=abc asserting 400 BadRequestData.
  • [ ] [10.5.5] count=true sets NGSILD-Results-Count header with total count — NGSILD-Results-Count header is tested for entity/registration listings (query_entities_pagination.test, csource_reg_discovery_pagination.test) but never for GET /subscriptions?count=true.
  • [ ] [10.5.5] Accept application/ld+json returns JSON-LD with embedded @context — No GET /subscriptions with Accept: application/ld+json asserting an inline @context in each subscription and no @context Link header (existing ld+json usages on /subscriptions are POST Content-Type, not list GET).
  • [~] [10.5.5] Tenant scoping via NGSILD-Tenant header lists only that tenant's subscriptions — Subscriptions are created under a tenant and a single one is GET-retrieved with the tenant header, but no test does GET /subscriptions (list) with a tenant header and asserts only that tenant's subscriptions appear / cross-tenant isolation / unknown tenant -> empty array.
  • [ ] [10.5.6] No further notifications after delete — No test creates a subscription, deletes it, then changes a matching entity to assert that NO notification is delivered (e.g. via an ftClient notification receiver showing zero hits post-delete).
  • [ ] [10.5.7] No notification when subscription status is expired — No test verifies that a subscription whose status becomes 'expired' (e.g. expiresAt passes) suppresses notifications; subscription_expiration only covers a far-future expiry (still active) and past-expiry rejection at create-time.

temporal (45)

  • [ ] [11.2.2] Upsert onto existing Temporal Evolution returns 204 No Content — No test POSTs to /temporal/entities twice for the same id to verify the existing-entity update path returns 204 No Content (existing tests only POST /temporal/entities/{id}/attrs for the update path, or POST a fresh/deleted id which is a 201 create).
  • [ ] [11.2.2] New entity type names in type are merged into the existing type list — No temporal-upsert test supplies a type with new Entity Type names on update and asserts the target's type list gains them while retaining existing types.
  • [ ] [11.2.2] Invalid JSON payload raises InvalidRequest — No temporal-create test posts malformed JSON and asserts 400 InvalidRequest.
  • [ ] [11.2.2] Syntactically incorrect NGSI-LD data raises BadRequestData — No temporal-create test posts valid-JSON-but-bad-NGSI-LD (e.g. malformed attribute structure / missing required member) and asserts 400 BadRequestData.
  • [ ] [11.2.2] Missing Entity type raises BadRequestData — temporal_create_errors covers missing/empty/invalid id but does NOT cover an EntityTemporal lacking a type member; no test asserts 400 BadRequestData for missing type on temporal create.
  • [ ] [11.2.2] Invalid DateTime in observedAt/temporal member raises BadRequestData — No temporal-create test supplies a malformed observedAt/temporal DateTime and asserts 400 BadRequestData.
  • [ ] [11.2.2] Exclusive matching registration: attributes forwarded for remote processing — All temporal-upsert distop tests use inclusive mode only; no exclusive registration on upsertTemporal verifying matching attrs are forwarded and removed from the local fragment.
  • [ ] [11.2.2] Redirect matching registration: input data forwarded — No redirect-mode registration test for upsertTemporal verifying input data is forwarded and removed from the local fragment.
  • [ ] [11.2.3] Distributed add resolves a target known only via registration (no local entity) → 204 — In the inclusive test the target also exists locally (seeded via upsert fan-out). No test does appendAttrsTemporal to an entity that exists ONLY via a matching registration (no local temporal entity) and asserts success instead of ResourceNotFound.
  • [~] [11.2.4] Delete attribute from temporal evolution - success (default instance) — Step 05 deletes the whole 'color' attr (single instance) and verifies it's gone, but the no-datasetId/no-deleteAll case is never tested against an attr that has BOTH a default and datasetId instances to prove ONLY the default instance is removed and the datasetId ones remain.
  • [ ] [11.2.4] datasetId parameter removes only that dataset instance — No temporal DELETE /attrs/{attr}?datasetId=... test; the only datasetId-scoped delete is on the current-state /entities endpoint (entity_attr_crud.test), not on /temporal. Need a test that deletes one dataset instance and verifies the default + other datasets remain.
  • [ ] [11.2.4] No datasetId and no deleteAll removes only the default instance — No temporal delete-attr test seeds default + datasetId instances and deletes with neither flag to prove only the default (no-datasetId) instance is removed and datasetId instances are untouched.
  • [ ] [11.2.4] Invalid Entity ID URI -> 400 BadRequestData — No temporal DELETE /attrs test with a non-URI entity id asserting 400 BadRequestData.
  • [ ] [11.2.4] Unknown Entity -> 404 ResourceNotFound — temporal_writes.test step 09 covers DELETE of a whole unknown temporal entity (404), but there is no DELETE /attrs/{attr} on an unknown entity asserting 404 ResourceNotFound.
  • [ ] [11.2.4] Entity exists but does not contain the target Attribute -> 404 ResourceNotFound — No test deletes a non-existent attribute from an existing temporal entity asserting 404 ResourceNotFound (with ProblemDetails title).
  • [ ] [11.2.4] Exclusive registration match -> forward, no further local processing — No exclusive-registration temporal delete-attr distop test; only inclusive mode is covered. Need to verify forward + local skipped for deleteAttrsTemporal.
  • [ ] [11.2.4] Redirect registration match -> forward, no further local processing — No redirect-registration temporal delete-attr distop test verifying forwarding for deleteAttrsTemporal.
  • [ ] [11.2.4] Matched registration does not support op, complete failure -> 409 Conflict — No test where a matched exclusive/redirect reg lacks deleteAttrsTemporal support and the complete op fails, asserting 409 Conflict.
  • [~] [11.2.5] Modify Attribute instance success (createdAt preserved, modifiedAt updated) — Success+204+new-value-stored are asserted, but createdAt-preserved / modifiedAt-updated never verified via a sysAttrs temporal GET.
  • [ ] [11.2.5] createdAt of the modified instance remains unchanged — No test reads createdAt of the targeted instance before and after the PATCH (sysAttrs GET) to confirm it is unchanged.
  • [ ] [11.2.5] modifiedAt of the modified instance set to modification time — No test verifies the modified instance's modifiedAt is set to the operation timestamp (newer than before) via sysAttrs GET.
  • [ ] [11.2.5] Invalid Entity ID URI -> 400 BadRequestData — No instance-modify test sends an invalid Entity ID URI to assert 400 BadRequestData.
  • [ ] [11.2.5] Invalid target Attribute name -> 400 BadRequestData — No instance-modify test uses an invalid attribute name to assert 400 BadRequestData.
  • [ ] [11.2.5] Invalid instanceId URI -> 400 BadRequestData — No test PATCHes with a syntactically invalid instanceId URI to assert 400 BadRequestData (existing 404 case uses a well-formed-but-absent URN).
  • [ ] [11.2.5] Unknown target Entity -> 404 ResourceNotFound — No instance-modify test PATCHes against an entity the broker does not know (no local entity, no matching reg) to assert 404 ResourceNotFound.
  • [ ] [11.2.5] Target Attribute absent from the Temporal Evolution -> 404 ResourceNotFound — No test PATCHes an instance of an attribute that does not exist on the entity to assert 404 ResourceNotFound.
  • [ ] [11.2.5] Exclusive registration match forwards the input data — Only inclusive forwarding is tested; no exclusive-registration instance-modify forward (where local processing is skipped).
  • [ ] [11.2.5] Redirect registration match forwards the input data — No redirect-registration instance-modify forward test.
  • [ ] [11.2.6] Other attributes of the entity are unaffected — The happy-path entity has only one attribute (speed); no test deletes one instance and asserts a sibling attribute (e.g. color) is untouched.
  • [ ] [11.2.6] Entity ID not a valid URI -> 400 BadRequestData — No test issues DELETE on the instance endpoint with an invalid (non-URI) entity id and asserts 400 BadRequestData.
  • [ ] [11.2.6] instanceId not a valid URI -> 400 BadRequestData — No test deletes with an invalid (non-URI) instanceId expecting 400 BadRequestData.
  • [ ] [11.2.7] Invalid (non-URI) target Entity ID raises BadRequestData — No test does DELETE /temporal/entities/{malformed-non-URI-id} asserting 400 BadRequestData with ProblemDetails title 'BadRequestData'.
  • [ ] [11.2.7] Exclusive registration match: input forwarded to registration endpoint — Only an INCLUSIVE temporal-delete distop test exists; no exclusive-registration temporal delete forward test (the csource-reg-distops-delete-exclusive tests target non-temporal /entities).
  • [ ] [11.2.7] Redirect registration match: input forwarded to registration endpoint — No redirect-registration temporal-delete forwarding test exists.
  • [ ] [11.2.7] Resolution via matching registration only (no local entity) — No test deletes a temporal entity that exists only via a matching registration (no local copy) to confirm it forwards/succeeds rather than returning ResourceNotFound.
  • [ ] [11.3.2] Sub-attributes preserved within temporal instances — No temporal GET asserts that a sub-attribute (e.g. unitCode or a custom sub-property) attached to an instance is preserved in that instance's temporal representation.
  • [ ] [11.3.2] Distributed retrieve: auxiliary source fills gaps only — No temporal retrieve test registers an auxiliary CSR to prove auxiliary instances are added only for timestamps not already present from higher-priority sources.
  • [ ] [11.3.3] attrs list of only system attributes does not satisfy restriction -> BadRequestData — No test sends attrs=createdAt (only system attrs) and asserts 400 BadRequestData for failing the restriction requirement.
  • [ ] [11.3.3] Invalid URI in id list -> BadRequestData — No temporal test sends an invalid URI in the id list and asserts 400 BadRequestData.
  • [ ] [11.3.3] Syntactically invalid q -> BadRequestData — No temporal test sends a syntactically malformed q (e.g. q=speed>>) and asserts 400.
  • [ ] [11.3.3] Syntactically invalid geoquery -> BadRequestData — No temporal test sends malformed georel/geometry/coordinates and asserts 400 (the non-temporal geoQ validation tests exist but not on /temporal/entities).
  • [ ] [11.3.3] orderBy present without local scope -> BadRequestData — Implementation DIVERGES: orderBy without local scope returns 200 (orderby_restrictions.test asserts this), not the spec-mandated 400. Either the impl or the test needs aligning to 11.3.3-16; no test asserts the 400 behaviour.
  • [ ] [11.3.3] orderBy refers to member other than id -> BadRequestData — Implementation DIVERGES: orderBy=speed and orderBy=name.createdAt return 200 (test asserts acceptance of any member), not the spec-mandated 400 for non-id ordering.
  • [~] [11.3.3] q checked against instances within temporal interval only — q=speed>20 keeps V1 (whose value REACHED 30 in history) implying q evaluated over the series, but no test isolates a case where the snapshot value would FAIL while an in-interval instance PASSES (or vice versa) combined with a timerel window to prove interval-scoping of q.
  • [~] [11.3.3] Distributed query forwarded to exclusive/redirect/inclusive CSRs supporting queryTemporal — Only the INCLUSIVE mode is covered (CB+CP1 union merge per 8.5). Exclusive and redirect CSR modes for queryTemporal are not tested.

MEDIUM-priority gaps

batch (66)

  • [ ] [10.3.2] Payload not valid JSON -> 400 InvalidRequest — No batch-create test posts malformed/non-JSON body to /entityOperations/create asserting 400 InvalidRequest (title 'Invalid Request'); existing batch tests only cover valid-JSON-bad-content (BadRequestData)
  • [~] [10.3.2] Syntactically incorrect entity content -> 400 BadRequestData — Malformed attribute structure (e.g. bad value-object / Property both value+object) inside a batch-create element is not specifically exercised; covered only for single create (create_entity_errors.test). Batch path only tests missing/invalid id/type and missing @context
  • [ ] [10.3.2] urn:ngsi-ld:null as first-level member value -> BadRequestData — No create test asserts that key:"urn:ngsi-ld:null" as a first-level member is rejected with BadRequestData; the urn:ngsi-ld:null tests cover only merge/patch delete-marker semantics
  • [ ] [10.3.2] urn:ngsi-ld:null as Property value -> BadRequestData — No create test asserts a Property value of "urn:ngsi-ld:null" is rejected; merge_patch_null_sentinel only tests raw JSON null on merge-PATCH
  • [ ] [10.3.2] urn:ngsi-ld:null as Relationship object -> BadRequestData — No create test asserts a Relationship object of "urn:ngsi-ld:null" is rejected with BadRequestData
  • [ ] [10.3.2] Entity with Relationship attribute created — No batch-create test includes a Relationship attribute; only Property/LanguageProperty appear in batch create payloads
  • [ ] [10.3.2] Entity with GeoProperty created — No batch-create test creates a GeoProperty nor exercises invalid geometry/coordinates -> per-entity BadRequestData in errors[] via the batch endpoint
  • [ ] [10.3.2] Entity with multi-attribute (datasetId) instances created — No batch-create test creates an entity with multiple same-attribute instances distinguished by datasetId (batch_multi_instance_per_op is about repeated entities, not multi-attr datasetId)
  • [ ] [10.3.2] Concise representation entities accepted — No batch-create test uses concise representation (implicit Property/Relationship typing); concise is only tested for single create (create_entity_concise.test)
  • [ ] [10.3.2] Distributed forward via per-entity Create Entity when batch unsupported — No test where a matching CSR lacks createBatch but supports createEntity, forcing per-entity forwarding fallback for a batch-create input
  • [~] [10.3.2] Exclusive CSR attribute removal from peers — entity_batch_create_distops shows type-based filtering (Sensor not forwarded to Vehicle reg); exclusive attribute-slice removal from OTHER CSRs' IN is only exercised via single-entity create (excl-no-op), not through the batch /entityOperations/create endpoint with multiple peers
  • [~] [10.3.2] Redirect CSR attribute removal from peers — redirect attr-claim/chop is tested via single-entity POST /entities (two redirect CSRs claiming different attrs), not via the batch create endpoint; no explicit 'removed from IN unless current CSR is that redirect' assertion in batch path
  • [~] [10.3.2] Exclusive/redirect CSR with no usable op -> Conflict error — Conflict (409, title 'Conflict', errors/Conflict) for an exclusive CSR lacking createEntity/createBatch is asserted via single-entity POST /entities, not via the batch /entityOperations/create endpoint
  • [~] [10.3.2] Distributed operation failure/timeout/unsupported -> error in result — forward 503/403 failures producing per-entity error entries are asserted via single-entity POST /entities; no batch /entityOperations/create test drives a failing/timing-out downstream CSR into the BatchOperationResult errors[]
  • [~] [10.3.2] Mixed local+distributed result merge correctness — entity_batch_create_distops shows coherent local+remote inclusive merge; a true mixed batch where some entities go remote AND some fail (merged S/E with no duplicates) through the batch endpoint is not asserted
  • [ ] [10.3.2] Tenant scoping via NGSILD-Tenant header — No batch-create test uses NGSILD-Tenant to create entities in a non-default tenant and verify isolation from the default tenant
  • [~] [10.3.3] options=replace explicit replaces existing entity content entirely — options=replace is exercised explicitly (type change) but no test asserts that a prior attribute absent from the new content is dropped under explicit options=replace (only the default-mode drop is asserted in entity_batch_upsert step 04).
  • [ ] [10.3.3] Invalid/non-parseable JSON-LD rejected as InvalidRequest — No test posts syntactically broken JSON (e.g. truncated body) to /entityOperations/upsert to assert 400 InvalidRequest. InvalidRequest is tested only on create_entity/replace/query endpoints, not the upsert batch endpoint.
  • [~] [10.3.3] Replace-mode update entity content validated per local create — Replace-mode type change and id/type validation are asserted, but no test feeds a structurally-invalid attribute (e.g. Property with no value, malformed Relationship) in replace-mode upsert to confirm that single entity yields a BatchEntityError while others succeed.
  • [~] [10.3.3] Distributed forward: exclusive CSR attributes removed from other CSRs' IN — Exclusive CSR chops its claimed attr off the LOCAL fragment, but no upsert test has two CSRs where an exclusive CSR's attributes are demonstrably removed from a SECOND CSR's forwarded IN.
  • [~] [10.3.3] Distributed forward: redirect CSR attributes removed unless CSR is redirect — Two redirect CSRs both receive the forward (redirect-not-removed-from-redirect path), but no upsert test shows redirect-claimed attributes removed from a NON-redirect CSR's IN.
  • [ ] [10.3.3] Distributed fallback to Create Entity per-entity when batch upsert unsupported — No upsert test registers a CSR that supports createEntity but NOT upsertBatch to verify the per-entity Create-Entity fallback fan-out.
  • [ ] [10.3.3] Distributed AlreadyExists then Replace (replace mode) on fallback CSR — No test covers the fallback chain where per-entity Create returns AlreadyExists and the CSR supports Replace (replace/default mode) so a Replace Entity request is forwarded.
  • [ ] [10.3.3] Distributed AlreadyExists then Update Attributes (update mode) on fallback CSR — No test covers per-entity Create returning AlreadyExists in update mode followed by an Update-Attributes forward to the fallback CSR.
  • [ ] [10.3.3] Distributed AlreadyExists, no replace/update support => OperationNotSupported error — No test asserts an OperationNotSupported BatchEntityError when a fallback CSR supports neither the needed Replace nor Update after AlreadyExists.
  • [~] [10.3.3] Distributed operation unsupported/fails/times out surfaces in 207 — The 'unsupported op' branch surfaces in 207 (conflict test). No upsert test exercises a forwarded op that FAILS (remote 5xx) or TIMES OUT to confirm that registration error result lands in errors[] with overall 207.
  • [ ] [10.3.3] Wrong HTTP method on /entityOperations/upsert rejected — http_405_method_not_allowed.test covers /entities and /entities/{id} but never hits /entityOperations/upsert with a non-POST method to assert 405.
  • [~] [10.3.3] Tenant scoping via NGSILD-Tenant header — An upsert with NGSILD-Tenant: captn is issued and the entity is later GET'd in that tenant, but isolation from the default tenant (entity absent without the header) is not asserted, and the focus is notification not upsert tenant scoping.
  • [~] [10.3.4] Update appends new (previously absent) attributes to existing entity — No batch-update step adds a brand-new (previously absent) attribute and then GETs to confirm it appeared; existing tests only overwrite present attrs while preserving untouched ones.
  • [~] [10.3.4] options=noOverwrite keeps existing attribute, still appends new ones — noOverwrite keep-existing half is asserted, but the 'still appends a NEW attribute under noOverwrite' half is not exercised (all attrs in that test pre-exist).
  • [~] [10.3.4] All entities fail -> 207 Multi-Status (success array empty) — All-fail collapses to a plain 404 ProblemDetails (entity_batch_update.test step 08, batch_status_codes.test), not a 207 with empty success[]. The distops_nooverwrite test does show a 207 with success:[] but driven by noOverwrite-conflict, not a pure 'all non-existent entities' all-fail; a multi-error 207 with empty success array from heterogeneous local failures is not asserted.
  • [~] [10.3.4] Syntactically incorrect NGSI-LD content -> 400 BadRequestData — Malformed @type (non-string) is covered for batch create/upsert; for batch UPDATE only invalid/missing @id is asserted. A malformed Property/Relationship structure inside a batch-update element is not specifically tested.
  • [ ] [10.3.4] urn:ngsi-ld:null as first-level member value -> 400 BadRequestData — No batch-update test sends urn:ngsi-ld:null as a first-level member to assert BadRequestData (null sentinel only valid in merge/fragment context).
  • [ ] [10.3.4] urn:ngsi-ld:null as Property value RHS -> 400 BadRequestData — No batch-update test uses urn:ngsi-ld:null as a Property value RHS to assert rejection.
  • [ ] [10.3.4] urn:ngsi-ld:null as Relationship object RHS -> 400 BadRequestData — No batch-update test uses urn:ngsi-ld:null as a Relationship object RHS to assert rejection.
  • [ ] [10.3.4] Update with simplified (concise) representation accepted — No batch-update test sends entities in concise/simplified key-value form; all update payloads use full normalized Property objects.
  • [~] [10.3.4] @context honored from request body array @context entry — Batch update with inline @context is exercised only to verify the missing-@context error path; no batch-update test asserts a short term expanding to the expected IRI via an inline body @context.
  • [ ] [10.3.4] @context via Link header honored for term expansion — No batch-update test supplies @context via Link header and asserts short-name expansion (Link-header expansion is only tested for batch create).
  • [~] [10.3.4] Update Property attribute (value, observedAt, unitCode, sub-attrs) — Only Property value is updated; observedAt, unitCode and sub-attribute updates via batch update are not exercised/asserted.
  • [ ] [10.3.4] Update Relationship attribute (object + sub-attrs) — No batch-update test updates a Relationship's object (or its sub-attrs) and verifies the new object is persisted.
  • [ ] [10.3.4] Update GeoProperty attribute — No batch-update test updates a GeoProperty geometry (nor asserts invalid geometry -> per-entity BadRequestData).
  • [ ] [10.3.4] Update Property with multiple instances (datasetId) — per-instance handling — No batch-update test targets a specific datasetId instance vs the default instance.
  • [~] [10.3.4] Empty IN after pruning -> CSR skipped (no forward) — Exclusive test forwards only the claimed attr and keeps others local, but no test verifies that a CSR whose pruned IN becomes empty receives NO forwarded request (e.g. via ftClientDump showing zero calls).
  • [ ] [10.3.5] Merge appends a new Relationship attribute — No batch-merge test appends a new Relationship; all fragments use Property only.
  • [ ] [10.3.5] Merge updates an existing Relationship object — No batch-merge test updates an existing Relationship object value.
  • [ ] [10.3.5] Delete a specific datasetId attribute instance via NGSI-LD Null — No batch-merge test exercises datasetId-targeted null deletion of one instance.
  • [ ] [10.3.5] Merge a specific datasetId instance (overwrite allowed, non-null) — No batch-merge test merges a fragment carrying a datasetId matching an existing instance.
  • [ ] [10.3.5] Append a new datasetId instance not present in target — No batch-merge test appends a fragment instance with an unmatched datasetId.
  • [~] [10.3.5] Simplified representation flag preserves pre-existing attribute type — Batch merge uses a simplified bare RHS only for the null-delete case (size); no batch-merge test supplies a simplified keyValues value for an existing Property and asserts the pre-existing type is preserved.
  • [ ] [10.3.5] Common observedAt timestamp applied to merged attributes — No batch-merge test uses the observedAt request parameter.
  • [ ] [10.3.5] Common language tag merges string into existing languageMap — No batch-merge test uses the lang parameter with a LanguageProperty string fragment over an existing languageMap.
  • [ ] [10.3.5] Merge adds new Entity type names from fragment type — No batch-merge test supplies an additional type in the fragment and asserts it is added to the target type list.
  • [ ] [10.3.5] Merge of scope (overwrite allowed) replaces scope — No batch-merge test merges scope with overwrite-allowed.
  • [~] [10.3.5] Total failure: no entities merged → 207 with S empty, E populated — Total local-only failure collapses to a plain 404 (uniform-error collapse, step 09) rather than a 207 with empty S + E array. The empty-S+E-array shape is only seen for the ld+json missing-@context case; no batch-merge total-failure test asserts a 207 body with success:[] and a multi-entity E array.
  • [ ] [10.3.5] Whole-request error: payload is not valid JSON → InvalidRequest (400) — No batch-merge test posts a body that is not valid JSON to assert InvalidRequest/400 (the empty-array and non-array cases are valid JSON → BadRequestData).
  • [~] [10.3.5] Per-entity error: syntactically incorrect entity content → BadRequestData (400) in E — Only the missing-@context flavour of per-entity BadRequestData is asserted in E for merge; no batch-merge test puts a structurally invalid entity (e.g. malformed attribute) and asserts a per-entity BadRequestData in E[].
  • [~] [10.3.5] @context via application/ld+json (inline @context) used for expansion — ld+json with inline @context is exercised for merge only in the missing-@context error path; no batch-merge test uses an inline @context to expand a custom short-name attribute and assert correct merge into the expanded IRI.
  • [ ] [10.3.5] @context via Link header with application/json used for expansion — No batch-merge test supplies a Link-header @context with application/json and asserts term expansion of fragment attributes.
  • [~] [10.3.5] Distributed: CSR filtering — non-matching entities and attributes pruned from IN — Exclusive test proves attribute chopping (speed removed from local IN, rest kept), but no batch-merge test proves entity-level pruning (an entity with no matching attrs left being dropped from a CSR's IN / empty-IN CSR skipped).
  • [~] [10.3.5] Forwarded operations carry the appropriate @context and tenant — Forwards are proven to apply correctly under the core context, but no batch-merge distop test asserts tenant propagation or a non-core @context being carried on the forwarded merge request.
  • [~] [10.3.6] Duplicate entity ID: first occurrence deleted, subsequent occurrences ResourceNotFound — DELETE [V1,V1] only asserts the 207 status line via head -1; the S/E body (first ID in success, second occurrence as ResourceNotFound BatchEntityError) is not asserted
  • [~] [10.3.6] Per-CSR input IN is filtered by entity/attribute matching before forwarding — Exclusive/inclusive tests show covered IDs forwarded and uncovered IDs handled locally (entity-level matching), but no test asserts attribute-level pruning of IN before forwarding
  • [ ] [10.3.6] Attributes covered by another exclusive CSR are removed from IN — No test exercises attribute removal from IN when another exclusive CSR covers those attributes during batch delete
  • [ ] [10.3.6] Attributes covered by a redirect CSR are removed from IN unless CSR is itself redirect — No redirect-mode CSR batch-delete test exists; attribute removal-unless-self-redirect rule is untested
  • [ ] [10.3.6] Entities left without attributes are dropped from IN; empty IN skips the CSR — No test verifies that after attribute pruning an attribute-empty entity is dropped and an empty IN skips the CSR
  • [~] [10.3.6] S and E merge results from multiple CSRs plus local processing — Conflict test merges one CSR's E with local S, but no test merges S/E across MULTIPLE (2+) CSRs plus local processing

common-behaviour (7)

  • [~] [8.4] Partial update: matching member value is fully replaced — Replacement of a scalar value via attr-level PATCH is asserted, but no entity-level partial-update test replaces a deep/structured (multi-key object) value wholesale and verifies leftover nested keys are NOT carried over (the replace-not-merge distinction vs 8.4-18 is not isolated).
  • [~] [8.4] Partial update: absent datasetId targets the default instance (replace or add) — Absent-datasetId replacing the default instance is implicitly covered on single-instance attrs, but the multi-instance case (only datasetId instances exist, no-datasetId fragment ADDS a default instance) via /attrs partial update is not asserted.
  • [ ] [8.4] Partial update: datasetId itself cannot be deleted via urn:ngsi-ld:null — No test sets a datasetId member's value to urn:ngsi-ld:null in a partial-update fragment and asserts the datasetId is retained (not removed).
  • [~] [8.4] Merge patch: matching member value is merged (not replaced) — patch_entity.test merges sub-attributes (adds brand.country while keeping value) which shows attribute-level merge depth, but no test merges a structured/object Property VALUE supplying only some keys and asserts the unsupplied keys survive (the merge-vs-replace distinction at the value-object level, contrast with 8.4-07).
  • [~] [8.4] Merge patch: absent datasetId targets default instance (merge or add) — Absent-datasetId merging the existing default instance is covered (step 04, {speed:{value:150}} hits default). The add-a-default case (only datasetId instances exist, no-datasetId fragment adds the default) is not asserted.
  • [ ] [8.4] Merge patch: datasetId itself cannot be deleted via urn:ngsi-ld:null — No merge-PATCH test sets a datasetId to urn:ngsi-ld:null and asserts the datasetId is retained on the instance.
  • [~] [8.4] Three distinct alteration mechanisms behave per their level/depth definition — Each mechanism is tested in isolation, but no single comparison test applies the SAME fragment via (a) attribute-level partial update, (b) entity-level partial update, and (c) merge to the same starting entity to demonstrate the three documented divergent outcomes (preserve vs drop vs deep-merge) side by side. The 8.4-02 sub-attr-drop gap weakens this further.

consume (39)

  • [ ] [10.4.2] Projection attrs indicate linked-entity retrieval but not enabled -> BadRequestData — No test for projection-attribute syntax that implies linked-entity retrieval while join is not enabled returning 400. url_param_join.test only validates the join/joinLevel parameter values themselves.
  • [ ] [10.4.2] Projected attribute depth exceeds linked-entity depth -> BadRequestData — No test where a projected (dotted) attribute depth exceeds joinLevel and triggers 400.
  • [ ] [10.4.2] Type selector matches -> entity returned — No test issues GET /entities/{id}?type= to confirm the entity is returned when the type selector matches.
  • [~] [10.4.2] Accept application/geo+json returns GeoJSON Feature — GeoJSON Feature rendering is well asserted, but the 'containing only requested attributes if attrs present' clause is not tested for single-entity GET (no geo+json + attrs= combination).
  • [ ] [10.4.2] GeoJSON with Prefer body=json moves @context to Link header — No test sends Accept: application/geo+json with Prefer: body=json to assert @context removed from the Feature body and emitted as a Link header.
  • [~] [10.4.2] Prefer ngsi-ld= amends body and returns Preference-Applied — Preference-Applied echo is tested only on /info/sourceIdentity; not on a single-entity GET, and the actual body amendment to the requested spec version is not asserted.
  • [ ] [10.4.2] Inline linked-entity retrieval adds entityList for ListRelationship (ordered) — No single-entity GET join=inline test exercises a ListRelationship to assert an ordered entityList sub-property of linked entities.
  • [ ] [10.4.2] Flattened retrieval appends ordered ListRelationship targets — No single-entity GET join=flat test uses a ListRelationship to assert ordered appending of objectList targets to the array.
  • [ ] [10.4.2] Flattened + geo+json yields a GeoJSON FeatureCollection — No test combines join=flat with Accept: application/geo+json on a single-entity GET to assert a GeoJSON FeatureCollection output. (geojson_response.test's FeatureCollection is the GET /entities collection endpoint, not flattened linked-retrieve.)
  • [ ] [10.4.2] pick/omit apply to all entities in linked-entity retrieval payload — No test combines join=inline/flat with pick or omit to assert the member projection is applied to every entity in the linked-retrieval payload (target + linked).
  • [~] [10.4.3] GeoQuery: multiple GeoProperty instances — any-instance match — Tests an entity with multiple distinct GeoProperties and per-geoproperty selection, but not multiple instances (datasetId-differentiated) of the SAME GeoProperty name where any-one-instance-match suffices.
  • [ ] [10.4.3] Context source filter (csf) — csf is only tested on GET /csourceRegistrations (csource-reg-discovery-filters.test); no test exercises csf on the entities query path being propagated to discovery during a distributed query.
  • [~] [10.4.3] Accept application/ld+json → JSON-LD array with @context — ld+json is sent via Link/Accept on the entities array query, but no test explicitly asserts the returned array members carry an @context member (the asserted lines filter to id/pick output, not the @context).
  • [ ] [10.4.3] GeoJSON Prefer body=json moves @context to Link header — No test sets Prefer: return=representation; body=json on a geo+json query to verify @context is removed from the FeatureCollection and emitted as a Link header.
  • [ ] [10.4.3] Linked Entity retrieval (inline) adds entityList for ListRelationship — All linked-entity tests use single-object Relationship; none exercises a ListRelationship gaining an ordered entityList sub-property on inline retrieval.
  • [~] [10.4.3] Prefer ngsi-ld= → version-conformant body + Preference-Applied header — Preference-Applied header is asserted only on /info/sourceIdentity; no test sends Prefer: ngsi-ld= on a queryEntities call to verify the array body is amended to the requested version and the header echoed.
  • [~] [10.4.3] Distributed query: discarded remote entities with past expiresAt — Expired-instance discard during the merge is asserted on the single-entity retrieve path (distop_attr_conflict_merge), not specifically on the multi-entity query/EntityArray merge path.
  • [ ] [10.4.3] Error: attribute list contains only system attributes — No test asserts that an attrs/pick list containing only system attributes (e.g. createdAt) fails the minimum-restriction rule → 400.
  • [ ] [10.4.3] Error: q contains only system attributes — No test asserts that a q referencing only system attributes (e.g. q=createdAt>...) without another restriction is rejected 400 as too-wide.
  • [~] [10.4.3] Error: invalid Entity id URI in id list — post_query_errors step 21 covers a non-URI id in the POST body; the GET ?id= path with an invalid URI in the id list is not asserted to 400.
  • [~] [10.4.3] Error: syntactically invalid q — post_query_errors step 16 (q=='A==') and query_q_notexists step 05 (!P==5) cover some invalid q; broader syntactically-invalid q on the GET path (e.g. q=A==) is not directly asserted.
  • [ ] [10.4.3] Error: syntactically invalid context source filter — No test asserts a syntactically invalid csf on the entities query path → 400.
  • [ ] [10.4.3] Error: projection uses Linked Entity but linked retrieval not specified — No test asserts 400 when projection attributes indicate linked-entity retrieval without a join/linked-retrieval parameter.
  • [ ] [10.4.3] Error: geometryProperty present but Accept not geo+json — No test asserts 400 when geometryProperty is supplied with Accept other than application/geo+json.
  • [ ] [10.4.3] Error: ordering parameter present but not local scope — No coraine entities-query test asserts 400 when orderBy is used without local scope (the only orderBy-restriction test is on temporal/entities and accepts it).
  • [~] [10.4.3] Error: unresolvable / invalid @context — Unresolvable @context handling exists in context tests but no test asserts 400/LdContextNotAvailable specifically on a queryEntities request with a bad @context Link.
  • [ ] [10.4.4] Retrieve value of a JsonProperty attribute — No GET attrs/{attr}/value test for a JsonProperty; should assert the bare json member is returned.
  • [ ] [10.4.4] Retrieve value of a LanguageProperty attribute (no language filter) — No GET value test for a LanguageProperty returning the bare languageMap.
  • [ ] [10.4.4] Retrieve value of a VocabProperty attribute — No GET value test for a VocabProperty returning the bare vocab value.
  • [ ] [10.4.4] Retrieve value of a ListProperty attribute — No GET value test for a ListProperty returning the bare valueList.
  • [ ] [10.4.4] Retrieve value of a ListRelationship attribute — No GET value test for a ListRelationship returning the bare ordered objectList.
  • [~] [10.4.4] Output is bare value fragment per clause 5.4.2 (no sub-attributes/metadata) — temperature has unitCode and GET value returns bare 21/45 (case 02/04) implying metadata excluded, but no test attaches observedAt/extra sub-attrs and asserts they are stripped from the value-only fragment.
  • [ ] [10.4.4] type selector parameter narrows entity match — No GET attrs/{attr}/value?type=... test; handler does not appear to apply a type selector, so a mismatching type yielding 404 is untested.
  • [ ] [10.4.4] datasetId=@none selects the default instance — No GET value?datasetId=@none test; storage keys default as '@none' so it may work, but it is unverified.
  • [~] [10.4.4] Attribute name term-to-URI expansion via @context — Attr names (temperature/location/refDevice) are core/default-context terms expanded implicitly; no test exercises a custom @context (Link header) term expansion on the value path specifically.
  • [ ] [10.4.4] @context via Link header applied for expansion/compaction — No GET attrs/{attr}/value test supplying a Link-header @context to expand the attr name; value body has no @context so compaction is moot, but expansion via Link is untested.
  • [ ] [10.4.4] Accept application/ld+json returns JSON-LD value fragment with @context — Handler always returns application/json with no @context regardless of Accept; spec says ld+json should embed @context — divergence is untested/unimplemented.
  • [ ] [10.4.4] Language filter on LanguageProperty converts to Property with matching value — No GET attrs/{attr}/value?lang=... test; handler does not apply a lang filter (only full-entity GET does via retrieve_entity_lang.test).
  • [ ] [10.4.4] Distributed retrieval: forward to exclusive/redirect/inclusive registrations and merge — getEntityAttrValue is documented local-only; no distributed GET value test exists and forwarding is unimplemented.

context (19)

  • [~] [13.2] Generated identifier is a locally unique URI — Location is asserted to match urn:ngsi-ld:Context:.* (URI form), but uniqueness across two successive Add calls (two distinct localIds) is never asserted in a single test; the array test even POSTs a second hosted (empty array) without comparing ids.
  • [~] [13.2] Stored @context is retrievable via the returned Location — Round-trip GET of the served body is asserted only for the array @context (post_array step 04) and for DB-seeded Hosted objects (lazy_reload). No test POSTs an object @context via the API and then GETs the exact same content back through the returned Location; crud step 01 captures Location but never GETs the body.
  • [ ] [13.2] Only the @context subtree is kept; extra top-level fields discarded — No test POSTs a body with @context plus extra sibling top-level fields and verifies the extras are dropped (and not erroring) from the stored/served content.
  • [ ] [13.2] @context value as a single string URL — No POST to /jsonldContexts with @context as a single URL string (e.g. {"@context":"https://..."}). The Cached path uses a {"url":...} body, which is the broker's separate Cached shape, not the spec's single-string @context Hosted form.
  • [ ] [13.2] @context containing JSON-LD keywords (@vocab, @base, prefixes) — No Add @context test uses a body whose @context object contains JSON-LD keywords (@vocab, @base, prefix mappings, term objects with @id/@type) to confirm such a valid local context is accepted (201) and stored.
  • [~] [13.2] Valid JSON but @context not syntactically correct -> 400 BadRequestData — crud step 13 covers @context as a plain string ('not-an-object') -> 400 BadRequestData (title 'Invalid Context'). Other malformed local-context shapes (e.g. @context object with a term mapped to an invalid value) are not exercised.
  • [~] [13.2] Missing top-level @context member -> 400 BadRequestData — crud step 12 POSTs {} (no @context, no url) -> 400, but the broker returns InvalidRequest ('payload must contain either @context or url'), not BadRequestData; a body with other members but no @context is not separately tested. Behaviour deviates from the feature's expected BadRequestData.
  • [~] [13.2] @context with invalid value type (e.g. number/boolean) -> 400 BadRequestData — crud step 13 covers @context as a string. No test for @context being a number, boolean, or null, nor an array containing a non-string/non-object element.
  • [ ] [13.2] Unsupported Content-Type -> 415 Unsupported Media Type — 415 is tested only for POST /entities with text/plain; no test POSTs to /jsonldContexts with an unsupported Content-Type to assert 415 on that resource.
  • [~] [13.2] Unsupported HTTP verb on jsonldContexts/ -> 405 Method Not Allowed — OPTIONS confirms the Allow set (GET,POST,HEAD,OPTIONS) on /jsonldContexts, but no test actually issues an unsupported verb (PUT/PATCH/DELETE) on the /jsonldContexts collection to assert a 405 with the Allow header; the 405 test only exercises /entities.
  • [~] [13.3] kind filter combined with details=true — No test issues a LIST with both query params together (?kind=X&details=true); kind-filtered lists use the plain URL form and details=true lists use no kind filter. reload.test uses details=true only on a single-context GET. Add a list GET with ?kind=Cached&details=true asserting every object has kind Cached.
  • [ ] [13.4] details=false serves full content — No test issues GET /jsonldContexts/{id}?details=false against a Hosted/ImplicitlyGenerated context to confirm explicit details=false serves the full content (only the absent-details default is exercised).
  • [ ] [13.5] Deleting an array-entry @context does NOT delete the children @contexts — jsonld_contexts_post_array.test creates an array wrapper whose children are downloaded as Cached, but never DELETEs the array wrapper to assert the member/child @contexts remain present and resolvable afterward.
  • [~] [13.5] Reload=true on Cached @context: successful re-download replaces stored content → 204 — reload=true returns 204 and the entry survives, but the test acknowledges the re-downloaded body is invisible (Cached only exposes ?details metadata, GET body is 422), so the actual content REPLACEMENT (v1→v2) is asserted on metadata survival only, not on the refreshed served body.
  • [~] [13.5] Reload boolean parameter parsing: reload=false behaves as plain delete — reload=false is exercised only against the Core @context (step 18 → 400 immutable). No case asserts reload=false on a normal Cached entry deletes it with 204 and triggers no download.
  • [ ] [13.5] Missing @context identifier → 400 BadRequestData — No test issues DELETE /jsonldContexts/ with empty/absent contextId to assert 400 BadRequestData.
  • [ ] [13.5] ProblemDetails detail field populated on reload failure — No reload-failure response is captured, so the ProblemDetails 'detail' field on a failed DELETE ?reload=true is unasserted.
  • [ ] [13.5] Idempotency / double-delete: second delete of same identifier → 404 ResourceNotFound — Tests delete an entry then LIST/GET, but never re-issue DELETE on the same just-deleted identifier to assert the second DELETE returns 404 ResourceNotFound.
  • [~] [13.5] ProblemDetails title/type correctness across all error variants — Title/type verified for reload-on-non-Cached (400 BadRequestData) and unknown-id (404 ResourceNotFound), but NOT for missing-identifier (400) nor the re-download failure (504 / LdContextNotAvailable), since those error paths have no test.

counting (7)

  • [ ] [7.5] count=false explicitly suppresses the header — No test issues count=false; only default (absent param) and count=true are exercised.
  • [ ] [7.5] Count is independent of pagination: count constant across offset pages — No test repeats a count=true query across offset=0/offset=N to assert the count value stays constant.
  • [~] [7.5] Count reflects type filter — All count=true queries include type=T and the count equals the type-T population, but no test contrasts two types in the same store to prove the count is scoped to the selected type rather than total store size.
  • [ ] [7.5] Count reflects attribute (attrs) and id/idPattern selection filters — No test combines count=true with attrs, id, or idPattern selectors to verify the count tracks those selection filters.
  • [ ] [7.5] Count reflects geo-query filter — No test combines count=true with georel/geometry/coordinates to verify NGSILD-Results-Count matches the geo-filtered result set.
  • [~] [7.5] Count works with offset beyond the result set — Test 13 (offset=10) returns empty [] but does NOT include count=true, so it does not assert that the count header still reports the full total on an out-of-range offset page.
  • [~] [7.5] Counting supported on all NGSI-LD Query operations (entities, temporal, types/attributes listings) — count=true asserted on GET /entities and on registration discovery, but NOT on Query Temporal Entities (GET /temporal/entities) nor on entity type / attribute listing operations.

discovery (55)

  • [ ] [10.6.3] typeList omits types with no existing instances — No test creates instances of a type, deletes them all, then re-GETs /types to confirm the now-instance-less type disappears from typeList.
  • [ ] [10.6.3] Multi-typed entity contributes each of its types — No test creates an entity with a type array (e.g. type:[A,B]) and verifies both A and B appear in typeList.
  • [ ] [10.6.3] Empty system returns EntityTypeList with empty typeList — No test does GET /types against a freshly-dropped/empty DB (no local entities, no CSRs) asserting 200 with typeList:[].
  • [ ] [10.6.3] Tenant scoping: NGSILD-Tenant restricts listed types — No test seeds entities of distinct types in different tenants and verifies GET /types with NGSILD-Tenant lists only that tenant's types.
  • [~] [10.6.3] Response is valid JSON-LD with @context present when requested — application/json case (Link header carries @context) is well covered, but no GET /types with Accept: application/ld+json asserting the @context is embedded in the body and no Link header.
  • [ ] [10.6.3] 400 BadRequestData on invalid request parameter / content — No GET /types test with a malformed parameter (e.g. details=garbage) asserting 400 BadRequestData ProblemDetails.
  • [ ] [10.6.3] 400 InvalidRequest on syntactically invalid input (e.g. bad Link/@context) — No GET /types test with an unresolvable/malformed Link-header @context asserting 400 InvalidRequest.
  • [ ] [10.6.3] 406 Not Acceptable on unsupported Accept media type — http_415_406_media_type.test covers 406 on /entities only; no GET /types with Accept: application/xml (or text/plain) asserting 406.
  • [ ] [10.6.4] Empty system returns empty array (200) — No test does GET /types?details=true against an empty datastore asserting 200 with an empty JSON-LD array [] (not 404). discovery_local seeds entities first.
  • [ ] [10.6.4] Malformed/invalid request returns 400 InvalidRequest — No test sends GET /types with an unparseable Link/@context header and asserts 400 InvalidRequest.
  • [ ] [10.6.4] Unavailable referenced @context returns 503/504 LdContextNotAvailable — No test references an unreachable @context URL in the Link header on GET /types and asserts LdContextNotAvailable (504). Existing LdContextNotAvailable tests are on /jsonldContexts and subscriptions only.
  • [ ] [10.6.4] Nonexistent tenant returns 404 NonexistentTenant — No test sends GET /types with an NGSILD-Tenant for a nonexistent tenant asserting 404 NonexistentTenant. tenant.test only covers this on /entities.
  • [ ] [10.6.4] Tenant-scoped result reflects only that tenant's instances — No test seeds entities under a tenant and asserts GET /types?details=true (or /types) returns only that tenant's types, isolated from the default tenant.
  • [ ] [10.6.4] Unsupported HTTP verb on /types returns 405 Method Not Allowed — No test issues POST/PUT/DELETE on /types asserting 405 with an Allow header listing GET/HEAD.
  • [ ] [10.6.4] Not Acceptable Accept header returns 406 — No test sends GET /types with Accept: text/plain asserting 406. http_415_406_media_type.test covers 406 only on /entities.
  • [~] [10.6.4] Distributed: results merged from Context Sources supporting the operation — Distributed merge is asserted for GET /types (EntityTypeList) and GET /types/{type}, but not for GET /types?details=true (the EntityType[] detailed-array form) showing per-type attributeNames unioned across local + forwarded sources.
  • [ ] [10.6.5] HEAD /types/{type} supported — head_request.test only HEADs /entities; no HEAD /types/{type} asserting same status/headers as GET with empty body.
  • [ ] [10.6.5] attributeTypes lists multiple types for the same attr name — No test seeds two instances of one type using the same attribute name with different attribute kinds and asserts attributeTypes is the union (e.g. ["Property","Relationship"]).
  • [ ] [10.6.5] attributeTypes covers LanguageProperty / JsonProperty / VocabProperty / ListProperty — No GET /types/{type} test asserts attributeTypes for LanguageProperty, JsonProperty, VocabularyProperty, ListProperty or ListRelationship.
  • [ ] [10.6.5] type given as Fully Qualified Name — No test calls GET /types/{expanded-URI} (URL-encoded FQN) and resolves it without @context expansion.
  • [ ] [10.6.5] Tenant scoping via NGSILD-Tenant header — tenant.test only scopes /entities; no GET /types/{type} with NGSILD-Tenant asserting type info reflects only that tenant's instances.
  • [~] [10.6.5] Only types with existing instances are described — A type with truly zero instances anywhere returns 404 (NoSuch). But CSR-declared-only types with zero instances return 200 entityCount=0 (introspection_csr_empty_arrays/discovery_modes), so the strict 'zero instances => not known => 404' rule is only partially exercised and behaviour is registration-dependent.
  • [ ] [10.6.5] 400 Bad Request for an incorrect request/content — No test sends a malformed /types/{type} request (e.g. bad parameter) and asserts 400 BadRequestData.
  • [ ] [10.6.5] 400 InvalidRequest for invalid Link header / @context — No test on /types/{type} supplies an unparsable Link-header @context and asserts 400 InvalidRequest.
  • [ ] [10.6.5] 504 LdContextNotAvailable when @context cannot be fetched — No test on /types/{type} references an unreachable @context URL and asserts 504 LdContextNotAvailable.
  • [ ] [10.6.5] 404 NonexistentTenant for an unknown tenant — NonexistentTenant only covered via /entities (tenant.test); not asserted for GET /types/{type} with an unknown NGSILD-Tenant.
  • [ ] [10.6.5] 406 Not Acceptable for unsupported Accept media type — http_415_406_media_type.test does not target /types/{type}; no 406 assertion for an unsupported Accept on this resource.
  • [ ] [10.6.5] 405 Method Not Allowed for unsupported verb on the resource — http_405_method_not_allowed.test only covers /entities; no POST/PUT/PATCH/DELETE on /types/{type} asserting 405 + Allow: GET, HEAD.
  • [~] [10.6.5] Response content negotiation: application/json with Link vs application/ld+json — application/json-with-Link-header path fully asserted; the application/ld+json variant (Accept: application/ld+json embedding @context in the body) is never requested against /types/{type}.
  • [~] [10.6.6] Attributes derived from registration with attribute-level granularity — Registration-only attribute (propertyNames in CSR, no local entity, no live source) appearing in the NAMES-ONLY attributeList is not asserted; introspection_csr_empty_arrays proves it via /attributes?details=true (10.6.7 form) and discovery_modes proves it only via /attributes/{id}?noForward, not the bare GET /attributes list.
  • [ ] [10.6.6] Tenant scoping via NGSILD-Tenant — No test issues GET /attributes with NGSILD-Tenant to verify per-tenant isolation of the attribute list; tenant.test does not touch /attributes.
  • [ ] [10.6.6] Non-existent tenant -> 404 NonexistentTenant — No GET /attributes with an unknown NGSILD-Tenant asserting 404 + ProblemDetails title 'Non-existent tenant' (NonexistentTenant).
  • [ ] [10.6.6] Invalid query parameter value -> 400 BadRequestData — No GET /attributes with an invalid query-param value (e.g. local=notabool or details=notabool) asserting 400 BadRequestData.
  • [ ] [10.6.6] Unsupported HTTP method on /attributes -> 405 — 405+Allow is tested for /entities only; no POST/PUT/DELETE/PATCH against /ngsi-ld/v1/attributes asserting 405 with Allow: GET.
  • [ ] [10.6.6] System-generated attributes excluded from the list — No test seeds an entity (which always has createdAt/modifiedAt) and asserts those system attrs are absent from attributeList; seeded entities have observedAt in local_param_distops_suppress but no assertion that observedAt/createdAt/modifiedAt are excluded from the names list.
  • [~] [10.6.7] attributeName falls back to FQN/long name when not in @context — For non-core attrs with no defining @context, details=true falls back to core short names (speed/color/brand) which happen to be core-context terms; there is no details=true case where attributeName actually renders as a full IRI because the term is absent from the active context. Add an entity with a truly custom attr IRI queried under core context and assert attributeName is the full URI.
  • [~] [10.6.7] Only attributes that actually exist on instances are returned — discovery_local only lists attrs that were instantiated, but there is no negative assertion that an attribute defined in @context yet never instantiated is excluded from details=true. Add a context term never used on any entity and assert it is absent.
  • [~] [10.6.7] No @context supplied → core context short names / FQN fallback — discovery_local uses no @context and gets core short names + default-context IRIs in id, but a non-core attribute name appearing as a full URI under core context (the true FQN fallback) is not asserted for details=true. See 10.6.7-07.
  • [ ] [10.6.7] Accept application/ld+json returns body with embedded @context — Every discovery details=true test uses application/json (Link header context). None send Accept: application/ld+json to assert the @context is embedded in the Attribute[] body.
  • [ ] [10.6.7] Invalid or unresolvable @context (Link header) → 400 Bad Request — No discovery test supplies a malformed/unretrievable @context Link to GET /attributes?details=true asserting 400.
  • [ ] [10.6.7] ProblemDetails error body carries detail and is pure JSON — Tied to 10.6.7-22/23/24 which are uncovered; no error-body assertion exists for the /attributes?details path.
  • [ ] [10.6.7] Tenant scoping via NGSILD-Tenant header — No test issues GET /attributes?details=true with an NGSILD-Tenant header to assert tenant-scoped (or empty for unknown tenant) results.
  • [~] [10.6.8] Response member: attributeName is the short name when present in @context — attributeName short-name is asserted, but only with the core/default context (no user @context supplied); the 'short name if contained in @context' branch driven by a user @context is untested.
  • [~] [10.6.8] Response member: attributeTypes lists the attribute types for which instances exist — attributeTypes is asserted but only ever with the single value ["Property"]; no test exercises non-Property type values.
  • [ ] [10.6.8] attributeTypes lists multiple types when the same attribute name has differing types — No test creates the same attribute name as Property in one entity and Relationship (or GeoProperty) in another and asserts attributeTypes contains both.
  • [~] [10.6.8] typeNames aggregates all entity types carrying the attribute — Each covered case has the attribute on a single entity type only (typeNames is always one element); no test has the same attribute name across two different entity types and asserts typeNames lists both.
  • [~] [10.6.8] attributeCount aggregates across all entities/types carrying the attribute — discovery_local asserts attributeCount=2 for speed across two Vehicle entities (same type); no test aggregates the count across entities of different types.
  • [ ] [10.6.8] attrId may be supplied as the Fully Qualified Name (FQN) — No test issues GET /attributes/{FQN} (e.g. the expanded https://uri.etsi.org/ngsi-ld/default-context/speed URI) and asserts 200; only short names are used.
  • [~] [10.6.8] attrId may be supplied as the short name and is expanded via @context — Short-name attrId is exercised, but expansion is only via the implicit core/default context; no test supplies a user @context that maps a short name to a non-default FQN and asserts resolution.
  • [ ] [10.6.8] @context provided via Link header controls short-name expansion of attrId and attributeName — No GET /attributes/{attrId} test supplies a Link-header @context (analogous to get_type_link_header_context.test for /types) to drive attrId expansion and attributeName short-name rendering.
  • [~] [10.6.8] Without a user @context, the core context is used and attributeName falls back to FQN if no short name — Core-context path is exercised, but every attribute used is in the default context so attributeName always resolves to a short name; the FQN-fallback branch (attribute with no short name in context) is untested.
  • [ ] [10.6.8] Response @context present for application/ld+json — All covered requests respond as application/json with @context in a Link header; no GET /attributes/{attrId} requests application/ld+json and asserts an inline @context member in the body.
  • [ ] [10.6.8] 400 Bad Request / BadRequestData for an invalid request or content — No test sends a malformed attrId or bad @context content to /attributes/{attrId} expecting 400 BadRequestData.
  • [ ] [10.6.8] 405 Method Not Allowed for unsupported verbs on the resource — No test issues POST/PUT/PATCH/DELETE on /attributes/{attrId} expecting 405 with an Allow header.
  • [ ] [10.6.8] Tenant scoping via NGSILD-Tenant header — No test scopes GET /attributes/{attrId} with NGSILD-Tenant and asserts tenant-isolated attribute info.

distops (52)

  • [~] [9.3] Redirect: register Entities by Entity type only — Type-only redirect CSR is accepted (201) but no test seeds entities at a CP and asserts a type-only redirect actually MATCHES and FORWARDS a retrieve/query to those proxied entities.
  • [ ] [9.3] Redirect: register Entities by type with specific attributes — No test creates a redirect CSR with both an entity type AND propertyNames/relationshipNames and asserts only those attrs for that type are proxied/forwarded.
  • [ ] [9.3] Redirect: register Attributes only (no entity id/type) — No redirect CSR registers attributes-only (information with propertyNames but no entities) and asserts those attrs are proxied across matching entities. Attrs-only info appears only in discovery/validation tests, not a redirect-forwarding test.
  • [ ] [9.3] Precedence: exclusive operations processed before all others — No test sets up an entity covered simultaneously by exclusive + redirect + inclusive + auxiliary + local sources and asserts the exclusive source's value/processing wins/precedes. The exclusive-vs-local case is covered, but the full ordering against redirect/inclusive/auxiliary on the same attr is not.
  • [ ] [9.3] Precedence: redirect ops occur after exclusive, then block further ops — No test layers a redirect CSR over the same attr as an inclusive/auxiliary/local source and asserts redirect blocks the subsequent local/inclusive/auxiliary handling for its matched attrs (redirect+exclusive overlap is rejected at creation, but redirect-vs-inclusive runtime precedence on the same attr is untested).
  • [~] [9.3] Precedence: auxiliary data added last, only after all others exhausted — The redirect-auxiliary test proves auxiliary fills a gap only when local+redirect have no value, but it does not include an inclusive/exclusive source in the same scenario, so 'last after ALL of local+exclusive+redirect+inclusive exhausted' ordering is only partially exercised (local + redirect tier).
  • [ ] [9.4] Subscription attribute spec = watchedAttributes alone when NotificationParams attributes empty/absent — No test registers a CSR with attributeNames and a subscription whose ONLY attribute identifiers come from watchedAttributes, then asserts the derived sub is/ isn't fanned out based on that set. distsub tests use type/id-only registrations; watchedAttributes only appears in PATCH-cascade plumbing, not in attribute-spec matching against a reg's attributeNames.
  • [ ] [9.4] Subscription attribute spec = union of watchedAttributes and NotificationParams attributes — No test exercises the union of watchedAttributes and notification.attributes being matched against a CSR attributeNames set to select/skip fanout. notification.attributes is never used as a matching input in any distsub test.
  • [~] [9.4] Registration matches if at least one RegistrationInfo in information[] matches — A single CSR with 3 RegistrationInfo entries is matched via DISCOVERY (?type/?pick) and the matching entry returned, proving the one-of-many match on the discovery path. No DISTRIBUTED-QUERY-forwarding test uses a multi-information[] CSR (one matching, one not) to assert the source is selected and forwarded — query/distsub forwarding tests all use single-information regs.
  • [~] [9.4] RegistrationInfo match requires BOTH entity condition AND attribute condition to hold — pick-disjoint→skip (distop_pick_narrowing #06) covers the attribute-condition-fails-while-entity-matches case for query forwarding, and discovery filtering pairs type+attr per info entry. No single query/forward test explicitly shows entity-type matches but attribute fails (or vice-versa) → registration NOT selected as one combined assertion in the distributed-forward path.
  • [~] [9.4] Identifier condition: both request idPattern and EntityInfo idPattern present always match — #03 shows a type-only parent sub against a reg idPattern yielding the reg's pattern in the derivative, but no test has BOTH a request-side idPattern AND a reg-side idPattern present simultaneously asserting the always-match (undecidable-overlap) rule.
  • [ ] [9.4] Attribute matching against relationshipNames — relationshipNames is exercised only in registration CRUD/merge rendering (csource-reg-attributenames.test); no distributed query/subscription test registers a CSR via relationshipNames and asserts a matching relationship attribute selects (and a non-matching one skips) the source.
  • [ ] [9.4] datasetId matching: both request and registration specify datasetId with a common value — datasetId on registrations is only validated at the top level (csource_reg_validation_datasetid.test). No test places datasetId inside RegistrationInfo and issues a datasetId-bearing request to assert common-value selection.
  • [ ] [9.4] datasetId mismatch: both specify datasetId with no common value = no match — No test exercises disjoint request/registration datasetId values excluding the registration from a distributed op.
  • [ ] [9.4] Matching algorithm is used when EntityMap is invalid or expired — No test supplies an expired/invalid EntityMap (e.g. ?entityMap= or one past expiresAt) and asserts the broker falls back to live registration matching. EntityMap expiresAt is only checked as a rendered field.
  • [ ] [9.5] urn:ngsi-ld:request placeholder when the value is absent from the triggering request — No test verifies that when contextSourceInfo value=urn:ngsi-ld:request but the named item is absent from the triggering request, the broker forwards NO such header (does not emit the literal sentinel). Add a GET without the named header and assert the forwarded request lacks it.
  • [ ] [9.5] Connection/interaction binding-specific info in contextSourceInfo is ignored — No test puts a connection/interaction-specific entry (e.g. Content-Length, Host) in contextSourceInfo and asserts it does not override the actual forwarded value.
  • [ ] [9.5] accept=application/json sets forwarded Accept and response handled as JSON — Only the validation of the accept value (bad value -> 400) is tested; no test positively asserts a CSR with accept=application/json causes the forwarded request to carry Accept: application/json (or that response is handled as JSON).
  • [ ] [9.5] accept=application/ld+json sets forwarded Accept and response handled as ld+json — No test asserts accept=application/ld+json produces a forwarded Accept: application/ld+json header on the outbound request.
  • [ ] [9.5] contentType=application/json forwards request+@context as JSON regardless of original — Only contentType validation (bad value -> 400) is tested. No test asserts that contextSourceInfo contentType=application/json forces forwarded Content-Type: application/json with @context via Link even when the original request used ld+json inline.
  • [ ] [9.5] contentType=application/ld+json forwards request+@context as ld+json regardless of original — No test asserts contentType=application/ld+json forces forwarded Content-Type: application/ld+json with inline @context regardless of how the original request supplied the context.
  • [~] [9.5] ngsildConformance value form major.minor — major.minor format validation (bad string -> 400) is asserted only for Subscriptions, not for a CSR contextSourceInfo ngsildConformance entry. No CSR/forwarding test exercises the ngsildConformance contextSourceInfo key.
  • [~] [9.5] Fallback: Entity expiresAt removed when downgrading below 1.9 — Entity-level expiresAt stripping for <1.9 is asserted on the subscription notification path; not on the distributed-forwarding (CSR ngsildConformance) path.
  • [~] [9.5] Fallback: Entity scope removed when downgrading below 1.4 — Scope stripping for <1.4 asserted on notification path (v1.0/v1.3 strip, v1.4 keeps); not on the forwarding path.
  • [ ] [9.5] Fallback: Entity type[] reduced to single value for 1.0 target (NOTE 1) — The subscription entity has a single type, so multi-type->first-type reduction for 1.0 is not actually asserted on any path. Needs a multi-type entity downgraded to 1.0.
  • [~] [9.5] Fallback: datasetId-separated attribute instances reduced to single for 1.0 (NOTE 2) — Multi-instance speed collapsed to a single dict for v1.0 is asserted on the notification path (shape=dict for v10 vs list for v13); not on the forwarding path, and 'preference to the default instance' is not explicitly verified by value.
  • [~] [9.5] Fallback: LanguageProperty reformatted as Property below 1.4 — name=Property for v1.0/v1.3, LanguageProperty for v1.4+ asserted on notification path; not on the forwarding path.
  • [~] [9.5] Fallback: JsonProperty reformatted as Property below 1.8 — config=Property for <1.8, JsonProperty for 1.8 asserted on notification path; not on the forwarding path.
  • [~] [9.5] Fallback: VocabProperty reformatted as Property below 1.8 — category=Property for <1.8, VocabProperty for 1.8 asserted on notification path; not on the forwarding path.
  • [~] [9.5] Fallback: ListProperty reformatted as Property below 1.8 — stops=Property for <1.8, ListProperty for 1.8 asserted on notification path; not on the forwarding path.
  • [~] [9.5] Fallback: ListRelationship reformatted as Relationship below 1.8 — drivers=Relationship for <1.8, ListRelationship for 1.8 asserted on notification path; not on the forwarding path.
  • [~] [9.5] Fallback: Property datasetId removed below 1.3 — datasetId present for 1.3+ and absent for 1.0 (collapse) asserted on notification path; the standalone 'remove datasetId below 1.3' for a single-instance Property and the forwarding path are not separately exercised.
  • [~] [9.5] Fallback: Property expiresAt removed below 1.9 — speed expiresAt stripped for all <1.9 targets asserted on notification path; not on the forwarding path.
  • [~] [9.5] Fallback: Property observedAt removed below 1.3 — observedAt present for 1.3+ and absent for 1.0 asserted on notification path; not on the forwarding path.
  • [ ] [9.5] Fallback: Property unitCode removed below 1.3 — The dump only checks datasetId/observedAt/valueType/expiresAt on speed, not unitCode, so unitCode stripping for <1.3 is not actually asserted on any path.
  • [~] [9.5] Fallback: Property valueType removed below 1.9 — valueType stripped for all <1.9 targets asserted on notification path; not on the forwarding path.
  • [ ] [9.5] Fallback: Relationship datasetId removed below 1.3 — No test exercises a Relationship instance carrying datasetId being stripped below 1.3 (the conformance entity has no Relationship with datasetId).
  • [ ] [9.5] Fallback: Relationship expiresAt removed below 1.9 — No test exercises Relationship expiresAt stripping below 1.9.
  • [ ] [9.5] Fallback: Relationship objectType removed below 1.8 — No test exercises Relationship objectType stripping below 1.8.
  • [ ] [9.5] Fallback: Relationship observedAt removed below 1.3 — No test exercises Relationship observedAt stripping below 1.3.
  • [ ] [9.6] q filter applied at page render over a Relationship — entitymap_paginate_with_filter only re-checks q over a Property (speed). No test re-checks a bound q targeting a Relationship object at page-render time with map removal. (q-over-Relationship is covered for plain queries but not for the entityMap re-filter path.)
  • [ ] [9.6] q filter applied at page render over a sub-attribute — No test exercises a bound q over a sub-attribute path (attr.sub / attr[member]) being re-checked during entityMap pagination and the candidate being dropped/removed.
  • [~] [9.6] scope query filter applied before adding Entity to a result page — scopeQ on a map is only tested as an introduced-parameter 400 (step 09); no test binds scopeQ at creation and re-applies it at page render to remove a non-matching candidate.
  • [ ] [9.6] attribute filter applied before adding Entity to a result page — attrs is used to shape the map at create time (entitymap_post_create step 04) but no test binds attrs and re-applies it during pagination to remove an entity whose attrs changed.
  • [~] [9.6] Non-matching identifiers are removed from the Entity Map at check time — Step 11 shows a drifted entity (V2 speed->5) excluded from the rendered page while count stays 2 — i.e. it is SKIPPED at render, not proven permanently removed from the map's id set on subsequent pages. Add a follow-up page assertion that the dropped id is gone (GET /entityMaps/{id} no longer lists it).
  • [ ] [9.6] Retrieve Entity can use an Entity Map to target only relevant Context Sources — csource-reg-distops-retrieve-exclusive.test forwards a single retrieve to one source but never primes/reuses an EntityMap. No test proves a second retrieveEntity reuses a map to skip non-listed sources.
  • [~] [9.6] Default behaviour: no Entity Map field returned when not requested — query_entities_distops step 14 asserts the header is PRESENT when entityMap=true (grep -c). No test asserts a plain distributed query WITHOUT the indicator returns NO NGSILD-EntityMap header (grep -c == 0).
  • [~] [9.6] Reuse: existing map used for registration matching in preference to the matching algorithm — The header comment states routing follows recorded sources not live reg-match, but the test never actually mutates/removes a registration between create and reuse to PROVE the captured (stale) reg set is used instead of fresh matching. Add a test that changes a CSR after map creation and asserts reuse still routes by the captured linkedMaps.
  • [ ] [9.6] Reuse: Entity identifier specification may differ from the original request — No test reuses an EntityMap while changing the id/idPattern spec (e.g. ?entityMap=&id=urn:V2) and asserts results are the map set intersected with the narrowed id list.
  • [ ] [9.6] Split entities: map initially stores candidate Entities (no filters applied yet) — No test creates an EntityMap in split-entities mode with a filter and asserts the map initially stores candidate ids (including ones that will later fail the filter once assembled).
  • [ ] [9.6] Split entities: filters re-checked during pagination, failing candidates removed from map — query_entities_distops_split re-filters assembled split entities for a PLAIN query, but no test does this through an EntityMap reuse (entityMap=) asserting a candidate fails the assembled-entity filter and is removed from the map.
  • [ ] [9.6] Multi-tenancy: each tenant in each registered source considered separately — No test builds/uses an EntityMap under a non-default NGSILD-Tenant nor asserts a map from one tenant is not reused across tenants.

entity-attr-CRUD (123)

  • [~] [10.2.2] createdAt/modifiedAt system-generated on create — sysattrs test only asserts createdAt/modifiedAt EXIST via REGEX(.*); no test asserts createdAt==modifiedAt at creation, nor that a client-supplied entity-level createdAt/modifiedAt is ignored on POST /entities (the timestamp-drop is only tested on POST /attrs in post_entity_attrs_entity_level_fields.test)
  • [~] [10.2.2] Create entity with multi-attribute (datasetId instances) — create_entity_multi_attr.test only asserts 201 on a default+datasetId multi-instance create; no GET round-trip verifying all instances (incl the default no-datasetId) are retained after create
  • [ ] [10.2.2] {"@none":"urn:ngsi-ld:null"} as languageMap RHS → 400 BadRequestData — No Create Entity test sends {"@none":"urn:ngsi-ld:null"} as a languageMap RHS expecting 400 (only the patch-delete sentinel form is exercised)
  • [ ] [10.2.2] urn:ngsi-ld:null as value inside Property value object → 400 BadRequestData — No Create Entity test embeds "urn:ngsi-ld:null" as a key/value inside a Property value object expecting 400
  • [~] [10.2.2] Exclusive reg supports create, endpoint error → complete failure error / partial success — Partial-success (207) on a failing redirect/exclusive forward is well covered; the single-error complete-failure flatten to a single ProblemDetails (e.g. one exclusive CSR fails and nothing else succeeds → ProblemDetails not 207) is not asserted for the exclusive-reg create path (the 409-named test actually returns 207 multi-status with two errors)
  • [~] [10.2.2] Redirect reg supports create, endpoint error → complete failure error / partial success — Partial success (207) on a failing redirect forward is covered (create-207 single failure, create-409 both fail → 207 listing both); a single-redirect-only complete failure flattening to one ProblemDetails (not 207) is not separately asserted
  • [ ] [10.2.2] Redirect reg does NOT support create → 409 Conflict (or partial success) — The does-not-support-create→Conflict case is tested only for an EXCLUSIVE reg (csource-reg-distops-create-excl-no-op.test); no test exercises a REDIRECT reg lacking createEntity in operations
  • [~] [10.2.2] Distributed create complete failure → single ProblemDetails error — The complete-failure scenario (all forwards fail, nothing succeeds) is tested but returns 207 multi-status (two distinct errors). The single-error / all-404 flatten to a single ProblemDetails body (per project_distop_write_flatten design) is not asserted for createEntity
  • [~] [10.2.3] Update existing default Relationship instance — No test PATCHes /attrs with a valid Relationship that already exists and asserts the object/metadata was replaced (204 + GET verify); rel_without_object only covers the error path. Add a happy-path Relationship replace via Update Attributes.
  • [ ] [10.2.3] createdAt preserved on default-instance replace — entity_attr_timestamps_on_update only PATCHes /attrs/{attr} (Partial Update). No test does PATCH /attrs (Update Attributes) on an existing attr and asserts createdAt unchanged + modifiedAt advanced via sysAttrs.
  • [~] [10.2.3] NGSI-LD Null on absent default instance appends — patch_entity_attrs case 04 deletes a missing default attr via Null and treats it as a 204 no-op (entity unchanged), but does not assert the spec's 'shall be appended' append-of-Null outcome; only the no-op interpretation is verified.
  • [ ] [10.2.3] type in fragment with already-present types is a no-op addition — patch_entity_attrs_entity_level_fields adds a NEW type (Car) only. No test supplies type listing only already-present types and asserts no duplication in the resulting type set.
  • [ ] [10.2.3] Invalid (non-URI) Entity ID -> BadRequestData — No PATCH /entities/{id}/attrs test supplies a non-URI id and asserts 400 BadRequestData. url_parse case 12 uses a url-as-id with an absent entity (404) and a routing focus, not invalid-URI validation.
  • [ ] [10.2.3] Invalid JSON payload -> InvalidRequest — No PATCH /entities/{id}/attrs test sends syntactically invalid JSON and asserts 400 InvalidRequest (the 8.2.3 invalid-JSON vs valid-JSON-bad-content distinction is untested on the Update Attributes route).
  • [ ] [10.2.3] type selector mismatch -> ResourceNotFound — No PATCH /entities/{id}/attrs?type= test asserting 404 ResourceNotFound.
  • [~] [10.2.3] Term expansion applied to attribute matching — Term expansion of attribute names under @context is exercised on the forwarding/single-attr paths, but no test does a local PATCH /entities/{id}/attrs with a DIFFERENT @context that expands a short name to an existing attribute's IRI and verifies the existing instance is updated (not appended as a duplicate).
  • [ ] [10.2.3] Distributed: redirect registration forwards matching attrs — No Update Attributes (PATCH /attrs) test uses a redirect-mode CSR and verifies matching attrs are forwarded and removed from the local fragment. Only exclusive (update) and inclusive (update) are covered.
  • [~] [10.2.3] Only some attributes updated -> 207 Multi-Status with updated list — 207 with notUpdated/updated lists is asserted only for the scope-cannot-be-added case. No test produces a 207 where a genuine attribute fails (e.g. one attr not updatable) while another succeeds, with the attribute names in updated vs notUpdated.
  • [ ] [10.2.3] Update GeoProperty/JsonProperty/LanguageProperty/VocabProperty/ListProperty instances — Sub-type updates exist only on /attrs/{attr} (Partial Attribute Update: langprop_patch_attribute, patch_entity_attr_vocab) or PATCH entity (Merge: patch_invalid_geoproperty_type). No Update Attributes (PATCH /attrs) test replaces existing Geo/Json/Language/Vocab/List instances with verified typed values.
  • [~] [10.2.3] Update sub-attributes (metadata) of an Attribute — concise_property_with_subrel PATCHes /attrs replacing an attr with a sub-Relationship, but the GET asserts 'unchanged' rather than a changed sub-attribute set; no test verifies sub-attrs (unitCode/observedAt/custom) are replaced per 8.4.2 via Update Attributes.
  • [ ] [10.2.3] Empty Entity Fragment / no attributes -> BadRequestData — No PATCH /entities/{id}/attrs test sends an empty/attribute-less fragment ({} or only entity-level fields) and asserts 400 BadRequestData.
  • [~] [10.2.4] Append new attribute to existing entity (Relationship) — attribute_validation_errors step 20 appends a Relationship but as an overwrite of an existing Property (type-change case); no test appends a genuinely-new Relationship attribute to an entity via POST /attrs and verifies it lands as a Relationship with its object
  • [ ] [10.2.4] createdAt preserved when datasetId instance overwritten — No POST /attrs test asserts createdAt is preserved on a datasetId-matched instance overwrite (no sysAttrs inspection on append at all)
  • [ ] [10.2.4] Overwrite denied leaves existing datasetId instance untouched — No POST /attrs?options=noOverwrite test with a fragment datasetId matching an existing instance, asserting that instance is left untouched
  • [~] [10.2.4] Existing entity type names unchanged when fragment type already present — The test only adds a brand-new type (Car) and sees [Vehicle,Car]; no append where the fragment type includes an already-present name (e.g. type=Vehicle) to assert it is not duplicated
  • [ ] [10.2.4] Scope appended (union) when overwrite not allowed — No POST /attrs?options=noOverwrite test supplies a scope and asserts new scopes are unioned with the entity's existing scope
  • [ ] [10.2.4] Type selector restricts target entity — No POST /attrs test uses an Entity type selector (?type=) to constrain the target entity for the append
  • [ ] [10.2.4] Entity exists but specified type does not match -> 404 ResourceNotFound — No POST /attrs test targets an existing entity with a non-matching ?type= selector and asserts 404 ResourceNotFound
  • [ ] [10.2.4] Exclusive reg without Append support, some succeeded -> partial success — No test asserts partial-success (multi-status) when an exclusive registration lacking Append support fails but some local parts succeed
  • [~] [10.2.4] Redirect registration: matched attributes removed from local fragment — The merge test forwards each attr to its redirect CSR and merges results, but does not separately assert the matched attribute was removed from the local fragment (no local entity to check residue against, unlike the exclusive test)
  • [~] [10.2.4] Redirect reg without Append support, some succeeded -> partial success — The merge test produces 207 partial-success when a forwarded redirect CSR returns 503/502/207, but the scenario is a forward-error, not specifically the 'Append operation not supported by the registration' branch
  • [~] [10.2.4] Forwarding order: exclusive/redirect remove before inclusive/local — The exclusive test shows exclusive-matched attrs forwarded and the rest applied locally, but there is no single append test combining exclusive/redirect AND inclusive to assert the documented removal-then-forward ordering
  • [ ] [10.2.5] Update GeoProperty value — GeoProperty geometry update via the fragment-based partial-update route (PATCH /attrs/{geo} with a value GeoJSON) is untested; entity_attr_value.test only covers the value-only sub-resource PUT /attrs/{attr}/value (a different operation). Add a PATCH /attrs/location with a new Point geometry and verify persistence.
  • [ ] [10.2.5] Whole-attribute deletion not supported by this operation — No test asserts that a top-level Null on the whole attribute via PATCH /attrs/{attr} does NOT delete the attribute (op supports only sub-attr deletion). Add a case verifying the attribute survives such an attempt.
  • [~] [10.2.5] observedAt update — observedAt is only ever updated together with value (value+observedAt in the same fragment) in the troe tests; no test PATCHes observedAt alone and asserts the new timestamp persists while value is untouched.
  • [~] [10.2.5] datasetId-targeted instance update — datasetId-targeted UPDATE is asserted via the plural PATCH /attrs route (patch_attrs_datasetid_instance_update.test); on the single-attr route entity_attr_crud only GETs/DELETEs a datasetId instance. Add a PATCH /attrs/{attr}?datasetId=... (or fragment datasetId) update of a specific instance leaving default + other datasets intact.
  • [ ] [10.2.5] Invalid or missing target Entity ID -> 400 BadRequestData — No test sends a syntactically invalid Entity ID (non-URI) on the partial-attr-update path expecting 400 BadRequestData; existing cases use a valid-but-nonexistent id (404). Add a malformed-id PATCH /attrs/{attr} -> 400.
  • [ ] [10.2.5] Invalid JSON payload -> 400 InvalidRequest — No test sends a syntactically malformed JSON body to PATCH /attrs/{attr} expecting 400 with title InvalidRequest (as opposed to BadRequestData for valid-JSON-bad-content). Add a broken-JSON partial-update case.
  • [ ] [10.2.5] Entity exists but lacks target attribute with given datasetId -> 404 ResourceNotFound — No test PATCHes /attrs/{attr} with a datasetId that does not match any stored instance and asserts 404 ResourceNotFound.
  • [~] [10.2.5] Redirect registration match -> forward, no local processing — Redirect-mode forwarding is verified end-to-end only for Merge Entity (csource-reg-distops-patch-misc.test) and for the local-conflict 409 on the partial-attr route; no test shows a redirect CSR forwarding an actual PATCH /attrs/{attr} to a real CP and verifying remote application. Add a redirect single-attr-update forward case.
  • [~] [10.2.5] Inclusive registration match -> also forward (op supported) — Inclusive local+forward is verified for Merge Entity (PATCH /entities/{id}), not for the Partial Attribute Update single-attr route (PATCH /attrs/{attr}). Add an inclusive-mode partial-attr-update case verifying both local apply and forward.
  • [ ] [10.2.5] Registration does not support partial-update, complete failure -> 409 Conflict — No test exercises a matching exclusive/redirect registration that does NOT support updateAttrs/the partial-update op, with complete failure yielding 409 Conflict. (entity_update_local_reg_conflict's 409 is the ?local-vs-exclusive overlap case, a different scenario.)
  • [ ] [10.2.5] Registration does not support partial-update, partial success -> 207 — No test produces a 207 MultiStatus partial-success result for a Partial Attribute Update where the op is unsupported on some endpoints.
  • [ ] [10.2.6] Type filter parameter (Entity types selector) accepted — No test issues PUT .../value?type=; the type selector accept-path on the value subresource is unexercised.
  • [ ] [10.2.6] observedAt query parameter used as timestamp when setting value — No test sets a value via PUT .../value?observedAt= and verifies the observedAt sub-attr takes the param value (observedAt URL param is only tested on PATCH /entities, patch_entity_url_params.test).
  • [ ] [10.2.6] datasetId query parameter targets a specific attribute instance — No test uses PUT .../value?datasetId= to target a specific multi-instance attribute; datasetId-targeting tests use PUT/PATCH /attrs, not the value subresource.
  • [~] [10.2.6] Default instance targeted when no datasetId present — Single-instance attrs are set (implicitly the default instance), but there is no test with a multi-instance attr proving the no-datasetId set hits the default (no-datasetId) instance and leaves datasetId instances untouched.
  • [ ] [10.2.6] Term-to-URI expansion of attribute name before replacement — No test PUTs to .../attrs//value with a @context-aliased short name and verifies it targets the expanded-IRI attribute; only literal attr names used.
  • [ ] [10.2.6] Term-to-URI expansion within the Attribute Fragment before replacement — Relationship object set (step 09) uses an already-URI object; no test verifies term expansion of a fragment object/sub-attr term on the value subresource (corLdExpandTree path).
  • [ ] [10.2.6] observedAt sub-attribute updated when supplied (value-only + pre-existing observedAt) — No test on the value subresource where attr has a pre-existing observedAt and observedAt param is supplied, verifying the sub-attr is updated.
  • [~] [10.2.6] Set on Relationship attribute — Relationship object is replaced and verified (steps 08-09) but the supplied object is already a URI; term expansion of a short-name/aliased object URI is not asserted.
  • [ ] [10.2.6] ResourceNotFound (404) via matching registration when operation unsupported but otherwise resolved — No test on /value verifies operation-support gating prevents forwarding to a registration not supporting Set Attribute Value.
  • [ ] [10.2.6] Invalid/absent target Attribute name -> 400 BadRequestData — No test PUTs .../value with an invalid attribute name expecting 400 BadRequestData.
  • [ ] [10.2.6] Entity does not contain target attribute instance for given datasetId -> 404 ResourceNotFound — No test uses PUT .../value?datasetId= expecting 404 (and datasetId targeting is not wired on the value route — a test would expose whether it is supported).
  • [ ] [10.2.6] Exclusive/redirect registration matches but operation not supported (complete failure) -> 409 Conflict — No distop test on /value yields a complete-failure 409 Conflict.
  • [ ] [10.2.6] Exclusive/redirect registration matches but operation not supported (partial) -> 207 multi-status — No distop test on /value yields a partial-success 207.
  • [ ] [10.2.6] Type selector mismatch -> entity treated as not-found (404 ResourceNotFound) — No test PUTs .../value?type= expecting 404 ResourceNotFound for a type-selector mismatch.
  • [~] [10.2.7] Deleting the attribute removes all of its children/sub-attributes — Delete targets only attrs whose children are not explicitly asserted gone; no test deletes an attribute carrying observedAt/unitCode/user metadata and then verifies the whole sub-attr subtree is removed (only top-level attr absence is checked).
  • [~] [10.2.7] Delete a Relationship attribute — Relationship (isParkedIn) DELETE is issued but the 204 is piped to /dev/null; removal is only indirectly confirmed via the temporal deletedAt tombstone, not a direct 204 + post-GET 404 on a Relationship.
  • [ ] [10.2.7] Delete a GeoProperty attribute — No test deletes a GeoProperty (e.g. location) attribute and asserts 204 + removal.
  • [~] [10.2.7] Delete the scope attribute — DELETE /attrs/scope is issued but its 204 is piped to /dev/null; removal only confirmed indirectly via temporal tombstone. No direct assertion of scope-delete 204 and scope absence in the entity.
  • [~] [10.2.7] No datasetId and no deleteAll removes only the default instance — Step 17 deletes the ds:A instance (not the default) leaving the default; no test removes the default-only while a datasetId instance survives — i.e. the inverse (delete default, datasetId remains) is not asserted.
  • [ ] [10.2.7] Type selector narrows the target Entity (matching type) — No DELETE /attrs request supplies a type selector (?type=) with a matching type to confirm normal 204.
  • [ ] [10.2.7] Type selector mismatch → ResourceNotFound (404) — No test supplies a non-matching type selector on DELETE /attrs and asserts 404 ResourceNotFound.
  • [ ] [10.2.7] JSON-LD @context applied for term expansion of the attribute name — No DELETE /attrs request carries a Link/@context with a short name that expands to the entity's attribute IRI and is matched/removed.
  • [ ] [10.2.7] Invalid Attribute name → BadRequestData (400) — No DELETE /attrs/{badName} with a syntactically invalid attribute name asserting 400 BadRequestData.
  • [ ] [10.2.7] datasetId parameter naming a non-existent instance → ResourceNotFound (404) — No DELETE /attrs/{a}?datasetId=does-not-exist asserting 404 ResourceNotFound.
  • [ ] [10.2.7] Exclusive/redirect match but operation unsupported, complete failure → Conflict (409) — No test where a matched exclusive/redirect reg does not support Delete Attribute and the complete delete fails, asserting 409 Conflict.
  • [~] [10.2.7] Inclusive registration match → operation also forwarded to remote endpoints — Inclusive forwarding of deleteAttrs is covered only on the temporal endpoint (deleteAttrsTemporal); no non-temporal Delete Attribute inclusive-forward test.
  • [ ] [10.2.7] Distributed delete: attribute held only remotely (no local Entity) deleted via registration — No non-temporal test where the entity/attr is held only via a registration (no local copy) and the delete is satisfied by forwarding without a local 404.
  • [ ] [10.2.8] Type selector matches existing entity type -> deletes — deleteEntity.c reads corNgsild.typeV (a type selector IS supported), but no functest passes ?type= to DELETE /entities/{id} for a matching type to confirm 204. Add a delete-with-matching-type-selector case.
  • [ ] [10.2.8] Type selector expansion via @context — No test exercises a short-name type selector on DELETE expanded via @context (matching IRI under a different alias) to confirm it still deletes.
  • [ ] [10.2.8] Inclusive registration not supporting delete is skipped (no error) — No test registers an inclusive CSR WITHOUT deleteEntity in operations and asserts the delete is silently not forwarded to it (no error, local delete still succeeds). Existing inclusive delete tests always include deleteEntity in operations.
  • [~] [10.2.9] Term expansion when matching attribute names — No merge-entity test where a short-name in the fragment expands (via a non-default @context/prefix) to the SAME IRI as an existing attribute and is therefore merged (not appended as a separate attr). context_remote_patch_attr_to_array PATCHes under a hosted context but is /attrs-style and asserts context integrity, not same-IRI merge identity.
  • [ ] [10.2.9] Explicit observedAt in fragment overrides common observedAt — No test where ?observedAt= is given AND the fragment attribute carries its own explicit observedAt; the fragment value should win for that attribute while common applies to others. Only common-applies and common-omitted-preserves cases are covered.
  • [~] [10.2.9] JSON-LD validation per clause 8.2.3 — Valid-JSON-bad-content→400 BadRequestData is well covered (raw JSON null, bad observedAt, attr type change). Missing: an explicitly malformed-JSON body on PATCH yielding 400 InvalidRequest (the invalid-JSON branch of 8.2.3) and a bad/unresolvable @context on a merge payload.
  • [~] [10.2.9] Redirect reg not supporting Merge -> Conflict (full) / partial success — The redirect failure test (csource-reg-distops-patch-errors step 04) uses a dead 503 endpoint giving 207, not a redirect CSR that lacks mergeEntity in operations giving 409. The 'redirect reg does not support Merge -> 409 Conflict (complete failure)' branch is not specifically asserted (the exclusive variant is).
  • [~] [10.2.10] Entity id in URL is authoritative; payload may omit/echo id — Matching echoed id is implicitly accepted (all happy-path PUTs echo the URL id) and mismatch->400 is asserted (step 05), but the spec's allowed 'payload omits id entirely, URL id authoritative' case is NOT a success path here: entity_replace step 04 treats a body with no id as 400 'Missing Entity Id'. This is a broker policy choice rather than 'URL id takes precedence'; worth a deliberate test/decision.
  • [~] [10.2.10] Replace target Entity ID not a valid URI -> 400 BadRequestData — entity_replace_errors #04 validates a non-URI id in the PAYLOAD (URL id is valid). A PUT where the URL path entityId itself is not a valid URI (e.g. /entities/not-a-uri) is not exercised.
  • [ ] [10.2.10] type URL parameter selects entity by type (matching type) — No PUT /entities/{id}?type= test where the existing entity's type matches and the replace proceeds (204).
  • [ ] [10.2.10] type URL parameter mismatch -> 404 ResourceNotFound — No PUT /entities/{id}?type= test asserting 404 ResourceNotFound when no local entity of that id+type exists.
  • [~] [10.2.10] @context resolution from Link header (default core context) — All replace tests rely on the default core context (short names resolved via core); no replace test supplies a custom @context and verifies short-name expansion. Core-context default path is implicitly covered.
  • [ ] [10.2.10] Replace via application/ld+json with inline @context — No PUT with Content-Type application/ld+json carrying an inline @context and verifying attribute-name expansion via that context.
  • [ ] [10.2.10] Replace via application/json with @context in Link header — No PUT with application/json + a Link header @context exercised on the Replace path.
  • [ ] [10.2.10] Replace entity with a Relationship attribute — No successful PUT /entities/{id} replace whose payload contains a Relationship attribute (type Relationship, object URI) with a post-replace GET verifying it stored. Relationship only appears in an error case in entity_replace_errors #11.
  • [~] [10.2.10] Replace entity with GeoProperty / other typed attributes — LanguageProperty replace is covered (langprop_write_ops #06/#07). GeoProperty/JsonProperty/ListProperty/VocabProperty in a successful entity Replace are not exercised (GeoProperty appears only as error cases in entity_replace_errors #15/#16).
  • [ ] [10.2.10] Replace preserves/sets sub-attributes (observedAt, unitCode, datasetId, nested metadata) — No entity-Replace test sends sub-attributes (observedAt/unitCode/datasetId/user sub-attrs) in the payload and verifies they are stored after replace and that prior sub-attrs not in payload are gone. (Sub-attrs appear only as error cases in entity_replace_errors.)
  • [ ] [10.2.10] Replace with multi-instance (datasetId) attributes — datasetid_attribute_put.test covers PUT /attrs/{attr} (attr-level), not entity Replace. No PUT /entities/{id} body with multiple datasetId instances of one attr verifying full replacement of the instance set.
  • [~] [10.2.10] Distributed Replace: registration unsupported but partial success -> 207 partial success — The 207 partial-success case in -errors #04 is dead-endpoint (503) vs live, not specifically 'registration does NOT support replaceEntity for one slice while another part succeeds'. The unsupported-but-partial-success variant (mixed supported/unsupported regs) is not isolated.
  • [~] [10.2.11] Replace a Relationship attribute — attribute_validation_errors step 18 PUTs a Relationship over a Property and only asserts 204; no GET verifies the Relationship object/sub-attributes were stored. No pure Relationship-over-Relationship replace with content verification.
  • [ ] [10.2.11] Replace a GeoProperty attribute — No test PUTs a GeoProperty (GeoJSON value) to /attrs/{attrId} and verifies the new geometry is stored.
  • [~] [10.2.11] Term expansion applied to target attribute name — csource_reg_distops_forward_compaction exercises expansion only on the forwarded path (exclusive CSR). No local-apply test PUTs a short attr name under a non-core @context and verifies it hits the attribute stored under the expanded IRI (and that short name == IRI).
  • [~] [10.2.11] JSON-LD @context via Link header is honoured — Only the exclusive-forward case uses a Link header on PUT /attrs/speed (step 04); no local-processing test relies on a Link-header @context for expansion of a single-attr Replace.
  • [ ] [10.2.11] JSON-LD @context inline in body is honoured (application/ld+json) — No PUT /attrs/{attrId} sends application/ld+json with an inline @context for local processing (the forward test uses Link header, not inline, on its PUT step).
  • [ ] [10.2.11] type URL parameter selects the entity type for matching — No test passes ?type= on PUT /attrs/{attrId} to confirm the type selector is honoured for a matching entity.
  • [ ] [10.2.11] type URL parameter mismatch yields ResourceNotFound — No test PUTs /attrs/{attrId}?type= against an existing entity to assert 404 ResourceNotFound.
  • [ ] [10.2.11] Invalid target attribute name yields BadRequestData — No test PUTs to /attrs/ to assert 400 BadRequestData (scope is covered separately as a special case).
  • [~] [10.2.11] JSON-LD validation failures yield BadRequestData — attribute_validation_errors exercises the full malformed-attribute matrix only on POST /entities, not via PUT /attrs/{attrId}; at least one content-invalid Replace-Attribute fragment (e.g. conflicting value keys or missing type-specific value) should assert 400 BadRequestData on the PUT path.
  • [ ] [10.2.11] Fragment contains an entity-level / multi-attribute structure rejected — No test PUTs a body containing id/type wrappers or multiple attributes to /attrs/{attrId} to assert 400 BadRequestData (the wrapped-fragment test only covers the single-attr name-keyed form, which is accepted).
  • [ ] [10.2.11] Redirect registration match forwards the operation — No test sets up a redirect-mode CSR supporting replaceAttrs and asserts a PUT /attrs/{attrId} is forwarded to the registration endpoint.
  • [ ] [10.2.11] Redirect registration not supporting Replace Attribute yields Conflict — No test asserts 409 Conflict when a matching redirect CSR does not support Replace Attribute.
  • [ ] [10.2.11] Inclusive registrations also receive the forwarded operation — No test asserts a Replace Attribute PUT is also forwarded to matching inclusive-mode CSRs alongside local processing.
  • [ ] [10.2.11] Distributed unsupported/failure/timeout reflected in result — No test exercises a distributed Replace Attribute against an unsupported/failing/timing-out endpoint and inspects the 207 UpdateResult per clause 6.3.5.
  • [ ] [10.2.11] Partial success when only some parts of the operation succeed — No test covers the partial-success branch for distributed Replace Attribute (some registrations succeed, others unsupported/unknown/missing-attr).
  • [ ] [10.2.12] Purge with fully-qualified (URI) type name in selector — No test purges using a fully-qualified URI type name in the type selector; only short name 'Vehicle' is exercised.
  • [ ] [10.2.12] Purge filtered by NGSI-LD Query (q) over a Relationship object — No test purges with a q filter over a Relationship object URI.
  • [ ] [10.2.12] Purge filtered by NGSI-LD Query (q) over a sub-attribute — No test purges with a q sub-attribute path (attr.sub).
  • [ ] [10.2.12] Purge filtered by q inequality operator — No purge test exercises the q != operator.
  • [ ] [10.2.12] Purge filtered by q range/comparison operators (>, <, >=, <=) — No purge test exercises q comparison operators.
  • [ ] [10.2.12] Purge filtered by q existence / non-existence — No purge test exercises q attribute existence/non-existence.
  • [ ] [10.2.12] Purge filtered by Scope query — scopeQ purge is implemented (filter.scopeExpr) but no test purges with a scope query.
  • [~] [10.2.12] Combined restrictions are ANDed (all conditions must hold) — Only id+drop / id+keep combos are tested (and that is attr-list semantics, not selection AND); no test verifies that e.g. type AND q together narrow the purged set vs each alone.
  • [~] [10.2.12] Term-to-URI expansion of type and attribute names — Short names (Vehicle, humidity, temp) implicitly expand via core context, but no test asserts a custom-@context short name and its expanded IRI select the same entity/attr for purge.
  • [ ] [10.2.12] @context reference honored for expansion — No purge test supplies a Link/@context to drive term expansion of type/attr/q names.
  • [ ] [10.2.12] Only Entity ids provided (no further restriction) → 400 BadRequestData — Implementation treats id alone as a valid restrictive filter (hasRestrictiveFilter returns true for idV), so id-only does NOT 400 — divergence from this spec item is untested either way; no test asserts id-only behaviour.
  • [ ] [10.2.12] Attr list with only system attributes → 400 BadRequestData — No test for a drop/keep list containing only system attributes triggering 400; note drop/keep are not even counted as restrictive filters in hasRestrictiveFilter.
  • [ ] [10.2.12] q referencing only system attributes → 400 BadRequestData — No test for a q over only system attributes triggering BadRequestData.
  • [ ] [10.2.12] Invalid Entity id URI in id list → 400 BadRequestData — No purge test supplies an invalid URI in the id list to verify 400 BadRequestData.
  • [ ] [10.2.12] Syntactically invalid q → 400 BadRequestData — No purge test supplies a syntactically invalid q to verify 400.
  • [ ] [10.2.12] Syntactically invalid geoquery → 400 BadRequestData — No purge test supplies a bad geometry/coordinates/georel to verify 400.
  • [~] [10.2.12] Distributed purge forwards to matching inclusive/exclusive/redirect CSRs supporting purgeEntity — Only redirect mode with purgeEntity support is tested; inclusive and exclusive modes forwarding are implemented but not covered by a test.
  • [~] [10.2.12] local scope flag suppresses forwarding to CSRs — local=true purge is tested locally (purge_entities.test) and GET ?local=true verifies local-only deletion (csource-reg-distops-purge.test), but no test asserts that a ?local=true PURGE with a matching CSR present is NOT forwarded (CSR entity stays).
  • [~] [10.2.12] Internal Query Entities semantics drive selection — Only type and id selection parity is exercised; q/geoquery/scope selection parity with GET /entities (which shares db.entityQuery) is not asserted for purge.

entity-maps (73)

  • [ ] [14.2] HEAD /entityMaps/{entityMapId} returns 200 with no body — No test issues a HEAD request to /entityMaps/{id}; the 200-with-no-body HEAD variant is entirely untested.
  • [ ] [14.2] Missing/empty entityMapId path segment is rejected — No test exercises GET /entityMaps/ with an empty/missing id segment expecting 400 BadRequestData.
  • [ ] [14.2] Invalid (non-URI) entityMapId is rejected — No test sends a GET with a non-URI entityMapId expecting 400 BadRequestData.
  • [ ] [14.2] Expired entity map is no longer retrievable — No test sets a short/past expiresAt (e.g. via PATCH) and then GETs the map expecting 404 ResourceNotFound after expiry.
  • [~] [14.3] Partial update succeeds, changing only provided fields — Steps 02/03 PATCH expiresAt and read it back, but no assertion that the other stored elements (entityMap entries, linkedMaps, id, type) remain intact after the update.
  • [ ] [14.3] Fragment body is a JSON-LD EntityMap fragment — patchEntityMap.c skips @-prefixed keywords (accepts @context), but no test sends a PATCH body containing @context to verify JSON-LD handling on the partial update.
  • [ ] [14.3] Empty fragment leaves the EntityMap unchanged — Spec expects an empty/no-updatable-element fragment to succeed with no change, but step 07 sends {} and the broker returns 400 'Empty Structure' (and the routine itself would 400 'Mandatory Field Missing' for a non-empty body lacking expiresAt). The spec's success-unchanged behaviour is not covered; current test asserts a 400 instead.
  • [ ] [14.3] Missing EntityMap ID -> 400 BadRequestData — No test exercises an absent EntityMap ID (the router always supplies wildcard[0]). A request with no id segment / empty id should be verified to yield 400 BadRequestData (or document that the route simply does not match).
  • [~] [14.3] Malformed / invalid JSON-LD fragment body -> 400 BadRequestData — Steps 04/05/06 cover structurally-invalid-but-parseable bodies (wrong/immutable fields, bad date). No test sends a malformed/unparseable JSON body (or a non-object body) to the PATCH /entityMaps/{id} endpoint to assert 400.
  • [ ] [14.4] Output data is empty on success — No test asserts the empty 204 body (no entityMap content / no @context) on a successful delete.
  • [ ] [14.4] Entity Map ID path parameter is the target identifier — No test exercises the DELETE path-parameter form /entityMaps/{id}; the only-input-is-the-ID contract is unverified.
  • [ ] [14.4] Missing Entity Map ID → BadRequestData (400) — No test for DELETE /entityMaps (no ID). Note: broker routes this only via wildcard, so missing-ID handling/400 is also not implemented or tested.
  • [ ] [14.5] Query by selector of Entity types (fully qualified URI) — No EntityMap-create test passes a fully-qualified URI type selector; only short names exercised.
  • [ ] [14.5] Query by type selector with disjunction/multiple types — No EntityMap-create test uses a multi-type / disjunction type selector (e.g. type=Vehicle,Sensor).
  • [ ] [14.5] Query by list of Entity identifiers (id) — No EntityMap-create test restricts by an id list (id=urn:V1,urn:V2) and asserts the map holds only those ids.
  • [ ] [14.5] Query by id pattern (idPattern regex) — No EntityMap-create test uses idPattern to restrict candidate ids.
  • [~] [14.5] Query by list of Attribute names (existence selector) — POST attrs:[speed] runs but all 3 seeded entities have a value-bearing attr so it does not actually exclude any entity lacking the attr; existence-selection not isolated (V1/V2 speed, S1 temp all present -> all included).
  • [ ] [14.5] NGSI-LD Query (q) filter over a Relationship object — No EntityMap-create q test over a Relationship object URI.
  • [ ] [14.5] NGSI-LD Query (q) filter over a sub-attribute / compound path — No EntityMap-create q test over attr.sub or attr[member] paths.
  • [ ] [14.5] NGSI-LD Query (q) inequality operator (!=) — No != operator exercised on the EntityMap-create path.
  • [~] [14.5] NGSI-LD Query (q) relational operators (>, <, >=, <=) — Only > exercised (q=speed>15); <, >=, <= not tested on the EntityMap-create path.
  • [ ] [14.5] NGSI-LD Query (q) range and value-list operators — No range (a..b) or comma value-list q on the EntityMap-create path.
  • [ ] [14.5] NGSI-LD Query (q) pattern-match operators (~=, etc.) — No pattern-match (~=) q on the EntityMap-create path.
  • [ ] [14.5] NGSI-LD Query (q) attribute existence / non-existence — No q existence (attr) / non-existence (!attr) test on the EntityMap-create path.
  • [ ] [14.5] NGSI-LD Query (q) logical AND/OR composition — No compound q with ; (AND) or | (OR) on the EntityMap-create path.
  • [ ] [14.5] GeoQuery: near (distance) georel — No georel=near geoquery exercised when creating an EntityMap.
  • [ ] [14.5] GeoQuery: within/contains/intersects/etc. georel — No topological georel geoquery on the EntityMap-create path.
  • [~] [14.5] Scope query filter (scopeQ) — scopeQ only appears as a reuse-rejection (introducing scopeQ -> 400); no test creates an EntityMap WITH scopeQ and asserts scope filtering of candidate ids.
  • [ ] [14.5] Context source filter (csf) query — No csf filtering of forwarded CSRs on the EntityMap-create path.
  • [~] [14.5] @context reference (Link header / context body) — Responses carry the core-context Link, but no EntityMap-create test supplies a custom @context and asserts term expansion via it.
  • [~] [14.5] Suggested expiry time for the EntityMap honoured — PATCH can set expiresAt and GET reflects it, but no test supplies a SUGGESTED expiry at CREATE time and asserts the created map carries/respects it.
  • [~] [14.5] splitEntities default (unset) follows deployment default — Single-broker create tests run with the default deployment (no split flag) but never assert split-vs-nonsplit behaviour differs by default; default semantics not explicitly pinned.
  • [~] [14.5] splitEntities false / non-split → full local filter set applied — Distributed tests run with --noSplitEntities and a q filter is applied locally in create_with_filter, but no single test asserts the FULL non-split local filter set (id+type+attr+idPattern+q+geo+scope) is applied together.
  • [~] [14.5] Distributed forward to createEntityMapQueryEntity-supporting CSRs — Forwarding to a CSR and capturing its remote EntityMap is tested, but the CSR is registered with queryEntity/retrieveEntity ops, not the specific createEntityMapQueryEntity operation; no test asserts forwarding is gated on createEntityMapQueryEntity support.
  • [~] [14.5] Local scope restricts to local-only (no forwarding) — GET /entityMaps?local=true returns a map with all local entities, but in a single-broker setup; no test asserts that local=true SUPPRESSES forwarding when a matching CSR exists.
  • [~] [14.5] Local scope alone is a sufficient minimum restriction — GET /entityMaps?local=true succeeds (200/201) with no other filter, implying local satisfies the minimum, but the too-wide rule is not exercised on the /entityMaps endpoint to contrast it.
  • [ ] [14.5] limit parameter is ignored — No EntityMap-create test supplies limit and asserts the candidate id set is NOT truncated.
  • [ ] [14.5] ERROR: attr list with only system attributes → 400 (too wide) — No test that an attrs list of only system attributes is rejected as too-wide on the EntityMap-create path.
  • [ ] [14.5] ERROR: q with only system attributes → 400 (too wide) — No test that a q over only system attributes is rejected as too-wide on the EntityMap-create path.
  • [ ] [14.5] ERROR: invalid Entity identifier URI in id list → 400 — No test for an invalid id URI in the id list on the EntityMap-create path.
  • [ ] [14.5] ERROR: syntactically invalid q → 400 — No test for a syntactically invalid q on the EntityMap-create path.
  • [ ] [14.5] ERROR: syntactically invalid geoquery → 400 — No test for an invalid geoquery (bad geometry/coords) on the EntityMap-create path.
  • [ ] [14.6] Entity Map always returned regardless of the location-return flag — No temporal-entity-map test exists, so the always-return-the-map behaviour for the temporal operation is unverified.
  • [ ] [14.6] limit parameter is ignored — limit/offset are tested for temporal pagination of DATA (troe_timescale_temporal_query) but never in an entity-map-creation context where it must be ignored.
  • [ ] [14.6] location of existing Entity Map resource (entityMap input) is ignored — No test supplies an existing entityMap location on the temporal create-map operation to confirm it is ignored.
  • [~] [14.6] Restriction satisfied by selector of Entity Types → success — type=Vehicle temporal queries succeed, but they return temporal DATA, not an EntityMap; the restriction-satisfies rule is not asserted in the entity-map-creation operation.
  • [~] [14.6] Restriction satisfied by attribute-name list (non-system attr) → success — attrs=speed is exercised on temporal data queries, but not as a restriction satisfying the at-least-one-restriction rule in an entity-map create.
  • [~] [14.6] Restriction satisfied by NGSI-LD Query (non-system attr) → success — q=speed>50 is tested on temporal data, but not as a restriction-satisfier in entity-map creation.
  • [~] [14.6] Restriction satisfied by GeoQuery → success — GeoQuery is tested on temporal data filtering, but not validated as the at-least-one-restriction satisfier for an entity-map create (and no map is produced).
  • [~] [14.6] Restriction satisfied by local scope → success (no further restriction needed) — local=true temporal queries are tested, but never as a stand-in restriction permitting a no-type/no-attr entity-map create; entity-map not produced.
  • [ ] [14.6] Linked Entity retrieval indicated by projection attributes → 400 — No test triggers Linked Entity retrieval via projection attrs on the temporal operation to assert 400.
  • [ ] [14.6] Linked Entity retrieval indicated by filter conditions → 400 — No test triggers Linked Entity retrieval via q on the temporal operation to assert 400.
  • [ ] [14.6] Syntactically invalid geoquery → 400 BadRequestData — No test sends a malformed geoquery to the temporal operation to assert 400 (geoq validation tested for non-temporal geoQ only).
  • [ ] [14.6] Syntactically invalid context source filter (csf) → 400 — No test sends a malformed csf to the temporal operation to assert 400.
  • [ ] [14.6] expandValues (entitiesToExpand) attr list triggers JSON-LD type coercion — No test supplies an expandValues/entitiesToExpand attr list on the temporal operation to verify value coercion before filtering.
  • [~] [14.6] id list filter restricts candidate Entities — id=urn:V1,urn:P1 filters temporal DATA results; not verified as restricting the candidate set of a created temporal EntityMap.
  • [ ] [14.6] idPattern (regex) restricts candidate Entities — No temporal query uses idPattern; not tested for data or entity-map creation.
  • [~] [14.6] Type selector restricts candidate Entities — type= restricts temporal DATA results; not asserted as restricting the entity-map candidate set.
  • [~] [14.6] Temporal-interval filter (S1): entities with no in-interval instances excluded — timerel/timeAt interval filtering of temporal DATA is tested, but S1 candidate-set exclusion for an entity-map create is not (no map produced).
  • [~] [14.6] q values filter over a Property → narrows result set (S2) — q=speed>50 narrows temporal DATA; the S2 candidate-set narrowing for entity-map creation is not asserted.
  • [ ] [14.6] q values filter over a Relationship object → narrows result set — No temporal q over a Relationship object value is tested.
  • [ ] [14.6] q values filter over a sub-attribute path → narrows result set — No temporal q using attr.sub path is tested.
  • [ ] [14.6] q values filter over a compound/member path → narrows result set — No temporal q using attr[member] compound path is tested.
  • [~] [14.6] q operator equality (==) over in-interval instances — q uses > (speed>50/>20); == equality over in-interval instances not explicitly tested on the temporal path, and not for entity-map creation.
  • [~] [14.6] q operator inequality/relational (!=,>,<,>=,<=) over in-interval instances — Only > is exercised; !=,<,>=,<= over in-interval temporal instances are untested; none in entity-map context.
  • [ ] [14.6] q operator range (..), pattern (~=), existence over in-interval instances — No temporal q using range, ~= pattern, or existence checks is tested.
  • [~] [14.6] geoquery over in-interval GeoProperty instances → narrows result set (S3) — geoq narrows temporal DATA results; S3 candidate-set narrowing for entity-map creation not asserted.
  • [~] [14.6] Scope query → narrows result set (S4) — scopeQ narrows temporal DATA; S4 candidate-set narrowing for entity-map creation not asserted.
  • [ ] [14.6] Suggested expiry time for the Entity Map accepted — No test supplies a suggested expiry for a temporal EntityMap (operation unimplemented).
  • [ ] [14.6] context source filter (csf) accepted to filter Context Sources — No temporal query (or entity-map create) supplies a csf to filter CSRs.
  • [~] [14.6] Local scope: no forwarding, map from local entities only — local=true suppresses forwarding on temporal data queries, but no EntityMap is built; the local-only map-from-local-entities behaviour is not asserted.
  • [ ] [14.6] attrs list doubles as restriction-attrs and projection attributes — No test demonstrates a temporal attrs list serving both restriction and projection roles in the entity-map operation.
  • [ ] [14.6] splitEntities flag default behaviour follows deployment setting — splitEntities default behaviour for the temporal entity-map operation is untested (split mode unimplemented for temporal).

errors (5)

  • [~] [8.3] InternalError error type during operation execution — InternalError is only asserted as the type member inside distop forwarding-failure bodies returned with HTTP 502/504 (gateway errors). No test exercises a genuine internal execution failure surfacing as the InternalError type with HTTP 500.
  • [ ] [8.3] TooComplexQuery error type for unresolvable complex query — No test references TooComplexQuery. No functest induces a query the broker rejects as too complex (HTTP 403). If the broker never raises this type it should be documented as not-applicable; otherwise a query-complexity rejection test is missing.
  • [ ] [8.3] TooManyResults error type when query result set too large — No test references TooManyResults. No functest drives a query past a result-count threshold to get HTTP 403 TooManyResults. Either the broker has no such threshold (document as not-applicable) or the path is untested.
  • [~] [8.3] Unexpected/runtime failure surfaces as InternalError (incl. DB timeout) — Only distributed-forwarding failures (connection refused / cooldown / timeout) map to the InternalError type, and those are reported as 502/504. No test induces a backend/DB timeout or other unexpected runtime failure and asserts the InternalError mapping with HTTP 500.
  • [ ] [8.3] Invalid (not merely unavailable) remote @context yields BadRequestData — Tests cover the unreachable-context case (LdContextNotAvailable/504), but none push a reachable-but-malformed/invalid @context body to the context server and assert that fetching it yields BadRequestData (HTTP 400). The invalid-vs-unavailable distinction is untested.

json-ld (9)

  • [~] [8.2] urn:ngsi-ld:null as first-level member value → 400 BadRequestData — First-level urn:ngsi-ld:null rejection is asserted for Create Subscription and Create Registration, but NOT for Create/Replace Entity (POST /entities, PUT /entities/{id}) — the entity-document path lacks the 400 assertion.
  • [ ] [8.2] {"@none": "urn:ngsi-ld:null"} as RHS of languageMap → 400 BadRequestData — No test asserts {"@none":"urn:ngsi-ld:null"} in a languageMap on a CREATE/REPLACE entity is rejected 400 BadRequestData (only the merge-delete ALLOWED direction and notification rendering are tested).
  • [ ] [8.2] urn:ngsi-ld:null as value of a key inside a JSON object that is a Property value → 400 BadRequestData — No test asserts that a Property whose value object contains a nested {"key":"urn:ngsi-ld:null"} is rejected 400 BadRequestData on CREATE (outside merge).
  • [~] [8.2] urn:ngsi-ld:null inside Property-value object ALLOWED in merge Fragments — Merge-delete of attributes/sub-attributes via the sentinel is covered, but deletion of a NESTED KEY inside a Property-value JSON object via {"key":"urn:ngsi-ld:null"} (RFC-7386 merge into a value object) is not explicitly asserted.
  • [~] [8.2] VocabProperty values are expanded/compacted as terms — vocab_property.test proves vocab values are @vocab-expanded to IRIs and round-trip, but uses the core/default @vocab, not a USER @context that maps the vocab term to a specific IRI and compacts it back to a short name on query — the term-to-URI-via-user-context expand/compact path for VocabProperty values is not isolated.
  • [~] [8.2] Query Entities POST + application/json → @context via Link header — POST query with application/json + Link-header @context is exercised, but no test specifically asserts that an inline @context in the body is rejected/ignored under application/json for the POST-query binding (the binding-conflict assertion exists for POST /entities create, not for /entityOperations/query).
  • [~] [8.2] Query Entities POST + application/ld+json → @context within payload body — No test clearly asserts a POST /entityOperations/query with Content-Type application/ld+json and an INLINE body @context driving term expansion (the common pattern in the suite is Link-header on POST query). A dedicated ld+json-body-context query case is missing.
  • [~] [8.2] Core @context has absolute precedence regardless of position in @context array — Core precedence is proven (shadow attempt ignored; old-core-URL stub) but not specifically with a user @context that redefines a core term placed BEFORE and AFTER the core URL in the SAME array to prove position-independence. The array-ordering matrix is not isolated.
  • [~] [8.2] JsonProperty json keys use short-hand names verbatim (no expansion/compaction) — json_property.test carries native JSON verbatim, but does NOT use json-object keys that collide with @context terms while retrieving under that @context to prove the keys are returned UNCHANGED (no expansion/compaction inside the 'json' element).

local-scope (7)

  • [ ] [8.6] local=true on GET /entities/{id}/attrs/{attr} suppresses fan-out — No GET on /entities/{id}/attrs/{attr}?local=true is asserted; local single-attr coverage exists only for the discovery resource /attributes/{attr} (local_param_distops_suppress.test) and only for entity-attr WRITES (entity_update_local_reg_conflict.test), not a read of a single attribute of an entity that has a matching CSR.
  • [ ] [8.6] local=true on count (GET /entities?count=true) counts only local entities — No test combines count=true with local=true to assert NGSILD-Results-Count reflects only locally held matching entities (vs the distributed total). count and local are each tested but never together.
  • [~] [8.6] local=true on a write/update operation limits effect to the local Broker — Existing tests assert that local=true writes against exclusive/redirect claims 409 (no chop-and-forward, conflict refused) and that an inclusive-only/unclaimed attr write succeeds locally. The positive semantic — a local=true write against a remote-claiming CSR succeeding purely locally with NO forward to the registered source (rather than 409) — is not directly asserted; coverage is the conflict path only.
  • [ ] [8.6] Subscription localOnly absent/false matches distributed Entities — No subscription test contrasts localOnly absent/false (distributed matching) against localOnly=true; the subscription localOnly member is untested entirely.
  • [~] [8.6] localOnly in CSR persists and round-trips on GET registration — Only the negative validation case (management.localOnly:"yes" non-boolean → 400) is asserted. No test creates a CSR with management.localOnly:true (or false) and GETs it back to confirm the value is stored and returned verbatim.
  • [ ] [8.6] Operations on a Snapshot are always implicitly local scope — Snapshot tests cover capture-via-distops and snapshot CRUD/read, but none asserts that an operation targeting a Snapshot ignores Context Source Registrations (no fan-out) regardless of any registration matching the snapshot's entities.
  • [~] [8.6] Via header passed on forwarded distributed requests lists previously encountered Sources — Via is exercised indirectly: incoming Via is honored for loop/dup suppression and two-hop loops fire, which proves the broker emits Via on its own forwards. But no test directly inspects an OUTBOUND forwarded request to assert the Via header content (the broker's own alias/source) it sends downstream.

multi-attr-datasetId (8)

  • [ ] [8.5] datasetId equal to JSON-LD keyword @none accepted — No test sends "datasetId":"@none" in a request body to verify it is accepted (only @none as a URL query-param value and in csourceRegistration top-level datasetId arrays is tested).
  • [~] [8.5] Append with datasetId affects only same-datasetId instance — PATCH /attrs targeting an instance is asserted, but no POST /entities/{id}/attrs (true append) with a body datasetId verifying only the matching instance is created/updated while other instances and the default are left untouched.
  • [~] [8.5] datasetId @none is treated as the default instance — @none is verified as the default selector on RETRIEVAL (datasetId=@none query param), but not as equivalent to no-datasetId on a write body (create/update/delete with "datasetId":"@none" targeting the default instance).
  • [ ] [8.5] No multi-attribute support for non-reified createdAt — No test verifies a datasetId/multi-instance on createdAt is rejected with 400 BadRequestData (createdAt is system-owned/dropped at intake, so behaviour may differ — needs an explicit assertion).
  • [ ] [8.5] No multi-attribute support for non-reified modifiedAt — No test verifies a datasetId/multi-instance on modifiedAt is rejected with 400 BadRequestData.
  • [ ] [8.5] No multi-attribute support for non-reified expiresAt — No test verifies a datasetId/multi-instance on expiresAt is rejected with 400 BadRequestData.
  • [ ] [8.5] No multi-attribute support for non-reified observedAt — No test verifies a datasetId/multi-instance on observedAt is rejected with 400 BadRequestData.
  • [ ] [8.5] No multi-attribute support for non-reified unitCode — No test verifies a datasetId/multi-instance on unitCode is rejected with 400 BadRequestData.

ordering (15)

  • [ ] [7.6] orderBy single attribute, explicit ascending (;asc) — No test exercises the explicit ;asc direction term; only default-ascending and ;desc are asserted. Add orderBy=name;asc and assert equivalence to default.
  • [ ] [7.6] orderBy mixed per-element directions — No test uses per-element directions like orderBy=name,age;desc (primary asc, secondary desc); only uniform directions are tested.
  • [~] [7.6] orderBy on a Property value of string type using ICU root collation — String ordering is asserted (alpha/bravo/charlie; Alice/Bob/Charlie) but all values are same-case lowercase/leading-cap ASCII, so ICU root collation is indistinguishable from raw ASCII sort. No test proves ICU root behaviour (e.g. accented/diacritic ordering).
  • [ ] [7.6] orderBy on a DateTime Property value — No test orders entities by a DateTime Property value to verify chronological sort.
  • [ ] [7.6] orderBy on a Relationship (target object) ascending/descending — No test orders entities by a Relationship's target object URI.
  • [ ] [7.6] orderBy by sub-item within a complex JSON Property value using bracket path — No test uses orderBy=address[city] bracket-path into a complex JSON value.
  • [ ] [7.6] Mixed-datatype value comparison order (Number<String<Object<Array<Boolean<Time<Date<DateTime<Null) — No test ranks entities whose ordering attribute holds different datatypes to verify the cross-type precedence order.
  • [ ] [7.6] null values sorted last among present values — No test ranks an entity whose ordering attribute value is null to verify null-last placement among present values.
  • [~] [7.6] Entities missing the ordering attribute sorted after null (absolute last) — Missing-attribute-sorts-last is asserted (V5 last), but there is no entity with an explicit null value, so the missing-after-null relative ordering is not distinguished.
  • [ ] [7.6] Sort by distance uses Haversine spherical distance — No test verifies distance ordering reflects great-circle (Haversine) distance vs planar distance.
  • [ ] [7.6] orderFrom with non-Point reference geometry via orderGeometry (e.g. LineString) — No test uses orderGeometry=LineString with orderFrom coordinates for distance ordering against a non-Point reference geometry.
  • [ ] [7.6] orderFrom coordinates conform to RFC 7946 §3.1.2 — No test exercises orderFrom coordinate parsing ([lon,lat] GeoJSON semantics).
  • [ ] [7.6] Distance sort limited to GeoProperties; non-GeoProperty attributes ranked after GeoProperties — No test verifies that under distance sort, non-GeoProperty entities are ranked after GeoProperty-holding ones.
  • [ ] [7.6] collation parameter selects case-insensitive ordering (und-u-ks-identic) — No test uses the collation parameter (und-u-ks-identic) for case-insensitive ordering.
  • [ ] [7.6] collation parameter selects locale-specific ordering (de-u-co-phonebk) — No test uses a locale-specific collation (de-u-co-phonebk) to alter sort order.

pagination (7)

  • [~] [7.4] Pagination pointers carry all parameters to re-execute the query — next/prev Link URLs are asserted to echo type/limit/offset/count, but no test actually FOLLOWS a returned next pointer and verifies the page it yields; filter (q) round-trip in a paging pointer not asserted
  • [ ] [7.4] Backward iteration through the result set — no test iterates backwards by following prev pointers (prev pointer presence is asserted, but never followed to re-fetch the prior page)
  • [ ] [7.4] Temporal limit applies per Attribute — all temporal tests use a single attribute (speed); no test asserts firstN/lastN caps instances independently for two or more attributes in one entity
  • [~] [7.4] Entity-map split-entity candidates filtered only at page prep — sources test runs --noSplitEntities; the split-entity aggregate-then-filter-at-page-prep path (filter dropping a non-matching aggregated split entity) is not specifically asserted
  • [~] [7.4] Entity-map pages filled to maximum while Entities available — step 11 returns 1 entity (V2 filtered out) under limit-default; not asserted that a page is back-filled to the maximum from remaining candidates after a recheck removes one
  • [ ] [7.4] Same @context must be used throughout pagination — no test asserts that following pagination pointers preserves/requires the original @context across iterations
  • [ ] [7.4] limit above hard maximum honoured or rejected per policy — no test exercises a client limit exceeding the implementation hard maximum (cap-or-reject policy); http_411_413 caps request body size, not page size

query-filter (22)

  • [~] [7.2] q existence: top-level Relationship — Existence-only q on a (single) Relationship is not directly asserted; q=lr (ListRelationship) existence and Geo/Json existence are, but a plain q= existence match on a Relationship has no dedicated case.
  • [~] [7.2] q value type: dateTime / date / time — Full DateTime comparison (with timezone offsets) is thoroughly covered. Date-only (YYYY-MM-DD) and Time-only comparable values in q are not tested.
  • [~] [7.2] q value type: URI / IRI — URI as a CompEqualityValue against a Relationship object is covered (urn:). No test uses an http(s):// URI or an IRI, nor exercises the RFC 3986 false-negative-minimising URI comparison.
  • [~] [7.2] q logical AND precedence over OR — AND and OR are each tested, and a grouped (OR);AND is tested, but no case proves the default precedence a;b|c == (a;b)|c without parentheses.
  • [ ] [7.2] q trailing-path undefined member → non-existent — No test queries a bracketed member that does not resolve (e.g. m[nope]==x on an object lacking 'nope') to assert the target is treated as non-existent / no match.
  • [~] [7.2] q on JsonProperty member with jsonKeys — jsonKeys is accepted as a parameter (step 04 'doesn't affect query') and JsonProperty existence is tested, but no test does q=jp[member]==value with jsonKeys=jp to assert raw-JSON members are matched WITHOUT @context expansion.
  • [ ] [7.2] q linked-entity relation with EntityType hint — No test exercises the q=sensor{Device:humidity}==N EntityType-hint form to restrict followed objects to a given type.
  • [ ] [7.2] q target value: Property with multiple datasetId instances — No q test creates a multi-instance (datasetId) Property and asserts that q matches when ANY instance's value satisfies the term.
  • [~] [7.2] q target value: LanguageProperty, no language — q=L[es]==value (specific language) is tested. The any-language form description[*]==value (match across ALL languageMap keys with no language addressed) is not exercised.
  • [~] [7.2] q equality: ValueList against array target — ValueList against scalar targets is covered (q_compound) and single value against list target is covered (q_attr_types lp/lr). A ValueList against an ARRAY target (list==v1,v2 where target is itself an array) is not directly asserted.
  • [ ] [7.2] q equality: URI ValueList vs Relationship object(s) — No test does q=rel=="urn:a","urn:b" (a list of URIs) against a Relationship/ListRelationship to assert match when any object equals any list URI.
  • [ ] [7.2] q equality: sub-attribute in compound object (ValueList) — No test does q=address[city]==Berlin,Tokyo (member compared against a ValueList), nor across an array of JSON objects.
  • [~] [7.2] geoQ: geometry types (GeoJSON, except GeometryCollection) — Point, Polygon, LineString are exercised. MultiPoint/MultiLineString/MultiPolygon as the reference geometry are not, and there is no test asserting GeometryCollection is rejected.
  • [~] [7.2] geoQ: maxDistance/minDistance value must be PositiveNumber — maxDistance==-5 (negative) and maxDistance==abc → 400 are asserted. No case asserts maxDistance==0 → 400, nor a negative/zero minDistance specifically.
  • [~] [7.2] temporal: timerel=before (exclusive) — timerel=before is used (e.g. timeAt far-future returning all, and before+no-timeAt→400). The exclusive-bound semantics (a value exactly at timeAt being excluded) is not specifically probed.
  • [~] [7.2] temporal: timerel=after (inclusive) — timerel=after is heavily used as a filter, but inclusivity of the timeAt bound (a value exactly at timeAt being included) is not specifically asserted.
  • [~] [7.2] temporal: timerel=between (incl lower, excl upper) — timerel=between 09:30..11:30 returns speed[20,30]+color[red]; this implies the upper bound 11:30 color row is included though spec says upper is exclusive — boundary inclusivity (lower inclusive / upper exclusive) is not crisply isolated/asserted.
  • [~] [7.2] temporal: timeAt/endTimeAt must be DateTime — timerel without timeAt → 400 and timerel-mandatory → 400 are asserted, but a malformed (non-DateTime) timeAt/endTimeAt value → 400 is not tested.
  • [ ] [7.2] temporal: entity without target Temporal Property → non-matching — No test asserts that an entity lacking the queried temporal property (or the timeproperty axis) is non-matching rather than erroring.
  • [ ] [7.2] lang filter: multiple langtags no preference — No test uses lang="fr-CH,fr" (comma-separated multiple langtags) to assert a value in either listed language is returned.
  • [ ] [7.2] lang filter: wildcard * — No test uses lang=* to return a LanguageProperty in any supported language.
  • [ ] [7.2] lang filter: quality-value ranking — No test uses an Accept-Language-style ranked lang filter (e.g. lang="fr-CH,fr;q=0.9,en;q=0.8,*;q=0.5"). (accept_q_weighted covers HTTP Accept q-values, a different feature.)

query-projection (5)

  • [ ] [7.3] pick multiple attributes (pipe operator) — No test uses the '|' OR separator in pick=/omit= (pipe is only exercised in q=/scopeQ=); add a test asserting ?pick=speed|color equals the comma form.
  • [~] [7.3] omit multiple attributes — Comma form of omit=speed,color is asserted, but the pipe-separated omit form is not tested.
  • [ ] [7.3] Linked-Entity term grammar (nested braces) — No test of nested LinkedEntityTerm grammar (rel1{rel2{attr}}) in pick/omit projection.
  • [ ] [7.3] Combined top-level and linked-entity terms in one pick — No test mixing a direct AttrName term with a Linked-Entity brace term in a single pick=.
  • [ ] [7.3] attrs with multiple attributes (existence of all) — No test asserts AND-existence semantics of multi-attr attrs= (entity missing one of two listed attrs excluded); only single-attr attrs= existence is covered.

registration (46)

  • [~] [12.2] Register — base entity-creation behaviour of 10.2.2.4 (JSON-LD validation, term expansion) — forward_compaction exercises propertyNames expansion under an inline/URL @context for forwarding, but no create-registration test directly asserts that a short attribute name supplied with a custom @context is stored/rendered expanded vs compacted; coverage is incidental to distop forwarding
  • [~] [12.2] Register — invalid JSON-LD payload → 400 (InvalidRequest/BadRequestData per 8.2.3) — errors.test covers empty/no body (411) and array-not-object (400 BadRequestData), but no registration test posts syntactically-invalid JSON and asserts InvalidRequest, nor a bad @context yielding 400
  • [~] [12.2] Update — JSON-LD validation per 8.2.3 — delete_marker step 05 rejects raw JSON null in a PATCH (400), but no PATCH test posts invalid JSON / bad @context asserting InvalidRequest vs BadRequestData on update
  • [ ] [12.2] Update — invalid contextSourceInfo (9.5.2) → 400 BadRequestData — No PATCH-registration test supplies an invalid contextSourceInfo fragment and asserts 400; contextSourceInfo validation is only tested on the create path
  • [ ] [12.2] Update — attribute name term-to-URI expansion observed (8.2.4) — No PATCH-registration test supplies short attribute names in an information fragment with a custom @context and asserts they are expanded/stored correctly on update
  • [ ] [12.2] Update redirect mode — existing Entity already matches → 409 Conflict — No test updates a registration to redirect overlapping an existing local entity and asserts 409 on the update path
  • [ ] [12.2] Update redirect mode — endpoint+tenant match broker itself → 409 Conflict — No test PATCHes a registration's endpoint+tenant to point at the broker itself and asserts 409 on the update path
  • [ ] [12.2] Delete — target id missing or not a valid URI → 400 BadRequestData — No DELETE /csourceRegistrations/ test asserting 400 BadRequestData
  • [ ] [12.3] Retrieve CSR: term-to-URI expansion of Attribute names observed — No test registers a CSR with prefixed/custom-@context attribute names and retrieves it to confirm expansion-then-compaction; all retrieve tests use core-context short names.
  • [ ] [12.3] Retrieve CSR: invalid URI id -> BadRequestData — No GET /csourceRegistrations/{badUri} test asserting 400 BadRequestData for a non-URI id (creation-side invalid-URI is tested, but not retrieval).
  • [~] [12.3] Query CSR: only entity ids (no type/attr/q/geoQ) -> BadRequestData — id-only discovery (step 07-09) is currently accepted as a valid filter and returns matches rather than 400; spec says id alone (no type/attr/q/geoQ) is too-wide. No test asserts the 400-on-id-only behaviour, and current behaviour may diverge from spec.
  • [ ] [12.3] Query CSR: invalid entity identifier URI -> BadRequestData — No discovery test passes ?id= and asserts 400 BadRequestData.
  • [ ] [12.3] Query CSR: syntactically invalid Query (q) -> BadRequestData — No discovery test passes a malformed q expression and asserts 400 Invalid query / BadRequestData.
  • [ ] [12.3] Query CSR: term-to-URI expansion of type and attribute names — No discovery test supplies a custom @context (Link header/body) so that a prefixed/short type or attr is expanded before matching RegistrationInfo; all tests rely on core-context names matching directly.
  • [ ] [12.3] Query CSR: type as fully qualified URI — No discovery test supplies ?type= and asserts it matches a RegistrationInfo EntityInfo type.
  • [ ] [12.3] Query CSR: match by list of entity ids — Discovery is exercised with single ?id and ?type=A,B (type list) but not with a list of entity ids; no assertion that any-of-id-list matches.
  • [~] [12.3] Query CSR: match by attribute name that is a Relationship — relationshipNames registration is tested (create/render), but no discovery query with ?attrs= asserts that a Relationship-named attribute causes a CSR match.
  • [~] [12.3] Query CSR: empty Properties/Relationships in RegistrationInfo matches any attr — CSRs with no propertyNames are returned for type-only queries, but no test issues ?attrs= against a CSR that declares no Properties/Relationships to assert the match-any-attr rule.
  • [~] [12.3] Query CSR: GeoQuery matched against named GeoProperty — geoQ matched against default location; no test names a non-default geoproperty on the CSR and queries it.
  • [~] [12.3] Query CSR: GeoQuery georel within/contains/intersects/equals/disjoint/overlaps — Only near and within georels exercised on discovery; contains/intersects/equals/disjoint/overlaps not tested.
  • [ ] [12.3] Query CSR: temporal timeproperty modifiedAt matches managementInterval — timeproperty=modifiedAt against managementInterval not separately tested (only createdAt is).
  • [~] [12.3] Query CSR: relevant interval absent -> no match — observationInterval-out-of-range yields empty (step 06), but there is no test where a temporal query targets managementInterval and the CSR has only observationInterval (or vice versa) to assert exclusion when the relevant interval is absent.
  • [ ] [12.3] Query CSR: language filter (lang) applied — lang is named in the discovery-filters header comment but there is NO actual RUN step registering a LanguageProperty CSR and querying ?lang= to assert language reduction.
  • [~] [12.3] Query CSR: optional @context reference applied — Responses carry the core-context Link header, but no discovery test supplies a custom @context (Link header) and asserts it is used for type/attr expansion and response compaction.
  • [~] [12.4] Create CSR Sub: invalid Subscription body → 400 BadRequestData — Only specific invalids on the CSR-sub endpoint are asserted (invalid q syntax, unknown jsonldContext, past expiresAt). No CSR-sub test for a structurally malformed Subscription (e.g. missing notification/endpoint, bad type, bad watchedAttributes type) asserting 400 + title BadRequestData.
  • [ ] [12.4] geoQ default GeoProperty is location — No CSR-sub geoQ test omitting geoproperty to verify default 'location' is used.
  • [ ] [12.4] geoQ matches when CSR location directly matches or possibly contains matching locations — No CSR-sub test for area-containment geoQ matching semantics on a CSR's GeoProperty.
  • [ ] [12.4] temporalQ timeproperty observedAt → matched against observationInterval — No CSR-sub temporalQ test against a CSR observationInterval with timeproperty observedAt.
  • [ ] [12.4] temporalQ default timeproperty (omitted) → observedAt → observationInterval — No CSR-sub temporalQ test omitting timeproperty to verify observedAt default vs observationInterval.
  • [ ] [12.4] temporalQ timeproperty createdAt → matched against managementInterval — No CSR-sub temporalQ test with timeproperty createdAt against managementInterval.
  • [ ] [12.4] temporalQ timeproperty modifiedAt → matched against managementInterval — No CSR-sub temporalQ test with timeproperty modifiedAt against managementInterval.
  • [ ] [12.4] temporalQ timeproperty deletedAt → matched against managementInterval — No CSR-sub temporalQ test with timeproperty deletedAt against managementInterval.
  • [ ] [12.4] temporalQ 'before' relation: timeAt contained in or endpoint of CSR interval — No CSR-sub temporalQ 'before' relation match test against a CSR interval.
  • [ ] [12.4] temporalQ 'after' relation: timeAt contained in or endpoint of CSR interval — No CSR-sub temporalQ 'after' relation match test against a CSR interval.
  • [ ] [12.4] temporalQ 'between' relation: overlap between [timeAt,endTimeAt] and CSR interval — No CSR-sub temporalQ 'between' relation overlap test against a CSR interval.
  • [~] [12.4] Filtered CSRs in notification (only matching RegistrationInfo) — All CSRs in the tests carry a single information[] element, so per-element RegistrationInfo filtering (a multi-info CSR where only some information elements match) is never asserted.
  • [ ] [12.4] notification.lastSuccess updated on successful delivery — All CSR-sub tests use dead/example endpoints (failure path) or ftClient (dumped, not asserting lastSuccess); no test asserts lastSuccess is set on a successful CSR-sub delivery.
  • [ ] [12.4] Update CSR Sub: missing/invalid subscription Id URI → 400 BadRequestData — No PATCH on /csourceSubscriptions with a non-URI id asserting 400 BadRequestData.
  • [ ] [12.4] Update CSR Sub: invalid Subscription Fragment → 400 BadRequestData — No PATCH on /csourceSubscriptions with an invalid fragment (bad field type/value) asserting 400 BadRequestData; only valid PATCHes are tested.
  • [ ] [12.4] Update CSR Sub: non-existent subscription Id — No PATCH on /csourceSubscriptions with a syntactically valid but non-existent id asserting 404 ResourceNotFound.
  • [ ] [12.4] Retrieve CSR Sub: missing/invalid subscription Id URI → 400 BadRequestData — No GET on /csourceSubscriptions/{id} with a non-URI id asserting 400 BadRequestData.
  • [ ] [12.4] Query CSR Subs: pagination per 7.4.2 — No /csourceSubscriptions list test exercises limit/offset pagination or paging links/count.
  • [ ] [12.4] Delete CSR Sub: missing/invalid subscription Id URI → 400 BadRequestData — No DELETE on /csourceSubscriptions/{id} with a non-URI id asserting 400 BadRequestData.
  • [~] [12.4] Delete CSR Sub: deletes subscription and stops notifications — Delete returns 204 and the sub disappears from list/retrieve, but no test deletes a CSR-sub then triggers a matching CSR change and asserts NO further notification is sent.
  • [ ] [12.4] q over CSR Relationship — No CSR-sub test uses q over a CSR Relationship to verify match/non-match.
  • [ ] [12.4] q over CSR sub-attribute — No CSR-sub test uses q over a CSR sub-attribute path to verify match/non-match.

snapshots (39)

  • [ ] [16.2] Create Snapshot with both snapshotQueries and snapshotTemporalQueries — No test posts a single Snapshot document containing BOTH snapshotQueries and snapshotTemporalQueries; need to verify both lists execute and both Details arrays populate.
  • [ ] [16.2] createdAt and modifiedAt set to current system time — No snapshot GET response asserts createdAt/modifiedAt members at all (responses show only expiresAt + lastUsedAt); creation-time timestamp setting is unverified.
  • [~] [16.2] snapshotStatus initialized to 'preparation' — The async test only uses 'preparing' as a poll-loop sentinel; it never asserts the snapshot ever reported snapshotStatus=preparation/preparing in a response. No explicit assertion of the initial preparation state.
  • [~] [16.2] expiresAt set honoring snapshotLifetime within configured limit — expiresAt is masked with REGEX(.*) so the computed now+duration value (PT2H/P1D/etc.) is never actually checked; only the echoed snapshotLifetime is asserted.
  • [ ] [16.2] snapshotLifetime exceeding configured limit is capped — No test requests a snapshotLifetime larger than the system limit to verify expiresAt is capped to the configured maximum.
  • [ ] [16.2] Full pagination retrieval for paginated query results — No capture-time test uses a result set larger than one page to verify all pages are retrieved before storing; pagination is only tested on snapshot READ (snapshot_orderby_q.test).
  • [ ] [16.2] Output-only members provided by client are ignored — No test supplies output-only members (snapshotStatus, snapshotQueriesDetails, createdAt, modifiedAt, expiresAt) in the create body to verify they are ignored rather than honored.
  • [~] [16.2] BadRequestData when data types/cardinalities/restrictions not met — Type and snapshotLifetime restrictions yield 400, but generic data-type/cardinality violations (e.g. snapshotQueries not an array, malformed Query objects) are not specifically asserted.
  • [~] [16.2] BadRequestData when snapshotPriority out of range (not 1..10) — Out-of-range priority (11) is only tested via PATCH, not at CREATE; values 0, negative, and non-integer are untested at any operation.
  • [ ] [16.2] BadRequestData when id is not a valid URI — No test creates a Snapshot with a non-URI id (e.g. plain string) to verify BadRequestData.
  • [ ] [16.2] BadRequestData when endpoint is not a dereferenceable URI — No test creates a Snapshot with a malformed/non-URI endpoint to verify BadRequestData.
  • [ ] [16.2] BadRequestData on invalid JSON-LD / non-conforming document — No test posts a structurally invalid/non-conforming JSON-LD body (e.g. broken JSON, non-object) to /snapshots to verify BadRequestData.
  • [ ] [16.3] Wrong-typed member in Snapshot document -> 400 BadRequestData — No clone test sends a wrong-typed member (e.g. snapshotLifetime non-number, malformed endpoint, wrong-typed snapshotStatus) and asserts 400. Wrong-typed snapshotLifetime is tested only on create (snapshot_lifetime_duration.test), not on clone.
  • [ ] [16.3] Cardinality violation in Snapshot document -> 400 BadRequestData — No clone test exercises a cardinality violation (missing mandatory / duplicated single-cardinality member) on the clone body expecting 400.
  • [ ] [16.3] createdAt of clone set to current system time — No test GETs the clone with sysAttrs and asserts createdAt is fresh/current (not copied from source). Clone responses only assert Location + Content-Length 0.
  • [ ] [16.3] modifiedAt of clone set to current system time — No test asserts the clone's modifiedAt is set to current system time.
  • [ ] [16.3] snapshotStatus of clone initialized to preparation — No test GETs the clone immediately after creation to assert snapshotStatus='preparation'. Tests only observe terminal 'success' (and only for the create path in async_capture).
  • [ ] [16.3] expiresAt set from requested snapshotLifetime — No clone body specifies snapshotLifetime and asserts the clone's expiresAt reflects it. expiresAt-from-lifetime is only tested on the create path (snapshot_lifetime_duration.test).
  • [ ] [16.3] expiresAt clamped to configured system limit — No test (clone or create) requests a snapshotLifetime exceeding a configured limit and asserts expiresAt is clamped to that limit.
  • [~] [16.3] snapshotStatus transitions to success after successful copy — Cloned data is read back successfully (implying success), but no clone test GETs /snapshots/{cloneId} and asserts snapshotStatus='success' after the copy.
  • [ ] [16.3] snapshotStatus transitions to failure if copy fails — No test forces a clone background-copy failure and asserts snapshotStatus='failure' (the 'failure' status is asserted nowhere in the suite).
  • [~] [16.3] No snapshot notification when endpoint member absent — Clones in snapshot_lifecycle omit endpoint and no ftClient runs there, so no notification is implicitly sent; but there is no explicit ftClient assertion of zero notifications for an endpoint-less clone.
  • [~] [16.3] Clone is an independent copy decoupled from source — snapshot_temporal_lifecycle deletes the source (Src) and the clone (Dst) data survives independently, showing decoupling of stored rows; but no test mutates the source's captured data after cloning and asserts the clone is unchanged.
  • [ ] [16.4] Response includes createdAt DateTime when generated — No snapshot GET response asserts a createdAt member (snapshots have no createdAt/modifiedAt in any expect, and no ?options=sysAttrs variant is tested). If createdAt is mandated for Snapshot, add a GET (likely with sysAttrs) asserting createdAt is a valid DateTime.
  • [ ] [16.4] Response includes modifiedAt DateTime when generated — No snapshot GET response asserts a modifiedAt member; a PATCH (e.g. snapshotPriority change in snapshot_lifecycle) followed by a GET asserting modifiedAt reflects the update is missing.
  • [~] [16.4] Response echoes configured endpoint and receiverInfo — endpoint is echoed+asserted in snapshot_async_capture GET, but receiverInfo is only asserted as emitted notification HTTP headers (snapshot_notification), never asserted as a member of a retrieved Snapshot status body. Add a GET asserting receiverInfo is reflected in the status object.
  • [ ] [16.4] Missing Snapshot Id raises BadRequestData — No test of GET /snapshots/ with an absent id segment expecting 400 BadRequestData (the route inherently requires an id, so the empty-id path may be untestable/return 404; verify and add a test if a distinct 400 is mandated).
  • [~] [16.5] Updating snapshotLifetime indirectly updates expiresAt — PATCH snapshotLifetime=PT3H succeeds (204) and the GET shows snapshotLifetime updated, but expiresAt is masked with REGEX(.*) so the recomputed ~10800s value is never actually asserted to have changed; comment claims recompute but the test does not prove it.
  • [~] [16.5] Partial fragment: only provided members are modified — PATCH {snapshotPriority:9} is followed by a GET showing priority=9 while snapshotQueries/type are still present, which implicitly demonstrates patch semantics, but there is no explicit test that PATCHing one member (e.g. priority) leaves another independently-set member (e.g. a previously-set snapshotLifetime or endpoint) unchanged.
  • [ ] [16.5] modifiedAt updated on successful update — No test asserts a modifiedAt timestamp at all; GET responses show expiresAt/lastUsedAt but never modifiedAt, so the update-bumps-modifiedAt behaviour is unverified (and modifiedAt may not even be emitted).
  • [ ] [16.5] Missing or invalid Snapshot Id -> BadRequestData — No PATCH against a malformed (non-URI) snapshot id to assert 400 BadRequestData; only the well-formed-but-unknown id (404) case is covered.
  • [ ] [16.5] Invalid JSON / JSON-LD validation failure -> error — No PATCH with syntactically invalid JSON body (expect InvalidRequest 400) on the snapshots endpoint; only valid-JSON-bad-value cases are exercised.
  • [ ] [16.5] type member not equal to 'Snapshot' -> BadRequestData — wrong-type→400 is tested only on POST (snapshot_crud.test); no PATCH fragment with type!=Snapshot to verify the same 400 on update.
  • [ ] [16.5] endpoint not a dereferenceable/valid URI -> BadRequestData — No test PATCHes a malformed endpoint URI to assert 400 BadRequestData (endpoint is never updated nor validated on PATCH in any test).
  • [~] [16.5] @context handling for the Snapshot Fragment — All PATCH calls go through corCurl (application/json default) with core terms only; there is no application/ld+json PATCH with inline @context, and no Link-header @context variant, so dual content-type term-expansion on the fragment is not specifically exercised.
  • [ ] [16.5] Empty fragment / no updatable members — No PATCH with an empty body {} (or only a type member) to verify the implementation's defined outcome (no-op 204 success vs BadRequestData).
  • [ ] [16.6] Missing Snapshot id → 400 BadRequestData — No DELETE-with-missing-id → 400 assertion. In this broker DELETE /snapshots with no id routes to Purge Snapshots (204), so a 400 BadRequestData for a delete missing the id is not exercised; if the spec mandates 400 for the single-delete path, it is untested.
  • [ ] [16.6] Error-precedence: validity check before existence check — No test feeds an invalid-URI snapshot id to DELETE to prove 400 (BadRequestData) wins over 404 (ResourceNotFound); precedence is unverified because the invalid-URI 400 case (16.6-05) is itself missing.
  • [~] [16.6] Error responses are pure ProblemDetails JSON — 404 ResourceNotFound on DELETE is asserted as pure ProblemDetails (Content-Type application/json, type+title, no @context/Link). The 400 BadRequestData branch for delete is not covered (depends on 16.6-04/05), so the 400 error representation is unverified for the delete operation.

subscription (55)

  • [~] [10.5.2] EntitySelector by idPattern — idPattern is accepted/round-tripped and used in distributed-sub narrowing, but no local (non-distributed) subscription test creates entities:[{idPattern:...}] and asserts a matching entity fires while a non-matching id does NOT.
  • [ ] [10.5.2] watchedAttributes undergo Term-to-URI expansion — No test feeds a short watchedAttributes term under a custom @context and asserts it is expanded to the IRI (e.g. via mongoc/db dump or a matching-by-IRI notification). Term-to-URI expansion of watchedAttributes is unverified.
  • [ ] [10.5.2] jsonldContext present -> used as notification @context — No test sets jsonldContext to a (valid, downloadable) context distinct from the Subscription @context and asserts the delivered notification body/Link uses the jsonldContext vocabulary. Only invalid-jsonldContext rejection is tested.
  • [~] [10.5.2] Unavailable remote jsonldContext -> 503 LdContextNotAvailable — An unfetchable https jsonldContext is asserted, but the test expects 504 Gateway Timeout (title 'Context Not Available', type LdContextNotAvailable) — the spec/feature names 503 LdContextNotAvailable. Behaviour is exercised; the exact 503 status is not asserted (504 instead).
  • [ ] [10.5.2] Invalid remote jsonldContext -> 400 BadRequestData — No test serves a syntactically invalid downloadable @context via jsonldContext and asserts 400 BadRequestData. Only non-URL/URN jsonldContext (rejected before fetch) and unfetchable URL (504) are tested.
  • [~] [10.5.2] Change on watched Relationship triggers notification — A Relationship is rendered in a notification, but no test asserts that CHANGING a watched Relationship's object (PATCH) triggers a notification (only Property change is verified in subscription_triggers).
  • [ ] [10.5.2] Expiration auto-transitions status to 'expired' — No test lets a near-future expiresAt elapse and asserts status flips to 'expired' and notifications stop. subscription_expiration only checks future-expiry stays active and past-expiry is rejected at create.
  • [~] [10.5.2] splitEntities true (or default) drops q/geoQ/scopeQ and notification.attributes/pick/omit from forwarded copy — Filter/id narrowing of the forwarded copy is tested, but no test creates a sub carrying q/geoQ/scopeQ and notification.attributes/pick/omit and asserts those specific members are stripped from the forwarded derivative.
  • [ ] [10.5.2] Invalid JSON body -> 400 (InvalidRequest) — InvalidRequest on malformed JSON is tested for entities/queries (create_entity_errors.test etc.) but never for POST /subscriptions. No subscription test sends syntactically broken JSON and asserts 400 InvalidRequest (distinct from valid-JSON BadRequestData).
  • [~] [10.5.3] Update notification.attributes (notified attribute projection) — PATCH of notification.attributes is verified via GET only; no test drives a real notification after the PATCH to confirm the payload then carries only the listed attributes.
  • [~] [10.5.3] Update notification.format (normalized / concise / keyValues) — PATCH to notification.format=keyValues stored value verified via GET, but no test PATCHes the format then triggers a notification to confirm the payload representation actually switches; concise/normalized not PATCH-tested at all.
  • [~] [10.5.3] Update notification.endpoint (uri/accept/receiverInfo/notifierInfo) — Only endpoint.uri change is PATCH-tested (verified via GET, not by a delivered notification to the new URI). PATCH of endpoint.accept, receiverInfo, and notifierInfo (and that custom headers take effect) is untested.
  • [~] [10.5.3] Update q query filter — q is PATCHed and verified via GET (and delete-marker removes it), but no test PATCHes q then confirms notification matching follows the NEW expression (vs the geoQ test which does verify matching effect).
  • [ ] [10.5.3] Update scopeQ / csf / temporalQ / other filter fields — No PATCH test exercises scopeQ, csf, lang, timeInterval, or temporalQ updates; throttling is PATCH-tested (crud/patch_all_fields) but the other filter/control fields are only tested at create time, never via Update Subscription.
  • [~] [10.5.3] isActive=true with future expiresAt sets status=active — patch_all_fields PATCHes a future expiresAt (no isActive) and GETs status=active, but the specific {isActive:true, expiresAt:}->active combination is not directly asserted.
  • [ ] [10.5.3] Only future expiresAt on a non-expired sub does not force status to active — No test PATCHes only a future expiresAt onto a paused (non-expired) subscription to assert status is left unchanged (stays paused), i.e. the expired->active rule does not apply.
  • [~] [10.5.3] expiresAt in the past raises BadRequestData regardless of isActive — PATCH expiresAt-to-past->400 BadRequestData is covered for the isActive-absent case, but not with isActive:true and isActive:false in the same fragment to prove rejection is irrespective of isActive.
  • [ ] [10.5.3] JSON-LD validation failure raises BadRequestData (clause 8.2.3) — No PATCH test sends invalid JSON or a malformed @context structure to a subscription to assert 400 BadRequestData on update.
  • [~] [10.5.3] Fragment violating Subscription data types/restrictions raises BadRequestData — Only timeInterval+watchedAttributes conflict and raw-null-on-PATCH are asserted on update. Malformed notification, invalid geoQ geometry, bad timeInterval/throttling type, and invalid format value via PATCH are untested (those checks are asserted on create only, in subscription_errors.test).
  • [~] [10.5.3] jsonldContext referenced @context not available raises LdContextNotAvailable — LdContextNotAvailable (504) for an unreachable jsonldContext is asserted at CREATE only; not exercised via PATCH (Update Subscription).
  • [ ] [10.5.3] jsonldContext referenced @context invalid raises BadRequestData — No test references a retrievable-but-invalid @context via jsonldContext (on create or update) to assert 400 BadRequestData; only non-URL shapes and unreachable URLs are tested.
  • [ ] [10.5.3] @context provided via Link header (application/json body) — No PATCH /subscriptions test uses application/json with the @context supplied via the Link header and asserts attribute-name expansion using it.
  • [~] [10.5.3] @context provided inline (application/ld+json body) — A PATCH with --in jsonld and an inline core @context exists (step 08, expiresAt), proving ld+json bodies are accepted on update, but no PATCH uses a non-core inline @context to assert short attribute names actually expand via that context.
  • [~] [10.5.4] entities (EntitySelector[]) round-trips in retrieval — entities round-trip only ever asserts {type:...} (and type:"*"); no retrieve test asserts an EntitySelector carrying id or idPattern is preserved on GET
  • [ ] [10.5.4] scopeQ round-trips in retrieval — subscription_scopeq.test creates a sub with scopeQ and asserts notification matching, but never GETs the subscription to confirm scopeQ is returned/stored as set
  • [ ] [10.5.4] datasetId[] round-trips in retrieval — subscription_notif_datasetid.test sets datasetId (incl @none) and asserts notification filtering, but never GETs the subscription to verify the datasetId array round-trips on retrieve
  • [~] [10.5.4] timeInterval / throttling / isActive / subscriptionName / lang / other members round-trip — throttling and isActive round-trips are asserted on GET; timeInterval round-trip on an entity-subscription GET, and subscriptionName and lang round-trips, are not asserted (subscriptionName only appears as a delete-marker error case, lang not exercised on subscription retrieve)
  • [~] [10.5.4] Short attribute names returned compacted against the subscription/request @context — q attribute names are proven to re-compact per request @context, but entity-type compaction in the retrieved entities[] against a non-core user @context is not asserted (all retrieve tests use core-context type names like Vehicle/T)
  • [~] [10.5.4] BadRequestData (400) when subscription id is not a valid URI — http_invalid_uri_pathparam.test asserts 400 Invalid URI for DELETE /subscriptions/, but no test asserts the same 400 on GET /subscriptions/ (retrieve verb)
  • [~] [10.5.4] Tenant isolation: retrieving a subscription from the wrong tenant yields 404 — GET under the correct tenant (captn) returns 200, but no test attempts to retrieve a tenant-scoped subscription from a different/default tenant and asserts 404
  • [~] [10.5.4] Response content-type is application/ld+json (or application/json with Link) — the application/json + Link-header branch is thoroughly asserted (including per-context Link), but no retrieve test sends Accept: application/ld+json and asserts Content-Type: application/ld+json with an inline @context in the body
  • [ ] [10.5.5] limit URL parameter caps number of subscriptions returned — No test issues GET /subscriptions?limit=N with >N subscriptions and asserts the array is capped at N (entity-list pagination is tested in query_entities_pagination.test but never the subscriptions collection).
  • [ ] [10.5.5] limit=0 only allowed together with count — No test for GET /subscriptions?limit=0 (without count rejected) vs limit=0&count=true (allowed).
  • [ ] [10.5.5] offset URL parameter skips into the result set — No test issues GET /subscriptions?offset=N and asserts the listing skips the first N subscriptions.
  • [ ] [10.5.5] count=true with limit=0 returns count and empty array — No count-only test (count=true&limit=0) on the subscriptions list returning the count header plus an empty array.
  • [ ] [10.5.5] Pagination next-page Link header (rel=next) when more results pending — rel=next Link is tested for entity/registration listings but never for the paginated subscriptions list.
  • [ ] [10.5.5] Pagination previous-page Link header (rel=prev) on non-first pages — rel=prev Link (entitymap_paginate_prev_link.test for entities) is never exercised on the subscriptions list.
  • [ ] [10.5.5] Accept neither json nor ld+json returns 406 Not Acceptable — 406 Not Acceptable is tested for /entities and /info endpoints (accept_q_weighted.test, http_415_406_media_type.test) but never for GET /subscriptions.
  • [ ] [10.5.5] HEAD /subscriptions/ returns headers without body — No HEAD request against /subscriptions; all subscriptions-list calls are GET (the few HEAD-ish matches were POSTs).
  • [~] [10.5.5] Subscription sysAttrs (createdAt/modifiedAt) presence controlled per representation rules — Default list EXPECTs implicitly omit createdAt/modifiedAt but no test explicitly asserts the rule: sysAttrs absent by default and present only when options=sysAttrs is requested on GET /subscriptions.
  • [ ] [10.5.6] Delete NOT forwarded to Context Sources that don't support delete-subscription — No test registers a CSR advertising createSubscription but NOT deleteSubscription and verifies that deleting the parent subscription does not contact / does not delete the derived sub on that source (or simply isn't forwarded).
  • [~] [10.5.6] Local delete succeeds even when a forwarded CSR delete is unavailable/fails — Cascade tests use real reachable CP brokers that succeed; no test points the subordinate CSR at an unreachable/erroring endpoint to assert the local delete still returns 204 (best-effort forwarding).
  • [ ] [10.5.6] Missing/empty subscription id -> 400 BadRequestData — No test issues DELETE /ngsi-ld/v1/subscriptions/ (empty path segment) to assert a 400 BadRequestData; only routing/non-existence/invalid-URI cases exist.
  • [ ] [10.5.6] Tenant scoping of delete (NGSILD-Tenant) — tenant.test covers only entities. No test creates a subscription under NGSILD-Tenant t1 and verifies that deleting without/with-wrong tenant returns 404 while it persists under t1, and deleting with the correct tenant succeeds (204).
  • [~] [10.5.7] timeInterval notification includes all subscribed entities matching query/geoquery/scopeQuery — Periodic firing is asserted but no interval test combines q/geoquery/scopeQuery with multiple entities to prove the interval message includes exactly the matching set (not only changed ones).
  • [~] [10.5.7] timeInterval with no query/geoquery/scopeQuery includes all subscribed entities — pernot has only one matching entity; no interval test with several subscribed entities and no filters to assert ALL are included in the periodic notification.
  • [ ] [10.5.7] timeInterval entities filtered to attribute instances matching subscription datasetId — subscription_notif_datasetid covers datasetId filtering only for change-triggered notifications (no timeInterval); no interval+datasetId test exists.
  • [ ] [10.5.7] No periodic notification sent when no entities match — No interval-subscription test asserts that zero notifications are sent when no entities match at the interval tick.
  • [ ] [10.5.7] geoquery matches if any GeoProperty instance meets geospatial restriction — No subscription geoQ test creates an entity with multiple GeoProperty instances (multi-datasetId location) where only one satisfies the restriction; all geoQ tests use a single location instance.
  • [ ] [10.5.7] Context Source filter restricts included entities by origin Context Source — No subscription test defines a Context Source filter (csf) and asserts that only entities from the matching origin Context Source appear in the notification.
  • [~] [10.5.7] Received notification with mapped subscriptionId is copied (distributed/split-entities) — Redispatch test maps the received subscriptionId to the local sub and re-emits, but does not exercise the splitEntities=true copy-for-further-processing path explicitly (single source, no split).
  • [ ] [10.5.7] Split-entities: entities retrieved locally and from other Context Sources — No test exercises split-entities retrieval that pulls the notified entity locally and from additional Context Sources (excluding the originating source).
  • [ ] [10.5.7] Split-entities: retrieved entities merged with notification data member — No test asserts that locally/remotely retrieved entities are merged into the received notification's data member.
  • [ ] [10.5.7] Split-entities: non-matching entities removed from data member — No test asserts that after merge, entities not matching the local subscription's q/geoquery/scopeQuery are removed from the notification copy.
  • [ ] [10.5.7] q query matching over Relationship object triggers/filters notification — subscription_notify_q/q_operators only exercise q over Property values and observedAt/sub-attrs; no notification q test gates on a Relationship object (e.g. q=rel==urn:...).

temporal (107)

  • [~] [11.2.2] All input Attribute instances are added to the existing temporal evolution — Instance-append on update is verified via POST /temporal/entities/{id}/attrs (writes.test step 03/04), but not via the upsert path (POST /temporal/entities with existing id) which is what 11.2.2 specifies; the 'all instances appended not replaced' assertion for the upsert collection endpoint is missing.
  • [ ] [11.2.2] Existing type list unchanged when no new types supplied — No test asserts the type list is left unchanged on an upsert that omits type or repeats existing types.
  • [~] [11.2.2] GeoProperty temporal instances accepted — A GeoProperty supplied as an array of temporal instances is POSTed (geoq.test step 05) but the create response and stored GeoProperty shape are not directly asserted (payload piped to /dev/null; only verified indirectly via a geoquery match). No direct round-trip GET of the GeoProperty temporal instances.
  • [ ] [11.2.2] Simplified temporal representation accepted — format=temporalValues is only tested as a GET output format (values_format.test); no test POSTs an EntityTemporal in the Simplified temporal representation as input and verifies it is accepted and stored equivalently to normalized.
  • [ ] [11.2.2] Sub-attributes on temporal instances preserved — No temporal-create test includes Attribute instances carrying sub-attributes (e.g. unitCode or nested Property metadata) and verifies they round-trip with the instance.
  • [ ] [11.2.2] JSON-LD @context from body honoured for term expansion — No temporal-create test supplies a non-default inline or referenced @context that maps short names to custom IRIs and verifies expansion; temporal_create_errors uses the core context only on error paths.
  • [ ] [11.2.2] @context supplied via Link header — No temporal-create test sends an application/json body with a Link-header @context and verifies the upsert succeeds with Link-header-based expansion.
  • [ ] [11.2.2] urn:ngsi-ld:null as first-level member value raises BadRequestData — No temporal-create test uses urn:ngsi-ld:null as a first-level member value and asserts 400 BadRequestData.
  • [ ] [11.2.2] urn:ngsi-ld:null as Property value raises BadRequestData — No temporal-create test uses urn:ngsi-ld:null as a Property value and asserts 400 BadRequestData (deleted_kinds.test uses the sentinel only via regular PATCH delete-markers, not as a rejected temporal-create value).
  • [ ] [11.2.2] urn:ngsi-ld:null as Relationship object raises BadRequestData — No temporal-create test uses urn:ngsi-ld:null as a Relationship object and asserts 400 BadRequestData.
  • [ ] [11.2.2] Exclusive forward error → complete failure surfaces as error — No test covers an exclusive upsertTemporal forward where the endpoint errors and the whole operation fails, asserting error propagation.
  • [ ] [11.2.2] Exclusive forward partial success → 207-style partial result — No test covers partial success on an exclusive forwarded upsertTemporal operation.
  • [ ] [11.2.2] Exclusive reg not supporting upsert temporal → Conflict on complete failure — No test covers an exclusive registration not supporting upsertTemporal yielding 409 Conflict on complete failure.
  • [ ] [11.2.2] Redirect forward error → complete failure surfaces as error — No test covers a redirect upsertTemporal forward error producing a complete-failure error response.
  • [ ] [11.2.2] Redirect reg not supporting upsert temporal → Conflict on complete failure — No test covers a redirect registration not supporting upsertTemporal yielding 409 Conflict.
  • [ ] [11.2.2] DistOp processing order exclusive → redirect → inclusive then local — Only the inclusive leg is exercised; no test mixes exclusive+redirect+inclusive registrations on upsertTemporal to verify processing order and what remains for local handling.
  • [~] [11.2.2] Local create after distop removal of forwarded attributes — Inclusive mode keeps data locally AND forwards (verified), but the exclusive/redirect case where forwarded attrs are removed and only the remaining attrs are created locally is not tested.
  • [~] [11.2.2] Tenant-scoped upsert via NGSILD-Tenant — Tenant isolation for temporal data is verified, but the seeding is done via POST /entities (current-state path), not via POST /temporal/entities; an explicit tenant-scoped upsert directly through the temporal-create endpoint with default-tenant isolation assertion is missing.
  • [ ] [11.2.3] Add a new Relationship instance (type Relationship) — Relationship is only added via the CREATE endpoint (troe_timescale_temporal_post_attr_kinds.test); no POST /temporal/entities/{id}/attrs test adds a Relationship instance and reads back object/observedAt.
  • [ ] [11.2.3] Add a new GeoProperty instance (type GeoProperty) — No append test (POST /attrs) adds a GeoProperty instance; GeoProperty temporal coverage exists only via create/query/geoq tests, not the add-attrs operation.
  • [ ] [11.2.3] Add a new LanguageProperty instance (type LanguageProperty) — LanguageProperty is exercised only on CREATE (troe_timescale_temporal_post_attr_kinds.test); no add-attrs test adds a LanguageProperty and reads back its languageMap.
  • [ ] [11.2.3] Add a new JsonProperty / VocabProperty / ListProperty / ListRelationship instance — None of the extended attribute types are added via POST /temporal/entities/{id}/attrs in any test; append payloads only use Property.
  • [ ] [11.2.3] Sub-attributes (metadata) of an added instance are stored — No add-attrs test includes sub-attributes (e.g. unitCode or a Property-of-Property) on the appended instance and verifies persistence; appended instances carry only value+observedAt.
  • [ ] [11.2.3] New Entity Type names in Fragment are merged into the temporal entity type list — No test posts a Fragment with a new 'type' to /temporal/entities/{id}/attrs and verifies the new Entity Type name is merged into (and existing types preserved in) the temporal entity's type list.
  • [~] [11.2.3] Term expansion applied to attribute and type names per 8.2.4 — Append uses default-context short names (speed/color) which the GET read-back strips from the default-context IRI, so basic expansion is implicitly exercised, but no add-attrs test uses a custom @context term that expands to a non-default IRI and asserts the stored expanded attribute identity.
  • [ ] [11.2.3] @context supplied inline (application/ld+json body) — No add-attrs (POST /temporal/entities/{id}/attrs) test sends an application/ld+json body with an inline @context.
  • [ ] [11.2.3] @context supplied via Link header (application/json body) — No add-attrs test supplies the @context via the Link header on the append operation.
  • [ ] [11.2.3] Entity ID not a valid URI → BadRequestData (400) — Invalid-URI entityId is tested only on CREATE (temporal_create_errors.test); no add-attrs test posts to /temporal/entities/{invalidId}/attrs expecting 400 BadRequestData.
  • [ ] [11.2.3] Invalid JSON payload body → InvalidRequest (400) — No add-attrs test posts a malformed-JSON body expecting 400 InvalidRequest.
  • [ ] [11.2.3] Syntactically incorrect / structurally invalid NGSI-LD content → BadRequestData (400) — No add-attrs test posts a structurally invalid fragment (e.g. malformed value object / bad attribute structure) expecting 400 BadRequestData.
  • [ ] [11.2.3] urn:ngsi-ld:null as a first-level member value → BadRequestData (400) — No add-attrs test uses urn:ngsi-ld:null as a first-level member value expecting 400 BadRequestData on the temporal append path.
  • [ ] [11.2.3] urn:ngsi-ld:null as Property value / Relationship object / @none languageMap → BadRequestData (400) — No add-attrs test uses urn:ngsi-ld:null as a Property value / Relationship object / languageMap @none on the temporal append path expecting 400.
  • [ ] [11.2.3] Exclusive registration match → matching attrs forwarded — Only an inclusive registration is tested for appendAttrsTemporal; no exclusive-mode temporal append test asserting matching attrs are forwarded and removed from local processing.
  • [ ] [11.2.3] Exclusive registration not supporting the operation → Conflict (409) — No test exercises an exclusive temporal-append match whose registration lacks appendAttrsTemporal, expecting 409 Conflict on complete failure.
  • [ ] [11.2.3] Redirect registration match → matching attrs forwarded — No redirect-mode temporal append (appendAttrsTemporal) distop test exists; only inclusive is covered.
  • [ ] [11.2.3] Redirect registration not supporting the operation → Conflict (409) — No test exercises a redirect temporal-append match whose registration lacks appendAttrsTemporal, expecting 409 Conflict on complete failure.
  • [~] [11.2.3] Local processing of remaining attrs alongside forwarding (mixed/partial success) — Inclusive fan-out is verified on CP1, but the entity also exists locally only because of the upsert fan-out; no test mixes attrs that are partly handled locally and partly forwarded and asserts a combined local+remote outcome (partial-success) specifically for appendAttrsTemporal.
  • [~] [11.2.4] Term expansion of target attribute name via @context — Short name 'color' is expanded against the core/default context (implicit), but no test deletes via a short name whose IRI differs from the default-context expansion to prove expanded-IRI targeting; only the trivial default-context case is exercised.
  • [ ] [11.2.4] Optional JSON-LD @context used for expansion — No test supplies a custom @context (Link header) mapping the short attr name to a non-default IRI and verifies the temporal delete-attr targets that IRI.
  • [~] [11.2.4] deleteAll=true removes all instances regardless of datasetId — deleteAll=true is exercised (step 05) but only against an attr with default-only / no datasetId instances; it does not seed both a default AND datasetId-bearing instance and assert ALL are removed regardless of datasetId.
  • [ ] [11.2.4] Missing/absent Entity ID -> 400 BadRequestData — No temporal delete-attr test for an absent entity id path asserting 400 BadRequestData (likely routed as 404/405 in practice but untested for this op).
  • [ ] [11.2.4] Invalid target Attribute name -> 400 BadRequestData — No temporal DELETE /attrs/{attr} test with an invalid attribute name asserting 400 BadRequestData.
  • [ ] [11.2.4] datasetId given but no matching instance -> 404 ResourceNotFound — No temporal DELETE /attrs/{attr}?datasetId= test asserting 404 ResourceNotFound; datasetId-no-match 404 is only covered for GET (datasetid.test step 07), not delete.
  • [~] [11.2.4] Forward only if registration supports the operation — The inclusive reg lists deleteAttrsTemporal among supported operations and forwarding occurs, but no negative case proves a reg that does NOT list deleteAttrsTemporal is skipped for forwarding.
  • [ ] [11.2.4] Matched registration does not support op, partial -> partial success — No partial-success (207) test for temporal delete-attr where some part succeeds and an unsupported reg fails.
  • [~] [11.2.4] Local exists AND inclusive regs match -> both processed — The inclusive distop test fans out to CP1 and verifies CP1 (remote) state, but it does not explicitly assert the LOCAL CB temporal store was also updated by the deleteAttrs=true op; combined local+remote is only proven for the entity-level delete, not unambiguously for the attr-level delete.
  • [ ] [11.2.5] Optional @context in body (JSON-LD) applied — No instance-modify test supplies an inline @context in the body to verify short-name term expansion of the target attribute.
  • [ ] [11.2.5] Optional @context via Link header applied — No instance-modify test supplies the @context via a Link header (application/json) to verify term expansion.
  • [~] [11.2.5] Term expansion of target Attribute name per clause 8.2.4 — Short name 'speed' resolves and modifies, but no case proves a short name and its fully-expanded IRI both target the same attribute instance.
  • [ ] [11.2.5] Modify instance of a Relationship — No test modifies a Relationship-type attribute instance (new object) by instanceId.
  • [ ] [11.2.5] Modify instance of a GeoProperty — No test modifies a GeoProperty-type attribute instance (new geometry) by instanceId.
  • [ ] [11.2.5] Missing Entity ID -> 400 BadRequestData — No test exercises a missing Entity ID on the instance-modify path expecting 400.
  • [ ] [11.2.5] Missing target Attribute name -> 400 BadRequestData — No test exercises a missing attribute name on the instance-modify path expecting 400.
  • [ ] [11.2.5] Matched registration not supporting the operation, complete failure -> 409 Conflict — No test where an exclusive/redirect reg lacks updateAttrInstanceTemporal and the whole op fails, asserting 409 Conflict.
  • [ ] [11.2.5] Matched registration not supporting the operation, partial success -> 207 — No test asserting partial-success 207 when the matched reg cannot do the op.
  • [~] [11.2.6] Attribute instance and ALL its child elements are deleted — Deleted instance has only value+observedAt; no test deletes an instance carrying sub-attributes and asserts the children are gone too.
  • [ ] [11.2.6] Delete a Relationship attribute instance — No test deletes a Relationship-type temporal instance by instanceId and verifies the object instance is removed.
  • [ ] [11.2.6] Delete a GeoProperty attribute instance — No test deletes a GeoProperty-type temporal instance by instanceId.
  • [ ] [11.2.6] Optional @context provided via Link header — No instance-delete test supplies a Link/@context to expand the attribute short name in the path.
  • [~] [11.2.6] Term expansion applied to attribute name (short name -> expanded IRI) — Path uses core short name 'speed' which is expanded by default context, but no test proves an aliased/custom short name expands to the correct IRI before matching.
  • [ ] [11.2.6] Attribute name not a valid name -> 400 BadRequestData — No test sends an invalid attribute name in the instance-delete path expecting 400 BadRequestData.
  • [~] [11.2.6] Unknown target Entity (no local entity + no matching registration) -> 404 ResourceNotFound — 404 is returned for re-delete of a gone instance, but no test targets a completely unknown entity id on the instance endpoint and asserts 404 ResourceNotFound title.
  • [ ] [11.2.6] Entity exists locally but does not contain the target Attribute -> 404 ResourceNotFound — No test deletes an instance of an attribute that the (existing) entity does not have, expecting 404 ResourceNotFound.
  • [~] [11.2.6] Attribute exists but no instance with the specified instanceId -> 404 ResourceNotFound — Step 07 re-deletes an already-removed instanceId and gets 404 (status only, head -1); the ProblemDetails title 'ResourceNotFound' is not asserted, nor a same-attr unknown-instanceId case.
  • [ ] [11.2.6] Exclusive registration match: operation supported -> input forwarded, no further local processing — Only an inclusive registration is tested; no exclusive-mode forward of the delete-instance op (no local processing) is asserted.
  • [ ] [11.2.6] Redirect registration match: operation supported -> input forwarded, no further local processing — No redirect-mode registration test for the delete-instance op.
  • [ ] [11.2.6] Exclusive/redirect match but operation NOT supported, complete failure -> 409 Conflict — No test for a matching exclusive/redirect registration lacking deleteAttrInstanceTemporal yielding 409 Conflict.
  • [ ] [11.2.7] Missing target Entity ID raises BadRequestData — No test issues DELETE /temporal/entities (no/empty id segment) expecting 400 BadRequestData; routing likely yields 404/405 instead - needs an explicit case.
  • [~] [11.2.7] Unknown entity (no local entity, no matching registration) raises ResourceNotFound — writes.test step 09 deletes an already-gone entity and asserts only the 404 status line; it does not assert ProblemDetails type=ResourceNotFound. Add a delete of a never-existed id asserting the full ResourceNotFound ProblemDetails body.
  • [ ] [11.2.7] Exclusive/redirect match: no further processing after forwarding — No exclusive/redirect temporal-delete test, so the 'no further local processing' semantics after forwarding are unverified.
  • [ ] [11.2.7] Forwarded delete to multiple matching exclusive/redirect registrations — No test forwards a temporal delete to more than one matching exclusive/redirect registration endpoint.
  • [ ] [11.2.7] Operation unsupported by matched registration, complete failure: Conflict — No test where a matched registration lacks deleteTemporal and the whole op fails, asserting 409 Conflict.
  • [~] [11.2.7] Local deletion combined with inclusive forwarding — The inclusive test verifies the CP1 (remote) side becomes 404 after delete but does not also assert the LOCAL CB copy was removed (no GET on CB after step 07), so the 'both effects together' assertion is incomplete.
  • [ ] [11.3.2] Entity ID not a valid URI -> BadRequestData — No temporal-GET test supplies a non-URI id (e.g. /temporal/entities/not_a_uri) to assert 400 BadRequestData / invalid URI.
  • [~] [11.3.2] attrs projection: multiple attribute names — attrs=single is asserted (step 03) but no temporal GET asserts a multi-name attrs=a,b returning exactly those two attribute series.
  • [~] [11.3.2] attrs term-to-URI expansion via @context — attrs/pick/omit expansion is only exercised under the core/default context; no temporal GET supplies a custom Link @context with a prefix or aliased term to prove attrs expansion to a non-default IRI.
  • [ ] [11.3.2] pick/omit including special members id/type/scope — pick/omit are only tested with attribute names; no temporal GET asserts pick=id|type|scope or omit=id|type|scope behaviour.
  • [~] [11.3.2] JSON-LD @context via Link header applied to response/expansion — Responses carry the core-context Link, but no temporal GET supplies a custom @context via Link header to prove that header context drives attrs/pick/omit expansion and response compaction.
  • [~] [11.3.2] Temporal representation of GeoProperty attribute — GeoProperty value survives the temporal path (geo_shapes step 05) but it is seeded without observedAt and rendered as a single value object, not as a temporal instance array with timestamp; geoq uses location only for filtering and strips it from the response, so a GeoProperty instance array with geo value + timestamp is never asserted.
  • [~] [11.3.2] Distributed retrieve: forward to exclusive/redirect/inclusive sources and merge — Single-entity temporal retrieve merge is proven only for inclusive mode; no test covers exclusive or redirect CSRs on the retrieveTemporal path.
  • [~] [11.3.2] Entity known only via registration (no local data) still retrievable — The query path returns a remote-only entity (urn:V3 only on CP1), but no single-entity GET /temporal/entities/{id} test retrieves an entity that has zero local data and exists only behind a registration.
  • [ ] [11.3.2] Entity Map: return-map flag yields Entity Map location — No temporal retrieve test exercises the return-Entity-Map flag or asserts an NGSILD-EntityMap header / map location.
  • [~] [11.3.3] Restriction satisfied by attrs with a non-system attribute — attrs=speed is exercised with timerel, but no test isolates attrs (non-system) as the SOLE restriction to prove it satisfies the at-least-one rule (every attrs case also carries type or single-id).
  • [~] [11.3.3] Restriction satisfied by q with a non-system attribute — q=speed>20 is always combined with type=Vehicle; no test proves q alone (no type/attrs) satisfies the restriction.
  • [ ] [11.3.3] q referencing only system attributes does not satisfy restriction -> BadRequestData — No test sends a temporal query whose only restriction is q over a system attr (e.g. q=createdAt>...) without a type/attrs selector and asserts 400.
  • [~] [11.3.3] Restriction satisfied by GeoQuery — All geoq steps also pass type=Vehicle, so geoquery is never shown as the SOLE restriction satisfying the at-least-one rule.
  • [ ] [11.3.3] Syntactically invalid context source filter -> BadRequestData — csf is not exercised at all on the temporal entity query; no invalid-csf 400 test.
  • [~] [11.3.3] orderBy by id with local scope succeeds and orders result — orderBy=id&local=true returns 200 but against an empty DB ([]), so the actual ordering of results is never asserted.
  • [ ] [11.3.3] Aggregation method not eligible for an attribute -> InvalidRequest — nonnumeric test shows ineligible methods emit EMPTY arrays (avg on String => []), it does NOT assert the spec-mandated 400 InvalidRequest when an attribute is eligible for none of the requested methods.
  • [~] [11.3.3] Term-to-URI expansion of type and attribute names — Default-context expansion is implicit (short names work, response keys are expanded IRIs stripped in python), but no test supplies a custom @context to prove term expansion of a non-core type/attr name in a temporal query.
  • [ ] [11.3.3] @context reference honoured for expansion — No temporal query test supplies a Link @context to drive term/attr/value expansion.
  • [ ] [11.3.3] Filter by idPattern regex — idPattern is only mentioned in a comment in query.test; no actual idPattern request/assertion exists.
  • [ ] [11.3.3] q over Relationship object — No temporal query test runs q against a Relationship object within the interval.
  • [ ] [11.3.3] q over sub-attribute path — No temporal query test uses a q sub-attribute path (attr.sub) over interval instances.
  • [ ] [11.3.3] q with equality operator — Temporal q only tested with > ; no == over interval instances.
  • [ ] [11.3.3] q with inequality operator — No temporal q with != operator.
  • [~] [11.3.3] q with relational operators (>, <, >=, <=) — Only > is tested in the temporal context; <, >=, <= over interval instances are untested.
  • [ ] [11.3.3] q with range operator — No temporal q range (min..max).
  • [ ] [11.3.3] q with value-list operator — No temporal q comma value-list.
  • [ ] [11.3.3] q with pattern-match operator (~=) — No temporal q ~= / !~= over interval instances.
  • [ ] [11.3.3] q with existence/non-existence check — No temporal q attribute existence/non-existence check.
  • [ ] [11.3.3] q with logical AND / OR — No temporal q compound ; (AND) / | (OR) expression.
  • [ ] [11.3.3] geoquery georel=within — georel=within (polygon) is not exercised on the temporal query (only near).
  • [~] [11.3.3] Pagination logic (offset/Link headers/count) — Entity-level offset=1 verified and instance-level interval Link pointers verified, but entity-level next/prev Link headers and the NGSILD-Results-Count total-count header (count=true) are not asserted for the temporal query.
  • [ ] [11.3.3] Context source filter (csf) used in discovery — csf is not exercised on the temporal entity query / discovery path.
  • [ ] [11.3.3] Auxiliary CSR merge only fills missing timeproperty instances — No temporal test exercises an auxiliary CSR whose data fills only timeproperty-instance gaps not already present locally.
  • [ ] [11.3.3] Split-entities flag removes filters before forwarding and re-applies after aggregation — No temporal distop test exercises the split-entities path (strip q/geoquery/scope/attrs before forward, re-apply after aggregation).