def test_operator_define_operator_error_2(self, mock_error): op = Operator() op.no_failed = 0 op.define_operator(self.hostname, 12, 'mock_xpath', ['ele1'], 'mock_err', 'mock_info', 'mock command', True, ['mock_id'], 'test_name') self.assertEqual(op.no_failed, 1) #attribute error mock_error.assert_called()
def test_operator_not_equal_1(self, mock_error): with self.assertRaises(Exception): op = Operator() op.not_equal('mock_path', [], 'mock_err', 'mock_info', 'mock_command', True, ['mock_id'], 'test_name', 'mock_xml1', 'mock_xml2') mock_error.assert_called()
def test_operator_no_diff_2(self, mock_error, mock_xpath, mock_print): mock_xpath.return_value = None , ['mock_post'] op = Operator() op.no_diff('mock_path', ['mock_node'], 'mock_err', 'mock_info', 'mock_command', True, ['mock_id'], 'test_name', 'mock_xml1', 'mock_xml2') mock_error.assert_called() mock_print.assert_called()
def test_operator_all_same_1(self, mock_error): with self.assertRaises(IndexError): op = Operator() op.all_same('mock_path', [], 'mock_err', 'mock_info', 'mock_command', True, ['mock_id'], 'test_name', 'mock_xml1', 'mock_xml2') mock_error.assert_called()
def test_operator_define_operator_error_2(self, mock_error): op = Operator() op.no_failed = 0 op.define_operator(self.hostname, 12, 'mock_xpath', ['ele1'], 'mock_err', 'mock_info', 'mock command', True, ['mock_id'], 'test_name') self.assertEqual(op.no_failed, 1) #attribute error mock_error.assert_called()
def test_operator_no_diff_2(self, mock_error, mock_xpath, mock_print): mock_xpath.return_value = None , ['mock_post'] op = Operator() op.no_diff('mock_path', ['mock_node'], 'mock_err', 'mock_info', 'mock_command', True, ['mock_id'], 'test_name', 'mock_xml1', 'mock_xml2') mock_error.assert_called() mock_print.assert_called()
def test_operator_define_operator_error_3(self, mock_error, mock_all_same): mock_all_same.side_effect = etree.XPathEvalError('Xpath Mock Error') op = Operator() op.no_failed = 0 op.define_operator(self.hostname, 'all-same', 'mock_xpath', ['ele1'], 'mock_err', 'mock_info', 'mock command', True, ['mock_id'], 'test_name') self.assertEqual(op.no_failed, 1) #xpathError mock_error.assert_called_with('\x1b[31mError in evaluating XPATH, \nComplete Message: Xpath Mock Error', extra='1.1.1.1')
def test_operator_define_operator_error_3(self, mock_error, mock_all_same): mock_all_same.side_effect = etree.XPathEvalError('Xpath Mock Error') op = Operator() op.no_failed = 0 op.define_operator(self.hostname, 'all-same', 'mock_xpath', ['ele1'], 'mock_err', 'mock_info', 'mock command', True, ['mock_id'], 'test_name') self.assertEqual(op.no_failed, 1) #xpathError mock_error.assert_called_with('\x1b[31mError in evaluating XPATH, \nComplete Message: Xpath Mock Error', extra='1.1.1.1')
def test_operator_list_not_less_1(self, mock_xpath, mock_data, mock_print, mock_getnode, mock_printMessage): mock_xpath.return_value = ['mock_pre'], ['mock_post'] mock_data.return_value = {(('mock_node_value',),):'mock_Element'} mock_getnode.return_value = {}, {} op = Operator() op.list_not_less('mock_path', ['no node'], 'mock_err', 'mock_info', 'mock_command', True, ['mock_id'], 'test_name', 'mock_xml1', 'mock_xml2') mock_printMessage.assert_called() mock_print.assert_called()
def test_operator_list_not_less_1(self, mock_xpath, mock_data, mock_print, mock_getnode, mock_printMessage): mock_xpath.return_value = ['mock_pre'], ['mock_post'] mock_data.return_value = {(('mock_node_value',),):'mock_Element'} mock_getnode.return_value = {}, {} op = Operator() op.list_not_less('mock_path', ['no node'], 'mock_err', 'mock_info', 'mock_command', True, ['mock_id'], 'test_name', 'mock_xml1', 'mock_xml2') mock_printMessage.assert_called() mock_print.assert_called()
def test_operator_define_operator_error_1(self, mock_error): op = Operator() op.no_failed = 0 op.define_operator(self.hostname, 'all-same', 'mock_xpath', ['ele1'], 'mock_err', 'mock_info', 'mock command', True, ['mock_id'], 'test_name') self.assertEqual(op.no_failed, 1) mock_error.assert_called( ) #error called because the all_same requires 2 more args
def test_notify_not_login(self, mock_fqdn, mock_connect, mock_ehlo, mock_starttls, mock_login, mock_log, mock_error): res = Operator() mock_fqdn.return_value = '1.1.1.1' mock_connect.return_value = (220, "ok") mock_login.side_effect = Exception('could not login') res.result = 'Passed' mfile = os.path.join(os.path.dirname(__file__), 'configs', 'mail.yml') mail_file = open(mfile, 'r') mail_file = yaml.load(mail_file) #smtplib.SMTP#connectsocket.getfqdn, Loader=yaml.FullLoader passwd = mail_file['passwd'] notf = Notification() notf.notify(mail_file, self.hostname, passwd, res) mock_log.assert_called() mock_error.assert_called_with('\x1b[31mERROR occurred: could not login', extra={'hostname': '10.209.12.121', 'hostame': None})
def test_check_4(self, mock_info, mock_error): comp = Comparator() self.db['check_from_sqlite'] = False oper = Operator() flag = comp.compare_xml(oper, self.db, 'mock_rpc_or_command', 'pre', 'pre') mock_info.assert_called() self.assertTrue(flag)
def test_notify_send_mail(self, mock_fqdn, mock_connect, mock_ehlo, mock_starttls, mock_login, mock_quit, mock_log, mock_error, mock_send): res = Operator() mock_send.side_effect = Exception('not able to send mail') mock_fqdn.return_value = '1.1.1.1' mock_connect.return_value = (220, "ok") res.result = 'Passed' mfile = os.path.join(os.path.dirname(__file__), 'configs', 'mail.yml') mail_file = open(mfile, 'r') mail_file = yaml.load(mail_file) #smtplib.SMTP#connectsocket.getfqdn passwd = mail_file['passwd'] notf = Notification() notf.notify(mail_file, self.hostname, passwd, res) mock_log.assert_called() mock_error.assert_called_with( '\x1b[31mERROR!! in sending mail: not able to send mail', extra={ 'hostname': '10.209.12.121', 'hostame': None }) mock_quit.assert_called()
def generate_test_files(self, main_file, device, check, diff, db, snap_del, pre=None, action=None, post=None): """ generate names of snap files from hostname and out files given by user, tests are performed on values stored in these snap files, in which test is to be performed :param main_file: main config file, to extract test files user wants to run :param device: device name :param check: variable to check if --check option is given or not :param diff: variable to check if --diff option is given or not :param db: database object :param snap_del: if --snapcheck operator is used without any test file name it will create temprory file and then will delete it at the end :param pre: file name of pre snapshot :param post: file name of post snapshot :param action: given by module version, either snap, snapcheck or check :return: object of operator.Operator containing test details """ op = Operator() op.device = device tests_files = [] self.log_detail['hostname'] = device # pre_user and post_user are the names of the snapshot files # that the user wants to keep and store the snapfiles # with these names pre_user = pre post_user = post # get the test files from config.yml if main_file.get('tests') is None: self.logger_check.error( colorama.Fore.RED + "\nERROR!! No test file found, Please mention test files !!", extra=self.log_detail) else: # extract test files, first search in path given in jsnapy.cfg for tfile in main_file.get('tests'): if not os.path.isfile(tfile): tfile = os.path.join( expanduser(get_path('DEFAULT', 'test_file_path')), tfile) if os.path.isfile(tfile): test_file = open(tfile, 'r') tests_files.append( yaml.load(test_file, Loader=yaml.FullLoader)) else: self.logger_check.error( colorama.Fore.RED + "ERROR!! File %s not found for testing" % tfile, extra=self.log_detail) # check what all test cases need to be included, if nothing given # then include all test cases #### for tests in tests_files: tests_included = [] if 'tests_include' in tests: tests_included = tests.get('tests_include') else: for t in tests: tests_included.append(t) message = self._print_testmssg("Device: " + device, "*") self.logger_check.info(colorama.Fore.BLUE + message, extra=self.log_detail) for val in tests_included: self.logger_check.info("Tests Included: %s " % (val), extra=self.log_detail) # This is Where we are going to print the description mentioned by the user for the testcase # Enumerate generate a tuple of index and corresponding element in the list # index[0] is index and index[1] is the dictionary in which it will search. description_index = [ index[0] for index in enumerate(tests[val]) if 'description' in index[1] ] if len(description_index) > 0: description_index = description_index[0] description = tests[val][description_index][ 'description'] if description is not None: self.logger_check.info("Description: %s " % (description), extra=self.log_detail) try: if any('command' in d for d in tests[val]): index = next((i for i, x in enumerate(tests[val]) if 'command' in x), 0) command = tests[val][index].get('command').split( '|')[0].strip() reply_format = tests[val][0].get('format', 'xml') message = self._print_testmssg( "Command: " + command, "*") self.logger_check.info(colorama.Fore.BLUE + message, extra=self.log_detail) name = '_'.join(command.split()) teston = command # this is necessary for the pre and post to be the same that user specified # In a case when there are multiple rpc's with kwargs and a rpc with no kwargs pre = pre_user post = post_user else: index = next((i for i, x in enumerate(tests[val]) if 'rpc' in x), 0) index_kwargs = next( (i for i, x in enumerate(tests[val]) if 'kwargs' in x or 'args' in x), 1) rpc = tests[val][index]['rpc'] reply_format = tests[val][index].get( 'format', 'xml') self.logger_check.info(colorama.Fore.BLUE + (25) * "*" + "RPC is " + rpc + (25) * '*', extra=self.log_detail) name = rpc teston = rpc # this is necessary for the pre and post to be the same that user specified # In a case when there are multiple rpc's with kwargs and a rpc with no kwargs pre = pre_user post = post_user # here the user specified name is being used and the hash value generated for # kwargs part is appended to the name if 'kwargs' in tests[val][index_kwargs] and tests[ val][index_kwargs].get('kwargs') is None: del tests[val][index_kwargs]['kwargs'] if 'args' in tests[val][index_kwargs] and tests[ val][index_kwargs].get('args') is None: del tests[val][index_kwargs]['args'] if 'kwargs' in tests[val][ index_kwargs] or 'args' in tests[val][ index_kwargs]: if tests[val][index_kwargs].get('kwargs'): data = tests[val][index_kwargs].get( 'kwargs') elif tests[val][index_kwargs].get('args'): data = tests[val][index_kwargs].get('args') hash_kwargs = hashlib.md5( json.dumps(data, sort_keys=True).encode( 'utf-8')).digest() hash_kwargs = base64.urlsafe_b64encode( hash_kwargs).strip() if action == 'check' and pre_user is not None and post_user is not None: pre = pre_user + '_' + hash_kwargs.decode( 'utf-8') post = post_user + '_' + hash_kwargs.decode( 'utf-8') elif action == 'snapcheck' and pre_user is not None and post_user is None: pre = pre_user + '_' + hash_kwargs.decode( 'utf-8') elif diff is True and pre_user is not None and post_user is not None: pre = pre_user + '_' + hash_kwargs.decode( 'utf-8') post = post_user + '_' + hash_kwargs.decode( 'utf-8') except KeyError: self.logger_check.error( colorama.Fore.RED + "ERROR occurred, test keys 'command' or 'rpc' not defined properly", extra=self.log_detail) except Exception as ex: self.logger_check.error(colorama.Fore.RED + "ERROR Occurred: %s" % str(ex), extra=self.log_detail) else: # extract snap files, if check from sqlite is true t if db.get('check_from_sqlite') is True and ( check is True or diff is True or action in ["check", "diff"]): a = SqliteExtractXml(db.get('db_name')) # while checking from database, preference is given # to id and then snap name if (db['first_snap_id'] is not None) and (db['second_snap_id'] is not None): snapfile1, data_format1 = a.get_xml_using_snap_id( str(device), name, db['first_snap_id']) snapfile2, data_format2 = a.get_xml_using_snap_id( str(device), name, db['second_snap_id']) else: snapfile1, data_format1 = a.get_xml_using_snapname( str(device), name, pre) snapfile2, data_format2 = a.get_xml_using_snapname( str(device), name, post) if reply_format != data_format1 or reply_format != data_format2: self.logger_check.error( colorama.Fore.RED + "ERROR!! Data stored in database is not in %s format." % reply_format, extra=self.log_detail) pass # sys.exit(1) ###### taking snapshot for --snapcheck operation #### elif db.get('check_from_sqlite') is True: a = SqliteExtractXml(db.get('db_name')) snapfile1, data_format1 = a.get_xml_using_snapname( str(device), name, pre) if reply_format != data_format1: self.logger_check.error( colorama.Fore.RED + "ERROR!! Data stored in database is not in %s format." % reply_format, extra=self.log_detail) pass # sys.exit(1) else: snapfile1 = self.generate_snap_file( device, pre, name, reply_format) # if check is true then call function to compare two # snapshots #### if (check is True or action == "check") and reply_format == 'xml': if db.get('check_from_sqlite') is False: snapfile2 = self.generate_snap_file( device, post, name, reply_format) self.compare_reply(op, tests[val], val, teston, check, db, snapfile1, snapfile2, action) # if --diff is true then call compare_diff to compare # two snapshots word by word #### elif (diff is True): if db.get('check_from_sqlite') is False: snapfile2 = self.generate_snap_file( device, post, name, reply_format) self.compare_diff(snapfile1, snapfile2, db.get('check_from_sqlite')) # else call --snapcheck test operation, it works only # for xml reply format #### elif (reply_format == 'xml'): self.compare_reply(op, tests[val], val, teston, check, db, snapfile1, action) ######## bug here ############ # multiple testcases for single command and same device, its deleting that file #################### """ if snap_del is True: snapfile1 = snapfile1 if os.path.isfile(snapfile1) else self.generate_snap_file(device, pre, name, reply_format) os.remove(snapfile1) """ else: # give error message if snapshot in text format is # used with operations other than --diff #### self.logger_check.error( colorama.Fore.RED + "ERROR!! for checking snapshots in text format use '--diff' option ", extra=self.log_detail) # print final result, if operation is --diff then message gets # printed compare_diff function only #### if (diff is not True): op.final_result(self.log_detail) return op
def get_test(self, config_data, hostname, snap_file, post_snap, action): """ Analyse testfile and return object of operator.Operator containing test details called by connect() function and other functions of Jsnapy module functions :param config_data: data of main config file :param hostname: hostname :param snap_file: pre snapshot file name :param post_snap: post snapshot file name :param action: action to be taken (check, snapcheck, snap) :return: object of testop.Operator containing test details """ res = Operator() res = self.compare_tests(hostname, config_data, snap_file, post_snap, action) result_status = res.result mail_condition = 'all' if result_status == 'Passed': mail_condition = 'pass' elif result_status == 'Failed': mail_condition = 'fail' mail_pref = config_data.get("mail") #we don't want to send mail when diff operation is run if mail_pref is not None and self.args.diff is False: mail_file_path = None if type(mail_pref) is str: mail_file_path = mail_pref elif type(mail_pref) is dict: if mail_condition in mail_pref: mail_file_path = mail_pref.get(mail_condition) else: self.logger.error( colorama.Fore.RED + "ERROR!! Type of mail preferences should be either dictionary or string", extra=self.log_detail) if mail_file_path is not None and mail_file_path != '': mfile = os.path.join(expanduser(get_path('DEFAULT', 'test_file_path')), mail_file_path)\ if os.path.isfile(mail_file_path) is False else mail_file_path if os.path.isfile(mfile): mail_file = open(mfile, 'r') mail_file = yaml.load(mail_file) if "passwd" not in mail_file: passwd = getpass.getpass( "Please enter ur email password ") else: passwd = mail_file['passwd'] send_mail = Notification() send_mail.notify(mail_file, hostname, passwd, res) else: self.logger.error( colorama.Fore.RED + "ERROR!! Path of file containing mail content is not correct", extra=self.log_detail) # else: # res = self.compare_tests( # hostname, # config_data, # snap_file, # post_snap, # action) self.q.put(res) return res
def test_operator_in_range_1(self, mock_error): with self.assertRaises(Exception): op = Operator() op.in_range('mock_path', [], 'mock_err', 'mock_info', 'mock_command', True, ['mock_id'], 'test_name', 'mock_xml1', 'mock_xml2') mock_error.assert_called()
def test_operator_all_same_1(self, mock_error): with self.assertRaises(IndexError): op = Operator() op.all_same('mock_path', [], 'mock_err', 'mock_info', 'mock_command', True, ['mock_id'],'test_name', 'mock_xml1', 'mock_xml2') mock_error.assert_called()
def test_operator_define_operator_error_1(self,mock_error): op = Operator() op.no_failed = 0 op.define_operator(self.hostname,'all-same','mock_xpath',['ele1'],'mock_err','mock_info','mock command',True,['mock_id'], 'test_name') self.assertEqual(op.no_failed,1) mock_error.assert_called() #error called because the all_same requires 2 more args
def generate_test_files(self, main_file, device, check, diff, db, snap_del, pre=None, action=None, post=None): """ generate names of snap files from hostname and out files given by user, tests are performed on values stored in these snap files, in which test is to be performed :param main_file: main config file, to extract test files user wants to run :param device: device name :param check: variable to check if --check option is given or not :param diff: variable to check if --diff option is given or not :param db: database object :param snap_del: if --snapcheck operator is used without any test file name it will create temprory file and then will delete it at the end :param pre: file name of pre snapshot :param post: file name of post snapshot :param action: given by module version, either snap, snapcheck or check :return: object of operator.Operator containing test details """ op = Operator() op.device = device tests_files = [] self.log_detail['hostname'] = device # get the test files from config.yml if main_file.get('tests') is None: self.logger_check.error( colorama.Fore.RED + "\nERROR!! No test file found, Please mention test files !!", extra=self.log_detail) else: # extract test files, first search in path given in jsnapy.cfg for tfile in main_file.get('tests'): if not os.path.isfile(tfile): tfile = os.path.join(get_path('DEFAULT', 'test_file_path'), tfile) if os.path.isfile(tfile): test_file = open(tfile, 'r') tests_files.append(yaml.load(test_file)) else: self.logger_check.error( colorama.Fore.RED + "ERROR!! File %s not found for testing" % tfile, extra=self.log_detail) # check what all test cases need to be included, if nothing given # then include all test cases #### for tests in tests_files: tests_included = [] if 'tests_include' in tests: tests_included = tests.get('tests_include') else: for t in tests: tests_included.append(t) message = self._print_testmssg("Device: " + device, "*") self.logger_check.info(colorama.Fore.BLUE + message, extra=self.log_detail) for val in tests_included: self.logger_check.info("Tests Included: %s " % (val), extra=self.log_detail) try: if 'command' in list(tests[val][0].keys()): command = tests[val][0].get('command').split( '|')[0].strip() reply_format = tests[val][0].get('format', 'xml') message = self._print_testmssg( "Command: " + command, "*") self.logger_check.info(colorama.Fore.BLUE + message, extra=self.log_detail) name = '_'.join(command.split()) teston = command else: rpc = tests[val][0]['rpc'] reply_format = tests[val][0].get('format', 'xml') self.logger_check.info(colorama.Fore.BLUE + (25) * "*" + "RPC is " + rpc + (25) * '*', extra=self.log_detail) name = rpc teston = rpc except KeyError: self.logger_check.error( colorama.Fore.RED + "ERROR occurred, test keys 'command' or 'rpc' not defined properly", extra=self.log_detail) except Exception as ex: self.logger_check.error(colorama.Fore.RED + "ERROR Occurred: %s" % str(ex), extra=self.log_detail) else: # extract snap files, if check from sqlite is true t if db.get('check_from_sqlite') is True and ( check is True or diff is True or action in ["check", "diff"]): a = SqliteExtractXml(db.get('db_name')) # while checking from database, preference is given # to id and then snap name if (db['first_snap_id'] is not None) and (db['second_snap_id'] is not None): snapfile1, data_format1 = a.get_xml_using_snap_id( str(device), name, db['first_snap_id']) snapfile2, data_format2 = a.get_xml_using_snap_id( str(device), name, db['second_snap_id']) else: snapfile1, data_format1 = a.get_xml_using_snapname( str(device), name, pre) snapfile2, data_format2 = a.get_xml_using_snapname( str(device), name, post) if reply_format != data_format1 or reply_format != data_format2: self.logger_check.error( colorama.Fore.RED + "ERROR!! Data stored in database is not in %s format." % reply_format, extra=self.log_detail) pass # sys.exit(1) ###### taking snapshot for --snapcheck operation #### elif db.get('check_from_sqlite') is True: a = SqliteExtractXml(db.get('db_name')) snapfile1, data_format1 = a.get_xml_using_snapname( str(device), name, pre) if reply_format != data_format1: self.logger_check.error( colorama.Fore.RED + "ERROR!! Data stored in database is not in %s format." % reply_format, extra=self.log_detail) pass # sys.exit(1) else: snapfile1 = self.generate_snap_file( device, pre, name, reply_format) # if check is true then call function to compare two # snapshots #### if (check is True or action is "check") and reply_format == 'xml': if db.get('check_from_sqlite') is False: snapfile2 = self.generate_snap_file( device, post, name, reply_format) self.compare_reply(op, tests[val], val, teston, check, db, snapfile1, snapfile2, action) # if --diff is true then call compare_diff to compare # two snapshots word by word #### elif (diff is True): if db.get('check_from_sqlite') is False: snapfile2 = self.generate_snap_file( device, post, name, reply_format) self.compare_diff(snapfile1, snapfile2, db.get('check_from_sqlite')) # else call --snapcheck test operation, it works only # for xml reply format #### elif (reply_format == 'xml'): self.compare_reply(op, tests[val], val, teston, check, db, snapfile1, action) ######## bug here ############ # multiple testcases for single command and same device, its deleting that file #################### """ if snap_del is True: snapfile1 = snapfile1 if os.path.isfile(snapfile1) else self.generate_snap_file(device, pre, name, reply_format) os.remove(snapfile1) """ else: # give error message if snapshot in text format is # used with operations other than --diff #### self.logger_check.error( colorama.Fore.RED + "ERROR!! for checking snapshots in text format use '--diff' option ", extra=self.log_detail) # print final result, if operation is --diff then message gets # printed compare_diff function only #### if (diff is not True): op.final_result(self.log_detail) return op