From 9f24fe3af94f65eb3102485f17e67dc0800fc825 Mon Sep 17 00:00:00 2001 From: kzangeli Date: Fri, 29 May 2026 00:26:50 +0200 Subject: [PATCH 1/3] test-infra: 2 small housekeeping fixes (missing var, missing fixture mapping) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two independent test-side issues, each preventing one or a few tests from reaching the broker: - 038_05.robot: add the standard `${date_format}` variable, copying the convention from sibling 046_07/11. - jsonldContext.resource: add missing `${ERROR_TYPE_RESOURCE_NOT_FOUND}` mapping so 053_03_01 / 051_04_02 / 051_04_03 resolve their assertion. Documented as testsuite-doubts.md #78 with per-item subsections (78a, 78b). Verified: each affected test now passes against swBroker. (MR-review feedback 2026-05-30: original bundle had three more items — almostFull compaction in 001_05/003_05, notificationTrigger ignore in 038_01/040_01, Library DateTime in Common.resource. All three pulled after deeper analysis: the first two are broker-side bugs to file separately; the DateTime case is likely an env-delta on the reporter side. Notes inline in testsuite-doubts.md #78.) --- .../038_05.robot | 1 + resources/ApiUtils/jsonldContext.resource | 1 + testsuite-doubts.md | 38 +++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/TP/NGSI-LD/ContextSource/RegistrationSubscription/CreateContextSourceRegistrationSubscription/038_05.robot b/TP/NGSI-LD/ContextSource/RegistrationSubscription/CreateContextSourceRegistrationSubscription/038_05.robot index 63711cf7..28b117a6 100644 --- a/TP/NGSI-LD/ContextSource/RegistrationSubscription/CreateContextSourceRegistrationSubscription/038_05.robot +++ b/TP/NGSI-LD/ContextSource/RegistrationSubscription/CreateContextSourceRegistrationSubscription/038_05.robot @@ -12,6 +12,7 @@ Suite Teardown Delete Created Context Source Registration Subscriptions *** Variables *** ${subscription_payload_file_path}= csourceSubscriptions/subscription-expiresAt.jsonld +${date_format}= %Y-%m-%dT%H:%M:%SZ *** Test Cases *** diff --git a/resources/ApiUtils/jsonldContext.resource b/resources/ApiUtils/jsonldContext.resource index 17cfa1ed..89f77326 100644 --- a/resources/ApiUtils/jsonldContext.resource +++ b/resources/ApiUtils/jsonldContext.resource @@ -17,6 +17,7 @@ ${response} ${EMPTY} ${ERROR_OPERATION_NOT_SUPPORTED} https://uri.etsi.org/ngsi-ld/errors/OperationNotSupported ${ERROR_TYPE_BAD_REQUEST_DATA} https://uri.etsi.org/ngsi-ld/errors/BadRequestData +${ERROR_TYPE_RESOURCE_NOT_FOUND} https://uri.etsi.org/ngsi-ld/errors/ResourceNotFound *** Keywords *** diff --git a/testsuite-doubts.md b/testsuite-doubts.md index e637472f..b8bacbc9 100644 --- a/testsuite-doubts.md +++ b/testsuite-doubts.md @@ -2428,3 +2428,41 @@ keywords in the file. **Verified:** with the one-line fix both tests pass **Fix wanted:** swap the assertion to `ERROR_TYPE_INVALID_REQUEST`. One-line change. **Status:** RESOLVED — fixed in this MR. + +## 78. Test-infra housekeeping bundle: missing keywords, variables, fixture cleanups + +Two small, independent test-suite issues that each prevented one or a few +tests from reaching the broker. Bundled into one MR for low-noise review. + +**78a) `038_05_01` — undefined `${date_format}` variable** + +`038_05.robot` referenced `${date_format}` in its body but had no +corresponding Variables-section entry. **Fix:** added the standard +`%Y-%m-%dT%H:%M:%SZ` definition in that file's Variables section, matching +sibling test files (`046_07/11`). + +**78b) `053_03_01 / 051_04_02 / 051_04_03` — `Variable '${ERROR_TYPE_RESOURCE_NOT_FOUND}' not found`** + +`${ERROR_TYPE_RESOURCE_NOT_FOUND}` was defined in some resource files but not +in `resources/ApiUtils/jsonldContext.resource` (which the three failing tests +use exclusively). **Fix:** added the standard mapping +`https://uri.etsi.org/ngsi-ld/errors/ResourceNotFound` to that file's +Variables section, alongside the existing `ERROR_TYPE_BAD_REQUEST_DATA`. + +**Status:** RESOLVED — both items fixed in this MR. + +**Items removed from the original bundle after MR review (2026-05-30):** + +- `001_05_02 / 003_05_02 almostFull` — broker-side bug (@vocab over-stripping + when the user @context defines the same short name to a different IRI). + The expected `ngsi-ld:default-context/almostFull` form is correct per the + JSON-LD compaction algorithm. Filed as a broker issue. +- `038_01_01 / 040_01_01 notificationTrigger` — broker-side bug. TS + 104-175 § 5.2 Subscription table is explicit: `notificationTrigger` + *"is not applicable and shall be ignored if the Subscription data type + is used for a Context Source Registration Subscription"*. The broker + shouldn't be auto-populating it on CSR subs; filed separately. +- `021_15_* / 029_10_01 DateTime keyword resolution` — likely env-delta + on the reporter side (Robot 7.4.1 / Python 3.14.4) rather than a + genuinely missing import; the tests have been passing on Forge CI for + years. Pulled from the MR pending re-verification on a clean checkout. -- GitLab From b7083557f885e6494983fb71c496351e13bec505 Mon Sep 17 00:00:00 2001 From: kzangeli Date: Sun, 31 May 2026 21:44:58 +0200 Subject: [PATCH 2/3] fix(HttpCtrl): Set Stub Reply must not re-encode an already-serialized body MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mock-server stub-reply helper unconditionally called json.dumps() on the body argument. Most Robot tests in the suite (D011_02_red, D011_03_inc, D011_04_inc, D011_01_aux, etc.) build the body via `Load Entity As Serialized Array`, which already calls `Convert JSON To String` and returns a JSON-encoded string. The unconditional dump then double-encoded that string into an escaped JSON string-of-a-string (e.g. `"[{\\"id\\":...}]"`), and the broker under test failed to parse the entity payload coming back from the mocked CSR. Skip the dump when the body is already str/bytes (or None). Pre- serialized callers now get their string through verbatim; callers that pass a Python dict/list still get the dump. Also adds testsuite-doubts.md entries: #79 D011_02_exc_01 — mock stub URL uses deprecated `attrs=` param; broker forwards `pick=` per v1.9 § 5.7.2 / § 6.3.2 #80 046_22_08 — `deleteAll=${true}` serializes to capital-T "True"; broker correctly rejects per NGSI-LD § 4 / RFC 3986 #80b Create Subscription And Entity keyword default-arg bugs causing every caller to use literal id `urn:ngsi-ld:Building:None` Co-Authored-By: Claude Opus 4.7 --- .../src/HttpCtrl/__init__.py | 4 +- testsuite-doubts.md | 126 ++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py b/libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py index d37c89de..a4c1658f 100755 --- a/libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py +++ b/libraries/robotframework-httpctrl/src/HttpCtrl/__init__.py @@ -1118,7 +1118,9 @@ class Server: raise AssertionError(message_error) criteria = HttpStubCriteria(method=method, url=url) - response = Response(int(status), None, json.dumps(body), None, None) + if not isinstance(body, (str, bytes)) and body is not None: + body = json.dumps(body) + response = Response(int(status), None, body, None, None) HttpStubContainer().add(criteria, response) def get_stub(self, method, url): diff --git a/testsuite-doubts.md b/testsuite-doubts.md index b8bacbc9..a20cc20c 100644 --- a/testsuite-doubts.md +++ b/testsuite-doubts.md @@ -2466,3 +2466,129 @@ Variables section, alongside the existing `ERROR_TYPE_BAD_REQUEST_DATA`. on the reporter side (Robot 7.4.1 / Python 3.14.4) rather than a genuinely missing import; the tests have been passing on Forge CI for years. Pulled from the MR pending re-verification on a clean checkout. + +## 79. `D011_02_exc_01` — mock stub URL keys on `attrs=` but broker forwards `pick=` + +**Files:** +- `TP/NGSI-LD/DistributedOperations/Consumption/Entity/QueryEntities/D011_02_exc.robot` + +**Symptom:** broker query forward returns 200 with the entity skeleton but +no `speed` attribute; `Should Have Value In Json $.speed` fails. + +**Cause:** the test sets the CSR mock stub URL to +`${url}?type=Vehicle&id=${entity_id}&attrs=speed` and only replies with the +speed-bearing payload when that exact URL is hit. The broker forwards the +query with `pick=speed` (the current-spec attribute-projection parameter, +since `attrs=` is the deprecated v1.6 form). The stub URL doesn't match, so +the mock returns its default empty reply and the assertion fails. + +This was found on swBroker, where the @vocab over-stripping bug previously +masked the issue by causing a different failure mode upstream. Once the +broker bug was fixed, the stub-URL mismatch surfaced. + +All NGSI-LD payloads in this test use the same compound test-suite context +(`ngsi-ld-test-suite-compound.jsonld`), so the parameter mismatch is purely +`attrs` vs `pick`, not a context-resolution issue: + +- entity create — `vehicle-simple-attributes.jsonld` carries the compound context +- CSR registration — same compound context, `propertyNames:["speed"]` +- query — `context=${ngsild_test_suite_context}` resolves to the same URL +- mock stub reply (`vehicle-speed-attribute.json`) has no `@context` at all + +**Fix:** change the stub URL in the `GET` branch to use `pick=speed` +instead of `attrs=speed`. Check `D011_02_red_01` / `D011_02_inc_01` and +any other sibling that builds stub URLs from `attrs=` for the same pattern. + +**Spec angle:** § 5.7.2 (Query Entities) and § 6.3.2 list `pick` and `omit` +as the projection parameters; `attrs=` is not in the v1.9 parameter table. +The spec could be clearer that distributed-operation forwards must +translate any legacy `attrs=` from a 1.6-era CSR into `pick=` so that mock +test stubs written against the modern spec match the forwarded URL. + +## 80. `046_22_08` — `deleteAll=${true}` serializes as `deleteAll=True` (capital T) + +**Files:** +- `TP/NGSI-LD/ContextInformation/Subscription/SubscriptionNotificationBehaviour/046_22_08.robot` + +**Symptom:** broker returns 400 BadRequestData on the DELETE attribute +call: +``` +"detail": "'deleteAll' must be 'true' or 'false' (lowercase); got 'True'" +``` + +**Cause:** the test passes `deleteAll=${true}` (Robot Framework boolean +literal) to the `Delete Entity Attributes` keyword. The keyword in +`ContextInformationProvision.resource:248` appends it to the URL as +`deleteAll=${true}` → which Robot serializes to the string `"True"` +(capital T). The broker correctly rejects this per the strict-case URL +parameter rule. + +NGSI-LD § 4 and RFC 3986 § 6.2.2.1 both require URL parameter values to +be case-sensitive; the spec uses the literal lowercase tokens `true` / +`false` everywhere. swBroker enforces this strictly (parseBool in +`ldUrlParams.c`); accepting `True` / `TRUE` / etc. would be a silent +deviation from the spec. + +All ten sibling tests `046_22_01`..`046_22_07`/`09`..`11` pass +`deleteAll=${EMPTY}` (omit the parameter entirely), so this is a +one-off bug isolated to `046_22_08`. + +**Fix:** change `deleteAll=${true}` to the literal string `deleteAll=true` +in `046_22_08.robot:30`. The keyword's existing serialization will then +produce the lowercase form the broker (and the spec) expect. + +**Related:** when this is fixed, the test will progress past the URL-param +rejection and into the actual notification-trigger logic — which is what +the test is intended to exercise. The current 400 short-circuits the +whole assertion. + +**80b) `Create Subscription And Entity` keyword — `${entity_id_suffix}=None` default never falls through to `Generate Random Building Entity Id`** + +The trace for 046_22_08 (and all sibling 046_22_* tests) shows the +entity URL as `urn:ngsi-ld:Building:None` — a literal "None" suffix +rather than the intended random-uuid. Source in +`resources/SubscriptionUtils.resource:14`: + +```robot +[Arguments] ${subscription_payload_file_path} ${building_filename} ${entity_id_suffix}=None + +IF '${entity_id_suffix}' == None + ${entity_id}= Generate Random Building Entity Id +ELSE + ${entity_id}= Catenate ${BUILDING_ID_PREFIX}${entity_id_suffix} +END +``` + +Two layered bugs: + +1. The argument default `${entity_id_suffix}=None` makes the default + value the literal string `"None"`, not Robot's `${None}` (Python + `None`). To get the actual `None` object the default would need to + be `${entity_id_suffix}=${None}`. + +2. The condition `'${entity_id_suffix}' == None` compares the + stringified `'None'` against Python's `None` (built-in identifier in + Robot evaluator). Strings never compare equal to NoneType in + Python, so the IF branch (which calls + `Generate Random Building Entity Id`) never fires — every caller + that omits the suffix ends up with `urn:ngsi-ld:Building:None`. + +The tests "work" because each setup creates the entity with that fixed +id and the teardown deletes it again — a single test's create / use / +delete cycle is consistent. But: + +- Any test parallelism would break with a collision on `:None`. +- Cross-test state leak between siblings is hidden by the matching + delete in teardown — but the entity briefly exists for two adjacent + tests at the same time during the Robot run, which is unintentional. +- The keyword's `Generate Random Building Entity Id` branch is dead + code today. + +**Fix:** change the default and the condition to be consistent. Either: +- `${entity_id_suffix}=${None}` + `IF '${entity_id_suffix}' == 'None'` (compare against the string), OR +- `${entity_id_suffix}=${EMPTY}` + `IF '${entity_id_suffix}' == ''` + +The second form matches the convention already used elsewhere in the +suite (`deleteAll=${EMPTY}` etc.). + + -- GitLab From f7b2517e8bb3074c70f94cac517180731c33509a Mon Sep 17 00:00:00 2001 From: kzangeli Date: Mon, 1 Jun 2026 08:49:42 +0200 Subject: [PATCH 3/3] testsuite-doubts: #82 D010_01_exc / D002_02_exc / D003_02_exc / D004_01_exc triage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four distop "later error" failures triaged after the lowercase-bool URL params fix unmasked them. Each is test-side; broker is correct: 82a D010_01_exc - stub-count check uses the wrong URL pattern (by-type vs by-id) so it always reads 0. 82b D002_02_exc - vehicle-redirection-ops.jsonld is invalid for exclusive mode per § 9.3.3 (type-only entity, no attribute names) - broker correctly 400s. 82c D003_02_exc - application/json without Link header doesn't propagate the test-suite context, so 'speed' in the body expands differently than 'speed' in the CSR's propertyNames; forward never fires. 82d D004_01_exc - Update Entity Attributes keyword reads the fragment verbatim, never substituting the body's 'randomUUID' id - broker correctly 400s with "Entity Id Mismatch". Each item lists the specific fix; none require broker changes. Co-Authored-By: Claude Opus 4.7 --- testsuite-doubts.md | 75 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/testsuite-doubts.md b/testsuite-doubts.md index a20cc20c..50417d0d 100644 --- a/testsuite-doubts.md +++ b/testsuite-doubts.md @@ -2591,4 +2591,79 @@ delete cycle is consistent. But: The second form matches the convention already used elsewhere in the suite (`deleteAll=${EMPTY}` etc.). +## 82. `D010_01_exc` / `D002_02_exc` / `D003_02_exc` / `D004_01_exc` — distop tests surfaced as test-side after § 9.3.3 enforcement + +The triage of four distop "later error" failures (from the `lowercase +boolean URL params` MR (#81)) found four distinct test-side problems +behind them. Brokers that strictly validate exclusive registrations per +§ 9.3.3 and `application/ld+json` body shape per § 5.6.2 will reject +the tests' fixtures and keyword setup. Each item below stands on its +own; group them here because the same audit pass surfaced all four. + +**82a) `D010_01_exc` — stub-count assertion checks the wrong URL pattern** + +- Stub registered at `/broker1/ngsi-ld/v1/entities/${entity_id}` (by-id) +- Assertion at line 34 counts hits at `/broker1/ngsi-ld/v1/entities?type=Vehicle` (by-type listing) + +The broker correctly forwards a by-id retrieve for an exclusive CSR +that pins a specific entity id — the by-id stub matches. The by-type +stub-count URL never matches by construction and always returns 0, so +`Should Be True ${stub_count} > 0` always fails. **Fix:** change the +`Get Stub Count` URL in line 34 to the by-id pattern actually +registered at line 29. + +**82b) `D002_02_exc` — fixture invalid for exclusive mode (§ 9.3.3)** + +The test uses +`csourceRegistrations/context-source-registration-vehicle-redirection-ops.jsonld` +as an exclusive CSR. The fixture's `information[0].entities[0]` +declares only `{"type": "Vehicle"}` — a type-only group selector. Per +§ 9.3.3, exclusive registrations "shall always relate to specific +Attributes found on a single Entity" — both a specific entity id AND +attribute names are mandatory. swBroker (and any spec-strict broker) +now rejects the CSR creation with **400 BadRequestData**; the test's +setup then fails (`Check Response Status Code 201` doesn't see 201). + +The same fixture, used as a redirect CSR (e.g. `D010_02_red.robot`), +is fine — § 9.3.3 only constrains exclusive mode. The fix is to give +this test its own fixture (or extend +`vehicle-redirection-ops.jsonld` keeping the original redirect-mode +behaviour intact) that adds `propertyNames` matching what the test +actually exercises. The test name "Delete Entity Without Redirection +Operations" is also slightly misleading — per § 9.2, +`redirectionOps` includes `deleteEntity`, so the premise that "this +CSR doesn't support delete" doesn't hold with the listed operation +set. + +**82c) `D003_02_exc` — `application/json` body without Link header doesn't propagate the test-suite context to attribute matching** + +The test POSTs `data/entities/fragmentEntities/vehicle-speed-isParked-fragment.json` +to `/entities/{id}/attrs/` with `Content-Type: application/json` and +no Link header. The fragment carries no `@context`, so the broker +expands `speed` against the **core** context → +`https://uri.etsi.org/ngsi-ld/default-context/speed`. The CSR was +registered with `${ngsild_test_suite_context}` so its `propertyNames: +["speed"]` claim expanded to a different IRI. The two don't match, +the broker doesn't forward to the CS, and `Wait for redirected request` +times out. + +The test should either send the body as `application/ld+json` with a +root `@context`, OR pass a Link header carrying +`${ngsild_test_suite_context}`, so the broker's attr expansion lines +up with the CSR's. Same pattern probably affects other +`Append Entity Attributes With Parameters` callers. + +**82d) `D004_01_exc` — fragment placeholder `randomUUID` is never substituted** + +`Update Entity Attributes` (`ContextInformationProvision.resource:248`) +reads the fragment file (`vehicle-speed-different-attribute.jsonld`) +verbatim and PATCHes it. The fixture's root carries +`"id": "urn:ngsi-ld:Vehicle:randomUUID"` — never replaced with the +actual `${entity_id}` the test set up. The broker correctly returns +**400 BadRequestData** with `"Entity Id Mismatch"` because the body id +doesn't match the URL id. + +**Fix:** mirror what `Create Entity` does — substitute the body's +`$.id` with the actual `${entity_id}` before PATCHing. Or omit the +`id` from the fragment entirely (PATCH attrs doesn't need it). -- GitLab