blob: 2661715f2f9ee07acb7406d6501ee81cf3b9bd3c [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
jenkinsfa1cdbb2015-06-23 14:02:35 -0700166 if "OC" in self.componentDictionary[component]['host']:
167 try:
168 self.componentDictionary[component]['host'] = os.environ[str( self.componentDictionary[component]['host'])]
169 except KeyError:
170 self.log.info("Missing OC environment variable! Using stored IPs")
171 f = open("myIps","r")
172 ips = f.readlines()
173 for line in ips:
174 if self.componentDictionary[component]['host'] in line:
175 line = line.split("=")
176 myIp = line[1]
177 self.componentDictionary[component]['host'] = myIp
178 except Exception as inst:
179 self.log.error("Uncaught exception: " + str(inst))
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700180
adminbae64d82013-08-01 10:50:15 -0700181 connect_result = driverObject.connect(user_name = self.componentDictionary[component]['user'] if ('user' in self.componentDictionary[component].keys()) else getpass.getuser(),
182 ip_address= self.componentDictionary[component]['host'] if ('host' in self.componentDictionary[component].keys()) else 'localhost',
183 pwd = self.componentDictionary[component]['password'] if ('password' in self.componentDictionary[component].keys()) else 'changeme',
184 port = self.componentDictionary[component]['port'] if ('port' in self.componentDictionary[component].keys()) else None,
185 options = driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700186
adminbae64d82013-08-01 10:50:15 -0700187 if not connect_result:
188 self.log.error("Exiting form the test execution because the connecting to the "+component+" component failed.")
Jon Halld61331b2015-02-17 16:35:47 -0800189 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700190
adminbae64d82013-08-01 10:50:15 -0700191 vars(self)[component] = driverObject
kelvin-onlabf70fd542015-05-07 18:41:40 -0700192
adminbae64d82013-08-01 10:50:15 -0700193 def run(self):
194 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700195 The Execution of the test script's cases listed in the Test params file will be done here.
196 And Update each test case result.
197 This method will return TRUE if it executed all the test cases successfully,
adminbae64d82013-08-01 10:50:15 -0700198 else will retun FALSE
199 '''
adminbae64d82013-08-01 10:50:15 -0700200 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700201 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700202 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800203 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700204 self.TOTAL_TC_NORESULT = 0
205 self.TOTAL_TC_FAIL = 0
206 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700207 self.TEST_ITERATION = 0
adminbae64d82013-08-01 10:50:15 -0700208 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700209 self.CASERESULT = self.NORESULT
210
Jon Halld61331b2015-02-17 16:35:47 -0800211 import testparser
adminbae64d82013-08-01 10:50:15 -0700212 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
213 test = testparser.TestParser(testFile)
214 self.testscript = test.testscript
215 self.code = test.getStepCode()
Jon Hallfebb1c72015-03-05 13:30:09 -0800216 repeat= int(self.params['repeat']) if ('repeat' in self.params) else 1
217 self.TOTAL_TC_PLANNED = len(self.testcases_list)*repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700218
adminbae64d82013-08-01 10:50:15 -0700219 result = self.TRUE
Jon Hallfebb1c72015-03-05 13:30:09 -0800220 while(repeat):
Jon Halla1185982014-09-15 14:55:10 -0700221 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Halld61331b2015-02-17 16:35:47 -0800222 result = self.runCase(self.CurrentTestCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800223 repeat-=1
adminbae64d82013-08-01 10:50:15 -0700224 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700225
adminbae64d82013-08-01 10:50:15 -0700226 def runCase(self,testCaseNumber):
227 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700228 self.CurrentTestCase = ""
229 self.stepResults = []
230 self.stepName = ""
231 self.caseExplaination = ""
adminbae64d82013-08-01 10:50:15 -0700232 result = self.TRUE
233 self.stepCount = 0
234 self.EXPERIMENTAL_MODE = self.FALSE
235 self.addCaseHeader()
236 self.testCaseNumber = str(testCaseNumber)
237 stopped = False
238 try :
239 self.stepList = self.code[self.testCaseNumber].keys()
Jon Halld61331b2015-02-17 16:35:47 -0800240 except KeyError:
Jon Hallfebb1c72015-03-05 13:30:09 -0800241 self.log.error("There is no Test-Case "+ self.testCaseNumber)
242 return self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700243
adminbae64d82013-08-01 10:50:15 -0700244 self.stepCount = 0
245 while self.stepCount < len(self.code[self.testCaseNumber].keys()):
246 result = self.runStep(self.stepList,self.code,self.testCaseNumber)
Jon Hallfebb1c72015-03-05 13:30:09 -0800247 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700248 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800249 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700250 continue
adminbae64d82013-08-01 10:50:15 -0700251 if not stopped :
kelvin-onlabf70fd542015-05-07 18:41:40 -0700252 if all( self.TRUE == i for i in self.stepResults ):
253 # ALL PASSED
254 self.CASERESULT = self.TRUE
255 elif self.FALSE in self.stepResults:
256 # AT LEAST ONE FAILED
257 self.CASERESULT = self.FALSE
258 elif self.TRUE in self.stepResults:
259 # AT LEAST ONE PASSED
260 self.CASERESULT = self.TRUE
261 else:
262 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700263 self.testCaseResult[str(self.CurrentTestCaseNumber)] = self.CASERESULT
264 self.logger.updateCaseResults(self)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700265 self.log.wiki( "<p>" + self.caseExplaination + "</p>" )
266 self.log.summary( self.caseExplaination )
267 self.log.wiki( "<ul>" )
268 for line in self.stepCache.splitlines():
269 if re.search( " - PASS$", line ):
270 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
271 elif re.search( " - FAIL$", line ):
272 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
273 elif re.search( " - No Result$", line ):
274 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700275 else: # Should only be on fail message
276 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700277 self.log.wiki( "</ul>" )
278 self.log.summary( self.stepCache )
279 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700280 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700281
adminbae64d82013-08-01 10:50:15 -0700282 def runStep(self,stepList,code,testCaseNumber):
283 if not cli.pause:
284 try :
285 step = stepList[self.stepCount]
kelvin-onlabf70fd542015-05-07 18:41:40 -0700286 self.STEPRESULT = self.NORESULT
Jon Hall90627612015-06-09 14:57:02 -0700287 self.onFailMsg = "\t\tNo on fail message given"
adminbae64d82013-08-01 10:50:15 -0700288 exec code[testCaseNumber][step] in module.__dict__
289 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700290 if step > 0:
291 self.stepCache += "\t"+str(testCaseNumber)+"."+str(step)+" "+self.stepName+" - "
292 if self.STEPRESULT == self.TRUE:
293 self.stepCache += "PASS\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700294 elif self.STEPRESULT == self.FALSE:
295 self.stepCache += "FAIL\n"
Jon Hall8ce34e82015-06-05 10:41:45 -0700296 # TODO: Print the on-fail statement here
Jon Hall90627612015-06-09 14:57:02 -0700297 self.stepCache += "\t\t" + self.onFailMsg + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700298 else:
299 self.stepCache += "No Result\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700300 self.stepResults.append(self.STEPRESULT)
Jon Hall40d2cbd2015-06-03 16:24:29 -0700301 except StandardError as e:
302 self.log.exception( "\nException in the following section of" +
303 " code: " + str(testCaseNumber) + "." +
304 str(step) + ": " + self.stepName )
Jon Hall63604932015-02-26 17:09:50 -0800305 #print code[testCaseNumber][step]
adminbae64d82013-08-01 10:50:15 -0700306 self.stepCount = self.stepCount + 1
kelvin-onlabf70fd542015-05-07 18:41:40 -0700307 self.logger.updateCaseResults(self)
308 #WIKI results
309 self.log.wiki( "<ul>" )
310 for line in self.stepCache.splitlines():
311 if re.search( " - PASS$", line ):
312 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
313 elif re.search( " - FAIL$", line ):
314 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
315 elif re.search( " - No Result$", line ):
316 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700317 else: # Should only be on fail message
318 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700319 self.log.wiki( "</ul>" )
320 #summary results
321 self.log.summary( self.stepCache )
322 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700323 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700324 self.exit()
adminbae64d82013-08-01 10:50:15 -0700325 return main.TRUE
adminbae64d82013-08-01 10:50:15 -0700326 if cli.stop:
327 cli.stop = False
328 stopped = True
329 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
330 self.testCaseResult[str(self.CurrentTestCaseNumber)] = "Stopped"
331 self.logger.updateCaseResults(self)
332 result = self.cleanup()
333 return main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700334
adminbae64d82013-08-01 10:50:15 -0700335 def addCaseHeader(self):
336 caseHeader = "\n"+"*" * 30+"\n Result summary for Testcase"+str(self.CurrentTestCaseNumber)+"\n"+"*" * 30+"\n"
Jon Halld61331b2015-02-17 16:35:47 -0800337 self.log.exact(caseHeader)
338 caseHeader = "\n"+"*" * 40 +"\nStart of Test Case"+str(self.CurrentTestCaseNumber)+" : "
adminbae64d82013-08-01 10:50:15 -0700339 for driver in self.componentDictionary.keys():
340 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700341
adminbae64d82013-08-01 10:50:15 -0700342 def addCaseFooter(self):
343 if self.stepCount-1 > 0 :
344 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
345 stepHeader = "\n"+"*" * 40+"\nEnd of Step "+previousStep+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700346
adminbae64d82013-08-01 10:50:15 -0700347 caseFooter = "\n"+"*" * 40+"\nEnd of Test case "+str(self.CurrentTestCaseNumber)+"\n"+"*" * 40+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700348
adminbae64d82013-08-01 10:50:15 -0700349 for driver in self.driversList:
350 vars(self)[driver].write(stepHeader+"\n"+caseFooter)
351
352 def cleanup(self):
353 '''
354 Release all the component handles and the close opened file handles.
355 This will return TRUE if all the component handles and log handles closed properly,
356 else return FALSE
357
358 '''
359 result = self.TRUE
360 self.logger.testSummary(self)
Jon Halld61331b2015-02-17 16:35:47 -0800361
adminbae64d82013-08-01 10:50:15 -0700362 #self.reportFile.close()
Jon Halld61331b2015-02-17 16:35:47 -0800363
admin2c7034f2013-08-02 15:09:17 -0700364 #utilities.send_mail()
Jon Hall00539b12015-04-03 13:55:46 -0700365 for component in self.componentDictionary.keys():
366 try :
Jon Halld61331b2015-02-17 16:35:47 -0800367 tempObject = vars(self)[component]
Jon Hall1a77a1e2015-04-06 10:41:13 -0700368 print "Disconnecting from " + str(tempObject.name) + ": " + \
369 str(tempObject)
adminbae64d82013-08-01 10:50:15 -0700370 tempObject.disconnect()
Jon Halld61331b2015-02-17 16:35:47 -0800371 #tempObject.execute(cmd="exit",prompt="(.*)",timeout=120)
adminbae64d82013-08-01 10:50:15 -0700372
Jon Hall00539b12015-04-03 13:55:46 -0700373 except (Exception):
374 self.log.exception( "Exception while disconnecting from " +
375 str( component ) )
376 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700377 # Closing all the driver's session files
378 for driver in self.componentDictionary.keys():
379 vars(self)[driver].close_log_handles()
Jon Halld61331b2015-02-17 16:35:47 -0800380
adminbae64d82013-08-01 10:50:15 -0700381 return result
Jon Halld61331b2015-02-17 16:35:47 -0800382
adminbae64d82013-08-01 10:50:15 -0700383 def pause(self):
384 '''
385 This function will pause the test's execution, and will continue after user provide 'resume' command.
386 '''
387 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700388
adminbae64d82013-08-01 10:50:15 -0700389 def onfail(self,*components):
390 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700391 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700392 '''
adminbae64d82013-08-01 10:50:15 -0700393 if not components:
394 try :
395 for component in self.componentDictionary.keys():
396 tempObject = vars(self)[component]
397 result = tempObject.onfail()
398 except(Exception),e:
399 print str(e)
400 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700401 else:
402 try :
403 for component in components:
404 tempObject = vars(self)[component]
405 result = tempObject.onfail()
406 except(Exception),e:
407 print str(e)
408 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700409
adminbae64d82013-08-01 10:50:15 -0700410 def getDriverPath(self,driverName):
411 '''
412 Based on the component 'type' specified in the params , this method will find the absolute path ,
413 by recursively searching the name of the component.
414 '''
415 import commands
416
417 cmd = "find "+drivers_path+" -name "+driverName+".py"
418 result = commands.getoutput(cmd)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700419
adminbae64d82013-08-01 10:50:15 -0700420 result_array = str(result).split('\n')
421 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700422
adminbae64d82013-08-01 10:50:15 -0700423 for drivers_list in result_array:
424 result_count = result_count+1
425 if result_count > 1 :
426 print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
427 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700428
adminbae64d82013-08-01 10:50:15 -0700429 result = re.sub("(.*)drivers","",result)
430 result = re.sub("\.py","",result)
431 result = re.sub("\.pyc","",result)
432 result = re.sub("\/",".",result)
433 result = "drivers"+result
434 return result
adminbae64d82013-08-01 10:50:15 -0700435
436 def step(self,stepDesc):
437 '''
438 The step information of the test-case will append to the logs.
439 '''
440 previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
441 self.stepName = stepDesc
442
443 stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
444 try :
445 if self.stepCount == 0:
446 stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
447 except AttributeError:
448 stepName = " INIT : Initializing the test case :"+str(self.CurrentTestCaseNumber)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700449
adminbae64d82013-08-01 10:50:15 -0700450 self.log.step(stepName)
451 stepHeader = ""
452 if self.stepCount > 1 :
453 stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700454
Jon Halld61331b2015-02-17 16:35:47 -0800455 stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
adminbae64d82013-08-01 10:50:15 -0700456 for driver in self.componentDictionary.keys():
457 vars(self)[driver+'log'].info(stepHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700458
adminbae64d82013-08-01 10:50:15 -0700459 def case(self,testCaseName):
460 '''
461 Test's each test-case information will append to the logs.
462 '''
Jon Halld61331b2015-02-17 16:35:47 -0800463 self.CurrentTestCase = testCaseName
adminbae64d82013-08-01 10:50:15 -0700464 testCaseName = " " + str(testCaseName) + ""
465 self.log.case(testCaseName)
Jon Halld61331b2015-02-17 16:35:47 -0800466 caseHeader = testCaseName+"\n"+"*" * 40+"\n"
adminbae64d82013-08-01 10:50:15 -0700467 for driver in self.componentDictionary.keys():
468 vars(self)[driver+'log'].info(caseHeader)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700469
adminbae64d82013-08-01 10:50:15 -0700470 def testDesc(self,description):
471 '''
472 Test description will append to the logs.
473 '''
474 description = "Test Description : " + str (description) + ""
475 self.log.info(description)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700476
adminbae64d82013-08-01 10:50:15 -0700477 def _getTest(self):
478 '''
479 This method will parse the test script to find required test information.
480 '''
481 testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
482 testFileHandler = open(testFile, 'r')
483 testFileList = testFileHandler.readlines()
484 testFileHandler.close()
485 #self.TOTAL_TC_PLANNED = 0
486 counter = 0
487 for index in range(len(testFileList)):
488 lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
489 if lineMatch:
490 counter = counter + 1
Jon Halla1185982014-09-15 14:55:10 -0700491 self.TC_PLANNED = len(self.testcases_list)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700492
adminbae64d82013-08-01 10:50:15 -0700493 def response_parser(self,response, return_format):
494 ''' It will load the default response parser '''
495 response_dict = {}
496 response_dict = self.response_to_dict(response, return_format)
Jon Halld61331b2015-02-17 16:35:47 -0800497 return_format_string = self.dict_to_return_format(response,return_format,response_dict)
adminbae64d82013-08-01 10:50:15 -0700498 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700499
adminbae64d82013-08-01 10:50:15 -0700500 def response_to_dict(self,response,return_format):
adminbae64d82013-08-01 10:50:15 -0700501 response_dict = {}
502 json_match = re.search('^\s*{', response)
503 xml_match = re.search('^\s*\<', response)
504 ini_match = re.search('^\s*\[', response)
505 if json_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800506 self.log.info(" Response is in 'JSON' format and Converting to '"+return_format+"' format")
Jon Halld61331b2015-02-17 16:35:47 -0800507 # Formatting the json string
adminbae64d82013-08-01 10:50:15 -0700508 response = re.sub(r"{\s*'?(\w)", r'{"\1', response)
509 response = re.sub(r",\s*'?(\w)", r',"\1', response)
510 response = re.sub(r"(\w)'?\s*:", r'\1":', response)
511 response = re.sub(r":\s*'(\w)'\s*([,}])", r':"\1"\2', response)
adminbae64d82013-08-01 10:50:15 -0700512 try :
513 import json
514 response_dict = json.loads(response)
Jon Hall30b82fa2015-03-04 17:15:43 -0800515 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800516 self.log.exception( e )
517 self.log.error("Json Parser is unable to parse the string")
adminbae64d82013-08-01 10:50:15 -0700518 return response_dict
adminbae64d82013-08-01 10:50:15 -0700519 elif ini_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800520 self.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700521 from configobj import ConfigObj
522 response_file = open("respnse_file.temp",'w')
523 response_file.write(response)
Jon Halld61331b2015-02-17 16:35:47 -0800524 response_file.close()
adminbae64d82013-08-01 10:50:15 -0700525 response_dict = ConfigObj("respnse_file.temp")
526 return response_dict
adminbae64d82013-08-01 10:50:15 -0700527 elif xml_match :
Jon Hallfebb1c72015-03-05 13:30:09 -0800528 self.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
adminbae64d82013-08-01 10:50:15 -0700529 try :
adminbae64d82013-08-01 10:50:15 -0700530 response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
531 except Exception, e:
Jon Hallfebb1c72015-03-05 13:30:09 -0800532 self.log.exception( e )
adminbae64d82013-08-01 10:50:15 -0700533 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700534
adminbae64d82013-08-01 10:50:15 -0700535 def dict_to_return_format(self,response,return_format,response_dict):
adminbae64d82013-08-01 10:50:15 -0700536 if return_format =='table' :
537 ''' Will return in table format'''
538 to_do = "Call the table output formatter"
539 global response_table
540 response_table = '\n'
541 response_table = response_table +'\t'.join(response_dict)+"\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700542
adminbae64d82013-08-01 10:50:15 -0700543 def get_table(value_to_convert):
544 ''' This will parse the dictionary recusrsively and print as table format'''
545 table_data = ""
546 if type(value_to_convert) == dict :
547 table_data = table_data +'\t'.join(value_to_convert)+"\n"
548 for temp_val in value_to_convert.values() :
549 table_data = table_data + get_table(temp_val)
550 else :
551 table_data = table_data + str(value_to_convert) +"\t"
Jon Halld61331b2015-02-17 16:35:47 -0800552 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700553
adminbae64d82013-08-01 10:50:15 -0700554 for value in response_dict.values() :
555 response_table = response_table + get_table(value)
Jon Hall88e498c2015-03-06 09:54:35 -0800556 # response_table = response_table + '\t'.join(response_dict.values())
adminbae64d82013-08-01 10:50:15 -0700557 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700558
adminbae64d82013-08-01 10:50:15 -0700559 elif return_format =='config':
560 ''' Will return in config format'''
561 to_do = 'Call dict to config coverter'
562 response_string = str(response_dict)
563 print response_string
564 response_config = re.sub(",", "\n\t", response_string)
565 response_config = re.sub("u\'", "\'", response_config)
566 response_config = re.sub("{", "", response_config)
567 response_config = re.sub("}", "\n", response_config)
568 response_config = re.sub(":", " =", response_config)
569 return "[response]\n\t "+response_config
adminbae64d82013-08-01 10:50:15 -0700570 elif return_format == 'xml':
571 ''' Will return in xml format'''
adminbae64d82013-08-01 10:50:15 -0700572 response_xml = xmldict.dict_to_xml(response_dict)
573 response_xml = re.sub(">\s*<", ">\n<", response_xml)
574 return "\n"+response_xml
adminbae64d82013-08-01 10:50:15 -0700575 elif return_format == 'json':
576 ''' Will return in json format'''
577 to_do = 'Call dict to xml coverter'
578 import json
579 response_json = json.dumps(response_dict)
580 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700581
adminbae64d82013-08-01 10:50:15 -0700582 def get_random(self):
583 self.random_order = self.random_order + 1
584 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700585
adminbae64d82013-08-01 10:50:15 -0700586 def exit(self):
587 __builtin__.testthread = None
588 sys.exit()
589
590def verifyOptions(options):
591 '''
592 This will verify the command line options and set to default values, if any option not given in command line.
593 '''
594 import pprint
595 pp = pprint.PrettyPrinter(indent=4)
596
Jon Hall88e498c2015-03-06 09:54:35 -0800597 # pp.pprint(options)
adminbae64d82013-08-01 10:50:15 -0700598 verifyTest(options)
599 verifyExample(options)
600 verifyTestScript(options)
601 verifyParams()
602 verifyLogdir(options)
603 verifyMail(options)
604 verifyTestCases(options)
605
606def verifyTest(options):
607 if options.testname:
608 main.TEST = options.testname
609 main.classPath = "tests."+main.TEST+"."+main.TEST
610 main.tests_path = tests_path
611 elif options.example :
612 main.TEST = options.example
613 main.tests_path = path+"/examples/"
614 main.classPath = "examples."+main.TEST+"."+main.TEST
615 else :
616 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
617 self.exit()
618
619def verifyExample(options):
620 if options.example:
621 main.testDir = path+'/examples/'
622 main.tests_path = path+"/examples/"
623 main.classPath = "examples."+main.TEST+"."+main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700624
adminbae64d82013-08-01 10:50:15 -0700625def verifyLogdir(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800626 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700627 if options.logdir:
628 main.logdir = options.logdir
629 else :
Jon Halld61331b2015-02-17 16:35:47 -0800630 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700631
adminbae64d82013-08-01 10:50:15 -0700632def verifyMail(options):
Jon Halld61331b2015-02-17 16:35:47 -0800633 # Checking the mailing list
adminbae64d82013-08-01 10:50:15 -0700634 if options.mail:
635 main.mail = options.mail
636 elif main.params.has_key('mail'):
637 main.mail = main.params['mail']
638 else :
639 main.mail = 'paxweb@paxterrasolutions.com'
640
641def verifyTestCases(options):
Jon Hall88e498c2015-03-06 09:54:35 -0800642 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700643 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800644 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800645 # sys.exit()
adminbae64d82013-08-01 10:50:15 -0700646 testcases_list = re.sub("(\[|\])", "", options.testcases)
647 main.testcases_list = eval(testcases_list+",")
648 else :
649 if 'testcases' in main.params.keys():
Jon Halla1185982014-09-15 14:55:10 -0700650 temp = eval(main.params['testcases']+",")
651 list1=[]
652 if type(temp[0])==list:
Jon Hallfebb1c72015-03-05 13:30:09 -0800653 for test in temp:
654 for testcase in test:
655 if type(testcase)==int:
656 testcase=[testcase]
657 list1.extend(testcase)
658 else :
659 temp=list(temp)
660 for testcase in temp:
661 if type(testcase)==int:
662 testcase=[testcase]
663 list1.extend(testcase)
664 main.testcases_list=list1
adminbae64d82013-08-01 10:50:15 -0700665 else :
666 print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800667 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700668
adminbae64d82013-08-01 10:50:15 -0700669def verifyTestScript(options):
670 '''
671 Verifyies test script.
672 '''
Jon Halld61331b2015-02-17 16:35:47 -0800673 main.openspeak = openspeak.OpenSpeak()
adminbae64d82013-08-01 10:50:15 -0700674 openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
675 testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
676 if os.path.exists(openspeakfile) :
677 main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
678 elif os.path.exists(testfile):
679 print ''
680 else:
681 print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
682 __builtin__.testthread = None
683 main.exit()
adminbae64d82013-08-01 10:50:15 -0700684 try :
adminbae64d82013-08-01 10:50:15 -0700685 testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
686 except(ImportError):
Jon Hallf8ecf732014-12-02 21:14:16 -0500687 print "There was an import error, it might mean that there is no test like "+main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800688 main.exit()
adminbae64d82013-08-01 10:50:15 -0700689
690 testClass = getattr(testModule, main.TEST)
691 main.testObject = testClass()
692 load_parser()
Jon Halld61331b2015-02-17 16:35:47 -0800693 main.params = main.parser.parseParams(main.classPath)
694 main.topology = main.parser.parseTopology(main.classPath)
kelvin-onlabf70fd542015-05-07 18:41:40 -0700695
adminbae64d82013-08-01 10:50:15 -0700696def verifyParams():
697 try :
698 main.params = main.params['PARAMS']
699 except(KeyError):
700 print "Error with the params file: Either the file not specified or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800701 main.exit()
adminbae64d82013-08-01 10:50:15 -0700702 try :
703 main.topology = main.topology['TOPOLOGY']
704 except(KeyError):
705 print "Error with the Topology file: Either the file not specified or the format is not correct"
706 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700707
adminbae64d82013-08-01 10:50:15 -0700708def load_parser() :
709 '''
710 It facilitates the loading customised parser for topology and params file.
711 It loads parser mentioned in tab named parser of teston.cfg file.
712 It also loads default xmlparser if no parser have specified in teston.cfg file.
713
714 '''
715 confighash = main.configDict
716 if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
717 if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
718 if os.path.exists(confighash['config']['parser']['file']) :
719 module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
720 moduleList = module.split("/")
721 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
722 try :
723 parsingClass = confighash['config']['parser']['class']
724 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
725 parsingClass = getattr(parsingModule, parsingClass)
726 main.parser = parsingClass()
727 #hashobj = main.parser.parseParams(main.classPath)
728 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
adminbae64d82013-08-01 10:50:15 -0700729 pass
730 else:
731 main.exit()
adminbae64d82013-08-01 10:50:15 -0700732 except ImportError:
733 print sys.exc_info()[1]
734 main.exit()
735 else :
736 print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
Jon Halld61331b2015-02-17 16:35:47 -0800737 load_defaultParser()
738 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
739 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700740 else:
741 load_defaultParser()
742
743def load_defaultParser():
744 '''
745 It will load the default parser which is xml parser to parse the params and topology file.
746 '''
747 moduleList = main.parserPath.split("/")
748 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
749 try :
Jon Halld61331b2015-02-17 16:35:47 -0800750 parsingClass = main.parsingClass
adminbae64d82013-08-01 10:50:15 -0700751 parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
752 parsingClass = getattr(parsingModule, parsingClass)
753 main.parser = parsingClass()
754 if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
755 pass
756 else:
757 main.exit()
758
759 except ImportError:
760 print sys.exc_info()[1]
761
adminbae64d82013-08-01 10:50:15 -0700762def load_logger() :
763 '''
764 It facilitates the loading customised parser for topology and params file.
765 It loads parser mentioned in tab named parser of teston.cfg file.
766 It also loads default xmlparser if no parser have specified in teston.cfg file.
767
768 '''
769 confighash = main.configDict
770 if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
771 if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
772 if os.path.exists(confighash['config']['logger']['file']) :
773 module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
774 moduleList = module.split("/")
775 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
776 try :
777 loggerClass = confighash['config']['logger']['class']
778 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
779 loggerClass = getattr(loggerModule, loggerClass)
780 main.logger = loggerClass()
781 #hashobj = main.parser.parseParams(main.classPath)
782
783 except ImportError:
784 print sys.exc_info()[1]
785 else :
786 print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
787 load_defaultlogger()
Jon Halld61331b2015-02-17 16:35:47 -0800788 elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
789 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -0700790 else:
791 load_defaultlogger()
792
793def load_defaultlogger():
794 '''
795 It will load the default parser which is xml parser to parse the params and topology file.
796 '''
797 moduleList = main.loggerPath.split("/")
798 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
799 try :
Jon Halld61331b2015-02-17 16:35:47 -0800800 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700801 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
802 loggerClass = getattr(loggerModule, loggerClass)
803 main.logger = loggerClass()
804
805 except ImportError:
806 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -0800807 main.exit()
adminbae64d82013-08-01 10:50:15 -0700808
809def load_defaultlogger():
810 '''
811 It will load the default parser which is xml parser to parse the params and topology file.
812 '''
813 moduleList = main.loggerPath.split("/")
814 newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
815 try :
Jon Halld61331b2015-02-17 16:35:47 -0800816 loggerClass = main.loggerClass
adminbae64d82013-08-01 10:50:15 -0700817 loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
818 loggerClass = getattr(loggerModule, loggerClass)
819 main.logger = loggerClass()
820
821 except ImportError:
822 print sys.exc_info()[1]
823 main.exit()
824
adminbae64d82013-08-01 10:50:15 -0700825def _echo(self):
826 print "THIS IS ECHO"