blob: 8eea8455f8932ff4bc15b4013e899e1480efba9e [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)
Hari Krishna03f530e2015-07-10 17:28:27 -0700616 verifyOnosCell(options)
adminbae64d82013-08-01 10:50:15 -0700617
618def verifyTest(options):
619 if options.testname:
620 main.TEST = options.testname
621 main.classPath = "tests."+main.TEST+"."+main.TEST
622 main.tests_path = tests_path
623 elif options.example :
624 main.TEST = options.example
625 main.tests_path = path+"/examples/"
626 main.classPath = "examples."+main.TEST+"."+main.TEST
627 else :
628 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700629 main.exit()
adminbae64d82013-08-01 10:50:15 -0700630
631def verifyExample(options):
632 if options.example:
633 main.testDir = path+'/examples/'
634 main.tests_path = path+"/examples/"
635 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700636
adminbae64d82013-08-01 10:50:15 -0700637def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800638 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700639 if options.logdir:
640 main.logdir = options.logdir
641 else :
Jon Halld61331b2015-02-17 16:35:47 -0800642 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700643
adminbae64d82013-08-01 10:50:15 -0700644def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800645 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700646 if options.mail:
647 main.mail = options.mail
648 elif main.params.has_key('mail'):
649 main.mail = main.params['mail']
650 else :
651 main.mail = 'paxweb@paxterrasolutions.com'
652
653def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800654 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700655 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800656 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800657 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700658 testcases_list = re.sub("(\[|\])", "", options.testcases)
659 main.testcases_list = eval(testcases_list+",")
660 else :
661 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700662 temp = eval(main.params['testcases']+",")
663 list1=[]
664 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800665 for test in temp:
666 for testcase in test:
667 if type(testcase)==int:
668 testcase=[testcase]
669 list1.extend(testcase)
670 else :
671 temp=list(temp)
672 for testcase in temp:
673 if type(testcase)==int:
674 testcase=[testcase]
675 list1.extend(testcase)
676 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700677 else :
678 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800679 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700680
Hari Krishna03f530e2015-07-10 17:28:27 -0700681def verifyOnosCell(options):
682 # Verifying onoscell option. This could be extended to do even more from here.
683 if options.onoscell:
684 main.onoscell = options.onoscell
685 else :
686 main.onoscell = main.FALSE
687
adminbae64d82013-08-01 10:50:15 -0700688def verifyTestScript(options):
689 '''
690 Verifyies test script.
691 '''
Jon Halld61331b2015-02-17 16:35:47 -0800692 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700693 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
694 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
695 if os.path.exists(openspeakfile) :
696 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
697 elif os.path.exists(testfile):
698 print ''
699 else:
700 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
701 __builtin__.testthread = None
702 main.exit()
adminbae64d82013-08-01 10:50:15 -0700703 try :
adminbae64d82013-08-01 10:50:15 -0700704 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
705 except(ImportError):
Jon Hallf8ecf732014-12-02 21:14:16 -0500706 print "There was an import error, it might mean that there is no test like "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800707 main.exit()
adminbae64d82013-08-01 10:50:15 -0700708
709 testClass = getattr(testModule, main.TEST)
710 main.testObject = testClass()
711 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800712 main.params = main.parser.parseParams(main.classPath)
713 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700714
adminbae64d82013-08-01 10:50:15 -0700715def verifyParams():
716 try :
717 main.params = main.params['PARAMS']
718 except(KeyError):
719 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800720 main.exit()
adminbae64d82013-08-01 10:50:15 -0700721 try :
722 main.topology = main.topology['TOPOLOGY']
723 except(KeyError):
724 print "Error with the Topology file: Either the file not specified or the format is not correct"
725 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700726
adminbae64d82013-08-01 10:50:15 -0700727def load_parser() :
728 '''
729 It facilitates the loading customised parser for topology and params file.
730 It loads parser mentioned in tab named parser of teston.cfg file.
731 It also loads default xmlparser if no parser have specified in teston.cfg file.
732
733 '''
734 confighash = main.configDict
735 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
736 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
737 if os.path.exists(confighash['config']['parser']['file']) :
738 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
739 moduleList = module.split("/")
740 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
741 try :
742 parsingClass = confighash['config']['parser']['class']
743 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
744 parsingClass = getattr(parsingModule, parsingClass)
745 main.parser = parsingClass()
746 #hashobj = main.parser.parseParams(main.classPath)
747 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
adminbae64d82013-08-01 10:50:15 -0700748 pass
749 else:
750 main.exit()
adminbae64d82013-08-01 10:50:15 -0700751 except ImportError:
752 print sys.exc_info()[1]
753 main.exit()
754 else :
755 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
Jon Halld61331b2015-02-17 16:35:47 -0800756 load_defaultParser()
757 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
758 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700759 else:
760 load_defaultParser()
761
762def load_defaultParser():
763 '''
764 It will load the default parser which is xml parser to parse the params and topology file.
765 '''
766 moduleList = main.parserPath.split("/")
767 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
768 try :
Jon Halld61331b2015-02-17 16:35:47 -0800769 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700770 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
771 parsingClass = getattr(parsingModule, parsingClass)
772 main.parser = parsingClass()
773 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
774 pass
775 else:
776 main.exit()
777
778 except ImportError:
779 print sys.exc_info()[1]
780
adminbae64d82013-08-01 10:50:15 -0700781def load_logger() :
782 '''
783 It facilitates the loading customised parser for topology and params file.
784 It loads parser mentioned in tab named parser of teston.cfg file.
785 It also loads default xmlparser if no parser have specified in teston.cfg file.
786
787 '''
788 confighash = main.configDict
789 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
790 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
791 if os.path.exists(confighash['config']['logger']['file']) :
792 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
793 moduleList = module.split("/")
794 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
795 try :
796 loggerClass = confighash['config']['logger']['class']
797 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
798 loggerClass = getattr(loggerModule, loggerClass)
799 main.logger = loggerClass()
800 #hashobj = main.parser.parseParams(main.classPath)
801
802 except ImportError:
803 print sys.exc_info()[1]
804 else :
805 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
806 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800807 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
808 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700809 else:
810 load_defaultlogger()
811
812def load_defaultlogger():
813 '''
814 It will load the default parser which is xml parser to parse the params and topology file.
815 '''
816 moduleList = main.loggerPath.split("/")
817 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
818 try :
Jon Halld61331b2015-02-17 16:35:47 -0800819 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700820 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
821 loggerClass = getattr(loggerModule, loggerClass)
822 main.logger = loggerClass()
823
824 except ImportError:
825 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800826 main.exit()
adminbae64d82013-08-01 10:50:15 -0700827
adminbae64d82013-08-01 10:50:15 -0700828def _echo(self):
829 print "THIS IS ECHO"