From be00389b933556c6b24d2f7cc517912a0ac98f2b Mon Sep 17 00:00:00 2001 From: selurvedu Date: Mon, 24 Oct 2016 19:03:17 +0000 Subject: [PATCH 1/8] Fix an erroneous indentation of `else` blocks --- op_robot_tests/tests_files/service_keywords.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/op_robot_tests/tests_files/service_keywords.py b/op_robot_tests/tests_files/service_keywords.py index 6906aa974..34df7d0ed 100644 --- a/op_robot_tests/tests_files/service_keywords.py +++ b/op_robot_tests/tests_files/service_keywords.py @@ -434,8 +434,8 @@ def get_object_index_by_id(data, object_id): element_id = get_id_from_object(element) if element_id == object_id: break - else: - index += 1 + else: + index += 1 return index @@ -445,8 +445,8 @@ def get_complaint_index_by_complaintID(data, complaintID): for index, element in enumerate(data): if element['complaintID'] == complaintID: break - else: - index += 1 + else: + index += 1 return index From 384f995da5472080caddeb21fd85e5e525f4aff0 Mon Sep 17 00:00:00 2001 From: selurvedu Date: Mon, 24 Oct 2016 19:34:17 +0000 Subject: [PATCH 2/8] Replace robot.output.LOGGER with robot.api.logger --- .../tests_files/service_keywords.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/op_robot_tests/tests_files/service_keywords.py b/op_robot_tests/tests_files/service_keywords.py index 34df7d0ed..17b966633 100644 --- a/op_robot_tests/tests_files/service_keywords.py +++ b/op_robot_tests/tests_files/service_keywords.py @@ -10,10 +10,9 @@ from json import load from jsonpath_rw import parse as parse_path from munch import fromYAML, Munch, munchify +from robot.api import logger from robot.errors import ExecutionFailed from robot.libraries.BuiltIn import BuiltIn -from robot.output import LOGGER -from robot.output.loggerhelper import Message # These imports are not pointless. Robot's resource and testsuite files # can access them by simply importing library "service_keywords". # Please ignore the warning given by Flake8 or other linter. @@ -108,7 +107,8 @@ def compare_date(left, right, accuracy="minute", absolute_delta=True): try: accuracy = float(accuracy) except ValueError: - LOGGER.log_message(Message("Could not convert from {} to float. Accuracy is set to 60 seconds.".format(accuracy), "WARN")) + logger.warn("Could not convert from {} to float. " + "Accuracy is set to 60 seconds.".format(accuracy)) accuracy = 60 if absolute_delta: delta = abs(delta) @@ -180,14 +180,13 @@ def log_object_data(data, file_name=None, format="yaml", update=False, artifact= file_obj.seek(0) file_obj.truncate() except IOError as e: - LOGGER.log_message(Message(e, "INFO")) - LOGGER.log_message(Message("Nothing to update, " - "creating new file.", "INFO")) + logger.info(e) + logger.info("Nothing to update, creating new file.") data_obj = munch_to_object(data, format) with open(file_path, "w") as file_obj: file_obj.write(data_obj) data_obj = munch_to_object(data, format) - LOGGER.log_message(Message(data_obj.decode('utf-8'), "INFO")) + logger.info(data_obj.decode('utf-8')) def munch_from_object(data, format="yaml"): @@ -270,7 +269,7 @@ def prepare_test_tender_data(procedure_intervals, tender_parameters): intervals = procedure_intervals[mode] else: intervals = procedure_intervals['default'] - LOGGER.log_message(Message(intervals)) + logger.info(intervals) tender_parameters['intervals'] = intervals # Set acceleration value for certain modes @@ -361,9 +360,9 @@ def set_to_object(obj, attribute, value): def wait_to_date(date_stamp): date = parse(date_stamp) - LOGGER.log_message(Message("date: {}".format(date.isoformat()), "INFO")) + logger.info("date: {}".format(date.isoformat())) now = get_now() - LOGGER.log_message(Message("now: {}".format(now.isoformat()), "INFO")) + logger.info("now: {}".format(now.isoformat())) wait_seconds = (date - now).total_seconds() wait_seconds += 2 if wait_seconds < 0: From 0a04313afbb9aaa47f2c14e59625978f29e46a4f Mon Sep 17 00:00:00 2001 From: selurvedu Date: Mon, 24 Oct 2016 19:41:29 +0000 Subject: [PATCH 3/8] Make `get_id_from_object` more error-proof --- .../tests_files/service_keywords.py | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/op_robot_tests/tests_files/service_keywords.py b/op_robot_tests/tests_files/service_keywords.py index 17b966633..13499520d 100644 --- a/op_robot_tests/tests_files/service_keywords.py +++ b/op_robot_tests/tests_files/service_keywords.py @@ -410,11 +410,43 @@ def munch_dict(arg=None, data=False): return munchify(arg) +def _get_id_from_object(obj, key): + logger.debug('obj["%s"]: "%s"' % (key, unicode(obj[key]))) + if obj[key] is None: + return None + else: + return re.match(r'(^[filq]-[0-9a-fA-F]{8}): ', obj[key]) + + def get_id_from_object(obj): - obj_id = re.match(r'(^[filq]-[0-9a-fA-F]{8}): ', obj.get('title', '')) - if not obj_id: - obj_id = re.match(r'(^[filq]-[0-9a-fA-F]{8}): ', obj.get('description', '')) - return obj_id.group(1) + if not isinstance(obj, dict): + raise TypeError('Object is not an instance of class "dict"') + + if not ('title' in obj.keys() or 'description' in obj.keys()): + raise KeyError('Unable to get object ID. ' + 'Object does not contain any keys called ' + '"title" or "description"') + + title_id = None + description_id = None + + if 'title' in obj.keys(): + title_id = _get_id_from_object(obj, 'title') + + if 'description' in obj.keys(): + description_id = _get_id_from_object(obj, 'description') + + if not (title_id or description_id): + raise ValueError('Object ID can not be found' + 'in title or description') + + if title_id and description_id and title_id != description_id: + # This is a rare case, yet it may happen + raise ValueError('IDs in title and description are not equal') + + # Returning group 1 instead of group 0 because the only part we need + # is that one in the parentheses + return (title_id or description_id).group(1) def get_id_from_doc_name(name): From 4d26f0818f1b299b7f98095708134e8e7956a418 Mon Sep 17 00:00:00 2001 From: selurvedu Date: Tue, 25 Oct 2016 00:46:25 +0000 Subject: [PATCH 4/8] Add a docstring for `get_id_from_object` --- op_robot_tests/tests_files/service_keywords.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/op_robot_tests/tests_files/service_keywords.py b/op_robot_tests/tests_files/service_keywords.py index 13499520d..c8bcd45e3 100644 --- a/op_robot_tests/tests_files/service_keywords.py +++ b/op_robot_tests/tests_files/service_keywords.py @@ -419,6 +419,16 @@ def _get_id_from_object(obj, key): def get_id_from_object(obj): + """Extract the identifier string from an object. + + :param obj: The dictionary-like object (mapping) with at least one + mandatory key, either "title" or "description". + The value mapped to that key should begin with a prefix which + holds an automatically generated identifier of the object + :type obj: dict + :returns: object ID + :rtype: str + """ if not isinstance(obj, dict): raise TypeError('Object is not an instance of class "dict"') From 44178d870ca2f4ebe73603e6a802b5be9aad8de7 Mon Sep 17 00:00:00 2001 From: selurvedu Date: Tue, 25 Oct 2016 00:46:57 +0000 Subject: [PATCH 5/8] Rewrite `Compare Objects` --- .../tests_files/service_keywords.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/op_robot_tests/tests_files/service_keywords.py b/op_robot_tests/tests_files/service_keywords.py index c8bcd45e3..4e2355bfa 100644 --- a/op_robot_tests/tests_files/service_keywords.py +++ b/op_robot_tests/tests_files/service_keywords.py @@ -64,6 +64,45 @@ def add_minutes_to_date(date, minutes): return (parse(date) + timedelta(minutes=float(minutes))).isoformat() +def compare_objects(first, second, msg=None, values=True, + inequal=False, allow_nonetype=False): + """Test two objects for (in)equality. + + :param first: First object to be compared + :param second: Second object to be compared + :param msg: Custom error message to be printed + :type msg: str or unicode + :param values: If set to True, the values will be printed as well + as the error message + :type values: bool + :param inequal: If set to True, the values should not be equal + :type inequal: bool + :param allow_nonetype: If set to False, the comparison will fail + if at least one of the two objects is None + :type allow_nonetype: bool + """ + logger.info('first: ' + unicode(first)) + logger.info('second: ' + unicode(second)) + if not allow_nonetype: + BuiltIn().should_not_be_equal(first, + None, + msg="First object is None", + values=False) + BuiltIn().should_not_be_equal(second, + None, + msg="Second object is None", + values=False) + if msg is None: + if inequal: + msg="Objects are equal" + else: + msg="Objects are not equal" + if inequal: + BuiltIn().should_not_be_equal(first, second, msg=msg, values=values) + else: + BuiltIn().should_be_equal(first, second, msg=msg, values=values) + + def compare_date(left, right, accuracy="minute", absolute_delta=True): '''Compares dates with specified accuracy From 8e82b4c6892846e16364fc2e59da52bdb11f6977 Mon Sep 17 00:00:00 2001 From: selurvedu Date: Tue, 25 Oct 2016 00:50:05 +0000 Subject: [PATCH 6/8] Remove the old version of `Compare Objects` --- .../tests_files/base_keywords.robot | 8 ++++---- .../brokers/openprocurement_client.robot | 2 +- op_robot_tests/tests_files/cancelation.robot | 4 ++-- op_robot_tests/tests_files/keywords.robot | 19 +++++-------------- .../tests_files/qualification.robot | 2 +- 5 files changed, 13 insertions(+), 22 deletions(-) diff --git a/op_robot_tests/tests_files/base_keywords.robot b/op_robot_tests/tests_files/base_keywords.robot index b1c714d0d..31f380098 100644 --- a/op_robot_tests/tests_files/base_keywords.robot +++ b/op_robot_tests/tests_files/base_keywords.robot @@ -71,7 +71,7 @@ Resource resource.robot Звірити відображення поля ${field} документа ${doc_id} із ${left} для користувача ${username} ${right}= Run As ${username} Отримати інформацію із документа ${TENDER['TENDER_UAID']} ${doc_id} ${field} - Порівняти об'єкти ${left} ${right} + Compare Objects ${left} ${right} Звірити відображення поля ${field} тендера для усіх користувачів @@ -90,7 +90,7 @@ Resource resource.robot Звірити відображення вмісту документа ${doc_id} із ${left} для користувача ${username} ${file_name}= Run as ${username} Отримати документ ${TENDER['TENDER_UAID']} ${doc_id} ${right}= Get File ${OUTPUT_DIR}${/}${file_name} - Порівняти об'єкти ${left} ${right} + Compare Objects ${left} ${right} Звірити відображення дати ${date} тендера для усіх користувачів @@ -536,13 +536,13 @@ Resource resource.robot Звірити відображення поля ${field} документа ${doc_id} до скарги ${complaintID} з ${left} для користувача ${username} ${right}= Run As ${username} Отримати інформацію із документа до скарги ${TENDER['TENDER_UAID']} ${complaintID} ${doc_id} ${field} - Порівняти об'єкти ${left} ${right} + Compare Objects ${left} ${right} Звірити відображення вмісту документа ${doc_id} до скарги ${complaintID} з ${left} для користувача ${username} ${file_name}= Run as ${username} Отримати документ до скарги ${TENDER['TENDER_UAID']} ${complaintID} ${doc_id} ${right}= Get File ${OUTPUT_DIR}${/}${file_name} - Порівняти об'єкти ${left} ${right} + Compare Objects ${left} ${right} ############################################################################################## # BIDDING diff --git a/op_robot_tests/tests_files/brokers/openprocurement_client.robot b/op_robot_tests/tests_files/brokers/openprocurement_client.robot index 6f5f10a93..963b68586 100644 --- a/op_robot_tests/tests_files/brokers/openprocurement_client.robot +++ b/op_robot_tests/tests_files/brokers/openprocurement_client.robot @@ -191,7 +191,7 @@ Library openprocurement_client_helper.py ... Remove From Dictionary ${tender.data} enquiryPeriod ${tender}= set_access_key ${tender} ${USERS.users['${username}'].access_token} ${tender}= Call Method ${USERS.users['${username}'].client} patch_tender ${tender} - Порівняти об'єкти ${prev_value} ${USERS.users['${username}'].tender_data['${fieldname}']} + Compare Objects ${prev_value} ${USERS.users['${username}'].tender_data['${fieldname}']} Set_To_Object ${USERS.users['${username}'].tender_data} ${fieldname} ${fieldvalue} ############################################################################## diff --git a/op_robot_tests/tests_files/cancelation.robot b/op_robot_tests/tests_files/cancelation.robot index 389fc1557..4727aa56a 100644 --- a/op_robot_tests/tests_files/cancelation.robot +++ b/op_robot_tests/tests_files/cancelation.robot @@ -167,10 +167,10 @@ Suite Teardown Test Suite Teardown Звірити відображення поля ${field} документа до скасування ${doc_id} із ${left} для користувача ${username} ${right}= Run As ${username} Отримати інформацію із документа ${TENDER['TENDER_UAID']} ${doc_id} ${field} - Порівняти об'єкти ${left} ${right} + Compare Objects ${left} ${right} Звірити відображення вмісту документа до скасування ${doc_id} з ${left} для користувача ${username} ${file_name}= Run as ${username} Отримати документ до скасування ${TENDER['TENDER_UAID']} ${doc_id} ${right}= Get File ${OUTPUT_DIR}${/}${file_name} - Порівняти об'єкти ${left} ${right} + Compare Objects ${left} ${right} diff --git a/op_robot_tests/tests_files/keywords.robot b/op_robot_tests/tests_files/keywords.robot index 37823812c..9de0e0cdc 100644 --- a/op_robot_tests/tests_files/keywords.robot +++ b/op_robot_tests/tests_files/keywords.robot @@ -394,7 +394,7 @@ Log differences between dicts Звірити поле тендера із значенням [Arguments] ${username} ${tender_uaid} ${left} ${field} ${object_id}=${Empty} ${right}= Отримати дані із тендера ${username} ${tender_uaid} ${field} ${object_id} - Порівняти об'єкти ${left} ${right} + Compare Objects ${left} ${right} Звірити значення поля серед усіх документів ставки @@ -405,16 +405,7 @@ Log differences between dicts :FOR ${document_index} IN RANGE ${number_of_documents} \ ${field_value}= Отримати дані із документу пропозиції ${username} ${tender_uaid} ${bid_index} ${document_index} ${field} \ ${match_in_document}= Set Variable If '${field_value}'=='${value}' True - Порівняти об'єкти ${match_in_document} True - - -Порівняти об'єкти - [Arguments] ${left} ${right} - Log ${left} - Log ${right} - Should Not Be Equal ${left} ${None} - Should Not Be Equal ${right} ${None} - Should Be Equal ${left} ${right} msg=Objects are not equal + Compare Objects ${match_in_document} True Перевірити неможливість зміни поля ${field} тендера на значення ${new_value} для користувача ${username} @@ -556,7 +547,7 @@ Log differences between dicts Звірити поле скарги із значенням [Arguments] ${username} ${tender_uaid} ${given_value} ${field_name} ${complaintID} ${award_index}=${None} ${received_value}= Run as ${username} Отримати інформацію із скарги ${tender_uaid} ${complaintID} ${field_name} ${award_index} - Порівняти об'єкти ${given_value} ${received_value} + Compare Objects ${given_value} ${received_value} Можливість скасувати тендер @@ -643,13 +634,13 @@ Require Failure Звірити статус тендера [Arguments] ${username} ${tender_uaid} ${left} ${right}= Run as ${username} Отримати інформацію із тендера ${tender_uaid} status - Порівняти об'єкти ${left} ${right} + Compare Objects ${left} ${right} Звірити статус вимоги/скарги [Arguments] ${username} ${tender_uaid} ${complaintID} ${left} ${award_index}=${None} ${right}= Run as ${username} Отримати інформацію із скарги ${tender_uaid} ${complaintID} status ${award_index} - Порівняти об'єкти ${left} ${right} + Compare Objects ${left} ${right} Дочекатись дати початку прийому пропозицій diff --git a/op_robot_tests/tests_files/qualification.robot b/op_robot_tests/tests_files/qualification.robot index 4f9c18826..f605068a7 100644 --- a/op_robot_tests/tests_files/qualification.robot +++ b/op_robot_tests/tests_files/qualification.robot @@ -80,7 +80,7 @@ ${award_index} ${0} ... ${USERS.users['${provider}'].claim_data.doc_id} ... title ... ${award_index} - Порівняти об'єкти ${USERS.users['${provider}'].claim_data.doc_name} ${right} + Compare Objects ${USERS.users['${provider}'].claim_data.doc_name} ${right} Відображення вмісту документа до вимоги про виправлення визначення переможця From 654276a5ba051eb7ddb2ea0d6e0b1caa7b95633b Mon Sep 17 00:00:00 2001 From: selurvedu Date: Tue, 25 Oct 2016 01:25:32 +0000 Subject: [PATCH 7/8] Add stricter requirements for expected failure --- .../tests_files/brokers/openprocurement_client.robot | 10 +++++++++- op_robot_tests/tests_files/keywords.robot | 5 ++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/op_robot_tests/tests_files/brokers/openprocurement_client.robot b/op_robot_tests/tests_files/brokers/openprocurement_client.robot index 963b68586..c8f2e293a 100644 --- a/op_robot_tests/tests_files/brokers/openprocurement_client.robot +++ b/op_robot_tests/tests_files/brokers/openprocurement_client.robot @@ -191,7 +191,15 @@ Library openprocurement_client_helper.py ... Remove From Dictionary ${tender.data} enquiryPeriod ${tender}= set_access_key ${tender} ${USERS.users['${username}'].access_token} ${tender}= Call Method ${USERS.users['${username}'].client} patch_tender ${tender} - Compare Objects ${prev_value} ${USERS.users['${username}'].tender_data['${fieldname}']} + # The two values should differ. If they are equal, then probably the server refused to, + # or failed to modify the value of a field, so this keyword should instantly fail. + ${new_value}= Get From Object ${USERS.users['${username}'].tender_data.data} ${fieldname} + Compare Objects + ... ${prev_value} + ... ${new_value} + ... msg=Failed to modify "${fieldname}" + ... values=${False} + ... inequal=${True} Set_To_Object ${USERS.users['${username}'].tender_data} ${fieldname} ${fieldvalue} ############################################################################## diff --git a/op_robot_tests/tests_files/keywords.robot b/op_robot_tests/tests_files/keywords.robot index 9de0e0cdc..12b536016 100644 --- a/op_robot_tests/tests_files/keywords.robot +++ b/op_robot_tests/tests_files/keywords.robot @@ -409,7 +409,10 @@ Log differences between dicts Перевірити неможливість зміни поля ${field} тендера на значення ${new_value} для користувача ${username} - Require Failure ${username} Внести зміни в тендер ${TENDER['TENDER_UAID']} ${field} ${new_value} + Run Keyword And Expect Error + ... Failed to modify "${field}" + ... Run As ${username} + ... Внести зміни в тендер ${TENDER['TENDER_UAID']} ${field} ${new_value} Звірити дату тендера From 20fab8c08ef25f650664a67abd2c0e5cec223f06 Mon Sep 17 00:00:00 2001 From: selurvedu Date: Tue, 25 Oct 2016 02:14:07 +0000 Subject: [PATCH 8/8] Store artifact in `${OUTPUT_DIR}` This allows running test suites in parallel without overwriting the artifact file. All you need is the `-d` (`--outputdir`) argument. --- op_robot_tests/tests_files/keywords.robot | 8 ++++---- op_robot_tests/tests_files/service_keywords.py | 15 +++++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/op_robot_tests/tests_files/keywords.robot b/op_robot_tests/tests_files/keywords.robot index 12b536016..563a5b464 100644 --- a/op_robot_tests/tests_files/keywords.robot +++ b/op_robot_tests/tests_files/keywords.robot @@ -175,12 +175,12 @@ Get Broker Property By Username Run Keyword And Ignore Error Set To Dictionary ${artifact} provider_bid_id=${USERS.users['${provider}'].bid_id} Run Keyword And Ignore Error Set To Dictionary ${artifact} provider1_bid_id=${USERS.users['${provider1}'].bid_id} Log ${artifact} - log_object_data ${artifact} file_name=artifact update=${True} artifact=${True} + log_object_data ${artifact} file_name=artifact update=${True} Завантажити дані про тендер - ${file_path}= Get Variable Value ${ARTIFACT_FILE} artifact.yaml - ${ARTIFACT}= load_data_from ${file_path} + ${file_path}= Get Variable Value ${ARTIFACT_FILE} artifact + ${ARTIFACT}= load_artifact ${file_path} Run Keyword And Ignore Error Set To Dictionary ${USERS.users['${tender_owner}']} access_token=${ARTIFACT.access_token} ${TENDER}= Create Dictionary TENDER_UAID=${ARTIFACT.tender_uaid} LAST_MODIFICATION_DATE=${ARTIFACT.last_modification_date} LOT_ID=${Empty} ${MODE}= Get Variable Value ${MODE} ${ARTIFACT.mode} @@ -191,7 +191,7 @@ Get Broker Property By Username Run Keyword And Ignore Error Set To Dictionary ${USERS.users['${provider}']} bid_id=${ARTIFACT.provider_bid_id} Run Keyword And Ignore Error Set To Dictionary ${USERS.users['${provider1}']} bid_id=${ARTIFACT.provider1_bid_id} Set Suite Variable ${TENDER} - log_object_data ${ARTIFACT} file_name=artifact update=${True} artifact=${True} + log_object_data ${ARTIFACT} file_name=artifact update=${True} Підготувати дані для створення тендера diff --git a/op_robot_tests/tests_files/service_keywords.py b/op_robot_tests/tests_files/service_keywords.py index 4e2355bfa..600e2fc8d 100644 --- a/op_robot_tests/tests_files/service_keywords.py +++ b/op_robot_tests/tests_files/service_keywords.py @@ -184,7 +184,7 @@ def compare_coordinates(left_lat, left_lon, right_lat, right_lon, accuracy=0.1): return True -def log_object_data(data, file_name=None, format="yaml", update=False, artifact=False): +def log_object_data(data, file_name=None, format="yaml", update=False): """Log object data in pretty format (JSON or YAML) Two output formats are supported: "yaml" and "json". @@ -205,11 +205,8 @@ def log_object_data(data, file_name=None, format="yaml", update=False, artifact= if not isinstance(data, Munch): data = munchify(data) if file_name: - if artifact: - file_path = os.path.join(os.path.dirname(__file__), 'data', file_name + '.' + format) - else: - output_dir = BuiltIn().get_variable_value("${OUTPUT_DIR}") - file_path = os.path.join(output_dir, file_name + '.' + format) + output_dir = BuiltIn().get_variable_value("${OUTPUT_DIR}") + file_path = os.path.join(output_dir, file_name + '.' + format) if update: try: with open(file_path, "r+") as file_obj: @@ -260,6 +257,12 @@ def load_data_from(file_name, mode=None): return file_data +def load_artifact(file_name, format="yaml"): + output_dir = BuiltIn().get_variable_value("${OUTPUT_DIR}") + file_path = os.path.join(output_dir, file_name + '.' + format) + return load_data_from(file_path) + + def compute_intrs(brokers_data, used_brokers): """Compute optimal values for period intervals.