blob: ff973edb8bf6b27515da7ff1a023f17ecd5e680a [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)
Hari Krishna03f530e2015-07-10 17:28:27 -0700631 verifyOnosCell(options)
adminbae64d82013-08-01 10:50:15 -0700632
633def verifyTest(options):
634 if options.testname:
635 main.TEST = options.testname
636 main.classPath = "tests."+main.TEST+"."+main.TEST
637 main.tests_path = tests_path
638 elif options.example :
639 main.TEST = options.example
640 main.tests_path = path+"/examples/"
641 main.classPath = "examples."+main.TEST+"."+main.TEST
642 else :
643 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700644 main.exit()
adminbae64d82013-08-01 10:50:15 -0700645
646def verifyExample(options):
647 if options.example:
648 main.testDir = path+'/examples/'
649 main.tests_path = path+"/examples/"
650 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700651
adminbae64d82013-08-01 10:50:15 -0700652def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800653 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700654 if options.logdir:
655 main.logdir = options.logdir
656 else :
Jon Halld61331b2015-02-17 16:35:47 -0800657 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700658
adminbae64d82013-08-01 10:50:15 -0700659def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800660 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700661 if options.mail:
662 main.mail = options.mail
663 elif main.params.has_key('mail'):
664 main.mail = main.params['mail']
665 else :
666 main.mail = 'paxweb@paxterrasolutions.com'
667
668def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800669 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700670 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800671 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800672 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700673 testcases_list = re.sub("(\[|\])", "", options.testcases)
674 main.testcases_list = eval(testcases_list+",")
675 else :
676 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700677 temp = eval(main.params['testcases']+",")
678 list1=[]
679 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800680 for test in temp:
681 for testcase in test:
682 if type(testcase)==int:
683 testcase=[testcase]
684 list1.extend(testcase)
685 else :
686 temp=list(temp)
687 for testcase in temp:
688 if type(testcase)==int:
689 testcase=[testcase]
690 list1.extend(testcase)
691 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700692 else :
693 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800694 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700695
Hari Krishna03f530e2015-07-10 17:28:27 -0700696def verifyOnosCell(options):
697 # Verifying onoscell option. This could be extended to do even more from here.
698 if options.onoscell:
699 main.onoscell = options.onoscell
700 else :
701 main.onoscell = main.FALSE
702
adminbae64d82013-08-01 10:50:15 -0700703def verifyTestScript(options):
704 '''
705 Verifyies test script.
706 '''
Jon Halld61331b2015-02-17 16:35:47 -0800707 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700708 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
709 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
710 if os.path.exists(openspeakfile) :
711 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
712 elif os.path.exists(testfile):
713 print ''
714 else:
715 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
716 __builtin__.testthread = None
717 main.exit()
adminbae64d82013-08-01 10:50:15 -0700718 try :
adminbae64d82013-08-01 10:50:15 -0700719 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
720 except(ImportError):
Jon Hallf8ecf732014-12-02 21:14:16 -0500721 print "There was an import error, it might mean that there is no test like "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800722 main.exit()
adminbae64d82013-08-01 10:50:15 -0700723
724 testClass = getattr(testModule, main.TEST)
725 main.testObject = testClass()
726 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800727 main.params = main.parser.parseParams(main.classPath)
728 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700729
adminbae64d82013-08-01 10:50:15 -0700730def verifyParams():
731 try :
732 main.params = main.params['PARAMS']
733 except(KeyError):
734 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800735 main.exit()
adminbae64d82013-08-01 10:50:15 -0700736 try :
737 main.topology = main.topology['TOPOLOGY']
738 except(KeyError):
739 print "Error with the Topology file: Either the file not specified or the format is not correct"
740 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700741
adminbae64d82013-08-01 10:50:15 -0700742def load_parser() :
743 '''
744 It facilitates the loading customised parser for topology and params file.
745 It loads parser mentioned in tab named parser of teston.cfg file.
746 It also loads default xmlparser if no parser have specified in teston.cfg file.
747
748 '''
749 confighash = main.configDict
750 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
751 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
752 if os.path.exists(confighash['config']['parser']['file']) :
753 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
754 moduleList = module.split("/")
755 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
756 try :
757 parsingClass = confighash['config']['parser']['class']
758 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
759 parsingClass = getattr(parsingModule, parsingClass)
760 main.parser = parsingClass()
761 #hashobj = main.parser.parseParams(main.classPath)
762 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
adminbae64d82013-08-01 10:50:15 -0700763 pass
764 else:
765 main.exit()
adminbae64d82013-08-01 10:50:15 -0700766 except ImportError:
767 print sys.exc_info()[1]
768 main.exit()
769 else :
770 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
Jon Halld61331b2015-02-17 16:35:47 -0800771 load_defaultParser()
772 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
773 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700774 else:
775 load_defaultParser()
776
777def load_defaultParser():
778 '''
779 It will load the default parser which is xml parser to parse the params and topology file.
780 '''
781 moduleList = main.parserPath.split("/")
782 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
783 try :
Jon Halld61331b2015-02-17 16:35:47 -0800784 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700785 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
786 parsingClass = getattr(parsingModule, parsingClass)
787 main.parser = parsingClass()
788 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
789 pass
790 else:
791 main.exit()
792
793 except ImportError:
794 print sys.exc_info()[1]
795
adminbae64d82013-08-01 10:50:15 -0700796def load_logger() :
797 '''
798 It facilitates the loading customised parser for topology and params file.
799 It loads parser mentioned in tab named parser of teston.cfg file.
800 It also loads default xmlparser if no parser have specified in teston.cfg file.
801
802 '''
803 confighash = main.configDict
804 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
805 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
806 if os.path.exists(confighash['config']['logger']['file']) :
807 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
808 moduleList = module.split("/")
809 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
810 try :
811 loggerClass = confighash['config']['logger']['class']
812 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
813 loggerClass = getattr(loggerModule, loggerClass)
814 main.logger = loggerClass()
815 #hashobj = main.parser.parseParams(main.classPath)
816
817 except ImportError:
818 print sys.exc_info()[1]
819 else :
820 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
821 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800822 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
823 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700824 else:
825 load_defaultlogger()
826
827def load_defaultlogger():
828 '''
829 It will load the default parser which is xml parser to parse the params and topology file.
830 '''
831 moduleList = main.loggerPath.split("/")
832 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
833 try :
Jon Halld61331b2015-02-17 16:35:47 -0800834 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700835 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
836 loggerClass = getattr(loggerModule, loggerClass)
837 main.logger = loggerClass()
838
839 except ImportError:
840 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800841 main.exit()
adminbae64d82013-08-01 10:50:15 -0700842
adminbae64d82013-08-01 10:50:15 -0700843def _echo(self):
844 print "THIS IS ECHO"