Skip to content
...@@ -17,7 +17,7 @@ ${expectation_file}= vehicles-temporal-representation-021-06-expe ...@@ -17,7 +17,7 @@ ${expectation_file}= vehicles-temporal-representation-021-06-expe
*** Test Cases *** *** Test Cases ***
Query the temporal evolution of entities matching the given identifier(s) 021_06_01 Query the temporal evolution of entities matching the given identifier(s)
[Documentation] Check that you can query the temporal evolution of entities matching the given identifier(s) [Documentation] Check that you can query the temporal evolution of entities matching the given identifier(s)
[Tags] te-query 5_7_4 [Tags] te-query 5_7_4
${entity_types_to_be_retrieved}= Catenate SEPARATOR=, Vehicle ${entity_types_to_be_retrieved}= Catenate SEPARATOR=, Vehicle
......
...@@ -17,7 +17,7 @@ ${expectation_file}= vehicles-temporal-representation-021-07-expe ...@@ -17,7 +17,7 @@ ${expectation_file}= vehicles-temporal-representation-021-07-expe
*** Test Cases *** *** Test Cases ***
Query the temporal evolution of entities matching the given id pattern 021_07_01 Query the temporal evolution of entities matching the given id pattern
[Documentation] Check that you can query the temporal evolution of entities matching the given id pattern [Documentation] Check that you can query the temporal evolution of entities matching the given id pattern
[Tags] te-query 5_7_4 [Tags] te-query 5_7_4
${entity_types_to_be_retrieved}= Catenate SEPARATOR=, Vehicle ${entity_types_to_be_retrieved}= Catenate SEPARATOR=, Vehicle
......
...@@ -17,7 +17,7 @@ ${expectation_file}= vehicles-temporal-representation-021-08-expe ...@@ -17,7 +17,7 @@ ${expectation_file}= vehicles-temporal-representation-021-08-expe
*** Test Cases *** *** Test Cases ***
Query the temporal evolution of entities matching the given NGSI-LD query 021_08_01 Query the temporal evolution of entities matching the given NGSI-LD query
[Documentation] Check that you can query the temporal evolution of entities matching the given NGSI-LD query [Documentation] Check that you can query the temporal evolution of entities matching the given NGSI-LD query
[Tags] te-query 5_7_4 [Tags] te-query 5_7_4
${entity_types_to_be_retrieved}= Catenate SEPARATOR=, Vehicle ${entity_types_to_be_retrieved}= Catenate SEPARATOR=, Vehicle
......
...@@ -18,9 +18,9 @@ ${expectation_file}= vehicles-temporal-representation-021-09-expe ...@@ -18,9 +18,9 @@ ${expectation_file}= vehicles-temporal-representation-021-09-expe
*** Test Cases *** GEOREL GEOMETRY COORDINATES GEOPROPERTY EXPECTATION_FILE *** Test Cases *** GEOREL GEOMETRY COORDINATES GEOPROPERTY EXPECTATION_FILE
Near Point [Tags] te-query 5_7_4 021_09_01 Near Point [Tags] te-query 5_7_4
near;maxDistance==2000 Point [-8.503,41.202] ${EMPTY} vehicles-temporal-representation-021-09-01-expectation.jsonld near;maxDistance==2000 Point [-8.503,41.202] ${EMPTY} vehicles-temporal-representation-021-09-01-expectation.jsonld
Within Polygon [Tags] te-query 5_7_4 021_09_02 Within Polygon [Tags] te-query 5_7_4
contains Polygon [[[-13.503,47.202],[6.541, 52.961],[20.37,44.653],[9.46,32.57],[-13.503,32.57],[-13.503,47.202]]] location vehicles-temporal-representation-021-09-02-expectation.jsonld contains Polygon [[[-13.503,47.202],[6.541, 52.961],[20.37,44.653],[9.46,32.57],[-13.503,32.57],[-13.503,47.202]]] location vehicles-temporal-representation-021-09-02-expectation.jsonld
......
...@@ -17,7 +17,7 @@ ${context_source_url}= http://${context_source_ ...@@ -17,7 +17,7 @@ ${context_source_url}= http://${context_source_
*** Test Cases *** *** Test Cases ***
Query the temporal evolution of entities matching the given NGSI-LD context source filter 021_10_01 Query the temporal evolution of entities matching the given NGSI-LD context source filter
[Documentation] Check that you can query the temporal evolution of entities matching the given NGSI-LD Context Source filter [Documentation] Check that you can query the temporal evolution of entities matching the given NGSI-LD Context Source filter
[Tags] te-query 5_7_4 [Tags] te-query 5_7_4
${entity_types_to_be_retrieved}= Catenate SEPARATOR=, Building ${entity_types_to_be_retrieved}= Catenate SEPARATOR=, Building
......
...@@ -15,7 +15,7 @@ ${vehicle_payload_file}= 2020-08-vehicule-temporal-representation-sample.json ...@@ -15,7 +15,7 @@ ${vehicle_payload_file}= 2020-08-vehicule-temporal-representation-sample.json
*** Test Cases *** *** Test Cases ***
Query the temporal evolution of entities with an invalid request 021_12_01 Query the temporal evolution of entities with an invalid request
[Documentation] Check that you cannot query the temporal evolution of entities with an invalid request [Documentation] Check that you cannot query the temporal evolution of entities with an invalid request
[Tags] te-query 5_7_4 [Tags] te-query 5_7_4
${response}= Query Temporal Representation Of Entities ${response}= Query Temporal Representation Of Entities
......
...@@ -16,7 +16,7 @@ ${vehicle_expectation_file}= vehicle-temporal-representation-020-01-expectati ...@@ -16,7 +16,7 @@ ${vehicle_expectation_file}= vehicle-temporal-representation-020-01-expectati
*** Test Cases *** *** Test Cases ***
Retrieve the temporal evolution of an entity 020_01_01 Retrieve the temporal evolution of an entity
[Documentation] Check that you can retrieve the temporal evolution of an entity [Documentation] Check that you can retrieve the temporal evolution of an entity
[Tags] te-retrieve 5_7_3 [Tags] te-retrieve 5_7_3
${response}= Retrieve Temporal Representation Of Entity ${temporal_entity_representation_id} ${response}= Retrieve Temporal Representation Of Entity ${temporal_entity_representation_id}
......
...@@ -16,7 +16,7 @@ ${vehicle_expectation_file}= vehicle-temporal-representation-020-02-expectati ...@@ -16,7 +16,7 @@ ${vehicle_expectation_file}= vehicle-temporal-representation-020-02-expectati
*** Test Cases *** *** Test Cases ***
Retrieve the temporal evolution of an entity using a context 020_02_01 Retrieve the temporal evolution of an entity using a context
[Documentation] Check that you can retrieve the temporal evolution of an entity using a context [Documentation] Check that you can retrieve the temporal evolution of an entity using a context
[Tags] te-retrieve 5_7_3 [Tags] te-retrieve 5_7_3
${response}= Retrieve Temporal Representation Of Entity ${response}= Retrieve Temporal Representation Of Entity
......
...@@ -16,7 +16,7 @@ ${vehicle_expectation_file}= vehicle-temporal-representation-020-03-expectati ...@@ -16,7 +16,7 @@ ${vehicle_expectation_file}= vehicle-temporal-representation-020-03-expectati
*** Test Cases *** *** Test Cases ***
Retrieve the temporal evolution of certain attributes of an entity 020_03_01 Retrieve the temporal evolution of certain attributes of an entity
[Documentation] Check that you can retrieve the temporal evolution of certain attributes of an entity [Documentation] Check that you can retrieve the temporal evolution of certain attributes of an entity
[Tags] te-retrieve 5_7_3 [Tags] te-retrieve 5_7_3
@{temporal_attributes_to_be_retrieved}= Create List fuelLevel @{temporal_attributes_to_be_retrieved}= Create List fuelLevel
......
...@@ -7,7 +7,7 @@ Resource ${EXECDIR}/resources/JsonUtils.resource ...@@ -7,7 +7,7 @@ Resource ${EXECDIR}/resources/JsonUtils.resource
*** Test Cases *** *** Test Cases ***
Retrieve the temporal evolution of an entity with an invalid id 020_06_01 Retrieve the temporal evolution of an entity with an invalid id
[Documentation] Check that you cannot retrieve the temporal evolution of an entity with an invalid id (invalid URI) [Documentation] Check that you cannot retrieve the temporal evolution of an entity with an invalid id (invalid URI)
[Tags] te-retrieve 5_7_3 [Tags] te-retrieve 5_7_3
${response}= Retrieve Temporal Representation Of Entity invalidUri ${response}= Retrieve Temporal Representation Of Entity invalidUri
......
...@@ -7,7 +7,7 @@ Resource ${EXECDIR}/resources/JsonUtils.resource ...@@ -7,7 +7,7 @@ Resource ${EXECDIR}/resources/JsonUtils.resource
*** Test Cases *** *** Test Cases ***
Retrieve the temporal evolution of a non-existing entity 020_07_01 Retrieve the temporal evolution of a non-existing entity
[Documentation] Check that you cannot retrieve the temporal evolution of a non-existing entity [Documentation] Check that you cannot retrieve the temporal evolution of a non-existing entity
[Tags] te-retrieve 5_7_3 [Tags] te-retrieve 5_7_3
${response}= Retrieve Temporal Representation Of Entity urn:ngsi-ld:Vehicle:unknowEntity ${response}= Retrieve Temporal Representation Of Entity urn:ngsi-ld:Vehicle:unknowEntity
......
...@@ -15,7 +15,7 @@ ${vehicle_payload_file}= 2020-08-vehicule-temporal-representation-sample.json ...@@ -15,7 +15,7 @@ ${vehicle_payload_file}= 2020-08-vehicule-temporal-representation-sample.json
*** Test Cases *** *** Test Cases ***
Retrieve the temporal evolution of non-existing entity attributes 020_08_01 Retrieve the temporal evolution of non-existing entity attributes
[Documentation] Check that you cannot retrieve the temporal evolution of non-existing entity attributes [Documentation] Check that you cannot retrieve the temporal evolution of non-existing entity attributes
[Tags] te-retrieve 5_7_3 [Tags] te-retrieve 5_7_3
@{temporal_attributes_to_be_retrieved}= Create List unknownAttribute @{temporal_attributes_to_be_retrieved}= Create List unknownAttribute
......
...@@ -16,7 +16,7 @@ ${vehicle_expectation_file}= vehicle-temporal-representation-020-10-expectati ...@@ -16,7 +16,7 @@ ${vehicle_expectation_file}= vehicle-temporal-representation-020-10-expectati
*** Test Cases *** *** Test Cases ***
Retrieve the temporal evolution of an entity with the simplified temporal representation 020_10_01 Retrieve the temporal evolution of an entity with the simplified temporal representation
[Documentation] Check that you can retrieve the temporal evolution of an entity with the simplified temporal representation [Documentation] Check that you can retrieve the temporal evolution of an entity with the simplified temporal representation
[Tags] te-retrieve 5_7_3 [Tags] te-retrieve 5_7_3
@{options}= Create List temporalValues @{options}= Create List temporalValues
......
...@@ -91,16 +91,16 @@ class Checks: ...@@ -91,16 +91,16 @@ class Checks:
}, },
'Check Response Headers Containing Content-Type set to': { 'Check Response Headers Containing Content-Type set to': {
'params': ['content_type'], 'params': ['content_type'],
'position': [] 'position': [1]
}, },
'Check Response Body Containing an Attribute set to': { 'Check Response Body Containing an Attribute set to': {
'params': ['attribute_name'], 'params': ['attribute_name'],
'position': [] 'position': []
}, },
'Check Response Body Containing List Containing EntityTemporal elements': { 'Check Response Body Containing List Containing EntityTemporal elements': {
'params': ['timeRel', 'timeAt'], 'params': ['filename', 'entity_ids'],
'position': [] 'position': [1, 2]
}, },
'Check Response Body Containing List Containing Subscription elements': { 'Check Response Body Containing List Containing Subscription elements': {
'params': ['number'], 'params': ['number'],
'position': [] 'position': []
...@@ -212,7 +212,7 @@ class Checks: ...@@ -212,7 +212,7 @@ class Checks:
@staticmethod @staticmethod
def check_response_body_containing_list_containing_entity_elements(kwargs: list) -> str: def check_response_body_containing_list_containing_entity_elements(kwargs: list) -> str:
return 'Response Body containing a list containing Entity elements, containing ${value} provided' return 'Response Body containing a list containing Entity Elements, containing ${value} provided'
@staticmethod @staticmethod
def check_response_body_containing_list_containing_entity_elements_with_different_types(kwargs: list) -> str: def check_response_body_containing_list_containing_entity_elements_with_different_types(kwargs: list) -> str:
...@@ -226,12 +226,12 @@ class Checks: ...@@ -226,12 +226,12 @@ class Checks:
@staticmethod @staticmethod
def check_response_body_containing_list_containing_entitytemporal_elements(kwargs: list) -> str: def check_response_body_containing_list_containing_entitytemporal_elements(kwargs: list) -> str:
if "timeRel" in kwargs and "timeAt" in kwargs: if 'filename' in kwargs and 'entity_ids' in kwargs:
return (f"Response Body containing a list containing EntityTemporal elements containing entity type in the " return (f"Request response body containing a list that contains Entity Temporal Elements\n"
f"list of entity types provided and entity id matching id pattern provided and attribute instances " f" compared with file '{kwargs['filename']}'\n"
f"'{kwargs['timeRel']}' '{kwargs['timeAt']}'") f" and using the list of entity ids define in '{kwargs['entity_ids']}'")
else: else:
raise Exception(f'ERROR, timeRel and/or timeAt attributes were not provided, but received: {kwargs}') raise Exception(f"ERROR, expected parameters 'filename' and 'entity_ids', but received '{kwargs}'")
@staticmethod @staticmethod
def check_response_body_containing_subscription_element(kwargs: list) -> str: def check_response_body_containing_subscription_element(kwargs: list) -> str:
......
from os.path import dirname from os.path import dirname
from robot.api import TestSuiteBuilder from robot.api import TestSuiteBuilder
from doc.analysis.parserobotfile import ParseRobotFile from analysis.parserobotfile import ParseRobotFile
from doc.analysis.parseapiutilsfile import ParseApiUtilsFile from analysis.parseapiutilsfile import ParseApiUtilsFile
from analysis.parsevariablesfile import ParseVariablesFile
import re import re
class GenerateRobotData: class GenerateRobotData:
def __init__(self, robot_file: str, execdir: str): def __init__(self, robot_file: str, execdir: str):
self.robot = ParseRobotFile(filename=robot_file, execdir=execdir) self.robot_file = robot_file
self.execdir = execdir
self.config_variables = ParseVariablesFile()
self.robot = ParseRobotFile(filename=robot_file, execdir=execdir, config_file=self.config_variables)
self.apiutil = ParseApiUtilsFile(filename=self.robot.resource_file) self.apiutil = ParseApiUtilsFile(filename=self.robot.resource_file)
self.robot.set_apiutils(self.apiutil) self.robot.set_apiutils(self.apiutil)
...@@ -22,9 +27,13 @@ class GenerateRobotData: ...@@ -22,9 +27,13 @@ class GenerateRobotData:
'ContextInformation': 'CI', 'ContextInformation': 'CI',
'CommonBehaviours': 'CB', 'CommonBehaviours': 'CB',
'Consumption': 'Cons', 'Consumption': 'Cons',
'Provision': 'Prov',
'Discovery/RetrieveAvailableAttributeInformation': 'DISC',
'Discovery/RetrieveAvailableEntityTypeInformation': 'DISC',
'Entity/RetrieveEntity': 'E', 'Entity/RetrieveEntity': 'E',
'Entities/CreateEntity': 'E', 'Entities/CreateEntity': 'E',
'Provision': 'Prov' 'Entity/QueryEntities': 'E',
'TemporalEntity/QueryTemporalEvolutionOfEntities': 'TE'
} }
self.references = { self.references = {
'v1.3.1': 'ETSI GS CIM 009 V1.3.1 [], clause ' 'v1.3.1': 'ETSI GS CIM 009 V1.3.1 [], clause '
...@@ -44,6 +53,9 @@ class GenerateRobotData: ...@@ -44,6 +53,9 @@ class GenerateRobotData:
self.base_TP_id = str() self.base_TP_id = str()
def get_info(self): def get_info(self):
self.test_suite['robotpath'] = (self.robot_file.replace(f'{self.execdir}/TP/NGSI-LD/', '')
.replace(f'/{self.robot.test_suite}.robot', ''))
self.test_suite['robotfile'] = self.robot.test_suite
return self.test_suite return self.test_suite
def parse_robot(self): def parse_robot(self):
...@@ -66,15 +78,17 @@ class GenerateRobotData: ...@@ -66,15 +78,17 @@ class GenerateRobotData:
return keys_with_different_values return keys_with_different_values
def get_params(self, string: str): def get_params(self, test_case: str):
# New content # New content
test_case = self.robot.test_cases[string] # test_case = self.robot.test_cases[string]
lines_starting_response = re.findall(r'^\s*\$\{response\}.*', test_case, re.MULTILINE) lines_starting_response = re.findall(r'^\s*\$\{response\}.*', test_case, re.MULTILINE)
# If there is more than one line, it means that the test case has several operations, all of them to # If there is more than one line, it means that the test case has several operations, all of them to
# create the environment content to execute the last one, which is the correct one to test the Test Case # create the environment content to execute the last one, which is the correct one to test the Test Case
if len(lines_starting_response) > 1: if len(lines_starting_response) > 1:
# The last one corresponds to the execution of the test, the rest corresponds to the initial condition of
# test case...
response_to_check = lines_starting_response[-1] response_to_check = lines_starting_response[-1]
else: else:
response_to_check = lines_starting_response[0] response_to_check = lines_starting_response[0]
...@@ -102,8 +116,8 @@ class GenerateRobotData: ...@@ -102,8 +116,8 @@ class GenerateRobotData:
break break
else: else:
# the attributes are in the same line # the attributes are in the same line
regex = r"\s*\$\{response\}=\s{4}(.*)\n" regex = r"\s*\$\{response\}=\s{4}(.*)"
matches = re.finditer(regex, string, re.MULTILINE) matches = re.finditer(regex, response_to_check, re.MULTILINE)
request = aux[0].split(' ')[2] request = aux[0].split(' ')[2]
# We have two options from here, or the parameters are defined in the same line or the parameters are defined in # We have two options from here, or the parameters are defined in the same line or the parameters are defined in
...@@ -115,16 +129,18 @@ class GenerateRobotData: ...@@ -115,16 +129,18 @@ class GenerateRobotData:
# Get the list of keys # Get the list of keys
params = aux.split(' ')[1:] params = aux.split(' ')[1:]
print(params)
else: else:
raise Exception(f"Error, unexpected format, received: '{string}'") raise Exception(f"Error, unexpected format, received: '{response_to_check}'")
return request, params return request, params
def get_step_data(self, test: str): def get_step_data(self, test: str):
string = self.robot.get_substring(initial_string=test, final_string=self.suite.name, include=False) # string = self.robot.get_substring(initial_string=test, final_string=self.suite.name, include=False)
string = self.robot.test_cases[test]
# request, params = self.get_params(string=string) # request, params = self.get_params(string=string)
request, params = self.get_params(string=test) request, params = self.get_params(test_case=string)
#self.check_header_parameters(params=params, test=test) #self.check_header_parameters(params=params, test=test)
...@@ -249,7 +265,7 @@ class GenerateRobotData: ...@@ -249,7 +265,7 @@ class GenerateRobotData:
'config_id': '', 'config_id': '',
'parent_release': version, 'parent_release': version,
'pics_selection': pics, 'pics_selection': pics,
'keywords': list(self.suite.keywords), 'keywords': [str(x) for x in self.suite.keywords],
'teardown': str(self.suite.teardown), 'teardown': str(self.suite.teardown),
'initial_condition': self.suite.setup, 'initial_condition': self.suite.setup,
'test_cases': list() 'test_cases': list()
......
...@@ -23,12 +23,13 @@ class ParseApiUtilsFile: ...@@ -23,12 +23,13 @@ class ParseApiUtilsFile:
index = None index = None
for i, item in enumerate(string): for i, item in enumerate(string):
if 'response' in item: if 'response' in item:
regex = "\s{4}\$\{response\}=\s{4}(.*)" regex = "\s{4}\$\{response\}=\s{4}(POST|GET|PUT|PATCH|DELETE).*"
match = re.match(pattern=regex, string=item) match = re.match(pattern=regex, string=item)
if match: if match:
verb = match.groups()[0] verb = match.groups()[0]
elif 'url' in item:
if 'url' in item:
#url = item.split('/')[1] #url = item.split('/')[1]
url = self.get_url_request(url=item) url = self.get_url_request(url=item)
...@@ -36,7 +37,14 @@ class ParseApiUtilsFile: ...@@ -36,7 +37,14 @@ class ParseApiUtilsFile:
@staticmethod @staticmethod
def get_url_request(url: str) -> list: def get_url_request(url: str) -> list:
regex = r"\s*\.{3}\s*url=\$\{url\}\/(.*)" # We have two options, the url is defined in the same line of the response or it is defined in the following
# lines with '...'
keys = list()
if 'response' in url:
url = [x for x in url.split(' ') if 'url' in x][0]
regex = r"\s*\.*\s*url=\$\{url\}\/(.*)"
match = re.match(pattern=regex, string=url) match = re.match(pattern=regex, string=url)
if match: if match:
......
import re import re
import os import os
from doc.analysis.checks import Checks from analysis.checks import Checks
from doc.analysis.requests import Requests from analysis.requests import Requests
class ParseRobotFile: class ParseRobotFile:
def __init__(self, filename: str, execdir: str): def __init__(self, filename: str, execdir: str, config_file):
self.test_suite = os.path.basename(filename).split('.')[0] self.test_suite = os.path.basename(filename).split('.')[0]
with open(filename, 'r') as file: with open(filename, 'r') as file:
...@@ -21,6 +21,8 @@ class ParseRobotFile: ...@@ -21,6 +21,8 @@ class ParseRobotFile:
self.get_apiutils_path() self.get_apiutils_path()
self.get_test_cases() self.get_test_cases()
self.config_file = config_file
def set_apiutils(self, apiutils): def set_apiutils(self, apiutils):
self.apiutils = apiutils self.apiutils = apiutils
...@@ -37,19 +39,6 @@ class ParseRobotFile: ...@@ -37,19 +39,6 @@ class ParseRobotFile:
else: else:
raise Exception("Error, the variable is not following the format ${thing} = <value>") raise Exception("Error, the variable is not following the format ${thing} = <value>")
# def get_expected_status_code(self, keyword: str):
# # Check Response Status Code ${expected_status_code} ${response.status_code}
# # Check Response Body Containing ProblemDetails Element Containing Type Element set to
# # ... ${response.json()}
# # ... ${ERROR_TYPE_LD_CONTEXT_NOT_AVAILABLE}
# string = self.get_substring(initial_string=keyword, final_string='\n', include=True)
# expected_status_code = string.split(' ')[1]
#
# if expected_status_code.isdigit():
# return expected_status_code
# else:
# return self.variables[expected_status_code]
def get_apiutils_path(self): def get_apiutils_path(self):
string = self.get_substring(initial_string='Resource', final_string='*** Variables ***', include=True) string = self.get_substring(initial_string='Resource', final_string='*** Variables ***', include=True)
result = [item for item in string.split('\n') if 'ApiUtils.resource' in item and item[0] != '#'] result = [item for item in string.split('\n') if 'ApiUtils.resource' in item and item[0] != '#']
...@@ -90,16 +79,30 @@ class ParseRobotFile: ...@@ -90,16 +79,30 @@ class ParseRobotFile:
indexes = list() indexes = list()
self.test_case_names = list() self.test_case_names = list()
for match in matches: if matches:
name = match.strip() for match in matches:
self.test_case_names.append(name) name = match.strip()
indexes.append(string.find(name)) self.test_case_names.append(name)
indexes.append(string.find(name))
else:
# The test case has the same id. number as the test suite
pattern = f'{self.test_suite}\s.*'
matches = re.findall(pattern=pattern, string=string)
for match in matches:
name = match.strip()
self.test_case_names.append(name)
indexes.append(string.find(name))
self.test_cases = dict() self.test_cases = dict()
for i in range(0, len(indexes)-1): for i in range(0, len(indexes)-1):
self.test_cases[self.test_case_names[i]] = string[indexes[i]:indexes[i+1]] self.test_cases[self.test_case_names[i]] = string[indexes[i]:indexes[i+1]]
self.test_cases[self.test_case_names[-1]] = string[indexes[-1]:] try:
self.test_cases[self.test_case_names[-1]] = string[indexes[-1]:]
except IndexError:
raise Exception(f"ERROR, List index out of range, "
f"probably the name of the Test Case is not following the pattern '{pattern}'")
def get_checks(self, test_name, apiutils): def get_checks(self, test_name, apiutils):
data = Checks() data = Checks()
...@@ -136,8 +139,9 @@ class ParseRobotFile: ...@@ -136,8 +139,9 @@ class ParseRobotFile:
return new_list return new_list
def get_request(self, test_name): def get_request(self, test_name):
print(test_name) data = Requests(variables=self.variables,
data = Requests(variables=self.variables, apiutils_variables=self.apiutils.variables) apiutils_variables=self.apiutils.variables,
config_file=self.config_file)
description = data.get_description(string=self.test_cases[test_name]) description = data.get_description(string=self.test_cases[test_name])
return description return description
...@@ -212,7 +216,6 @@ class ParseRobotFile: ...@@ -212,7 +216,6 @@ class ParseRobotFile:
for i in range(0, len(position_params['position'])): for i in range(0, len(position_params['position'])):
param_key = position_params['params'][i] param_key = position_params['params'][i]
param_position = position_params['position'][i] param_position = position_params['position'][i]
# param_value = self.variables[params[param_position]-1]
param_value = self.get_param_value(position=params[param_position-1]) param_value = self.get_param_value(position=params[param_position-1])
param[param_key] = param_value param[param_key] = param_value
......
from os.path import dirname
class ParseVariablesFile:
def __init__(self):
folder = dirname(dirname(dirname(__file__)))
filename = f'{folder}/resources/variables.py'
self.variables = dict()
with open(filename, 'r') as file:
# Read the contents of the file
file_content = file.read()
file_content = file_content.split('\n')
file_content = [x.split('=') for x in file_content if x != '']
self.variables = {x[0].strip(): x[1].replace("'", "").strip() for x in file_content}
def get_variable(self, variable: str) -> str:
# We request the variable in the form '${...}'
variable = variable.strip('${}')
value = self.variables[variable]
return value
...@@ -2,30 +2,78 @@ import re ...@@ -2,30 +2,78 @@ import re
class Requests: class Requests:
def __init__(self, variables, apiutils_variables): def __init__(self, variables, apiutils_variables, config_file):
self.op = { self.op = {
'Create Entity Selecting Content Type': { 'Create Entity Selecting Content Type': {
'positions': [1, 3], 'positions': [0, 2],
'params': ['filename', 'content_type'] 'params': ['filename', 'content_type']
}, },
'Create Subscription': { 'Create Subscription': {
'positions': [2, 3], 'positions': [1, 2],
'params': ['filename', 'content_type'] 'params': ['filename', 'content_type']
}, },
'Create Or Update Temporal Representation Of Entity Selecting Content Type': { 'Create Or Update Temporal Representation Of Entity Selecting Content Type': {
'positions': [2, 3], 'positions': [1, 2],
'params': ['filename', 'content_type'] 'params': ['filename', 'content_type']
}, },
'Batch Create Entities': { 'Batch Create Entities': {
'positions': [2], 'positions': [1],
'params': ['content_type'] 'params': ['content_type']
}, },
'Create Context Source Registration With Return': { 'Create Context Source Registration With Return': {
'positions': [1], 'positions': [0],
'params': ['filename'] 'params': ['filename']
},
'Query Entity': {
'positions': [1, 1],
'params': ['context', 'accept']
},
'Retrieve Subscription': {
'positions': [1],
'params': ['accept']
},
'Query Context Source Registrations With Return': {
'positions': [0, 1],
'params': ["type", "accept"]
},
'Query Temporal Representation Of Entities With Return': {
'positions': [],
'params': []
},
'Partial Update Entity Attributes': {
'positions': [2, 3, 4],
'params': ['filename', "content", "context"]
},
'Update Subscription': {
'positions': [1, 2, 3],
'params': ['filename', 'content', 'context']
},
'Query Context Source Registration Subscriptions': {
'positions': [0],
'params': ['accept']
},
'Query Temporal Representation Of Entities': {
'positions': [0, 1, 2, 3],
'params': ['entity_types', 'timerel', 'timeAt', 'accept']
},
'Retrieve Attribute': {
'positions': [0],
'params': ['attribute_name']
},
'Retrieve Entity Type': {
'positions': [0, 1],
'params': ['type', 'context']
},
'Query Entities': {
'positions': [0, 1],
'params': ['entity_ids', 'entity_types', 'accepts']
},
'Retrieve Temporal Representation Of Entity': {
'params': ['entity_ids', 'entity_types', 'accepts']
} }
} }
self.description = { self.description = {
'Create Entity Selecting Content Type': 'Create Entity Selecting Content Type':
Requests.create_entity_selecting_content_type, Requests.create_entity_selecting_content_type,
...@@ -36,33 +84,93 @@ class Requests: ...@@ -36,33 +84,93 @@ class Requests:
'Batch Create Entities': 'Batch Create Entities':
Requests.batch_create_entities, Requests.batch_create_entities,
'Create Context Source Registration With Return': 'Create Context Source Registration With Return':
Requests.create_context_source_registration_with_return Requests.create_context_source_registration_with_return,
} 'Query Entity':
Requests.query_entity,
'Retrieve Subscription':
Requests.retrieve_subscription,
'Query Context Source Registrations With Return':
Requests.query_context_source_registrations_with_return,
'Query Temporal Representation Of Entities With Return':
Requests.query_temporal_representation_of_entities_with_return,
'Partial Update Entity Attributes':
Requests.partial_update_entity_attributes,
'Update Subscription':
Requests.update_subscription,
'Query Context Source Registration Subscriptions':
Requests.query_context_source_registration_subscriptions,
'Query Temporal Representation Of Entities':
Requests.query_temporal_representation_of_entities,
'Retrieve Attribute':
Requests.retrieve_attribute,
'Retrieve Entity Type':
Requests.retrieve_entity_type,
'Query Entities':
Requests.query_entities
}
self.variables = variables self.variables = variables
self.apiutils_variables = apiutils_variables self.apiutils_variables = apiutils_variables
self.config_file = config_file
def get_description(self, string): def get_description(self, string):
keys = self.op.keys() keys = self.op.keys()
params = dict() params = dict()
index = None # New version
for k in keys: lines_starting_response = re.findall(r'^\s*\$\{response\}.*', string, re.MULTILINE)
index = string.find(k)
if index != -1:
break
pattern = f"^.*{k}.*\n" # If there is more than one line, it means that the test case has several operations, all of them to
lines_starting_with_request = re.findall(pattern, string, re.MULTILINE) # create the environment content to execute the last one, which is the correct one to test the Test Case
for line in lines_starting_with_request: if len(lines_starting_response) > 1:
data = line.strip().split(" ") # The last one corresponds to the execution of the test, the rest corresponds to the initial condition of
if len(data) == 2: # test case...
# We are in multiline definition response_to_check = lines_starting_response[-1]
params = self.find_attributes_next_line(string=string, position=index, request_name=k) else:
else: response_to_check = lines_starting_response[0]
# The definition of the request is in the same line
params = self.find_attributes_in_the_same_line(request_name=k, params=data[1:]) index = string.find(response_to_check)
aux = string[index:].split('\n')
params = list()
request = str()
# Get the list of params of the function, they are the keys
if ' ... ' in aux[1]:
request = aux[0].split(' ')[2]
# We are in the case that the attributes are in following lines
for i in range(1, len(aux)):
if ' ... ' in aux[i]:
regex = '\s{4}\.{3}\s{4}(.*)'
param = re.match(pattern=regex, string=aux[i])
if aux:
params.append(param.groups()[0])
else:
break
#params = self.find_attributes_next_lines(string=string, position=index, request_name=request)
params = self.find_attributes_in_the_same_line(request_name=request, params=params)
else:
# the attributes are in the same line
regex = r"\s*\$\{response\}=\s{4}(.*)"
matches = re.finditer(regex, response_to_check, re.MULTILINE)
request = aux[0].split(' ')[2]
# We have two options from here, or the parameters are defined in the same line or the parameters are defined in
# following lines, next lines
for match in matches:
# Check that we have 1 group matched
if len(match.groups()) == 1:
aux = match.group(1)
description = self.description[k](params) # Get the list of keys
params = aux.split(' ')[1:]
else:
raise Exception(f"Error, unexpected format, received: '{response_to_check}'")
params = self.find_attributes_in_the_same_line(request_name=request, params=params)
description = self.description[request](params)
return description return description
def find_attributes_in_the_same_line(self, request_name, params): def find_attributes_in_the_same_line(self, request_name, params):
...@@ -70,12 +178,12 @@ class Requests: ...@@ -70,12 +178,12 @@ class Requests:
for i in range(0, len(self.op[request_name]['positions'])): for i in range(0, len(self.op[request_name]['positions'])):
param_position = self.op[request_name]['positions'][i] param_position = self.op[request_name]['positions'][i]
param_key = self.op[request_name]['params'][i] param_key = self.op[request_name]['params'][i]
param_value = self.get_value(params=params, param_position=param_position) param_value = self.get_value(params=params, param_position=param_position, param_key=param_key)
param[param_key] = param_value param[param_key] = param_value
return param return param
def find_attributes_next_line(self, string, position, request_name): def find_attributes_next_lines(self, string, position, request_name):
aux = string[position+len(request_name)+1:].split('\n') aux = string[position+len(request_name)+1:].split('\n')
params = list() params = list()
...@@ -90,8 +198,8 @@ class Requests: ...@@ -90,8 +198,8 @@ class Requests:
for i in range(0, len(self.op[request_name]['positions'])): for i in range(0, len(self.op[request_name]['positions'])):
print(i) print(i)
param_position = self.op[request_name]['positions'][i] - 1 param_position = self.op[request_name]['positions'][i] - 1
param_value = self.get_value(params=params, param_position=param_position)
param_key = self.op[request_name]['params'][i] param_key = self.op[request_name]['params'][i]
param_value = self.get_value(params=params, param_position=param_position, param_key=param_key)
param[param_key] = param_value param[param_key] = param_value
return param return param
...@@ -123,13 +231,163 @@ class Requests: ...@@ -123,13 +231,163 @@ class Requests:
else: else:
raise Exception(f"ERROR, expected filename attribute, but received {kwargs}") raise Exception(f"ERROR, expected filename attribute, but received {kwargs}")
def get_value(self, params, param_position): @staticmethod
def query_entity(kwargs) -> str:
result = ''
if 'context' in kwargs and kwargs['context'] != '':
result = f"Request Header['Link'] contain the context {kwargs['context']}"
if 'accept' in kwargs:
result = f"{result}\nHeader['Accept'] set to {kwargs['accept']}"
if 'context' not in kwargs and 'accept' not in kwargs:
raise Exception(f"ERROR, expected context attribute, but received {kwargs}")
return result
@staticmethod
def retrieve_subscription(kwargs) -> str:
if 'accept' in kwargs:
return f"Request a subscription\nHeader['Accept'] set to '{kwargs['accept']}'"
else:
return "Request a subscription"
def query_context_source_registrations_with_return(kwargs) -> str:
if 'type' in kwargs and 'accept' in kwargs:
result = "Request a Context Source Registration with Return"
if kwargs['type'] != '':
result = f"{result}\nEntity Type set to '{kwargs['type']}'"
if kwargs['accept'] != '':
result = f"{result}\nHeader['Accept'] set to '{kwargs['accept']}'"
else:
result = "Request a Context Source Registration with Return"
return result
def query_temporal_representation_of_entities_with_return(kwargs) -> str:
return "Request a Temporal Representation of Entities with Return"
def partial_update_entity_attributes(kwargs) -> str:
if 'context' in kwargs and 'content' in kwargs and 'filename' in kwargs:
context = kwargs['context']
if context == '':
return (f"Request Partial Update Entity Attributes and \n"
f"Header['Content-Type'] set to '{kwargs['content']}' and\n"
f"Payload defined in file '{kwargs['filename']}'")
else:
return (f"Request Partial Update Entity Attributes and \n"
f"Header['Link'] contain the context '{kwargs['context']}' and \n"
f"Header['Content-Type'] set to '{kwargs['content']}' and\n"
f"Payload defined in file '{kwargs['filename']}'")
else:
raise Exception(f"ERROR, expected context attribute, but received {kwargs}")
def update_subscription(kwargs) -> str:
if 'context' in kwargs and 'content' in kwargs and 'filename' in kwargs:
context = kwargs['context']
if context == '':
return (f"Request Update Subscription and \n"
f"Header['Content-Type'] set to '{kwargs['content']}' and\n"
f"Payload defined in file '{kwargs['filename']}'")
else:
return (f"Request Update Subscription and \n"
f"Header['Link'] contain the context '{kwargs['context']}' and\n"
f"Header['Content-Type'] set to '{kwargs['content']}' and\n"
f"Payload defined in file '{kwargs['filename']}'")
else:
raise Exception(f"ERROR, expected context attribute, but received {kwargs}")
@staticmethod
def query_context_source_registration_subscriptions(kwargs) -> str:
if 'accept' in kwargs:
return (f"Request Context Source Registration Subscriptions\n"
f"Header['Accept'] set to '{kwargs['accept']}'")
else:
raise Exception(f"ERROR, expected accept attribute, but received {kwargs}")
@staticmethod
def query_temporal_representation_of_entities(kwargs) -> str:
expected_parameters = ['entity_types', 'timerel', 'timeAt', 'accept']
result = [x for x in expected_parameters if x not in kwargs]
if len(result) == 0:
response = ("Response containing:\n"
f" * Entity-Type is equal to '{kwargs['entity_types']}'\n"
f" * timeRel is equal to '{kwargs['timerel']}'\n"
f" * timeAt is equal to '{kwargs['timeAt']}'\n"
f" * Accept is equal to '{kwargs['accept']}'")
return response
else:
raise Exception(f"ERROR, unexpected attribute '{result}', the attributes expected are "
f"'{expected_parameters}', but received: {kwargs}")
@staticmethod
def retrieve_attribute(kwargs) -> str:
if 'attribute_name' in kwargs:
return f"Retrieve Attribute with attributeName set to '{kwargs['attribute_name']}'"
@staticmethod
def retrieve_entity_type(kwargs) -> str:
result = "Retrieve Entity Type"
if 'type' in kwargs:
result = f"{result}, with type set to '{kwargs['type']}'"
if 'context' in kwargs and kwargs['context'] != '':
result = f"{result}, with Header['Link'] containing '{kwargs['context']}'"
if 'type' not in kwargs or 'context' not in kwargs:
raise Exception(f"ERROR, expected type or context attributes, received '{kwargs}'")
return result
@staticmethod
def query_entities(kwargs) -> str:
result = "Request Query Entities"
if 'entity_ids' in kwargs and kwargs['entity_ids'] != '':
result = f"{result} with entity_ids set to '{kwargs['entity_ids']}'"
if 'entity_types' in kwargs and kwargs['entity_types'] != '':
result = f"{result} with entity_types set to '{kwargs['entity_types']}"
if 'accept' in kwargs and kwargs['accept'] != '':
result = f"{result} with Header['Accept'] set to '{kwargs['accept']}'"
return result
def get_value(self, params, param_position, param_key):
data = [x for x in params if f'{param_key}=' in x]
if len(data) == 1:
# The name of the attribute is passed to the function in the form attribute=value
data = data[0]
data = data.split('=')
if data[0] != param_key:
return ''
data = data[1]
elif len(data) == 0:
# There is no attribute=something therefore we have to apply the position
try:
data = params[param_position]
# Workaround
if 'accept' in data and param_key != 'accept':
data = ''
except IndexError:
return ''
try: try:
value = self.variables[params[param_position]] value = self.variables[data]
return value return value
except KeyError: except KeyError:
try: try:
value = self.apiutils_variables[params[param_position]] value = self.apiutils_variables[data]
return value return value
except KeyError: except KeyError:
return params[param_position] try:
value = self.config_file.get_variable(variable=data)
return value
except KeyError:
return data
{
"tp_id": "TP/NGSI-LD/CB/044_01",
"test_objective": "Verify that PATCH HTTP requests can be done with \"application/merge-patch+json\" as Content-Type",
"reference": "ETSI GS CIM 009 V1.3.1 [], clause 6.3.4",
"config_id": "",
"parent_release": "v1.3.1",
"pics_selection": "PICS_6_3_4",
"keywords": [],
"teardown": "None",
"initial_condition": "with {\n the SUT in the \"initial state\"\n}",
"test_cases": [
{
"name": "044_01_01 endpoint /entities/{entityId}/attrs/{attrId}",
"permutation_tp_id": "TP/NGSI-LD/CB/044_01_01",
"doc": "Verify that PATCH HTTP requests can be done with \"application/merge-patch+json\" as Content-Type",
"tags": [
"6_3_4",
"ea-partial-update"
],
"setup": null,
"teardown": "Delete Entity by Id",
"template": null,
"then": "then {\n the SUT sends a valid Response containing:\n Response Status Code set to 204\n}",
"when": "when {\n the SUT receives a Request from the client containing:\n URL set to '/ngsi-ld/v1/entities/{entityId}/attrs/{attributeId}'\n method set to 'PATCH'\n Request Header['Content-Type'] set to 'application/ld+json' and\n payload defined in file: 'vehicle-simple-attributes-sample.jsonld'",
"http_verb": "PATCH",
"endpoint": "entities/{entityId}/attrs/{attributeId}"
},
{
"name": "044_01_02 endpoint /subscriptions/{subscriptionId}",
"permutation_tp_id": "TP/NGSI-LD/CB/044_01_02",
"doc": "Verify that PATCH HTTP requests can be done with \"application/merge-patch+json\" as Content-Type",
"tags": [
"6_3_4",
"sub-update"
],
"setup": null,
"teardown": "Delete Subscription",
"template": null,
"then": "then {\n the SUT sends a valid Response containing:\n Response Status Code set to 204\n}",
"when": "when {\n the SUT receives a Request from the client containing:\n URL set to '/ngsi-ld/v1/subscriptions/{subscription_id}'\n method set to 'PATCH'\n Request Header['Content-Type'] set to 'application/ld+json' and\n payload defined in file: 'subscriptions/subscription-sample.jsonld'",
"http_verb": "PATCH",
"endpoint": "subscriptions/{subscription_id}"
}
],
"permutations": [
"endpoint",
"when"
]
}
\ No newline at end of file