blob: 7e99ffd886d4dd097a47fb7a063ad684271c0e44 [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
jenkinsfa1cdbb2015-06-23 14:02:35 -0700168 if "OC" in self.componentDictionary[component]['host']:
169 try:
170 self.componentDictionary[component]['host'] = os.environ[str( self.componentDictionary[component]['host'])]
171 except KeyError:
172 self.log.info("Missing OC environment variable! Using stored IPs")
173 f = open("myIps","r")
174 ips = f.readlines()
175 for line in ips:
176 if self.componentDictionary[component]['host'] in line:
177 line = line.split("=")
178 myIp = line[1]
179 self.componentDictionary[component]['host'] = myIp
180 except Exception as inst:
181 self.log.error("Uncaught exception: " + str(inst))
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700182
adminbae64d82013-08-01 10:50:15 -0700183 connect_result = driverObject.connect(user_name = self.componentDictionary[component]['user'] if ('user' in self.componentDictionary[component].keys()) else getpass.getuser(),
184 ip_address= self.componentDictionary[component]['host'] if ('host' in self.componentDictionary[component].keys()) else 'localhost',
185 pwd = self.componentDictionary[component]['password'] if ('password' in self.componentDictionary[component].keys()) else 'changeme',
186 port = self.componentDictionary[component]['port'] if ('port' in self.componentDictionary[component].keys()) else None,
187 options = driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700188
adminbae64d82013-08-01 10:50:15 -0700189 if not connect_result:
190 self.log.error("Exiting form the test execution because the connecting to the "+component+" component failed.")
Jon Halld61331b2015-02-17 16:35:47 -0800191 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700192
adminbae64d82013-08-01 10:50:15 -0700193 vars(self)[component] = driverObject
kelvin-onlabf70fd542015-05-07 18:41:40 -0700194
adminbae64d82013-08-01 10:50:15 -0700195 def run(self):
196 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700197 The Execution of the test script's cases listed in the Test params file will be done here.
198 And Update each test case result.
199 This method will return TRUE if it executed all the test cases successfully,
adminbae64d82013-08-01 10:50:15 -0700200 else will retun FALSE
201 '''
adminbae64d82013-08-01 10:50:15 -0700202 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700203 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700204 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800205 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700206 self.TOTAL_TC_NORESULT = 0
207 self.TOTAL_TC_FAIL = 0
208 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700209 self.TEST_ITERATION = 0
adminbae64d82013-08-01 10:50:15 -0700210 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700211 self.CASERESULT = self.NORESULT
212
Jon Halld61331b2015-02-17 16:35:47 -0800213 import testparser
adminbae64d82013-08-01 10:50:15 -0700214 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
215 test = testparser.TestParser(testFile)
216 self.testscript = test.testscript
217 self.code = test.getStepCode()
Jon Hallfebb1c72015-03-05 13:30:09 -0800218 repeat= int(self.params['repeat']) if ('repeat' in self.params) else 1
219 self.TOTAL_TC_PLANNED = len(self.testcases_list)*repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700220
adminbae64d82013-08-01 10:50:15 -0700221 result = self.TRUE
Jon Hallfebb1c72015-03-05 13:30:09 -0800222 while(repeat):
Jon Halla1185982014-09-15 14:55:10 -0700223 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Halld61331b2015-02-17 16:35:47 -0800224 result = self.runCase(self.CurrentTestCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800225 repeat-=1
adminbae64d82013-08-01 10:50:15 -0700226 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700227
adminbae64d82013-08-01 10:50:15 -0700228 def runCase(self,testCaseNumber):
229 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700230 self.CurrentTestCase = ""
231 self.stepResults = []
232 self.stepName = ""
233 self.caseExplaination = ""
adminbae64d82013-08-01 10:50:15 -0700234 result = self.TRUE
235 self.stepCount = 0
236 self.EXPERIMENTAL_MODE = self.FALSE
237 self.addCaseHeader()
238 self.testCaseNumber = str(testCaseNumber)
239 stopped = False
240 try :
241 self.stepList = self.code[self.testCaseNumber].keys()
Jon Halld61331b2015-02-17 16:35:47 -0800242 except KeyError:
Jon Hallfebb1c72015-03-05 13:30:09 -0800243 self.log.error("There is no Test-Case "+ self.testCaseNumber)
244 return self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700245
adminbae64d82013-08-01 10:50:15 -0700246 self.stepCount = 0
247 while self.stepCount < len(self.code[self.testCaseNumber].keys()):
248 result = self.runStep(self.stepList,self.code,self.testCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800249 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700250 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800251 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700252 continue
adminbae64d82013-08-01 10:50:15 -0700253 if not stopped :
kelvin-onlabf70fd542015-05-07 18:41:40 -0700254 if all( self.TRUE == i for i in self.stepResults ):
255 # ALL PASSED
256 self.CASERESULT = self.TRUE
257 elif self.FALSE in self.stepResults:
258 # AT LEAST ONE FAILED
259 self.CASERESULT = self.FALSE
260 elif self.TRUE in self.stepResults:
261 # AT LEAST ONE PASSED
262 self.CASERESULT = self.TRUE
263 else:
264 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700265 self.testCaseResult[str(self.CurrentTestCaseNumber)] = self.CASERESULT
266 self.logger.updateCaseResults(self)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700267 self.log.wiki( "<p>" + self.caseExplaination + "</p>" )
268 self.log.summary( self.caseExplaination )
269 self.log.wiki( "<ul>" )
270 for line in self.stepCache.splitlines():
271 if re.search( " - PASS$", line ):
272 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
273 elif re.search( " - FAIL$", line ):
274 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
275 elif re.search( " - No Result$", line ):
276 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700277 else: # Should only be on fail message
278 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700279 self.log.wiki( "</ul>" )
280 self.log.summary( self.stepCache )
281 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700282 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700283
adminbae64d82013-08-01 10:50:15 -0700284 def runStep(self,stepList,code,testCaseNumber):
285 if not cli.pause:
286 try :
287 step = stepList[self.stepCount]
kelvin-onlabf70fd542015-05-07 18:41:40 -0700288 self.STEPRESULT = self.NORESULT
Jon Hall90627612015-06-09 14:57:02 -0700289 self.onFailMsg = "\t\tNo on fail message given"
adminbae64d82013-08-01 10:50:15 -0700290 exec code[testCaseNumber][step] in module.__dict__
291 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700292 if step > 0:
293 self.stepCache += "\t"+str(testCaseNumber)+"."+str(step)+" "+self.stepName+" - "
294 if self.STEPRESULT == self.TRUE:
295 self.stepCache += "PASS\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700296 elif self.STEPRESULT == self.FALSE:
297 self.stepCache += "FAIL\n"
Jon Hall8ce34e82015-06-05 10:41:45 -0700298 # TODO: Print the on-fail statement here
Jon Hall90627612015-06-09 14:57:02 -0700299 self.stepCache += "\t\t" + self.onFailMsg + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700300 else:
301 self.stepCache += "No Result\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700302 self.stepResults.append(self.STEPRESULT)
Jon Hall5b586732015-06-11 11:39:39 -0700303 except StandardError:
Jon Hall40d2cbd2015-06-03 16:24:29 -0700304 self.log.exception( "\nException in the following section of" +
305 " code: " + str(testCaseNumber) + "." +
306 str(step) + ": " + self.stepName )
Jon Hall63604932015-02-26 17:09:50 -0800307 #print code[testCaseNumber][step]
adminbae64d82013-08-01 10:50:15 -0700308 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700309 self.logger.updateCaseResults(self)
310 #WIKI results
311 self.log.wiki( "<ul>" )
312 for line in self.stepCache.splitlines():
313 if re.search( " - PASS$", line ):
314 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
315 elif re.search( " - FAIL$", line ):
316 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
317 elif re.search( " - No Result$", line ):
318 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700319 else: # Should only be on fail message
320 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700321 self.log.wiki( "</ul>" )
322 #summary results
323 self.log.summary( self.stepCache )
324 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700325 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700326 self.exit()
adminbae64d82013-08-01 10:50:15 -0700327 return main.TRUE
adminbae64d82013-08-01 10:50:15 -0700328 if cli.stop:
329 cli.stop = False
330 stopped = True
331 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
332 self.testCaseResult[str(self.CurrentTestCaseNumber)] = "Stopped"
333 self.logger.updateCaseResults(self)
334 result = self.cleanup()
335 return main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700336
adminbae64d82013-08-01 10:50:15 -0700337 def addCaseHeader(self):
338 caseHeader = "\n"+"*" * 30+"\n Result summary for Testcase"+str(self.CurrentTestCaseNumber)+"\n"+"*" * 30+"\n"
Jon Halld61331b2015-02-17 16:35:47 -0800339 self.log.exact(caseHeader)
340 caseHeader = "\n"+"*" * 40 +"\nStart of Test Case"+str(self.CurrentTestCaseNumber)+" : "
adminbae64d82013-08-01 10:50:15 -0700341 for driver in self.componentDictionary.keys():
342 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700343
adminbae64d82013-08-01 10:50:15 -0700344 def addCaseFooter(self):
345 if self.stepCount-1 > 0 :
346 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
347 stepHeader = "\n"+"*" * 40+"\nEnd of Step "+previousStep+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700348
adminbae64d82013-08-01 10:50:15 -0700349 caseFooter = "\n"+"*" * 40+"\nEnd of Test case "+str(self.CurrentTestCaseNumber)+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700350
adminbae64d82013-08-01 10:50:15 -0700351 for driver in self.driversList:
352 vars(self)[driver].write(stepHeader+"\n"+caseFooter)
353
354 def cleanup(self):
355 '''
Jon Hall5b586732015-06-11 11:39:39 -0700356 Print a summary of the current test's results then attempt to release
357 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700358
Jon Hall5b586732015-06-11 11:39:39 -0700359 This function shouldbe threadsafe such that cleanup will only be
360 executed once per test.
361
362 This will return TRUE if all the component handles and log handles
363 closed properly, else return FALSE.
adminbae64d82013-08-01 10:50:15 -0700364 '''
365 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700366 lock = self.cleanupLock
367 if lock.acquire( False ):
368 try:
369 if self.cleanupFlag is False: # First thread to run this
370 self.cleanupFlag = True
371 self.logger.testSummary(self)
372 for component in self.componentDictionary.keys():
373 try :
374 tempObject = vars(self)[component]
375 print "Disconnecting from " + str(tempObject.name) + ": " + \
376 str(tempObject)
377 tempObject.disconnect()
378 except Exception:
379 self.log.exception( "Exception while disconnecting from " +
380 str( component ) )
381 result = self.FALSE
382 # Closing all the driver's session files
383 for driver in self.componentDictionary.keys():
384 try:
385 vars(self)[driver].close_log_handles()
386 except Exception:
387 self.log.exception( "Exception while closing log files for " +
388 str( driver ) )
389 result = self.FALSE
390 else:
391 pass # Someone else already ran through this function
392 finally:
393 lock.release()
394 else: # Someone already has a lock
395 # NOTE: This could cause problems if we don't release the lock
396 # correctly
397 lock.acquire() # Wait for the other thread to finish
398 # NOTE: If we don't wait, exit could be called while the thread
399 # with the lock is still cleaning up
400 lock.release()
adminbae64d82013-08-01 10:50:15 -0700401 return result
Jon Halld61331b2015-02-17 16:35:47 -0800402
adminbae64d82013-08-01 10:50:15 -0700403 def pause(self):
404 '''
405 This function will pause the test's execution, and will continue after user provide 'resume' command.
406 '''
407 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700408
adminbae64d82013-08-01 10:50:15 -0700409 def onfail(self,*components):
410 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700411 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700412 '''
adminbae64d82013-08-01 10:50:15 -0700413 if not components:
414 try :
415 for component in self.componentDictionary.keys():
416 tempObject = vars(self)[component]
417 result = tempObject.onfail()
418 except(Exception),e:
419 print str(e)
420 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700421 else:
422 try :
423 for component in components:
424 tempObject = vars(self)[component]
425 result = tempObject.onfail()
426 except(Exception),e:
427 print str(e)
428 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700429
adminbae64d82013-08-01 10:50:15 -0700430 def getDriverPath(self,driverName):
431 '''
432 Based on the component 'type' specified in the params , this method will find the absolute path ,
433 by recursively searching the name of the component.
434 '''
435 import commands
436
437 cmd = "find "+drivers_path+" -name "+driverName+".py"
438 result = commands.getoutput(cmd)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700439
adminbae64d82013-08-01 10:50:15 -0700440 result_array = str(result).split('\n')
441 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700442
adminbae64d82013-08-01 10:50:15 -0700443 for drivers_list in result_array:
444 result_count = result_count+1
445 if result_count > 1 :
446 print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
447 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700448
adminbae64d82013-08-01 10:50:15 -0700449 result = re.sub("(.*)drivers","",result)
450 result = re.sub("\.py","",result)
451 result = re.sub("\.pyc","",result)
452 result = re.sub("\/",".",result)
453 result = "drivers"+result
454 return result
adminbae64d82013-08-01 10:50:15 -0700455
456 def step(self,stepDesc):
457 '''
458 The step information of the test-case will append to the logs.
459 '''
460 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
461 self.stepName = stepDesc
462
463 stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
464 try :
465 if self.stepCount == 0:
466 stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
467 except AttributeError:
468 stepName = " INIT : Initializing the test case :"+str(self.CurrentTestCaseNumber)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700469
adminbae64d82013-08-01 10:50:15 -0700470 self.log.step(stepName)
471 stepHeader = ""
472 if self.stepCount > 1 :
473 stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700474
Jon Halld61331b2015-02-17 16:35:47 -0800475 stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
adminbae64d82013-08-01 10:50:15 -0700476 for driver in self.componentDictionary.keys():
477 vars(self)[driver+'log'].info(stepHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700478
adminbae64d82013-08-01 10:50:15 -0700479 def case(self,testCaseName):
480 '''
481 Test's each test-case information will append to the logs.
482 '''
Jon Halld61331b2015-02-17 16:35:47 -0800483 self.CurrentTestCase = testCaseName
adminbae64d82013-08-01 10:50:15 -0700484 testCaseName = " " + str(testCaseName) + ""
485 self.log.case(testCaseName)
Jon Halld61331b2015-02-17 16:35:47 -0800486 caseHeader = testCaseName+"\n"+"*" * 40+"\n"
adminbae64d82013-08-01 10:50:15 -0700487 for driver in self.componentDictionary.keys():
488 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700489
adminbae64d82013-08-01 10:50:15 -0700490 def testDesc(self,description):
491 '''
492 Test description will append to the logs.
493 '''
494 description = "Test Description : " + str (description) + ""
495 self.log.info(description)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700496
adminbae64d82013-08-01 10:50:15 -0700497 def _getTest(self):
498 '''
499 This method will parse the test script to find required test information.
500 '''
501 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
502 testFileHandler = open(testFile, 'r')
503 testFileList = testFileHandler.readlines()
504 testFileHandler.close()
505 #self.TOTAL_TC_PLANNED = 0
506 counter = 0
507 for index in range(len(testFileList)):
508 lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
509 if lineMatch:
510 counter = counter + 1
Jon Halla1185982014-09-15 14:55:10 -0700511 self.TC_PLANNED = len(self.testcases_list)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700512
adminbae64d82013-08-01 10:50:15 -0700513 def response_parser(self,response, return_format):
514 ''' It will load the default response parser '''
515 response_dict = {}
516 response_dict = self.response_to_dict(response, return_format)
Jon Halld61331b2015-02-17 16:35:47 -0800517 return_format_string = self.dict_to_return_format(response,return_format,response_dict)
adminbae64d82013-08-01 10:50:15 -0700518 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700519
adminbae64d82013-08-01 10:50:15 -0700520 def response_to_dict(self,response,return_format):
adminbae64d82013-08-01 10:50:15 -0700521 response_dict = {}
522 json_match = re.search('^\s*{', response)
523 xml_match = re.search('^\s*\<', response)
524 ini_match = re.search('^\s*\[', response)
525 if json_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800526 self.log.info(" Response is in 'JSON' format and Converting to '"+return_format+"' format")
Jon Halld61331b2015-02-17 16:35:47 -0800527 # Formatting the json string
adminbae64d82013-08-01 10:50:15 -0700528 response = re.sub(r"{\s*'?(\w)", r'{"\1', response)
529 response = re.sub(r",\s*'?(\w)", r',"\1', response)
530 response = re.sub(r"(\w)'?\s*:", r'\1":', response)
531 response = re.sub(r":\s*'(\w)'\s*([,}])", r':"\1"\2', response)
adminbae64d82013-08-01 10:50:15 -0700532 try :
533 import json
534 response_dict = json.loads(response)
Jon Hall30b82fa2015-03-04 17:15:43 -0800535 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800536 self.log.exception( e )
537 self.log.error("Json Parser is unable to parse the string")
adminbae64d82013-08-01 10:50:15 -0700538 return response_dict
adminbae64d82013-08-01 10:50:15 -0700539 elif ini_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800540 self.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700541 from configobj import ConfigObj
542 response_file = open("respnse_file.temp",'w')
543 response_file.write(response)
Jon Halld61331b2015-02-17 16:35:47 -0800544 response_file.close()
adminbae64d82013-08-01 10:50:15 -0700545 response_dict = ConfigObj("respnse_file.temp")
546 return response_dict
adminbae64d82013-08-01 10:50:15 -0700547 elif xml_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800548 self.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700549 try :
adminbae64d82013-08-01 10:50:15 -0700550 response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
551 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800552 self.log.exception( e )
adminbae64d82013-08-01 10:50:15 -0700553 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700554
adminbae64d82013-08-01 10:50:15 -0700555 def dict_to_return_format(self,response,return_format,response_dict):
adminbae64d82013-08-01 10:50:15 -0700556 if return_format =='table' :
557 ''' Will return in table format'''
558 to_do = "Call the table output formatter"
559 global response_table
560 response_table = '\n'
561 response_table = response_table +'\t'.join(response_dict)+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700562
adminbae64d82013-08-01 10:50:15 -0700563 def get_table(value_to_convert):
564 ''' This will parse the dictionary recusrsively and print as table format'''
565 table_data = ""
566 if type(value_to_convert) == dict :
567 table_data = table_data +'\t'.join(value_to_convert)+"\n"
568 for temp_val in value_to_convert.values() :
569 table_data = table_data + get_table(temp_val)
570 else :
571 table_data = table_data + str(value_to_convert) +"\t"
Jon Halld61331b2015-02-17 16:35:47 -0800572 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700573
adminbae64d82013-08-01 10:50:15 -0700574 for value in response_dict.values() :
575 response_table = response_table + get_table(value)
Jon Hall88e498c2015-03-06 09:54:35 -0800576 # response_table = response_table + '\t'.join(response_dict.values())
adminbae64d82013-08-01 10:50:15 -0700577 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700578
adminbae64d82013-08-01 10:50:15 -0700579 elif return_format =='config':
580 ''' Will return in config format'''
581 to_do = 'Call dict to config coverter'
582 response_string = str(response_dict)
583 print response_string
584 response_config = re.sub(",", "\n\t", response_string)
585 response_config = re.sub("u\'", "\'", response_config)
586 response_config = re.sub("{", "", response_config)
587 response_config = re.sub("}", "\n", response_config)
588 response_config = re.sub(":", " =", response_config)
589 return "[response]\n\t "+response_config
adminbae64d82013-08-01 10:50:15 -0700590 elif return_format == 'xml':
591 ''' Will return in xml format'''
adminbae64d82013-08-01 10:50:15 -0700592 response_xml = xmldict.dict_to_xml(response_dict)
593 response_xml = re.sub(">\s*<", ">\n<", response_xml)
594 return "\n"+response_xml
adminbae64d82013-08-01 10:50:15 -0700595 elif return_format == 'json':
596 ''' Will return in json format'''
597 to_do = 'Call dict to xml coverter'
598 import json
599 response_json = json.dumps(response_dict)
600 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700601
adminbae64d82013-08-01 10:50:15 -0700602 def get_random(self):
603 self.random_order = self.random_order + 1
604 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700605
adminbae64d82013-08-01 10:50:15 -0700606 def exit(self):
607 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700608 for thread in threading.enumerate():
609 if thread.isAlive():
610 try:
611 thread._Thread__stop()
612 except:
613 print(str(thread.getName()) + ' could not be terminated' )
adminbae64d82013-08-01 10:50:15 -0700614 sys.exit()
615
616def verifyOptions(options):
617 '''
618 This will verify the command line options and set to default values, if any option not given in command line.
619 '''
620 import pprint
621 pp = pprint.PrettyPrinter(indent=4)
622
Jon Hall88e498c2015-03-06 09:54:35 -0800623 # pp.pprint(options)
adminbae64d82013-08-01 10:50:15 -0700624 verifyTest(options)
625 verifyExample(options)
626 verifyTestScript(options)
627 verifyParams()
628 verifyLogdir(options)
629 verifyMail(options)
630 verifyTestCases(options)
631
632def verifyTest(options):
633 if options.testname:
634 main.TEST = options.testname
635 main.classPath = "tests."+main.TEST+"."+main.TEST
636 main.tests_path = tests_path
637 elif options.example :
638 main.TEST = options.example
639 main.tests_path = path+"/examples/"
640 main.classPath = "examples."+main.TEST+"."+main.TEST
641 else :
642 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700643 main.exit()
adminbae64d82013-08-01 10:50:15 -0700644
645def verifyExample(options):
646 if options.example:
647 main.testDir = path+'/examples/'
648 main.tests_path = path+"/examples/"
649 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700650
adminbae64d82013-08-01 10:50:15 -0700651def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800652 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700653 if options.logdir:
654 main.logdir = options.logdir
655 else :
Jon Halld61331b2015-02-17 16:35:47 -0800656 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700657
adminbae64d82013-08-01 10:50:15 -0700658def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800659 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700660 if options.mail:
661 main.mail = options.mail
662 elif main.params.has_key('mail'):
663 main.mail = main.params['mail']
664 else :
665 main.mail = 'paxweb@paxterrasolutions.com'
666
667def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800668 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700669 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800670 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800671 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700672 testcases_list = re.sub("(\[|\])", "", options.testcases)
673 main.testcases_list = eval(testcases_list+",")
674 else :
675 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700676 temp = eval(main.params['testcases']+",")
677 list1=[]
678 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800679 for test in temp:
680 for testcase in test:
681 if type(testcase)==int:
682 testcase=[testcase]
683 list1.extend(testcase)
684 else :
685 temp=list(temp)
686 for testcase in temp:
687 if type(testcase)==int:
688 testcase=[testcase]
689 list1.extend(testcase)
690 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700691 else :
692 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800693 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700694
adminbae64d82013-08-01 10:50:15 -0700695def verifyTestScript(options):
696 '''
697 Verifyies test script.
698 '''
Jon Halld61331b2015-02-17 16:35:47 -0800699 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700700 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
701 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
702 if os.path.exists(openspeakfile) :
703 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
704 elif os.path.exists(testfile):
705 print ''
706 else:
707 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
708 __builtin__.testthread = None
709 main.exit()
adminbae64d82013-08-01 10:50:15 -0700710 try :
adminbae64d82013-08-01 10:50:15 -0700711 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
712 except(ImportError):
Jon Hallf8ecf732014-12-02 21:14:16 -0500713 print "There was an import error, it might mean that there is no test like "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800714 main.exit()
adminbae64d82013-08-01 10:50:15 -0700715
716 testClass = getattr(testModule, main.TEST)
717 main.testObject = testClass()
718 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800719 main.params = main.parser.parseParams(main.classPath)
720 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700721
adminbae64d82013-08-01 10:50:15 -0700722def verifyParams():
723 try :
724 main.params = main.params['PARAMS']
725 except(KeyError):
726 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800727 main.exit()
adminbae64d82013-08-01 10:50:15 -0700728 try :
729 main.topology = main.topology['TOPOLOGY']
730 except(KeyError):
731 print "Error with the Topology file: Either the file not specified or the format is not correct"
732 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700733
adminbae64d82013-08-01 10:50:15 -0700734def load_parser() :
735 '''
736 It facilitates the loading customised parser for topology and params file.
737 It loads parser mentioned in tab named parser of teston.cfg file.
738 It also loads default xmlparser if no parser have specified in teston.cfg file.
739
740 '''
741 confighash = main.configDict
742 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
743 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
744 if os.path.exists(confighash['config']['parser']['file']) :
745 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
746 moduleList = module.split("/")
747 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
748 try :
749 parsingClass = confighash['config']['parser']['class']
750 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
751 parsingClass = getattr(parsingModule, parsingClass)
752 main.parser = parsingClass()
753 #hashobj = main.parser.parseParams(main.classPath)
754 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
adminbae64d82013-08-01 10:50:15 -0700755 pass
756 else:
757 main.exit()
adminbae64d82013-08-01 10:50:15 -0700758 except ImportError:
759 print sys.exc_info()[1]
760 main.exit()
761 else :
762 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
Jon Halld61331b2015-02-17 16:35:47 -0800763 load_defaultParser()
764 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
765 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700766 else:
767 load_defaultParser()
768
769def load_defaultParser():
770 '''
771 It will load the default parser which is xml parser to parse the params and topology file.
772 '''
773 moduleList = main.parserPath.split("/")
774 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
775 try :
Jon Halld61331b2015-02-17 16:35:47 -0800776 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700777 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
778 parsingClass = getattr(parsingModule, parsingClass)
779 main.parser = parsingClass()
780 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
781 pass
782 else:
783 main.exit()
784
785 except ImportError:
786 print sys.exc_info()[1]
787
adminbae64d82013-08-01 10:50:15 -0700788def load_logger() :
789 '''
790 It facilitates the loading customised parser for topology and params file.
791 It loads parser mentioned in tab named parser of teston.cfg file.
792 It also loads default xmlparser if no parser have specified in teston.cfg file.
793
794 '''
795 confighash = main.configDict
796 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
797 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
798 if os.path.exists(confighash['config']['logger']['file']) :
799 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
800 moduleList = module.split("/")
801 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
802 try :
803 loggerClass = confighash['config']['logger']['class']
804 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
805 loggerClass = getattr(loggerModule, loggerClass)
806 main.logger = loggerClass()
807 #hashobj = main.parser.parseParams(main.classPath)
808
809 except ImportError:
810 print sys.exc_info()[1]
811 else :
812 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
813 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800814 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
815 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700816 else:
817 load_defaultlogger()
818
819def load_defaultlogger():
820 '''
821 It will load the default parser which is xml parser to parse the params and topology file.
822 '''
823 moduleList = main.loggerPath.split("/")
824 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
825 try :
Jon Halld61331b2015-02-17 16:35:47 -0800826 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700827 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
828 loggerClass = getattr(loggerModule, loggerClass)
829 main.logger = loggerClass()
830
831 except ImportError:
832 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800833 main.exit()
adminbae64d82013-08-01 10:50:15 -0700834
adminbae64d82013-08-01 10:50:15 -0700835def _echo(self):
836 print "THIS IS ECHO"