blob: 657e65933d0a32372340246679683b7ebb0ca4b6 [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
kelvin-onlab0a28a742015-05-18 16:03:13 -0700168 try:
169 self.componentDictionary[component]['host'] = os.environ[str( self.componentDictionary[component]['host'])]
170 except KeyError:
171 self.log.info("Missing OC environment variable! Using stored IPs")
172 except Exception as inst:
173 self.log.error("Uncaught exception: " + str(inst))
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700174
adminbae64d82013-08-01 10:50:15 -0700175 connect_result = driverObject.connect(user_name = self.componentDictionary[component]['user'] if ('user' in self.componentDictionary[component].keys()) else getpass.getuser(),
176 ip_address= self.componentDictionary[component]['host'] if ('host' in self.componentDictionary[component].keys()) else 'localhost',
177 pwd = self.componentDictionary[component]['password'] if ('password' in self.componentDictionary[component].keys()) else 'changeme',
178 port = self.componentDictionary[component]['port'] if ('port' in self.componentDictionary[component].keys()) else None,
179 options = driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700180
adminbae64d82013-08-01 10:50:15 -0700181 if not connect_result:
182 self.log.error("Exiting form the test execution because the connecting to the "+component+" component failed.")
Jon Halld61331b2015-02-17 16:35:47 -0800183 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700184
adminbae64d82013-08-01 10:50:15 -0700185 vars(self)[component] = driverObject
kelvin-onlabf70fd542015-05-07 18:41:40 -0700186
adminbae64d82013-08-01 10:50:15 -0700187 def run(self):
188 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700189 The Execution of the test script's cases listed in the Test params file will be done here.
190 And Update each test case result.
191 This method will return TRUE if it executed all the test cases successfully,
adminbae64d82013-08-01 10:50:15 -0700192 else will retun FALSE
193 '''
adminbae64d82013-08-01 10:50:15 -0700194 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700195 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700196 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800197 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700198 self.TOTAL_TC_NORESULT = 0
199 self.TOTAL_TC_FAIL = 0
200 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700201 self.TEST_ITERATION = 0
adminbae64d82013-08-01 10:50:15 -0700202 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700203 self.CASERESULT = self.NORESULT
204
Jon Halld61331b2015-02-17 16:35:47 -0800205 import testparser
adminbae64d82013-08-01 10:50:15 -0700206 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
207 test = testparser.TestParser(testFile)
208 self.testscript = test.testscript
209 self.code = test.getStepCode()
Jon Hallfebb1c72015-03-05 13:30:09 -0800210 repeat= int(self.params['repeat']) if ('repeat' in self.params) else 1
211 self.TOTAL_TC_PLANNED = len(self.testcases_list)*repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700212
adminbae64d82013-08-01 10:50:15 -0700213 result = self.TRUE
Jon Hallfebb1c72015-03-05 13:30:09 -0800214 while(repeat):
Jon Halla1185982014-09-15 14:55:10 -0700215 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Halld61331b2015-02-17 16:35:47 -0800216 result = self.runCase(self.CurrentTestCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800217 repeat-=1
adminbae64d82013-08-01 10:50:15 -0700218 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700219
adminbae64d82013-08-01 10:50:15 -0700220 def runCase(self,testCaseNumber):
221 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700222 self.CurrentTestCase = ""
223 self.stepResults = []
224 self.stepName = ""
225 self.caseExplaination = ""
adminbae64d82013-08-01 10:50:15 -0700226 result = self.TRUE
227 self.stepCount = 0
228 self.EXPERIMENTAL_MODE = self.FALSE
229 self.addCaseHeader()
230 self.testCaseNumber = str(testCaseNumber)
231 stopped = False
232 try :
233 self.stepList = self.code[self.testCaseNumber].keys()
Jon Halld61331b2015-02-17 16:35:47 -0800234 except KeyError:
Jon Hallfebb1c72015-03-05 13:30:09 -0800235 self.log.error("There is no Test-Case "+ self.testCaseNumber)
236 return self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700237
adminbae64d82013-08-01 10:50:15 -0700238 self.stepCount = 0
239 while self.stepCount < len(self.code[self.testCaseNumber].keys()):
240 result = self.runStep(self.stepList,self.code,self.testCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800241 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700242 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800243 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700244 continue
adminbae64d82013-08-01 10:50:15 -0700245 if not stopped :
kelvin-onlabf70fd542015-05-07 18:41:40 -0700246 if all( self.TRUE == i for i in self.stepResults ):
247 # ALL PASSED
248 self.CASERESULT = self.TRUE
249 elif self.FALSE in self.stepResults:
250 # AT LEAST ONE FAILED
251 self.CASERESULT = self.FALSE
252 elif self.TRUE in self.stepResults:
253 # AT LEAST ONE PASSED
254 self.CASERESULT = self.TRUE
255 else:
256 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700257 self.testCaseResult[str(self.CurrentTestCaseNumber)] = self.CASERESULT
258 self.logger.updateCaseResults(self)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700259 self.log.wiki( "<p>" + self.caseExplaination + "</p>" )
260 self.log.summary( self.caseExplaination )
261 self.log.wiki( "<ul>" )
262 for line in self.stepCache.splitlines():
263 if re.search( " - PASS$", line ):
264 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
265 elif re.search( " - FAIL$", line ):
266 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
267 elif re.search( " - No Result$", line ):
268 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700269 else: # Should only be on fail message
270 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700271 self.log.wiki( "</ul>" )
272 self.log.summary( self.stepCache )
273 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700274 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700275
adminbae64d82013-08-01 10:50:15 -0700276 def runStep(self,stepList,code,testCaseNumber):
277 if not cli.pause:
278 try :
279 step = stepList[self.stepCount]
kelvin-onlabf70fd542015-05-07 18:41:40 -0700280 self.STEPRESULT = self.NORESULT
Jon Hall90627612015-06-09 14:57:02 -0700281 self.onFailMsg = "\t\tNo on fail message given"
adminbae64d82013-08-01 10:50:15 -0700282 exec code[testCaseNumber][step] in module.__dict__
283 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700284 if step > 0:
285 self.stepCache += "\t"+str(testCaseNumber)+"."+str(step)+" "+self.stepName+" - "
286 if self.STEPRESULT == self.TRUE:
287 self.stepCache += "PASS\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700288 elif self.STEPRESULT == self.FALSE:
289 self.stepCache += "FAIL\n"
Jon Hall8ce34e82015-06-05 10:41:45 -0700290 # TODO: Print the on-fail statement here
Jon Hall90627612015-06-09 14:57:02 -0700291 self.stepCache += "\t\t" + self.onFailMsg + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700292 else:
293 self.stepCache += "No Result\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700294 self.stepResults.append(self.STEPRESULT)
Jon Hall5b586732015-06-11 11:39:39 -0700295 except StandardError:
Jon Hall40d2cbd2015-06-03 16:24:29 -0700296 self.log.exception( "\nException in the following section of" +
297 " code: " + str(testCaseNumber) + "." +
298 str(step) + ": " + self.stepName )
Jon Hall63604932015-02-26 17:09:50 -0800299 #print code[testCaseNumber][step]
adminbae64d82013-08-01 10:50:15 -0700300 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700301 self.logger.updateCaseResults(self)
302 #WIKI results
303 self.log.wiki( "<ul>" )
304 for line in self.stepCache.splitlines():
305 if re.search( " - PASS$", line ):
306 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
307 elif re.search( " - FAIL$", line ):
308 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
309 elif re.search( " - No Result$", line ):
310 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700311 else: # Should only be on fail message
312 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700313 self.log.wiki( "</ul>" )
314 #summary results
315 self.log.summary( self.stepCache )
316 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700317 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700318 self.exit()
adminbae64d82013-08-01 10:50:15 -0700319 return main.TRUE
adminbae64d82013-08-01 10:50:15 -0700320 if cli.stop:
321 cli.stop = False
322 stopped = True
323 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
324 self.testCaseResult[str(self.CurrentTestCaseNumber)] = "Stopped"
325 self.logger.updateCaseResults(self)
326 result = self.cleanup()
327 return main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700328
adminbae64d82013-08-01 10:50:15 -0700329 def addCaseHeader(self):
330 caseHeader = "\n"+"*" * 30+"\n Result summary for Testcase"+str(self.CurrentTestCaseNumber)+"\n"+"*" * 30+"\n"
Jon Halld61331b2015-02-17 16:35:47 -0800331 self.log.exact(caseHeader)
332 caseHeader = "\n"+"*" * 40 +"\nStart of Test Case"+str(self.CurrentTestCaseNumber)+" : "
adminbae64d82013-08-01 10:50:15 -0700333 for driver in self.componentDictionary.keys():
334 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700335
adminbae64d82013-08-01 10:50:15 -0700336 def addCaseFooter(self):
337 if self.stepCount-1 > 0 :
338 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
339 stepHeader = "\n"+"*" * 40+"\nEnd of Step "+previousStep+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700340
adminbae64d82013-08-01 10:50:15 -0700341 caseFooter = "\n"+"*" * 40+"\nEnd of Test case "+str(self.CurrentTestCaseNumber)+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700342
adminbae64d82013-08-01 10:50:15 -0700343 for driver in self.driversList:
344 vars(self)[driver].write(stepHeader+"\n"+caseFooter)
345
346 def cleanup(self):
347 '''
Jon Hall5b586732015-06-11 11:39:39 -0700348 Print a summary of the current test's results then attempt to release
349 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700350
Jon Hall5b586732015-06-11 11:39:39 -0700351 This function shouldbe threadsafe such that cleanup will only be
352 executed once per test.
353
354 This will return TRUE if all the component handles and log handles
355 closed properly, else return FALSE.
adminbae64d82013-08-01 10:50:15 -0700356 '''
357 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700358 lock = self.cleanupLock
359 if lock.acquire( False ):
360 try:
361 if self.cleanupFlag is False: # First thread to run this
362 self.cleanupFlag = True
363 self.logger.testSummary(self)
364 for component in self.componentDictionary.keys():
365 try :
366 tempObject = vars(self)[component]
367 print "Disconnecting from " + str(tempObject.name) + ": " + \
368 str(tempObject)
369 tempObject.disconnect()
370 except Exception:
371 self.log.exception( "Exception while disconnecting from " +
372 str( component ) )
373 result = self.FALSE
374 # Closing all the driver's session files
375 for driver in self.componentDictionary.keys():
376 try:
377 vars(self)[driver].close_log_handles()
378 except Exception:
379 self.log.exception( "Exception while closing log files for " +
380 str( driver ) )
381 result = self.FALSE
382 else:
383 pass # Someone else already ran through this function
384 finally:
385 lock.release()
386 else: # Someone already has a lock
387 # NOTE: This could cause problems if we don't release the lock
388 # correctly
389 lock.acquire() # Wait for the other thread to finish
390 # NOTE: If we don't wait, exit could be called while the thread
391 # with the lock is still cleaning up
392 lock.release()
adminbae64d82013-08-01 10:50:15 -0700393 return result
Jon Halld61331b2015-02-17 16:35:47 -0800394
adminbae64d82013-08-01 10:50:15 -0700395 def pause(self):
396 '''
397 This function will pause the test's execution, and will continue after user provide 'resume' command.
398 '''
399 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700400
adminbae64d82013-08-01 10:50:15 -0700401 def onfail(self,*components):
402 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700403 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700404 '''
adminbae64d82013-08-01 10:50:15 -0700405 if not components:
406 try :
407 for component in self.componentDictionary.keys():
408 tempObject = vars(self)[component]
409 result = tempObject.onfail()
410 except(Exception),e:
411 print str(e)
412 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700413 else:
414 try :
415 for component in components:
416 tempObject = vars(self)[component]
417 result = tempObject.onfail()
418 except(Exception),e:
419 print str(e)
420 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700421
adminbae64d82013-08-01 10:50:15 -0700422 def getDriverPath(self,driverName):
423 '''
424 Based on the component 'type' specified in the params , this method will find the absolute path ,
425 by recursively searching the name of the component.
426 '''
427 import commands
428
429 cmd = "find "+drivers_path+" -name "+driverName+".py"
430 result = commands.getoutput(cmd)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700431
adminbae64d82013-08-01 10:50:15 -0700432 result_array = str(result).split('\n')
433 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700434
adminbae64d82013-08-01 10:50:15 -0700435 for drivers_list in result_array:
436 result_count = result_count+1
437 if result_count > 1 :
438 print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
439 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700440
adminbae64d82013-08-01 10:50:15 -0700441 result = re.sub("(.*)drivers","",result)
442 result = re.sub("\.py","",result)
443 result = re.sub("\.pyc","",result)
444 result = re.sub("\/",".",result)
445 result = "drivers"+result
446 return result
adminbae64d82013-08-01 10:50:15 -0700447
448 def step(self,stepDesc):
449 '''
450 The step information of the test-case will append to the logs.
451 '''
452 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
453 self.stepName = stepDesc
454
455 stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
456 try :
457 if self.stepCount == 0:
458 stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
459 except AttributeError:
460 stepName = " INIT : Initializing the test case :"+str(self.CurrentTestCaseNumber)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700461
adminbae64d82013-08-01 10:50:15 -0700462 self.log.step(stepName)
463 stepHeader = ""
464 if self.stepCount > 1 :
465 stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700466
Jon Halld61331b2015-02-17 16:35:47 -0800467 stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
adminbae64d82013-08-01 10:50:15 -0700468 for driver in self.componentDictionary.keys():
469 vars(self)[driver+'log'].info(stepHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700470
adminbae64d82013-08-01 10:50:15 -0700471 def case(self,testCaseName):
472 '''
473 Test's each test-case information will append to the logs.
474 '''
Jon Halld61331b2015-02-17 16:35:47 -0800475 self.CurrentTestCase = testCaseName
adminbae64d82013-08-01 10:50:15 -0700476 testCaseName = " " + str(testCaseName) + ""
477 self.log.case(testCaseName)
Jon Halld61331b2015-02-17 16:35:47 -0800478 caseHeader = testCaseName+"\n"+"*" * 40+"\n"
adminbae64d82013-08-01 10:50:15 -0700479 for driver in self.componentDictionary.keys():
480 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700481
adminbae64d82013-08-01 10:50:15 -0700482 def testDesc(self,description):
483 '''
484 Test description will append to the logs.
485 '''
486 description = "Test Description : " + str (description) + ""
487 self.log.info(description)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700488
adminbae64d82013-08-01 10:50:15 -0700489 def _getTest(self):
490 '''
491 This method will parse the test script to find required test information.
492 '''
493 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
494 testFileHandler = open(testFile, 'r')
495 testFileList = testFileHandler.readlines()
496 testFileHandler.close()
497 #self.TOTAL_TC_PLANNED = 0
498 counter = 0
499 for index in range(len(testFileList)):
500 lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
501 if lineMatch:
502 counter = counter + 1
Jon Halla1185982014-09-15 14:55:10 -0700503 self.TC_PLANNED = len(self.testcases_list)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700504
adminbae64d82013-08-01 10:50:15 -0700505 def response_parser(self,response, return_format):
506 ''' It will load the default response parser '''
507 response_dict = {}
508 response_dict = self.response_to_dict(response, return_format)
Jon Halld61331b2015-02-17 16:35:47 -0800509 return_format_string = self.dict_to_return_format(response,return_format,response_dict)
adminbae64d82013-08-01 10:50:15 -0700510 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700511
adminbae64d82013-08-01 10:50:15 -0700512 def response_to_dict(self,response,return_format):
adminbae64d82013-08-01 10:50:15 -0700513 response_dict = {}
514 json_match = re.search('^\s*{', response)
515 xml_match = re.search('^\s*\<', response)
516 ini_match = re.search('^\s*\[', response)
517 if json_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800518 self.log.info(" Response is in 'JSON' format and Converting to '"+return_format+"' format")
Jon Halld61331b2015-02-17 16:35:47 -0800519 # Formatting the json string
adminbae64d82013-08-01 10:50:15 -0700520 response = re.sub(r"{\s*'?(\w)", r'{"\1', response)
521 response = re.sub(r",\s*'?(\w)", r',"\1', response)
522 response = re.sub(r"(\w)'?\s*:", r'\1":', response)
523 response = re.sub(r":\s*'(\w)'\s*([,}])", r':"\1"\2', response)
adminbae64d82013-08-01 10:50:15 -0700524 try :
525 import json
526 response_dict = json.loads(response)
Jon Hall30b82fa2015-03-04 17:15:43 -0800527 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800528 self.log.exception( e )
529 self.log.error("Json Parser is unable to parse the string")
adminbae64d82013-08-01 10:50:15 -0700530 return response_dict
adminbae64d82013-08-01 10:50:15 -0700531 elif ini_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800532 self.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700533 from configobj import ConfigObj
534 response_file = open("respnse_file.temp",'w')
535 response_file.write(response)
Jon Halld61331b2015-02-17 16:35:47 -0800536 response_file.close()
adminbae64d82013-08-01 10:50:15 -0700537 response_dict = ConfigObj("respnse_file.temp")
538 return response_dict
adminbae64d82013-08-01 10:50:15 -0700539 elif xml_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800540 self.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700541 try :
adminbae64d82013-08-01 10:50:15 -0700542 response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
543 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800544 self.log.exception( e )
adminbae64d82013-08-01 10:50:15 -0700545 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700546
adminbae64d82013-08-01 10:50:15 -0700547 def dict_to_return_format(self,response,return_format,response_dict):
adminbae64d82013-08-01 10:50:15 -0700548 if return_format =='table' :
549 ''' Will return in table format'''
550 to_do = "Call the table output formatter"
551 global response_table
552 response_table = '\n'
553 response_table = response_table +'\t'.join(response_dict)+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700554
adminbae64d82013-08-01 10:50:15 -0700555 def get_table(value_to_convert):
556 ''' This will parse the dictionary recusrsively and print as table format'''
557 table_data = ""
558 if type(value_to_convert) == dict :
559 table_data = table_data +'\t'.join(value_to_convert)+"\n"
560 for temp_val in value_to_convert.values() :
561 table_data = table_data + get_table(temp_val)
562 else :
563 table_data = table_data + str(value_to_convert) +"\t"
Jon Halld61331b2015-02-17 16:35:47 -0800564 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700565
adminbae64d82013-08-01 10:50:15 -0700566 for value in response_dict.values() :
567 response_table = response_table + get_table(value)
Jon Hall88e498c2015-03-06 09:54:35 -0800568 # response_table = response_table + '\t'.join(response_dict.values())
adminbae64d82013-08-01 10:50:15 -0700569 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700570
adminbae64d82013-08-01 10:50:15 -0700571 elif return_format =='config':
572 ''' Will return in config format'''
573 to_do = 'Call dict to config coverter'
574 response_string = str(response_dict)
575 print response_string
576 response_config = re.sub(",", "\n\t", response_string)
577 response_config = re.sub("u\'", "\'", response_config)
578 response_config = re.sub("{", "", response_config)
579 response_config = re.sub("}", "\n", response_config)
580 response_config = re.sub(":", " =", response_config)
581 return "[response]\n\t "+response_config
adminbae64d82013-08-01 10:50:15 -0700582 elif return_format == 'xml':
583 ''' Will return in xml format'''
adminbae64d82013-08-01 10:50:15 -0700584 response_xml = xmldict.dict_to_xml(response_dict)
585 response_xml = re.sub(">\s*<", ">\n<", response_xml)
586 return "\n"+response_xml
adminbae64d82013-08-01 10:50:15 -0700587 elif return_format == 'json':
588 ''' Will return in json format'''
589 to_do = 'Call dict to xml coverter'
590 import json
591 response_json = json.dumps(response_dict)
592 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700593
adminbae64d82013-08-01 10:50:15 -0700594 def get_random(self):
595 self.random_order = self.random_order + 1
596 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700597
adminbae64d82013-08-01 10:50:15 -0700598 def exit(self):
599 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700600 for thread in threading.enumerate():
601 if thread.isAlive():
602 try:
603 thread._Thread__stop()
604 except:
605 print(str(thread.getName()) + ' could not be terminated' )
adminbae64d82013-08-01 10:50:15 -0700606 sys.exit()
607
608def verifyOptions(options):
609 '''
610 This will verify the command line options and set to default values, if any option not given in command line.
611 '''
612 import pprint
613 pp = pprint.PrettyPrinter(indent=4)
614
Jon Hall88e498c2015-03-06 09:54:35 -0800615 # pp.pprint(options)
adminbae64d82013-08-01 10:50:15 -0700616 verifyTest(options)
617 verifyExample(options)
618 verifyTestScript(options)
619 verifyParams()
620 verifyLogdir(options)
621 verifyMail(options)
622 verifyTestCases(options)
623
624def verifyTest(options):
625 if options.testname:
626 main.TEST = options.testname
627 main.classPath = "tests."+main.TEST+"."+main.TEST
628 main.tests_path = tests_path
629 elif options.example :
630 main.TEST = options.example
631 main.tests_path = path+"/examples/"
632 main.classPath = "examples."+main.TEST+"."+main.TEST
633 else :
634 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700635 main.exit()
adminbae64d82013-08-01 10:50:15 -0700636
637def verifyExample(options):
638 if options.example:
639 main.testDir = path+'/examples/'
640 main.tests_path = path+"/examples/"
641 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700642
adminbae64d82013-08-01 10:50:15 -0700643def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800644 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700645 if options.logdir:
646 main.logdir = options.logdir
647 else :
Jon Halld61331b2015-02-17 16:35:47 -0800648 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700649
adminbae64d82013-08-01 10:50:15 -0700650def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800651 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700652 if options.mail:
653 main.mail = options.mail
654 elif main.params.has_key('mail'):
655 main.mail = main.params['mail']
656 else :
657 main.mail = 'paxweb@paxterrasolutions.com'
658
659def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800660 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700661 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800662 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800663 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700664 testcases_list = re.sub("(\[|\])", "", options.testcases)
665 main.testcases_list = eval(testcases_list+",")
666 else :
667 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700668 temp = eval(main.params['testcases']+",")
669 list1=[]
670 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800671 for test in temp:
672 for testcase in test:
673 if type(testcase)==int:
674 testcase=[testcase]
675 list1.extend(testcase)
676 else :
677 temp=list(temp)
678 for testcase in temp:
679 if type(testcase)==int:
680 testcase=[testcase]
681 list1.extend(testcase)
682 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700683 else :
684 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800685 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700686
adminbae64d82013-08-01 10:50:15 -0700687def verifyTestScript(options):
688 '''
689 Verifyies test script.
690 '''
Jon Halld61331b2015-02-17 16:35:47 -0800691 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700692 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
693 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
694 if os.path.exists(openspeakfile) :
695 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
696 elif os.path.exists(testfile):
697 print ''
698 else:
699 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
700 __builtin__.testthread = None
701 main.exit()
adminbae64d82013-08-01 10:50:15 -0700702 try :
adminbae64d82013-08-01 10:50:15 -0700703 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
704 except(ImportError):
Jon Hallf8ecf732014-12-02 21:14:16 -0500705 print "There was an import error, it might mean that there is no test like "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800706 main.exit()
adminbae64d82013-08-01 10:50:15 -0700707
708 testClass = getattr(testModule, main.TEST)
709 main.testObject = testClass()
710 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800711 main.params = main.parser.parseParams(main.classPath)
712 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700713
adminbae64d82013-08-01 10:50:15 -0700714def verifyParams():
715 try :
716 main.params = main.params['PARAMS']
717 except(KeyError):
718 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800719 main.exit()
adminbae64d82013-08-01 10:50:15 -0700720 try :
721 main.topology = main.topology['TOPOLOGY']
722 except(KeyError):
723 print "Error with the Topology file: Either the file not specified or the format is not correct"
724 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700725
adminbae64d82013-08-01 10:50:15 -0700726def load_parser() :
727 '''
728 It facilitates the loading customised parser for topology and params file.
729 It loads parser mentioned in tab named parser of teston.cfg file.
730 It also loads default xmlparser if no parser have specified in teston.cfg file.
731
732 '''
733 confighash = main.configDict
734 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
735 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
736 if os.path.exists(confighash['config']['parser']['file']) :
737 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
738 moduleList = module.split("/")
739 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
740 try :
741 parsingClass = confighash['config']['parser']['class']
742 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
743 parsingClass = getattr(parsingModule, parsingClass)
744 main.parser = parsingClass()
745 #hashobj = main.parser.parseParams(main.classPath)
746 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
adminbae64d82013-08-01 10:50:15 -0700747 pass
748 else:
749 main.exit()
adminbae64d82013-08-01 10:50:15 -0700750 except ImportError:
751 print sys.exc_info()[1]
752 main.exit()
753 else :
754 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
Jon Halld61331b2015-02-17 16:35:47 -0800755 load_defaultParser()
756 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
757 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700758 else:
759 load_defaultParser()
760
761def load_defaultParser():
762 '''
763 It will load the default parser which is xml parser to parse the params and topology file.
764 '''
765 moduleList = main.parserPath.split("/")
766 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
767 try :
Jon Halld61331b2015-02-17 16:35:47 -0800768 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700769 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
770 parsingClass = getattr(parsingModule, parsingClass)
771 main.parser = parsingClass()
772 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
773 pass
774 else:
775 main.exit()
776
777 except ImportError:
778 print sys.exc_info()[1]
779
adminbae64d82013-08-01 10:50:15 -0700780def load_logger() :
781 '''
782 It facilitates the loading customised parser for topology and params file.
783 It loads parser mentioned in tab named parser of teston.cfg file.
784 It also loads default xmlparser if no parser have specified in teston.cfg file.
785
786 '''
787 confighash = main.configDict
788 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
789 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
790 if os.path.exists(confighash['config']['logger']['file']) :
791 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
792 moduleList = module.split("/")
793 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
794 try :
795 loggerClass = confighash['config']['logger']['class']
796 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
797 loggerClass = getattr(loggerModule, loggerClass)
798 main.logger = loggerClass()
799 #hashobj = main.parser.parseParams(main.classPath)
800
801 except ImportError:
802 print sys.exc_info()[1]
803 else :
804 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
805 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800806 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
807 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700808 else:
809 load_defaultlogger()
810
811def load_defaultlogger():
812 '''
813 It will load the default parser which is xml parser to parse the params and topology file.
814 '''
815 moduleList = main.loggerPath.split("/")
816 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
817 try :
Jon Halld61331b2015-02-17 16:35:47 -0800818 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700819 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
820 loggerClass = getattr(loggerModule, loggerClass)
821 main.logger = loggerClass()
822
823 except ImportError:
824 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800825 main.exit()
adminbae64d82013-08-01 10:50:15 -0700826
adminbae64d82013-08-01 10:50:15 -0700827def _echo(self):
828 print "THIS IS ECHO"