blob: db17d8ed6180765abc12ca775589f53d755994c5 [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
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700168 if "OC" in self.componentDictionary[component]['host']:
cameron@onlab.usfa93ecf2015-05-13 16:13:46 -0700169 try:
170 self.componentDictionary[component]['host'] = os.environ[str( self.componentDictionary[component]['host'])]
171 except:
172 self.log.error("Missing OC environment variable! Check your environment setup and retry")
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700173
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
kelvin-onlabf70fd542015-05-07 18:41:40 -0700185
adminbae64d82013-08-01 10:50:15 -0700186 def run(self):
187 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700188 The Execution of the test script's cases listed in the Test params file will be done here.
189 And Update each test case result.
190 This method will return TRUE if it executed all the test cases successfully,
adminbae64d82013-08-01 10:50:15 -0700191 else will retun FALSE
192 '''
adminbae64d82013-08-01 10:50:15 -0700193 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700194 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700195 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800196 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700197 self.TOTAL_TC_NORESULT = 0
198 self.TOTAL_TC_FAIL = 0
199 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700200 self.TEST_ITERATION = 0
adminbae64d82013-08-01 10:50:15 -0700201 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700202 self.CASERESULT = self.NORESULT
203
Jon Halld61331b2015-02-17 16:35:47 -0800204 import testparser
adminbae64d82013-08-01 10:50:15 -0700205 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
206 test = testparser.TestParser(testFile)
207 self.testscript = test.testscript
208 self.code = test.getStepCode()
Jon Hallfebb1c72015-03-05 13:30:09 -0800209 repeat= int(self.params['repeat']) if ('repeat' in self.params) else 1
210 self.TOTAL_TC_PLANNED = len(self.testcases_list)*repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700211
adminbae64d82013-08-01 10:50:15 -0700212 result = self.TRUE
Jon Hallfebb1c72015-03-05 13:30:09 -0800213 while(repeat):
Jon Halla1185982014-09-15 14:55:10 -0700214 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Halld61331b2015-02-17 16:35:47 -0800215 result = self.runCase(self.CurrentTestCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800216 repeat-=1
adminbae64d82013-08-01 10:50:15 -0700217 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700218
adminbae64d82013-08-01 10:50:15 -0700219 def runCase(self,testCaseNumber):
220 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700221 self.CurrentTestCase = ""
222 self.stepResults = []
223 self.stepName = ""
224 self.caseExplaination = ""
adminbae64d82013-08-01 10:50:15 -0700225 result = self.TRUE
226 self.stepCount = 0
227 self.EXPERIMENTAL_MODE = self.FALSE
228 self.addCaseHeader()
229 self.testCaseNumber = str(testCaseNumber)
230 stopped = False
231 try :
232 self.stepList = self.code[self.testCaseNumber].keys()
Jon Halld61331b2015-02-17 16:35:47 -0800233 except KeyError:
Jon Hallfebb1c72015-03-05 13:30:09 -0800234 self.log.error("There is no Test-Case "+ self.testCaseNumber)
235 return self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700236
adminbae64d82013-08-01 10:50:15 -0700237 self.stepCount = 0
238 while self.stepCount < len(self.code[self.testCaseNumber].keys()):
239 result = self.runStep(self.stepList,self.code,self.testCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800240 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700241 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800242 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700243 continue
adminbae64d82013-08-01 10:50:15 -0700244 if not stopped :
kelvin-onlabf70fd542015-05-07 18:41:40 -0700245 if all( self.TRUE == i for i in self.stepResults ):
246 # ALL PASSED
247 self.CASERESULT = self.TRUE
248 elif self.FALSE in self.stepResults:
249 # AT LEAST ONE FAILED
250 self.CASERESULT = self.FALSE
251 elif self.TRUE in self.stepResults:
252 # AT LEAST ONE PASSED
253 self.CASERESULT = self.TRUE
254 else:
255 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700256 self.testCaseResult[str(self.CurrentTestCaseNumber)] = self.CASERESULT
257 self.logger.updateCaseResults(self)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700258 self.log.wiki( "<p>" + self.caseExplaination + "</p>" )
259 self.log.summary( self.caseExplaination )
260 self.log.wiki( "<ul>" )
261 for line in self.stepCache.splitlines():
262 if re.search( " - PASS$", line ):
263 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
264 elif re.search( " - FAIL$", line ):
265 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
266 elif re.search( " - No Result$", line ):
267 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
268 self.log.wiki( "</ul>" )
269 self.log.summary( self.stepCache )
270 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700271 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700272
adminbae64d82013-08-01 10:50:15 -0700273 def runStep(self,stepList,code,testCaseNumber):
274 if not cli.pause:
275 try :
276 step = stepList[self.stepCount]
kelvin-onlabf70fd542015-05-07 18:41:40 -0700277 self.STEPRESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700278 exec code[testCaseNumber][step] in module.__dict__
279 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700280 if step > 0:
281 self.stepCache += "\t"+str(testCaseNumber)+"."+str(step)+" "+self.stepName+" - "
282 if self.STEPRESULT == self.TRUE:
283 self.stepCache += "PASS\n"
284 #self.stepCache += "PASS <ac:emoticon ac:name=\"tick\" /></li>\n"
285 elif self.STEPRESULT == self.FALSE:
286 self.stepCache += "FAIL\n"
287 #self.stepCache += "FAIL <ac:emoticon ac:name=\"cross\" /></li>\n"
288 else:
289 self.stepCache += "No Result\n"
290 #self.stepCache += "No Result <ac:emoticon ac:name=\"warning\" /></li>\n"
291 self.stepResults.append(self.STEPRESULT)
adminbae64d82013-08-01 10:50:15 -0700292 except TypeError,e:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700293 print "\nException in the following section of code: " +\
294 str(testCaseNumber) + "." + str(step) + ": " +\
295 self.stepName
Jon Hall63604932015-02-26 17:09:50 -0800296 #print code[testCaseNumber][step]
adminbae64d82013-08-01 10:50:15 -0700297 self.stepCount = self.stepCount + 1
Jon Hall30b82fa2015-03-04 17:15:43 -0800298 self.log.exception(e)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700299 self.logger.updateCaseResults(self)
300 #WIKI results
301 self.log.wiki( "<ul>" )
302 for line in self.stepCache.splitlines():
303 if re.search( " - PASS$", line ):
304 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
305 elif re.search( " - FAIL$", line ):
306 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
307 elif re.search( " - No Result$", line ):
308 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
309 self.log.wiki( "</ul>" )
310 #summary results
311 self.log.summary( self.stepCache )
312 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700313 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700314 self.exit()
adminbae64d82013-08-01 10:50:15 -0700315 return main.TRUE
adminbae64d82013-08-01 10:50:15 -0700316 if cli.stop:
317 cli.stop = False
318 stopped = True
319 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
320 self.testCaseResult[str(self.CurrentTestCaseNumber)] = "Stopped"
321 self.logger.updateCaseResults(self)
322 result = self.cleanup()
323 return main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700324
adminbae64d82013-08-01 10:50:15 -0700325 def addCaseHeader(self):
326 caseHeader = "\n"+"*" * 30+"\n Result summary for Testcase"+str(self.CurrentTestCaseNumber)+"\n"+"*" * 30+"\n"
Jon Halld61331b2015-02-17 16:35:47 -0800327 self.log.exact(caseHeader)
328 caseHeader = "\n"+"*" * 40 +"\nStart of Test Case"+str(self.CurrentTestCaseNumber)+" : "
adminbae64d82013-08-01 10:50:15 -0700329 for driver in self.componentDictionary.keys():
330 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700331
adminbae64d82013-08-01 10:50:15 -0700332 def addCaseFooter(self):
333 if self.stepCount-1 > 0 :
334 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
335 stepHeader = "\n"+"*" * 40+"\nEnd of Step "+previousStep+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700336
adminbae64d82013-08-01 10:50:15 -0700337 caseFooter = "\n"+"*" * 40+"\nEnd of Test case "+str(self.CurrentTestCaseNumber)+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700338
adminbae64d82013-08-01 10:50:15 -0700339 for driver in self.driversList:
340 vars(self)[driver].write(stepHeader+"\n"+caseFooter)
341
342 def cleanup(self):
343 '''
344 Release all the component handles and the close opened file handles.
345 This will return TRUE if all the component handles and log handles closed properly,
346 else return FALSE
347
348 '''
349 result = self.TRUE
350 self.logger.testSummary(self)
Jon Halld61331b2015-02-17 16:35:47 -0800351
adminbae64d82013-08-01 10:50:15 -0700352 #self.reportFile.close()
Jon Halld61331b2015-02-17 16:35:47 -0800353
admin2c7034f2013-08-02 15:09:17 -0700354 #utilities.send_mail()
Jon Hall00539b12015-04-03 13:55:46 -0700355 for component in self.componentDictionary.keys():
356 try :
Jon Halld61331b2015-02-17 16:35:47 -0800357 tempObject = vars(self)[component]
Jon Hall1a77a1e2015-04-06 10:41:13 -0700358 print "Disconnecting from " + str(tempObject.name) + ": " + \
359 str(tempObject)
adminbae64d82013-08-01 10:50:15 -0700360 tempObject.disconnect()
Jon Halld61331b2015-02-17 16:35:47 -0800361 #tempObject.execute(cmd="exit",prompt="(.*)",timeout=120)
adminbae64d82013-08-01 10:50:15 -0700362
Jon Hall00539b12015-04-03 13:55:46 -0700363 except (Exception):
364 self.log.exception( "Exception while disconnecting from " +
365 str( component ) )
366 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700367 # Closing all the driver's session files
368 for driver in self.componentDictionary.keys():
369 vars(self)[driver].close_log_handles()
Jon Halld61331b2015-02-17 16:35:47 -0800370
adminbae64d82013-08-01 10:50:15 -0700371 return result
Jon Halld61331b2015-02-17 16:35:47 -0800372
adminbae64d82013-08-01 10:50:15 -0700373 def pause(self):
374 '''
375 This function will pause the test's execution, and will continue after user provide 'resume' command.
376 '''
377 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700378
adminbae64d82013-08-01 10:50:15 -0700379 def onfail(self,*components):
380 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700381 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700382 '''
adminbae64d82013-08-01 10:50:15 -0700383 if not components:
384 try :
385 for component in self.componentDictionary.keys():
386 tempObject = vars(self)[component]
387 result = tempObject.onfail()
388 except(Exception),e:
389 print str(e)
390 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700391 else:
392 try :
393 for component in components:
394 tempObject = vars(self)[component]
395 result = tempObject.onfail()
396 except(Exception),e:
397 print str(e)
398 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700399
adminbae64d82013-08-01 10:50:15 -0700400 def getDriverPath(self,driverName):
401 '''
402 Based on the component 'type' specified in the params , this method will find the absolute path ,
403 by recursively searching the name of the component.
404 '''
405 import commands
406
407 cmd = "find "+drivers_path+" -name "+driverName+".py"
408 result = commands.getoutput(cmd)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700409
adminbae64d82013-08-01 10:50:15 -0700410 result_array = str(result).split('\n')
411 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700412
adminbae64d82013-08-01 10:50:15 -0700413 for drivers_list in result_array:
414 result_count = result_count+1
415 if result_count > 1 :
416 print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
417 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700418
adminbae64d82013-08-01 10:50:15 -0700419 result = re.sub("(.*)drivers","",result)
420 result = re.sub("\.py","",result)
421 result = re.sub("\.pyc","",result)
422 result = re.sub("\/",".",result)
423 result = "drivers"+result
424 return result
adminbae64d82013-08-01 10:50:15 -0700425
426 def step(self,stepDesc):
427 '''
428 The step information of the test-case will append to the logs.
429 '''
430 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
431 self.stepName = stepDesc
432
433 stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
434 try :
435 if self.stepCount == 0:
436 stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
437 except AttributeError:
438 stepName = " INIT : Initializing the test case :"+str(self.CurrentTestCaseNumber)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700439
adminbae64d82013-08-01 10:50:15 -0700440 self.log.step(stepName)
441 stepHeader = ""
442 if self.stepCount > 1 :
443 stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700444
Jon Halld61331b2015-02-17 16:35:47 -0800445 stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
adminbae64d82013-08-01 10:50:15 -0700446 for driver in self.componentDictionary.keys():
447 vars(self)[driver+'log'].info(stepHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700448
adminbae64d82013-08-01 10:50:15 -0700449 def case(self,testCaseName):
450 '''
451 Test's each test-case information will append to the logs.
452 '''
Jon Halld61331b2015-02-17 16:35:47 -0800453 self.CurrentTestCase = testCaseName
adminbae64d82013-08-01 10:50:15 -0700454 testCaseName = " " + str(testCaseName) + ""
455 self.log.case(testCaseName)
Jon Halld61331b2015-02-17 16:35:47 -0800456 caseHeader = testCaseName+"\n"+"*" * 40+"\n"
adminbae64d82013-08-01 10:50:15 -0700457 for driver in self.componentDictionary.keys():
458 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700459
adminbae64d82013-08-01 10:50:15 -0700460 def testDesc(self,description):
461 '''
462 Test description will append to the logs.
463 '''
464 description = "Test Description : " + str (description) + ""
465 self.log.info(description)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700466
adminbae64d82013-08-01 10:50:15 -0700467 def _getTest(self):
468 '''
469 This method will parse the test script to find required test information.
470 '''
471 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
472 testFileHandler = open(testFile, 'r')
473 testFileList = testFileHandler.readlines()
474 testFileHandler.close()
475 #self.TOTAL_TC_PLANNED = 0
476 counter = 0
477 for index in range(len(testFileList)):
478 lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
479 if lineMatch:
480 counter = counter + 1
Jon Halla1185982014-09-15 14:55:10 -0700481 self.TC_PLANNED = len(self.testcases_list)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700482
adminbae64d82013-08-01 10:50:15 -0700483 def response_parser(self,response, return_format):
484 ''' It will load the default response parser '''
485 response_dict = {}
486 response_dict = self.response_to_dict(response, return_format)
Jon Halld61331b2015-02-17 16:35:47 -0800487 return_format_string = self.dict_to_return_format(response,return_format,response_dict)
adminbae64d82013-08-01 10:50:15 -0700488 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700489
adminbae64d82013-08-01 10:50:15 -0700490 def response_to_dict(self,response,return_format):
adminbae64d82013-08-01 10:50:15 -0700491 response_dict = {}
492 json_match = re.search('^\s*{', response)
493 xml_match = re.search('^\s*\<', response)
494 ini_match = re.search('^\s*\[', response)
495 if json_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800496 self.log.info(" Response is in 'JSON' format and Converting to '"+return_format+"' format")
Jon Halld61331b2015-02-17 16:35:47 -0800497 # Formatting the json string
adminbae64d82013-08-01 10:50:15 -0700498 response = re.sub(r"{\s*'?(\w)", r'{"\1', response)
499 response = re.sub(r",\s*'?(\w)", r',"\1', response)
500 response = re.sub(r"(\w)'?\s*:", r'\1":', response)
501 response = re.sub(r":\s*'(\w)'\s*([,}])", r':"\1"\2', response)
adminbae64d82013-08-01 10:50:15 -0700502 try :
503 import json
504 response_dict = json.loads(response)
Jon Hall30b82fa2015-03-04 17:15:43 -0800505 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800506 self.log.exception( e )
507 self.log.error("Json Parser is unable to parse the string")
adminbae64d82013-08-01 10:50:15 -0700508 return response_dict
adminbae64d82013-08-01 10:50:15 -0700509 elif ini_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800510 self.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700511 from configobj import ConfigObj
512 response_file = open("respnse_file.temp",'w')
513 response_file.write(response)
Jon Halld61331b2015-02-17 16:35:47 -0800514 response_file.close()
adminbae64d82013-08-01 10:50:15 -0700515 response_dict = ConfigObj("respnse_file.temp")
516 return response_dict
adminbae64d82013-08-01 10:50:15 -0700517 elif xml_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800518 self.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700519 try :
adminbae64d82013-08-01 10:50:15 -0700520 response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
521 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800522 self.log.exception( e )
adminbae64d82013-08-01 10:50:15 -0700523 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700524
adminbae64d82013-08-01 10:50:15 -0700525 def dict_to_return_format(self,response,return_format,response_dict):
adminbae64d82013-08-01 10:50:15 -0700526 if return_format =='table' :
527 ''' Will return in table format'''
528 to_do = "Call the table output formatter"
529 global response_table
530 response_table = '\n'
531 response_table = response_table +'\t'.join(response_dict)+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700532
adminbae64d82013-08-01 10:50:15 -0700533 def get_table(value_to_convert):
534 ''' This will parse the dictionary recusrsively and print as table format'''
535 table_data = ""
536 if type(value_to_convert) == dict :
537 table_data = table_data +'\t'.join(value_to_convert)+"\n"
538 for temp_val in value_to_convert.values() :
539 table_data = table_data + get_table(temp_val)
540 else :
541 table_data = table_data + str(value_to_convert) +"\t"
Jon Halld61331b2015-02-17 16:35:47 -0800542 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700543
adminbae64d82013-08-01 10:50:15 -0700544 for value in response_dict.values() :
545 response_table = response_table + get_table(value)
Jon Hall88e498c2015-03-06 09:54:35 -0800546 # response_table = response_table + '\t'.join(response_dict.values())
adminbae64d82013-08-01 10:50:15 -0700547 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700548
adminbae64d82013-08-01 10:50:15 -0700549 elif return_format =='config':
550 ''' Will return in config format'''
551 to_do = 'Call dict to config coverter'
552 response_string = str(response_dict)
553 print response_string
554 response_config = re.sub(",", "\n\t", response_string)
555 response_config = re.sub("u\'", "\'", response_config)
556 response_config = re.sub("{", "", response_config)
557 response_config = re.sub("}", "\n", response_config)
558 response_config = re.sub(":", " =", response_config)
559 return "[response]\n\t "+response_config
adminbae64d82013-08-01 10:50:15 -0700560 elif return_format == 'xml':
561 ''' Will return in xml format'''
adminbae64d82013-08-01 10:50:15 -0700562 response_xml = xmldict.dict_to_xml(response_dict)
563 response_xml = re.sub(">\s*<", ">\n<", response_xml)
564 return "\n"+response_xml
adminbae64d82013-08-01 10:50:15 -0700565 elif return_format == 'json':
566 ''' Will return in json format'''
567 to_do = 'Call dict to xml coverter'
568 import json
569 response_json = json.dumps(response_dict)
570 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700571
adminbae64d82013-08-01 10:50:15 -0700572 def get_random(self):
573 self.random_order = self.random_order + 1
574 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700575
adminbae64d82013-08-01 10:50:15 -0700576 def exit(self):
577 __builtin__.testthread = None
578 sys.exit()
579
580def verifyOptions(options):
581 '''
582 This will verify the command line options and set to default values, if any option not given in command line.
583 '''
584 import pprint
585 pp = pprint.PrettyPrinter(indent=4)
586
Jon Hall88e498c2015-03-06 09:54:35 -0800587 # pp.pprint(options)
adminbae64d82013-08-01 10:50:15 -0700588 verifyTest(options)
589 verifyExample(options)
590 verifyTestScript(options)
591 verifyParams()
592 verifyLogdir(options)
593 verifyMail(options)
594 verifyTestCases(options)
595
596def verifyTest(options):
597 if options.testname:
598 main.TEST = options.testname
599 main.classPath = "tests."+main.TEST+"."+main.TEST
600 main.tests_path = tests_path
601 elif options.example :
602 main.TEST = options.example
603 main.tests_path = path+"/examples/"
604 main.classPath = "examples."+main.TEST+"."+main.TEST
605 else :
606 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
607 self.exit()
608
609def verifyExample(options):
610 if options.example:
611 main.testDir = path+'/examples/'
612 main.tests_path = path+"/examples/"
613 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700614
adminbae64d82013-08-01 10:50:15 -0700615def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800616 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700617 if options.logdir:
618 main.logdir = options.logdir
619 else :
Jon Halld61331b2015-02-17 16:35:47 -0800620 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700621
adminbae64d82013-08-01 10:50:15 -0700622def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800623 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700624 if options.mail:
625 main.mail = options.mail
626 elif main.params.has_key('mail'):
627 main.mail = main.params['mail']
628 else :
629 main.mail = 'paxweb@paxterrasolutions.com'
630
631def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800632 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700633 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800634 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800635 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700636 testcases_list = re.sub("(\[|\])", "", options.testcases)
637 main.testcases_list = eval(testcases_list+",")
638 else :
639 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700640 temp = eval(main.params['testcases']+",")
641 list1=[]
642 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800643 for test in temp:
644 for testcase in test:
645 if type(testcase)==int:
646 testcase=[testcase]
647 list1.extend(testcase)
648 else :
649 temp=list(temp)
650 for testcase in temp:
651 if type(testcase)==int:
652 testcase=[testcase]
653 list1.extend(testcase)
654 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700655 else :
656 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800657 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700658
adminbae64d82013-08-01 10:50:15 -0700659def verifyTestScript(options):
660 '''
661 Verifyies test script.
662 '''
Jon Halld61331b2015-02-17 16:35:47 -0800663 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700664 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
665 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
666 if os.path.exists(openspeakfile) :
667 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
668 elif os.path.exists(testfile):
669 print ''
670 else:
671 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
672 __builtin__.testthread = None
673 main.exit()
adminbae64d82013-08-01 10:50:15 -0700674 try :
adminbae64d82013-08-01 10:50:15 -0700675 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
676 except(ImportError):
Jon Hallf8ecf732014-12-02 21:14:16 -0500677 print "There was an import error, it might mean that there is no test like "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800678 main.exit()
adminbae64d82013-08-01 10:50:15 -0700679
680 testClass = getattr(testModule, main.TEST)
681 main.testObject = testClass()
682 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800683 main.params = main.parser.parseParams(main.classPath)
684 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700685
adminbae64d82013-08-01 10:50:15 -0700686def verifyParams():
687 try :
688 main.params = main.params['PARAMS']
689 except(KeyError):
690 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800691 main.exit()
adminbae64d82013-08-01 10:50:15 -0700692 try :
693 main.topology = main.topology['TOPOLOGY']
694 except(KeyError):
695 print "Error with the Topology file: Either the file not specified or the format is not correct"
696 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700697
adminbae64d82013-08-01 10:50:15 -0700698def load_parser() :
699 '''
700 It facilitates the loading customised parser for topology and params file.
701 It loads parser mentioned in tab named parser of teston.cfg file.
702 It also loads default xmlparser if no parser have specified in teston.cfg file.
703
704 '''
705 confighash = main.configDict
706 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
707 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
708 if os.path.exists(confighash['config']['parser']['file']) :
709 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
710 moduleList = module.split("/")
711 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
712 try :
713 parsingClass = confighash['config']['parser']['class']
714 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
715 parsingClass = getattr(parsingModule, parsingClass)
716 main.parser = parsingClass()
717 #hashobj = main.parser.parseParams(main.classPath)
718 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
adminbae64d82013-08-01 10:50:15 -0700719 pass
720 else:
721 main.exit()
adminbae64d82013-08-01 10:50:15 -0700722 except ImportError:
723 print sys.exc_info()[1]
724 main.exit()
725 else :
726 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
Jon Halld61331b2015-02-17 16:35:47 -0800727 load_defaultParser()
728 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
729 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700730 else:
731 load_defaultParser()
732
733def load_defaultParser():
734 '''
735 It will load the default parser which is xml parser to parse the params and topology file.
736 '''
737 moduleList = main.parserPath.split("/")
738 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
739 try :
Jon Halld61331b2015-02-17 16:35:47 -0800740 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700741 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
742 parsingClass = getattr(parsingModule, parsingClass)
743 main.parser = parsingClass()
744 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
745 pass
746 else:
747 main.exit()
748
749 except ImportError:
750 print sys.exc_info()[1]
751
adminbae64d82013-08-01 10:50:15 -0700752def load_logger() :
753 '''
754 It facilitates the loading customised parser for topology and params file.
755 It loads parser mentioned in tab named parser of teston.cfg file.
756 It also loads default xmlparser if no parser have specified in teston.cfg file.
757
758 '''
759 confighash = main.configDict
760 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
761 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
762 if os.path.exists(confighash['config']['logger']['file']) :
763 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
764 moduleList = module.split("/")
765 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
766 try :
767 loggerClass = confighash['config']['logger']['class']
768 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
769 loggerClass = getattr(loggerModule, loggerClass)
770 main.logger = loggerClass()
771 #hashobj = main.parser.parseParams(main.classPath)
772
773 except ImportError:
774 print sys.exc_info()[1]
775 else :
776 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
777 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800778 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
779 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700780 else:
781 load_defaultlogger()
782
783def load_defaultlogger():
784 '''
785 It will load the default parser which is xml parser to parse the params and topology file.
786 '''
787 moduleList = main.loggerPath.split("/")
788 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
789 try :
Jon Halld61331b2015-02-17 16:35:47 -0800790 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700791 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
792 loggerClass = getattr(loggerModule, loggerClass)
793 main.logger = loggerClass()
794
795 except ImportError:
796 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800797 main.exit()
adminbae64d82013-08-01 10:50:15 -0700798
799def load_defaultlogger():
800 '''
801 It will load the default parser which is xml parser to parse the params and topology file.
802 '''
803 moduleList = main.loggerPath.split("/")
804 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
805 try :
Jon Halld61331b2015-02-17 16:35:47 -0800806 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700807 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
808 loggerClass = getattr(loggerModule, loggerClass)
809 main.logger = loggerClass()
810
811 except ImportError:
812 print sys.exc_info()[1]
813 main.exit()
814
adminbae64d82013-08-01 10:50:15 -0700815def _echo(self):
816 print "THIS IS ECHO"