blob: 067d26895572beb0b91faee639374b9f6e225a86 [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
Hari Krishnabe4b97b2015-07-15 12:19:43 -070038import subprocess
adminbae64d82013-08-01 10:50:15 -070039global path, drivers_path, core_path, tests_path,logs_path
40path = re.sub("(core|bin)$", "", os.getcwd())
41drivers_path = path+"drivers/"
42core_path = path+"core"
43tests_path = path+"tests"
44logs_path = path+"logs/"
45config_path = path + "config/"
46sys.path.append(path)
47sys.path.append( drivers_path)
48sys.path.append(core_path )
49sys.path.append(tests_path)
50
51from core.utilities import Utilities
kelvin-onlabfb521662015-02-27 09:52:40 -080052from core.Thread import Thread
adminbae64d82013-08-01 10:50:15 -070053
adminbae64d82013-08-01 10:50:15 -070054
55class TestON:
56 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -070057 TestON will initiate the specified test.
58 The main tasks are :
59 * Initiate the required Component handles for the test.
adminbae64d82013-08-01 10:50:15 -070060 * Create Log file Handles.
adminbae64d82013-08-01 10:50:15 -070061 '''
62 def __init__(self,options):
63 '''
64 Initialise the component handles specified in the topology file of the specified test.
adminbae64d82013-08-01 10:50:15 -070065 '''
66 # Initialization of the variables.
67 __builtin__.main = self
adminbae64d82013-08-01 10:50:15 -070068 __builtin__.path = path
69 __builtin__.utilities = Utilities()
70 self.TRUE = 1
71 self.FALSE = 0
72 self.ERROR = -1
kelvin-onlabf70fd542015-05-07 18:41:40 -070073 self.NORESULT = 2
adminbae64d82013-08-01 10:50:15 -070074 self.FAIL = False
75 self.PASS = True
kelvin-onlabf70fd542015-05-07 18:41:40 -070076 self.CASERESULT = self.ERROR
77 self.STEPRESULT = self.NORESULT
78 self.stepResults = []
adminbae64d82013-08-01 10:50:15 -070079 self.init_result = self.TRUE
80 self.testResult = "Summary"
kelvin-onlabf70fd542015-05-07 18:41:40 -070081 self.stepName = ""
82 self.stepCache = ""
Jon Halld61331b2015-02-17 16:35:47 -080083 self.EXPERIMENTAL_MODE = False
adminbae64d82013-08-01 10:50:15 -070084 self.test_target = None
85 self.lastcommand = None
Jon Halld61331b2015-02-17 16:35:47 -080086 self.testDir = tests_path
87 self.configFile = config_path + "teston.cfg"
adminbae64d82013-08-01 10:50:15 -070088 self.parsingClass = "xmlparser"
89 self.parserPath = core_path + "/xmlparser"
90 self.loggerPath = core_path + "/logger"
91 self.loggerClass = "Logger"
92 self.logs_path = logs_path
93 self.driver = ''
kelvin-onlabfb521662015-02-27 09:52:40 -080094 self.Thread = Thread
Jon Hall5b586732015-06-11 11:39:39 -070095 self.cleanupFlag = False
96 self.cleanupLock = threading.Lock()
Jon Hall0fc0d452015-07-14 09:49:58 -070097 self.initiated = False
Jon Hall65844a32015-03-09 19:09:37 -070098
adminbae64d82013-08-01 10:50:15 -070099 self.configparser()
100 verifyOptions(options)
101 load_logger()
102 self.componentDictionary = {}
103 self.componentDictionary = self.topology ['COMPONENT']
104 self.driversList=[]
105 if type(self.componentDictionary) == str :
106 self.componentDictionary = dict(self.componentDictionary)
Jon Hall65844a32015-03-09 19:09:37 -0700107
adminbae64d82013-08-01 10:50:15 -0700108 for component in self.componentDictionary :
109 self.driversList.append(self.componentDictionary[component]['type'])
Jon Hall65844a32015-03-09 19:09:37 -0700110
adminbae64d82013-08-01 10:50:15 -0700111 self.driversList = list(set(self.driversList)) # Removing duplicates.
112 # Checking the test_target option set for the component or not
113 if type(self.componentDictionary) == dict:
114 for component in self.componentDictionary.keys():
115 if 'test_target' in self.componentDictionary[component].keys():
116 self.test_target = component
Jon Hall65844a32015-03-09 19:09:37 -0700117
Jon Halld61331b2015-02-17 16:35:47 -0800118 # Checking for the openspeak file and test script
adminbae64d82013-08-01 10:50:15 -0700119 self.logger.initlog(self)
120
121 # Creating Drivers Handles
122 initString = "\n"+"*" * 30+"\n CASE INIT \n"+"*" * 30+"\n"
123 self.log.exact(initString)
124 self.driverObject = {}
125 self.random_order = 111 # Random order id to connect the components
126 components_connect_order = {}
127 #component_list.append()
128 if type(self.componentDictionary) == dict:
129 for component in self.componentDictionary.keys():
130 self.componentDictionary[component]['connect_order'] = self.componentDictionary[component]['connect_order'] if ('connect_order' in self.componentDictionary[component].keys()) else str(self.get_random())
131 components_connect_order[component] = eval(self.componentDictionary[component]['connect_order'])
132 #Ordering components based on the connect order.
133 ordered_component_list =sorted(components_connect_order, key=lambda key: components_connect_order[key])
134 print ordered_component_list
adminbae64d82013-08-01 10:50:15 -0700135 for component in ordered_component_list:
136 self.componentInit(component)
137
138 def configparser(self):
139 '''
140 It will parse the config file (teston.cfg) and return as dictionary
141 '''
142 matchFileName = re.match(r'(.*)\.cfg', self.configFile, re.M | re.I)
143 if matchFileName:
144 xml = open(self.configFile).read()
145 try :
146 self.configDict = xmldict.xml_to_dict(xml)
147 return self.configDict
Jon Hallfebb1c72015-03-05 13:30:09 -0800148 except Exception:
adminbae64d82013-08-01 10:50:15 -0700149 print "There is no such file to parse " + self.configFile
kelvin-onlabf70fd542015-05-07 18:41:40 -0700150
adminbae64d82013-08-01 10:50:15 -0700151 def componentInit(self,component):
152 '''
153 This method will initialize specified component
154 '''
155 global driver_options
Jon Hall0fc0d452015-07-14 09:49:58 -0700156 self.initiated = False
adminbae64d82013-08-01 10:50:15 -0700157 self.log.info("Creating component Handle: "+component)
Jon Halld61331b2015-02-17 16:35:47 -0800158 driver_options = {}
adminbae64d82013-08-01 10:50:15 -0700159 if 'COMPONENTS' in self.componentDictionary[component].keys():
160 driver_options =dict(self.componentDictionary[component]['COMPONENTS'])
161
162 driver_options['name']=component
163 driverName = self.componentDictionary[component]['type']
164 driver_options ['type'] = driverName
kelvin-onlabf70fd542015-05-07 18:41:40 -0700165
adminbae64d82013-08-01 10:50:15 -0700166 classPath = self.getDriverPath(driverName.lower())
Jon Hall30b82fa2015-03-04 17:15:43 -0800167 driverModule = importlib.import_module(classPath)
adminbae64d82013-08-01 10:50:15 -0700168 driverClass = getattr(driverModule, driverName)
169 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700170
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700171 if ( "OCN" in self.componentDictionary[component]['host'] and main.onoscell ):
172 self.componentDictionary[component]['host'] = main.mnIP
173
adminbae64d82013-08-01 10:50:15 -0700174 connect_result = driverObject.connect(user_name = self.componentDictionary[component]['user'] if ('user' in self.componentDictionary[component].keys()) else getpass.getuser(),
175 ip_address= self.componentDictionary[component]['host'] if ('host' in self.componentDictionary[component].keys()) else 'localhost',
176 pwd = self.componentDictionary[component]['password'] if ('password' in self.componentDictionary[component].keys()) else 'changeme',
177 port = self.componentDictionary[component]['port'] if ('port' in self.componentDictionary[component].keys()) else None,
178 options = driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700179
adminbae64d82013-08-01 10:50:15 -0700180 if not connect_result:
181 self.log.error("Exiting form the test execution because the connecting to the "+component+" component failed.")
Jon Halld61331b2015-02-17 16:35:47 -0800182 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700183
adminbae64d82013-08-01 10:50:15 -0700184 vars(self)[component] = driverObject
Jon Hall0fc0d452015-07-14 09:49:58 -0700185 self.initiated = True
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 = ""
Jon Hall783bbf92015-07-23 14:33:19 -0700225 self.caseExplanation = ""
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)
Jon Hall783bbf92015-07-23 14:33:19 -0700259 self.log.wiki( "<p>" + self.caseExplanation + "</p>" )
260 self.log.summary( self.caseExplanation )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700261 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
Jon Hall0fc0d452015-07-14 09:49:58 -0700363 if self.initiated:
364 self.logger.testSummary(self)
Jon Hall5b586732015-06-11 11:39:39 -0700365 for component in self.componentDictionary.keys():
366 try :
367 tempObject = vars(self)[component]
368 print "Disconnecting from " + str(tempObject.name) + ": " + \
369 str(tempObject)
370 tempObject.disconnect()
371 except Exception:
372 self.log.exception( "Exception while disconnecting from " +
373 str( component ) )
374 result = self.FALSE
375 # Closing all the driver's session files
376 for driver in self.componentDictionary.keys():
377 try:
378 vars(self)[driver].close_log_handles()
379 except Exception:
380 self.log.exception( "Exception while closing log files for " +
381 str( driver ) )
382 result = self.FALSE
383 else:
384 pass # Someone else already ran through this function
385 finally:
386 lock.release()
387 else: # Someone already has a lock
388 # NOTE: This could cause problems if we don't release the lock
389 # correctly
390 lock.acquire() # Wait for the other thread to finish
391 # NOTE: If we don't wait, exit could be called while the thread
392 # with the lock is still cleaning up
393 lock.release()
adminbae64d82013-08-01 10:50:15 -0700394 return result
Jon Halld61331b2015-02-17 16:35:47 -0800395
adminbae64d82013-08-01 10:50:15 -0700396 def pause(self):
397 '''
398 This function will pause the test's execution, and will continue after user provide 'resume' command.
399 '''
400 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700401
adminbae64d82013-08-01 10:50:15 -0700402 def onfail(self,*components):
403 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700404 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700405 '''
adminbae64d82013-08-01 10:50:15 -0700406 if not components:
407 try :
408 for component in self.componentDictionary.keys():
409 tempObject = vars(self)[component]
410 result = tempObject.onfail()
411 except(Exception),e:
412 print str(e)
413 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700414 else:
415 try :
416 for component in components:
417 tempObject = vars(self)[component]
418 result = tempObject.onfail()
419 except(Exception),e:
420 print str(e)
421 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700422
adminbae64d82013-08-01 10:50:15 -0700423 def getDriverPath(self,driverName):
424 '''
425 Based on the component 'type' specified in the params , this method will find the absolute path ,
426 by recursively searching the name of the component.
427 '''
428 import commands
429
430 cmd = "find "+drivers_path+" -name "+driverName+".py"
431 result = commands.getoutput(cmd)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700432
adminbae64d82013-08-01 10:50:15 -0700433 result_array = str(result).split('\n')
434 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700435
adminbae64d82013-08-01 10:50:15 -0700436 for drivers_list in result_array:
437 result_count = result_count+1
438 if result_count > 1 :
439 print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
440 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700441
adminbae64d82013-08-01 10:50:15 -0700442 result = re.sub("(.*)drivers","",result)
443 result = re.sub("\.py","",result)
444 result = re.sub("\.pyc","",result)
445 result = re.sub("\/",".",result)
446 result = "drivers"+result
447 return result
adminbae64d82013-08-01 10:50:15 -0700448
449 def step(self,stepDesc):
450 '''
451 The step information of the test-case will append to the logs.
452 '''
453 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
454 self.stepName = stepDesc
455
456 stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
457 try :
458 if self.stepCount == 0:
459 stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
460 except AttributeError:
461 stepName = " INIT : Initializing the test case :"+str(self.CurrentTestCaseNumber)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700462
adminbae64d82013-08-01 10:50:15 -0700463 self.log.step(stepName)
464 stepHeader = ""
465 if self.stepCount > 1 :
466 stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700467
Jon Halld61331b2015-02-17 16:35:47 -0800468 stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
adminbae64d82013-08-01 10:50:15 -0700469 for driver in self.componentDictionary.keys():
470 vars(self)[driver+'log'].info(stepHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700471
adminbae64d82013-08-01 10:50:15 -0700472 def case(self,testCaseName):
473 '''
474 Test's each test-case information will append to the logs.
475 '''
Jon Halld61331b2015-02-17 16:35:47 -0800476 self.CurrentTestCase = testCaseName
adminbae64d82013-08-01 10:50:15 -0700477 testCaseName = " " + str(testCaseName) + ""
478 self.log.case(testCaseName)
Jon Halld61331b2015-02-17 16:35:47 -0800479 caseHeader = testCaseName+"\n"+"*" * 40+"\n"
adminbae64d82013-08-01 10:50:15 -0700480 for driver in self.componentDictionary.keys():
481 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700482
adminbae64d82013-08-01 10:50:15 -0700483 def testDesc(self,description):
484 '''
485 Test description will append to the logs.
486 '''
487 description = "Test Description : " + str (description) + ""
488 self.log.info(description)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700489
adminbae64d82013-08-01 10:50:15 -0700490 def _getTest(self):
491 '''
492 This method will parse the test script to find required test information.
493 '''
494 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
495 testFileHandler = open(testFile, 'r')
496 testFileList = testFileHandler.readlines()
497 testFileHandler.close()
498 #self.TOTAL_TC_PLANNED = 0
499 counter = 0
500 for index in range(len(testFileList)):
501 lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
502 if lineMatch:
503 counter = counter + 1
Jon Halla1185982014-09-15 14:55:10 -0700504 self.TC_PLANNED = len(self.testcases_list)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700505
adminbae64d82013-08-01 10:50:15 -0700506 def response_parser(self,response, return_format):
507 ''' It will load the default response parser '''
508 response_dict = {}
509 response_dict = self.response_to_dict(response, return_format)
Jon Halld61331b2015-02-17 16:35:47 -0800510 return_format_string = self.dict_to_return_format(response,return_format,response_dict)
adminbae64d82013-08-01 10:50:15 -0700511 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700512
adminbae64d82013-08-01 10:50:15 -0700513 def response_to_dict(self,response,return_format):
adminbae64d82013-08-01 10:50:15 -0700514 response_dict = {}
515 json_match = re.search('^\s*{', response)
516 xml_match = re.search('^\s*\<', response)
517 ini_match = re.search('^\s*\[', response)
518 if json_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800519 self.log.info(" Response is in 'JSON' format and Converting to '"+return_format+"' format")
Jon Halld61331b2015-02-17 16:35:47 -0800520 # Formatting the json string
adminbae64d82013-08-01 10:50:15 -0700521 response = re.sub(r"{\s*'?(\w)", r'{"\1', response)
522 response = re.sub(r",\s*'?(\w)", r',"\1', response)
523 response = re.sub(r"(\w)'?\s*:", r'\1":', response)
524 response = re.sub(r":\s*'(\w)'\s*([,}])", r':"\1"\2', response)
adminbae64d82013-08-01 10:50:15 -0700525 try :
526 import json
527 response_dict = json.loads(response)
Jon Hall30b82fa2015-03-04 17:15:43 -0800528 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800529 self.log.exception( e )
530 self.log.error("Json Parser is unable to parse the string")
adminbae64d82013-08-01 10:50:15 -0700531 return response_dict
adminbae64d82013-08-01 10:50:15 -0700532 elif ini_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800533 self.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700534 from configobj import ConfigObj
535 response_file = open("respnse_file.temp",'w')
536 response_file.write(response)
Jon Halld61331b2015-02-17 16:35:47 -0800537 response_file.close()
adminbae64d82013-08-01 10:50:15 -0700538 response_dict = ConfigObj("respnse_file.temp")
539 return response_dict
adminbae64d82013-08-01 10:50:15 -0700540 elif xml_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800541 self.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700542 try :
adminbae64d82013-08-01 10:50:15 -0700543 response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
544 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800545 self.log.exception( e )
adminbae64d82013-08-01 10:50:15 -0700546 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700547
adminbae64d82013-08-01 10:50:15 -0700548 def dict_to_return_format(self,response,return_format,response_dict):
adminbae64d82013-08-01 10:50:15 -0700549 if return_format =='table' :
550 ''' Will return in table format'''
551 to_do = "Call the table output formatter"
552 global response_table
553 response_table = '\n'
554 response_table = response_table +'\t'.join(response_dict)+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700555
adminbae64d82013-08-01 10:50:15 -0700556 def get_table(value_to_convert):
557 ''' This will parse the dictionary recusrsively and print as table format'''
558 table_data = ""
559 if type(value_to_convert) == dict :
560 table_data = table_data +'\t'.join(value_to_convert)+"\n"
561 for temp_val in value_to_convert.values() :
562 table_data = table_data + get_table(temp_val)
563 else :
564 table_data = table_data + str(value_to_convert) +"\t"
Jon Halld61331b2015-02-17 16:35:47 -0800565 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700566
adminbae64d82013-08-01 10:50:15 -0700567 for value in response_dict.values() :
568 response_table = response_table + get_table(value)
Jon Hall88e498c2015-03-06 09:54:35 -0800569 # response_table = response_table + '\t'.join(response_dict.values())
adminbae64d82013-08-01 10:50:15 -0700570 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700571
adminbae64d82013-08-01 10:50:15 -0700572 elif return_format =='config':
573 ''' Will return in config format'''
574 to_do = 'Call dict to config coverter'
575 response_string = str(response_dict)
576 print response_string
577 response_config = re.sub(",", "\n\t", response_string)
578 response_config = re.sub("u\'", "\'", response_config)
579 response_config = re.sub("{", "", response_config)
580 response_config = re.sub("}", "\n", response_config)
581 response_config = re.sub(":", " =", response_config)
582 return "[response]\n\t "+response_config
adminbae64d82013-08-01 10:50:15 -0700583 elif return_format == 'xml':
584 ''' Will return in xml format'''
adminbae64d82013-08-01 10:50:15 -0700585 response_xml = xmldict.dict_to_xml(response_dict)
586 response_xml = re.sub(">\s*<", ">\n<", response_xml)
587 return "\n"+response_xml
adminbae64d82013-08-01 10:50:15 -0700588 elif return_format == 'json':
589 ''' Will return in json format'''
590 to_do = 'Call dict to xml coverter'
591 import json
592 response_json = json.dumps(response_dict)
593 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700594
adminbae64d82013-08-01 10:50:15 -0700595 def get_random(self):
596 self.random_order = self.random_order + 1
597 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700598
adminbae64d82013-08-01 10:50:15 -0700599 def exit(self):
600 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700601 for thread in threading.enumerate():
602 if thread.isAlive():
603 try:
604 thread._Thread__stop()
605 except:
606 print(str(thread.getName()) + ' could not be terminated' )
adminbae64d82013-08-01 10:50:15 -0700607 sys.exit()
608
609def verifyOptions(options):
610 '''
611 This will verify the command line options and set to default values, if any option not given in command line.
612 '''
613 import pprint
614 pp = pprint.PrettyPrinter(indent=4)
615
Jon Hall88e498c2015-03-06 09:54:35 -0800616 # pp.pprint(options)
adminbae64d82013-08-01 10:50:15 -0700617 verifyTest(options)
618 verifyExample(options)
619 verifyTestScript(options)
620 verifyParams()
621 verifyLogdir(options)
622 verifyMail(options)
623 verifyTestCases(options)
Hari Krishna03f530e2015-07-10 17:28:27 -0700624 verifyOnosCell(options)
adminbae64d82013-08-01 10:50:15 -0700625
626def verifyTest(options):
627 if options.testname:
628 main.TEST = options.testname
629 main.classPath = "tests."+main.TEST+"."+main.TEST
630 main.tests_path = tests_path
631 elif options.example :
632 main.TEST = options.example
633 main.tests_path = path+"/examples/"
634 main.classPath = "examples."+main.TEST+"."+main.TEST
635 else :
636 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700637 main.exit()
adminbae64d82013-08-01 10:50:15 -0700638
639def verifyExample(options):
640 if options.example:
641 main.testDir = path+'/examples/'
642 main.tests_path = path+"/examples/"
643 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700644
adminbae64d82013-08-01 10:50:15 -0700645def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800646 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700647 if options.logdir:
648 main.logdir = options.logdir
649 else :
Jon Halld61331b2015-02-17 16:35:47 -0800650 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700651
adminbae64d82013-08-01 10:50:15 -0700652def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800653 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700654 if options.mail:
655 main.mail = options.mail
656 elif main.params.has_key('mail'):
657 main.mail = main.params['mail']
658 else :
659 main.mail = 'paxweb@paxterrasolutions.com'
660
661def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800662 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700663 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800664 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800665 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700666 testcases_list = re.sub("(\[|\])", "", options.testcases)
667 main.testcases_list = eval(testcases_list+",")
668 else :
669 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700670 temp = eval(main.params['testcases']+",")
671 list1=[]
672 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800673 for test in temp:
674 for testcase in test:
675 if type(testcase)==int:
676 testcase=[testcase]
677 list1.extend(testcase)
678 else :
679 temp=list(temp)
680 for testcase in temp:
681 if type(testcase)==int:
682 testcase=[testcase]
683 list1.extend(testcase)
684 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700685 else :
686 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800687 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700688
Hari Krishna03f530e2015-07-10 17:28:27 -0700689def verifyOnosCell(options):
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700690 # Verifying onoscell option
Hari Krishna03f530e2015-07-10 17:28:27 -0700691 if options.onoscell:
692 main.onoscell = options.onoscell
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700693 main.onosIPs = []
694 main.mnIP = ""
695 cellCMD = ". ~/.profile; cell "+main.onoscell
696 output=subprocess.check_output( ["bash", '-c', cellCMD] )
697 splitOutput = output.splitlines()
698 for i in range( len(splitOutput) ):
699 if( re.match( "OCN", splitOutput[i] ) ):
700 mnNode=splitOutput[i].split("=")
701 main.mnIP = mnNode[1]
702 # cell already sorts OC variables in bash, so no need to sort in TestON
703 if( re.match( "OC[1-9]", splitOutput[i] ) ):
704 onosNodes = splitOutput[i].split("=")
705 main.onosIPs.append( onosNodes[1] )
Hari Krishna03f530e2015-07-10 17:28:27 -0700706 else :
707 main.onoscell = main.FALSE
708
adminbae64d82013-08-01 10:50:15 -0700709def verifyTestScript(options):
710 '''
711 Verifyies test script.
712 '''
Jon Halld61331b2015-02-17 16:35:47 -0800713 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700714 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
715 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
716 if os.path.exists(openspeakfile) :
717 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
718 elif os.path.exists(testfile):
719 print ''
720 else:
721 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
722 __builtin__.testthread = None
723 main.exit()
adminbae64d82013-08-01 10:50:15 -0700724 try :
adminbae64d82013-08-01 10:50:15 -0700725 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
726 except(ImportError):
Jon Hallf8ecf732014-12-02 21:14:16 -0500727 print "There was an import error, it might mean that there is no test like "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800728 main.exit()
adminbae64d82013-08-01 10:50:15 -0700729
730 testClass = getattr(testModule, main.TEST)
731 main.testObject = testClass()
732 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800733 main.params = main.parser.parseParams(main.classPath)
734 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700735
adminbae64d82013-08-01 10:50:15 -0700736def verifyParams():
737 try :
738 main.params = main.params['PARAMS']
739 except(KeyError):
740 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800741 main.exit()
adminbae64d82013-08-01 10:50:15 -0700742 try :
743 main.topology = main.topology['TOPOLOGY']
744 except(KeyError):
745 print "Error with the Topology file: Either the file not specified or the format is not correct"
746 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700747
adminbae64d82013-08-01 10:50:15 -0700748def load_parser() :
749 '''
750 It facilitates the loading customised parser for topology and params file.
751 It loads parser mentioned in tab named parser of teston.cfg file.
752 It also loads default xmlparser if no parser have specified in teston.cfg file.
753
754 '''
755 confighash = main.configDict
756 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
757 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
758 if os.path.exists(confighash['config']['parser']['file']) :
759 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
760 moduleList = module.split("/")
761 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
762 try :
763 parsingClass = confighash['config']['parser']['class']
764 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
765 parsingClass = getattr(parsingModule, parsingClass)
766 main.parser = parsingClass()
767 #hashobj = main.parser.parseParams(main.classPath)
768 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
adminbae64d82013-08-01 10:50:15 -0700769 pass
770 else:
771 main.exit()
adminbae64d82013-08-01 10:50:15 -0700772 except ImportError:
773 print sys.exc_info()[1]
774 main.exit()
775 else :
776 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
Jon Halld61331b2015-02-17 16:35:47 -0800777 load_defaultParser()
778 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
779 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700780 else:
781 load_defaultParser()
782
783def load_defaultParser():
784 '''
785 It will load the default parser which is xml parser to parse the params and topology file.
786 '''
787 moduleList = main.parserPath.split("/")
788 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
789 try :
Jon Halld61331b2015-02-17 16:35:47 -0800790 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700791 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
792 parsingClass = getattr(parsingModule, parsingClass)
793 main.parser = parsingClass()
794 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
795 pass
796 else:
797 main.exit()
798
799 except ImportError:
800 print sys.exc_info()[1]
801
adminbae64d82013-08-01 10:50:15 -0700802def load_logger() :
803 '''
804 It facilitates the loading customised parser for topology and params file.
805 It loads parser mentioned in tab named parser of teston.cfg file.
806 It also loads default xmlparser if no parser have specified in teston.cfg file.
807
808 '''
809 confighash = main.configDict
810 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
811 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
812 if os.path.exists(confighash['config']['logger']['file']) :
813 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
814 moduleList = module.split("/")
815 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
816 try :
817 loggerClass = confighash['config']['logger']['class']
818 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
819 loggerClass = getattr(loggerModule, loggerClass)
820 main.logger = loggerClass()
821 #hashobj = main.parser.parseParams(main.classPath)
822
823 except ImportError:
824 print sys.exc_info()[1]
825 else :
826 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
827 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800828 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
829 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700830 else:
831 load_defaultlogger()
832
833def load_defaultlogger():
834 '''
835 It will load the default parser which is xml parser to parse the params and topology file.
836 '''
837 moduleList = main.loggerPath.split("/")
838 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
839 try :
Jon Halld61331b2015-02-17 16:35:47 -0800840 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700841 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
842 loggerClass = getattr(loggerModule, loggerClass)
843 main.logger = loggerClass()
844
845 except ImportError:
846 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800847 main.exit()
adminbae64d82013-08-01 10:50:15 -0700848
adminbae64d82013-08-01 10:50:15 -0700849def _echo(self):
850 print "THIS IS ECHO"