blob: aeb944c1836549663566310fb9159ae503b3595f [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
Jon Hall5b586732015-06-11 11:39:39 -070035import threading
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 Hall5b586732015-06-11 11:39:39 -070094 self.cleanupFlag = False
95 self.cleanupLock = threading.Lock()
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
adminbae64d82013-08-01 10:50:15 -0700168 connect_result = driverObject.connect(user_name = self.componentDictionary[component]['user'] if ('user' in self.componentDictionary[component].keys()) else getpass.getuser(),
169 ip_address= self.componentDictionary[component]['host'] if ('host' in self.componentDictionary[component].keys()) else 'localhost',
170 pwd = self.componentDictionary[component]['password'] if ('password' in self.componentDictionary[component].keys()) else 'changeme',
171 port = self.componentDictionary[component]['port'] if ('port' in self.componentDictionary[component].keys()) else None,
172 options = driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700173
adminbae64d82013-08-01 10:50:15 -0700174 if not connect_result:
175 self.log.error("Exiting form the test execution because the connecting to the "+component+" component failed.")
Jon Halld61331b2015-02-17 16:35:47 -0800176 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700177
adminbae64d82013-08-01 10:50:15 -0700178 vars(self)[component] = driverObject
kelvin-onlabf70fd542015-05-07 18:41:40 -0700179
adminbae64d82013-08-01 10:50:15 -0700180 def run(self):
181 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700182 The Execution of the test script's cases listed in the Test params file will be done here.
183 And Update each test case result.
184 This method will return TRUE if it executed all the test cases successfully,
adminbae64d82013-08-01 10:50:15 -0700185 else will retun FALSE
186 '''
adminbae64d82013-08-01 10:50:15 -0700187 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700188 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700189 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800190 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700191 self.TOTAL_TC_NORESULT = 0
192 self.TOTAL_TC_FAIL = 0
193 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700194 self.TEST_ITERATION = 0
adminbae64d82013-08-01 10:50:15 -0700195 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700196 self.CASERESULT = self.NORESULT
197
Jon Halld61331b2015-02-17 16:35:47 -0800198 import testparser
adminbae64d82013-08-01 10:50:15 -0700199 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
200 test = testparser.TestParser(testFile)
201 self.testscript = test.testscript
202 self.code = test.getStepCode()
Jon Hallfebb1c72015-03-05 13:30:09 -0800203 repeat= int(self.params['repeat']) if ('repeat' in self.params) else 1
204 self.TOTAL_TC_PLANNED = len(self.testcases_list)*repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700205
adminbae64d82013-08-01 10:50:15 -0700206 result = self.TRUE
Jon Hallfebb1c72015-03-05 13:30:09 -0800207 while(repeat):
Jon Halla1185982014-09-15 14:55:10 -0700208 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Halld61331b2015-02-17 16:35:47 -0800209 result = self.runCase(self.CurrentTestCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800210 repeat-=1
adminbae64d82013-08-01 10:50:15 -0700211 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700212
adminbae64d82013-08-01 10:50:15 -0700213 def runCase(self,testCaseNumber):
214 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700215 self.CurrentTestCase = ""
216 self.stepResults = []
217 self.stepName = ""
218 self.caseExplaination = ""
adminbae64d82013-08-01 10:50:15 -0700219 result = self.TRUE
220 self.stepCount = 0
221 self.EXPERIMENTAL_MODE = self.FALSE
222 self.addCaseHeader()
223 self.testCaseNumber = str(testCaseNumber)
224 stopped = False
225 try :
226 self.stepList = self.code[self.testCaseNumber].keys()
Jon Halld61331b2015-02-17 16:35:47 -0800227 except KeyError:
Jon Hallfebb1c72015-03-05 13:30:09 -0800228 self.log.error("There is no Test-Case "+ self.testCaseNumber)
229 return self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700230
adminbae64d82013-08-01 10:50:15 -0700231 self.stepCount = 0
232 while self.stepCount < len(self.code[self.testCaseNumber].keys()):
233 result = self.runStep(self.stepList,self.code,self.testCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800234 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700235 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800236 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700237 continue
adminbae64d82013-08-01 10:50:15 -0700238 if not stopped :
kelvin-onlabf70fd542015-05-07 18:41:40 -0700239 if all( self.TRUE == i for i in self.stepResults ):
240 # ALL PASSED
241 self.CASERESULT = self.TRUE
242 elif self.FALSE in self.stepResults:
243 # AT LEAST ONE FAILED
244 self.CASERESULT = self.FALSE
245 elif self.TRUE in self.stepResults:
246 # AT LEAST ONE PASSED
247 self.CASERESULT = self.TRUE
248 else:
249 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700250 self.testCaseResult[str(self.CurrentTestCaseNumber)] = self.CASERESULT
251 self.logger.updateCaseResults(self)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700252 self.log.wiki( "<p>" + self.caseExplaination + "</p>" )
253 self.log.summary( self.caseExplaination )
254 self.log.wiki( "<ul>" )
255 for line in self.stepCache.splitlines():
256 if re.search( " - PASS$", line ):
257 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
258 elif re.search( " - FAIL$", line ):
259 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
260 elif re.search( " - No Result$", line ):
261 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700262 else: # Should only be on fail message
263 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700264 self.log.wiki( "</ul>" )
265 self.log.summary( self.stepCache )
266 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700267 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700268
adminbae64d82013-08-01 10:50:15 -0700269 def runStep(self,stepList,code,testCaseNumber):
270 if not cli.pause:
271 try :
272 step = stepList[self.stepCount]
kelvin-onlabf70fd542015-05-07 18:41:40 -0700273 self.STEPRESULT = self.NORESULT
Jon Hall90627612015-06-09 14:57:02 -0700274 self.onFailMsg = "\t\tNo on fail message given"
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"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700281 elif self.STEPRESULT == self.FALSE:
282 self.stepCache += "FAIL\n"
Jon Hall8ce34e82015-06-05 10:41:45 -0700283 # TODO: Print the on-fail statement here
Jon Hall90627612015-06-09 14:57:02 -0700284 self.stepCache += "\t\t" + self.onFailMsg + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700285 else:
286 self.stepCache += "No Result\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700287 self.stepResults.append(self.STEPRESULT)
Jon Hall5b586732015-06-11 11:39:39 -0700288 except StandardError:
Jon Hall40d2cbd2015-06-03 16:24:29 -0700289 self.log.exception( "\nException in the following section of" +
290 " code: " + str(testCaseNumber) + "." +
291 str(step) + ": " + self.stepName )
Jon Hall63604932015-02-26 17:09:50 -0800292 #print code[testCaseNumber][step]
adminbae64d82013-08-01 10:50:15 -0700293 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700294 self.logger.updateCaseResults(self)
295 #WIKI results
296 self.log.wiki( "<ul>" )
297 for line in self.stepCache.splitlines():
298 if re.search( " - PASS$", line ):
299 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
300 elif re.search( " - FAIL$", line ):
301 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
302 elif re.search( " - No Result$", line ):
303 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700304 else: # Should only be on fail message
305 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700306 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 '''
Jon Hall5b586732015-06-11 11:39:39 -0700341 Print a summary of the current test's results then attempt to release
342 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700343
Jon Hall5b586732015-06-11 11:39:39 -0700344 This function shouldbe threadsafe such that cleanup will only be
345 executed once per test.
346
347 This will return TRUE if all the component handles and log handles
348 closed properly, else return FALSE.
adminbae64d82013-08-01 10:50:15 -0700349 '''
350 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700351 lock = self.cleanupLock
352 if lock.acquire( False ):
353 try:
354 if self.cleanupFlag is False: # First thread to run this
355 self.cleanupFlag = True
356 self.logger.testSummary(self)
357 for component in self.componentDictionary.keys():
358 try :
359 tempObject = vars(self)[component]
360 print "Disconnecting from " + str(tempObject.name) + ": " + \
361 str(tempObject)
362 tempObject.disconnect()
363 except Exception:
364 self.log.exception( "Exception while disconnecting from " +
365 str( component ) )
366 result = self.FALSE
367 # Closing all the driver's session files
368 for driver in self.componentDictionary.keys():
369 try:
370 vars(self)[driver].close_log_handles()
371 except Exception:
372 self.log.exception( "Exception while closing log files for " +
373 str( driver ) )
374 result = self.FALSE
375 else:
376 pass # Someone else already ran through this function
377 finally:
378 lock.release()
379 else: # Someone already has a lock
380 # NOTE: This could cause problems if we don't release the lock
381 # correctly
382 lock.acquire() # Wait for the other thread to finish
383 # NOTE: If we don't wait, exit could be called while the thread
384 # with the lock is still cleaning up
385 lock.release()
adminbae64d82013-08-01 10:50:15 -0700386 return result
Jon Halld61331b2015-02-17 16:35:47 -0800387
adminbae64d82013-08-01 10:50:15 -0700388 def pause(self):
389 '''
390 This function will pause the test's execution, and will continue after user provide 'resume' command.
391 '''
392 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700393
adminbae64d82013-08-01 10:50:15 -0700394 def onfail(self,*components):
395 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700396 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700397 '''
adminbae64d82013-08-01 10:50:15 -0700398 if not components:
399 try :
400 for component in self.componentDictionary.keys():
401 tempObject = vars(self)[component]
402 result = tempObject.onfail()
403 except(Exception),e:
404 print str(e)
405 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700406 else:
407 try :
408 for component in components:
409 tempObject = vars(self)[component]
410 result = tempObject.onfail()
411 except(Exception),e:
412 print str(e)
413 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700414
adminbae64d82013-08-01 10:50:15 -0700415 def getDriverPath(self,driverName):
416 '''
417 Based on the component 'type' specified in the params , this method will find the absolute path ,
418 by recursively searching the name of the component.
419 '''
420 import commands
421
422 cmd = "find "+drivers_path+" -name "+driverName+".py"
423 result = commands.getoutput(cmd)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700424
adminbae64d82013-08-01 10:50:15 -0700425 result_array = str(result).split('\n')
426 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700427
adminbae64d82013-08-01 10:50:15 -0700428 for drivers_list in result_array:
429 result_count = result_count+1
430 if result_count > 1 :
431 print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
432 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700433
adminbae64d82013-08-01 10:50:15 -0700434 result = re.sub("(.*)drivers","",result)
435 result = re.sub("\.py","",result)
436 result = re.sub("\.pyc","",result)
437 result = re.sub("\/",".",result)
438 result = "drivers"+result
439 return result
adminbae64d82013-08-01 10:50:15 -0700440
441 def step(self,stepDesc):
442 '''
443 The step information of the test-case will append to the logs.
444 '''
445 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
446 self.stepName = stepDesc
447
448 stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
449 try :
450 if self.stepCount == 0:
451 stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
452 except AttributeError:
453 stepName = " INIT : Initializing the test case :"+str(self.CurrentTestCaseNumber)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700454
adminbae64d82013-08-01 10:50:15 -0700455 self.log.step(stepName)
456 stepHeader = ""
457 if self.stepCount > 1 :
458 stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700459
Jon Halld61331b2015-02-17 16:35:47 -0800460 stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
adminbae64d82013-08-01 10:50:15 -0700461 for driver in self.componentDictionary.keys():
462 vars(self)[driver+'log'].info(stepHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700463
adminbae64d82013-08-01 10:50:15 -0700464 def case(self,testCaseName):
465 '''
466 Test's each test-case information will append to the logs.
467 '''
Jon Halld61331b2015-02-17 16:35:47 -0800468 self.CurrentTestCase = testCaseName
adminbae64d82013-08-01 10:50:15 -0700469 testCaseName = " " + str(testCaseName) + ""
470 self.log.case(testCaseName)
Jon Halld61331b2015-02-17 16:35:47 -0800471 caseHeader = testCaseName+"\n"+"*" * 40+"\n"
adminbae64d82013-08-01 10:50:15 -0700472 for driver in self.componentDictionary.keys():
473 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700474
adminbae64d82013-08-01 10:50:15 -0700475 def testDesc(self,description):
476 '''
477 Test description will append to the logs.
478 '''
479 description = "Test Description : " + str (description) + ""
480 self.log.info(description)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700481
adminbae64d82013-08-01 10:50:15 -0700482 def _getTest(self):
483 '''
484 This method will parse the test script to find required test information.
485 '''
486 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
487 testFileHandler = open(testFile, 'r')
488 testFileList = testFileHandler.readlines()
489 testFileHandler.close()
490 #self.TOTAL_TC_PLANNED = 0
491 counter = 0
492 for index in range(len(testFileList)):
493 lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
494 if lineMatch:
495 counter = counter + 1
Jon Halla1185982014-09-15 14:55:10 -0700496 self.TC_PLANNED = len(self.testcases_list)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700497
adminbae64d82013-08-01 10:50:15 -0700498 def response_parser(self,response, return_format):
499 ''' It will load the default response parser '''
500 response_dict = {}
501 response_dict = self.response_to_dict(response, return_format)
Jon Halld61331b2015-02-17 16:35:47 -0800502 return_format_string = self.dict_to_return_format(response,return_format,response_dict)
adminbae64d82013-08-01 10:50:15 -0700503 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700504
adminbae64d82013-08-01 10:50:15 -0700505 def response_to_dict(self,response,return_format):
adminbae64d82013-08-01 10:50:15 -0700506 response_dict = {}
507 json_match = re.search('^\s*{', response)
508 xml_match = re.search('^\s*\<', response)
509 ini_match = re.search('^\s*\[', response)
510 if json_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800511 self.log.info(" Response is in 'JSON' format and Converting to '"+return_format+"' format")
Jon Halld61331b2015-02-17 16:35:47 -0800512 # Formatting the json string
adminbae64d82013-08-01 10:50:15 -0700513 response = re.sub(r"{\s*'?(\w)", r'{"\1', response)
514 response = re.sub(r",\s*'?(\w)", r',"\1', response)
515 response = re.sub(r"(\w)'?\s*:", r'\1":', response)
516 response = re.sub(r":\s*'(\w)'\s*([,}])", r':"\1"\2', response)
adminbae64d82013-08-01 10:50:15 -0700517 try :
518 import json
519 response_dict = json.loads(response)
Jon Hall30b82fa2015-03-04 17:15:43 -0800520 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800521 self.log.exception( e )
522 self.log.error("Json Parser is unable to parse the string")
adminbae64d82013-08-01 10:50:15 -0700523 return response_dict
adminbae64d82013-08-01 10:50:15 -0700524 elif ini_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800525 self.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700526 from configobj import ConfigObj
527 response_file = open("respnse_file.temp",'w')
528 response_file.write(response)
Jon Halld61331b2015-02-17 16:35:47 -0800529 response_file.close()
adminbae64d82013-08-01 10:50:15 -0700530 response_dict = ConfigObj("respnse_file.temp")
531 return response_dict
adminbae64d82013-08-01 10:50:15 -0700532 elif xml_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800533 self.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700534 try :
adminbae64d82013-08-01 10:50:15 -0700535 response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
536 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800537 self.log.exception( e )
adminbae64d82013-08-01 10:50:15 -0700538 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700539
adminbae64d82013-08-01 10:50:15 -0700540 def dict_to_return_format(self,response,return_format,response_dict):
adminbae64d82013-08-01 10:50:15 -0700541 if return_format =='table' :
542 ''' Will return in table format'''
543 to_do = "Call the table output formatter"
544 global response_table
545 response_table = '\n'
546 response_table = response_table +'\t'.join(response_dict)+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700547
adminbae64d82013-08-01 10:50:15 -0700548 def get_table(value_to_convert):
549 ''' This will parse the dictionary recusrsively and print as table format'''
550 table_data = ""
551 if type(value_to_convert) == dict :
552 table_data = table_data +'\t'.join(value_to_convert)+"\n"
553 for temp_val in value_to_convert.values() :
554 table_data = table_data + get_table(temp_val)
555 else :
556 table_data = table_data + str(value_to_convert) +"\t"
Jon Halld61331b2015-02-17 16:35:47 -0800557 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700558
adminbae64d82013-08-01 10:50:15 -0700559 for value in response_dict.values() :
560 response_table = response_table + get_table(value)
Jon Hall88e498c2015-03-06 09:54:35 -0800561 # response_table = response_table + '\t'.join(response_dict.values())
adminbae64d82013-08-01 10:50:15 -0700562 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700563
adminbae64d82013-08-01 10:50:15 -0700564 elif return_format =='config':
565 ''' Will return in config format'''
566 to_do = 'Call dict to config coverter'
567 response_string = str(response_dict)
568 print response_string
569 response_config = re.sub(",", "\n\t", response_string)
570 response_config = re.sub("u\'", "\'", response_config)
571 response_config = re.sub("{", "", response_config)
572 response_config = re.sub("}", "\n", response_config)
573 response_config = re.sub(":", " =", response_config)
574 return "[response]\n\t "+response_config
adminbae64d82013-08-01 10:50:15 -0700575 elif return_format == 'xml':
576 ''' Will return in xml format'''
adminbae64d82013-08-01 10:50:15 -0700577 response_xml = xmldict.dict_to_xml(response_dict)
578 response_xml = re.sub(">\s*<", ">\n<", response_xml)
579 return "\n"+response_xml
adminbae64d82013-08-01 10:50:15 -0700580 elif return_format == 'json':
581 ''' Will return in json format'''
582 to_do = 'Call dict to xml coverter'
583 import json
584 response_json = json.dumps(response_dict)
585 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700586
adminbae64d82013-08-01 10:50:15 -0700587 def get_random(self):
588 self.random_order = self.random_order + 1
589 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700590
adminbae64d82013-08-01 10:50:15 -0700591 def exit(self):
592 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700593 for thread in threading.enumerate():
594 if thread.isAlive():
595 try:
596 thread._Thread__stop()
597 except:
598 print(str(thread.getName()) + ' could not be terminated' )
adminbae64d82013-08-01 10:50:15 -0700599 sys.exit()
600
601def verifyOptions(options):
602 '''
603 This will verify the command line options and set to default values, if any option not given in command line.
604 '''
605 import pprint
606 pp = pprint.PrettyPrinter(indent=4)
607
Jon Hall88e498c2015-03-06 09:54:35 -0800608 # pp.pprint(options)
adminbae64d82013-08-01 10:50:15 -0700609 verifyTest(options)
610 verifyExample(options)
611 verifyTestScript(options)
612 verifyParams()
613 verifyLogdir(options)
614 verifyMail(options)
615 verifyTestCases(options)
616
617def verifyTest(options):
618 if options.testname:
619 main.TEST = options.testname
620 main.classPath = "tests."+main.TEST+"."+main.TEST
621 main.tests_path = tests_path
622 elif options.example :
623 main.TEST = options.example
624 main.tests_path = path+"/examples/"
625 main.classPath = "examples."+main.TEST+"."+main.TEST
626 else :
627 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700628 main.exit()
adminbae64d82013-08-01 10:50:15 -0700629
630def verifyExample(options):
631 if options.example:
632 main.testDir = path+'/examples/'
633 main.tests_path = path+"/examples/"
634 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700635
adminbae64d82013-08-01 10:50:15 -0700636def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800637 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700638 if options.logdir:
639 main.logdir = options.logdir
640 else :
Jon Halld61331b2015-02-17 16:35:47 -0800641 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700642
adminbae64d82013-08-01 10:50:15 -0700643def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800644 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700645 if options.mail:
646 main.mail = options.mail
647 elif main.params.has_key('mail'):
648 main.mail = main.params['mail']
649 else :
650 main.mail = 'paxweb@paxterrasolutions.com'
651
652def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800653 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700654 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800655 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800656 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700657 testcases_list = re.sub("(\[|\])", "", options.testcases)
658 main.testcases_list = eval(testcases_list+",")
659 else :
660 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700661 temp = eval(main.params['testcases']+",")
662 list1=[]
663 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800664 for test in temp:
665 for testcase in test:
666 if type(testcase)==int:
667 testcase=[testcase]
668 list1.extend(testcase)
669 else :
670 temp=list(temp)
671 for testcase in temp:
672 if type(testcase)==int:
673 testcase=[testcase]
674 list1.extend(testcase)
675 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700676 else :
677 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800678 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700679
adminbae64d82013-08-01 10:50:15 -0700680def verifyTestScript(options):
681 '''
682 Verifyies test script.
683 '''
Jon Halld61331b2015-02-17 16:35:47 -0800684 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700685 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
686 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
687 if os.path.exists(openspeakfile) :
688 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
689 elif os.path.exists(testfile):
690 print ''
691 else:
692 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
693 __builtin__.testthread = None
694 main.exit()
adminbae64d82013-08-01 10:50:15 -0700695 try :
adminbae64d82013-08-01 10:50:15 -0700696 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
697 except(ImportError):
Jon Hallf8ecf732014-12-02 21:14:16 -0500698 print "There was an import error, it might mean that there is no test like "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800699 main.exit()
adminbae64d82013-08-01 10:50:15 -0700700
701 testClass = getattr(testModule, main.TEST)
702 main.testObject = testClass()
703 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800704 main.params = main.parser.parseParams(main.classPath)
705 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700706
adminbae64d82013-08-01 10:50:15 -0700707def verifyParams():
708 try :
709 main.params = main.params['PARAMS']
710 except(KeyError):
711 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800712 main.exit()
adminbae64d82013-08-01 10:50:15 -0700713 try :
714 main.topology = main.topology['TOPOLOGY']
715 except(KeyError):
716 print "Error with the Topology file: Either the file not specified or the format is not correct"
717 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700718
adminbae64d82013-08-01 10:50:15 -0700719def load_parser() :
720 '''
721 It facilitates the loading customised parser for topology and params file.
722 It loads parser mentioned in tab named parser of teston.cfg file.
723 It also loads default xmlparser if no parser have specified in teston.cfg file.
724
725 '''
726 confighash = main.configDict
727 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
728 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
729 if os.path.exists(confighash['config']['parser']['file']) :
730 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
731 moduleList = module.split("/")
732 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
733 try :
734 parsingClass = confighash['config']['parser']['class']
735 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
736 parsingClass = getattr(parsingModule, parsingClass)
737 main.parser = parsingClass()
738 #hashobj = main.parser.parseParams(main.classPath)
739 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
adminbae64d82013-08-01 10:50:15 -0700740 pass
741 else:
742 main.exit()
adminbae64d82013-08-01 10:50:15 -0700743 except ImportError:
744 print sys.exc_info()[1]
745 main.exit()
746 else :
747 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
Jon Halld61331b2015-02-17 16:35:47 -0800748 load_defaultParser()
749 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
750 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700751 else:
752 load_defaultParser()
753
754def load_defaultParser():
755 '''
756 It will load the default parser which is xml parser to parse the params and topology file.
757 '''
758 moduleList = main.parserPath.split("/")
759 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
760 try :
Jon Halld61331b2015-02-17 16:35:47 -0800761 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700762 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
763 parsingClass = getattr(parsingModule, parsingClass)
764 main.parser = parsingClass()
765 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
766 pass
767 else:
768 main.exit()
769
770 except ImportError:
771 print sys.exc_info()[1]
772
adminbae64d82013-08-01 10:50:15 -0700773def load_logger() :
774 '''
775 It facilitates the loading customised parser for topology and params file.
776 It loads parser mentioned in tab named parser of teston.cfg file.
777 It also loads default xmlparser if no parser have specified in teston.cfg file.
778
779 '''
780 confighash = main.configDict
781 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
782 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
783 if os.path.exists(confighash['config']['logger']['file']) :
784 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
785 moduleList = module.split("/")
786 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
787 try :
788 loggerClass = confighash['config']['logger']['class']
789 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
790 loggerClass = getattr(loggerModule, loggerClass)
791 main.logger = loggerClass()
792 #hashobj = main.parser.parseParams(main.classPath)
793
794 except ImportError:
795 print sys.exc_info()[1]
796 else :
797 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
798 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800799 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
800 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700801 else:
802 load_defaultlogger()
803
804def load_defaultlogger():
805 '''
806 It will load the default parser which is xml parser to parse the params and topology file.
807 '''
808 moduleList = main.loggerPath.split("/")
809 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
810 try :
Jon Halld61331b2015-02-17 16:35:47 -0800811 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700812 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
813 loggerClass = getattr(loggerModule, loggerClass)
814 main.logger = loggerClass()
815
816 except ImportError:
817 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800818 main.exit()
adminbae64d82013-08-01 10:50:15 -0700819
adminbae64d82013-08-01 10:50:15 -0700820def _echo(self):
821 print "THIS IS ECHO"