blob: ce53f528e88b679eaded599a78dd0351cd6a7e66 [file] [log] [blame]
adminbae64d82013-08-01 10:50:15 -07001#!/usr/bin/env python
2'''
3Created on 22-Oct-2012
Jon Hall65844a32015-03-09 19:09:37 -07004
adminbae64d82013-08-01 10:50:15 -07005@author: Anil Kumar (anilkumar.s@paxterrasolutions.com)
6
7
8 TestON is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
12
13 TestON is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
Jon Hall65844a32015-03-09 19:09:37 -070019 along with TestON. If not, see <http://www.gnu.org/licenses/>.
adminbae64d82013-08-01 10:50:15 -070020
21
22
23teston is the main module.
24
25'''
26
27import sys
28import getpass
29import os
30import re
31import __builtin__
32import new
33import xmldict
Jon Hall30b82fa2015-03-04 17:15:43 -080034import importlib
Jon Hall5b586732015-06-11 11:39:39 -070035import threading
Jon Hall714eeba2015-09-29 17:53:10 -070036module = new.module( "test" )
adminbae64d82013-08-01 10:50:15 -070037import openspeak
Hari Krishnabe4b97b2015-07-15 12:19:43 -070038import subprocess
Jon Hall714eeba2015-09-29 17:53:10 -070039global path, drivers_path, core_path, tests_path, logs_path
Jon Hall44506242015-07-29 17:40:26 -070040location = os.path.abspath( os.path.dirname( __file__ ) )
41path = re.sub( "(core|bin)$", "", location )
Jon Hall714eeba2015-09-29 17:53:10 -070042drivers_path = path + "drivers"
43core_path = path + "core"
44tests_path = path + "tests"
45logs_path = path + "logs/"
adminbae64d82013-08-01 10:50:15 -070046config_path = path + "config/"
Jon Hall44506242015-07-29 17:40:26 -070047sys.path.append( path )
48sys.path.append( drivers_path )
49sys.path.append( core_path )
50sys.path.append( tests_path )
adminbae64d82013-08-01 10:50:15 -070051
52from core.utilities import Utilities
kelvin-onlabfb521662015-02-27 09:52:40 -080053from core.Thread import Thread
adminbae64d82013-08-01 10:50:15 -070054
adminbae64d82013-08-01 10:50:15 -070055
56class TestON:
57 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -070058 TestON will initiate the specified test.
Jon Hall714eeba2015-09-29 17:53:10 -070059 The main tasks are:
kelvin-onlabf70fd542015-05-07 18:41:40 -070060 * Initiate the required Component handles for the test.
adminbae64d82013-08-01 10:50:15 -070061 * Create Log file Handles.
adminbae64d82013-08-01 10:50:15 -070062 '''
Jon Hall714eeba2015-09-29 17:53:10 -070063 def __init__( self, options ):
adminbae64d82013-08-01 10:50:15 -070064 '''
Jon Hall714eeba2015-09-29 17:53:10 -070065 Initialise the component handles specified in the topology file of
66 the specified test.
adminbae64d82013-08-01 10:50:15 -070067 '''
68 # Initialization of the variables.
69 __builtin__.main = self
adminbae64d82013-08-01 10:50:15 -070070 __builtin__.path = path
71 __builtin__.utilities = Utilities()
72 self.TRUE = 1
73 self.FALSE = 0
74 self.ERROR = -1
kelvin-onlabf70fd542015-05-07 18:41:40 -070075 self.NORESULT = 2
adminbae64d82013-08-01 10:50:15 -070076 self.FAIL = False
77 self.PASS = True
kelvin-onlabf70fd542015-05-07 18:41:40 -070078 self.CASERESULT = self.ERROR
79 self.STEPRESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -070080 self.init_result = self.TRUE
81 self.testResult = "Summary"
kelvin-onlabf70fd542015-05-07 18:41:40 -070082 self.stepName = ""
83 self.stepCache = ""
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 Hall5b586732015-06-11 11:39:39 -070096 self.cleanupFlag = False
97 self.cleanupLock = threading.Lock()
Jon Hall0fc0d452015-07-14 09:49:58 -070098 self.initiated = False
Jon Hall65844a32015-03-09 19:09:37 -070099
Jon Hall25079782015-10-13 13:54:39 -0700100 self.config = self.configparser()
Jon Hall714eeba2015-09-29 17:53:10 -0700101 verifyOptions( options )
adminbae64d82013-08-01 10:50:15 -0700102 load_logger()
103 self.componentDictionary = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700104 self.componentDictionary = self.topology['COMPONENT']
105 self.driversList = []
106 if isinstance( self.componentDictionary, str):
107 self.componentDictionary = dict( self.componentDictionary )
Jon Hall65844a32015-03-09 19:09:37 -0700108
Jon Hall714eeba2015-09-29 17:53:10 -0700109 for component in self.componentDictionary:
110 self.driversList.append( self.componentDictionary[component]['type'] )
Jon Hall65844a32015-03-09 19:09:37 -0700111
Jon Hall714eeba2015-09-29 17:53:10 -0700112 self.driversList = list( set( self.driversList ) ) # Removing duplicates.
adminbae64d82013-08-01 10:50:15 -0700113 # Checking the test_target option set for the component or not
Jon Hall714eeba2015-09-29 17:53:10 -0700114 if isinstance( self.componentDictionary, dict ):
adminbae64d82013-08-01 10:50:15 -0700115 for component in self.componentDictionary.keys():
116 if 'test_target' in self.componentDictionary[component].keys():
117 self.test_target = component
Jon Hall65844a32015-03-09 19:09:37 -0700118
Jon Halld61331b2015-02-17 16:35:47 -0800119 # Checking for the openspeak file and test script
Jon Hall714eeba2015-09-29 17:53:10 -0700120 self.logger.initlog( self )
adminbae64d82013-08-01 10:50:15 -0700121
122 # Creating Drivers Handles
Jon Hall714eeba2015-09-29 17:53:10 -0700123 initString = "\n" + "*" * 30 + "\n CASE INIT \n" + "*" * 30 + "\n"
124 self.log.exact( initString )
adminbae64d82013-08-01 10:50:15 -0700125 self.driverObject = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700126 self.random_order = 111 # Random order id to connect the components
adminbae64d82013-08-01 10:50:15 -0700127 components_connect_order = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700128 if isinstance( self.componentDictionary, dict ):
adminbae64d82013-08-01 10:50:15 -0700129 for component in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700130 if 'connect_order' not in self.componentDictionary[component].keys():
131 self.componentDictionary[component]['connect_order'] = str( self.get_random() )
132 components_connect_order[component] = eval( self.componentDictionary[component]['connect_order'] )
133 # Ordering components based on the connect order.
134 ordered_component_list = sorted( components_connect_order,
135 key=lambda key: components_connect_order[key] )
adminbae64d82013-08-01 10:50:15 -0700136 print ordered_component_list
adminbae64d82013-08-01 10:50:15 -0700137 for component in ordered_component_list:
Jon Hall714eeba2015-09-29 17:53:10 -0700138 self.componentInit( component )
adminbae64d82013-08-01 10:50:15 -0700139
Jon Hall714eeba2015-09-29 17:53:10 -0700140 def configparser( self ):
adminbae64d82013-08-01 10:50:15 -0700141 '''
142 It will parse the config file (teston.cfg) and return as dictionary
143 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700144 matchFileName = re.match( r'(.*)\.cfg', self.configFile, re.M | re.I )
adminbae64d82013-08-01 10:50:15 -0700145 if matchFileName:
Jon Hall714eeba2015-09-29 17:53:10 -0700146 xml = open( self.configFile ).read()
147 try:
148 self.configDict = xmldict.xml_to_dict( xml )
adminbae64d82013-08-01 10:50:15 -0700149 return self.configDict
Jon Hall1306a562015-09-04 11:21:24 -0700150 except IOError:
adminbae64d82013-08-01 10:50:15 -0700151 print "There is no such file to parse " + self.configFile
Jon Hall1306a562015-09-04 11:21:24 -0700152 else:
153 print "There is no such file to parse " + self.configFile
kelvin-onlabf70fd542015-05-07 18:41:40 -0700154
Jon Hall714eeba2015-09-29 17:53:10 -0700155 def componentInit( self, component ):
adminbae64d82013-08-01 10:50:15 -0700156 '''
157 This method will initialize specified component
158 '''
159 global driver_options
Jon Hall0fc0d452015-07-14 09:49:58 -0700160 self.initiated = False
Jon Hall714eeba2015-09-29 17:53:10 -0700161 self.log.info( "Creating component Handle: " + component )
Jon Halld61331b2015-02-17 16:35:47 -0800162 driver_options = {}
adminbae64d82013-08-01 10:50:15 -0700163 if 'COMPONENTS' in self.componentDictionary[component].keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700164 driver_options = dict( self.componentDictionary[component]['COMPONENTS'] )
Jon Hall714eeba2015-09-29 17:53:10 -0700165 driver_options['name'] = component
adminbae64d82013-08-01 10:50:15 -0700166 driverName = self.componentDictionary[component]['type']
Jon Hall714eeba2015-09-29 17:53:10 -0700167 driver_options['type'] = driverName
kelvin-onlabf70fd542015-05-07 18:41:40 -0700168
Jon Hall714eeba2015-09-29 17:53:10 -0700169 classPath = self.getDriverPath( driverName.lower() )
170 driverModule = importlib.import_module( classPath )
171 driverClass = getattr( driverModule, driverName )
adminbae64d82013-08-01 10:50:15 -0700172 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700173
Jon Hall714eeba2015-09-29 17:53:10 -0700174 if "OCN" in self.componentDictionary[component]['host'] and\
175 main.onoscell:
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700176 self.componentDictionary[component]['host'] = main.mnIP
177
Jon Hall714eeba2015-09-29 17:53:10 -0700178 user_name = self.componentDictionary[component].get( 'user',
179 getpass.getuser() )
180 ip_address = self.componentDictionary[component].get( 'host',
181 'localhost' )
182 pwd = self.componentDictionary[component].get( 'password',
183 'changeme' )
184 port = self.componentDictionary[component].get( 'port' )
185 connect_result = driverObject.connect( user_name=user_name,
186 ip_address=ip_address,
187 pwd=pwd,
188 port=port,
189 options=driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700190
adminbae64d82013-08-01 10:50:15 -0700191 if not connect_result:
Jon Hall714eeba2015-09-29 17:53:10 -0700192 self.log.error( "Exiting from the test execution because connecting to the " +
193 component + " component failed." )
Jon Halld61331b2015-02-17 16:35:47 -0800194 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700195
Jon Hall714eeba2015-09-29 17:53:10 -0700196 vars( self )[component] = driverObject
Jon Hall0fc0d452015-07-14 09:49:58 -0700197 self.initiated = True
kelvin-onlabf70fd542015-05-07 18:41:40 -0700198
Jon Hall714eeba2015-09-29 17:53:10 -0700199 def run( self ):
adminbae64d82013-08-01 10:50:15 -0700200 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700201 The Execution of the test script's cases listed in the Test params
202 file will be done here then update each test case result.
203 This method will return main.TRUE if it executed all the test cases
204 successfully, else will retun main.FALSE
adminbae64d82013-08-01 10:50:15 -0700205 '''
adminbae64d82013-08-01 10:50:15 -0700206 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700207 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700208 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800209 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700210 self.TOTAL_TC_NORESULT = 0
211 self.TOTAL_TC_FAIL = 0
212 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700213 self.TEST_ITERATION = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700214
215 # NOTE: number of main.step statements in the
216 # outer most level of the test case. used to
217 # execute code in smaller steps
218 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700219 self.CASERESULT = self.NORESULT
220
Jon Halld61331b2015-02-17 16:35:47 -0800221 import testparser
Jon Hall714eeba2015-09-29 17:53:10 -0700222 testFile = self.tests_path + "/" + self.TEST + "/" + self.TEST + ".py"
223 test = testparser.TestParser( testFile )
adminbae64d82013-08-01 10:50:15 -0700224 self.testscript = test.testscript
225 self.code = test.getStepCode()
Jon Hall714eeba2015-09-29 17:53:10 -0700226 repeat = int( self.params.get( 'repeat', 1 ) )
227 self.TOTAL_TC_PLANNED = len( self.testcases_list ) * repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700228
adminbae64d82013-08-01 10:50:15 -0700229 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700230 while repeat:
Jon Halla1185982014-09-15 14:55:10 -0700231 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Hall714eeba2015-09-29 17:53:10 -0700232 result = self.runCase( self.CurrentTestCaseNumber )
233 repeat -= 1
adminbae64d82013-08-01 10:50:15 -0700234 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700235
Jon Halle234cc42015-08-31 15:26:47 -0700236 def runCase( self, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700237 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700238 self.CurrentTestCase = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700239
240 # List of step results in a case. ANDed together to get the result
241 self.stepResultsList = []
kelvin-onlabf70fd542015-05-07 18:41:40 -0700242 self.stepName = ""
Jon Hall783bbf92015-07-23 14:33:19 -0700243 self.caseExplanation = ""
adminbae64d82013-08-01 10:50:15 -0700244 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700245
246 # NOTE: number of main.step statements in the
247 # outer most level of the test case. used to
248 # execute code in smaller steps
249 self.stepCount = 0
250
251 # NOTE: This is the current number of main.step()'s executed
252 # in a case. Used for logging.
253 self.stepNumber = 0
adminbae64d82013-08-01 10:50:15 -0700254 self.EXPERIMENTAL_MODE = self.FALSE
255 self.addCaseHeader()
Jon Halle234cc42015-08-31 15:26:47 -0700256 self.testCaseNumber = str( testCaseNumber )
257 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700258 stopped = False
Jon Hall5a72b712015-09-28 12:20:59 -0700259 try:
260 self.code[self.testCaseNumber]
Jon Halld61331b2015-02-17 16:35:47 -0800261 except KeyError:
Jon Halle234cc42015-08-31 15:26:47 -0700262 self.log.error( "There is no Test-Case " + self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800263 return self.FALSE
adminbae64d82013-08-01 10:50:15 -0700264 self.stepCount = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700265 while self.stepCount < len( self.code[self.testCaseNumber].keys() ):
266 result = self.runStep( self.code, self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800267 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700268 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800269 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700270 continue
Jon Hall5a72b712015-09-28 12:20:59 -0700271 # stepResults format: ( stepNo[], stepName[], stepResult[], onFail[] )
272 stepResults = self.stepResultsList
Jon Halle234cc42015-08-31 15:26:47 -0700273 if not stopped:
274 if self.CASERESULT == self.TRUE or self.CASERESULT == self.FALSE:
Jon Hall714eeba2015-09-29 17:53:10 -0700275 # Result was already explitily set somewhere else like
276 # in skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700277 pass
Jon Hall5a72b712015-09-28 12:20:59 -0700278 elif all( self.TRUE == i for i in stepResults ):
kelvin-onlabf70fd542015-05-07 18:41:40 -0700279 # ALL PASSED
280 self.CASERESULT = self.TRUE
Jon Hall5a72b712015-09-28 12:20:59 -0700281 elif self.FALSE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700282 # AT LEAST ONE FAILED
283 self.CASERESULT = self.FALSE
Jon Hall5a72b712015-09-28 12:20:59 -0700284 elif self.TRUE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700285 # AT LEAST ONE PASSED
286 self.CASERESULT = self.TRUE
287 else:
288 self.CASERESULT = self.NORESULT
Jon Hall714eeba2015-09-29 17:53:10 -0700289 self.testCaseResult[str( self.CurrentTestCaseNumber )] = self.CASERESULT
290 self.logger.updateCaseResults( self )
Jon Hall783bbf92015-07-23 14:33:19 -0700291 self.log.wiki( "<p>" + self.caseExplanation + "</p>" )
292 self.log.summary( self.caseExplanation )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700293 self.log.wiki( "<ul>" )
acsmarse2d1ed12015-10-05 13:51:17 -0700294 subcaseMessage = False
kelvin-onlabf70fd542015-05-07 18:41:40 -0700295 for line in self.stepCache.splitlines():
acsmarse2d1ed12015-10-05 13:51:17 -0700296 if re.search( "[0-9]\.[0-9]", line ): # Step
297 if subcaseMessage: # End of Failure Message Printout
298 self.log.wiki( "</ul>\n" )
299 subcaseMessage = False
300 if re.search( " - PASS$", line ):
301 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
302 elif re.search( " - FAIL$", line ):
303 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
304 elif re.search( " - No Result$", line ):
305 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
306 else: # Substep
307 if not subcaseMessage: # Open Failure Message Printout
308 self.log.wiki( "<ul><li>" + line + "</li>\n" )
309 subcaseMessage = True
310 else: # Add to Failure Message Printout
311 self.log.wiki( "<li>" + line + "</li>\n" )
acsmars27e62dd2015-10-06 11:35:47 -0700312 if subcaseMessage: # End of Failure Message Printout for last item
313 self.log.wiki( "</ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700314 self.log.wiki( "</ul>" )
315 self.log.summary( self.stepCache )
316 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700317 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700318
Jon Hall714eeba2015-09-29 17:53:10 -0700319 def runStep( self, code, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700320 if not cli.pause:
Jon Hall5a72b712015-09-28 12:20:59 -0700321 try:
322 step = self.stepCount
323 # stepResults format: ( stepNo, stepName, stepResult, onFail )
324 # NOTE: This is needed to catch results of main.step()'s
325 # called inside functions or loops
326 self.stepResults = ( [], [], [], [] )
adminbae64d82013-08-01 10:50:15 -0700327 exec code[testCaseNumber][step] in module.__dict__
328 self.stepCount = self.stepCount + 1
Jon Hall5a72b712015-09-28 12:20:59 -0700329
330 # Iterate through each of the steps and print them
331 for index in range( len( self.stepResults[0] ) ):
Jon Hall714eeba2015-09-29 17:53:10 -0700332 # stepResults = ( stepNo, stepName, stepResult, onFail )
Jon Hall5a72b712015-09-28 12:20:59 -0700333 stepNo = self.stepResults[0][ index ]
334 stepName = self.stepResults[1][ index ]
335 stepResult = self.stepResults[2][ index ]
336 onFail = self.stepResults[3][ index ]
337 self.stepCache += "\t" + str( testCaseNumber ) + "."
338 self.stepCache += str( stepNo ) + " "
339 self.stepCache += stepName + " - "
340 if stepResult == self.TRUE:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700341 self.stepCache += "PASS\n"
Jon Hall5a72b712015-09-28 12:20:59 -0700342 elif stepResult == self.FALSE:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700343 self.stepCache += "FAIL\n"
Jon Hall5a72b712015-09-28 12:20:59 -0700344 self.stepCache += "\t\t" + onFail + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700345 else:
346 self.stepCache += "No Result\n"
Jon Hall714eeba2015-09-29 17:53:10 -0700347 self.stepResultsList.append( stepResult )
Jon Halle234cc42015-08-31 15:26:47 -0700348 except StopIteration: # Raised in self.skipCase()
349 self.log.warn( "Skipping the rest of CASE" +
350 str( testCaseNumber ) )
Jon Hall714eeba2015-09-29 17:53:10 -0700351 self.stepResultsList.append( self.STEPRESULT )
Jon Halle234cc42015-08-31 15:26:47 -0700352 self.stepCache += "\t\t" + self.onFailMsg + "\n"
353 self.stepCount = self.stepCount + 1
354 return self.FALSE
Jon Hallc1606352015-10-06 14:51:36 -0700355 except StandardError as e:
356 try:
357 stepNo = self.stepResults[0][ self.stepNumber - 1 ]
358 except IndexError:
359 stepNo = "<IndexError>"
360 main.log.warn( "Error trying to get step number. " +
361 "It is likely between step " +
362 str( self.stepNumber ) + " and step" +
363 str( self.stepNumber + 1 ) )
364 try:
365 stepName = self.stepResults[1][ self.stepNumber - 1 ]
366 except IndexError:
367 stepName = "<IndexError>"
368 self.log.error( "\nException in the following section of" +
369 " code: " + str( testCaseNumber ) + "." +
370 str( stepNo ) + ": " + stepName )
371 self.log.error( e )
adminbae64d82013-08-01 10:50:15 -0700372 self.stepCount = self.stepCount + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700373 self.logger.updateCaseResults( self )
374 # WIKI results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700375 self.log.wiki( "<ul>" )
376 for line in self.stepCache.splitlines():
377 if re.search( " - PASS$", line ):
378 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
379 elif re.search( " - FAIL$", line ):
380 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
381 elif re.search( " - No Result$", line ):
382 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700383 else: # Should only be on fail message
384 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700385 self.log.wiki( "</ul>" )
Jon Hall714eeba2015-09-29 17:53:10 -0700386 # summary results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700387 self.log.summary( self.stepCache )
388 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700389 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700390 self.exit()
Jon Halle234cc42015-08-31 15:26:47 -0700391 return self.TRUE
adminbae64d82013-08-01 10:50:15 -0700392 if cli.stop:
393 cli.stop = False
adminbae64d82013-08-01 10:50:15 -0700394 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700395 self.testCaseResult[str( self.CurrentTestCaseNumber )] = "Stopped"
396 self.logger.updateCaseResults( self )
adminbae64d82013-08-01 10:50:15 -0700397 result = self.cleanup()
Jon Halle234cc42015-08-31 15:26:47 -0700398 return self.FALSE
399
400 def skipCase( self, result="DEFAULT", msg=None ):
401 """
402 Will skip the rest of the code in a test case. The case results will be
403 determined as normal based on completed assertions unless the result
404 argument is given.
405
406 Optional Arguments:
407 result: Case insensite string. Can be 'PASS' or 'FAIL' and will set
408 the case result accordingly.
409 msg: Message to be printed when the case is skipped in the reports.
410 """
411 result = result.upper().strip()
412 if result == "PASS":
413 self.CASERESULT = self.TRUE
414 elif result == "FAIL":
415 self.CASERESULT = self.FALSE
416 self.onFailMsg = "Skipping the rest of this case. "
417 if msg:
418 self.onFailMsg += str( msg )
419 raise StopIteration
kelvin-onlabf70fd542015-05-07 18:41:40 -0700420
Jon Hall714eeba2015-09-29 17:53:10 -0700421 def addCaseHeader( self ):
422 caseHeader = "\n" + "*" * 30 + "\n Result summary for Testcase" +\
423 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 30 + "\n"
424 self.log.exact( caseHeader )
425 caseHeader = "\n" + "*" * 40 + "\nStart of Test Case" +\
426 str( self.CurrentTestCaseNumber ) + " : "
adminbae64d82013-08-01 10:50:15 -0700427 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700428 vars( self )[driver + 'log'].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700429
Jon Hall714eeba2015-09-29 17:53:10 -0700430 def addCaseFooter( self ):
Jon Hall5a72b712015-09-28 12:20:59 -0700431 stepNo = self.stepResults[0][-2]
Jon Hall714eeba2015-09-29 17:53:10 -0700432 if stepNo > 0:
433 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." +\
434 str( stepNo ) + ": " + str( self.stepName )
435 stepHeader = "\n" + "*" * 40 + "\nEnd of Step " + previousStep +\
436 "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700437
Jon Hall714eeba2015-09-29 17:53:10 -0700438 caseFooter = "\n" + "*" * 40 + "\nEnd of Test case " +\
439 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700440
adminbae64d82013-08-01 10:50:15 -0700441 for driver in self.driversList:
Jon Hall714eeba2015-09-29 17:53:10 -0700442 vars( self )[driver].write( stepHeader + "\n" + caseFooter )
adminbae64d82013-08-01 10:50:15 -0700443
Jon Hall714eeba2015-09-29 17:53:10 -0700444 def cleanup( self ):
adminbae64d82013-08-01 10:50:15 -0700445 '''
Jon Hall5b586732015-06-11 11:39:39 -0700446 Print a summary of the current test's results then attempt to release
447 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700448
Jon Hall5b586732015-06-11 11:39:39 -0700449 This function shouldbe threadsafe such that cleanup will only be
450 executed once per test.
451
452 This will return TRUE if all the component handles and log handles
453 closed properly, else return FALSE.
adminbae64d82013-08-01 10:50:15 -0700454 '''
455 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700456 lock = self.cleanupLock
457 if lock.acquire( False ):
458 try:
459 if self.cleanupFlag is False: # First thread to run this
460 self.cleanupFlag = True
Jon Hall0fc0d452015-07-14 09:49:58 -0700461 if self.initiated:
Jon Hall714eeba2015-09-29 17:53:10 -0700462 self.logger.testSummary( self )
Jon Hall892818c2015-10-20 17:58:34 -0700463 components = self.componentDictionary
464 for component in sorted( components,
465 key=lambda item: components[item]['connect_order'],
466 reverse=True ):
Jon Hall714eeba2015-09-29 17:53:10 -0700467 try:
468 tempObject = vars( self )[component]
469 print "Disconnecting from " + str( tempObject.name ) +\
470 ": " + str( tempObject.__class__)
Jon Hall5b586732015-06-11 11:39:39 -0700471 tempObject.disconnect()
Jon Hall1306a562015-09-04 11:21:24 -0700472 except KeyboardInterrupt:
473 pass
474 except KeyError:
475 # Component not created yet
476 self.log.warn( "Could not find the component " +
477 str( component ) )
478 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700479 self.log.exception( "Exception while disconnecting from " +
480 str( component ) )
481 result = self.FALSE
482 # Closing all the driver's session files
483 for driver in self.componentDictionary.keys():
484 try:
Jon Hall714eeba2015-09-29 17:53:10 -0700485 vars( self )[driver].close_log_handles()
Jon Hall1306a562015-09-04 11:21:24 -0700486 except KeyboardInterrupt:
487 pass
488 except KeyError:
489 # Component not created yet
490 self.log.warn( "Could not find the component " +
491 str( driver ) + " while trying to" +
492 " close log file" )
493 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700494 self.log.exception( "Exception while closing log files for " +
495 str( driver ) )
496 result = self.FALSE
497 else:
498 pass # Someone else already ran through this function
499 finally:
500 lock.release()
501 else: # Someone already has a lock
502 # NOTE: This could cause problems if we don't release the lock
503 # correctly
504 lock.acquire() # Wait for the other thread to finish
505 # NOTE: If we don't wait, exit could be called while the thread
506 # with the lock is still cleaning up
507 lock.release()
adminbae64d82013-08-01 10:50:15 -0700508 return result
Jon Halld61331b2015-02-17 16:35:47 -0800509
Jon Hall714eeba2015-09-29 17:53:10 -0700510 def pause( self ):
adminbae64d82013-08-01 10:50:15 -0700511 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700512 This function will pause the test's execution, and will continue after
513 user provide 'resume' command.
adminbae64d82013-08-01 10:50:15 -0700514 '''
515 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700516
Jon Hall714eeba2015-09-29 17:53:10 -0700517 def onfail( self, *components ):
adminbae64d82013-08-01 10:50:15 -0700518 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700519 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700520 '''
adminbae64d82013-08-01 10:50:15 -0700521 if not components:
Jon Hall714eeba2015-09-29 17:53:10 -0700522 try:
adminbae64d82013-08-01 10:50:15 -0700523 for component in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700524 tempObject = vars( self )[component]
adminbae64d82013-08-01 10:50:15 -0700525 result = tempObject.onfail()
Jon Hall1306a562015-09-04 11:21:24 -0700526 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700527 print str( e )
adminbae64d82013-08-01 10:50:15 -0700528 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700529 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700530 try:
adminbae64d82013-08-01 10:50:15 -0700531 for component in components:
Jon Hall714eeba2015-09-29 17:53:10 -0700532 tempObject = vars( self )[component]
adminbae64d82013-08-01 10:50:15 -0700533 result = tempObject.onfail()
Jon Hall1306a562015-09-04 11:21:24 -0700534 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700535 print str( e )
adminbae64d82013-08-01 10:50:15 -0700536 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700537
Jon Hall714eeba2015-09-29 17:53:10 -0700538 def getDriverPath( self, driverName ):
adminbae64d82013-08-01 10:50:15 -0700539 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700540 Based on the component 'type' specified in the params , this method
541 will find the absolute path, by recursively searching the name of
542 the component.
543
544 NOTE: This function requires the linux 'find' command.
adminbae64d82013-08-01 10:50:15 -0700545 '''
546 import commands
547
Jon Hall714eeba2015-09-29 17:53:10 -0700548 cmd = "find " + drivers_path + " -name " + driverName + ".py"
549 result = commands.getoutput( cmd )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700550
Jon Hall714eeba2015-09-29 17:53:10 -0700551 result_array = str( result ).split( '\n' )
adminbae64d82013-08-01 10:50:15 -0700552 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700553
adminbae64d82013-08-01 10:50:15 -0700554 for drivers_list in result_array:
Jon Hall714eeba2015-09-29 17:53:10 -0700555 result_count = result_count + 1
556 if result_count > 1:
557 print "Found " + driverName + " " + str( result_count ) + " times:"
558 print str( result_array )
adminbae64d82013-08-01 10:50:15 -0700559 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700560
Jon Hall714eeba2015-09-29 17:53:10 -0700561 result = re.sub( "(.*)drivers", "", result )
562 result = re.sub( "\/\/", "/", result )
563 result = re.sub( "\.py", "", result )
564 result = re.sub( "\.pyc", "", result )
565 result = re.sub( "\/", ".", result )
566 result = "drivers" + result
adminbae64d82013-08-01 10:50:15 -0700567 return result
adminbae64d82013-08-01 10:50:15 -0700568
Jon Hall714eeba2015-09-29 17:53:10 -0700569 def step( self, stepDesc ):
adminbae64d82013-08-01 10:50:15 -0700570 '''
571 The step information of the test-case will append to the logs.
572 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700573 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." +\
574 str( self.stepNumber ) + ": " + str( self.stepName )
adminbae64d82013-08-01 10:50:15 -0700575 self.stepName = stepDesc
Jon Hall5a72b712015-09-28 12:20:59 -0700576 self.stepNumber += 1
577 self.stepResults[0].append( self.stepNumber )
578 self.stepResults[1].append( stepDesc )
579 self.stepResults[2].append( self.NORESULT )
580 self.stepResults[3].append( "No on fail message given" )
adminbae64d82013-08-01 10:50:15 -0700581
Jon Hall714eeba2015-09-29 17:53:10 -0700582 stepName = " " + str( self.CurrentTestCaseNumber ) + "." +\
583 str( self.stepNumber ) + ": " + str( stepDesc )
adminbae64d82013-08-01 10:50:15 -0700584 self.log.step(stepName)
585 stepHeader = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700586 line = "\n" + "-" * 45 + "\n"
587 if self.stepNumber > 1:
588 stepHeader = line + "End of Step " + previousStep + line
589 stepHeader += line + "Start of Step" + stepName + line
adminbae64d82013-08-01 10:50:15 -0700590 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700591 vars( self )[driver + 'log'].info( stepHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700592
Jon Hall714eeba2015-09-29 17:53:10 -0700593 def case( self, testCaseName ):
adminbae64d82013-08-01 10:50:15 -0700594 '''
595 Test's each test-case information will append to the logs.
596 '''
Jon Halld61331b2015-02-17 16:35:47 -0800597 self.CurrentTestCase = testCaseName
Jon Hall714eeba2015-09-29 17:53:10 -0700598 testCaseName = " " + str( testCaseName )
599 self.log.case( testCaseName )
600 caseHeader = testCaseName + "\n" + "*" * 40 + "\n"
adminbae64d82013-08-01 10:50:15 -0700601 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700602 vars( self )[driver + 'log'].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700603
Jon Hall714eeba2015-09-29 17:53:10 -0700604 def testDesc( self, description ):
adminbae64d82013-08-01 10:50:15 -0700605 '''
606 Test description will append to the logs.
607 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700608 description = "Test Description : " + str( description )
609 self.log.info( description )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700610
Jon Hall714eeba2015-09-29 17:53:10 -0700611 def _getTest( self ):
adminbae64d82013-08-01 10:50:15 -0700612 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700613 This method will parse the test script to find required test
614 information.
adminbae64d82013-08-01 10:50:15 -0700615 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700616 testFile = self.tests_path + "/" + self.TEST + "/" + self.TEST + ".py"
617 testFileHandler = open( testFile, 'r' )
adminbae64d82013-08-01 10:50:15 -0700618 testFileList = testFileHandler.readlines()
619 testFileHandler.close()
adminbae64d82013-08-01 10:50:15 -0700620 counter = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700621 for index in range( len( testFileList ) ):
622 lineMatch = re.match( '\s+def CASE(\d+)(.*):',
623 testFileList[index],
624 0 )
adminbae64d82013-08-01 10:50:15 -0700625 if lineMatch:
Jon Hall714eeba2015-09-29 17:53:10 -0700626 counter = counter + 1
627 self.TC_PLANNED = len( self.testcases_list )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700628
Jon Hall714eeba2015-09-29 17:53:10 -0700629 def response_parser( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700630 ''' It will load the default response parser '''
631 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700632 response_dict = self.response_to_dict( response, return_format )
633 return_format_string = self.dict_to_return_format( response,
634 return_format,
635 response_dict )
adminbae64d82013-08-01 10:50:15 -0700636 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700637
Jon Hall714eeba2015-09-29 17:53:10 -0700638 def response_to_dict( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700639 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700640 json_match = re.search( '^\s*{', response )
641 xml_match = re.search( '^\s*\<', response )
642 ini_match = re.search( '^\s*\[', response )
643 if json_match:
644 self.log.info( "Response is in 'JSON' format, converting to '" +
645 return_format + "' format" )
Jon Halld61331b2015-02-17 16:35:47 -0800646 # Formatting the json string
Jon Hall714eeba2015-09-29 17:53:10 -0700647 response = re.sub( r"{\s*'?(\w)", r'{"\1', response )
648 response = re.sub( r",\s*'?(\w)", r',"\1', response )
649 response = re.sub( r"(\w)'?\s*:", r'\1":', response )
650 response = re.sub( r":\s*'(\w)'\s*([,}])", r':"\1"\2', response )
651 try:
adminbae64d82013-08-01 10:50:15 -0700652 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700653 response_dict = json.loads( response )
Jon Hall1306a562015-09-04 11:21:24 -0700654 except StandardError:
Jon Hall2a5002c2015-08-21 16:49:11 -0700655 self.log.exception( "Json Parser is unable to parse the string" )
adminbae64d82013-08-01 10:50:15 -0700656 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700657 elif ini_match:
658 self.log.info( "Response is in 'INI' format, converting to '" +
659 return_format + "' format" )
adminbae64d82013-08-01 10:50:15 -0700660 from configobj import ConfigObj
Jon Hall714eeba2015-09-29 17:53:10 -0700661 response_file = open( "respnse_file.temp", 'w' )
662 response_file.write( response )
Jon Halld61331b2015-02-17 16:35:47 -0800663 response_file.close()
Jon Hall714eeba2015-09-29 17:53:10 -0700664 response_dict = ConfigObj( "respnse_file.temp" )
adminbae64d82013-08-01 10:50:15 -0700665 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700666 elif xml_match:
667 self.log.info( "Response is in 'XML' format, converting to '" +
668 return_format + "' format" )
669 try:
670 response_dict = xmldict.xml_to_dict( "<response> " +
671 str( response ) +
672 " </response>" )
Jon Hall1306a562015-09-04 11:21:24 -0700673 except StandardError:
674 self.log.exception()
adminbae64d82013-08-01 10:50:15 -0700675 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700676
Jon Hall714eeba2015-09-29 17:53:10 -0700677 def dict_to_return_format( self, response, return_format, response_dict ):
678 if return_format == 'table':
adminbae64d82013-08-01 10:50:15 -0700679 ''' Will return in table format'''
680 to_do = "Call the table output formatter"
681 global response_table
682 response_table = '\n'
Jon Hall714eeba2015-09-29 17:53:10 -0700683 response_table = response_table + '\t'.join( response_dict ) + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700684
Jon Hall714eeba2015-09-29 17:53:10 -0700685 def get_table( value_to_convert ):
686 ''' This will parse the dictionary recusrsively and print as
687 table format'''
adminbae64d82013-08-01 10:50:15 -0700688 table_data = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700689 if isinstance( value_to_convert, dict ):
690 table_data = table_data + '\t'.join( value_to_convert ) +\
691 "\n"
692 for temp_val in value_to_convert.values():
693 table_data = table_data + get_table( temp_val )
694 else:
695 table_data = table_data + str( value_to_convert ) + "\t"
Jon Halld61331b2015-02-17 16:35:47 -0800696 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700697
Jon Hall714eeba2015-09-29 17:53:10 -0700698 for value in response_dict.values():
699 response_table = response_table + get_table( value )
adminbae64d82013-08-01 10:50:15 -0700700 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700701
Jon Hall714eeba2015-09-29 17:53:10 -0700702 elif return_format == 'config':
adminbae64d82013-08-01 10:50:15 -0700703 ''' Will return in config format'''
704 to_do = 'Call dict to config coverter'
Jon Hall714eeba2015-09-29 17:53:10 -0700705 response_string = str( response_dict )
adminbae64d82013-08-01 10:50:15 -0700706 print response_string
Jon Hall714eeba2015-09-29 17:53:10 -0700707 response_config = re.sub( ",", "\n\t", response_string )
708 response_config = re.sub( "u\'", "\'", response_config )
709 response_config = re.sub( "{", "", response_config )
710 response_config = re.sub( "}", "\n", response_config )
711 response_config = re.sub( ":", " =", response_config )
712 return "[response]\n\t " + response_config
adminbae64d82013-08-01 10:50:15 -0700713 elif return_format == 'xml':
714 ''' Will return in xml format'''
Jon Hall714eeba2015-09-29 17:53:10 -0700715 response_xml = xmldict.dict_to_xml( response_dict )
716 response_xml = re.sub( ">\s*<", ">\n<", response_xml )
717 return "\n" + response_xml
adminbae64d82013-08-01 10:50:15 -0700718 elif return_format == 'json':
719 ''' Will return in json format'''
720 to_do = 'Call dict to xml coverter'
721 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700722 response_json = json.dumps( response_dict )
adminbae64d82013-08-01 10:50:15 -0700723 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700724
Jon Hall714eeba2015-09-29 17:53:10 -0700725 def get_random( self ):
adminbae64d82013-08-01 10:50:15 -0700726 self.random_order = self.random_order + 1
727 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700728
Jon Hall714eeba2015-09-29 17:53:10 -0700729 def exit( self ):
adminbae64d82013-08-01 10:50:15 -0700730 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700731 for thread in threading.enumerate():
732 if thread.isAlive():
733 try:
734 thread._Thread__stop()
735 except:
Jon Hall1306a562015-09-04 11:21:24 -0700736 # NOTE: We should catch any exceptions while trying to
737 # close the thread so that we can try to close the other
738 # threads as well
Jon Hall714eeba2015-09-29 17:53:10 -0700739 print str( thread.getName() ) +\
740 ' could not be terminated'
adminbae64d82013-08-01 10:50:15 -0700741 sys.exit()
742
Jon Hallcd3d2a32015-10-01 11:07:28 -0700743 def stop( self, email=False ):
744 """
745 Stop the test until Ctrl-D is entered.
746 Ctrl-C will kill the test
Jon Hall25079782015-10-13 13:54:39 -0700747
748 Optional arguments:
749 email can either be a bool, or you can specify the email address
750 to send the email to
Jon Hallcd3d2a32015-10-01 11:07:28 -0700751 """
752 try:
753 if email:
Jon Hall25079782015-10-13 13:54:39 -0700754 if '@' in email:
755 main.mail = email
756 utilities.send_warning_email()
Jon Hallcd3d2a32015-10-01 11:07:28 -0700757 self.log.error( "Test execution suspended. Press Ctrl-D to "
758 "resume or Ctrl-C to exit the test" )
759 # NOTE: Ctrl-D needs to be entered on a new line
760 while True:
761 # TODO: we could give the user an interactive prompt where
762 # they could call functions
763 raw_input()
764 except EOFError:
765 return
766 # Pass all other exceptions up to caller
767
768
Jon Hall714eeba2015-09-29 17:53:10 -0700769def verifyOptions( options ):
adminbae64d82013-08-01 10:50:15 -0700770 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700771 This will verify the command line options and set to default values,
772 if any option not given in command line.
adminbae64d82013-08-01 10:50:15 -0700773 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700774 verifyTest( options )
775 verifyExample( options )
776 verifyTestScript( options )
adminbae64d82013-08-01 10:50:15 -0700777 verifyParams()
Jon Hall714eeba2015-09-29 17:53:10 -0700778 verifyLogdir( options )
779 verifyMail( options )
780 verifyTestCases( options )
781 verifyOnosCell( options )
adminbae64d82013-08-01 10:50:15 -0700782
Jon Hall714eeba2015-09-29 17:53:10 -0700783def verifyTest( options ):
Jon Hall44506242015-07-29 17:40:26 -0700784 try:
785 if options.testname:
786 main.TEST = options.testname
Jon Hall714eeba2015-09-29 17:53:10 -0700787 main.classPath = "tests." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700788 main.tests_path = tests_path
789 elif options.example:
790 main.TEST = options.example
Jon Hall714eeba2015-09-29 17:53:10 -0700791 main.tests_path = path + "/examples/"
792 main.classPath = "examples." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700793 except AttributeError:
adminbae64d82013-08-01 10:50:15 -0700794 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700795 main.exit()
adminbae64d82013-08-01 10:50:15 -0700796
Jon Hall714eeba2015-09-29 17:53:10 -0700797def verifyExample( options ):
adminbae64d82013-08-01 10:50:15 -0700798 if options.example:
Jon Hall714eeba2015-09-29 17:53:10 -0700799 main.testDir = path + '/examples/'
800 main.tests_path = path + "/examples/"
801 main.classPath = "examples." + main.TEST + "." + main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700802
Jon Hall714eeba2015-09-29 17:53:10 -0700803def verifyLogdir( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800804 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700805 if options.logdir:
806 main.logdir = options.logdir
Jon Hall714eeba2015-09-29 17:53:10 -0700807 else:
Jon Halld61331b2015-02-17 16:35:47 -0800808 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700809
Jon Hall714eeba2015-09-29 17:53:10 -0700810def verifyMail( options ):
Jon Hall25079782015-10-13 13:54:39 -0700811 # Mail-To: field
812 if options.mail: # Test run specific
adminbae64d82013-08-01 10:50:15 -0700813 main.mail = options.mail
Jon Hall25079782015-10-13 13:54:39 -0700814 elif main.params.get('mail'): # Test suite specific
815 main.mail = main.params.get( 'mail' )
816 else: # TestON specific
817 main.mail = main.config['config'].get( 'mail_to' )
818 # Mail-From: field
819 main.sender = main.config['config'].get( 'mail_from' )
820 # Mail smtp server
821 main.smtp = main.config['config'].get( 'mail_server' )
822 # Mail-From account password
823 main.senderPwd = main.config['config'].get( 'mail_pass' )
824
adminbae64d82013-08-01 10:50:15 -0700825
Jon Hall714eeba2015-09-29 17:53:10 -0700826def verifyTestCases( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800827 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700828 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800829 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800830 # sys.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700831 testcases_list = re.sub( "(\[|\])", "", options.testcases )
832 main.testcases_list = eval( testcases_list + "," )
833 else:
adminbae64d82013-08-01 10:50:15 -0700834 if 'testcases' in main.params.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700835 temp = eval( main.params['testcases'] + "," )
836 list1 = []
837 if isinstance( temp[0], list ):
Jon Hallfebb1c72015-03-05 13:30:09 -0800838 for test in temp:
839 for testcase in test:
Jon Hall714eeba2015-09-29 17:53:10 -0700840 if isinstance( testcase, int ):
841 testcase = [testcase]
842 list1.extend( testcase )
843 else:
844 temp = list( temp )
Jon Hallfebb1c72015-03-05 13:30:09 -0800845 for testcase in temp:
Jon Hall714eeba2015-09-29 17:53:10 -0700846 if isinstance( testcase, int ):
847 testcase = [testcase]
848 list1.extend( testcase )
849 main.testcases_list = list1
850 else:
851 print "Testcases not specifed in params, please provide in " +\
852 "params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800853 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700854
Jon Hall714eeba2015-09-29 17:53:10 -0700855def verifyOnosCell( options ):
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700856 # Verifying onoscell option
Hari Krishna03f530e2015-07-10 17:28:27 -0700857 if options.onoscell:
858 main.onoscell = options.onoscell
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700859 main.onosIPs = []
860 main.mnIP = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700861 cellCMD = ". ~/.profile; cell " + main.onoscell
862 output = subprocess.check_output( ["bash", '-c', cellCMD] )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700863 splitOutput = output.splitlines()
Jon Hall714eeba2015-09-29 17:53:10 -0700864 for i in range( len( splitOutput ) ):
865 if re.match( "OCN", splitOutput[i] ):
866 mnNode = splitOutput[i].split( "=" )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700867 main.mnIP = mnNode[1]
Jon Hall714eeba2015-09-29 17:53:10 -0700868 # cell already sorts OC variables in bash, so no need to
869 # sort in TestON
870 if re.match( "OC[1-9]", splitOutput[i] ):
871 onosNodes = splitOutput[i].split( "=" )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700872 main.onosIPs.append( onosNodes[1] )
Jon Hall714eeba2015-09-29 17:53:10 -0700873 else:
Hari Krishna03f530e2015-07-10 17:28:27 -0700874 main.onoscell = main.FALSE
875
Jon Hall714eeba2015-09-29 17:53:10 -0700876def verifyTestScript( options ):
adminbae64d82013-08-01 10:50:15 -0700877 '''
878 Verifyies test script.
879 '''
Jon Halld61331b2015-02-17 16:35:47 -0800880 main.openspeak = openspeak.OpenSpeak()
Jon Hall714eeba2015-09-29 17:53:10 -0700881 openspeakfile = main.testDir + "/" + main.TEST + "/" + main.TEST + ".ospk"
882 testfile = main.testDir + "/" + main.TEST + "/" + main.TEST + ".py"
883 if os.path.exists( openspeakfile ):
Jon Hall44506242015-07-29 17:40:26 -0700884 # Openspeak file found, compiling to python
Jon Hall714eeba2015-09-29 17:53:10 -0700885 main.openspeak.compiler( openspeakfile=openspeakfile, writetofile=1 )
886 elif os.path.exists( testfile ):
Jon Hall44506242015-07-29 17:40:26 -0700887 # No openspeak found, using python file instead
888 pass
adminbae64d82013-08-01 10:50:15 -0700889 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700890 print "\nThere is no \"" + main.TEST + "\" test script.\nPlease provide a " +\
Jon Hall44506242015-07-29 17:40:26 -0700891 "Python or OpenSpeak test script in the tests folder: " +\
Jon Hall714eeba2015-09-29 17:53:10 -0700892 main.testDir + "/" + main.TEST + "/"
adminbae64d82013-08-01 10:50:15 -0700893 __builtin__.testthread = None
894 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700895 try:
896 testModule = __import__( main.classPath,
897 globals(),
898 locals(),
899 [main.TEST],
900 -1 )
Jon Hall1306a562015-09-04 11:21:24 -0700901 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -0700902 print "There was an import error, it might mean that there is " +\
903 "no test named " + main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800904 main.exit()
adminbae64d82013-08-01 10:50:15 -0700905
Jon Hall714eeba2015-09-29 17:53:10 -0700906 testClass = getattr( testModule, main.TEST )
adminbae64d82013-08-01 10:50:15 -0700907 main.testObject = testClass()
908 load_parser()
Jon Hall714eeba2015-09-29 17:53:10 -0700909 main.params = main.parser.parseParams( main.classPath )
910 main.topology = main.parser.parseTopology( main.classPath )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700911
adminbae64d82013-08-01 10:50:15 -0700912def verifyParams():
Jon Hall714eeba2015-09-29 17:53:10 -0700913 try:
adminbae64d82013-08-01 10:50:15 -0700914 main.params = main.params['PARAMS']
Jon Hall1306a562015-09-04 11:21:24 -0700915 except KeyError:
Jon Hall714eeba2015-09-29 17:53:10 -0700916 print "Error with the params file: Either the file not specified " +\
917 "or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800918 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700919 try:
adminbae64d82013-08-01 10:50:15 -0700920 main.topology = main.topology['TOPOLOGY']
Jon Hall1306a562015-09-04 11:21:24 -0700921 except KeyError:
Jon Hall714eeba2015-09-29 17:53:10 -0700922 print "Error with the Topology file: Either the file not specified " +\
923 "or the format is not correct"
adminbae64d82013-08-01 10:50:15 -0700924 main.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700925
Jon Hall714eeba2015-09-29 17:53:10 -0700926def load_parser():
adminbae64d82013-08-01 10:50:15 -0700927 '''
928 It facilitates the loading customised parser for topology and params file.
929 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -0700930 It also loads default xmlparser if no parser have specified in teston.cfg
931 file.
adminbae64d82013-08-01 10:50:15 -0700932
933 '''
934 confighash = main.configDict
Jon Hall714eeba2015-09-29 17:53:10 -0700935 if 'file' in confighash['config']['parser'] and\
936 'class' in confighash['config']['parser']:
Jon Hall44506242015-07-29 17:40:26 -0700937 path = confighash['config']['parser']['file']
Jon Hall714eeba2015-09-29 17:53:10 -0700938 if path is not None or\
939 confighash['config']['parser']['class'] is not None:
Jon Hall44506242015-07-29 17:40:26 -0700940 try:
941 module = re.sub( r".py\s*$", "", path )
adminbae64d82013-08-01 10:50:15 -0700942 moduleList = module.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -0700943 newModule = ".".join( moduleList[-2:] )
Jon Hall44506242015-07-29 17:40:26 -0700944 parsingClass = confighash['config']['parser']['class']
Jon Hall714eeba2015-09-29 17:53:10 -0700945 parsingModule = __import__( newModule,
946 globals(),
947 locals(),
948 [parsingClass],
949 -1 )
950 parsingClass = getattr( parsingModule, parsingClass )
Jon Hall44506242015-07-29 17:40:26 -0700951 main.parser = parsingClass()
Jon Hall714eeba2015-09-29 17:53:10 -0700952 if hasattr( main.parser, "parseParams" ) and\
953 hasattr( main.parser, "parseTopology" ) and\
954 hasattr( main.parser, "parse" ):
Jon Hall44506242015-07-29 17:40:26 -0700955 pass
956 else:
957 print "Invalid parser format"
adminbae64d82013-08-01 10:50:15 -0700958 main.exit()
Jon Hall44506242015-07-29 17:40:26 -0700959 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -0700960 print "Could not find the file " + path +\
961 " using default parser."
Jon Halld61331b2015-02-17 16:35:47 -0800962 load_defaultParser()
Jon Hall714eeba2015-09-29 17:53:10 -0700963 elif confighash['config']['parser']['file'] is None or\
964 confighash['config']['parser']['class'] is None:
Jon Halld61331b2015-02-17 16:35:47 -0800965 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -0700966 else:
967 load_defaultParser()
968
969def load_defaultParser():
970 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700971 It will load the default parser which is xml parser to parse the params and
972 topology file.
adminbae64d82013-08-01 10:50:15 -0700973 '''
974 moduleList = main.parserPath.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -0700975 newModule = ".".join( moduleList[-2:] )
976 try:
Jon Halld61331b2015-02-17 16:35:47 -0800977 parsingClass = main.parsingClass
Jon Hall714eeba2015-09-29 17:53:10 -0700978 parsingModule = __import__( newModule,
979 globals(),
980 locals(),
981 [parsingClass],
982 -1 )
983 parsingClass = getattr( parsingModule, parsingClass )
adminbae64d82013-08-01 10:50:15 -0700984 main.parser = parsingClass()
Jon Hall714eeba2015-09-29 17:53:10 -0700985 if hasattr( main.parser, "parseParams" ) and\
986 hasattr( main.parser, "parseTopology" ) and\
987 hasattr( main.parser, "parse" ):
adminbae64d82013-08-01 10:50:15 -0700988 pass
989 else:
990 main.exit()
adminbae64d82013-08-01 10:50:15 -0700991 except ImportError:
992 print sys.exc_info()[1]
993
Jon Hall714eeba2015-09-29 17:53:10 -0700994def load_logger():
adminbae64d82013-08-01 10:50:15 -0700995 '''
996 It facilitates the loading customised parser for topology and params file.
997 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -0700998 It also loads default xmlparser if no parser have specified in teston.cfg
999 file.
adminbae64d82013-08-01 10:50:15 -07001000 '''
1001 confighash = main.configDict
Jon Hall714eeba2015-09-29 17:53:10 -07001002 if 'file' in confighash['config']['logger'] and\
1003 'class' in confighash['config']['logger']:
Jon Hall44506242015-07-29 17:40:26 -07001004 path = confighash['config']['logger']['file']
Jon Hall714eeba2015-09-29 17:53:10 -07001005 if path is not None or\
1006 confighash['config']['logger']['class'] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001007 try:
1008 module = re.sub( r".py\s*$", "", path )
Jon Hall714eeba2015-09-29 17:53:10 -07001009 moduleList = module.split( "/" )
1010 newModule = ".".join( moduleList[-2:] )
Jon Hall44506242015-07-29 17:40:26 -07001011 loggerClass = confighash['config']['logger']['class']
Jon Hall714eeba2015-09-29 17:53:10 -07001012 loggerModule = __import__( newModule,
1013 globals(),
1014 locals(),
1015 [loggerClass],
1016 -1 )
1017 loggerClass = getattr( loggerModule, loggerClass )
Jon Hall44506242015-07-29 17:40:26 -07001018 main.logger = loggerClass()
Jon Hall44506242015-07-29 17:40:26 -07001019 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -07001020 print "Could not find the file " + path +\
1021 " using default logger."
adminbae64d82013-08-01 10:50:15 -07001022 load_defaultlogger()
Jon Hall714eeba2015-09-29 17:53:10 -07001023 elif confighash['config']['parser']['file'] is None or\
1024 confighash['config']['parser']['class'] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001025 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -07001026 else:
1027 load_defaultlogger()
1028
1029def load_defaultlogger():
1030 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001031 It will load the default parser which is xml parser to parse the params and
1032 topology file.
adminbae64d82013-08-01 10:50:15 -07001033 '''
1034 moduleList = main.loggerPath.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -07001035 newModule = ".".join( moduleList[-2:] )
1036 try:
Jon Halld61331b2015-02-17 16:35:47 -08001037 loggerClass = main.loggerClass
Jon Hall714eeba2015-09-29 17:53:10 -07001038 loggerModule = __import__( newModule,
1039 globals(),
1040 locals(),
1041 [loggerClass],
1042 -1 )
1043 loggerClass = getattr( loggerModule, loggerClass )
adminbae64d82013-08-01 10:50:15 -07001044 main.logger = loggerClass()
1045
1046 except ImportError:
1047 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -08001048 main.exit()
adminbae64d82013-08-01 10:50:15 -07001049
Jon Hall714eeba2015-09-29 17:53:10 -07001050def _echo( self ):
adminbae64d82013-08-01 10:50:15 -07001051 print "THIS IS ECHO"