admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | ''' |
| 3 | Created on 23-Oct-2012 |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 4 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 5 | @authors: Anil Kumar (anilkumar.s@paxterrasolutions.com), |
| 6 | Raghav Kashyap(raghavkashyap@paxterrasolutions.com) |
| 7 | |
| 8 | |
| 9 | |
| 10 | TestON is free software: you can redistribute it and/or modify |
| 11 | it under the terms of the GNU General Public License as published by |
| 12 | the Free Software Foundation, either version 2 of the License, or |
| 13 | (at your option) any later version. |
| 14 | |
| 15 | TestON is distributed in the hope that it will be useful, |
| 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | GNU General Public License for more details. |
| 19 | |
| 20 | You should have received a copy of the GNU General Public License |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 21 | along with TestON. If not, see <http://www.gnu.org/licenses/>. |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 22 | |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 23 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 24 | Utilities will take care about the basic functions like : |
| 25 | * Extended assertion, |
| 26 | * parse_args for key-value pair handling |
| 27 | * Parsing the params or topology file. |
| 28 | |
| 29 | ''' |
| 30 | import re |
| 31 | from configobj import ConfigObj |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 32 | from core import ast as ast |
| 33 | import smtplib |
| 34 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 35 | import email |
| 36 | import os |
| 37 | import email.mime.application |
| 38 | |
| 39 | class Utilities: |
| 40 | ''' |
| 41 | Utilities will take care about the basic functions like : |
| 42 | * Extended assertion, |
| 43 | * parse_args for key-value pair handling |
| 44 | * Parsing the params or topology file. |
| 45 | ''' |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 46 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 47 | def __init__(self): |
| 48 | self.wrapped = sys.modules[__name__] |
| 49 | |
| 50 | def __getattr__(self, name): |
| 51 | ''' |
| 52 | This will invoke, if the attribute wasn't found the usual ways. |
| 53 | Here it will look for assert_attribute and will execute when AttributeError occurs. |
| 54 | It will return the result of the assert_attribute. |
| 55 | ''' |
| 56 | try: |
| 57 | return getattr(self.wrapped, name) |
| 58 | except AttributeError: |
| 59 | def assertHandling(**kwargs): |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 60 | nameVar = re.match("^assert",name,flags=0) |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 61 | matchVar = re.match("assert(_not_|_)(equals|matches|greater|lesser)",name,flags=0) |
| 62 | notVar = 0 |
| 63 | operators = "" |
| 64 | |
| 65 | try : |
| 66 | if matchVar.group(1) == "_not_" and matchVar.group(2) : |
| 67 | notVar = 1 |
| 68 | operators = matchVar.group(2) |
| 69 | elif matchVar.group(1) == "_" and matchVar.group(2): |
| 70 | operators = matchVar.group(2) |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 71 | except AttributeError: |
| 72 | if matchVar==None and nameVar: |
| 73 | operators ='equals' |
Jon Hall | 79bec22 | 2015-04-30 16:23:30 -0700 | [diff] [blame] | 74 | result = self._assert(NOT=notVar,operator=operators,**kwargs) |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 75 | if result == main.TRUE: |
| 76 | main.log.info("Assertion Passed") |
Jon Hall | 79bec22 | 2015-04-30 16:23:30 -0700 | [diff] [blame] | 77 | main.STEPRESULT = main.TRUE |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 78 | elif result == main.FALSE: |
| 79 | main.log.warn("Assertion Failed") |
Jon Hall | 79bec22 | 2015-04-30 16:23:30 -0700 | [diff] [blame] | 80 | main.STEPRESULT = main.FALSE |
| 81 | else: |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 82 | main.log.error("There is an Error in Assertion") |
Jon Hall | 79bec22 | 2015-04-30 16:23:30 -0700 | [diff] [blame] | 83 | main.STEPRESULT = main.ERROR |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 84 | return result |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 85 | return assertHandling |
Jon Hall | 79bec22 | 2015-04-30 16:23:30 -0700 | [diff] [blame] | 86 | |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 87 | def _assert (self,**assertParam): |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 88 | ''' |
| 89 | It will take the arguments : |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 90 | expect:'Expected output' |
| 91 | actual:'Actual output' |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 92 | onpass:'Action or string to be triggered or displayed respectively when the assert passed' |
| 93 | onfail:'Action or string to be triggered or displayed respectively when the assert failed' |
| 94 | not:'optional argument to specify the negation of the each assertion type' |
| 95 | operator:'assertion type will be defined by using operator. Like equal , greater, lesser, matches.' |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 96 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 97 | It will return the assertion result. |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 98 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 99 | ''' |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 100 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 101 | arguments = self.parse_args(["EXPECT","ACTUAL","ONPASS","ONFAIL","NOT","OPERATOR"],**assertParam) |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 102 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 103 | result = 0 |
| 104 | valuetype = '' |
| 105 | operation = "not "+ str(arguments["OPERATOR"]) if arguments['NOT'] and arguments['NOT'] == 1 else arguments["OPERATOR"] |
| 106 | operators = {'equals':{'STR':'==','NUM':'=='}, 'matches' : '=~', 'greater':'>' ,'lesser':'<'} |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 107 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 108 | expectMatch = re.match('^\s*[+-]?0(e0)?\s*$', str(arguments["EXPECT"]), re.I+re.M) |
| 109 | if not ((not expectMatch) and (arguments["EXPECT"]==0)): |
| 110 | valuetype = 'NUM' |
| 111 | else : |
| 112 | if arguments["OPERATOR"] == 'greater' or arguments["OPERATOR"] == 'lesser': |
| 113 | main.log.error("Numeric comparison on strings is not possibele") |
| 114 | return main.ERROR |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 115 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 116 | valuetype = 'STR' |
| 117 | arguments["ACTUAL"] = str(arguments["ACTUAL"]) |
| 118 | if arguments["OPERATOR"] != 'matches': |
| 119 | arguments["EXPECT"] = str(arguments["EXPECT"]) |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 120 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 121 | try : |
| 122 | opcode = operators[str(arguments["OPERATOR"])][valuetype] if arguments["OPERATOR"] == 'equals' else operators[str(arguments["OPERATOR"])] |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 123 | |
Jon Hall | 1306a56 | 2015-09-04 11:21:24 -0700 | [diff] [blame] | 124 | except KeyError as e: |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 125 | print "Key Error in assertion" |
Jon Hall | 1306a56 | 2015-09-04 11:21:24 -0700 | [diff] [blame] | 126 | print e |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 127 | return main.FALSE |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 128 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 129 | if opcode == '=~': |
| 130 | try: |
| 131 | assert re.search(str(arguments["EXPECT"]),str(arguments["ACTUAL"])) |
| 132 | result = main.TRUE |
| 133 | except AssertionError: |
| 134 | try : |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 135 | assert re.match(str(arguments["EXPECT"]),str(arguments["ACTUAL"])) |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 136 | result = main.TRUE |
| 137 | except AssertionError: |
| 138 | main.log.error("Assertion Failed") |
| 139 | result = main.FALSE |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 140 | else : |
| 141 | try: |
| 142 | if str(opcode)=="==": |
| 143 | main.log.info("Verifying the Expected is equal to the actual or not using assert_equal") |
| 144 | if (arguments["EXPECT"] == arguments["ACTUAL"]): |
| 145 | result = main.TRUE |
| 146 | else : |
| 147 | result = main.FALSE |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 148 | elif str(opcode) == ">": |
| 149 | main.log.info("Verifying the Expected is Greater than the actual or not using assert_greater") |
| 150 | if (ast.literal_eval(arguments["EXPECT"]) > ast.literal_eval(arguments["ACTUAL"])) : |
| 151 | result = main.TRUE |
| 152 | else : |
| 153 | result = main.FALSE |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 154 | elif str(opcode) == "<": |
| 155 | main.log.info("Verifying the Expected is Lesser than the actual or not using assert_lesser") |
| 156 | if (ast.literal_eval(arguments["EXPECT"]) < ast.literal_eval(arguments["ACTUAL"])): |
| 157 | result = main.TRUE |
| 158 | else : |
| 159 | result = main.FALSE |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 160 | except AssertionError: |
| 161 | main.log.error("Assertion Failed") |
| 162 | result = main.FALSE |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 163 | result = result if result else 0 |
| 164 | result = not result if arguments["NOT"] and arguments["NOT"] == 1 else result |
| 165 | resultString = "" |
| 166 | if result : |
| 167 | resultString = str(resultString) + "PASS" |
| 168 | main.log.info(arguments["ONPASS"]) |
| 169 | else : |
| 170 | resultString = str(resultString) + "FAIL" |
| 171 | if not isinstance(arguments["ONFAIL"],str): |
| 172 | eval(str(arguments["ONFAIL"])) |
| 173 | else : |
| 174 | main.log.error(arguments["ONFAIL"]) |
| 175 | main.log.report(arguments["ONFAIL"]) |
Jon Hall | 9062761 | 2015-06-09 14:57:02 -0700 | [diff] [blame] | 176 | main.onFailMsg = arguments[ 'ONFAIL' ] |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 177 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 178 | msg = arguments["ON" + str(resultString)] |
| 179 | |
| 180 | if not isinstance(msg,str): |
| 181 | try: |
| 182 | eval(str(msg)) |
Jon Hall | 1306a56 | 2015-09-04 11:21:24 -0700 | [diff] [blame] | 183 | except SyntaxError as e: |
| 184 | print "function definition is not right" |
| 185 | print e |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 186 | |
| 187 | main.last_result = result |
Jon Hall | 5a72b71 | 2015-09-28 12:20:59 -0700 | [diff] [blame^] | 188 | main.stepResults[2][-1] = result |
| 189 | try: |
| 190 | main.stepResults[3][-1] = arguments[ 'ONFAIL' ] |
| 191 | except AttributeError: |
| 192 | pass |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 193 | return result |
Jon Hall | 8ce34e8 | 2015-06-05 10:41:45 -0700 | [diff] [blame] | 194 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 195 | def parse_args(self,args, **kwargs): |
| 196 | ''' |
| 197 | It will accept the (key,value) pair and will return the (key,value) pairs with keys in uppercase. |
| 198 | ''' |
| 199 | newArgs = {} |
| 200 | for key,value in kwargs.iteritems(): |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 201 | if isinstance(args,list) and str.upper(key) in args: |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 202 | for each in args: |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 203 | if each==str.upper(key): |
| 204 | newArgs [str(each)] = value |
| 205 | elif each != str.upper(key) and (newArgs.has_key(str(each)) == False ): |
| 206 | newArgs[str(each)] = None |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 207 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 208 | return newArgs |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 209 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 210 | def send_mail(self): |
| 211 | # Create a text/plain message |
| 212 | msg = email.mime.Multipart.MIMEMultipart() |
| 213 | try : |
| 214 | if main.test_target: |
| 215 | sub = "Result summary of \""+main.TEST+"\" run on component \""+main.test_target+"\" Version \""+vars(main)[main.test_target].get_version()+"\": "+str(main.TOTAL_TC_SUCCESS)+"% Passed" |
| 216 | else : |
| 217 | sub = "Result summary of \""+main.TEST+"\": "+str(main.TOTAL_TC_SUCCESS)+"% Passed" |
Jon Hall | 1306a56 | 2015-09-04 11:21:24 -0700 | [diff] [blame] | 218 | except ( KeyError, AttributeError ): |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 219 | sub = "Result summary of \""+main.TEST+"\": "+str(main.TOTAL_TC_SUCCESS)+"% Passed" |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 220 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 221 | msg['Subject'] = sub |
| 222 | msg['From'] = 'paxweb@paxterrasolutions.com' |
| 223 | msg['To'] = main.mail |
| 224 | #msg['Cc'] = 'paxweb@paxterrasolutions.com' |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 225 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 226 | # The main body is just another attachment |
| 227 | body = email.mime.Text.MIMEText(main.logHeader+"\n"+main.testResult) |
| 228 | msg.attach(body) |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 229 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 230 | # Attachment |
| 231 | for filename in os.listdir(main.logdir): |
| 232 | filepath = main.logdir+"/"+filename |
| 233 | fp=open(filepath,'rb') |
| 234 | att = email.mime.application.MIMEApplication(fp.read(),_subtype="") |
| 235 | fp.close() |
| 236 | att.add_header('Content-Disposition','attachment',filename=filename) |
| 237 | msg.attach(att) |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 238 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 239 | smtp = smtplib.SMTP('198.57.211.46') |
| 240 | smtp.starttls() |
| 241 | smtp.login('paxweb@paxterrasolutions.com','pax@peace') |
| 242 | smtp.sendmail(msg['From'],[msg['To']], msg.as_string()) |
| 243 | smtp.quit() |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 244 | return main.TRUE |
| 245 | |
| 246 | |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 247 | def parse(self,fileName): |
| 248 | ''' |
| 249 | This will parse the params or topo or cfg file and return content in the file as Dictionary |
| 250 | ''' |
| 251 | self.fileName = fileName |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 252 | matchFileName = re.match(r'(.*)\.(cfg|params|topo)',self.fileName,re.M|re.I) |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 253 | if matchFileName: |
| 254 | try : |
| 255 | parsedInfo = ConfigObj(self.fileName) |
| 256 | return parsedInfo |
Jon Hall | 1306a56 | 2015-09-04 11:21:24 -0700 | [diff] [blame] | 257 | except StandardError: |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 258 | print "There is no such file to parse "+fileName |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 259 | else: |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 260 | return 0 |
admin | bae64d8 | 2013-08-01 10:50:15 -0700 | [diff] [blame] | 261 | |
| 262 | |
| 263 | if __name__ != "__main__": |
| 264 | import sys |
Jon Hall | 4ba53f0 | 2015-07-29 13:07:41 -0700 | [diff] [blame] | 265 | |
| 266 | sys.modules[__name__] = Utilities() |