blob: 1d41acf73bf9f5064d95dcdebf4441ce6ec25bb5 [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
cameron@onlab.us5cc6a372015-05-11 17:18:07 -070035import os
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 = ""
82 # make this into two lists? one for step names, one for results?
83 # this way, the case result could be a true AND of these results
Jon Halld61331b2015-02-17 16:35:47 -080084 self.EXPERIMENTAL_MODE = False
adminbae64d82013-08-01 10:50:15 -070085 self.test_target = None
86 self.lastcommand = None
Jon Halld61331b2015-02-17 16:35:47 -080087 self.testDir = tests_path
88 self.configFile = config_path + "teston.cfg"
adminbae64d82013-08-01 10:50:15 -070089 self.parsingClass = "xmlparser"
90 self.parserPath = core_path + "/xmlparser"
91 self.loggerPath = core_path + "/logger"
92 self.loggerClass = "Logger"
93 self.logs_path = logs_path
94 self.driver = ''
kelvin-onlabfb521662015-02-27 09:52:40 -080095 self.Thread = Thread
Jon Hall65844a32015-03-09 19:09:37 -070096
adminbae64d82013-08-01 10:50:15 -070097 self.configparser()
98 verifyOptions(options)
99 load_logger()
100 self.componentDictionary = {}
101 self.componentDictionary = self.topology ['COMPONENT']
102 self.driversList=[]
103 if type(self.componentDictionary) == str :
104 self.componentDictionary = dict(self.componentDictionary)
Jon Hall65844a32015-03-09 19:09:37 -0700105
adminbae64d82013-08-01 10:50:15 -0700106 for component in self.componentDictionary :
107 self.driversList.append(self.componentDictionary[component]['type'])
Jon Hall65844a32015-03-09 19:09:37 -0700108
adminbae64d82013-08-01 10:50:15 -0700109 self.driversList = list(set(self.driversList)) # Removing duplicates.
110 # Checking the test_target option set for the component or not
111 if type(self.componentDictionary) == dict:
112 for component in self.componentDictionary.keys():
113 if 'test_target' in self.componentDictionary[component].keys():
114 self.test_target = component
Jon Hall65844a32015-03-09 19:09:37 -0700115
Jon Halld61331b2015-02-17 16:35:47 -0800116 # Checking for the openspeak file and test script
adminbae64d82013-08-01 10:50:15 -0700117 self.logger.initlog(self)
118
119 # Creating Drivers Handles
120 initString = "\n"+"*" * 30+"\n CASE INIT \n"+"*" * 30+"\n"
121 self.log.exact(initString)
122 self.driverObject = {}
123 self.random_order = 111 # Random order id to connect the components
124 components_connect_order = {}
125 #component_list.append()
126 if type(self.componentDictionary) == dict:
127 for component in self.componentDictionary.keys():
128 self.componentDictionary[component]['connect_order'] = self.componentDictionary[component]['connect_order'] if ('connect_order' in self.componentDictionary[component].keys()) else str(self.get_random())
129 components_connect_order[component] = eval(self.componentDictionary[component]['connect_order'])
130 #Ordering components based on the connect order.
131 ordered_component_list =sorted(components_connect_order, key=lambda key: components_connect_order[key])
132 print ordered_component_list
adminbae64d82013-08-01 10:50:15 -0700133 for component in ordered_component_list:
134 self.componentInit(component)
135
136 def configparser(self):
137 '''
138 It will parse the config file (teston.cfg) and return as dictionary
139 '''
140 matchFileName = re.match(r'(.*)\.cfg', self.configFile, re.M | re.I)
141 if matchFileName:
142 xml = open(self.configFile).read()
143 try :
144 self.configDict = xmldict.xml_to_dict(xml)
145 return self.configDict
Jon Hallfebb1c72015-03-05 13:30:09 -0800146 except Exception:
adminbae64d82013-08-01 10:50:15 -0700147 print "There is no such file to parse " + self.configFile
kelvin-onlabf70fd542015-05-07 18:41:40 -0700148
adminbae64d82013-08-01 10:50:15 -0700149 def componentInit(self,component):
150 '''
151 This method will initialize specified component
152 '''
153 global driver_options
154 self.log.info("Creating component Handle: "+component)
Jon Halld61331b2015-02-17 16:35:47 -0800155 driver_options = {}
adminbae64d82013-08-01 10:50:15 -0700156 if 'COMPONENTS' in self.componentDictionary[component].keys():
157 driver_options =dict(self.componentDictionary[component]['COMPONENTS'])
158
159 driver_options['name']=component
160 driverName = self.componentDictionary[component]['type']
161 driver_options ['type'] = driverName
kelvin-onlabf70fd542015-05-07 18:41:40 -0700162
adminbae64d82013-08-01 10:50:15 -0700163 classPath = self.getDriverPath(driverName.lower())
Jon Hall30b82fa2015-03-04 17:15:43 -0800164 driverModule = importlib.import_module(classPath)
adminbae64d82013-08-01 10:50:15 -0700165 driverClass = getattr(driverModule, driverName)
166 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700167
kelvin-onlab0a28a742015-05-18 16:03:13 -0700168 try:
169 self.componentDictionary[component]['host'] = os.environ[str( self.componentDictionary[component]['host'])]
170 except KeyError:
171 self.log.info("Missing OC environment variable! Using stored IPs")
172 except Exception as inst:
173 self.log.error("Uncaught exception: " + str(inst))
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700174
adminbae64d82013-08-01 10:50:15 -0700175 connect_result = driverObject.connect(user_name = self.componentDictionary[component]['user'] if ('user' in self.componentDictionary[component].keys()) else getpass.getuser(),
176 ip_address= self.componentDictionary[component]['host'] if ('host' in self.componentDictionary[component].keys()) else 'localhost',
177 pwd = self.componentDictionary[component]['password'] if ('password' in self.componentDictionary[component].keys()) else 'changeme',
178 port = self.componentDictionary[component]['port'] if ('port' in self.componentDictionary[component].keys()) else None,
179 options = driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700180
adminbae64d82013-08-01 10:50:15 -0700181 if not connect_result:
182 self.log.error("Exiting form the test execution because the connecting to the "+component+" component failed.")
Jon Halld61331b2015-02-17 16:35:47 -0800183 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700184
adminbae64d82013-08-01 10:50:15 -0700185 vars(self)[component] = driverObject
kelvin-onlabf70fd542015-05-07 18:41:40 -0700186
adminbae64d82013-08-01 10:50:15 -0700187 def run(self):
188 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700189 The Execution of the test script's cases listed in the Test params file will be done here.
190 And Update each test case result.
191 This method will return TRUE if it executed all the test cases successfully,
adminbae64d82013-08-01 10:50:15 -0700192 else will retun FALSE
193 '''
adminbae64d82013-08-01 10:50:15 -0700194 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700195 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700196 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800197 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700198 self.TOTAL_TC_NORESULT = 0
199 self.TOTAL_TC_FAIL = 0
200 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700201 self.TEST_ITERATION = 0
adminbae64d82013-08-01 10:50:15 -0700202 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700203 self.CASERESULT = self.NORESULT
204
Jon Halld61331b2015-02-17 16:35:47 -0800205 import testparser
adminbae64d82013-08-01 10:50:15 -0700206 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
207 test = testparser.TestParser(testFile)
208 self.testscript = test.testscript
209 self.code = test.getStepCode()
Jon Hallfebb1c72015-03-05 13:30:09 -0800210 repeat= int(self.params['repeat']) if ('repeat' in self.params) else 1
211 self.TOTAL_TC_PLANNED = len(self.testcases_list)*repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700212
adminbae64d82013-08-01 10:50:15 -0700213 result = self.TRUE
Jon Hallfebb1c72015-03-05 13:30:09 -0800214 while(repeat):
Jon Halla1185982014-09-15 14:55:10 -0700215 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Halld61331b2015-02-17 16:35:47 -0800216 result = self.runCase(self.CurrentTestCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800217 repeat-=1
adminbae64d82013-08-01 10:50:15 -0700218 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700219
adminbae64d82013-08-01 10:50:15 -0700220 def runCase(self,testCaseNumber):
221 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700222 self.CurrentTestCase = ""
223 self.stepResults = []
224 self.stepName = ""
225 self.caseExplaination = ""
adminbae64d82013-08-01 10:50:15 -0700226 result = self.TRUE
227 self.stepCount = 0
228 self.EXPERIMENTAL_MODE = self.FALSE
229 self.addCaseHeader()
230 self.testCaseNumber = str(testCaseNumber)
231 stopped = False
232 try :
233 self.stepList = self.code[self.testCaseNumber].keys()
Jon Halld61331b2015-02-17 16:35:47 -0800234 except KeyError:
Jon Hallfebb1c72015-03-05 13:30:09 -0800235 self.log.error("There is no Test-Case "+ self.testCaseNumber)
236 return self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700237
adminbae64d82013-08-01 10:50:15 -0700238 self.stepCount = 0
239 while self.stepCount < len(self.code[self.testCaseNumber].keys()):
240 result = self.runStep(self.stepList,self.code,self.testCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800241 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700242 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800243 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700244 continue
adminbae64d82013-08-01 10:50:15 -0700245 if not stopped :
kelvin-onlabf70fd542015-05-07 18:41:40 -0700246 if all( self.TRUE == i for i in self.stepResults ):
247 # ALL PASSED
248 self.CASERESULT = self.TRUE
249 elif self.FALSE in self.stepResults:
250 # AT LEAST ONE FAILED
251 self.CASERESULT = self.FALSE
252 elif self.TRUE in self.stepResults:
253 # AT LEAST ONE PASSED
254 self.CASERESULT = self.TRUE
255 else:
256 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700257 self.testCaseResult[str(self.CurrentTestCaseNumber)] = self.CASERESULT
258 self.logger.updateCaseResults(self)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700259 self.log.wiki( "<p>" + self.caseExplaination + "</p>" )
260 self.log.summary( self.caseExplaination )
261 self.log.wiki( "<ul>" )
262 for line in self.stepCache.splitlines():
263 if re.search( " - PASS$", line ):
264 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
265 elif re.search( " - FAIL$", line ):
266 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
267 elif re.search( " - No Result$", line ):
268 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
269 self.log.wiki( "</ul>" )
270 self.log.summary( self.stepCache )
271 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700272 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700273
adminbae64d82013-08-01 10:50:15 -0700274 def runStep(self,stepList,code,testCaseNumber):
275 if not cli.pause:
276 try :
277 step = stepList[self.stepCount]
kelvin-onlabf70fd542015-05-07 18:41:40 -0700278 self.STEPRESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700279 exec code[testCaseNumber][step] in module.__dict__
280 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700281 if step > 0:
282 self.stepCache += "\t"+str(testCaseNumber)+"."+str(step)+" "+self.stepName+" - "
283 if self.STEPRESULT == self.TRUE:
284 self.stepCache += "PASS\n"
285 #self.stepCache += "PASS <ac:emoticon ac:name=\"tick\" /></li>\n"
286 elif self.STEPRESULT == self.FALSE:
287 self.stepCache += "FAIL\n"
288 #self.stepCache += "FAIL <ac:emoticon ac:name=\"cross\" /></li>\n"
289 else:
290 self.stepCache += "No Result\n"
291 #self.stepCache += "No Result <ac:emoticon ac:name=\"warning\" /></li>\n"
292 self.stepResults.append(self.STEPRESULT)
adminbae64d82013-08-01 10:50:15 -0700293 except TypeError,e:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700294 print "\nException in the following section of code: " +\
295 str(testCaseNumber) + "." + str(step) + ": " +\
296 self.stepName
Jon Hall63604932015-02-26 17:09:50 -0800297 #print code[testCaseNumber][step]
adminbae64d82013-08-01 10:50:15 -0700298 self.stepCount = self.stepCount + 1
Jon Hall30b82fa2015-03-04 17:15:43 -0800299 self.log.exception(e)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700300 self.logger.updateCaseResults(self)
301 #WIKI results
302 self.log.wiki( "<ul>" )
303 for line in self.stepCache.splitlines():
304 if re.search( " - PASS$", line ):
305 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
306 elif re.search( " - FAIL$", line ):
307 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
308 elif re.search( " - No Result$", line ):
309 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
310 self.log.wiki( "</ul>" )
311 #summary results
312 self.log.summary( self.stepCache )
313 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700314 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700315 self.exit()
adminbae64d82013-08-01 10:50:15 -0700316 return main.TRUE
adminbae64d82013-08-01 10:50:15 -0700317 if cli.stop:
318 cli.stop = False
319 stopped = True
320 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
321 self.testCaseResult[str(self.CurrentTestCaseNumber)] = "Stopped"
322 self.logger.updateCaseResults(self)
323 result = self.cleanup()
324 return main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700325
adminbae64d82013-08-01 10:50:15 -0700326 def addCaseHeader(self):
327 caseHeader = "\n"+"*" * 30+"\n Result summary for Testcase"+str(self.CurrentTestCaseNumber)+"\n"+"*" * 30+"\n"
Jon Halld61331b2015-02-17 16:35:47 -0800328 self.log.exact(caseHeader)
329 caseHeader = "\n"+"*" * 40 +"\nStart of Test Case"+str(self.CurrentTestCaseNumber)+" : "
adminbae64d82013-08-01 10:50:15 -0700330 for driver in self.componentDictionary.keys():
331 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700332
adminbae64d82013-08-01 10:50:15 -0700333 def addCaseFooter(self):
334 if self.stepCount-1 > 0 :
335 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
336 stepHeader = "\n"+"*" * 40+"\nEnd of Step "+previousStep+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700337
adminbae64d82013-08-01 10:50:15 -0700338 caseFooter = "\n"+"*" * 40+"\nEnd of Test case "+str(self.CurrentTestCaseNumber)+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700339
adminbae64d82013-08-01 10:50:15 -0700340 for driver in self.driversList:
341 vars(self)[driver].write(stepHeader+"\n"+caseFooter)
342
343 def cleanup(self):
344 '''
345 Release all the component handles and the close opened file handles.
346 This will return TRUE if all the component handles and log handles closed properly,
347 else return FALSE
348
349 '''
350 result = self.TRUE
351 self.logger.testSummary(self)
Jon Halld61331b2015-02-17 16:35:47 -0800352
adminbae64d82013-08-01 10:50:15 -0700353 #self.reportFile.close()
Jon Halld61331b2015-02-17 16:35:47 -0800354
admin2c7034f2013-08-02 15:09:17 -0700355 #utilities.send_mail()
Jon Hall00539b12015-04-03 13:55:46 -0700356 for component in self.componentDictionary.keys():
357 try :
Jon Halld61331b2015-02-17 16:35:47 -0800358 tempObject = vars(self)[component]
Jon Hall1a77a1e2015-04-06 10:41:13 -0700359 print "Disconnecting from " + str(tempObject.name) + ": " + \
360 str(tempObject)
adminbae64d82013-08-01 10:50:15 -0700361 tempObject.disconnect()
Jon Halld61331b2015-02-17 16:35:47 -0800362 #tempObject.execute(cmd="exit",prompt="(.*)",timeout=120)
adminbae64d82013-08-01 10:50:15 -0700363
Jon Hall00539b12015-04-03 13:55:46 -0700364 except (Exception):
365 self.log.exception( "Exception while disconnecting from " +
366 str( component ) )
367 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700368 # Closing all the driver's session files
369 for driver in self.componentDictionary.keys():
370 vars(self)[driver].close_log_handles()
Jon Halld61331b2015-02-17 16:35:47 -0800371
adminbae64d82013-08-01 10:50:15 -0700372 return result
Jon Halld61331b2015-02-17 16:35:47 -0800373
adminbae64d82013-08-01 10:50:15 -0700374 def pause(self):
375 '''
376 This function will pause the test's execution, and will continue after user provide 'resume' command.
377 '''
378 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700379
adminbae64d82013-08-01 10:50:15 -0700380 def onfail(self,*components):
381 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700382 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700383 '''
adminbae64d82013-08-01 10:50:15 -0700384 if not components:
385 try :
386 for component in self.componentDictionary.keys():
387 tempObject = vars(self)[component]
388 result = tempObject.onfail()
389 except(Exception),e:
390 print str(e)
391 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700392 else:
393 try :
394 for component in components:
395 tempObject = vars(self)[component]
396 result = tempObject.onfail()
397 except(Exception),e:
398 print str(e)
399 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700400
adminbae64d82013-08-01 10:50:15 -0700401 def getDriverPath(self,driverName):
402 '''
403 Based on the component 'type' specified in the params , this method will find the absolute path ,
404 by recursively searching the name of the component.
405 '''
406 import commands
407
408 cmd = "find "+drivers_path+" -name "+driverName+".py"
409 result = commands.getoutput(cmd)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700410
adminbae64d82013-08-01 10:50:15 -0700411 result_array = str(result).split('\n')
412 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700413
adminbae64d82013-08-01 10:50:15 -0700414 for drivers_list in result_array:
415 result_count = result_count+1
416 if result_count > 1 :
417 print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
418 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700419
adminbae64d82013-08-01 10:50:15 -0700420 result = re.sub("(.*)drivers","",result)
421 result = re.sub("\.py","",result)
422 result = re.sub("\.pyc","",result)
423 result = re.sub("\/",".",result)
424 result = "drivers"+result
425 return result
adminbae64d82013-08-01 10:50:15 -0700426
427 def step(self,stepDesc):
428 '''
429 The step information of the test-case will append to the logs.
430 '''
431 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
432 self.stepName = stepDesc
433
434 stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
435 try :
436 if self.stepCount == 0:
437 stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
438 except AttributeError:
439 stepName = " INIT : Initializing the test case :"+str(self.CurrentTestCaseNumber)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700440
adminbae64d82013-08-01 10:50:15 -0700441 self.log.step(stepName)
442 stepHeader = ""
443 if self.stepCount > 1 :
444 stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700445
Jon Halld61331b2015-02-17 16:35:47 -0800446 stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
adminbae64d82013-08-01 10:50:15 -0700447 for driver in self.componentDictionary.keys():
448 vars(self)[driver+'log'].info(stepHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700449
adminbae64d82013-08-01 10:50:15 -0700450 def case(self,testCaseName):
451 '''
452 Test's each test-case information will append to the logs.
453 '''
Jon Halld61331b2015-02-17 16:35:47 -0800454 self.CurrentTestCase = testCaseName
adminbae64d82013-08-01 10:50:15 -0700455 testCaseName = " " + str(testCaseName) + ""
456 self.log.case(testCaseName)
Jon Halld61331b2015-02-17 16:35:47 -0800457 caseHeader = testCaseName+"\n"+"*" * 40+"\n"
adminbae64d82013-08-01 10:50:15 -0700458 for driver in self.componentDictionary.keys():
459 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700460
adminbae64d82013-08-01 10:50:15 -0700461 def testDesc(self,description):
462 '''
463 Test description will append to the logs.
464 '''
465 description = "Test Description : " + str (description) + ""
466 self.log.info(description)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700467
adminbae64d82013-08-01 10:50:15 -0700468 def _getTest(self):
469 '''
470 This method will parse the test script to find required test information.
471 '''
472 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
473 testFileHandler = open(testFile, 'r')
474 testFileList = testFileHandler.readlines()
475 testFileHandler.close()
476 #self.TOTAL_TC_PLANNED = 0
477 counter = 0
478 for index in range(len(testFileList)):
479 lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
480 if lineMatch:
481 counter = counter + 1
Jon Halla1185982014-09-15 14:55:10 -0700482 self.TC_PLANNED = len(self.testcases_list)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700483
adminbae64d82013-08-01 10:50:15 -0700484 def response_parser(self,response, return_format):
485 ''' It will load the default response parser '''
486 response_dict = {}
487 response_dict = self.response_to_dict(response, return_format)
Jon Halld61331b2015-02-17 16:35:47 -0800488 return_format_string = self.dict_to_return_format(response,return_format,response_dict)
adminbae64d82013-08-01 10:50:15 -0700489 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700490
adminbae64d82013-08-01 10:50:15 -0700491 def response_to_dict(self,response,return_format):
adminbae64d82013-08-01 10:50:15 -0700492 response_dict = {}
493 json_match = re.search('^\s*{', response)
494 xml_match = re.search('^\s*\<', response)
495 ini_match = re.search('^\s*\[', response)
496 if json_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800497 self.log.info(" Response is in 'JSON' format and Converting to '"+return_format+"' format")
Jon Halld61331b2015-02-17 16:35:47 -0800498 # Formatting the json string
adminbae64d82013-08-01 10:50:15 -0700499 response = re.sub(r"{\s*'?(\w)", r'{"\1', response)
500 response = re.sub(r",\s*'?(\w)", r',"\1', response)
501 response = re.sub(r"(\w)'?\s*:", r'\1":', response)
502 response = re.sub(r":\s*'(\w)'\s*([,}])", r':"\1"\2', response)
adminbae64d82013-08-01 10:50:15 -0700503 try :
504 import json
505 response_dict = json.loads(response)
Jon Hall30b82fa2015-03-04 17:15:43 -0800506 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800507 self.log.exception( e )
508 self.log.error("Json Parser is unable to parse the string")
adminbae64d82013-08-01 10:50:15 -0700509 return response_dict
adminbae64d82013-08-01 10:50:15 -0700510 elif ini_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800511 self.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700512 from configobj import ConfigObj
513 response_file = open("respnse_file.temp",'w')
514 response_file.write(response)
Jon Halld61331b2015-02-17 16:35:47 -0800515 response_file.close()
adminbae64d82013-08-01 10:50:15 -0700516 response_dict = ConfigObj("respnse_file.temp")
517 return response_dict
adminbae64d82013-08-01 10:50:15 -0700518 elif xml_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800519 self.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700520 try :
adminbae64d82013-08-01 10:50:15 -0700521 response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
522 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800523 self.log.exception( e )
adminbae64d82013-08-01 10:50:15 -0700524 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700525
adminbae64d82013-08-01 10:50:15 -0700526 def dict_to_return_format(self,response,return_format,response_dict):
adminbae64d82013-08-01 10:50:15 -0700527 if return_format =='table' :
528 ''' Will return in table format'''
529 to_do = "Call the table output formatter"
530 global response_table
531 response_table = '\n'
532 response_table = response_table +'\t'.join(response_dict)+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700533
adminbae64d82013-08-01 10:50:15 -0700534 def get_table(value_to_convert):
535 ''' This will parse the dictionary recusrsively and print as table format'''
536 table_data = ""
537 if type(value_to_convert) == dict :
538 table_data = table_data +'\t'.join(value_to_convert)+"\n"
539 for temp_val in value_to_convert.values() :
540 table_data = table_data + get_table(temp_val)
541 else :
542 table_data = table_data + str(value_to_convert) +"\t"
Jon Halld61331b2015-02-17 16:35:47 -0800543 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700544
adminbae64d82013-08-01 10:50:15 -0700545 for value in response_dict.values() :
546 response_table = response_table + get_table(value)
Jon Hall88e498c2015-03-06 09:54:35 -0800547 # response_table = response_table + '\t'.join(response_dict.values())
adminbae64d82013-08-01 10:50:15 -0700548 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700549
adminbae64d82013-08-01 10:50:15 -0700550 elif return_format =='config':
551 ''' Will return in config format'''
552 to_do = 'Call dict to config coverter'
553 response_string = str(response_dict)
554 print response_string
555 response_config = re.sub(",", "\n\t", response_string)
556 response_config = re.sub("u\'", "\'", response_config)
557 response_config = re.sub("{", "", response_config)
558 response_config = re.sub("}", "\n", response_config)
559 response_config = re.sub(":", " =", response_config)
560 return "[response]\n\t "+response_config
adminbae64d82013-08-01 10:50:15 -0700561 elif return_format == 'xml':
562 ''' Will return in xml format'''
adminbae64d82013-08-01 10:50:15 -0700563 response_xml = xmldict.dict_to_xml(response_dict)
564 response_xml = re.sub(">\s*<", ">\n<", response_xml)
565 return "\n"+response_xml
adminbae64d82013-08-01 10:50:15 -0700566 elif return_format == 'json':
567 ''' Will return in json format'''
568 to_do = 'Call dict to xml coverter'
569 import json
570 response_json = json.dumps(response_dict)
571 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700572
adminbae64d82013-08-01 10:50:15 -0700573 def get_random(self):
574 self.random_order = self.random_order + 1
575 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700576
adminbae64d82013-08-01 10:50:15 -0700577 def exit(self):
578 __builtin__.testthread = None
579 sys.exit()
580
581def verifyOptions(options):
582 '''
583 This will verify the command line options and set to default values, if any option not given in command line.
584 '''
585 import pprint
586 pp = pprint.PrettyPrinter(indent=4)
587
Jon Hall88e498c2015-03-06 09:54:35 -0800588 # pp.pprint(options)
adminbae64d82013-08-01 10:50:15 -0700589 verifyTest(options)
590 verifyExample(options)
591 verifyTestScript(options)
592 verifyParams()
593 verifyLogdir(options)
594 verifyMail(options)
595 verifyTestCases(options)
596
597def verifyTest(options):
598 if options.testname:
599 main.TEST = options.testname
600 main.classPath = "tests."+main.TEST+"."+main.TEST
601 main.tests_path = tests_path
602 elif options.example :
603 main.TEST = options.example
604 main.tests_path = path+"/examples/"
605 main.classPath = "examples."+main.TEST+"."+main.TEST
606 else :
607 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
608 self.exit()
609
610def verifyExample(options):
611 if options.example:
612 main.testDir = path+'/examples/'
613 main.tests_path = path+"/examples/"
614 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700615
adminbae64d82013-08-01 10:50:15 -0700616def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800617 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700618 if options.logdir:
619 main.logdir = options.logdir
620 else :
Jon Halld61331b2015-02-17 16:35:47 -0800621 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700622
adminbae64d82013-08-01 10:50:15 -0700623def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800624 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700625 if options.mail:
626 main.mail = options.mail
627 elif main.params.has_key('mail'):
628 main.mail = main.params['mail']
629 else :
630 main.mail = 'paxweb@paxterrasolutions.com'
631
632def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800633 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700634 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800635 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800636 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700637 testcases_list = re.sub("(\[|\])", "", options.testcases)
638 main.testcases_list = eval(testcases_list+",")
639 else :
640 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700641 temp = eval(main.params['testcases']+",")
642 list1=[]
643 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800644 for test in temp:
645 for testcase in test:
646 if type(testcase)==int:
647 testcase=[testcase]
648 list1.extend(testcase)
649 else :
650 temp=list(temp)
651 for testcase in temp:
652 if type(testcase)==int:
653 testcase=[testcase]
654 list1.extend(testcase)
655 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700656 else :
657 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800658 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700659
adminbae64d82013-08-01 10:50:15 -0700660def verifyTestScript(options):
661 '''
662 Verifyies test script.
663 '''
Jon Halld61331b2015-02-17 16:35:47 -0800664 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700665 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
666 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
667 if os.path.exists(openspeakfile) :
668 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
669 elif os.path.exists(testfile):
670 print ''
671 else:
672 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
673 __builtin__.testthread = None
674 main.exit()
adminbae64d82013-08-01 10:50:15 -0700675 try :
adminbae64d82013-08-01 10:50:15 -0700676 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
677 except(ImportError):
Jon Hallf8ecf732014-12-02 21:14:16 -0500678 print "There was an import error, it might mean that there is no test like "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800679 main.exit()
adminbae64d82013-08-01 10:50:15 -0700680
681 testClass = getattr(testModule, main.TEST)
682 main.testObject = testClass()
683 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800684 main.params = main.parser.parseParams(main.classPath)
685 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700686
adminbae64d82013-08-01 10:50:15 -0700687def verifyParams():
688 try :
689 main.params = main.params['PARAMS']
690 except(KeyError):
691 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800692 main.exit()
adminbae64d82013-08-01 10:50:15 -0700693 try :
694 main.topology = main.topology['TOPOLOGY']
695 except(KeyError):
696 print "Error with the Topology file: Either the file not specified or the format is not correct"
697 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700698
adminbae64d82013-08-01 10:50:15 -0700699def load_parser() :
700 '''
701 It facilitates the loading customised parser for topology and params file.
702 It loads parser mentioned in tab named parser of teston.cfg file.
703 It also loads default xmlparser if no parser have specified in teston.cfg file.
704
705 '''
706 confighash = main.configDict
707 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
708 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
709 if os.path.exists(confighash['config']['parser']['file']) :
710 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
711 moduleList = module.split("/")
712 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
713 try :
714 parsingClass = confighash['config']['parser']['class']
715 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
716 parsingClass = getattr(parsingModule, parsingClass)
717 main.parser = parsingClass()
718 #hashobj = main.parser.parseParams(main.classPath)
719 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
adminbae64d82013-08-01 10:50:15 -0700720 pass
721 else:
722 main.exit()
adminbae64d82013-08-01 10:50:15 -0700723 except ImportError:
724 print sys.exc_info()[1]
725 main.exit()
726 else :
727 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
Jon Halld61331b2015-02-17 16:35:47 -0800728 load_defaultParser()
729 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
730 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700731 else:
732 load_defaultParser()
733
734def load_defaultParser():
735 '''
736 It will load the default parser which is xml parser to parse the params and topology file.
737 '''
738 moduleList = main.parserPath.split("/")
739 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
740 try :
Jon Halld61331b2015-02-17 16:35:47 -0800741 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700742 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
743 parsingClass = getattr(parsingModule, parsingClass)
744 main.parser = parsingClass()
745 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
746 pass
747 else:
748 main.exit()
749
750 except ImportError:
751 print sys.exc_info()[1]
752
adminbae64d82013-08-01 10:50:15 -0700753def load_logger() :
754 '''
755 It facilitates the loading customised parser for topology and params file.
756 It loads parser mentioned in tab named parser of teston.cfg file.
757 It also loads default xmlparser if no parser have specified in teston.cfg file.
758
759 '''
760 confighash = main.configDict
761 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
762 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
763 if os.path.exists(confighash['config']['logger']['file']) :
764 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
765 moduleList = module.split("/")
766 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
767 try :
768 loggerClass = confighash['config']['logger']['class']
769 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
770 loggerClass = getattr(loggerModule, loggerClass)
771 main.logger = loggerClass()
772 #hashobj = main.parser.parseParams(main.classPath)
773
774 except ImportError:
775 print sys.exc_info()[1]
776 else :
777 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
778 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800779 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
780 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700781 else:
782 load_defaultlogger()
783
784def load_defaultlogger():
785 '''
786 It will load the default parser which is xml parser to parse the params and topology file.
787 '''
788 moduleList = main.loggerPath.split("/")
789 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
790 try :
Jon Halld61331b2015-02-17 16:35:47 -0800791 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700792 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
793 loggerClass = getattr(loggerModule, loggerClass)
794 main.logger = loggerClass()
795
796 except ImportError:
797 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800798 main.exit()
adminbae64d82013-08-01 10:50:15 -0700799
800def load_defaultlogger():
801 '''
802 It will load the default parser which is xml parser to parse the params and topology file.
803 '''
804 moduleList = main.loggerPath.split("/")
805 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
806 try :
Jon Halld61331b2015-02-17 16:35:47 -0800807 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700808 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
809 loggerClass = getattr(loggerModule, loggerClass)
810 main.logger = loggerClass()
811
812 except ImportError:
813 print sys.exc_info()[1]
814 main.exit()
815
adminbae64d82013-08-01 10:50:15 -0700816def _echo(self):
817 print "THIS IS ECHO"