blob: 271c0dd0080a700faf1ba92486d039ea11769673 [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 = ""
Jon Halld61331b2015-02-17 16:35:47 -080082 self.EXPERIMENTAL_MODE = False
adminbae64d82013-08-01 10:50:15 -070083 self.test_target = None
84 self.lastcommand = None
Jon Halld61331b2015-02-17 16:35:47 -080085 self.testDir = tests_path
86 self.configFile = config_path + "teston.cfg"
adminbae64d82013-08-01 10:50:15 -070087 self.parsingClass = "xmlparser"
88 self.parserPath = core_path + "/xmlparser"
89 self.loggerPath = core_path + "/logger"
90 self.loggerClass = "Logger"
91 self.logs_path = logs_path
92 self.driver = ''
kelvin-onlabfb521662015-02-27 09:52:40 -080093 self.Thread = Thread
Jon Hall65844a32015-03-09 19:09:37 -070094
adminbae64d82013-08-01 10:50:15 -070095 self.configparser()
96 verifyOptions(options)
97 load_logger()
98 self.componentDictionary = {}
99 self.componentDictionary = self.topology ['COMPONENT']
100 self.driversList=[]
101 if type(self.componentDictionary) == str :
102 self.componentDictionary = dict(self.componentDictionary)
Jon Hall65844a32015-03-09 19:09:37 -0700103
adminbae64d82013-08-01 10:50:15 -0700104 for component in self.componentDictionary :
105 self.driversList.append(self.componentDictionary[component]['type'])
Jon Hall65844a32015-03-09 19:09:37 -0700106
adminbae64d82013-08-01 10:50:15 -0700107 self.driversList = list(set(self.driversList)) # Removing duplicates.
108 # Checking the test_target option set for the component or not
109 if type(self.componentDictionary) == dict:
110 for component in self.componentDictionary.keys():
111 if 'test_target' in self.componentDictionary[component].keys():
112 self.test_target = component
Jon Hall65844a32015-03-09 19:09:37 -0700113
Jon Halld61331b2015-02-17 16:35:47 -0800114 # Checking for the openspeak file and test script
adminbae64d82013-08-01 10:50:15 -0700115 self.logger.initlog(self)
116
117 # Creating Drivers Handles
118 initString = "\n"+"*" * 30+"\n CASE INIT \n"+"*" * 30+"\n"
119 self.log.exact(initString)
120 self.driverObject = {}
121 self.random_order = 111 # Random order id to connect the components
122 components_connect_order = {}
123 #component_list.append()
124 if type(self.componentDictionary) == dict:
125 for component in self.componentDictionary.keys():
126 self.componentDictionary[component]['connect_order'] = self.componentDictionary[component]['connect_order'] if ('connect_order' in self.componentDictionary[component].keys()) else str(self.get_random())
127 components_connect_order[component] = eval(self.componentDictionary[component]['connect_order'])
128 #Ordering components based on the connect order.
129 ordered_component_list =sorted(components_connect_order, key=lambda key: components_connect_order[key])
130 print ordered_component_list
adminbae64d82013-08-01 10:50:15 -0700131 for component in ordered_component_list:
132 self.componentInit(component)
133
134 def configparser(self):
135 '''
136 It will parse the config file (teston.cfg) and return as dictionary
137 '''
138 matchFileName = re.match(r'(.*)\.cfg', self.configFile, re.M | re.I)
139 if matchFileName:
140 xml = open(self.configFile).read()
141 try :
142 self.configDict = xmldict.xml_to_dict(xml)
143 return self.configDict
Jon Hallfebb1c72015-03-05 13:30:09 -0800144 except Exception:
adminbae64d82013-08-01 10:50:15 -0700145 print "There is no such file to parse " + self.configFile
kelvin-onlabf70fd542015-05-07 18:41:40 -0700146
adminbae64d82013-08-01 10:50:15 -0700147 def componentInit(self,component):
148 '''
149 This method will initialize specified component
150 '''
151 global driver_options
152 self.log.info("Creating component Handle: "+component)
Jon Halld61331b2015-02-17 16:35:47 -0800153 driver_options = {}
adminbae64d82013-08-01 10:50:15 -0700154 if 'COMPONENTS' in self.componentDictionary[component].keys():
155 driver_options =dict(self.componentDictionary[component]['COMPONENTS'])
156
157 driver_options['name']=component
158 driverName = self.componentDictionary[component]['type']
159 driver_options ['type'] = driverName
kelvin-onlabf70fd542015-05-07 18:41:40 -0700160
adminbae64d82013-08-01 10:50:15 -0700161 classPath = self.getDriverPath(driverName.lower())
Jon Hall30b82fa2015-03-04 17:15:43 -0800162 driverModule = importlib.import_module(classPath)
adminbae64d82013-08-01 10:50:15 -0700163 driverClass = getattr(driverModule, driverName)
164 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700165
kelvin-onlab0a28a742015-05-18 16:03:13 -0700166 try:
167 self.componentDictionary[component]['host'] = os.environ[str( self.componentDictionary[component]['host'])]
168 except KeyError:
169 self.log.info("Missing OC environment variable! Using stored IPs")
170 except Exception as inst:
171 self.log.error("Uncaught exception: " + str(inst))
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700172
adminbae64d82013-08-01 10:50:15 -0700173 connect_result = driverObject.connect(user_name = self.componentDictionary[component]['user'] if ('user' in self.componentDictionary[component].keys()) else getpass.getuser(),
174 ip_address= self.componentDictionary[component]['host'] if ('host' in self.componentDictionary[component].keys()) else 'localhost',
175 pwd = self.componentDictionary[component]['password'] if ('password' in self.componentDictionary[component].keys()) else 'changeme',
176 port = self.componentDictionary[component]['port'] if ('port' in self.componentDictionary[component].keys()) else None,
177 options = driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700178
adminbae64d82013-08-01 10:50:15 -0700179 if not connect_result:
180 self.log.error("Exiting form the test execution because the connecting to the "+component+" component failed.")
Jon Halld61331b2015-02-17 16:35:47 -0800181 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700182
adminbae64d82013-08-01 10:50:15 -0700183 vars(self)[component] = driverObject
kelvin-onlabf70fd542015-05-07 18:41:40 -0700184
adminbae64d82013-08-01 10:50:15 -0700185 def run(self):
186 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700187 The Execution of the test script's cases listed in the Test params file will be done here.
188 And Update each test case result.
189 This method will return TRUE if it executed all the test cases successfully,
adminbae64d82013-08-01 10:50:15 -0700190 else will retun FALSE
191 '''
adminbae64d82013-08-01 10:50:15 -0700192 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700193 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700194 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800195 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700196 self.TOTAL_TC_NORESULT = 0
197 self.TOTAL_TC_FAIL = 0
198 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700199 self.TEST_ITERATION = 0
adminbae64d82013-08-01 10:50:15 -0700200 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700201 self.CASERESULT = self.NORESULT
202
Jon Halld61331b2015-02-17 16:35:47 -0800203 import testparser
adminbae64d82013-08-01 10:50:15 -0700204 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
205 test = testparser.TestParser(testFile)
206 self.testscript = test.testscript
207 self.code = test.getStepCode()
Jon Hallfebb1c72015-03-05 13:30:09 -0800208 repeat= int(self.params['repeat']) if ('repeat' in self.params) else 1
209 self.TOTAL_TC_PLANNED = len(self.testcases_list)*repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700210
adminbae64d82013-08-01 10:50:15 -0700211 result = self.TRUE
Jon Hallfebb1c72015-03-05 13:30:09 -0800212 while(repeat):
Jon Halla1185982014-09-15 14:55:10 -0700213 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Halld61331b2015-02-17 16:35:47 -0800214 result = self.runCase(self.CurrentTestCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800215 repeat-=1
adminbae64d82013-08-01 10:50:15 -0700216 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700217
adminbae64d82013-08-01 10:50:15 -0700218 def runCase(self,testCaseNumber):
219 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700220 self.CurrentTestCase = ""
221 self.stepResults = []
222 self.stepName = ""
223 self.caseExplaination = ""
adminbae64d82013-08-01 10:50:15 -0700224 result = self.TRUE
225 self.stepCount = 0
226 self.EXPERIMENTAL_MODE = self.FALSE
227 self.addCaseHeader()
228 self.testCaseNumber = str(testCaseNumber)
229 stopped = False
230 try :
231 self.stepList = self.code[self.testCaseNumber].keys()
Jon Halld61331b2015-02-17 16:35:47 -0800232 except KeyError:
Jon Hallfebb1c72015-03-05 13:30:09 -0800233 self.log.error("There is no Test-Case "+ self.testCaseNumber)
234 return self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700235
adminbae64d82013-08-01 10:50:15 -0700236 self.stepCount = 0
237 while self.stepCount < len(self.code[self.testCaseNumber].keys()):
238 result = self.runStep(self.stepList,self.code,self.testCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800239 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700240 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800241 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700242 continue
adminbae64d82013-08-01 10:50:15 -0700243 if not stopped :
kelvin-onlabf70fd542015-05-07 18:41:40 -0700244 if all( self.TRUE == i for i in self.stepResults ):
245 # ALL PASSED
246 self.CASERESULT = self.TRUE
247 elif self.FALSE in self.stepResults:
248 # AT LEAST ONE FAILED
249 self.CASERESULT = self.FALSE
250 elif self.TRUE in self.stepResults:
251 # AT LEAST ONE PASSED
252 self.CASERESULT = self.TRUE
253 else:
254 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700255 self.testCaseResult[str(self.CurrentTestCaseNumber)] = self.CASERESULT
256 self.logger.updateCaseResults(self)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700257 self.log.wiki( "<p>" + self.caseExplaination + "</p>" )
258 self.log.summary( self.caseExplaination )
259 self.log.wiki( "<ul>" )
260 for line in self.stepCache.splitlines():
261 if re.search( " - PASS$", line ):
262 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
263 elif re.search( " - FAIL$", line ):
264 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
265 elif re.search( " - No Result$", line ):
266 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700267 else: # Should only be on fail message
268 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700269 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
Jon Hall90627612015-06-09 14:57:02 -0700279 self.onFailMsg = "\t\tNo on fail message given"
adminbae64d82013-08-01 10:50:15 -0700280 exec code[testCaseNumber][step] in module.__dict__
281 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700282 if step > 0:
283 self.stepCache += "\t"+str(testCaseNumber)+"."+str(step)+" "+self.stepName+" - "
284 if self.STEPRESULT == self.TRUE:
285 self.stepCache += "PASS\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700286 elif self.STEPRESULT == self.FALSE:
287 self.stepCache += "FAIL\n"
Jon Hall8ce34e82015-06-05 10:41:45 -0700288 # TODO: Print the on-fail statement here
Jon Hall90627612015-06-09 14:57:02 -0700289 self.stepCache += "\t\t" + self.onFailMsg + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700290 else:
291 self.stepCache += "No Result\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700292 self.stepResults.append(self.STEPRESULT)
Jon Hall40d2cbd2015-06-03 16:24:29 -0700293 except StandardError as e:
294 self.log.exception( "\nException in the following section of" +
295 " code: " + str(testCaseNumber) + "." +
296 str(step) + ": " + 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
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" )
Jon Hall90627612015-06-09 14:57:02 -0700309 else: # Should only be on fail message
310 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700311 self.log.wiki( "</ul>" )
312 #summary results
313 self.log.summary( self.stepCache )
314 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700315 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700316 self.exit()
adminbae64d82013-08-01 10:50:15 -0700317 return main.TRUE
adminbae64d82013-08-01 10:50:15 -0700318 if cli.stop:
319 cli.stop = False
320 stopped = True
321 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
322 self.testCaseResult[str(self.CurrentTestCaseNumber)] = "Stopped"
323 self.logger.updateCaseResults(self)
324 result = self.cleanup()
325 return main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700326
adminbae64d82013-08-01 10:50:15 -0700327 def addCaseHeader(self):
328 caseHeader = "\n"+"*" * 30+"\n Result summary for Testcase"+str(self.CurrentTestCaseNumber)+"\n"+"*" * 30+"\n"
Jon Halld61331b2015-02-17 16:35:47 -0800329 self.log.exact(caseHeader)
330 caseHeader = "\n"+"*" * 40 +"\nStart of Test Case"+str(self.CurrentTestCaseNumber)+" : "
adminbae64d82013-08-01 10:50:15 -0700331 for driver in self.componentDictionary.keys():
332 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700333
adminbae64d82013-08-01 10:50:15 -0700334 def addCaseFooter(self):
335 if self.stepCount-1 > 0 :
336 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
337 stepHeader = "\n"+"*" * 40+"\nEnd of Step "+previousStep+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700338
adminbae64d82013-08-01 10:50:15 -0700339 caseFooter = "\n"+"*" * 40+"\nEnd of Test case "+str(self.CurrentTestCaseNumber)+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700340
adminbae64d82013-08-01 10:50:15 -0700341 for driver in self.driversList:
342 vars(self)[driver].write(stepHeader+"\n"+caseFooter)
343
344 def cleanup(self):
345 '''
346 Release all the component handles and the close opened file handles.
347 This will return TRUE if all the component handles and log handles closed properly,
348 else return FALSE
349
350 '''
351 result = self.TRUE
352 self.logger.testSummary(self)
Jon Halld61331b2015-02-17 16:35:47 -0800353
adminbae64d82013-08-01 10:50:15 -0700354 #self.reportFile.close()
Jon Halld61331b2015-02-17 16:35:47 -0800355
admin2c7034f2013-08-02 15:09:17 -0700356 #utilities.send_mail()
Jon Hall00539b12015-04-03 13:55:46 -0700357 for component in self.componentDictionary.keys():
358 try :
Jon Halld61331b2015-02-17 16:35:47 -0800359 tempObject = vars(self)[component]
Jon Hall1a77a1e2015-04-06 10:41:13 -0700360 print "Disconnecting from " + str(tempObject.name) + ": " + \
361 str(tempObject)
adminbae64d82013-08-01 10:50:15 -0700362 tempObject.disconnect()
Jon Halld61331b2015-02-17 16:35:47 -0800363 #tempObject.execute(cmd="exit",prompt="(.*)",timeout=120)
adminbae64d82013-08-01 10:50:15 -0700364
Jon Hall00539b12015-04-03 13:55:46 -0700365 except (Exception):
366 self.log.exception( "Exception while disconnecting from " +
367 str( component ) )
368 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700369 # Closing all the driver's session files
370 for driver in self.componentDictionary.keys():
371 vars(self)[driver].close_log_handles()
Jon Halld61331b2015-02-17 16:35:47 -0800372
adminbae64d82013-08-01 10:50:15 -0700373 return result
Jon Halld61331b2015-02-17 16:35:47 -0800374
adminbae64d82013-08-01 10:50:15 -0700375 def pause(self):
376 '''
377 This function will pause the test's execution, and will continue after user provide 'resume' command.
378 '''
379 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700380
adminbae64d82013-08-01 10:50:15 -0700381 def onfail(self,*components):
382 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700383 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700384 '''
adminbae64d82013-08-01 10:50:15 -0700385 if not components:
386 try :
387 for component in self.componentDictionary.keys():
388 tempObject = vars(self)[component]
389 result = tempObject.onfail()
390 except(Exception),e:
391 print str(e)
392 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700393 else:
394 try :
395 for component in components:
396 tempObject = vars(self)[component]
397 result = tempObject.onfail()
398 except(Exception),e:
399 print str(e)
400 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700401
adminbae64d82013-08-01 10:50:15 -0700402 def getDriverPath(self,driverName):
403 '''
404 Based on the component 'type' specified in the params , this method will find the absolute path ,
405 by recursively searching the name of the component.
406 '''
407 import commands
408
409 cmd = "find "+drivers_path+" -name "+driverName+".py"
410 result = commands.getoutput(cmd)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700411
adminbae64d82013-08-01 10:50:15 -0700412 result_array = str(result).split('\n')
413 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700414
adminbae64d82013-08-01 10:50:15 -0700415 for drivers_list in result_array:
416 result_count = result_count+1
417 if result_count > 1 :
418 print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
419 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700420
adminbae64d82013-08-01 10:50:15 -0700421 result = re.sub("(.*)drivers","",result)
422 result = re.sub("\.py","",result)
423 result = re.sub("\.pyc","",result)
424 result = re.sub("\/",".",result)
425 result = "drivers"+result
426 return result
adminbae64d82013-08-01 10:50:15 -0700427
428 def step(self,stepDesc):
429 '''
430 The step information of the test-case will append to the logs.
431 '''
432 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
433 self.stepName = stepDesc
434
435 stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
436 try :
437 if self.stepCount == 0:
438 stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
439 except AttributeError:
440 stepName = " INIT : Initializing the test case :"+str(self.CurrentTestCaseNumber)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700441
adminbae64d82013-08-01 10:50:15 -0700442 self.log.step(stepName)
443 stepHeader = ""
444 if self.stepCount > 1 :
445 stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700446
Jon Halld61331b2015-02-17 16:35:47 -0800447 stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
adminbae64d82013-08-01 10:50:15 -0700448 for driver in self.componentDictionary.keys():
449 vars(self)[driver+'log'].info(stepHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700450
adminbae64d82013-08-01 10:50:15 -0700451 def case(self,testCaseName):
452 '''
453 Test's each test-case information will append to the logs.
454 '''
Jon Halld61331b2015-02-17 16:35:47 -0800455 self.CurrentTestCase = testCaseName
adminbae64d82013-08-01 10:50:15 -0700456 testCaseName = " " + str(testCaseName) + ""
457 self.log.case(testCaseName)
Jon Halld61331b2015-02-17 16:35:47 -0800458 caseHeader = testCaseName+"\n"+"*" * 40+"\n"
adminbae64d82013-08-01 10:50:15 -0700459 for driver in self.componentDictionary.keys():
460 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700461
adminbae64d82013-08-01 10:50:15 -0700462 def testDesc(self,description):
463 '''
464 Test description will append to the logs.
465 '''
466 description = "Test Description : " + str (description) + ""
467 self.log.info(description)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700468
adminbae64d82013-08-01 10:50:15 -0700469 def _getTest(self):
470 '''
471 This method will parse the test script to find required test information.
472 '''
473 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
474 testFileHandler = open(testFile, 'r')
475 testFileList = testFileHandler.readlines()
476 testFileHandler.close()
477 #self.TOTAL_TC_PLANNED = 0
478 counter = 0
479 for index in range(len(testFileList)):
480 lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
481 if lineMatch:
482 counter = counter + 1
Jon Halla1185982014-09-15 14:55:10 -0700483 self.TC_PLANNED = len(self.testcases_list)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700484
adminbae64d82013-08-01 10:50:15 -0700485 def response_parser(self,response, return_format):
486 ''' It will load the default response parser '''
487 response_dict = {}
488 response_dict = self.response_to_dict(response, return_format)
Jon Halld61331b2015-02-17 16:35:47 -0800489 return_format_string = self.dict_to_return_format(response,return_format,response_dict)
adminbae64d82013-08-01 10:50:15 -0700490 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700491
adminbae64d82013-08-01 10:50:15 -0700492 def response_to_dict(self,response,return_format):
adminbae64d82013-08-01 10:50:15 -0700493 response_dict = {}
494 json_match = re.search('^\s*{', response)
495 xml_match = re.search('^\s*\<', response)
496 ini_match = re.search('^\s*\[', response)
497 if json_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800498 self.log.info(" Response is in 'JSON' format and Converting to '"+return_format+"' format")
Jon Halld61331b2015-02-17 16:35:47 -0800499 # Formatting the json string
adminbae64d82013-08-01 10:50:15 -0700500 response = re.sub(r"{\s*'?(\w)", r'{"\1', response)
501 response = re.sub(r",\s*'?(\w)", r',"\1', response)
502 response = re.sub(r"(\w)'?\s*:", r'\1":', response)
503 response = re.sub(r":\s*'(\w)'\s*([,}])", r':"\1"\2', response)
adminbae64d82013-08-01 10:50:15 -0700504 try :
505 import json
506 response_dict = json.loads(response)
Jon Hall30b82fa2015-03-04 17:15:43 -0800507 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800508 self.log.exception( e )
509 self.log.error("Json Parser is unable to parse the string")
adminbae64d82013-08-01 10:50:15 -0700510 return response_dict
adminbae64d82013-08-01 10:50:15 -0700511 elif ini_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800512 self.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700513 from configobj import ConfigObj
514 response_file = open("respnse_file.temp",'w')
515 response_file.write(response)
Jon Halld61331b2015-02-17 16:35:47 -0800516 response_file.close()
adminbae64d82013-08-01 10:50:15 -0700517 response_dict = ConfigObj("respnse_file.temp")
518 return response_dict
adminbae64d82013-08-01 10:50:15 -0700519 elif xml_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800520 self.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700521 try :
adminbae64d82013-08-01 10:50:15 -0700522 response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
523 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800524 self.log.exception( e )
adminbae64d82013-08-01 10:50:15 -0700525 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700526
adminbae64d82013-08-01 10:50:15 -0700527 def dict_to_return_format(self,response,return_format,response_dict):
adminbae64d82013-08-01 10:50:15 -0700528 if return_format =='table' :
529 ''' Will return in table format'''
530 to_do = "Call the table output formatter"
531 global response_table
532 response_table = '\n'
533 response_table = response_table +'\t'.join(response_dict)+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700534
adminbae64d82013-08-01 10:50:15 -0700535 def get_table(value_to_convert):
536 ''' This will parse the dictionary recusrsively and print as table format'''
537 table_data = ""
538 if type(value_to_convert) == dict :
539 table_data = table_data +'\t'.join(value_to_convert)+"\n"
540 for temp_val in value_to_convert.values() :
541 table_data = table_data + get_table(temp_val)
542 else :
543 table_data = table_data + str(value_to_convert) +"\t"
Jon Halld61331b2015-02-17 16:35:47 -0800544 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700545
adminbae64d82013-08-01 10:50:15 -0700546 for value in response_dict.values() :
547 response_table = response_table + get_table(value)
Jon Hall88e498c2015-03-06 09:54:35 -0800548 # response_table = response_table + '\t'.join(response_dict.values())
adminbae64d82013-08-01 10:50:15 -0700549 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700550
adminbae64d82013-08-01 10:50:15 -0700551 elif return_format =='config':
552 ''' Will return in config format'''
553 to_do = 'Call dict to config coverter'
554 response_string = str(response_dict)
555 print response_string
556 response_config = re.sub(",", "\n\t", response_string)
557 response_config = re.sub("u\'", "\'", response_config)
558 response_config = re.sub("{", "", response_config)
559 response_config = re.sub("}", "\n", response_config)
560 response_config = re.sub(":", " =", response_config)
561 return "[response]\n\t "+response_config
adminbae64d82013-08-01 10:50:15 -0700562 elif return_format == 'xml':
563 ''' Will return in xml format'''
adminbae64d82013-08-01 10:50:15 -0700564 response_xml = xmldict.dict_to_xml(response_dict)
565 response_xml = re.sub(">\s*<", ">\n<", response_xml)
566 return "\n"+response_xml
adminbae64d82013-08-01 10:50:15 -0700567 elif return_format == 'json':
568 ''' Will return in json format'''
569 to_do = 'Call dict to xml coverter'
570 import json
571 response_json = json.dumps(response_dict)
572 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700573
adminbae64d82013-08-01 10:50:15 -0700574 def get_random(self):
575 self.random_order = self.random_order + 1
576 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700577
adminbae64d82013-08-01 10:50:15 -0700578 def exit(self):
579 __builtin__.testthread = None
580 sys.exit()
581
582def verifyOptions(options):
583 '''
584 This will verify the command line options and set to default values, if any option not given in command line.
585 '''
586 import pprint
587 pp = pprint.PrettyPrinter(indent=4)
588
Jon Hall88e498c2015-03-06 09:54:35 -0800589 # pp.pprint(options)
adminbae64d82013-08-01 10:50:15 -0700590 verifyTest(options)
591 verifyExample(options)
592 verifyTestScript(options)
593 verifyParams()
594 verifyLogdir(options)
595 verifyMail(options)
596 verifyTestCases(options)
597
598def verifyTest(options):
599 if options.testname:
600 main.TEST = options.testname
601 main.classPath = "tests."+main.TEST+"."+main.TEST
602 main.tests_path = tests_path
603 elif options.example :
604 main.TEST = options.example
605 main.tests_path = path+"/examples/"
606 main.classPath = "examples."+main.TEST+"."+main.TEST
607 else :
608 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
609 self.exit()
610
611def verifyExample(options):
612 if options.example:
613 main.testDir = path+'/examples/'
614 main.tests_path = path+"/examples/"
615 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700616
adminbae64d82013-08-01 10:50:15 -0700617def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800618 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700619 if options.logdir:
620 main.logdir = options.logdir
621 else :
Jon Halld61331b2015-02-17 16:35:47 -0800622 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700623
adminbae64d82013-08-01 10:50:15 -0700624def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800625 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700626 if options.mail:
627 main.mail = options.mail
628 elif main.params.has_key('mail'):
629 main.mail = main.params['mail']
630 else :
631 main.mail = 'paxweb@paxterrasolutions.com'
632
633def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800634 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700635 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800636 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800637 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700638 testcases_list = re.sub("(\[|\])", "", options.testcases)
639 main.testcases_list = eval(testcases_list+",")
640 else :
641 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700642 temp = eval(main.params['testcases']+",")
643 list1=[]
644 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800645 for test in temp:
646 for testcase in test:
647 if type(testcase)==int:
648 testcase=[testcase]
649 list1.extend(testcase)
650 else :
651 temp=list(temp)
652 for testcase in temp:
653 if type(testcase)==int:
654 testcase=[testcase]
655 list1.extend(testcase)
656 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700657 else :
658 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800659 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700660
adminbae64d82013-08-01 10:50:15 -0700661def verifyTestScript(options):
662 '''
663 Verifyies test script.
664 '''
Jon Halld61331b2015-02-17 16:35:47 -0800665 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700666 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
667 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
668 if os.path.exists(openspeakfile) :
669 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
670 elif os.path.exists(testfile):
671 print ''
672 else:
673 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
674 __builtin__.testthread = None
675 main.exit()
adminbae64d82013-08-01 10:50:15 -0700676 try :
adminbae64d82013-08-01 10:50:15 -0700677 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
678 except(ImportError):
Jon Hallf8ecf732014-12-02 21:14:16 -0500679 print "There was an import error, it might mean that there is no test like "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800680 main.exit()
adminbae64d82013-08-01 10:50:15 -0700681
682 testClass = getattr(testModule, main.TEST)
683 main.testObject = testClass()
684 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800685 main.params = main.parser.parseParams(main.classPath)
686 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700687
adminbae64d82013-08-01 10:50:15 -0700688def verifyParams():
689 try :
690 main.params = main.params['PARAMS']
691 except(KeyError):
692 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800693 main.exit()
adminbae64d82013-08-01 10:50:15 -0700694 try :
695 main.topology = main.topology['TOPOLOGY']
696 except(KeyError):
697 print "Error with the Topology file: Either the file not specified or the format is not correct"
698 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700699
adminbae64d82013-08-01 10:50:15 -0700700def load_parser() :
701 '''
702 It facilitates the loading customised parser for topology and params file.
703 It loads parser mentioned in tab named parser of teston.cfg file.
704 It also loads default xmlparser if no parser have specified in teston.cfg file.
705
706 '''
707 confighash = main.configDict
708 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
709 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
710 if os.path.exists(confighash['config']['parser']['file']) :
711 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
712 moduleList = module.split("/")
713 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
714 try :
715 parsingClass = confighash['config']['parser']['class']
716 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
717 parsingClass = getattr(parsingModule, parsingClass)
718 main.parser = parsingClass()
719 #hashobj = main.parser.parseParams(main.classPath)
720 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
adminbae64d82013-08-01 10:50:15 -0700721 pass
722 else:
723 main.exit()
adminbae64d82013-08-01 10:50:15 -0700724 except ImportError:
725 print sys.exc_info()[1]
726 main.exit()
727 else :
728 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
Jon Halld61331b2015-02-17 16:35:47 -0800729 load_defaultParser()
730 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
731 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700732 else:
733 load_defaultParser()
734
735def load_defaultParser():
736 '''
737 It will load the default parser which is xml parser to parse the params and topology file.
738 '''
739 moduleList = main.parserPath.split("/")
740 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
741 try :
Jon Halld61331b2015-02-17 16:35:47 -0800742 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700743 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
744 parsingClass = getattr(parsingModule, parsingClass)
745 main.parser = parsingClass()
746 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
747 pass
748 else:
749 main.exit()
750
751 except ImportError:
752 print sys.exc_info()[1]
753
adminbae64d82013-08-01 10:50:15 -0700754def load_logger() :
755 '''
756 It facilitates the loading customised parser for topology and params file.
757 It loads parser mentioned in tab named parser of teston.cfg file.
758 It also loads default xmlparser if no parser have specified in teston.cfg file.
759
760 '''
761 confighash = main.configDict
762 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
763 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
764 if os.path.exists(confighash['config']['logger']['file']) :
765 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
766 moduleList = module.split("/")
767 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
768 try :
769 loggerClass = confighash['config']['logger']['class']
770 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
771 loggerClass = getattr(loggerModule, loggerClass)
772 main.logger = loggerClass()
773 #hashobj = main.parser.parseParams(main.classPath)
774
775 except ImportError:
776 print sys.exc_info()[1]
777 else :
778 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
779 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800780 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
781 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700782 else:
783 load_defaultlogger()
784
785def load_defaultlogger():
786 '''
787 It will load the default parser which is xml parser to parse the params and topology file.
788 '''
789 moduleList = main.loggerPath.split("/")
790 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
791 try :
Jon Halld61331b2015-02-17 16:35:47 -0800792 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700793 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
794 loggerClass = getattr(loggerModule, loggerClass)
795 main.logger = loggerClass()
796
797 except ImportError:
798 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800799 main.exit()
adminbae64d82013-08-01 10:50:15 -0700800
801def load_defaultlogger():
802 '''
803 It will load the default parser which is xml parser to parse the params and topology file.
804 '''
805 moduleList = main.loggerPath.split("/")
806 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
807 try :
Jon Halld61331b2015-02-17 16:35:47 -0800808 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700809 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
810 loggerClass = getattr(loggerModule, loggerClass)
811 main.logger = loggerClass()
812
813 except ImportError:
814 print sys.exc_info()[1]
815 main.exit()
816
adminbae64d82013-08-01 10:50:15 -0700817def _echo(self):
818 print "THIS IS ECHO"