Loading README.md +1 −1 Original line number Diff line number Diff line Loading @@ -147,7 +147,7 @@ Robot Framework. Our recommendations are: - Install [Robot Framework Language Server](https://plugins.jetbrains.com/plugin/16086-robot-framework-language-server) - Define as variable the path of the working directory. In Settings > Languages & Frameworks > Robot Framework (Project), insert the following: `{"EXECDIR": "{path}/auth-test-suite"}`. (Project), insert the following: `{"EXECDIR": "{path}/ngsi-ld-test-suite"}`. ### Run configurations (PyCharm) Loading doc/analysis/generaterobotdata.py +28 −21 Original line number Diff line number Diff line from os.path import dirname from robot.api import TestSuiteBuilder from analysis.parserobotfile import ParseRobotFile from analysis.parseapiutilsfile import ParseApiUtilsFile from analysis.parsevariablesfile import ParseVariablesFile from analysis.initial_setup import InitialSetup from doc.analysis.parserobotfile import ParseRobotFile from doc.analysis.parseapiutilsfile import ParseApiUtilsFile from doc.analysis.parsevariablesfile import ParseVariablesFile from doc.analysis.initial_setup import InitialSetup from re import match, findall, finditer, sub, MULTILINE Loading Loading @@ -102,7 +102,6 @@ class GenerateRobotData: self.initial_setup = InitialSetup() 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', '')) Loading Loading @@ -131,7 +130,8 @@ class GenerateRobotData: print(f'Something went wrong, the test suite {self.suite.resource.source} ' f'has different "setup" values for its test cases.') def get_permutation_keys(self, data): @staticmethod def get_permutation_keys(data): all_keys = set().union(*data) excluded_keys = ['doc', 'permutation_tp_id', 'setup', 'teardown', 'name', 'tags'] all_keys = [x for x in all_keys if x not in excluded_keys] Loading @@ -154,7 +154,7 @@ class GenerateRobotData: def get_params(self, test_case: str): test_case = self.get_data_template(string=test_case) lines_starting_response = findall(r'^\s*\$\{response\}.*|^\s*\$\{notification\}.*', test_case, MULTILINE) lines_starting_response = findall(r'^\s*\$\{response}.*|^\s*\$\{notification}.*', test_case, MULTILINE) # 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 Loading @@ -171,7 +171,7 @@ class GenerateRobotData: aux = [x for x in aux if x != ''] params = list() request = str() request = list() # Get the list of params of the function, they are the keys if ' ... ' in aux[1]: Loading @@ -181,7 +181,7 @@ class GenerateRobotData: # 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})*\s{4}\.{3}\s{4}(.*)' regex = r'(\s{4})*\s{4}\.{3}\s{4}(.*)' param = match(pattern=regex, string=aux[i]) if aux: params.append(param.groups()[1]) Loading @@ -193,8 +193,8 @@ class GenerateRobotData: matches = finditer(regex, response_to_check, 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 # 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 a_match in matches: # Check that we have 1 group matched if len(a_match.groups()) == 1: Loading @@ -215,6 +215,9 @@ class GenerateRobotData: request, params = self.get_params(test_case=string) verb = str() query_param = str() url = str() for data in self.apiutils: verb, url, query_param = data.get_response(keyword=request) if verb != '': Loading Loading @@ -245,6 +248,7 @@ class GenerateRobotData: key = header_key[0] value = self.get_header_value(key=key) else: aux = list() # 2nd case, maybe the params are defined in the way <param>=<value> for k in self.headers: aux = [x for x in params if k in x] Loading @@ -270,7 +274,7 @@ class GenerateRobotData: def get_values_url(self, keys: list, query_param: bool, request: str, params: list) -> str: data = [self.get_value_url(key=x, request=request, params=params) for x in keys] if query_param == False: if not query_param: data = '/'.join(data).replace('//', '/').replace('?/', '?') else: aux = '/'.join(data[:-1]).replace('//', '/').replace('?/', '?') Loading Loading @@ -374,6 +378,8 @@ class GenerateRobotData: tp_id = self.generate_name() reference, pics = self.generate_reference(version=version) # TODO: robotframework==7.0 has not property keywords in the class TestSuite(), we can get the data from # [x.to_dict()['name'] for x in list(self.suite.resource.keywords)] but with some differences in execution code self.test_suite = { 'tp_id': tp_id, 'test_objective': self.suite.doc, Loading @@ -381,7 +387,8 @@ class GenerateRobotData: 'config_id': str(), 'parent_release': version, 'pics_selection': pics, 'keywords': [str(x) for x in self.suite.keywords], # 'keywords': [str(x) for x in self.suite.keywords], 'keywords': [x.to_dict()['name'] for x in list(self.suite.resource.keywords)], 'teardown': str(self.suite.teardown), 'initial_condition': str(), 'test_cases': list() Loading Loading @@ -493,7 +500,6 @@ class GenerateRobotData: self.args = dict() _ = [self.args.update(x) for x in args] template_name = list(set([list(x.keywords)[0].name for x in self.suite.tests]))[0] # Due to the information of the tags are contained in the Keyword description of the template, we need to Loading Loading @@ -534,7 +540,8 @@ class GenerateRobotData: return reference, pics def get_substring(self, string: str, key: str): @staticmethod def get_substring(string: str, key: str): pos1 = string.find(key) - 1 pos2 = string[pos1:].find('\n') result = string[pos1:pos1+pos2].split(' ') Loading @@ -545,15 +552,15 @@ class GenerateRobotData: # check_tags = all(item == tags[0] for item in tags) # # if check_tags is False or len(tags) == 0: # raise Exception(f'ERROR: the Test Suite {{self.suite.name}} has different clauses or no clauses (Tags): {tags}\n' # f'Unable to select the corresponding Reference of this Test Suite') # raise Exception(f'ERROR: the Test Suite {{self.suite.name}} has different clauses or no clauses (Tags): ' # f'{tags}\nUnable to select the corresponding Reference of this Test Suite') # else: # # All the clauses are the same, so we select the first one # reference = f'{{self.references[version]}}{tags[0].replace("_", ".")}' # pics = f'PICS_{tags[0]}' # # return reference, pics aux = [x for x in tags if match(pattern='^(\d+_\d+_\d+)', string=x)] aux = [x for x in tags if match(pattern=r'^(\d+_\d+_\d+)', string=x)] if len(aux) == 0: raise Exception( Loading doc/analysis/initial_setup.py +10 −4 Original line number Diff line number Diff line Loading @@ -227,12 +227,12 @@ class InitialSetup: if len(deleted_setup) != 0: print(f" WARNING: Some of the Setup functions were deleted:\n{deleted_setup}") else: print(" INFO: All current Setup functions are used in the Robot files") print(f" INFO: All current Setup functions are used in the Robot files") if len(not_included_keys) != 0: print(f" ERROR: Some Setup functions are not include in the Class:\n{not_included_keys}") else: print(" INFO: All the current Setup functions used in Robot files are included in the Class") print(f" INFO: All the current Setup functions used in Robot files are included in the Class") print() Loading Loading @@ -264,13 +264,19 @@ class InitialSetup: def get_initial_condition(self, initial_condition: str) -> str: try: return self.init[initial_condition] if initial_condition is not None: data = self.init[initial_condition] else: data = '''with { the SUT containing an initial state }''' except KeyError: print(f"ERROR: the initial condition '{initial_condition}' is not defined in the dictionary. " f"Please check it and add the new initial condition.") data = '''with { the SUT containing an initial state }''' return data Loading doc/analysis/parseapiutilsfile.py +8 −9 Original line number Diff line number Diff line Loading @@ -21,10 +21,9 @@ class ParseApiUtilsFile: string = string[index:] string = string.split('\n') index = None for i, item in enumerate(string): if 'response' in item: regex = "\s{4}\$\{response\}=\s{4}(POST|GET|PUT|PATCH|DELETE).*" regex = r"\s{4}\$\{response\}=\s{4}(POST|GET|PUT|PATCH|DELETE).*" match = re.match(pattern=regex, string=item) if match: Loading @@ -35,8 +34,8 @@ class ParseApiUtilsFile: return verb, url, query_param @staticmethod def get_url_request(url: str) -> list: # We have two options, the url is defined in the same line of the response or it is defined in the following def get_url_request(url: str) -> [list, bool]: # 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() parameters = list() Loading @@ -57,7 +56,7 @@ class ParseApiUtilsFile: aux = parameters[0] query_param = True keys = re.split(r'\$|/', aux) keys = re.split(r'[$/]', aux) keys = [k for k in keys if k != ''] if len(parameters) != 0: Loading @@ -68,7 +67,7 @@ class ParseApiUtilsFile: match = re.match(pattern=regex, string=url) if match: aux = match.groups()[0] keys = re.split(r'\$|/', aux) keys = re.split(r'[$/]', aux) keys = [k for k in keys if k != ''] return keys, query_param Loading @@ -81,7 +80,7 @@ class ParseApiUtilsFile: def get_variables_data_variables(self, string): # Get the simple variables from the file regex = "^(\$\{.*\})\s*(.*)\n" regex = r"^(\$\{.*\})\s*(.*)\n" matches = re.finditer(regex, string, re.MULTILINE) for match in matches: Loading @@ -94,7 +93,7 @@ class ParseApiUtilsFile: def get_variables_data_dictionaries(self, string): # Get the dictionary variables from the file regex = '(\&\{.*\})' regex = r'(\&\{.*\})' matches = re.finditer(regex, string, re.MULTILINE) for match in matches: # Check that we have two groups matched Loading @@ -109,7 +108,7 @@ class ParseApiUtilsFile: index = aux.find('\n${') aux = aux[:index + 1] regex = '\.{3}[ ]*([a-zA-Z]+)=(.*)\n' regex = r'\.{3}[ ]*([a-zA-Z]+)=(.*)\n' matches2 = re.finditer(regex, aux, re.MULTILINE) dict_values = dict() for match2 in matches2: Loading doc/analysis/parserobotfile.py +2 −2 Original line number Diff line number Diff line import re import os from analysis.checks import Checks from analysis.requests import Requests from doc.analysis.checks import Checks from doc.analysis.requests import Requests class ParseRobotFile: Loading Loading
README.md +1 −1 Original line number Diff line number Diff line Loading @@ -147,7 +147,7 @@ Robot Framework. Our recommendations are: - Install [Robot Framework Language Server](https://plugins.jetbrains.com/plugin/16086-robot-framework-language-server) - Define as variable the path of the working directory. In Settings > Languages & Frameworks > Robot Framework (Project), insert the following: `{"EXECDIR": "{path}/auth-test-suite"}`. (Project), insert the following: `{"EXECDIR": "{path}/ngsi-ld-test-suite"}`. ### Run configurations (PyCharm) Loading
doc/analysis/generaterobotdata.py +28 −21 Original line number Diff line number Diff line from os.path import dirname from robot.api import TestSuiteBuilder from analysis.parserobotfile import ParseRobotFile from analysis.parseapiutilsfile import ParseApiUtilsFile from analysis.parsevariablesfile import ParseVariablesFile from analysis.initial_setup import InitialSetup from doc.analysis.parserobotfile import ParseRobotFile from doc.analysis.parseapiutilsfile import ParseApiUtilsFile from doc.analysis.parsevariablesfile import ParseVariablesFile from doc.analysis.initial_setup import InitialSetup from re import match, findall, finditer, sub, MULTILINE Loading Loading @@ -102,7 +102,6 @@ class GenerateRobotData: self.initial_setup = InitialSetup() 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', '')) Loading Loading @@ -131,7 +130,8 @@ class GenerateRobotData: print(f'Something went wrong, the test suite {self.suite.resource.source} ' f'has different "setup" values for its test cases.') def get_permutation_keys(self, data): @staticmethod def get_permutation_keys(data): all_keys = set().union(*data) excluded_keys = ['doc', 'permutation_tp_id', 'setup', 'teardown', 'name', 'tags'] all_keys = [x for x in all_keys if x not in excluded_keys] Loading @@ -154,7 +154,7 @@ class GenerateRobotData: def get_params(self, test_case: str): test_case = self.get_data_template(string=test_case) lines_starting_response = findall(r'^\s*\$\{response\}.*|^\s*\$\{notification\}.*', test_case, MULTILINE) lines_starting_response = findall(r'^\s*\$\{response}.*|^\s*\$\{notification}.*', test_case, MULTILINE) # 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 Loading @@ -171,7 +171,7 @@ class GenerateRobotData: aux = [x for x in aux if x != ''] params = list() request = str() request = list() # Get the list of params of the function, they are the keys if ' ... ' in aux[1]: Loading @@ -181,7 +181,7 @@ class GenerateRobotData: # 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})*\s{4}\.{3}\s{4}(.*)' regex = r'(\s{4})*\s{4}\.{3}\s{4}(.*)' param = match(pattern=regex, string=aux[i]) if aux: params.append(param.groups()[1]) Loading @@ -193,8 +193,8 @@ class GenerateRobotData: matches = finditer(regex, response_to_check, 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 # 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 a_match in matches: # Check that we have 1 group matched if len(a_match.groups()) == 1: Loading @@ -215,6 +215,9 @@ class GenerateRobotData: request, params = self.get_params(test_case=string) verb = str() query_param = str() url = str() for data in self.apiutils: verb, url, query_param = data.get_response(keyword=request) if verb != '': Loading Loading @@ -245,6 +248,7 @@ class GenerateRobotData: key = header_key[0] value = self.get_header_value(key=key) else: aux = list() # 2nd case, maybe the params are defined in the way <param>=<value> for k in self.headers: aux = [x for x in params if k in x] Loading @@ -270,7 +274,7 @@ class GenerateRobotData: def get_values_url(self, keys: list, query_param: bool, request: str, params: list) -> str: data = [self.get_value_url(key=x, request=request, params=params) for x in keys] if query_param == False: if not query_param: data = '/'.join(data).replace('//', '/').replace('?/', '?') else: aux = '/'.join(data[:-1]).replace('//', '/').replace('?/', '?') Loading Loading @@ -374,6 +378,8 @@ class GenerateRobotData: tp_id = self.generate_name() reference, pics = self.generate_reference(version=version) # TODO: robotframework==7.0 has not property keywords in the class TestSuite(), we can get the data from # [x.to_dict()['name'] for x in list(self.suite.resource.keywords)] but with some differences in execution code self.test_suite = { 'tp_id': tp_id, 'test_objective': self.suite.doc, Loading @@ -381,7 +387,8 @@ class GenerateRobotData: 'config_id': str(), 'parent_release': version, 'pics_selection': pics, 'keywords': [str(x) for x in self.suite.keywords], # 'keywords': [str(x) for x in self.suite.keywords], 'keywords': [x.to_dict()['name'] for x in list(self.suite.resource.keywords)], 'teardown': str(self.suite.teardown), 'initial_condition': str(), 'test_cases': list() Loading Loading @@ -493,7 +500,6 @@ class GenerateRobotData: self.args = dict() _ = [self.args.update(x) for x in args] template_name = list(set([list(x.keywords)[0].name for x in self.suite.tests]))[0] # Due to the information of the tags are contained in the Keyword description of the template, we need to Loading Loading @@ -534,7 +540,8 @@ class GenerateRobotData: return reference, pics def get_substring(self, string: str, key: str): @staticmethod def get_substring(string: str, key: str): pos1 = string.find(key) - 1 pos2 = string[pos1:].find('\n') result = string[pos1:pos1+pos2].split(' ') Loading @@ -545,15 +552,15 @@ class GenerateRobotData: # check_tags = all(item == tags[0] for item in tags) # # if check_tags is False or len(tags) == 0: # raise Exception(f'ERROR: the Test Suite {{self.suite.name}} has different clauses or no clauses (Tags): {tags}\n' # f'Unable to select the corresponding Reference of this Test Suite') # raise Exception(f'ERROR: the Test Suite {{self.suite.name}} has different clauses or no clauses (Tags): ' # f'{tags}\nUnable to select the corresponding Reference of this Test Suite') # else: # # All the clauses are the same, so we select the first one # reference = f'{{self.references[version]}}{tags[0].replace("_", ".")}' # pics = f'PICS_{tags[0]}' # # return reference, pics aux = [x for x in tags if match(pattern='^(\d+_\d+_\d+)', string=x)] aux = [x for x in tags if match(pattern=r'^(\d+_\d+_\d+)', string=x)] if len(aux) == 0: raise Exception( Loading
doc/analysis/initial_setup.py +10 −4 Original line number Diff line number Diff line Loading @@ -227,12 +227,12 @@ class InitialSetup: if len(deleted_setup) != 0: print(f" WARNING: Some of the Setup functions were deleted:\n{deleted_setup}") else: print(" INFO: All current Setup functions are used in the Robot files") print(f" INFO: All current Setup functions are used in the Robot files") if len(not_included_keys) != 0: print(f" ERROR: Some Setup functions are not include in the Class:\n{not_included_keys}") else: print(" INFO: All the current Setup functions used in Robot files are included in the Class") print(f" INFO: All the current Setup functions used in Robot files are included in the Class") print() Loading Loading @@ -264,13 +264,19 @@ class InitialSetup: def get_initial_condition(self, initial_condition: str) -> str: try: return self.init[initial_condition] if initial_condition is not None: data = self.init[initial_condition] else: data = '''with { the SUT containing an initial state }''' except KeyError: print(f"ERROR: the initial condition '{initial_condition}' is not defined in the dictionary. " f"Please check it and add the new initial condition.") data = '''with { the SUT containing an initial state }''' return data Loading
doc/analysis/parseapiutilsfile.py +8 −9 Original line number Diff line number Diff line Loading @@ -21,10 +21,9 @@ class ParseApiUtilsFile: string = string[index:] string = string.split('\n') index = None for i, item in enumerate(string): if 'response' in item: regex = "\s{4}\$\{response\}=\s{4}(POST|GET|PUT|PATCH|DELETE).*" regex = r"\s{4}\$\{response\}=\s{4}(POST|GET|PUT|PATCH|DELETE).*" match = re.match(pattern=regex, string=item) if match: Loading @@ -35,8 +34,8 @@ class ParseApiUtilsFile: return verb, url, query_param @staticmethod def get_url_request(url: str) -> list: # We have two options, the url is defined in the same line of the response or it is defined in the following def get_url_request(url: str) -> [list, bool]: # 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() parameters = list() Loading @@ -57,7 +56,7 @@ class ParseApiUtilsFile: aux = parameters[0] query_param = True keys = re.split(r'\$|/', aux) keys = re.split(r'[$/]', aux) keys = [k for k in keys if k != ''] if len(parameters) != 0: Loading @@ -68,7 +67,7 @@ class ParseApiUtilsFile: match = re.match(pattern=regex, string=url) if match: aux = match.groups()[0] keys = re.split(r'\$|/', aux) keys = re.split(r'[$/]', aux) keys = [k for k in keys if k != ''] return keys, query_param Loading @@ -81,7 +80,7 @@ class ParseApiUtilsFile: def get_variables_data_variables(self, string): # Get the simple variables from the file regex = "^(\$\{.*\})\s*(.*)\n" regex = r"^(\$\{.*\})\s*(.*)\n" matches = re.finditer(regex, string, re.MULTILINE) for match in matches: Loading @@ -94,7 +93,7 @@ class ParseApiUtilsFile: def get_variables_data_dictionaries(self, string): # Get the dictionary variables from the file regex = '(\&\{.*\})' regex = r'(\&\{.*\})' matches = re.finditer(regex, string, re.MULTILINE) for match in matches: # Check that we have two groups matched Loading @@ -109,7 +108,7 @@ class ParseApiUtilsFile: index = aux.find('\n${') aux = aux[:index + 1] regex = '\.{3}[ ]*([a-zA-Z]+)=(.*)\n' regex = r'\.{3}[ ]*([a-zA-Z]+)=(.*)\n' matches2 = re.finditer(regex, aux, re.MULTILINE) dict_values = dict() for match2 in matches2: Loading
doc/analysis/parserobotfile.py +2 −2 Original line number Diff line number Diff line import re import os from analysis.checks import Checks from analysis.requests import Requests from doc.analysis.checks import Checks from doc.analysis.requests import Requests class ParseRobotFile: Loading