blob: 9c2ebba467bdc5d4fb487aa8a8291beba959660b [file] [log] [blame]
adminbae64d82013-08-01 10:50:15 -07001#!/usr/bin/env python
2'''
3Created on 22-Oct-2012
Jon Hall65844a32015-03-09 19:09:37 -07004
adminbae64d82013-08-01 10:50:15 -07005@author: Anil Kumar (anilkumar.s@paxterrasolutions.com)
6
7
8 TestON is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
12
13 TestON is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
Jon Hall65844a32015-03-09 19:09:37 -070019 along with TestON. If not, see <http://www.gnu.org/licenses/>.
adminbae64d82013-08-01 10:50:15 -070020
21
22
23teston is the main module.
24
25'''
26
27import sys
28import getpass
29import os
30import re
31import __builtin__
32import new
33import xmldict
Jon Hall30b82fa2015-03-04 17:15:43 -080034import importlib
cameron@onlab.us5cc6a372015-05-11 17:18:07 -070035import os
adminbae64d82013-08-01 10:50:15 -070036module = new.module("test")
37import openspeak
38global path, drivers_path, core_path, tests_path,logs_path
39path = re.sub("(core|bin)$", "", os.getcwd())
40drivers_path = path+"drivers/"
41core_path = path+"core"
42tests_path = path+"tests"
43logs_path = path+"logs/"
44config_path = path + "config/"
45sys.path.append(path)
46sys.path.append( drivers_path)
47sys.path.append(core_path )
48sys.path.append(tests_path)
49
50from core.utilities import Utilities
kelvin-onlabfb521662015-02-27 09:52:40 -080051from core.Thread import Thread
adminbae64d82013-08-01 10:50:15 -070052
adminbae64d82013-08-01 10:50:15 -070053
54class TestON:
55 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -070056 TestON will initiate the specified test.
57 The main tasks are :
58 * Initiate the required Component handles for the test.
adminbae64d82013-08-01 10:50:15 -070059 * Create Log file Handles.
adminbae64d82013-08-01 10:50:15 -070060 '''
61 def __init__(self,options):
62 '''
63 Initialise the component handles specified in the topology file of the specified test.
adminbae64d82013-08-01 10:50:15 -070064 '''
65 # Initialization of the variables.
66 __builtin__.main = self
adminbae64d82013-08-01 10:50:15 -070067 __builtin__.path = path
68 __builtin__.utilities = Utilities()
69 self.TRUE = 1
70 self.FALSE = 0
71 self.ERROR = -1
kelvin-onlabf70fd542015-05-07 18:41:40 -070072 self.NORESULT = 2
adminbae64d82013-08-01 10:50:15 -070073 self.FAIL = False
74 self.PASS = True
kelvin-onlabf70fd542015-05-07 18:41:40 -070075 self.CASERESULT = self.ERROR
76 self.STEPRESULT = self.NORESULT
77 self.stepResults = []
adminbae64d82013-08-01 10:50:15 -070078 self.init_result = self.TRUE
79 self.testResult = "Summary"
kelvin-onlabf70fd542015-05-07 18:41:40 -070080 self.stepName = ""
81 self.stepCache = ""
82 # make this into two lists? one for step names, one for results?
83 # this way, the case result could be a true AND of these results
Jon Halld61331b2015-02-17 16:35:47 -080084 self.EXPERIMENTAL_MODE = False
adminbae64d82013-08-01 10:50:15 -070085 self.test_target = None
86 self.lastcommand = None
Jon Halld61331b2015-02-17 16:35:47 -080087 self.testDir = tests_path
88 self.configFile = config_path + "teston.cfg"
adminbae64d82013-08-01 10:50:15 -070089 self.parsingClass = "xmlparser"
90 self.parserPath = core_path + "/xmlparser"
91 self.loggerPath = core_path + "/logger"
92 self.loggerClass = "Logger"
93 self.logs_path = logs_path
94 self.driver = ''
kelvin-onlabfb521662015-02-27 09:52:40 -080095 self.Thread = Thread
Jon Hall65844a32015-03-09 19:09:37 -070096
adminbae64d82013-08-01 10:50:15 -070097 self.configparser()
98 verifyOptions(options)
99 load_logger()
100 self.componentDictionary = {}
101 self.componentDictionary = self.topology ['COMPONENT']
102 self.driversList=[]
103 if type(self.componentDictionary) == str :
104 self.componentDictionary = dict(self.componentDictionary)
Jon Hall65844a32015-03-09 19:09:37 -0700105
adminbae64d82013-08-01 10:50:15 -0700106 for component in self.componentDictionary :
107 self.driversList.append(self.componentDictionary[component]['type'])
Jon Hall65844a32015-03-09 19:09:37 -0700108
adminbae64d82013-08-01 10:50:15 -0700109 self.driversList = list(set(self.driversList)) # Removing duplicates.
110 # Checking the test_target option set for the component or not
111 if type(self.componentDictionary) == dict:
112 for component in self.componentDictionary.keys():
113 if 'test_target' in self.componentDictionary[component].keys():
114 self.test_target = component
Jon Hall65844a32015-03-09 19:09:37 -0700115
Jon Halld61331b2015-02-17 16:35:47 -0800116 # Checking for the openspeak file and test script
adminbae64d82013-08-01 10:50:15 -0700117 self.logger.initlog(self)
118
119 # Creating Drivers Handles
120 initString = "\n"+"*" * 30+"\n CASE INIT \n"+"*" * 30+"\n"
121 self.log.exact(initString)
122 self.driverObject = {}
123 self.random_order = 111 # Random order id to connect the components
124 components_connect_order = {}
125 #component_list.append()
126 if type(self.componentDictionary) == dict:
127 for component in self.componentDictionary.keys():
128 self.componentDictionary[component]['connect_order'] = self.componentDictionary[component]['connect_order'] if ('connect_order' in self.componentDictionary[component].keys()) else str(self.get_random())
129 components_connect_order[component] = eval(self.componentDictionary[component]['connect_order'])
130 #Ordering components based on the connect order.
131 ordered_component_list =sorted(components_connect_order, key=lambda key: components_connect_order[key])
132 print ordered_component_list
adminbae64d82013-08-01 10:50:15 -0700133 for component in ordered_component_list:
134 self.componentInit(component)
135
136 def configparser(self):
137 '''
138 It will parse the config file (teston.cfg) and return as dictionary
139 '''
140 matchFileName = re.match(r'(.*)\.cfg', self.configFile, re.M | re.I)
141 if matchFileName:
142 xml = open(self.configFile).read()
143 try :
144 self.configDict = xmldict.xml_to_dict(xml)
145 return self.configDict
Jon Hallfebb1c72015-03-05 13:30:09 -0800146 except Exception:
adminbae64d82013-08-01 10:50:15 -0700147 print "There is no such file to parse " + self.configFile
kelvin-onlabf70fd542015-05-07 18:41:40 -0700148
adminbae64d82013-08-01 10:50:15 -0700149 def componentInit(self,component):
150 '''
151 This method will initialize specified component
152 '''
153 global driver_options
154 self.log.info("Creating component Handle: "+component)
Jon Halld61331b2015-02-17 16:35:47 -0800155 driver_options = {}
adminbae64d82013-08-01 10:50:15 -0700156 if 'COMPONENTS' in self.componentDictionary[component].keys():
157 driver_options =dict(self.componentDictionary[component]['COMPONENTS'])
158
159 driver_options['name']=component
160 driverName = self.componentDictionary[component]['type']
161 driver_options ['type'] = driverName
kelvin-onlabf70fd542015-05-07 18:41:40 -0700162
adminbae64d82013-08-01 10:50:15 -0700163 classPath = self.getDriverPath(driverName.lower())
Jon Hall30b82fa2015-03-04 17:15:43 -0800164 driverModule = importlib.import_module(classPath)
adminbae64d82013-08-01 10:50:15 -0700165 driverClass = getattr(driverModule, driverName)
166 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700167
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700168 if "OC" in self.componentDictionary[component]['host']:
169 self.componentDictionary[component]['host'] = os.environ[str( self.componentDictionary[component]['host'])]
170
adminbae64d82013-08-01 10:50:15 -0700171 connect_result = driverObject.connect(user_name = self.componentDictionary[component]['user'] if ('user' in self.componentDictionary[component].keys()) else getpass.getuser(),
172 ip_address= self.componentDictionary[component]['host'] if ('host' in self.componentDictionary[component].keys()) else 'localhost',
173 pwd = self.componentDictionary[component]['password'] if ('password' in self.componentDictionary[component].keys()) else 'changeme',
174 port = self.componentDictionary[component]['port'] if ('port' in self.componentDictionary[component].keys()) else None,
175 options = driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700176
adminbae64d82013-08-01 10:50:15 -0700177 if not connect_result:
178 self.log.error("Exiting form the test execution because the connecting to the "+component+" component failed.")
Jon Halld61331b2015-02-17 16:35:47 -0800179 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700180
adminbae64d82013-08-01 10:50:15 -0700181 vars(self)[component] = driverObject
kelvin-onlabf70fd542015-05-07 18:41:40 -0700182
adminbae64d82013-08-01 10:50:15 -0700183 def run(self):
184 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700185 The Execution of the test script's cases listed in the Test params file will be done here.
186 And Update each test case result.
187 This method will return TRUE if it executed all the test cases successfully,
adminbae64d82013-08-01 10:50:15 -0700188 else will retun FALSE
189 '''
adminbae64d82013-08-01 10:50:15 -0700190 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700191 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700192 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800193 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700194 self.TOTAL_TC_NORESULT = 0
195 self.TOTAL_TC_FAIL = 0
196 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700197 self.TEST_ITERATION = 0
adminbae64d82013-08-01 10:50:15 -0700198 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700199 self.CASERESULT = self.NORESULT
200
Jon Halld61331b2015-02-17 16:35:47 -0800201 import testparser
adminbae64d82013-08-01 10:50:15 -0700202 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
203 test = testparser.TestParser(testFile)
204 self.testscript = test.testscript
205 self.code = test.getStepCode()
Jon Hallfebb1c72015-03-05 13:30:09 -0800206 repeat= int(self.params['repeat']) if ('repeat' in self.params) else 1
207 self.TOTAL_TC_PLANNED = len(self.testcases_list)*repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700208
adminbae64d82013-08-01 10:50:15 -0700209 result = self.TRUE
Jon Hallfebb1c72015-03-05 13:30:09 -0800210 while(repeat):
Jon Halla1185982014-09-15 14:55:10 -0700211 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Halld61331b2015-02-17 16:35:47 -0800212 result = self.runCase(self.CurrentTestCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800213 repeat-=1
adminbae64d82013-08-01 10:50:15 -0700214 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700215
adminbae64d82013-08-01 10:50:15 -0700216 def runCase(self,testCaseNumber):
217 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700218 self.CurrentTestCase = ""
219 self.stepResults = []
220 self.stepName = ""
221 self.caseExplaination = ""
adminbae64d82013-08-01 10:50:15 -0700222 result = self.TRUE
223 self.stepCount = 0
224 self.EXPERIMENTAL_MODE = self.FALSE
225 self.addCaseHeader()
226 self.testCaseNumber = str(testCaseNumber)
227 stopped = False
228 try :
229 self.stepList = self.code[self.testCaseNumber].keys()
Jon Halld61331b2015-02-17 16:35:47 -0800230 except KeyError:
Jon Hallfebb1c72015-03-05 13:30:09 -0800231 self.log.error("There is no Test-Case "+ self.testCaseNumber)
232 return self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700233
adminbae64d82013-08-01 10:50:15 -0700234 self.stepCount = 0
235 while self.stepCount < len(self.code[self.testCaseNumber].keys()):
236 result = self.runStep(self.stepList,self.code,self.testCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800237 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700238 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800239 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700240 continue
adminbae64d82013-08-01 10:50:15 -0700241 if not stopped :
kelvin-onlabf70fd542015-05-07 18:41:40 -0700242 if all( self.TRUE == i for i in self.stepResults ):
243 # ALL PASSED
244 self.CASERESULT = self.TRUE
245 elif self.FALSE in self.stepResults:
246 # AT LEAST ONE FAILED
247 self.CASERESULT = self.FALSE
248 elif self.TRUE in self.stepResults:
249 # AT LEAST ONE PASSED
250 self.CASERESULT = self.TRUE
251 else:
252 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700253 self.testCaseResult[str(self.CurrentTestCaseNumber)] = self.CASERESULT
254 self.logger.updateCaseResults(self)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700255 self.log.wiki( "<p>" + self.caseExplaination + "</p>" )
256 self.log.summary( self.caseExplaination )
257 self.log.wiki( "<ul>" )
258 for line in self.stepCache.splitlines():
259 if re.search( " - PASS$", line ):
260 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
261 elif re.search( " - FAIL$", line ):
262 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
263 elif re.search( " - No Result$", line ):
264 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
265 self.log.wiki( "</ul>" )
266 self.log.summary( self.stepCache )
267 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700268 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700269
adminbae64d82013-08-01 10:50:15 -0700270 def runStep(self,stepList,code,testCaseNumber):
271 if not cli.pause:
272 try :
273 step = stepList[self.stepCount]
kelvin-onlabf70fd542015-05-07 18:41:40 -0700274 self.STEPRESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700275 exec code[testCaseNumber][step] in module.__dict__
276 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700277 if step > 0:
278 self.stepCache += "\t"+str(testCaseNumber)+"."+str(step)+" "+self.stepName+" - "
279 if self.STEPRESULT == self.TRUE:
280 self.stepCache += "PASS\n"
281 #self.stepCache += "PASS <ac:emoticon ac:name=\"tick\" /></li>\n"
282 elif self.STEPRESULT == self.FALSE:
283 self.stepCache += "FAIL\n"
284 #self.stepCache += "FAIL <ac:emoticon ac:name=\"cross\" /></li>\n"
285 else:
286 self.stepCache += "No Result\n"
287 #self.stepCache += "No Result <ac:emoticon ac:name=\"warning\" /></li>\n"
288 self.stepResults.append(self.STEPRESULT)
adminbae64d82013-08-01 10:50:15 -0700289 except TypeError,e:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700290 print "\nException in the following section of code: " +\
291 str(testCaseNumber) + "." + str(step) + ": " +\
292 self.stepName
Jon Hall63604932015-02-26 17:09:50 -0800293 #print code[testCaseNumber][step]
adminbae64d82013-08-01 10:50:15 -0700294 self.stepCount = self.stepCount + 1
Jon Hall30b82fa2015-03-04 17:15:43 -0800295 self.log.exception(e)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700296 self.logger.updateCaseResults(self)
297 #WIKI results
298 self.log.wiki( "<ul>" )
299 for line in self.stepCache.splitlines():
300 if re.search( " - PASS$", line ):
301 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
302 elif re.search( " - FAIL$", line ):
303 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
304 elif re.search( " - No Result$", line ):
305 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
306 self.log.wiki( "</ul>" )
307 #summary results
308 self.log.summary( self.stepCache )
309 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700310 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700311 self.exit()
adminbae64d82013-08-01 10:50:15 -0700312 return main.TRUE
adminbae64d82013-08-01 10:50:15 -0700313 if cli.stop:
314 cli.stop = False
315 stopped = True
316 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
317 self.testCaseResult[str(self.CurrentTestCaseNumber)] = "Stopped"
318 self.logger.updateCaseResults(self)
319 result = self.cleanup()
320 return main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700321
adminbae64d82013-08-01 10:50:15 -0700322 def addCaseHeader(self):
323 caseHeader = "\n"+"*" * 30+"\n Result summary for Testcase"+str(self.CurrentTestCaseNumber)+"\n"+"*" * 30+"\n"
Jon Halld61331b2015-02-17 16:35:47 -0800324 self.log.exact(caseHeader)
325 caseHeader = "\n"+"*" * 40 +"\nStart of Test Case"+str(self.CurrentTestCaseNumber)+" : "
adminbae64d82013-08-01 10:50:15 -0700326 for driver in self.componentDictionary.keys():
327 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700328
adminbae64d82013-08-01 10:50:15 -0700329 def addCaseFooter(self):
330 if self.stepCount-1 > 0 :
331 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
332 stepHeader = "\n"+"*" * 40+"\nEnd of Step "+previousStep+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700333
adminbae64d82013-08-01 10:50:15 -0700334 caseFooter = "\n"+"*" * 40+"\nEnd of Test case "+str(self.CurrentTestCaseNumber)+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700335
adminbae64d82013-08-01 10:50:15 -0700336 for driver in self.driversList:
337 vars(self)[driver].write(stepHeader+"\n"+caseFooter)
338
339 def cleanup(self):
340 '''
341 Release all the component handles and the close opened file handles.
342 This will return TRUE if all the component handles and log handles closed properly,
343 else return FALSE
344
345 '''
346 result = self.TRUE
347 self.logger.testSummary(self)
Jon Halld61331b2015-02-17 16:35:47 -0800348
adminbae64d82013-08-01 10:50:15 -0700349 #self.reportFile.close()
Jon Halld61331b2015-02-17 16:35:47 -0800350
admin2c7034f2013-08-02 15:09:17 -0700351 #utilities.send_mail()
Jon Hall00539b12015-04-03 13:55:46 -0700352 for component in self.componentDictionary.keys():
353 try :
Jon Halld61331b2015-02-17 16:35:47 -0800354 tempObject = vars(self)[component]
Jon Hall1a77a1e2015-04-06 10:41:13 -0700355 print "Disconnecting from " + str(tempObject.name) + ": " + \
356 str(tempObject)
adminbae64d82013-08-01 10:50:15 -0700357 tempObject.disconnect()
Jon Halld61331b2015-02-17 16:35:47 -0800358 #tempObject.execute(cmd="exit",prompt="(.*)",timeout=120)
adminbae64d82013-08-01 10:50:15 -0700359
Jon Hall00539b12015-04-03 13:55:46 -0700360 except (Exception):
361 self.log.exception( "Exception while disconnecting from " +
362 str( component ) )
363 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700364 # Closing all the driver's session files
365 for driver in self.componentDictionary.keys():
366 vars(self)[driver].close_log_handles()
Jon Halld61331b2015-02-17 16:35:47 -0800367
adminbae64d82013-08-01 10:50:15 -0700368 return result
Jon Halld61331b2015-02-17 16:35:47 -0800369
adminbae64d82013-08-01 10:50:15 -0700370 def pause(self):
371 '''
372 This function will pause the test's execution, and will continue after user provide 'resume' command.
373 '''
374 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700375
adminbae64d82013-08-01 10:50:15 -0700376 def onfail(self,*components):
377 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700378 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700379 '''
adminbae64d82013-08-01 10:50:15 -0700380 if not components:
381 try :
382 for component in self.componentDictionary.keys():
383 tempObject = vars(self)[component]
384 result = tempObject.onfail()
385 except(Exception),e:
386 print str(e)
387 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700388 else:
389 try :
390 for component in components:
391 tempObject = vars(self)[component]
392 result = tempObject.onfail()
393 except(Exception),e:
394 print str(e)
395 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700396
adminbae64d82013-08-01 10:50:15 -0700397 def getDriverPath(self,driverName):
398 '''
399 Based on the component 'type' specified in the params , this method will find the absolute path ,
400 by recursively searching the name of the component.
401 '''
402 import commands
403
404 cmd = "find "+drivers_path+" -name "+driverName+".py"
405 result = commands.getoutput(cmd)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700406
adminbae64d82013-08-01 10:50:15 -0700407 result_array = str(result).split('\n')
408 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700409
adminbae64d82013-08-01 10:50:15 -0700410 for drivers_list in result_array:
411 result_count = result_count+1
412 if result_count > 1 :
413 print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
414 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700415
adminbae64d82013-08-01 10:50:15 -0700416 result = re.sub("(.*)drivers","",result)
417 result = re.sub("\.py","",result)
418 result = re.sub("\.pyc","",result)
419 result = re.sub("\/",".",result)
420 result = "drivers"+result
421 return result
adminbae64d82013-08-01 10:50:15 -0700422
423 def step(self,stepDesc):
424 '''
425 The step information of the test-case will append to the logs.
426 '''
427 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
428 self.stepName = stepDesc
429
430 stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
431 try :
432 if self.stepCount == 0:
433 stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
434 except AttributeError:
435 stepName = " INIT : Initializing the test case :"+str(self.CurrentTestCaseNumber)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700436
adminbae64d82013-08-01 10:50:15 -0700437 self.log.step(stepName)
438 stepHeader = ""
439 if self.stepCount > 1 :
440 stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700441
Jon Halld61331b2015-02-17 16:35:47 -0800442 stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
adminbae64d82013-08-01 10:50:15 -0700443 for driver in self.componentDictionary.keys():
444 vars(self)[driver+'log'].info(stepHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700445
adminbae64d82013-08-01 10:50:15 -0700446 def case(self,testCaseName):
447 '''
448 Test's each test-case information will append to the logs.
449 '''
Jon Halld61331b2015-02-17 16:35:47 -0800450 self.CurrentTestCase = testCaseName
adminbae64d82013-08-01 10:50:15 -0700451 testCaseName = " " + str(testCaseName) + ""
452 self.log.case(testCaseName)
Jon Halld61331b2015-02-17 16:35:47 -0800453 caseHeader = testCaseName+"\n"+"*" * 40+"\n"
adminbae64d82013-08-01 10:50:15 -0700454 for driver in self.componentDictionary.keys():
455 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700456
adminbae64d82013-08-01 10:50:15 -0700457 def testDesc(self,description):
458 '''
459 Test description will append to the logs.
460 '''
461 description = "Test Description : " + str (description) + ""
462 self.log.info(description)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700463
adminbae64d82013-08-01 10:50:15 -0700464 def _getTest(self):
465 '''
466 This method will parse the test script to find required test information.
467 '''
468 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
469 testFileHandler = open(testFile, 'r')
470 testFileList = testFileHandler.readlines()
471 testFileHandler.close()
472 #self.TOTAL_TC_PLANNED = 0
473 counter = 0
474 for index in range(len(testFileList)):
475 lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
476 if lineMatch:
477 counter = counter + 1
Jon Halla1185982014-09-15 14:55:10 -0700478 self.TC_PLANNED = len(self.testcases_list)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700479
adminbae64d82013-08-01 10:50:15 -0700480 def response_parser(self,response, return_format):
481 ''' It will load the default response parser '''
482 response_dict = {}
483 response_dict = self.response_to_dict(response, return_format)
Jon Halld61331b2015-02-17 16:35:47 -0800484 return_format_string = self.dict_to_return_format(response,return_format,response_dict)
adminbae64d82013-08-01 10:50:15 -0700485 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700486
adminbae64d82013-08-01 10:50:15 -0700487 def response_to_dict(self,response,return_format):
adminbae64d82013-08-01 10:50:15 -0700488 response_dict = {}
489 json_match = re.search('^\s*{', response)
490 xml_match = re.search('^\s*\<', response)
491 ini_match = re.search('^\s*\[', response)
492 if json_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800493 self.log.info(" Response is in 'JSON' format and Converting to '"+return_format+"' format")
Jon Halld61331b2015-02-17 16:35:47 -0800494 # Formatting the json string
adminbae64d82013-08-01 10:50:15 -0700495 response = re.sub(r"{\s*'?(\w)", r'{"\1', response)
496 response = re.sub(r",\s*'?(\w)", r',"\1', response)
497 response = re.sub(r"(\w)'?\s*:", r'\1":', response)
498 response = re.sub(r":\s*'(\w)'\s*([,}])", r':"\1"\2', response)
adminbae64d82013-08-01 10:50:15 -0700499 try :
500 import json
501 response_dict = json.loads(response)
Jon Hall30b82fa2015-03-04 17:15:43 -0800502 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800503 self.log.exception( e )
504 self.log.error("Json Parser is unable to parse the string")
adminbae64d82013-08-01 10:50:15 -0700505 return response_dict
adminbae64d82013-08-01 10:50:15 -0700506 elif ini_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800507 self.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700508 from configobj import ConfigObj
509 response_file = open("respnse_file.temp",'w')
510 response_file.write(response)
Jon Halld61331b2015-02-17 16:35:47 -0800511 response_file.close()
adminbae64d82013-08-01 10:50:15 -0700512 response_dict = ConfigObj("respnse_file.temp")
513 return response_dict
adminbae64d82013-08-01 10:50:15 -0700514 elif xml_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800515 self.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700516 try :
adminbae64d82013-08-01 10:50:15 -0700517 response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
518 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800519 self.log.exception( e )
adminbae64d82013-08-01 10:50:15 -0700520 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700521
adminbae64d82013-08-01 10:50:15 -0700522 def dict_to_return_format(self,response,return_format,response_dict):
adminbae64d82013-08-01 10:50:15 -0700523 if return_format =='table' :
524 ''' Will return in table format'''
525 to_do = "Call the table output formatter"
526 global response_table
527 response_table = '\n'
528 response_table = response_table +'\t'.join(response_dict)+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700529
adminbae64d82013-08-01 10:50:15 -0700530 def get_table(value_to_convert):
531 ''' This will parse the dictionary recusrsively and print as table format'''
532 table_data = ""
533 if type(value_to_convert) == dict :
534 table_data = table_data +'\t'.join(value_to_convert)+"\n"
535 for temp_val in value_to_convert.values() :
536 table_data = table_data + get_table(temp_val)
537 else :
538 table_data = table_data + str(value_to_convert) +"\t"
Jon Halld61331b2015-02-17 16:35:47 -0800539 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700540
adminbae64d82013-08-01 10:50:15 -0700541 for value in response_dict.values() :
542 response_table = response_table + get_table(value)
Jon Hall88e498c2015-03-06 09:54:35 -0800543 # response_table = response_table + '\t'.join(response_dict.values())
adminbae64d82013-08-01 10:50:15 -0700544 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700545
adminbae64d82013-08-01 10:50:15 -0700546 elif return_format =='config':
547 ''' Will return in config format'''
548 to_do = 'Call dict to config coverter'
549 response_string = str(response_dict)
550 print response_string
551 response_config = re.sub(",", "\n\t", response_string)
552 response_config = re.sub("u\'", "\'", response_config)
553 response_config = re.sub("{", "", response_config)
554 response_config = re.sub("}", "\n", response_config)
555 response_config = re.sub(":", " =", response_config)
556 return "[response]\n\t "+response_config
adminbae64d82013-08-01 10:50:15 -0700557 elif return_format == 'xml':
558 ''' Will return in xml format'''
adminbae64d82013-08-01 10:50:15 -0700559 response_xml = xmldict.dict_to_xml(response_dict)
560 response_xml = re.sub(">\s*<", ">\n<", response_xml)
561 return "\n"+response_xml
adminbae64d82013-08-01 10:50:15 -0700562 elif return_format == 'json':
563 ''' Will return in json format'''
564 to_do = 'Call dict to xml coverter'
565 import json
566 response_json = json.dumps(response_dict)
567 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700568
adminbae64d82013-08-01 10:50:15 -0700569 def get_random(self):
570 self.random_order = self.random_order + 1
571 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700572
adminbae64d82013-08-01 10:50:15 -0700573 def exit(self):
574 __builtin__.testthread = None
575 sys.exit()
576
577def verifyOptions(options):
578 '''
579 This will verify the command line options and set to default values, if any option not given in command line.
580 '''
581 import pprint
582 pp = pprint.PrettyPrinter(indent=4)
583
Jon Hall88e498c2015-03-06 09:54:35 -0800584 # pp.pprint(options)
adminbae64d82013-08-01 10:50:15 -0700585 verifyTest(options)
586 verifyExample(options)
587 verifyTestScript(options)
588 verifyParams()
589 verifyLogdir(options)
590 verifyMail(options)
591 verifyTestCases(options)
592
593def verifyTest(options):
594 if options.testname:
595 main.TEST = options.testname
596 main.classPath = "tests."+main.TEST+"."+main.TEST
597 main.tests_path = tests_path
598 elif options.example :
599 main.TEST = options.example
600 main.tests_path = path+"/examples/"
601 main.classPath = "examples."+main.TEST+"."+main.TEST
602 else :
603 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
604 self.exit()
605
606def verifyExample(options):
607 if options.example:
608 main.testDir = path+'/examples/'
609 main.tests_path = path+"/examples/"
610 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700611
adminbae64d82013-08-01 10:50:15 -0700612def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800613 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700614 if options.logdir:
615 main.logdir = options.logdir
616 else :
Jon Halld61331b2015-02-17 16:35:47 -0800617 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700618
adminbae64d82013-08-01 10:50:15 -0700619def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800620 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700621 if options.mail:
622 main.mail = options.mail
623 elif main.params.has_key('mail'):
624 main.mail = main.params['mail']
625 else :
626 main.mail = 'paxweb@paxterrasolutions.com'
627
628def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800629 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700630 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800631 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800632 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700633 testcases_list = re.sub("(\[|\])", "", options.testcases)
634 main.testcases_list = eval(testcases_list+",")
635 else :
636 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700637 temp = eval(main.params['testcases']+",")
638 list1=[]
639 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800640 for test in temp:
641 for testcase in test:
642 if type(testcase)==int:
643 testcase=[testcase]
644 list1.extend(testcase)
645 else :
646 temp=list(temp)
647 for testcase in temp:
648 if type(testcase)==int:
649 testcase=[testcase]
650 list1.extend(testcase)
651 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700652 else :
653 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800654 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700655
adminbae64d82013-08-01 10:50:15 -0700656def verifyTestScript(options):
657 '''
658 Verifyies test script.
659 '''
Jon Halld61331b2015-02-17 16:35:47 -0800660 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700661 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
662 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
663 if os.path.exists(openspeakfile) :
664 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
665 elif os.path.exists(testfile):
666 print ''
667 else:
668 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
669 __builtin__.testthread = None
670 main.exit()
adminbae64d82013-08-01 10:50:15 -0700671 try :
adminbae64d82013-08-01 10:50:15 -0700672 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
673 except(ImportError):
Jon Hallf8ecf732014-12-02 21:14:16 -0500674 print "There was an import error, it might mean that there is no test like "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800675 main.exit()
adminbae64d82013-08-01 10:50:15 -0700676
677 testClass = getattr(testModule, main.TEST)
678 main.testObject = testClass()
679 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800680 main.params = main.parser.parseParams(main.classPath)
681 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700682
adminbae64d82013-08-01 10:50:15 -0700683def verifyParams():
684 try :
685 main.params = main.params['PARAMS']
686 except(KeyError):
687 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800688 main.exit()
adminbae64d82013-08-01 10:50:15 -0700689 try :
690 main.topology = main.topology['TOPOLOGY']
691 except(KeyError):
692 print "Error with the Topology file: Either the file not specified or the format is not correct"
693 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700694
adminbae64d82013-08-01 10:50:15 -0700695def load_parser() :
696 '''
697 It facilitates the loading customised parser for topology and params file.
698 It loads parser mentioned in tab named parser of teston.cfg file.
699 It also loads default xmlparser if no parser have specified in teston.cfg file.
700
701 '''
702 confighash = main.configDict
703 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
704 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
705 if os.path.exists(confighash['config']['parser']['file']) :
706 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
707 moduleList = module.split("/")
708 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
709 try :
710 parsingClass = confighash['config']['parser']['class']
711 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
712 parsingClass = getattr(parsingModule, parsingClass)
713 main.parser = parsingClass()
714 #hashobj = main.parser.parseParams(main.classPath)
715 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
adminbae64d82013-08-01 10:50:15 -0700716 pass
717 else:
718 main.exit()
adminbae64d82013-08-01 10:50:15 -0700719 except ImportError:
720 print sys.exc_info()[1]
721 main.exit()
722 else :
723 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
Jon Halld61331b2015-02-17 16:35:47 -0800724 load_defaultParser()
725 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
726 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700727 else:
728 load_defaultParser()
729
730def load_defaultParser():
731 '''
732 It will load the default parser which is xml parser to parse the params and topology file.
733 '''
734 moduleList = main.parserPath.split("/")
735 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
736 try :
Jon Halld61331b2015-02-17 16:35:47 -0800737 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700738 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
739 parsingClass = getattr(parsingModule, parsingClass)
740 main.parser = parsingClass()
741 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
742 pass
743 else:
744 main.exit()
745
746 except ImportError:
747 print sys.exc_info()[1]
748
adminbae64d82013-08-01 10:50:15 -0700749def load_logger() :
750 '''
751 It facilitates the loading customised parser for topology and params file.
752 It loads parser mentioned in tab named parser of teston.cfg file.
753 It also loads default xmlparser if no parser have specified in teston.cfg file.
754
755 '''
756 confighash = main.configDict
757 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
758 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
759 if os.path.exists(confighash['config']['logger']['file']) :
760 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
761 moduleList = module.split("/")
762 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
763 try :
764 loggerClass = confighash['config']['logger']['class']
765 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
766 loggerClass = getattr(loggerModule, loggerClass)
767 main.logger = loggerClass()
768 #hashobj = main.parser.parseParams(main.classPath)
769
770 except ImportError:
771 print sys.exc_info()[1]
772 else :
773 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
774 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800775 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
776 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700777 else:
778 load_defaultlogger()
779
780def load_defaultlogger():
781 '''
782 It will load the default parser which is xml parser to parse the params and topology file.
783 '''
784 moduleList = main.loggerPath.split("/")
785 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
786 try :
Jon Halld61331b2015-02-17 16:35:47 -0800787 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700788 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
789 loggerClass = getattr(loggerModule, loggerClass)
790 main.logger = loggerClass()
791
792 except ImportError:
793 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800794 main.exit()
adminbae64d82013-08-01 10:50:15 -0700795
796def load_defaultlogger():
797 '''
798 It will load the default parser which is xml parser to parse the params and topology file.
799 '''
800 moduleList = main.loggerPath.split("/")
801 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
802 try :
Jon Halld61331b2015-02-17 16:35:47 -0800803 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700804 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
805 loggerClass = getattr(loggerModule, loggerClass)
806 main.logger = loggerClass()
807
808 except ImportError:
809 print sys.exc_info()[1]
810 main.exit()
811
adminbae64d82013-08-01 10:50:15 -0700812def _echo(self):
813 print "THIS IS ECHO"