blob: 8187e4eea75b81b86de77aa53ad86e9412206d67 [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 = ""
Jon Halld61331b2015-02-17 16:35:47 -080082 self.EXPERIMENTAL_MODE = False
adminbae64d82013-08-01 10:50:15 -070083 self.test_target = None
84 self.lastcommand = None
Jon Halld61331b2015-02-17 16:35:47 -080085 self.testDir = tests_path
86 self.configFile = config_path + "teston.cfg"
adminbae64d82013-08-01 10:50:15 -070087 self.parsingClass = "xmlparser"
88 self.parserPath = core_path + "/xmlparser"
89 self.loggerPath = core_path + "/logger"
90 self.loggerClass = "Logger"
91 self.logs_path = logs_path
92 self.driver = ''
kelvin-onlabfb521662015-02-27 09:52:40 -080093 self.Thread = Thread
Jon Hall65844a32015-03-09 19:09:37 -070094
adminbae64d82013-08-01 10:50:15 -070095 self.configparser()
96 verifyOptions(options)
97 load_logger()
98 self.componentDictionary = {}
99 self.componentDictionary = self.topology ['COMPONENT']
100 self.driversList=[]
101 if type(self.componentDictionary) == str :
102 self.componentDictionary = dict(self.componentDictionary)
Jon Hall65844a32015-03-09 19:09:37 -0700103
adminbae64d82013-08-01 10:50:15 -0700104 for component in self.componentDictionary :
105 self.driversList.append(self.componentDictionary[component]['type'])
Jon Hall65844a32015-03-09 19:09:37 -0700106
adminbae64d82013-08-01 10:50:15 -0700107 self.driversList = list(set(self.driversList)) # Removing duplicates.
108 # Checking the test_target option set for the component or not
109 if type(self.componentDictionary) == dict:
110 for component in self.componentDictionary.keys():
111 if 'test_target' in self.componentDictionary[component].keys():
112 self.test_target = component
Jon Hall65844a32015-03-09 19:09:37 -0700113
Jon Halld61331b2015-02-17 16:35:47 -0800114 # Checking for the openspeak file and test script
adminbae64d82013-08-01 10:50:15 -0700115 self.logger.initlog(self)
116
117 # Creating Drivers Handles
118 initString = "\n"+"*" * 30+"\n CASE INIT \n"+"*" * 30+"\n"
119 self.log.exact(initString)
120 self.driverObject = {}
121 self.random_order = 111 # Random order id to connect the components
122 components_connect_order = {}
123 #component_list.append()
124 if type(self.componentDictionary) == dict:
125 for component in self.componentDictionary.keys():
126 self.componentDictionary[component]['connect_order'] = self.componentDictionary[component]['connect_order'] if ('connect_order' in self.componentDictionary[component].keys()) else str(self.get_random())
127 components_connect_order[component] = eval(self.componentDictionary[component]['connect_order'])
128 #Ordering components based on the connect order.
129 ordered_component_list =sorted(components_connect_order, key=lambda key: components_connect_order[key])
130 print ordered_component_list
adminbae64d82013-08-01 10:50:15 -0700131 for component in ordered_component_list:
132 self.componentInit(component)
133
134 def configparser(self):
135 '''
136 It will parse the config file (teston.cfg) and return as dictionary
137 '''
138 matchFileName = re.match(r'(.*)\.cfg', self.configFile, re.M | re.I)
139 if matchFileName:
140 xml = open(self.configFile).read()
141 try :
142 self.configDict = xmldict.xml_to_dict(xml)
143 return self.configDict
Jon Hallfebb1c72015-03-05 13:30:09 -0800144 except Exception:
adminbae64d82013-08-01 10:50:15 -0700145 print "There is no such file to parse " + self.configFile
kelvin-onlabf70fd542015-05-07 18:41:40 -0700146
adminbae64d82013-08-01 10:50:15 -0700147 def componentInit(self,component):
148 '''
149 This method will initialize specified component
150 '''
151 global driver_options
152 self.log.info("Creating component Handle: "+component)
Jon Halld61331b2015-02-17 16:35:47 -0800153 driver_options = {}
adminbae64d82013-08-01 10:50:15 -0700154 if 'COMPONENTS' in self.componentDictionary[component].keys():
155 driver_options =dict(self.componentDictionary[component]['COMPONENTS'])
156
157 driver_options['name']=component
158 driverName = self.componentDictionary[component]['type']
159 driver_options ['type'] = driverName
kelvin-onlabf70fd542015-05-07 18:41:40 -0700160
adminbae64d82013-08-01 10:50:15 -0700161 classPath = self.getDriverPath(driverName.lower())
Jon Hall30b82fa2015-03-04 17:15:43 -0800162 driverModule = importlib.import_module(classPath)
adminbae64d82013-08-01 10:50:15 -0700163 driverClass = getattr(driverModule, driverName)
164 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700165
kelvin-onlab0a28a742015-05-18 16:03:13 -0700166 try:
167 self.componentDictionary[component]['host'] = os.environ[str( self.componentDictionary[component]['host'])]
168 except KeyError:
169 self.log.info("Missing OC environment variable! Using stored IPs")
170 except Exception as inst:
171 self.log.error("Uncaught exception: " + str(inst))
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700172
adminbae64d82013-08-01 10:50:15 -0700173 connect_result = driverObject.connect(user_name = self.componentDictionary[component]['user'] if ('user' in self.componentDictionary[component].keys()) else getpass.getuser(),
174 ip_address= self.componentDictionary[component]['host'] if ('host' in self.componentDictionary[component].keys()) else 'localhost',
175 pwd = self.componentDictionary[component]['password'] if ('password' in self.componentDictionary[component].keys()) else 'changeme',
176 port = self.componentDictionary[component]['port'] if ('port' in self.componentDictionary[component].keys()) else None,
177 options = driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700178
adminbae64d82013-08-01 10:50:15 -0700179 if not connect_result:
180 self.log.error("Exiting form the test execution because the connecting to the "+component+" component failed.")
Jon Halld61331b2015-02-17 16:35:47 -0800181 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700182
adminbae64d82013-08-01 10:50:15 -0700183 vars(self)[component] = driverObject
kelvin-onlabf70fd542015-05-07 18:41:40 -0700184
adminbae64d82013-08-01 10:50:15 -0700185 def run(self):
186 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700187 The Execution of the test script's cases listed in the Test params file will be done here.
188 And Update each test case result.
189 This method will return TRUE if it executed all the test cases successfully,
adminbae64d82013-08-01 10:50:15 -0700190 else will retun FALSE
191 '''
adminbae64d82013-08-01 10:50:15 -0700192 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700193 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700194 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800195 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700196 self.TOTAL_TC_NORESULT = 0
197 self.TOTAL_TC_FAIL = 0
198 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700199 self.TEST_ITERATION = 0
adminbae64d82013-08-01 10:50:15 -0700200 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700201 self.CASERESULT = self.NORESULT
202
Jon Halld61331b2015-02-17 16:35:47 -0800203 import testparser
adminbae64d82013-08-01 10:50:15 -0700204 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
205 test = testparser.TestParser(testFile)
206 self.testscript = test.testscript
207 self.code = test.getStepCode()
Jon Hallfebb1c72015-03-05 13:30:09 -0800208 repeat= int(self.params['repeat']) if ('repeat' in self.params) else 1
209 self.TOTAL_TC_PLANNED = len(self.testcases_list)*repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700210
adminbae64d82013-08-01 10:50:15 -0700211 result = self.TRUE
Jon Hallfebb1c72015-03-05 13:30:09 -0800212 while(repeat):
Jon Halla1185982014-09-15 14:55:10 -0700213 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Halld61331b2015-02-17 16:35:47 -0800214 result = self.runCase(self.CurrentTestCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800215 repeat-=1
adminbae64d82013-08-01 10:50:15 -0700216 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700217
adminbae64d82013-08-01 10:50:15 -0700218 def runCase(self,testCaseNumber):
219 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700220 self.CurrentTestCase = ""
221 self.stepResults = []
222 self.stepName = ""
223 self.caseExplaination = ""
adminbae64d82013-08-01 10:50:15 -0700224 result = self.TRUE
225 self.stepCount = 0
226 self.EXPERIMENTAL_MODE = self.FALSE
227 self.addCaseHeader()
228 self.testCaseNumber = str(testCaseNumber)
229 stopped = False
230 try :
231 self.stepList = self.code[self.testCaseNumber].keys()
Jon Halld61331b2015-02-17 16:35:47 -0800232 except KeyError:
Jon Hallfebb1c72015-03-05 13:30:09 -0800233 self.log.error("There is no Test-Case "+ self.testCaseNumber)
234 return self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700235
adminbae64d82013-08-01 10:50:15 -0700236 self.stepCount = 0
237 while self.stepCount < len(self.code[self.testCaseNumber].keys()):
238 result = self.runStep(self.stepList,self.code,self.testCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800239 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700240 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800241 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700242 continue
adminbae64d82013-08-01 10:50:15 -0700243 if not stopped :
kelvin-onlabf70fd542015-05-07 18:41:40 -0700244 if all( self.TRUE == i for i in self.stepResults ):
245 # ALL PASSED
246 self.CASERESULT = self.TRUE
247 elif self.FALSE in self.stepResults:
248 # AT LEAST ONE FAILED
249 self.CASERESULT = self.FALSE
250 elif self.TRUE in self.stepResults:
251 # AT LEAST ONE PASSED
252 self.CASERESULT = self.TRUE
253 else:
254 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700255 self.testCaseResult[str(self.CurrentTestCaseNumber)] = self.CASERESULT
256 self.logger.updateCaseResults(self)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700257 self.log.wiki( "<p>" + self.caseExplaination + "</p>" )
258 self.log.summary( self.caseExplaination )
259 self.log.wiki( "<ul>" )
260 for line in self.stepCache.splitlines():
261 if re.search( " - PASS$", line ):
262 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
263 elif re.search( " - FAIL$", line ):
264 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
265 elif re.search( " - No Result$", line ):
266 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
267 self.log.wiki( "</ul>" )
268 self.log.summary( self.stepCache )
269 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700270 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700271
adminbae64d82013-08-01 10:50:15 -0700272 def runStep(self,stepList,code,testCaseNumber):
273 if not cli.pause:
274 try :
275 step = stepList[self.stepCount]
kelvin-onlabf70fd542015-05-07 18:41:40 -0700276 self.STEPRESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700277 exec code[testCaseNumber][step] in module.__dict__
278 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700279 if step > 0:
280 self.stepCache += "\t"+str(testCaseNumber)+"."+str(step)+" "+self.stepName+" - "
281 if self.STEPRESULT == self.TRUE:
282 self.stepCache += "PASS\n"
283 #self.stepCache += "PASS <ac:emoticon ac:name=\"tick\" /></li>\n"
284 elif self.STEPRESULT == self.FALSE:
285 self.stepCache += "FAIL\n"
286 #self.stepCache += "FAIL <ac:emoticon ac:name=\"cross\" /></li>\n"
287 else:
288 self.stepCache += "No Result\n"
289 #self.stepCache += "No Result <ac:emoticon ac:name=\"warning\" /></li>\n"
290 self.stepResults.append(self.STEPRESULT)
adminbae64d82013-08-01 10:50:15 -0700291 except TypeError,e:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700292 print "\nException in the following section of code: " +\
293 str(testCaseNumber) + "." + str(step) + ": " +\
294 self.stepName
Jon Hall63604932015-02-26 17:09:50 -0800295 #print code[testCaseNumber][step]
adminbae64d82013-08-01 10:50:15 -0700296 self.stepCount = self.stepCount + 1
Jon Hall30b82fa2015-03-04 17:15:43 -0800297 self.log.exception(e)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700298 self.logger.updateCaseResults(self)
299 #WIKI results
300 self.log.wiki( "<ul>" )
301 for line in self.stepCache.splitlines():
302 if re.search( " - PASS$", line ):
303 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
304 elif re.search( " - FAIL$", line ):
305 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
306 elif re.search( " - No Result$", line ):
307 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
308 self.log.wiki( "</ul>" )
309 #summary results
310 self.log.summary( self.stepCache )
311 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700312 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700313 self.exit()
adminbae64d82013-08-01 10:50:15 -0700314 return main.TRUE
adminbae64d82013-08-01 10:50:15 -0700315 if cli.stop:
316 cli.stop = False
317 stopped = True
318 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
319 self.testCaseResult[str(self.CurrentTestCaseNumber)] = "Stopped"
320 self.logger.updateCaseResults(self)
321 result = self.cleanup()
322 return main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700323
adminbae64d82013-08-01 10:50:15 -0700324 def addCaseHeader(self):
325 caseHeader = "\n"+"*" * 30+"\n Result summary for Testcase"+str(self.CurrentTestCaseNumber)+"\n"+"*" * 30+"\n"
Jon Halld61331b2015-02-17 16:35:47 -0800326 self.log.exact(caseHeader)
327 caseHeader = "\n"+"*" * 40 +"\nStart of Test Case"+str(self.CurrentTestCaseNumber)+" : "
adminbae64d82013-08-01 10:50:15 -0700328 for driver in self.componentDictionary.keys():
329 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700330
adminbae64d82013-08-01 10:50:15 -0700331 def addCaseFooter(self):
332 if self.stepCount-1 > 0 :
333 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
334 stepHeader = "\n"+"*" * 40+"\nEnd of Step "+previousStep+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700335
adminbae64d82013-08-01 10:50:15 -0700336 caseFooter = "\n"+"*" * 40+"\nEnd of Test case "+str(self.CurrentTestCaseNumber)+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700337
adminbae64d82013-08-01 10:50:15 -0700338 for driver in self.driversList:
339 vars(self)[driver].write(stepHeader+"\n"+caseFooter)
340
341 def cleanup(self):
342 '''
343 Release all the component handles and the close opened file handles.
344 This will return TRUE if all the component handles and log handles closed properly,
345 else return FALSE
346
347 '''
348 result = self.TRUE
349 self.logger.testSummary(self)
Jon Halld61331b2015-02-17 16:35:47 -0800350
adminbae64d82013-08-01 10:50:15 -0700351 #self.reportFile.close()
Jon Halld61331b2015-02-17 16:35:47 -0800352
admin2c7034f2013-08-02 15:09:17 -0700353 #utilities.send_mail()
Jon Hall00539b12015-04-03 13:55:46 -0700354 for component in self.componentDictionary.keys():
355 try :
Jon Halld61331b2015-02-17 16:35:47 -0800356 tempObject = vars(self)[component]
Jon Hall1a77a1e2015-04-06 10:41:13 -0700357 print "Disconnecting from " + str(tempObject.name) + ": " + \
358 str(tempObject)
adminbae64d82013-08-01 10:50:15 -0700359 tempObject.disconnect()
Jon Halld61331b2015-02-17 16:35:47 -0800360 #tempObject.execute(cmd="exit",prompt="(.*)",timeout=120)
adminbae64d82013-08-01 10:50:15 -0700361
Jon Hall00539b12015-04-03 13:55:46 -0700362 except (Exception):
363 self.log.exception( "Exception while disconnecting from " +
364 str( component ) )
365 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700366 # Closing all the driver's session files
367 for driver in self.componentDictionary.keys():
368 vars(self)[driver].close_log_handles()
Jon Halld61331b2015-02-17 16:35:47 -0800369
adminbae64d82013-08-01 10:50:15 -0700370 return result
Jon Halld61331b2015-02-17 16:35:47 -0800371
adminbae64d82013-08-01 10:50:15 -0700372 def pause(self):
373 '''
374 This function will pause the test's execution, and will continue after user provide 'resume' command.
375 '''
376 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700377
adminbae64d82013-08-01 10:50:15 -0700378 def onfail(self,*components):
379 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700380 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700381 '''
adminbae64d82013-08-01 10:50:15 -0700382 if not components:
383 try :
384 for component in self.componentDictionary.keys():
385 tempObject = vars(self)[component]
386 result = tempObject.onfail()
387 except(Exception),e:
388 print str(e)
389 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700390 else:
391 try :
392 for component in components:
393 tempObject = vars(self)[component]
394 result = tempObject.onfail()
395 except(Exception),e:
396 print str(e)
397 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700398
adminbae64d82013-08-01 10:50:15 -0700399 def getDriverPath(self,driverName):
400 '''
401 Based on the component 'type' specified in the params , this method will find the absolute path ,
402 by recursively searching the name of the component.
403 '''
404 import commands
405
406 cmd = "find "+drivers_path+" -name "+driverName+".py"
407 result = commands.getoutput(cmd)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700408
adminbae64d82013-08-01 10:50:15 -0700409 result_array = str(result).split('\n')
410 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700411
adminbae64d82013-08-01 10:50:15 -0700412 for drivers_list in result_array:
413 result_count = result_count+1
414 if result_count > 1 :
415 print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
416 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700417
adminbae64d82013-08-01 10:50:15 -0700418 result = re.sub("(.*)drivers","",result)
419 result = re.sub("\.py","",result)
420 result = re.sub("\.pyc","",result)
421 result = re.sub("\/",".",result)
422 result = "drivers"+result
423 return result
adminbae64d82013-08-01 10:50:15 -0700424
425 def step(self,stepDesc):
426 '''
427 The step information of the test-case will append to the logs.
428 '''
429 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
430 self.stepName = stepDesc
431
432 stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
433 try :
434 if self.stepCount == 0:
435 stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
436 except AttributeError:
437 stepName = " INIT : Initializing the test case :"+str(self.CurrentTestCaseNumber)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700438
adminbae64d82013-08-01 10:50:15 -0700439 self.log.step(stepName)
440 stepHeader = ""
441 if self.stepCount > 1 :
442 stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700443
Jon Halld61331b2015-02-17 16:35:47 -0800444 stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
adminbae64d82013-08-01 10:50:15 -0700445 for driver in self.componentDictionary.keys():
446 vars(self)[driver+'log'].info(stepHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700447
adminbae64d82013-08-01 10:50:15 -0700448 def case(self,testCaseName):
449 '''
450 Test's each test-case information will append to the logs.
451 '''
Jon Halld61331b2015-02-17 16:35:47 -0800452 self.CurrentTestCase = testCaseName
adminbae64d82013-08-01 10:50:15 -0700453 testCaseName = " " + str(testCaseName) + ""
454 self.log.case(testCaseName)
Jon Halld61331b2015-02-17 16:35:47 -0800455 caseHeader = testCaseName+"\n"+"*" * 40+"\n"
adminbae64d82013-08-01 10:50:15 -0700456 for driver in self.componentDictionary.keys():
457 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700458
adminbae64d82013-08-01 10:50:15 -0700459 def testDesc(self,description):
460 '''
461 Test description will append to the logs.
462 '''
463 description = "Test Description : " + str (description) + ""
464 self.log.info(description)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700465
adminbae64d82013-08-01 10:50:15 -0700466 def _getTest(self):
467 '''
468 This method will parse the test script to find required test information.
469 '''
470 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
471 testFileHandler = open(testFile, 'r')
472 testFileList = testFileHandler.readlines()
473 testFileHandler.close()
474 #self.TOTAL_TC_PLANNED = 0
475 counter = 0
476 for index in range(len(testFileList)):
477 lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
478 if lineMatch:
479 counter = counter + 1
Jon Halla1185982014-09-15 14:55:10 -0700480 self.TC_PLANNED = len(self.testcases_list)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700481
adminbae64d82013-08-01 10:50:15 -0700482 def response_parser(self,response, return_format):
483 ''' It will load the default response parser '''
484 response_dict = {}
485 response_dict = self.response_to_dict(response, return_format)
Jon Halld61331b2015-02-17 16:35:47 -0800486 return_format_string = self.dict_to_return_format(response,return_format,response_dict)
adminbae64d82013-08-01 10:50:15 -0700487 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700488
adminbae64d82013-08-01 10:50:15 -0700489 def response_to_dict(self,response,return_format):
adminbae64d82013-08-01 10:50:15 -0700490 response_dict = {}
491 json_match = re.search('^\s*{', response)
492 xml_match = re.search('^\s*\<', response)
493 ini_match = re.search('^\s*\[', response)
494 if json_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800495 self.log.info(" Response is in 'JSON' format and Converting to '"+return_format+"' format")
Jon Halld61331b2015-02-17 16:35:47 -0800496 # Formatting the json string
adminbae64d82013-08-01 10:50:15 -0700497 response = re.sub(r"{\s*'?(\w)", r'{"\1', response)
498 response = re.sub(r",\s*'?(\w)", r',"\1', response)
499 response = re.sub(r"(\w)'?\s*:", r'\1":', response)
500 response = re.sub(r":\s*'(\w)'\s*([,}])", r':"\1"\2', response)
adminbae64d82013-08-01 10:50:15 -0700501 try :
502 import json
503 response_dict = json.loads(response)
Jon Hall30b82fa2015-03-04 17:15:43 -0800504 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800505 self.log.exception( e )
506 self.log.error("Json Parser is unable to parse the string")
adminbae64d82013-08-01 10:50:15 -0700507 return response_dict
adminbae64d82013-08-01 10:50:15 -0700508 elif ini_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800509 self.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700510 from configobj import ConfigObj
511 response_file = open("respnse_file.temp",'w')
512 response_file.write(response)
Jon Halld61331b2015-02-17 16:35:47 -0800513 response_file.close()
adminbae64d82013-08-01 10:50:15 -0700514 response_dict = ConfigObj("respnse_file.temp")
515 return response_dict
adminbae64d82013-08-01 10:50:15 -0700516 elif xml_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800517 self.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700518 try :
adminbae64d82013-08-01 10:50:15 -0700519 response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
520 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800521 self.log.exception( e )
adminbae64d82013-08-01 10:50:15 -0700522 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700523
adminbae64d82013-08-01 10:50:15 -0700524 def dict_to_return_format(self,response,return_format,response_dict):
adminbae64d82013-08-01 10:50:15 -0700525 if return_format =='table' :
526 ''' Will return in table format'''
527 to_do = "Call the table output formatter"
528 global response_table
529 response_table = '\n'
530 response_table = response_table +'\t'.join(response_dict)+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700531
adminbae64d82013-08-01 10:50:15 -0700532 def get_table(value_to_convert):
533 ''' This will parse the dictionary recusrsively and print as table format'''
534 table_data = ""
535 if type(value_to_convert) == dict :
536 table_data = table_data +'\t'.join(value_to_convert)+"\n"
537 for temp_val in value_to_convert.values() :
538 table_data = table_data + get_table(temp_val)
539 else :
540 table_data = table_data + str(value_to_convert) +"\t"
Jon Halld61331b2015-02-17 16:35:47 -0800541 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700542
adminbae64d82013-08-01 10:50:15 -0700543 for value in response_dict.values() :
544 response_table = response_table + get_table(value)
Jon Hall88e498c2015-03-06 09:54:35 -0800545 # response_table = response_table + '\t'.join(response_dict.values())
adminbae64d82013-08-01 10:50:15 -0700546 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700547
adminbae64d82013-08-01 10:50:15 -0700548 elif return_format =='config':
549 ''' Will return in config format'''
550 to_do = 'Call dict to config coverter'
551 response_string = str(response_dict)
552 print response_string
553 response_config = re.sub(",", "\n\t", response_string)
554 response_config = re.sub("u\'", "\'", response_config)
555 response_config = re.sub("{", "", response_config)
556 response_config = re.sub("}", "\n", response_config)
557 response_config = re.sub(":", " =", response_config)
558 return "[response]\n\t "+response_config
adminbae64d82013-08-01 10:50:15 -0700559 elif return_format == 'xml':
560 ''' Will return in xml format'''
adminbae64d82013-08-01 10:50:15 -0700561 response_xml = xmldict.dict_to_xml(response_dict)
562 response_xml = re.sub(">\s*<", ">\n<", response_xml)
563 return "\n"+response_xml
adminbae64d82013-08-01 10:50:15 -0700564 elif return_format == 'json':
565 ''' Will return in json format'''
566 to_do = 'Call dict to xml coverter'
567 import json
568 response_json = json.dumps(response_dict)
569 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700570
adminbae64d82013-08-01 10:50:15 -0700571 def get_random(self):
572 self.random_order = self.random_order + 1
573 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700574
adminbae64d82013-08-01 10:50:15 -0700575 def exit(self):
576 __builtin__.testthread = None
577 sys.exit()
578
579def verifyOptions(options):
580 '''
581 This will verify the command line options and set to default values, if any option not given in command line.
582 '''
583 import pprint
584 pp = pprint.PrettyPrinter(indent=4)
585
Jon Hall88e498c2015-03-06 09:54:35 -0800586 # pp.pprint(options)
adminbae64d82013-08-01 10:50:15 -0700587 verifyTest(options)
588 verifyExample(options)
589 verifyTestScript(options)
590 verifyParams()
591 verifyLogdir(options)
592 verifyMail(options)
593 verifyTestCases(options)
594
595def verifyTest(options):
596 if options.testname:
597 main.TEST = options.testname
598 main.classPath = "tests."+main.TEST+"."+main.TEST
599 main.tests_path = tests_path
600 elif options.example :
601 main.TEST = options.example
602 main.tests_path = path+"/examples/"
603 main.classPath = "examples."+main.TEST+"."+main.TEST
604 else :
605 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
606 self.exit()
607
608def verifyExample(options):
609 if options.example:
610 main.testDir = path+'/examples/'
611 main.tests_path = path+"/examples/"
612 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700613
adminbae64d82013-08-01 10:50:15 -0700614def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800615 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700616 if options.logdir:
617 main.logdir = options.logdir
618 else :
Jon Halld61331b2015-02-17 16:35:47 -0800619 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700620
adminbae64d82013-08-01 10:50:15 -0700621def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800622 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700623 if options.mail:
624 main.mail = options.mail
625 elif main.params.has_key('mail'):
626 main.mail = main.params['mail']
627 else :
628 main.mail = 'paxweb@paxterrasolutions.com'
629
630def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800631 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700632 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800633 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800634 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700635 testcases_list = re.sub("(\[|\])", "", options.testcases)
636 main.testcases_list = eval(testcases_list+",")
637 else :
638 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700639 temp = eval(main.params['testcases']+",")
640 list1=[]
641 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800642 for test in temp:
643 for testcase in test:
644 if type(testcase)==int:
645 testcase=[testcase]
646 list1.extend(testcase)
647 else :
648 temp=list(temp)
649 for testcase in temp:
650 if type(testcase)==int:
651 testcase=[testcase]
652 list1.extend(testcase)
653 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700654 else :
655 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800656 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700657
adminbae64d82013-08-01 10:50:15 -0700658def verifyTestScript(options):
659 '''
660 Verifyies test script.
661 '''
Jon Halld61331b2015-02-17 16:35:47 -0800662 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700663 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
664 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
665 if os.path.exists(openspeakfile) :
666 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
667 elif os.path.exists(testfile):
668 print ''
669 else:
670 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
671 __builtin__.testthread = None
672 main.exit()
adminbae64d82013-08-01 10:50:15 -0700673 try :
adminbae64d82013-08-01 10:50:15 -0700674 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
675 except(ImportError):
Jon Hallf8ecf732014-12-02 21:14:16 -0500676 print "There was an import error, it might mean that there is no test like "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800677 main.exit()
adminbae64d82013-08-01 10:50:15 -0700678
679 testClass = getattr(testModule, main.TEST)
680 main.testObject = testClass()
681 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800682 main.params = main.parser.parseParams(main.classPath)
683 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700684
adminbae64d82013-08-01 10:50:15 -0700685def verifyParams():
686 try :
687 main.params = main.params['PARAMS']
688 except(KeyError):
689 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800690 main.exit()
adminbae64d82013-08-01 10:50:15 -0700691 try :
692 main.topology = main.topology['TOPOLOGY']
693 except(KeyError):
694 print "Error with the Topology file: Either the file not specified or the format is not correct"
695 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700696
adminbae64d82013-08-01 10:50:15 -0700697def load_parser() :
698 '''
699 It facilitates the loading customised parser for topology and params file.
700 It loads parser mentioned in tab named parser of teston.cfg file.
701 It also loads default xmlparser if no parser have specified in teston.cfg file.
702
703 '''
704 confighash = main.configDict
705 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
706 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
707 if os.path.exists(confighash['config']['parser']['file']) :
708 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
709 moduleList = module.split("/")
710 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
711 try :
712 parsingClass = confighash['config']['parser']['class']
713 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
714 parsingClass = getattr(parsingModule, parsingClass)
715 main.parser = parsingClass()
716 #hashobj = main.parser.parseParams(main.classPath)
717 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
adminbae64d82013-08-01 10:50:15 -0700718 pass
719 else:
720 main.exit()
adminbae64d82013-08-01 10:50:15 -0700721 except ImportError:
722 print sys.exc_info()[1]
723 main.exit()
724 else :
725 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
Jon Halld61331b2015-02-17 16:35:47 -0800726 load_defaultParser()
727 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
728 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700729 else:
730 load_defaultParser()
731
732def load_defaultParser():
733 '''
734 It will load the default parser which is xml parser to parse the params and topology file.
735 '''
736 moduleList = main.parserPath.split("/")
737 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
738 try :
Jon Halld61331b2015-02-17 16:35:47 -0800739 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700740 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
741 parsingClass = getattr(parsingModule, parsingClass)
742 main.parser = parsingClass()
743 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
744 pass
745 else:
746 main.exit()
747
748 except ImportError:
749 print sys.exc_info()[1]
750
adminbae64d82013-08-01 10:50:15 -0700751def load_logger() :
752 '''
753 It facilitates the loading customised parser for topology and params file.
754 It loads parser mentioned in tab named parser of teston.cfg file.
755 It also loads default xmlparser if no parser have specified in teston.cfg file.
756
757 '''
758 confighash = main.configDict
759 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
760 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
761 if os.path.exists(confighash['config']['logger']['file']) :
762 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
763 moduleList = module.split("/")
764 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
765 try :
766 loggerClass = confighash['config']['logger']['class']
767 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
768 loggerClass = getattr(loggerModule, loggerClass)
769 main.logger = loggerClass()
770 #hashobj = main.parser.parseParams(main.classPath)
771
772 except ImportError:
773 print sys.exc_info()[1]
774 else :
775 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
776 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800777 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
778 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700779 else:
780 load_defaultlogger()
781
782def load_defaultlogger():
783 '''
784 It will load the default parser which is xml parser to parse the params and topology file.
785 '''
786 moduleList = main.loggerPath.split("/")
787 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
788 try :
Jon Halld61331b2015-02-17 16:35:47 -0800789 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700790 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
791 loggerClass = getattr(loggerModule, loggerClass)
792 main.logger = loggerClass()
793
794 except ImportError:
795 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800796 main.exit()
adminbae64d82013-08-01 10:50:15 -0700797
798def load_defaultlogger():
799 '''
800 It will load the default parser which is xml parser to parse the params and topology file.
801 '''
802 moduleList = main.loggerPath.split("/")
803 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
804 try :
Jon Halld61331b2015-02-17 16:35:47 -0800805 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700806 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
807 loggerClass = getattr(loggerModule, loggerClass)
808 main.logger = loggerClass()
809
810 except ImportError:
811 print sys.exc_info()[1]
812 main.exit()
813
adminbae64d82013-08-01 10:50:15 -0700814def _echo(self):
815 print "THIS IS ECHO"