Index: shared/scripts/configuration/config.py =================================================================== diff -u -r0cc92d3b75bfb96dc4ecafd760a9ce15e455033b -rf7bfeef1136eab7daee4c21ec1e6ee97f3412503 --- shared/scripts/configuration/config.py (.../config.py) (revision 0cc92d3b75bfb96dc4ecafd760a9ce15e455033b) +++ shared/scripts/configuration/config.py (.../config.py) (revision f7bfeef1136eab7daee4c21ec1e6ee97f3412503) @@ -32,3 +32,7 @@ BLOOD_PRIMING_TEXT = "Blood Priming" SALINE_UNIT = "mL" BLOOD_PRIMING_DEFAULT_VALUE = "0 mL" + + +ACK_REQ_STATUS = 'Ack Req' +ACK_BAK_STATUS = 'Ack Bak' Index: shared/scripts/configuration/strings.py =================================================================== diff -u -reefd61a5d338590b9ea89ef87d3a2c181e045cf5 -rf7bfeef1136eab7daee4c21ec1e6ee97f3412503 --- shared/scripts/configuration/strings.py (.../strings.py) (revision eefd61a5d338590b9ea89ef87d3a2c181e045cf5) +++ shared/scripts/configuration/strings.py (.../strings.py) (revision f7bfeef1136eab7daee4c21ec1e6ee97f3412503) @@ -1,22 +1,34 @@ + ########################################################################### # # Copyright (c) 2019-2021 Diality Inc. - All Rights Reserved. # # THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN # WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. # -# @file strings.py +# @file utils.py # -# @author (last) LTTS +# @author (last) Joseph varghese # @date (last) 18-Jan-2022 # ############################################################################ + +import os + +AUT_NAME = "denaliSquish" + +COMMON_PATH = os.environ['HOME']+"/Projects" + + +COLOR_CODES = {"Aqua": "#81ffff", "Blue": "#017dea", "Blue 2": "#1090d5", "Green": "#29fd2d", "Grey": "#d3d3d3", + "Lavender": "#db98f5", "Light Blue": "#acd7f1", "Light Teal": "#29f1da","Lime": "#b7fc36", + "Magenta":"#fd28fd", "Orange": "#f2721c", "Peach":"#f1979a", "Red": "#c53b33", "Rose":"#fc178d", + "Slate blue":"#7f7ffa", "Violet": "#6435c9", "White": "#ffffff", "Yellow": "#fcfc4d"} + +#standby mode +GOODMORNING_START_TIME_SEC = 0 +GOODEVENING_START_TIME_SEC = 43200 + BLOOD_PRIMING_TEXT = "Blood Priming" SALINE_UNIT = "mL" -BLOOD_PRIMING_UNIT = "mL" -BLOOD_PRIMING_VALUE_0 = "0" -BLOOD_PRIMING_DEFAULT_VALUE = BLOOD_PRIMING_VALUE_0 + " " + BLOOD_PRIMING_UNIT - -#ui_logs -ACK_REQ_STATUS = 'Ack Req' -ACK_BAK_STATUS = 'Ack Bak' \ No newline at end of file +BLOOD_PRIMING_DEFAULT_VALUE = "0 mL" Index: shared/scripts/configuration/utility.py =================================================================== diff -u -r0cc92d3b75bfb96dc4ecafd760a9ce15e455033b -rf7bfeef1136eab7daee4c21ec1e6ee97f3412503 --- shared/scripts/configuration/utility.py (.../utility.py) (revision 0cc92d3b75bfb96dc4ecafd760a9ce15e455033b) +++ shared/scripts/configuration/utility.py (.../utility.py) (revision f7bfeef1136eab7daee4c21ec1e6ee97f3412503) @@ -12,52 +12,14 @@ # ############################################################################ - -import sys import test import squish -from configuration import config +import csv +from builtins import format +from datetime import datetime from builtins import int as pyInt -def start_application(app_name): - """ - Function to start application and verify application status [running] - If application does not start or running status is false, test stops - Argument: - @param app_name : (str) - Name of the application - @param app_executable : (str) - Actual application - @return: handle for the application if the application is in running state, - or error (exist the application) - """ - counter = 0 - while True: - try: - counter += 1 - test.log("Starting {}".format(app_name)) - squish.startApplication(app_name) - if counter == 1: - test.log("Application launched at the "+str(counter)+" st try.") - elif counter == 2: - test.log("Application launched at the "+str(counter)+" nd try.") - elif counter == 3: - test.log("Application launched at the "+str(counter)+" rd try.") - else: - test.log("Application launched at the "+str(counter)+" th try.") - break - except RuntimeError: - if counter == 1: - test.log("Application failed to launch after "+str(counter)+" try - Please refer logs") - elif counter == 20: - test.log("Exiting after "+str(counter)+ " tries..") - sys.exit(1) - else: - test.log("Application failed to launch after "+str(counter)+ " tries - Please refer logs") - except: - logErrorDetails("Failed to start the application") - sys.exit(1) - - def check_if_object_is_within_the_container(obj=None, container=None): """ check if an object is inside a container @@ -108,3 +70,214 @@ raise LookupError("zone object is not in view to the user after " + \ "trying 100 times") + + +def get_current_date_and_time(date_format='%Y/%b/%d - %H:%M:%S'): + + date = datetime.now() + return str(date.strftime(date_format)) + +def is_float(num): + """ + This function checks the value is adaptable for float conversion. + + @param num - (string) input value for conversion. + @return True/False- (bool) returns True if the value can type casted into float, else False + """ + try: + if '.' in num: + float(num) + return True + except ValueError: + return False + + +def is_intiger(num): + """ + This function checks the value is adaptable for integer conversion. + + @param num - (string) (string) input value for conversion. + @return True/False- (bool) returns True if the value can type casted into int, else False + """ + try: + if num.isdigit(): + return True + except ValueError: + return False + + +def get_extracted_file(): + """ + This function is the handler for getting file from log folder. + + Application log file is automatically created on '/home/denali/Desktop/sd-card/log/ {current_date}_denaliSquish.log' + + @return latest_file - (string) returns latest file that append on log folder from sd-data + """ + try: + current_date = get_current_date_and_time(date_format = "%Y_%m_%d") + latest_file = '/home/denali/Desktop/sd-card/log/'+current_date+'_denaliSquish.log' + return latest_file + except: + return False + +def get_extracted_error_file(): + """ + This function is the handler for getting error file from service folder. + + Application log file is automatically created on '/home/denali/Desktop/sd-card/service/ {current_date}_denaliSquish.err ' + + @return latest_file - (string) returns latest file that append on log folder from service + """ + try: + current_date = get_current_date_and_time(date_format = "%Y_%m_%d") + latest_file = '/home/denali/Desktop/sd-card/service/'+current_date+'_denaliSquish.err' + return latest_file + except: + return False + + +def get_message_from_log(file_name, message_text): + + """ + This method intended to extract the message from application log. + For row[index], index represent column to be extracted. + + @param file_name - (string) path of the latest log file created. + @param message_text - (string) message text to be extracted. + @return message - (list) API arguments displayed in log. + """ + message = [] + count = 0 + try: + with open(file_name, 'r') as csv_file: + try: + for row in reversed(list(csv.reader(csv_file))): + if row[0].isalpha(): + pass + else: + row_length = sum(1 for values in row) + if row_length >= 4: + if row[3]!= None and row[3] == message_text: + if count == 30: + test.fail("handler unable to find message text from log file.") + message_length = sum(1 for values in row) + for column in range(4, message_length, 1): + message.append(row[column]) + count +=1 + for value in range(len(message)): + float_status = is_float(message[value]) + int_status = is_intiger(message[value]) + if float_status is True: + message[value] = float(message[value]) + if int_status is True: + message[value] = int(message[value]) + return message + else: + pass + except: + test.fail("application log data is corrupted") + except: + test.fail("Log file is not created or log file is not created based on standard log naming format.") + + +def get_ack_request_details(file_name, message_text): + """ + This method intended to extract acknowledgement request status, negative requested acknowledgement + and message id from application log. + + For row[index], were index represent column to be extracted. + + @param file_name - (string) path of the latest log file created. + @param message_text - (string) message text to be extracted from log. + @return row[3] - (string) acknowledgement request status. + @return row[4] - (string) Negative requested acknowledgement value (Sq). + @return message_id - (string) formatted message id from log. + """ + try: + message_id = " ID" + with open(file_name, 'r') as csv_file: + try: + for row in reversed(list(csv.reader(csv_file))): + if row[0].isalpha(): + pass + else: + row_length = sum(1 for values in row) + if row_length == 6 and row[3] != message_text: + if row[5].split(':')[0] == message_id: + extracted_message_id = pyInt(row[5].split(':')[1], 16) + formatted_message_id = format(extracted_message_id, '#0x') + # MSG_ID_HD_DEBUG_EVENT (0xFFF1) and MSG_ID_DG_DEBUG_EVENT (0xFFF2) hex values are reversed in log. + string_format_id = str(formatted_message_id) + first_two_char = string_format_id[2:4] + last_two_char = string_format_id[4:6] + if last_two_char != '00' and len(string_format_id) != 5: + return row[3], row[4], ('0x'+last_two_char+first_two_char) + else: + return row[3], row[4], string_format_id.replace("00", "") + else: + pass + except: + test.fail("application log data is corrupted - unable to fetch data") + except: + test.fail("Log file is not created or log file is not created based on standard log naming format.") + + +def get_bak_request_details(file_name, ack_bak_value): + """ + This method intended to extract the acknowledgement back status from application log. + + For row[index], were index represent column to be extracted. + + @param file_name - (string) path of the latest log file created. + @param ack_bak_value - (string) Positive back acknowledgement value (Sq). + @return row[3] - (string) acknowledgement back status. + """ + try: + with open(file_name, 'r') as csv_file: + try: + for row in reversed(list(csv.reader(csv_file))): + if row[0].isalpha(): + pass + else: + row_length = sum(1 for values in row) + if row_length >= 5: + if row[4] == ack_bak_value: + return row[3] + else: + pass + else: + pass + except: + test.fail("application log data is corrupted") + except: + test.fail("Log file is not created or log file is not created based on standard log naming format.") + + + +def get_current_log_details(message_ack = False, message_text = None): + """ + This function is capable to perform data analysis from application log folder. + + logs are automatically created in path :"/home/denali/Desktop/sd-card/log/*.log". + + In row[index], index represent column to be extracted. + @param message_ack - (bool) 'True' - if ack is satisfied in log / 'False' - if ack condition is not satisfied + @param message_text - (string) message text to be extracted from log. + @return content_record - (list) list contains extracted data (ack_req, ack_bak, message, message_id). + """ + content_record = [] + file_name = get_extracted_file() + if message_text != None: + message = get_message_from_log(file_name, message_text) + content_record.append(message) + if message_ack != False: + ack_req_status, ack_req_value, message_id = get_ack_request_details(file_name, message_text) + ack_bak_value = ack_req_value.replace(":-", ":") # getting negative requested ack from positive requested ack + content_record.append(ack_req_status) + content_record.append(message_id.lower()) + if message_ack != False and ack_bak_value != None: + ack_bak_status = get_bak_request_details(file_name, ack_bak_value) + content_record.append(ack_bak_status) + return content_record + Index: suite.conf =================================================================== diff -u -r8df6f936193bbd9127d3ec940562e62db0060bcb -rf7bfeef1136eab7daee4c21ec1e6ee97f3412503 --- suite.conf (.../suite.conf) (revision 8df6f936193bbd9127d3ec940562e62db0060bcb) +++ suite.conf (.../suite.conf) (revision f7bfeef1136eab7daee4c21ec1e6ee97f3412503) @@ -1,6 +1,6 @@ AUT=denaliSquish LANGUAGE=Python OBJECTMAPSTYLE=script -TEST_CASES=tst_environment tst_post tst_standbymode tst_In_treatment +TEST_CASES=tst_environment tst_post tst_standbymode tst_In_treatment "tst_cloud_sync - treatment_screen" VERSION=3 WRAPPERS=Qt Index: tst_cloud_sync - treatment_screen/test.py =================================================================== diff -u --- tst_cloud_sync - treatment_screen/test.py (revision 0) +++ tst_cloud_sync - treatment_screen/test.py (revision f7bfeef1136eab7daee4c21ec1e6ee97f3412503) @@ -0,0 +1,257 @@ +# -*- coding: utf-8 -*- +## +# Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. +# copyright +# THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, +# IN PART OR IN WHOLE, +# WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +# +# file tst_inhandled_message_log +# date 2022/04/09 +# author Amritha debnath +# joseph varghese +# +# +# NOTE: +# This test verifies the cloud sync - treatment screen. + + +import csv +from dialin.ui.hd_simulator import HDSimulator +from dialin.ui import utils +from configuration import utility +from configuration import config +from dialin.utils.conversions import float_to_bytearray, integer_to_bytearray,unsigned_integer_to_bytearray + + +hd_simulator = HDSimulator() + +LOCATION = '/home/denali/Projects/application/resources/settings/Messages/Unhandled.conf' + +DUMMY_FLOAT_VALUE_1 = 1.250 +DUMMY_FLOAT_VALUE_2 = 5.855 +DUMMY_INT_VALUE_1 = 25 +DUMMY_INT_VALUE_2 = 32 +DUMMY_UNSIGNED_INT_VALUE = 5 + +UNHANDLED_MESSAGE = { + 'MESSAGE_1' : "\n[0xBB00]\nHD_custom_data_verification_1\nU32=unsigned_32bit\nU32=argument_2\n", + 'MESSAGE_2' : "\n[0xAA00]\nHD_custom_data_verification_2\nF32=float_argument\nS32=argument_2\n" + } +ERROR_MESSAGE = { + "0x1300" : "Incorrect data length (9 of 32) for received Message with ID '0x1300'", + "0x0900" : "Incorrect data length (9 of 20) for received Message with ID '0x0900'" + } + + + +def verify_log(api_content): + """ + This function is capable to verify the log data from sd-card + + @param api_content - (string) combination of message id, message text and arguments separated with '\n' + @param message_extracted - (list) list contains extracted data (ack_req, ack_bak, message, message_id). + """ + + utils.waitForGUI(5) + test.log(str(api_content)) + message_extracted = utility.get_current_log_details(message_ack = True, message_text = '~'+api_content) + + parameter_index = 0 + #loop to remove default arguments present in API, here it is '?' + while('?' in message_extracted[parameter_index]): + message_extracted[parameter_index].remove('?') + + return message_extracted + + +def convert_message_id_from_unhandled_file_format_to_standared_format(message_id): + """ + This function is capable to remove square bracket and to convert message id into firmware support format. + + @param message_id - (string) message id from unhandled.conf file. + @return expected_meassage_id - (string) message id in the standared format. + """ + formated_meassage_id = message_id.replace('[', "") + formated_meassage_id = formated_meassage_id.replace(']', "") + if formated_meassage_id[-2:] == '00' and len(formated_meassage_id) == 6: + expected_meassage_id = formated_meassage_id.replace("00", "") + return expected_meassage_id + else: + return formated_meassage_id + + +def get_error_message_from_log(): + """ + This function is capable to verify the error logs from sd-card + + @param api_content - (string) combination of message id, message text and arguments separated with '\n' + @param expected_api_argument - (list) expected arguments for API. + """ + utils.waitForGUI(5) + count = 0 + file_name = utility.get_extracted_error_file() + try: + with open(file_name, 'r') as csv_file: + try: + for row in reversed(list(csv.reader(csv_file))): + if row[0].isalpha(): + pass + else: + if count == 30: + test.fail("handler unable to find message text from error file.") + break + row_length = sum(1 for values in row) + try: + if "'" in row[1]: + return row[1] + if "Unhandled Message ID (HD)" in row[1]: + return True + except: + pass + count+=1 + except: + test.fail("application error log data is corrupted") + except: + test.fail("err log file is not created or log file is not created based on standard log naming format.") + + +def append_unhandled_configuration_file(): + """ + This function is capable to write custom API's on unhandled.conf folder. + + unhandled.conf location = '/home/denali/Projects/application/resources/settings/Messages/Unhandled.conf' + + Through this method filereader act as a handler and it will write custom unhandled messages on Unhandled.conf + NB: it is a single time callable method should only use before starting the application. it is mandatory + to use deappend_unhandled_configuration_file() at the end of the testcase. + """ + with open(LOCATION, "a") as filereader: + filereader.write(UNHANDLED_MESSAGE['MESSAGE_1']) + filereader.write(UNHANDLED_MESSAGE['MESSAGE_2']) + utils.waitForGUI(5) + + +def remove_unhandled_configuration_file(): + """ + This function is capable to remove custom API's which is written during method "append_unhandled_configuration_file()". + + unhandled.conf location = '/home/denali/Projects/application/resources/settings/Messages/Unhandled.conf' + + NB: it is a single time callable method should use only after calling "append_unhandled_configuration_file()" method. + """ + count = 0 + for value in UNHANDLED_MESSAGE['MESSAGE_2']: + if value == '\n': + count+=1 + for value in UNHANDLED_MESSAGE['MESSAGE_1']: + if value == '\n': + count+=1 + with open(LOCATION, "r") as filereader: + lines = filereader.readlines() + with open(LOCATION, "w") as filereader: + filereader.writelines(lines[:-count]) + + + +def main(): + + append_unhandled_configuration_file() + + utils.tstStart(__file__) + startApplication(config.AUT_NAME) + + #checking if the message is not in the unhandled (err) + test.startSection("verify the message is not in unhandled (err)") + hd_simulator.cmd_send_hd_general_response(message_id = 275, accepted = 1, reason = 1) + unhandled_status = get_error_message_from_log() + test.verify(unhandled_status == True, "message is not in unhandled.conf file. verified error message from .err file") + + #checking if the message is not in the unhandled (err) + hd_simulator.cmd_send_hd_general_response(message_id = 276, accepted = 1, reason = 1) + unhandled_status = get_error_message_from_log() + test.verify(unhandled_status == True, "message is not in unhandled.conf file. verified error message from .err file") + test.endSection() + + + #checking the id exists and parameters passed is not correct regarding the definition in the conf. (err) + test.startSection("verify the id exists and parameters passed is not correct regarding the definition in the conf. (err)") + #0x1300 + hd_simulator.cmd_send_hd_general_response(message_id = 19, accepted = 1, reason = 1) + error_message = get_error_message_from_log() + test.compare(error_message, ERROR_MESSAGE["0x1300"], "error code should be verified in log file") + + #checking the id exists and parameters passed is not correct regarding the definition in the conf. (err) + #0x0900 + hd_simulator.cmd_send_hd_general_response(message_id = 9, accepted = 0, reason = 0) + error_message = get_error_message_from_log() + test.compare(error_message, ERROR_MESSAGE["0x0900"], "error code should be verified in log file") + test.endSection() + + + #checking the number of parameters are correct but the type is not correct. (err) + test.startSection("verify the number of parameters are correct but the type is not correct. (err)") + #0x0A00 + payload = float_to_bytearray(DUMMY_FLOAT_VALUE_1) #expected negative scenario verification + hd_simulator.cmd_send_hd_general_response(message_id = 10, accepted = 1, reason = 1, is_pure_data = False, has_parameters = True, parameters_payload = payload) + log_data = verify_log("HD_RTC_Epoch_Data") + test.verify(DUMMY_FLOAT_VALUE_1 not in log_data, "parameters type should show deviation in negative scenario.") + + #checking the number of parameters are correct but the type is not correct. (err) + #0x7D00 + payload = integer_to_bytearray(DUMMY_INT_VALUE_1) + payload += float_to_bytearray(DUMMY_FLOAT_VALUE_1) + payload += float_to_bytearray(DUMMY_FLOAT_VALUE_2) + payload += float_to_bytearray(DUMMY_FLOAT_VALUE_1) + payload += float_to_bytearray(DUMMY_INT_VALUE_2) #expected negative scenario verification + hd_simulator.cmd_send_hd_general_response(message_id = 125, accepted = 1, reason = 1, is_pure_data = False, has_parameters = True, parameters_payload = payload) + + log_data = verify_log("HD_Alarm_Information") + test.verify([DUMMY_INT_VALUE_1, DUMMY_FLOAT_VALUE_1, DUMMY_FLOAT_VALUE_2, DUMMY_FLOAT_VALUE_1, DUMMY_INT_VALUE_1] not in log_data, "parameters type should show deviation in negative scenario.") + test.endSection() + + + #checking everything is passed correctly. (log) + test.startSection("verify the log is passed correctly.") + #0xBB00 + messageID_index = 1 + message_index = 2 + payload = integer_to_bytearray(DUMMY_INT_VALUE_1) + payload += integer_to_bytearray(DUMMY_INT_VALUE_2) + hd_simulator.cmd_send_hd_general_response(message_id = 187, accepted = 1, reason = 1, is_pure_data = False, has_parameters = True, parameters_payload = payload) + + + unhandled_message = UNHANDLED_MESSAGE['MESSAGE_1'].split('\n') + #unhandled_message[message_index] is the expected message in unhandled.conf after API call + #unhandled_message[messageID_index] is the expected message id in unhandled.conf after API call + log_data = verify_log(unhandled_message[message_index]) + message_id = convert_message_id_from_unhandled_file_format_to_standared_format(unhandled_message[messageID_index]) + test.verify(message_id.lower() in log_data, "message id should be "+str(unhandled_message[messageID_index])) + test.verify([DUMMY_INT_VALUE_1, DUMMY_INT_VALUE_2] in log_data, "API arguments should be "+str([DUMMY_INT_VALUE_1, DUMMY_INT_VALUE_2])) + test.verify(config.ACK_REQ_STATUS in log_data, "ack request is verified") + test.verify(config.ACK_BAK_STATUS in log_data, "ack back is verified") + + + #checking everything is passed correctly. (log) + #0xAA00 + payload = float_to_bytearray(DUMMY_FLOAT_VALUE_1) + payload += unsigned_integer_to_bytearray(DUMMY_UNSIGNED_INT_VALUE) + hd_simulator.cmd_send_hd_general_response(message_id = 170, accepted = 1, reason = 0, is_pure_data = False, has_parameters = True, parameters_payload = payload) + + unhandled_message =UNHANDLED_MESSAGE['MESSAGE_2'].split('\n') + #unhandled_message[2] is the expected message in unhandled.conf after API call + #unhandled_message[messageID_index] is the expected message id in unhandled.conf after API call + + log_data = verify_log(unhandled_message[message_index]) + message_id = convert_message_id_from_unhandled_file_format_to_standared_format(unhandled_message[messageID_index]) + test.verify(message_id.lower() in log_data, "message id should be "+str(unhandled_message[messageID_index])) + test.verify([DUMMY_FLOAT_VALUE_1, DUMMY_UNSIGNED_INT_VALUE] in log_data, "API arguments should be "+str([DUMMY_FLOAT_VALUE_1, DUMMY_UNSIGNED_INT_VALUE, 0])) + test.verify(config.ACK_REQ_STATUS in log_data, "ack request is verified") + test.verify(config.ACK_BAK_STATUS in log_data, "ack back is verified") + test.endSection() + + remove_unhandled_configuration_file() + + utils.tstDone() + + \ No newline at end of file