From e1ab5cd3843bf0ef323dfd9f27b2c5c361a06356 Mon Sep 17 00:00:00 2001 From: Benedetta Arena Date: Tue, 31 Mar 2026 13:03:36 +0200 Subject: [PATCH 1/2] feat: implement new documentation script and update tests --- .../OffStreetParking1/IOP_CNF_01.robot | 16 +- .../OffStreetParking1}/IOP_CNF_02_01.robot | 14 +- .../OffStreetParking1}/IOP_CNF_02_02.robot | 14 +- .../OffStreetParking1}/IOP_CNF_03_01.robot | 15 +- .../OffStreetParking1}/IOP_CNF_03_02.robot | 16 +- .../OffStreetParking1}/IOP_CNF_04_01.robot | 17 +- .../OffStreetParking1}/IOP_CNF_04_02.robot | 18 +- .../OffStreetParking2/IOP_CNF_01.robot | 21 +- doc/generateIOPDocx.py | 250 ++++++++++++++++++ 9 files changed, 305 insertions(+), 76 deletions(-) rename TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_01_01.robot => IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_01.robot (88%) rename {TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity => IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1}/IOP_CNF_02_01.robot (90%) rename {TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity => IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1}/IOP_CNF_02_02.robot (89%) rename {TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity => IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1}/IOP_CNF_03_01.robot (88%) rename {TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity => IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1}/IOP_CNF_03_02.robot (88%) rename {TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity => IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1}/IOP_CNF_04_01.robot (92%) rename {TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity => IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1}/IOP_CNF_04_02.robot (90%) rename TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_01_02.robot => IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking2/IOP_CNF_01.robot (87%) create mode 100644 doc/generateIOPDocx.py diff --git a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_01_01.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_01.robot similarity index 88% rename from TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_01_01.robot rename to IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_01.robot index 50fd432e..a5438099 100644 --- a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_01_01.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_01.robot @@ -22,26 +22,27 @@ ${b2_url} ${b3_url} *** Test Cases *** -IOP_CNF_01_01 Retrieve Entities In Three Different Brokers - [Documentation] Check that the entity created in A only some attributes of the entity. The agent should also check that the entity in B is the full entity. +IOP_CNF_01 Retrieve OffStreetParking:1 + [Documentation] Pre-conditions: no user context. Data only on leaves. B contains OffStreetParking1 and OffStreetParking2. C contains OffStreetParking2. + ... Registrations established: Inclusive in A to B. Exclusive in A to C. [Tags] since_v1.6.1 iop 4_3_3 cf_06 additive-inclusive proxy-exclusive 4_3_6 5_7_1 - + + #Client retrieves OffStreetParking:1 in A and checks for a successful response. ${response}= Retrieve Entity ${entity_id1} broker_url=${b1_url} Check Response Status Code 200 ${response.status_code} Should Contain ${response.json()} availableSpotsNumber Should Contain ${response.json()} totalSpotsNumber + #Client retrieves OffStreetParking:1 in B. ${expected_payload}= Load Entity ${first_entity_payload_filename} ${entity_id1} ${response}= Retrieve Entity ${entity_id1} broker_url=${b2_url} Check Response Status Code 200 ${response.status_code} + + #Client checks that the entity returned is the full entity. Should Be Equal ${response.json()} ${expected_payload} *** Keywords *** Setup Initial Context Source Registrations - [Documentation] Pre-conditions: no user context. Data only on leaves. - ... Broker B contains OffStreetParking1 and OffStreetParking2. - ... Broker C contains OffStreetParking2. - ... CSR in A to B and in A to C. ${entity_id1}= Generate Random Parking Entity Id Set Suite Variable ${entity_id1} ${response}= Create Entity ${first_entity_payload_filename} ${entity_id1} broker_url=${b2_url} @@ -77,7 +78,6 @@ Setup Initial Context Source Registrations Check Response Status Code 201 ${response.status_code} Delete Entities And Delete Registrations - [Documentation] Post-conditions: no user context. no data in any broker. no registrations in any broker. Delete Context Source Registration ${registration_id1} broker_url=${b1_url} Delete Context Source Registration ${registration_id2} broker_url=${b1_url} Delete Entity ${entity_id1} broker_url=${b2_url} diff --git a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_02_01.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_01.robot similarity index 90% rename from TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_02_01.robot rename to IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_01.robot index abb8d1a8..6bfcc456 100644 --- a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_02_01.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_01.robot @@ -24,32 +24,31 @@ ${b3_url} ${b4_url} *** Test Cases *** -IOP_CNF_02_01 Retrieve Entities In Four Different Brokers - [Documentation] Check that entities returned from A has attributes from both entities in B and C. +IOP_CNF_02_01 Retrieve OffStreetParking:1 + [Documentation] Pre-conditions: no user context. Data only on leaves. B contains OffStreetParking1 without location. C contains OffStreetParking1. D contains OffStreetParking2. + ... Registrations established: Inclusive in A to B. Redirect in A to C. Redirect in A to D. [Tags] since_v1.6.1 iop 4_3_3 cf_06 additive-inclusive proxy-redirect 4_3_6 5_7_1 + #Client retrieves OffStreetParking:1 in A and checks for a partial successful. The entity returned should be the whole entity. ${response}= Retrieve Entity ${entity_id} broker_url=${b1_url} Check Response Status Code 207 ${response.status_code} ${payload}= Set To Dictionary ${response.json()} Should Be Equal ${payload} ${first_full_entity_payload_filename} + #Client retrieves OffStreetParking:1 in B and C. ${response}= Retrieve Entity ${entity_id} broker_url=${b2_url} ${first_expected_payload}= Set To Dictionary ${response.json()} ${response}= Retrieve Entity ${entity_id} broker_url=${b3_url} ${second_expected_payload}= Set To Dictionary ${response.json()} + #Client checks that the entity returned from A has attributes from the entities in B and C. Should Be Equal ${payload}[availableSpotNumbers][value] ${first_expected_payload}[availableSpotNumbers][value] Should Be Equal ${payload}[totalSpotsNumber][value] ${first_expected_payload}[totalSpotsNumber][value] Should Be Equal ${payload}[location][value] ${second_expected_payload}[location][value] *** Keywords *** Setup Initial Context Source Registrations - [Documentation] Pre-conditions: no user context. Data only on leaves. - ... Broker B contains OffStreetParking1 without location. - ... Broker C contains OffStreetParking1. - ... Broker D contains OffStreetParking2. - ... CSR in A to B, in A to C and in A to D. ${entity_id}= Generate Random Parking Entity Id Set Suite Variable ${entity_id} ${response}= Create Entity ${entity_payload_filename} ${entity_id} broker_url=${b2_url} @@ -93,7 +92,6 @@ Setup Initial Context Source Registrations Check Response Status Code 201 ${response.status_code} Delete Entities And Delete Registrations - [Documentation] Post-conditions: no user context. no data in any broker. no registrations in any broker. Delete Context Source Registration ${registration_id1} broker_url=${b1_url} Delete Context Source Registration ${registration_id2} broker_url=${b1_url} Delete Context Source Registration ${registration_id3} broker_url=${b1_url} diff --git a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_02_02.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_02.robot similarity index 89% rename from TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_02_02.robot rename to IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_02.robot index de7fd3b5..b359adc5 100644 --- a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_02_02.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_02.robot @@ -24,27 +24,26 @@ ${b3_url} ${b4_url} *** Test Cases *** -IOP_CNF_02_02 Retrieve Entities In Four Different Brokers - [Documentation] Check that the entity returned from C has the same location attribute found in A. +IOP_CNF_02_02 Retrieve OffStreetParking:1 Location Attribute + [Documentation] Pre-conditions: no user context. Data only on leaves. B contains OffStreetParking1. C contains OffStreetParking1 with location and name only. D contains OffStreetParking2. + ... Registrations established: Inclusive in A to B. Redirect in A to C. Redirect in A to D. [Tags] since_v1.6.1 iop 4_3_3 cf_06 additive-inclusive proxy-redirect 4_3_6 5_7_1 + #Client retrieves OffStreetParking:1 in A and checks for a partial successful. The entity returned should contain the location attribute. ${response}= Retrieve Entity ${entity_id} broker_url=${b1_url} Check Response Status Code 207 ${response.status_code} ${payload}= Set To Dictionary ${response.json()} Should Contain ${payload} location + #Client retrieves OffStreetParking:1 in C with local=true. ${response}= Retrieve Entity ${entity_id} broker_url=${b3_url} local=true ${expected_payload}= Set To Dictionary ${response.json()} + #Client checks that the location attribute in C is the same as the one in A. Should Be Equal ${payload}[location][value] ${expected_payload}[location][value] *** Keywords *** Setup Initial Context Source Registrations - [Documentation] Pre-conditions: no user context. Data only on leaves. - ... Broker B contains OffStreetParking1. - ... Broker C contains OffStreetParking1 with location and name only. - ... Broker D contains OffStreetParking2. - ... CSR in A to B, in A to C and in A to D. ${entity_id}= Generate Random Parking Entity Id Set Suite Variable ${entity_id} ${response}= Create Entity ${first_full_entity_payload_filename} ${entity_id} broker_url=${b2_url} @@ -88,7 +87,6 @@ Setup Initial Context Source Registrations Check Response Status Code 201 ${response.status_code} Delete Entities And Delete Registrations - [Documentation] Post-conditions: no user context. no data in any broker. no registrations in any broker. Delete Context Source Registration ${registration_id1} broker_url=${b1_url} Delete Context Source Registration ${registration_id2} broker_url=${b1_url} Delete Context Source Registration ${registration_id3} broker_url=${b1_url} diff --git a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_03_01.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_01.robot similarity index 88% rename from TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_03_01.robot rename to IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_01.robot index 0a147279..5c0e9713 100644 --- a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_03_01.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_01.robot @@ -25,15 +25,18 @@ ${b3_url} ${b4_url} *** Test Cases *** -IOP_CNF_03_01 Retrieve Entities In Four Different Brokers - [Documentation] Check the retrieval of entities in different brokers. The entity returned from A should have some attributes that match the entity in B and should not contain the location attribute found in C. +IOP_CNF_03_01 Retrieve OffStreetParking:1 + [Documentation] Pre-conditions: no user context. Data on every broker. A contains OffStreetParking1 without location. B contains OffStreetParking1. C contains OffStreetParking1 without location. D contains OffStreetParking2. + ... Registrations established: Auxiliary in A to B. Inclusive in A to C. Inclusive in A to D. [Tags] since_v1.6.1 iop 4_3_3 cf_06 additive-inclusive additive-auxiliary 4_3_6 5_7_1 + #Client retrieves OffStreetParking:1 in A and checks for a partial successful. The entity returned should not contain the location attribute. ${response}= Retrieve Entity ${entity_id} broker_url=${b1_url} Check Response Status Code 207 ${response.status_code} ${payload}= Set To Dictionary ${response.json()} Should Not Contain ${payload} location + #Client retrieves OffStreetParking:1 in B, C and D with the local=true flag. ${response}= Retrieve Entity ${entity_id} broker_url=${b1_url} local=true ${first_payload}= Set To Dictionary ${response.json()} ${response}= Retrieve Entity ${entity_id} broker_url=${b2_url} local=true @@ -41,17 +44,12 @@ IOP_CNF_03_01 Retrieve Entities In Four Different Brokers ${response}= Retrieve Entity ${entity_id} broker_url=${b3_url} local=true ${third_payload}= Set To Dictionary ${response.json()} + #Client checks that the entity returned from A should have the same attributes as the one in B and it should not contain the attribute location found in C. Should Be Equal ${payload} ${first_payload} Should Not Contain ${payload}[location] ${second_payload}[location] *** Keywords *** Setup Initial Context Source Registrations - [Documentation] Pre-conditions: no user context. Data on every broker. - ... Broker A contains OffStreetParking1 without location. - ... Broker B contains OffStreetParking1. - ... Broker C contains OffStreetParking1 without location. - ... Broker D contains OffStreetParking2. - ... CSR in A to B, in A to C and in A to D. ${entity_id}= Generate Random Parking Entity Id Set Suite Variable ${entity_id} ${response}= Create Entity ${entity_payload_filename} ${entity_id} broker_url=${b1_url} @@ -97,7 +95,6 @@ Setup Initial Context Source Registrations Check Response Status Code 201 ${response.status_code} Delete Entities And Delete Registrations - [Documentation] Post-conditions: no user context. no data in any broker. no registrations in any broker. Delete Context Source Registration ${registration_id1} broker_url=${b1_url} Delete Context Source Registration ${registration_id2} broker_url=${b1_url} Delete Context Source Registration ${registration_id3} broker_url=${b1_url} diff --git a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_03_02.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_02.robot similarity index 88% rename from TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_03_02.robot rename to IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_02.robot index f2750238..e4e6e94b 100644 --- a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_03_02.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_02.robot @@ -25,28 +25,26 @@ ${b3_url} ${b4_url} *** Test Cases *** -IOP_CNF_03_02 Retrieve Entities In Four Different Brokers - [Documentation] Check that the entity returned from A contains the attribute location and it matches the one from the entity returned from C. - [Tags] since_v1.6.1 iop 4_3_3 cf_06 additive-inclusive proxy-exclusive 4_3_6 5_7_1 +IOP_CNF_03_02 Retrieve OffStreetParking:1 Location Attribute + [Documentation] Pre-conditions: no user context. Data on every broker. A contains OffStreetParking1 without location. B contains OffStreetParking1. C contains OffStreetParking1 with location and name only. D contains OffStreetParking1 without location. + ... Registrations established: Auxiliary in A to B. Inclusive in A to C. Inclusive in A to D. + [Tags] since_v1.6.1 iop 4_3_3 cf_06 additive-inclusive additive-auxiliary 4_3_6 5_7_1 + #Client retrieves OffStreetParking:1 in A and checks for a partial successful. The entity returned should only contain the location attribute. ${response}= Retrieve Entity ${entity_id} broker_url=${b1_url} Check Response Status Code 207 ${response.status_code} ${payload}= Set To Dictionary ${response.json()} Should Contain ${payload} location + #Client retrieves OffStreetParking:1 in C with local=true. ${response}= Retrieve Entity ${entity_id} broker_url=${b3_url} local=true ${expected_payload}= Set To Dictionary ${response.json()} + #Client checks that the location attribute in A is the same as the one in C. Should Be Equal ${payload}[location][value] ${expected_payload}[location][value] *** Keywords *** Setup Initial Context Source Registrations - [Documentation] Pre-conditions: no user context. Data on every broker. - ... Broker A contains OffStreetParking1 without location. - ... Broker B contains OffStreetParking1. - ... Broker C contains OffStreetParking1 with location and name only. - ... Broker D contains OffStreetParking1 without location. - ... CSR in A to B, in A to C and in A to D. ${entity_id}= Generate Random Parking Entity Id Set Suite Variable ${entity_id} ${response}= Create Entity ${no_location_entity_payload_filename} ${entity_id} broker_url=${b1_url} diff --git a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_04_01.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_01.robot similarity index 92% rename from TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_04_01.robot rename to IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_01.robot index c4d72ef7..30fbc438 100644 --- a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_04_01.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_01.robot @@ -27,31 +27,29 @@ ${b4_url} ${b5_url} *** Test Cases *** -IOP_CNF_04_01 Retrieve Entities In Five Different Brokers - [Documentation] Check that the entity returned from A has attributes from the entity found in D and E. +IOP_CNF_04_01 Retrieve OffStreetParking:1 + [Documentation] Pre-conditions: no user context. Data only on leaves. D contains OffStreetParking1 without location. E contains OffStreetParking1. + ... Registrations established: Auxiliary in A to B and Inclusive in A to C. Redirect in B to D and Redirect in B to E. Exclusive in C to E. [Tags] since_v1.6.1 iop 4_3_3 cf_06 additive-inclusive additive-auxiliary proxy-redirect proxy-exclusive 4_3_6 5_7_1 - + + #Client retrieves OffStreetParking:1 in A and checks for a successful response. ${response}= Retrieve Entity ${entity_id} broker_url=${b1_url} Check Response Status Code 200 ${response.status_code} ${payload}= Set To Dictionary ${response.json()} + #Client retrieves OffStreetParking:1 in D and E. ${response}= Retrieve Entity ${entity_id} broker_url=${b4_url} ${first_expected_payload}= Set To Dictionary ${response.json()} ${response}= Retrieve Entity ${entity_id} broker_url=${b5_url} ${second_expected_payload}= Set To Dictionary ${response.json()} + #Client checks that the entity returned from A has attributes from the entity in D and E. Should Be Equal ${payload}[availableSpotNumbers] ${first_expected_payload}[availableSpotNumbers] Should Be Equal ${payload}[totalSpotsNumber] ${first_expected_payload}[totalSpotsNumber] Should Be Equal ${payload}[location] ${second_expected_payload}[location] *** Keywords *** Setup Initial Context Source Registrations - [Documentation] Pre-conditions: no user context. Data only on leaves. - ... Broker D contains OffStreetParking1 without location. - ... Broker E contains OffStreetParking1. - ... CSR in A to B and in A to C. - ... CSR in B to D and in B to E. - ... CSR in C to E. ${entity_id}= Generate Random Parking Entity Id Set Suite Variable ${entity_id} ${response}= Create Entity ${no_location_entity_payload_filename} ${entity_id} broker_url=${b4_url} @@ -115,7 +113,6 @@ Setup Initial Context Source Registrations Check Response Status Code 201 ${response.status_code} Delete Entities And Delete Registrations - [Documentation] Post-conditions: no user context. no data in any broker. no registrations in any broker. Delete Context Source Registration ${registration_id1} broker_url=${b1_url} Delete Context Source Registration ${registration_id2} broker_url=${b2_url} Delete Context Source Registration ${registration_id3} broker_url=${b2_url} diff --git a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_04_02.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_02.robot similarity index 90% rename from TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_04_02.robot rename to IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_02.robot index d3e7784b..b22c26fb 100644 --- a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_04_02.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_02.robot @@ -28,15 +28,18 @@ ${b4_url} ${b5_url} *** Test Cases *** -IOP_CNF_04_02 Retrieve Entities In Five Different Brokers - [Documentation] Check that the entity found in A has the same attributes from the entity found in B, C and E. +IOP_CNF_04_02 Retrieve OffStreetParking:1 Location Attribute + [Documentation] Pre-conditions: no user context. Data on every broker. A contains OffStreetParking1 without location. B contains OffStreetParking1 without location. C contains OffStreetParking1 without location. D contains OffStreetParking1. E contains OffStreetParking1 with location and name only. + ... Registrations established: Auxiliary in A to B and Inclusive in A to C. Redirect in B to D and Redirect in B to E. Exclusive in C to E. [Tags] since_v1.6.1 iop 4_3_3 cf_06 additive-inclusive additive-auxiliary proxy-redirect proxy-exclusive 4_3_6 5_7_1 + #Client retrieves OffStreetParking:1 in A and checks for a successful response. ${response}= Retrieve Entity ${entity_id} broker_url=${b1_url} Check Response Status Code 200 ${response.status_code} ${payload}= Set To Dictionary ${response.json()} Should Contain ${payload} location + #Client retrieves OffStreetParking:1 in B, C and E with local=true. ${response}= Retrieve Entity ${entity_id} broker_url=${b2_url} local=true ${first_expected_payload}= Set To Dictionary ${response.json()} ${response}= Retrieve Entity ${entity_id} broker_url=${b3_url} local=true @@ -44,6 +47,7 @@ IOP_CNF_04_02 Retrieve Entities In Five Different Brokers ${response}= Retrieve Entity ${entity_id} broker_url=${b5_url} local=true ${third_expected_payload}= Set To Dictionary ${response.json()} + #Client checks that the entity returned from A should have the same attributes as the one in B, C and E. Should Be Equal ${payload}[availableSpotsNumbers] ${first_expected_payload}[availableSpotsNumbers] Should Be Equal ${payload}[totalSpotsNumber] ${first_expected_payload}[totalSpotsNumber] Should Be Equal ${payload}[location] ${second_expected_payload}[location] @@ -51,15 +55,6 @@ IOP_CNF_04_02 Retrieve Entities In Five Different Brokers *** Keywords *** Setup Initial Context Source Registrations - [Documentation] Pre-conditions: no user context. Data on every broker. - ... Broker A contains OffStreetParking1 without location. - ... Broker B contains OffStreetParking1 without location. - ... Broker C contains OffStreetParking1 without location. - ... Broker D contains OffStreetParking1. - ... Broker E contains OffStreetParking1 with location and name only. - ... CSR in A to B and in A to C. - ... CSR in B to D and in B to E. - ... CSR in C to E. ${entity_id}= Generate Random Parking Entity Id Set Suite Variable ${entity_id} ${response}= Create Entity ${no_location_entity_payload_filename} ${entity_id} broker_url=${b1_url} @@ -129,7 +124,6 @@ Setup Initial Context Source Registrations Check Response Status Code 201 ${response.status_code} Delete Entities And Delete Registrations - [Documentation] Post-conditions: no user context. no data in any broker. no registrations in any broker. Delete Context Source Registration ${registration_id1} broker_url=${b1_url} Delete Context Source Registration ${registration_id2} broker_url=${b2_url} Delete Context Source Registration ${registration_id3} broker_url=${b2_url} diff --git a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_01_02.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking2/IOP_CNF_01.robot similarity index 87% rename from TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_01_02.robot rename to IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking2/IOP_CNF_01.robot index 2aea6c97..cdaf0e25 100644 --- a/TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/IOP_CNF_01_02.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking2/IOP_CNF_01.robot @@ -22,31 +22,29 @@ ${b2_url} ${b3_url} *** Test Cases *** -IOP_CNF_01_02 Retrieve Entities In Three Different Brokers - [Documentation] The entity returned from A should have attributes from both entities in B and C. +IOP_CNF_01 Retrieve OffStreetParking:2 + [Documentation] Pre-conditions: no user context. Data only on leaves. B contains OffStreetParking2 without location. C contains OffStreetParking2. + ... Registrations established: Inclusive in A to B. Exclusive in A to C. [Tags] since_v1.6.1 iop 4_3_3 cf_06 additive-inclusive proxy-exclusive 4_3_6 5_7_1 - + + #Client retrieves OffStreetParking:2 in A and checks for a successful response. ${response}= Retrieve Entity ${entity_id} broker_url=${b1_url} Check Response Status Code 200 ${response.status_code} - + ${payload}= Set To Dictionary ${response.json()} + + #Client retrieves OffStreetParking:2 in B and C. ${response}= Retrieve Entity ${entity_id} broker_url=${b2_url} ${first_expected_payload}= Set To Dictionary ${response.json()} ${response}= Retrieve Entity ${entity_id} broker_url=${b3_url} ${second_expected_payload}= Set To Dictionary ${response.json()} - ${response}= Retrieve Entity ${entity_id} broker_url=${b2_url} - Check Response Status Code 200 ${response.status_code} - ${payload}= Set To Dictionary ${response.json()} + #Client checks that the entity returned from A has attributes from both entities in B and C. Should Be Equal ${payload}[availableSpotNumbers][value] ${first_expected_payload}[availableSpotNumbers][value] Should Be Equal ${payload}[totalSpotsNumber][value] ${first_expected_payload}[totalSpotsNumber][value] Should Be Equal ${payload}[location][value] ${second_expected_payload}[location][value] *** Keywords *** Setup Initial Context Source Registrations - [Documentation] Pre-conditions: no user context. Data only on leaves. - ... Broker B contains OffStreetParking2 without location. - ... Broker C contains OffStreetParking2. - ... CSR in A to B and in A to C. ${entity_id}= Generate Random Parking Entity Id Set Suite Variable ${entity_id} ${response}= Create Entity ${entity_payload_filename} ${entity_id} broker_url=${b2_url} @@ -77,7 +75,6 @@ Setup Initial Context Source Registrations Check Response Status Code 201 ${response.status_code} Delete Entities And Delete Registrations - [Documentation] Post-conditions: no user context. no data in any broker. no registrations in any broker. Delete Context Source Registration ${registration_id1} broker_url=${b1_url} Delete Context Source Registration ${registration_id2} broker_url=${b1_url} Delete Entity ${entity_id} broker_url=${b2_url} diff --git a/doc/generateIOPDocx.py b/doc/generateIOPDocx.py new file mode 100644 index 00000000..221416f9 --- /dev/null +++ b/doc/generateIOPDocx.py @@ -0,0 +1,250 @@ +#!/usr/bin/env python3 +# +# Usage: python3 generateIOPDocx.py [output_directory] +# +""" +Script to generate a DOCX file from a Robot Framework test case. +""" + +import re +import sys +from pathlib import Path +from typing import Dict, List +from docx import Document +from docx.shared import Pt +from docx.enum.text import WD_PARAGRAPH_ALIGNMENT + +def process_continuation_lines(text: str) -> List[str]: + """ + Process lines with '...' continuation markers and return clean lines. + """ + lines = [] + for line in text.split('\n'): + line = line.strip() + if line and not line.startswith('...'): + lines.append(line) + elif line.startswith('...'): + line_content = line.replace('...', '').strip() + if line_content: + lines.append(line_content) + return lines + +def extract_with_regex(content: str, pattern: str, group: int = 1) -> str: + """ + Extract text from content using regex pattern. + """ + match = re.search(pattern, content, re.MULTILINE | re.DOTALL) + return match.group(group).strip() if match else "" + +def extract_test_info(robot_file_path: str) -> Dict: + """ + Extract test case information from a Robot Framework file using regex. + """ + result = { + 'test_id': None, + 'settings_documentation': [], + 'test_documentation': [], + 'tags': [], + 'comments': [] + } + + with open(robot_file_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Extract settings documentation + settings_doc = extract_with_regex( + content, + r'^\s*Documentation\s+(.*?)(?=\n\s*(?:Resource|Library|Test Setup|Test Teardown|Test Template|Suite Setup|Suite Teardown|\*\*\*))' + ) + if settings_doc: + result['settings_documentation'] = process_continuation_lines(settings_doc) + + # Extract test ID + result['test_id'] = extract_with_regex( + content, + r'^\*\*\* Test Cases \*\*\*\s+(.+?)(?:\n\s+\[Documentation\]|\n\s+\[Tags\]|\n\s+\[|\n\s*$)' + ) + + # Extract test documentation + test_doc = extract_with_regex( + content, + r'\[Documentation\]\s*(.*?)(?=\n\s+\[|\n\s*\n)' + ) + if test_doc: + result['test_documentation'] = process_continuation_lines(test_doc) + + # Extract tags + tags_text = extract_with_regex( + content, + r'\[Tags\]\s*(.*?)(?=\n\s+[A-Z]|\n\n|\Z)' + ) + result['tags'] = [tag.strip() for tag in tags_text.split() if tag.strip()] + + # Extract comments + result['comments'] = [c.strip() for c in re.findall(r'^\s*#(.+?)$', content, re.MULTILINE)] + + return result + +def add_table_row(table, label: str, content: str, is_header: bool = False): + """ + Add a row to the table with label and content. + """ + row = table.add_row() + + for cell, text in zip(row.cells, [label, content]): + para = cell.paragraphs[0] + para.text = text + + if is_header and para.runs: + para.runs[0].bold = True + para.runs[0].font.size = Pt(12) + +def add_merged_header_row(table, header_text: str): + row = table.add_row() + merged_cell = row.cells[0].merge(row.cells[1]) + para = merged_cell.paragraphs[0] + para.text = header_text + para.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER + for run in para.runs: + run.bold = True + run.font.size = Pt(12) + +def add_table_sections(table, test_info: Dict): + """ + Add all table sections using a parametrized approach. + """ + sections = [ + { + 'label': 'Test Purpose', + 'data': ' '.join(test_info['settings_documentation']) if test_info['settings_documentation'] else None, + 'split_multiline': False + }, + { + 'label': 'Documentation', + 'data': test_info['test_documentation'], + 'split_multiline': True, + 'split_on_colon': True + }, + { + 'label': 'Tags', + 'data': ', '.join(test_info['tags']) if test_info['tags'] else None, + 'split_multiline': False + }, + { + 'label': 'Test Case', + 'data': "\n".join([f"{i+1}. {c}" for i, c in enumerate(test_info['comments'])]) if test_info['comments'] else None, + 'split_multiline': False, + 'split_on_colon': False + } + ] + + for section in sections: + if not section['data']: + continue + + if section['split_multiline']: + for line in section['data']: + line = line.lstrip('.') + if section.get('split_on_colon') and ':' in line: + parts = line.split(':', 1) + add_table_row(table, parts[0].strip(), parts[1].strip()) + else: + add_table_row(table, section['label'], line) + else: + add_table_row(table, section['label'], section['data']) + +def find_robot_files(folder_path: Path) -> List[Path]: + """ + Find all .robot files in a folder recursively. + """ + return sorted(folder_path.glob('**/*.robot')) + +def create_docx_from_multiple_tests(robot_files: List[Path], output_dir: Path, folder_name: str) -> str: + """ + Create a single DOCX file with all robot tests as separate tables. + """ + doc = Document() + + title = doc.add_heading(folder_name, level=1) + title.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER + + for robot_file in robot_files: + test_info = extract_test_info(str(robot_file)) + test_name = robot_file.stem + + if not test_info['test_id']: + continue + + test_heading = doc.add_heading(test_name, level=2) + + table = doc.add_table(rows=0, cols=2) + add_merged_header_row(table, test_info['test_id']) + add_table_sections(table, test_info) + + doc.add_paragraph() + + output_path = output_dir / f"{folder_name}.docx" + doc.save(str(output_path)) + return str(output_path) + +def create_docx_from_robot_test(robot_file_path: str, output_dir: str = None, test_name: str = None, folder_name: str = None) -> str: + test_info = extract_test_info(robot_file_path) + + if not test_info['test_id']: + print("Error: Could not extract test case ID from the file") + return None + + test_name = test_name or test_info['test_id'] + + doc = Document() + + title_text = folder_name or test_name + title = doc.add_heading(title_text, level=1) + title.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER + + table = doc.add_table(rows=0, cols=2) + add_merged_header_row(table, test_name) + add_table_sections(table, test_info) + + output_dir = Path(output_dir or Path(robot_file_path).parent) + output_path = output_dir / f"{test_name}.docx" + + doc.save(str(output_path)) + +def main(): + if len(sys.argv) < 2: + print("Usage: python generate_test_doc.py [output_directory]") + sys.exit(1) + + input_path = Path(sys.argv[1]) + output_dir = Path(sys.argv[2]) if len(sys.argv) > 2 else None + + if not input_path.exists(): + print(f"Error: Path not found: {input_path}") + sys.exit(-1) + + try: + if input_path.is_file(): + # Single file + test_name = input_path.stem + folder_name = input_path.parent.name + output_dir = output_dir or input_path.parent + create_docx_from_robot_test(str(input_path), str(output_dir), test_name=test_name, folder_name=folder_name) + print("\nCorrectly exiting") + else: + # Folder + robot_files = find_robot_files(input_path) + if not robot_files: + print(f"Error: No .robot files found in {input_path}") + sys.exit(-1) + + output_dir = output_dir or input_path + folder_name = input_path.name + create_docx_from_multiple_tests(robot_files, output_dir, folder_name) + print("\nCorrectly exiting") + except Exception as e: + print(f"Error: {e}") + sys.exit(-1) + +if __name__ == "__main__": + main() -- GitLab From 70569f99c85ebd714a9af54f4452e2e6e3ac26dc Mon Sep 17 00:00:00 2001 From: Benedetta Arena Date: Thu, 2 Apr 2026 17:49:04 +0200 Subject: [PATCH 2/2] fix: enhance documentation and parsing for IOP test files --- .../OffStreetParking1/IOP_CNF_01.robot | 3 +- .../OffStreetParking1/IOP_CNF_02_01.robot | 3 +- .../OffStreetParking1/IOP_CNF_02_02.robot | 3 +- .../OffStreetParking1/IOP_CNF_03_01.robot | 3 +- .../OffStreetParking1/IOP_CNF_03_02.robot | 3 +- .../OffStreetParking1/IOP_CNF_04_01.robot | 3 +- .../OffStreetParking1/IOP_CNF_04_02.robot | 3 +- .../OffStreetParking2/IOP_CNF_01.robot | 3 +- doc/analysis/generaterobotdata.py | 115 +++++++- doc/analysis/parserobotfile.py | 242 ++++++++++++++++- doc/generateDocumentationData.py | 37 ++- doc/generateIOPDocx.py | 250 ------------------ doc/statisticsDocumentationData.py | 12 +- 13 files changed, 398 insertions(+), 282 deletions(-) delete mode 100644 doc/generateIOPDocx.py diff --git a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_01.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_01.robot index a5438099..b4ffbca5 100644 --- a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_01.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_01.robot @@ -1,6 +1,5 @@ *** Settings *** -Documentation Three brokers are set up A, B and C. A has two registrations, one inclusive for the entities created in B and one exclusive for the entity created in C. -... Check that the same entity created in B and C can be returned from A. +Documentation Three brokers are set up A, B and C. A has two registrations, one inclusive for the entities created in B and one exclusive for the entity created in C. Check that the same entity created in B and C can be returned from A. Resource ${EXECDIR}/resources/ApiUtils/ContextInformationConsumption.resource Resource ${EXECDIR}/resources/ApiUtils/ContextInformationProvision.resource diff --git a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_01.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_01.robot index 6bfcc456..a5ea6988 100644 --- a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_01.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_01.robot @@ -1,6 +1,5 @@ *** Settings *** -Documentation Four brokers are set up A, B, C and D. A has three registrations, one inclusive for the entity created in B, one redirect for the entity created in C and one redirect for the entity created in D. -... Check that the entity returned from A has attributes from the entities in B and C. +Documentation Four brokers are set up A, B, C and D. A has three registrations, one inclusive for the entity created in B, one redirect for the entity created in C and one redirect for the entity created in D. Check that the entity returned from A has attributes from the entities in B and C. Resource ${EXECDIR}/resources/ApiUtils/ContextInformationConsumption.resource Resource ${EXECDIR}/resources/ApiUtils/ContextInformationProvision.resource diff --git a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_02.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_02.robot index b359adc5..1f26d3a0 100644 --- a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_02.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_02_02.robot @@ -1,6 +1,5 @@ *** Settings *** -Documentation Four brokers are set up A, B, C and D. A has three registrations, one inclusive for the entity created in B, one redirect for the entity created in C and one redirect for the entity created in D. -... Check that the entity returned from C has the same location attribute found in A. +Documentation Four brokers are set up A, B, C and D. A has three registrations, one inclusive for the entity created in B, one redirect for the entity created in C and one redirect for the entity created in D. Check that the entity returned from C has the same location attribute found in A. Resource ${EXECDIR}/resources/ApiUtils/ContextInformationConsumption.resource Resource ${EXECDIR}/resources/ApiUtils/ContextInformationProvision.resource diff --git a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_01.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_01.robot index 5c0e9713..4128d647 100644 --- a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_01.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_01.robot @@ -1,6 +1,5 @@ *** Settings *** -Documentation Four brokers are set up A, B, C and D. A has three registrations, one auxiliary for the entity created in B, one inclusive for the entity created in C and one inclusive for the entity created in D. -... Check that a partial response was returned from A and that the entity matches the one in B and it does not contain the attribute location found in C. +Documentation Four brokers are set up A, B, C and D. A has three registrations, one auxiliary for the entity created in B, one inclusive for the entity created in C and one inclusive for the entity created in D. Check that a partial response was returned from A and that the entity matches the one in B and it does not contain the attribute location found in C. Resource ${EXECDIR}/resources/ApiUtils/ContextInformationConsumption.resource Resource ${EXECDIR}/resources/ApiUtils/ContextInformationProvision.resource diff --git a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_02.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_02.robot index e4e6e94b..f4ac18b9 100644 --- a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_02.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_03_02.robot @@ -1,6 +1,5 @@ *** Settings *** -Documentation Four brokers are set up A, B, C and D. A has three registrations, one auxiliary for the entity created in B, one inclusive for the entity created in C and one inclusive for the entity created in D. -... Check the entity returned from A contains the location property and said attribute is the same as the one returned from C. +Documentation Four brokers are set up A, B, C and D. A has three registrations, one auxiliary for the entity created in B, one inclusive for the entity created in C and one inclusive for the entity created in D. Check the entity returned from A contains the location property and said attribute is the same as the one returned from C. Resource ${EXECDIR}/resources/ApiUtils/ContextInformationConsumption.resource Resource ${EXECDIR}/resources/ApiUtils/ContextInformationProvision.resource diff --git a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_01.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_01.robot index 30fbc438..4e9c9279 100644 --- a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_01.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_01.robot @@ -1,6 +1,5 @@ *** Settings *** -Documentation Five brokers are set up A, B, C, D and E. A has two registrations, one auxiliary for the entity created in B, one inclusive for the entity created in C. B has two registrations, one redirect for the entity created in D and one redirect for the entity created in E. C shall establish one exclusive registration to E. -... Check that the entity returned from A has attributes from the entity in D and E. +Documentation Five brokers are set up A, B, C, D and E. A has two registrations, one auxiliary for the entity created in B, one inclusive for the entity created in C. B has two registrations, one redirect for the entity created in D and one redirect for the entity created in E. C shall establish one exclusive registration to E. Check that the entity returned from A has attributes from the entity in D and E. Resource ${EXECDIR}/resources/ApiUtils/ContextInformationConsumption.resource Resource ${EXECDIR}/resources/ApiUtils/ContextInformationProvision.resource diff --git a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_02.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_02.robot index b22c26fb..ab2f5b4e 100644 --- a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_02.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking1/IOP_CNF_04_02.robot @@ -1,6 +1,5 @@ *** Settings *** -Documentation Five brokers are set up A, B, C, D and E. A has two registrations, one auxiliary for the entity created in B, one inclusive for the entity created in C. B has two registrations, one redirect for the entity created in D and one redirect for the entity created in E. C shall establish one exclusive registration to E. -... Check that the entity returned from A match the attributes from the entity in B, C and E. +Documentation Five brokers are set up A, B, C, D and E. A has two registrations, one auxiliary for the entity created in B, one inclusive for the entity created in C. B has two registrations, one redirect for the entity created in D and one redirect for the entity created in E. C shall establish one exclusive registration to E. Check that the entity returned from A match the attributes from the entity in B, C and E. Resource ${EXECDIR}/resources/ApiUtils/ContextInformationConsumption.resource Resource ${EXECDIR}/resources/ApiUtils/ContextInformationProvision.resource diff --git a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking2/IOP_CNF_01.robot b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking2/IOP_CNF_01.robot index cdaf0e25..7e78b189 100644 --- a/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking2/IOP_CNF_01.robot +++ b/IOP_TP/NGSI-LD/Interoperability/Consumption/Entity/RetrieveEntity/OffStreetParking2/IOP_CNF_01.robot @@ -1,6 +1,5 @@ *** Settings *** -Documentation Three brokers are set up A, B and C. A has two registrations, one inclusive for the the entity created in B and one exclusive for the entity created in C. -... Check that the entity returned from A has attributes from both entities in B and C. +Documentation Three brokers are set up A, B and C. A has two registrations, one inclusive for the the entity created in B and one exclusive for the entity created in C. Check that the entity returned from A has attributes from both entities in B and C. Resource ${EXECDIR}/resources/ApiUtils/ContextInformationConsumption.resource Resource ${EXECDIR}/resources/ApiUtils/ContextInformationProvision.resource diff --git a/doc/analysis/generaterobotdata.py b/doc/analysis/generaterobotdata.py index 5837d75d..304b87a4 100644 --- a/doc/analysis/generaterobotdata.py +++ b/doc/analysis/generaterobotdata.py @@ -15,8 +15,14 @@ class GenerateRobotData: self.config_variables = ParseVariablesFile() self.robot = ParseRobotFile(filename=robot_file, execdir=execdir, config_file=self.config_variables) - self.apiutils = [ParseApiUtilsFile(filename=file) for file in self.robot.resource_files] - self.robot.set_apiutils(self.apiutils) + + self.file_type = self.robot.file_type + + if self.file_type == "IOP": + self.apiutils = [] + else: # TP + self.apiutils = [ParseApiUtilsFile(filename=file) for file in self.robot.resource_files] + self.robot.set_apiutils(self.apiutils) self.test_cases = list() self.test_suite = dict() @@ -120,6 +126,13 @@ class GenerateRobotData: return self.test_suite def parse_robot(self): + if self.file_type == "IOP": + self.parse_robot_iop() + else: + self.parse_robot_tp() + + def parse_robot_tp(self): + """Parse TP (Test Procedure) robot file with full complexity""" self.start_suite() _ = [self.visit_test(test=x) for x in self.suite.tests] @@ -134,6 +147,20 @@ class GenerateRobotData: # Generate the parent release and correct the reference in case that the tags include information since_v1.x.y self.get_version() + + def parse_robot_iop(self): + """Parse IOP (Interoperability) robot file with simplified structure""" + self.start_suite_iop() + + # Extract suite-level setup and teardown once + suite_setup = self.robot.get_iop_test_setup() + suite_teardown = self.robot.get_iop_test_teardown() + + # Process each test case in the IOP file + for test_name in self.robot.test_case_names: + self.visit_test_iop(test_name=test_name, suite_setup=suite_setup, suite_teardown=suite_teardown) + + self.test_suite['test_cases'] = self.test_cases def get_version(self): data = [x['tags'] for x in self.test_suite['test_cases']] @@ -609,3 +636,87 @@ class GenerateRobotData: reference = f'{self.references[version]}, clauses {", ".join(clauses)}' return reference, clauses + + def start_suite_iop(self): + """Initialize test suite for IOP files with simplified structure""" + version = 'v1.3.1' + tp_id = self.generate_name_iop() + + # Get suite documentation + suite_doc = self.robot.settings_documentation + + # Add test case documentation + if self.robot.test_case_names: + test_doc = self.robot.get_iop_test_documentation(self.robot.test_case_names[0]) + if test_doc: + suite_doc = f"{suite_doc}\n{test_doc}" if suite_doc else test_doc + + self.test_suite = { + 'tp_id': tp_id, + 'test_objective': suite_doc, + 'reference': 'ETSI GS CIM 009 V1.6.1 [1]', + 'config_id': '', + 'parent_release': version, + 'pics_selection': '', + 'initial_conditions': '', + 'test_cases': list() + } + + def visit_test_iop(self, test_name: str, suite_setup: str = "", suite_teardown: str = ""): + """Process a single IOP test case""" + # Get test information from the parsed robot file + tags = self.robot.get_iop_test_tags(test_name) + comments = self.robot.get_iop_comments(test_name) + + # Extract all documentation sections automatically + doc_sections = self.robot.get_iop_documentation_sections(test_name) + + test_case = { + 'name': test_name, + 'permutation_tp_id': self.base_TP_id, + 'tags': tags, + 'test_steps': comments, + 'setup': suite_setup, + 'teardown': suite_teardown + } + + # Add all extracted documentation sections to the test case + test_case.update(doc_sections) + + self.test_cases.append(test_case) + + def generate_name_iop(self) -> str: + robot_path = self.robot_file.replace('\\', "/") + + # Extract the relative path from IOP_TP onwards + if 'IOP_TP/NGSI-LD' in robot_path: + start_idx = robot_path.find('IOP_TP/NGSI-LD') + relative_path = robot_path[start_idx:] + + parts = relative_path.split('/') + + abbreviations = { + 'Consumption': 'Cons', + 'Provision': 'Prov', + 'Entity': 'E', + 'Entities': 'E' + } + + abbreviated_parts = [] + for part in parts[:5]: + if part in abbreviations: + abbreviated_parts.append(abbreviations[part]) + else: + abbreviated_parts.append(part) + + # Get the test file name (without .robot extension) + test_name = self.robot.test_suite + + # Construct the TP ID + tp_id = '/'.join(abbreviated_parts) + '/' + test_name + self.base_TP_id = tp_id + return tp_id + + # Fallback if pattern not found + return f"IOP_TP/NGSI-LD/{self.robot.test_suite}" + \ No newline at end of file diff --git a/doc/analysis/parserobotfile.py b/doc/analysis/parserobotfile.py index 71040b61..32154f12 100644 --- a/doc/analysis/parserobotfile.py +++ b/doc/analysis/parserobotfile.py @@ -7,6 +7,7 @@ from analysis.requests import Requests class ParseRobotFile: def __init__(self, filename: str, execdir: str, config_file): self.test_suite = os.path.basename(filename).split('.')[0] + self.filename = filename with open(filename, 'r') as file: # Read the contents of the file @@ -21,10 +22,17 @@ class ParseRobotFile: self.test_template_name = str() self.template_params_value = dict() self.check_template() - - self.get_variables_data() - self.get_apiutils_path() - self.get_test_cases() + self.file_type = self._detect_file_type() + + # Parse based on file type + if self.file_type == "IOP": + self.settings_documentation = self.get_iop_settings_documentation() + self.get_iop_variables_data() + self.get_iop_test_cases() + else: # TP + self.get_variables_data() + self.get_apiutils_path() + self.get_test_cases() self.config_file = config_file @@ -37,6 +45,17 @@ class ParseRobotFile: else: self.test_template_name = '' + def _detect_file_type(self) -> str: + """ + Detect if this is an IOP or TP (Test Procedure) file. + Returns: + "IOP" or "TP" + """ + if 'IOP_TP' in self.filename: + return "IOP" + + return "TP" + def set_apiutils(self, apiutils): self.apiutils = apiutils @@ -559,3 +578,218 @@ class ParseRobotFile: result = aux return result + + def get_iop_settings_documentation(self) -> str: + """Extract Documentation from *** Settings *** section for IOP files.""" + string = self.get_substring(initial_string='*** Settings ***\n', final_string='*** Variables ***', include=False) + pattern = r'Documentation\s+(.*?)(?=\n)' + match = re.search(pattern, string, re.MULTILINE) + if match: + return match.group(1).strip() + return "" + + def get_iop_test_setup(self) -> str: + """Extract Test Setup from *** Settings *** section (suite-level for IOP files).""" + string = self.get_substring(initial_string='*** Settings ***\n', final_string='*** Variables ***', include=False) + pattern = r'Test Setup\s+(.*?)(?=\n)' + match = re.search(pattern, string, re.MULTILINE) + if match: + return match.group(1).strip() + return "" + + def get_iop_test_teardown(self) -> str: + """Extract Test Teardown from *** Settings *** section (suite-level for IOP files).""" + string = self.get_substring(initial_string='*** Settings ***\n', final_string='*** Variables ***', include=False) + pattern = r'Test Teardown\s+(.*?)(?=\n)' + match = re.search(pattern, string, re.MULTILINE) + if match: + return match.group(1).strip() + return "" + + def get_iop_variables_data(self): + """Extract variables from *** Variables *** section for IOP files.""" + string = self.get_substring(initial_string='*** Variables ***\n', final_string='*** ', include=False) + + # Pattern: ${VAR_NAME} value + regex = r"\$\{([^}]+)\}\s+(.+?)(?=\n|$)" + matches = re.finditer(regex, string, re.MULTILINE) + + for match in matches: + if len(match.groups()) == 2: + var_name = match.group(1) + var_value = match.group(2).strip() + self.variables[f'${{{var_name}}}'] = var_value + + def get_iop_test_cases(self): + """Extract test cases from *** Test Cases *** section for IOP files.""" + index_start_test_cases = self.file_contents.find('*** Test Cases ***') + if index_start_test_cases == -1: + self.test_cases = dict() + self.test_case_names = list() + return + + index_start_keywords = self.file_contents.find('*** Keywords ***') + if index_start_keywords == -1: + string_test_cases = self.file_contents[index_start_test_cases + len('*** Test Cases ***') + 1:] + else: + string_test_cases = self.file_contents[index_start_test_cases + len('*** Test Cases ***') + 1:index_start_keywords] + + # Extract test case names (pattern: UPPERCASE_WITH_UNDERSCORES) + pattern = r'^([A-Z0-9_]+)(?:\s|$)' + matches = list(re.finditer(pattern, string_test_cases, re.MULTILINE)) + + if not matches: + self.test_cases = dict() + self.test_case_names = list() + return + + # Extract positions and names + indexes = [match.start() for match in matches] + self.test_case_names = [match.group(1) for match in matches] + + # Extract test case content + self.test_cases = dict() + for i in range(len(indexes) - 1): + content = string_test_cases[indexes[i]:indexes[i + 1]] + self.test_cases[self.test_case_names[i]] = content + + # Add last test case + if len(indexes) > 0: + self.test_cases[self.test_case_names[-1]] = string_test_cases[indexes[-1]:] + + def get_iop_test_documentation(self, test_name: str) -> str: + """Extract [Documentation] from a specific IOP test case - stops at labeled sections.""" + if test_name not in self.test_cases: + return "" + + test_content = self.test_cases[test_name] + + match = re.search(r'\[Documentation\]\s*', test_content) + if not match: + return "" + + # Start extracting from after [Documentation] + start_pos = match.end() + lines_list = test_content[start_pos:].split('\n') + + doc_lines = [] + for line in lines_list: + line_stripped = line.strip() + + # Stop if we hit a labeled section (e.g., "Pre-conditions: ...") + if line_stripped and re.match(r'^[A-Za-z\s\-]+:\s', line_stripped): + break + + # Stop if we hit another keyword block + if line_stripped and line_stripped.startswith('['): + break + + # Collect documentation content + if line_stripped: + if line_stripped.startswith('...'): + content = line_stripped.replace('...', '').strip() + if content: + doc_lines.append(content) + else: + doc_lines.append(line_stripped) + elif doc_lines: + break + + return ' '.join(doc_lines) + + def get_iop_documentation_sections(self, test_name: str) -> dict: + """ + Extract sections from test case documentation. + If documentation contains "LABEL: content" pattern, extracts those sections. + Otherwise, returns the documentation as is under 'doc' key. + """ + doc = self.get_iop_test_documentation(test_name) + sections = {} + + if not doc: + return sections + + pattern = r'([A-Za-z\s\-]+?):\s*(.+?)(?=[A-Za-z\s\-]+:\s|$)' + matches = list(re.finditer(pattern, doc)) + + if matches: + for match in matches: + label = match.group(1).strip() + content = match.group(2).strip() + + if content.endswith('.'): + content = content[:-1] + + key = label.lower().replace(' ', '_').replace('-', '_') + sections[key] = content + else: + # No WORD: WORD pattern found, return documentation as is + sections['doc'] = doc + + return sections + + def get_iop_test_tags(self, test_name: str) -> list: + """Extract [Tags] from a specific IOP test case.""" + if test_name not in self.test_cases: + return [] + + test_content = self.test_cases[test_name] + pattern = r'\[Tags\]\s*(.*?)(?=\n\s+\[|\n\s*$)' + match = re.search(pattern, test_content, re.MULTILINE | re.DOTALL) + + if not match: + return [] + + tags_text = match.group(1) + return [tag.strip() for tag in tags_text.split() if tag.strip()] + + def get_iop_comments(self, test_name: str) -> list: + """Extract comments from a specific IOP test case.""" + if test_name not in self.test_cases: + return [] + + test_content = self.test_cases[test_name] + comments = re.findall(r'^\s*#(.+?)$', test_content, re.MULTILINE) + return [comment.strip() for comment in comments] + + def get_iop_setup(self, test_name: str) -> str: + """Extract [Setup] from a specific IOP test case.""" + if test_name not in self.test_cases: + return "" + + test_content = self.test_cases[test_name] + pattern = r'\[Setup\]\s*(.*?)(?=\n\s+\[|\n\s*$)' + match = re.search(pattern, test_content, re.MULTILINE | re.DOTALL) + + if not match: + return "" + + setup_text = match.group(1).strip() + return setup_text + + def get_iop_teardown(self, test_name: str) -> str: + """Extract [Teardown] from a specific IOP test case.""" + if test_name not in self.test_cases: + return "" + + test_content = self.test_cases[test_name] + pattern = r'\[Teardown\]\s*(.*?)(?=\n\s+\[|\n\s*$)' + match = re.search(pattern, test_content, re.MULTILINE | re.DOTALL) + + if not match: + return "" + + teardown_text = match.group(1).strip() + return teardown_text + + def get_iop_test_info(self, test_name: str) -> dict: + """Get all information for a specific IOP test case.""" + return { + 'tp_id': test_name, + 'documentation': self.get_iop_test_documentation(test_name), + 'tags': self.get_iop_test_tags(test_name), + 'comments': self.get_iop_comments(test_name), + 'variables': self.variables, + 'resource_files': self.resource_files, + 'test_cases': self.test_case_names + } diff --git a/doc/generateDocumentationData.py b/doc/generateDocumentationData.py index f82decb6..62181370 100644 --- a/doc/generateDocumentationData.py +++ b/doc/generateDocumentationData.py @@ -52,26 +52,49 @@ def create_json_of_robotfile( def find_robot_file(basedir: str, filename: str): filename = f"{filename}.robot" - for root, dirs, files in walk(basedir): + + # Search in TP/NGSI-LD + tp_path = f"{basedir}/TP/NGSI-LD" + for root, dirs, files in walk(tp_path): if filename in files: - return root.replace(f"{basedir}/TP/NGSI-LD", ""), f"{root}/{filename}" + relative_path = root.replace(f"{basedir}/TP/NGSI-LD", "") + return root.replace(f""), f"{root}/{filename}" + + # Search in IOP_TP/NGSI-LD + iop_path = f"{basedir}/IOP_TP/NGSI-LD" + if exists(iop_path): + for root, dirs, files in walk(iop_path): + if filename in files: + relative_path = root.replace(f"{basedir}/IOP_TP/NGSI-LD", "") + return relative_path, f"{root}/{filename}" return None, None if __name__ == "__main__": - # Call with the folder below /TP/NGSI-LD which contains the robot file with name args[0] + # Call with the folder below /TP/NGSI-LD or /IOP_TP/NGSI-LD which contains the robot file with name args[0] args = argv[1:] if len(args) == 0: - tp_root_name = dirname(dirname(__file__)).replace("\\", "/") - robot_file_tbp = f"{tp_root_name}/TP/NGSI-LD/" - robot_file_tbp = robot_file_tbp.replace("\\", "/") - for root, dirs, files in walk(robot_file_tbp): + basedir = dirname(dirname(__file__)).replace("\\", "/") + + # Process all TP files + tp_path = f"{basedir}/TP/NGSI-LD" + for root, dirs, files in walk(tp_path): for file in files: if file.endswith(".robot"): filename = file.replace(".robot", "") print(f"Generating json for {filename}") create_json_of_robotfile(filename, computestatistics=True) + + # Process all IOP files + iop_path = f"{basedir}/IOP_TP/NGSI-LD" + if exists(iop_path): + for root, dirs, files in walk(iop_path): + for file in files: + if file.endswith(".robot"): + filename = file.replace(".robot", "") + print(f"Generating json for {filename}") + create_json_of_robotfile(filename, computestatistics=True) else: robot_file_tbp = args[0] resulting_json = create_json_of_robotfile(robot_file_tbp) diff --git a/doc/generateIOPDocx.py b/doc/generateIOPDocx.py deleted file mode 100644 index 221416f9..00000000 --- a/doc/generateIOPDocx.py +++ /dev/null @@ -1,250 +0,0 @@ -#!/usr/bin/env python3 -# -# Usage: python3 generateIOPDocx.py [output_directory] -# -""" -Script to generate a DOCX file from a Robot Framework test case. -""" - -import re -import sys -from pathlib import Path -from typing import Dict, List -from docx import Document -from docx.shared import Pt -from docx.enum.text import WD_PARAGRAPH_ALIGNMENT - -def process_continuation_lines(text: str) -> List[str]: - """ - Process lines with '...' continuation markers and return clean lines. - """ - lines = [] - for line in text.split('\n'): - line = line.strip() - if line and not line.startswith('...'): - lines.append(line) - elif line.startswith('...'): - line_content = line.replace('...', '').strip() - if line_content: - lines.append(line_content) - return lines - -def extract_with_regex(content: str, pattern: str, group: int = 1) -> str: - """ - Extract text from content using regex pattern. - """ - match = re.search(pattern, content, re.MULTILINE | re.DOTALL) - return match.group(group).strip() if match else "" - -def extract_test_info(robot_file_path: str) -> Dict: - """ - Extract test case information from a Robot Framework file using regex. - """ - result = { - 'test_id': None, - 'settings_documentation': [], - 'test_documentation': [], - 'tags': [], - 'comments': [] - } - - with open(robot_file_path, 'r', encoding='utf-8') as f: - content = f.read() - - # Extract settings documentation - settings_doc = extract_with_regex( - content, - r'^\s*Documentation\s+(.*?)(?=\n\s*(?:Resource|Library|Test Setup|Test Teardown|Test Template|Suite Setup|Suite Teardown|\*\*\*))' - ) - if settings_doc: - result['settings_documentation'] = process_continuation_lines(settings_doc) - - # Extract test ID - result['test_id'] = extract_with_regex( - content, - r'^\*\*\* Test Cases \*\*\*\s+(.+?)(?:\n\s+\[Documentation\]|\n\s+\[Tags\]|\n\s+\[|\n\s*$)' - ) - - # Extract test documentation - test_doc = extract_with_regex( - content, - r'\[Documentation\]\s*(.*?)(?=\n\s+\[|\n\s*\n)' - ) - if test_doc: - result['test_documentation'] = process_continuation_lines(test_doc) - - # Extract tags - tags_text = extract_with_regex( - content, - r'\[Tags\]\s*(.*?)(?=\n\s+[A-Z]|\n\n|\Z)' - ) - result['tags'] = [tag.strip() for tag in tags_text.split() if tag.strip()] - - # Extract comments - result['comments'] = [c.strip() for c in re.findall(r'^\s*#(.+?)$', content, re.MULTILINE)] - - return result - -def add_table_row(table, label: str, content: str, is_header: bool = False): - """ - Add a row to the table with label and content. - """ - row = table.add_row() - - for cell, text in zip(row.cells, [label, content]): - para = cell.paragraphs[0] - para.text = text - - if is_header and para.runs: - para.runs[0].bold = True - para.runs[0].font.size = Pt(12) - -def add_merged_header_row(table, header_text: str): - row = table.add_row() - merged_cell = row.cells[0].merge(row.cells[1]) - para = merged_cell.paragraphs[0] - para.text = header_text - para.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER - for run in para.runs: - run.bold = True - run.font.size = Pt(12) - -def add_table_sections(table, test_info: Dict): - """ - Add all table sections using a parametrized approach. - """ - sections = [ - { - 'label': 'Test Purpose', - 'data': ' '.join(test_info['settings_documentation']) if test_info['settings_documentation'] else None, - 'split_multiline': False - }, - { - 'label': 'Documentation', - 'data': test_info['test_documentation'], - 'split_multiline': True, - 'split_on_colon': True - }, - { - 'label': 'Tags', - 'data': ', '.join(test_info['tags']) if test_info['tags'] else None, - 'split_multiline': False - }, - { - 'label': 'Test Case', - 'data': "\n".join([f"{i+1}. {c}" for i, c in enumerate(test_info['comments'])]) if test_info['comments'] else None, - 'split_multiline': False, - 'split_on_colon': False - } - ] - - for section in sections: - if not section['data']: - continue - - if section['split_multiline']: - for line in section['data']: - line = line.lstrip('.') - if section.get('split_on_colon') and ':' in line: - parts = line.split(':', 1) - add_table_row(table, parts[0].strip(), parts[1].strip()) - else: - add_table_row(table, section['label'], line) - else: - add_table_row(table, section['label'], section['data']) - -def find_robot_files(folder_path: Path) -> List[Path]: - """ - Find all .robot files in a folder recursively. - """ - return sorted(folder_path.glob('**/*.robot')) - -def create_docx_from_multiple_tests(robot_files: List[Path], output_dir: Path, folder_name: str) -> str: - """ - Create a single DOCX file with all robot tests as separate tables. - """ - doc = Document() - - title = doc.add_heading(folder_name, level=1) - title.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER - - for robot_file in robot_files: - test_info = extract_test_info(str(robot_file)) - test_name = robot_file.stem - - if not test_info['test_id']: - continue - - test_heading = doc.add_heading(test_name, level=2) - - table = doc.add_table(rows=0, cols=2) - add_merged_header_row(table, test_info['test_id']) - add_table_sections(table, test_info) - - doc.add_paragraph() - - output_path = output_dir / f"{folder_name}.docx" - doc.save(str(output_path)) - return str(output_path) - -def create_docx_from_robot_test(robot_file_path: str, output_dir: str = None, test_name: str = None, folder_name: str = None) -> str: - test_info = extract_test_info(robot_file_path) - - if not test_info['test_id']: - print("Error: Could not extract test case ID from the file") - return None - - test_name = test_name or test_info['test_id'] - - doc = Document() - - title_text = folder_name or test_name - title = doc.add_heading(title_text, level=1) - title.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER - - table = doc.add_table(rows=0, cols=2) - add_merged_header_row(table, test_name) - add_table_sections(table, test_info) - - output_dir = Path(output_dir or Path(robot_file_path).parent) - output_path = output_dir / f"{test_name}.docx" - - doc.save(str(output_path)) - -def main(): - if len(sys.argv) < 2: - print("Usage: python generate_test_doc.py [output_directory]") - sys.exit(1) - - input_path = Path(sys.argv[1]) - output_dir = Path(sys.argv[2]) if len(sys.argv) > 2 else None - - if not input_path.exists(): - print(f"Error: Path not found: {input_path}") - sys.exit(-1) - - try: - if input_path.is_file(): - # Single file - test_name = input_path.stem - folder_name = input_path.parent.name - output_dir = output_dir or input_path.parent - create_docx_from_robot_test(str(input_path), str(output_dir), test_name=test_name, folder_name=folder_name) - print("\nCorrectly exiting") - else: - # Folder - robot_files = find_robot_files(input_path) - if not robot_files: - print(f"Error: No .robot files found in {input_path}") - sys.exit(-1) - - output_dir = output_dir or input_path - folder_name = input_path.name - create_docx_from_multiple_tests(robot_files, output_dir, folder_name) - print("\nCorrectly exiting") - except Exception as e: - print(f"Error: {e}") - sys.exit(-1) - -if __name__ == "__main__": - main() diff --git a/doc/statisticsDocumentationData.py b/doc/statisticsDocumentationData.py index 9ec989b0..2369a510 100644 --- a/doc/statisticsDocumentationData.py +++ b/doc/statisticsDocumentationData.py @@ -36,9 +36,13 @@ if __name__ == "__main__": for name in dirs: os.rmdir(join(root, name)) - fullpath = basedir + "/TP/NGSI-LD" + fullpath = [ + (basedir + "/TP/NGSI-LD", "TP"), + (basedir + "/IOP_TP/NGSI-LD", "IOP") + ] + excluded_dirs = [""] - for root, dirs, files in walk(fullpath): + for root, dirs, files in fullpath: if root == fullpath: dirs[:] = [d for d in dirs if d not in excluded_dirs] for filename in files: @@ -70,7 +74,9 @@ if __name__ == "__main__": number_of_successes += 1 # we add it here because Fernando's code does not, in case of successful parsing json_of_test_case["error_while_parsing"] = False - if json_of_test_case["robotpath"].startswith("DistributedOperations"): + if json_of_test_case["robotpath"].startswith("Interoperability"): + json_of_test_case["config_id"] = "CF_06" + elif json_of_test_case["robotpath"].startswith("DistributedOperations"): json_of_test_case["config_id"] = "CF_04" elif json_of_test_case["robotpath"].startswith("ContextSource"): json_of_test_case["config_id"] = "CF_03" -- GitLab