blob: 3030f3faff8f28bc7906ef082293a1f9fb1112e6 [file] [log] [blame]
adminbae64d82013-08-01 10:50:15 -07001#!/usr/bin/env python
2'''
3Created on 22-Oct-2012
Jeremy Ronquillob27ce4c2017-07-17 12:41:28 -07004Copyright 2012 Open Networking Foundation (ONF)
Jon Hall65844a32015-03-09 19:09:37 -07005
Jeremy Songsterae01bba2016-07-11 15:39:17 -07006Please refer questions to either the onos test mailing list at <onos-test@onosproject.org>,
7the System Testing Plans and Results wiki page at <https://wiki.onosproject.org/x/voMg>,
8or the System Testing Guide page at <https://wiki.onosproject.org/x/WYQg>
adminbae64d82013-08-01 10:50:15 -07009
10 TestON is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 2 of the License, or
13 (at your option) any later version.
14
15 TestON is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
Jon Hall65844a32015-03-09 19:09:37 -070021 along with TestON. If not, see <http://www.gnu.org/licenses/>.
adminbae64d82013-08-01 10:50:15 -070022
23
24
25teston is the main module.
26
27'''
28
29import sys
30import getpass
31import os
32import re
33import __builtin__
34import new
35import xmldict
Jon Hall30b82fa2015-03-04 17:15:43 -080036import importlib
Jon Hall5b586732015-06-11 11:39:39 -070037import threading
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -070038import pdb
Jon Hall714eeba2015-09-29 17:53:10 -070039module = new.module( "test" )
adminbae64d82013-08-01 10:50:15 -070040import openspeak
Hari Krishnabe4b97b2015-07-15 12:19:43 -070041import subprocess
Jon Hall714eeba2015-09-29 17:53:10 -070042global path, drivers_path, core_path, tests_path, logs_path
Jon Hall44506242015-07-29 17:40:26 -070043location = os.path.abspath( os.path.dirname( __file__ ) )
44path = re.sub( "(core|bin)$", "", location )
Jon Hall714eeba2015-09-29 17:53:10 -070045drivers_path = path + "drivers"
46core_path = path + "core"
47tests_path = path + "tests"
48logs_path = path + "logs/"
adminbae64d82013-08-01 10:50:15 -070049config_path = path + "config/"
Jon Hall44506242015-07-29 17:40:26 -070050sys.path.append( path )
51sys.path.append( drivers_path )
52sys.path.append( core_path )
53sys.path.append( tests_path )
adminbae64d82013-08-01 10:50:15 -070054
55from core.utilities import Utilities
kelvin-onlabfb521662015-02-27 09:52:40 -080056from core.Thread import Thread
adminbae64d82013-08-01 10:50:15 -070057
Jon Hallca319892017-06-15 15:25:22 -070058class SkipCase( Exception ):
59 pass
60
adminbae64d82013-08-01 10:50:15 -070061class TestON:
62 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -070063 TestON will initiate the specified test.
Jon Hall714eeba2015-09-29 17:53:10 -070064 The main tasks are:
kelvin-onlabf70fd542015-05-07 18:41:40 -070065 * Initiate the required Component handles for the test.
adminbae64d82013-08-01 10:50:15 -070066 * Create Log file Handles.
adminbae64d82013-08-01 10:50:15 -070067 '''
Jon Hall714eeba2015-09-29 17:53:10 -070068 def __init__( self, options ):
adminbae64d82013-08-01 10:50:15 -070069 '''
Jon Hall714eeba2015-09-29 17:53:10 -070070 Initialise the component handles specified in the topology file of
71 the specified test.
adminbae64d82013-08-01 10:50:15 -070072 '''
73 # Initialization of the variables.
74 __builtin__.main = self
adminbae64d82013-08-01 10:50:15 -070075 __builtin__.path = path
76 __builtin__.utilities = Utilities()
77 self.TRUE = 1
78 self.FALSE = 0
79 self.ERROR = -1
kelvin-onlabf70fd542015-05-07 18:41:40 -070080 self.NORESULT = 2
adminbae64d82013-08-01 10:50:15 -070081 self.FAIL = False
82 self.PASS = True
kelvin-onlabf70fd542015-05-07 18:41:40 -070083 self.CASERESULT = self.ERROR
84 self.STEPRESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -070085 self.init_result = self.TRUE
86 self.testResult = "Summary"
kelvin-onlabf70fd542015-05-07 18:41:40 -070087 self.stepName = ""
88 self.stepCache = ""
Jon Halld61331b2015-02-17 16:35:47 -080089 self.EXPERIMENTAL_MODE = False
adminbae64d82013-08-01 10:50:15 -070090 self.test_target = None
91 self.lastcommand = None
Jon Halld61331b2015-02-17 16:35:47 -080092 self.testDir = tests_path
93 self.configFile = config_path + "teston.cfg"
adminbae64d82013-08-01 10:50:15 -070094 self.parsingClass = "xmlparser"
95 self.parserPath = core_path + "/xmlparser"
96 self.loggerPath = core_path + "/logger"
97 self.loggerClass = "Logger"
98 self.logs_path = logs_path
99 self.driver = ''
kelvin-onlabfb521662015-02-27 09:52:40 -0800100 self.Thread = Thread
Jon Hall5b586732015-06-11 11:39:39 -0700101 self.cleanupFlag = False
102 self.cleanupLock = threading.Lock()
Jon Hall0fc0d452015-07-14 09:49:58 -0700103 self.initiated = False
Jon Hall65844a32015-03-09 19:09:37 -0700104
Jon Hall25079782015-10-13 13:54:39 -0700105 self.config = self.configparser()
Jon Hall714eeba2015-09-29 17:53:10 -0700106 verifyOptions( options )
adminbae64d82013-08-01 10:50:15 -0700107 load_logger()
108 self.componentDictionary = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700109 self.componentDictionary = self.topology['COMPONENT']
110 self.driversList = []
111 if isinstance( self.componentDictionary, str):
112 self.componentDictionary = dict( self.componentDictionary )
Jon Hall65844a32015-03-09 19:09:37 -0700113
Jon Hall714eeba2015-09-29 17:53:10 -0700114 for component in self.componentDictionary:
115 self.driversList.append( self.componentDictionary[component]['type'] )
Jon Hall65844a32015-03-09 19:09:37 -0700116
Jon Hall714eeba2015-09-29 17:53:10 -0700117 self.driversList = list( set( self.driversList ) ) # Removing duplicates.
adminbae64d82013-08-01 10:50:15 -0700118 # Checking the test_target option set for the component or not
Jon Hall714eeba2015-09-29 17:53:10 -0700119 if isinstance( self.componentDictionary, dict ):
adminbae64d82013-08-01 10:50:15 -0700120 for component in self.componentDictionary.keys():
121 if 'test_target' in self.componentDictionary[component].keys():
122 self.test_target = component
Jon Hall65844a32015-03-09 19:09:37 -0700123
Jon Halld61331b2015-02-17 16:35:47 -0800124 # Checking for the openspeak file and test script
Jon Hall714eeba2015-09-29 17:53:10 -0700125 self.logger.initlog( self )
adminbae64d82013-08-01 10:50:15 -0700126
127 # Creating Drivers Handles
Jon Hall714eeba2015-09-29 17:53:10 -0700128 initString = "\n" + "*" * 30 + "\n CASE INIT \n" + "*" * 30 + "\n"
129 self.log.exact( initString )
adminbae64d82013-08-01 10:50:15 -0700130 self.driverObject = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700131 self.random_order = 111 # Random order id to connect the components
adminbae64d82013-08-01 10:50:15 -0700132 components_connect_order = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700133 if isinstance( self.componentDictionary, dict ):
adminbae64d82013-08-01 10:50:15 -0700134 for component in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700135 if 'connect_order' not in self.componentDictionary[component].keys():
136 self.componentDictionary[component]['connect_order'] = str( self.get_random() )
137 components_connect_order[component] = eval( self.componentDictionary[component]['connect_order'] )
138 # Ordering components based on the connect order.
139 ordered_component_list = sorted( components_connect_order,
140 key=lambda key: components_connect_order[key] )
adminbae64d82013-08-01 10:50:15 -0700141 print ordered_component_list
adminbae64d82013-08-01 10:50:15 -0700142 for component in ordered_component_list:
Jon Hall714eeba2015-09-29 17:53:10 -0700143 self.componentInit( component )
adminbae64d82013-08-01 10:50:15 -0700144
Jon Hall714eeba2015-09-29 17:53:10 -0700145 def configparser( self ):
adminbae64d82013-08-01 10:50:15 -0700146 '''
147 It will parse the config file (teston.cfg) and return as dictionary
148 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700149 matchFileName = re.match( r'(.*)\.cfg', self.configFile, re.M | re.I )
adminbae64d82013-08-01 10:50:15 -0700150 if matchFileName:
Jon Hall714eeba2015-09-29 17:53:10 -0700151 xml = open( self.configFile ).read()
152 try:
153 self.configDict = xmldict.xml_to_dict( xml )
adminbae64d82013-08-01 10:50:15 -0700154 return self.configDict
Jon Hall1306a562015-09-04 11:21:24 -0700155 except IOError:
adminbae64d82013-08-01 10:50:15 -0700156 print "There is no such file to parse " + self.configFile
Jon Hall1306a562015-09-04 11:21:24 -0700157 else:
158 print "There is no such file to parse " + self.configFile
kelvin-onlabf70fd542015-05-07 18:41:40 -0700159
Jon Hall714eeba2015-09-29 17:53:10 -0700160 def componentInit( self, component ):
adminbae64d82013-08-01 10:50:15 -0700161 '''
162 This method will initialize specified component
163 '''
164 global driver_options
Jon Hall0fc0d452015-07-14 09:49:58 -0700165 self.initiated = False
Jon Hall714eeba2015-09-29 17:53:10 -0700166 self.log.info( "Creating component Handle: " + component )
Jon Halld61331b2015-02-17 16:35:47 -0800167 driver_options = {}
adminbae64d82013-08-01 10:50:15 -0700168 if 'COMPONENTS' in self.componentDictionary[component].keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700169 driver_options = dict( self.componentDictionary[component]['COMPONENTS'] )
Jon Hall714eeba2015-09-29 17:53:10 -0700170 driver_options['name'] = component
adminbae64d82013-08-01 10:50:15 -0700171 driverName = self.componentDictionary[component]['type']
Jon Hall714eeba2015-09-29 17:53:10 -0700172 driver_options['type'] = driverName
kelvin-onlabf70fd542015-05-07 18:41:40 -0700173
Jon Hall714eeba2015-09-29 17:53:10 -0700174 classPath = self.getDriverPath( driverName.lower() )
175 driverModule = importlib.import_module( classPath )
176 driverClass = getattr( driverModule, driverName )
adminbae64d82013-08-01 10:50:15 -0700177 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700178
Jon Hall714eeba2015-09-29 17:53:10 -0700179 if "OCN" in self.componentDictionary[component]['host'] and\
180 main.onoscell:
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700181 self.componentDictionary[component]['host'] = main.mnIP
182
Jon Hall714eeba2015-09-29 17:53:10 -0700183 user_name = self.componentDictionary[component].get( 'user',
184 getpass.getuser() )
185 ip_address = self.componentDictionary[component].get( 'host',
186 'localhost' )
187 pwd = self.componentDictionary[component].get( 'password',
188 'changeme' )
189 port = self.componentDictionary[component].get( 'port' )
190 connect_result = driverObject.connect( user_name=user_name,
191 ip_address=ip_address,
192 pwd=pwd,
193 port=port,
194 options=driver_options)
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700195
adminbae64d82013-08-01 10:50:15 -0700196 if not connect_result:
Jon Hall714eeba2015-09-29 17:53:10 -0700197 self.log.error( "Exiting from the test execution because connecting to the " +
198 component + " component failed." )
Jon Halld61331b2015-02-17 16:35:47 -0800199 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700200
Jon Hall714eeba2015-09-29 17:53:10 -0700201 vars( self )[component] = driverObject
Jon Hall0fc0d452015-07-14 09:49:58 -0700202 self.initiated = True
Jon Hallca319892017-06-15 15:25:22 -0700203 return driverObject
kelvin-onlabf70fd542015-05-07 18:41:40 -0700204
Jon Hall714eeba2015-09-29 17:53:10 -0700205 def run( self ):
adminbae64d82013-08-01 10:50:15 -0700206 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700207 The Execution of the test script's cases listed in the Test params
208 file will be done here then update each test case result.
209 This method will return main.TRUE if it executed all the test cases
210 successfully, else will retun main.FALSE
adminbae64d82013-08-01 10:50:15 -0700211 '''
adminbae64d82013-08-01 10:50:15 -0700212 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700213 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700214 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800215 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700216 self.TOTAL_TC_NORESULT = 0
217 self.TOTAL_TC_FAIL = 0
218 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700219 self.TEST_ITERATION = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700220
221 # NOTE: number of main.step statements in the
222 # outer most level of the test case. used to
223 # execute code in smaller steps
224 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700225 self.CASERESULT = self.NORESULT
226
Jon Halld61331b2015-02-17 16:35:47 -0800227 import testparser
Jon Hall53c5e662016-04-13 16:06:56 -0700228 test = testparser.TestParser( main.testFile )
adminbae64d82013-08-01 10:50:15 -0700229 self.testscript = test.testscript
230 self.code = test.getStepCode()
Jon Hall714eeba2015-09-29 17:53:10 -0700231 repeat = int( self.params.get( 'repeat', 1 ) )
232 self.TOTAL_TC_PLANNED = len( self.testcases_list ) * repeat
kelvin-onlabf70fd542015-05-07 18:41:40 -0700233
adminbae64d82013-08-01 10:50:15 -0700234 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700235 while repeat:
Jon Halla1185982014-09-15 14:55:10 -0700236 for self.CurrentTestCaseNumber in self.testcases_list:
Jon Hall714eeba2015-09-29 17:53:10 -0700237 result = self.runCase( self.CurrentTestCaseNumber )
238 repeat -= 1
adminbae64d82013-08-01 10:50:15 -0700239 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700240
Jon Halle234cc42015-08-31 15:26:47 -0700241 def runCase( self, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700242 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700243 self.CurrentTestCase = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700244
245 # List of step results in a case. ANDed together to get the result
246 self.stepResultsList = []
kelvin-onlabf70fd542015-05-07 18:41:40 -0700247 self.stepName = ""
Jon Hall783bbf92015-07-23 14:33:19 -0700248 self.caseExplanation = ""
adminbae64d82013-08-01 10:50:15 -0700249 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700250
251 # NOTE: number of main.step statements in the
252 # outer most level of the test case. used to
253 # execute code in smaller steps
254 self.stepCount = 0
255
256 # NOTE: This is the current number of main.step()'s executed
257 # in a case. Used for logging.
258 self.stepNumber = 0
adminbae64d82013-08-01 10:50:15 -0700259 self.EXPERIMENTAL_MODE = self.FALSE
260 self.addCaseHeader()
Jon Halle234cc42015-08-31 15:26:47 -0700261 self.testCaseNumber = str( testCaseNumber )
262 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700263 stopped = False
Jon Hall5a72b712015-09-28 12:20:59 -0700264 try:
265 self.code[self.testCaseNumber]
Jon Halld61331b2015-02-17 16:35:47 -0800266 except KeyError:
Jon Halle234cc42015-08-31 15:26:47 -0700267 self.log.error( "There is no Test-Case " + self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800268 return self.FALSE
adminbae64d82013-08-01 10:50:15 -0700269 self.stepCount = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700270 while self.stepCount < len( self.code[self.testCaseNumber].keys() ):
271 result = self.runStep( self.code, self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800272 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700273 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800274 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700275 continue
Jon Hall5a72b712015-09-28 12:20:59 -0700276 # stepResults format: ( stepNo[], stepName[], stepResult[], onFail[] )
277 stepResults = self.stepResultsList
Jon Halle234cc42015-08-31 15:26:47 -0700278 if not stopped:
279 if self.CASERESULT == self.TRUE or self.CASERESULT == self.FALSE:
Jon Hall714eeba2015-09-29 17:53:10 -0700280 # Result was already explitily set somewhere else like
281 # in skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700282 pass
Jon Hall5a72b712015-09-28 12:20:59 -0700283 elif all( self.TRUE == i for i in stepResults ):
kelvin-onlabf70fd542015-05-07 18:41:40 -0700284 # ALL PASSED
285 self.CASERESULT = self.TRUE
Jon Hall5a72b712015-09-28 12:20:59 -0700286 elif self.FALSE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700287 # AT LEAST ONE FAILED
288 self.CASERESULT = self.FALSE
Jon Hall5a72b712015-09-28 12:20:59 -0700289 elif self.TRUE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700290 # AT LEAST ONE PASSED
291 self.CASERESULT = self.TRUE
292 else:
293 self.CASERESULT = self.NORESULT
Jon Hall714eeba2015-09-29 17:53:10 -0700294 self.testCaseResult[str( self.CurrentTestCaseNumber )] = self.CASERESULT
295 self.logger.updateCaseResults( self )
Jon Hall783bbf92015-07-23 14:33:19 -0700296 self.log.wiki( "<p>" + self.caseExplanation + "</p>" )
297 self.log.summary( self.caseExplanation )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700298 self.log.wiki( "<ul>" )
acsmarse2d1ed12015-10-05 13:51:17 -0700299 subcaseMessage = False
kelvin-onlabf70fd542015-05-07 18:41:40 -0700300 for line in self.stepCache.splitlines():
acsmarse2d1ed12015-10-05 13:51:17 -0700301 if re.search( "[0-9]\.[0-9]", line ): # Step
302 if subcaseMessage: # End of Failure Message Printout
303 self.log.wiki( "</ul>\n" )
304 subcaseMessage = False
305 if re.search( " - PASS$", line ):
306 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
307 elif re.search( " - FAIL$", line ):
308 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
309 elif re.search( " - No Result$", line ):
310 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
311 else: # Substep
312 if not subcaseMessage: # Open Failure Message Printout
313 self.log.wiki( "<ul><li>" + line + "</li>\n" )
314 subcaseMessage = True
315 else: # Add to Failure Message Printout
316 self.log.wiki( "<li>" + line + "</li>\n" )
acsmars27e62dd2015-10-06 11:35:47 -0700317 if subcaseMessage: # End of Failure Message Printout for last item
318 self.log.wiki( "</ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700319 self.log.wiki( "</ul>" )
320 self.log.summary( self.stepCache )
321 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700322 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700323
Jon Hall714eeba2015-09-29 17:53:10 -0700324 def runStep( self, code, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700325 if not cli.pause:
Jon Hall5a72b712015-09-28 12:20:59 -0700326 try:
327 step = self.stepCount
328 # stepResults format: ( stepNo, stepName, stepResult, onFail )
329 # NOTE: This is needed to catch results of main.step()'s
330 # called inside functions or loops
331 self.stepResults = ( [], [], [], [] )
adminbae64d82013-08-01 10:50:15 -0700332 exec code[testCaseNumber][step] in module.__dict__
333 self.stepCount = self.stepCount + 1
Jon Hall96b816f2015-11-03 12:00:56 -0800334 self.parseStepResults( testCaseNumber )
Jon Hallca319892017-06-15 15:25:22 -0700335 except SkipCase: # Raised in self.skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700336 self.log.warn( "Skipping the rest of CASE" +
337 str( testCaseNumber ) )
Jon Hall96b816f2015-11-03 12:00:56 -0800338 self.parseStepResults( testCaseNumber )
Jon Hall714eeba2015-09-29 17:53:10 -0700339 self.stepResultsList.append( self.STEPRESULT )
Jon Halle234cc42015-08-31 15:26:47 -0700340 self.stepCache += "\t\t" + self.onFailMsg + "\n"
341 self.stepCount = self.stepCount + 1
342 return self.FALSE
Jon Hallc1606352015-10-06 14:51:36 -0700343 except StandardError as e:
344 try:
345 stepNo = self.stepResults[0][ self.stepNumber - 1 ]
346 except IndexError:
347 stepNo = "<IndexError>"
348 main.log.warn( "Error trying to get step number. " +
349 "It is likely between step " +
Jon Hall6e709752016-02-01 13:38:46 -0800350 str( self.stepNumber ) + " and step " +
Jon Hallc1606352015-10-06 14:51:36 -0700351 str( self.stepNumber + 1 ) )
352 try:
353 stepName = self.stepResults[1][ self.stepNumber - 1 ]
354 except IndexError:
355 stepName = "<IndexError>"
356 self.log.error( "\nException in the following section of" +
357 " code: " + str( testCaseNumber ) + "." +
358 str( stepNo ) + ": " + stepName )
Jeremyd9e4eb12016-04-13 12:09:06 -0700359 self.log.error( str( e.__class__ ) + str( e.message ) )
adminbae64d82013-08-01 10:50:15 -0700360 self.stepCount = self.stepCount + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700361 self.logger.updateCaseResults( self )
362 # WIKI results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700363 self.log.wiki( "<ul>" )
364 for line in self.stepCache.splitlines():
365 if re.search( " - PASS$", line ):
366 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
367 elif re.search( " - FAIL$", line ):
368 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
369 elif re.search( " - No Result$", line ):
370 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
Jon Hall90627612015-06-09 14:57:02 -0700371 else: # Should only be on fail message
372 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700373 self.log.wiki( "</ul>" )
Jon Hall714eeba2015-09-29 17:53:10 -0700374 # summary results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700375 self.log.summary( self.stepCache )
376 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700377 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700378 self.exit()
Jon Halle234cc42015-08-31 15:26:47 -0700379 return self.TRUE
adminbae64d82013-08-01 10:50:15 -0700380 if cli.stop:
381 cli.stop = False
adminbae64d82013-08-01 10:50:15 -0700382 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700383 self.testCaseResult[str( self.CurrentTestCaseNumber )] = "Stopped"
384 self.logger.updateCaseResults( self )
adminbae64d82013-08-01 10:50:15 -0700385 result = self.cleanup()
Jon Halle234cc42015-08-31 15:26:47 -0700386 return self.FALSE
387
Jon Hall96b816f2015-11-03 12:00:56 -0800388 def parseStepResults( self, testCaseNumber ):
389 """
390 Parse throught the step results for the wiki
391 """
392 try:
393 # Iterate through each of the steps and print them
394 for index in range( len( self.stepResults[0] ) ):
395 # stepResults = ( stepNo, stepName, stepResult, onFail )
396 stepNo = self.stepResults[0][ index ]
397 stepName = self.stepResults[1][ index ]
398 stepResult = self.stepResults[2][ index ]
399 onFail = self.stepResults[3][ index ]
400 self.stepCache += "\t" + str( testCaseNumber ) + "."
401 self.stepCache += str( stepNo ) + " "
402 self.stepCache += stepName + " - "
403 if stepResult == self.TRUE:
404 self.stepCache += "PASS\n"
405 elif stepResult == self.FALSE:
406 self.stepCache += "FAIL\n"
407 self.stepCache += "\t\t" + onFail + "\n"
408 else:
409 self.stepCache += "No Result\n"
410 self.stepResultsList.append( stepResult )
411 except Exception:
412 self.log.exception( "Error parsing step results" )
413
Jon Halle234cc42015-08-31 15:26:47 -0700414 def skipCase( self, result="DEFAULT", msg=None ):
415 """
416 Will skip the rest of the code in a test case. The case results will be
417 determined as normal based on completed assertions unless the result
418 argument is given.
419
420 Optional Arguments:
Jon Hall7c4f4302016-07-15 14:39:02 -0700421 result: Case insensitive string. Can be 'PASS' or 'FAIL' and will set
Jon Halle234cc42015-08-31 15:26:47 -0700422 the case result accordingly.
423 msg: Message to be printed when the case is skipped in the reports.
424 """
425 result = result.upper().strip()
426 if result == "PASS":
427 self.CASERESULT = self.TRUE
428 elif result == "FAIL":
429 self.CASERESULT = self.FALSE
430 self.onFailMsg = "Skipping the rest of this case. "
431 if msg:
432 self.onFailMsg += str( msg )
Jon Hallca319892017-06-15 15:25:22 -0700433 raise SkipCase
kelvin-onlabf70fd542015-05-07 18:41:40 -0700434
Jon Hall714eeba2015-09-29 17:53:10 -0700435 def addCaseHeader( self ):
436 caseHeader = "\n" + "*" * 30 + "\n Result summary for Testcase" +\
437 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 30 + "\n"
438 self.log.exact( caseHeader )
439 caseHeader = "\n" + "*" * 40 + "\nStart of Test Case" +\
440 str( self.CurrentTestCaseNumber ) + " : "
adminbae64d82013-08-01 10:50:15 -0700441 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700442 vars( self )[driver + 'log'].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700443
Jon Hall714eeba2015-09-29 17:53:10 -0700444 def addCaseFooter( self ):
Jon Hall5a72b712015-09-28 12:20:59 -0700445 stepNo = self.stepResults[0][-2]
Jon Hall714eeba2015-09-29 17:53:10 -0700446 if stepNo > 0:
447 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." +\
448 str( stepNo ) + ": " + str( self.stepName )
449 stepHeader = "\n" + "*" * 40 + "\nEnd of Step " + previousStep +\
450 "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700451
Jon Hall714eeba2015-09-29 17:53:10 -0700452 caseFooter = "\n" + "*" * 40 + "\nEnd of Test case " +\
453 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700454
adminbae64d82013-08-01 10:50:15 -0700455 for driver in self.driversList:
Jon Hall714eeba2015-09-29 17:53:10 -0700456 vars( self )[driver].write( stepHeader + "\n" + caseFooter )
adminbae64d82013-08-01 10:50:15 -0700457
Jon Hall714eeba2015-09-29 17:53:10 -0700458 def cleanup( self ):
adminbae64d82013-08-01 10:50:15 -0700459 '''
Jon Hall5b586732015-06-11 11:39:39 -0700460 Print a summary of the current test's results then attempt to release
461 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700462
Jon Hall5b586732015-06-11 11:39:39 -0700463 This function shouldbe threadsafe such that cleanup will only be
464 executed once per test.
465
466 This will return TRUE if all the component handles and log handles
467 closed properly, else return FALSE.
adminbae64d82013-08-01 10:50:15 -0700468 '''
469 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700470 lock = self.cleanupLock
471 if lock.acquire( False ):
472 try:
473 if self.cleanupFlag is False: # First thread to run this
474 self.cleanupFlag = True
Jon Hall0fc0d452015-07-14 09:49:58 -0700475 if self.initiated:
Jon Hall714eeba2015-09-29 17:53:10 -0700476 self.logger.testSummary( self )
Jon Hall892818c2015-10-20 17:58:34 -0700477 components = self.componentDictionary
478 for component in sorted( components,
479 key=lambda item: components[item]['connect_order'],
480 reverse=True ):
Jon Hall714eeba2015-09-29 17:53:10 -0700481 try:
482 tempObject = vars( self )[component]
483 print "Disconnecting from " + str( tempObject.name ) +\
484 ": " + str( tempObject.__class__)
Jon Hall5b586732015-06-11 11:39:39 -0700485 tempObject.disconnect()
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( component ) )
492 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700493 self.log.exception( "Exception while disconnecting from " +
494 str( component ) )
495 result = self.FALSE
496 # Closing all the driver's session files
497 for driver in self.componentDictionary.keys():
498 try:
Jon Hall714eeba2015-09-29 17:53:10 -0700499 vars( self )[driver].close_log_handles()
Jon Hall1306a562015-09-04 11:21:24 -0700500 except KeyboardInterrupt:
501 pass
502 except KeyError:
503 # Component not created yet
504 self.log.warn( "Could not find the component " +
505 str( driver ) + " while trying to" +
506 " close log file" )
507 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700508 self.log.exception( "Exception while closing log files for " +
509 str( driver ) )
510 result = self.FALSE
511 else:
512 pass # Someone else already ran through this function
513 finally:
514 lock.release()
515 else: # Someone already has a lock
516 # NOTE: This could cause problems if we don't release the lock
517 # correctly
518 lock.acquire() # Wait for the other thread to finish
519 # NOTE: If we don't wait, exit could be called while the thread
520 # with the lock is still cleaning up
521 lock.release()
adminbae64d82013-08-01 10:50:15 -0700522 return result
Jon Halld61331b2015-02-17 16:35:47 -0800523
Jon Hall714eeba2015-09-29 17:53:10 -0700524 def pause( self ):
adminbae64d82013-08-01 10:50:15 -0700525 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700526 This function will pause the test's execution, and will continue after
527 user provide 'resume' command.
adminbae64d82013-08-01 10:50:15 -0700528 '''
529 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700530
Jon Hall714eeba2015-09-29 17:53:10 -0700531 def onfail( self, *components ):
adminbae64d82013-08-01 10:50:15 -0700532 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700533 When test step failed, calling all the components onfail.
adminbae64d82013-08-01 10:50:15 -0700534 '''
adminbae64d82013-08-01 10:50:15 -0700535 if not components:
Jon Hall714eeba2015-09-29 17:53:10 -0700536 try:
adminbae64d82013-08-01 10:50:15 -0700537 for component in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700538 tempObject = vars( self )[component]
adminbae64d82013-08-01 10:50:15 -0700539 result = tempObject.onfail()
Jon Hall1306a562015-09-04 11:21:24 -0700540 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700541 print str( e )
adminbae64d82013-08-01 10:50:15 -0700542 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700543 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700544 try:
adminbae64d82013-08-01 10:50:15 -0700545 for component in components:
Jon Hall714eeba2015-09-29 17:53:10 -0700546 tempObject = vars( self )[component]
adminbae64d82013-08-01 10:50:15 -0700547 result = tempObject.onfail()
Jon Hall1306a562015-09-04 11:21:24 -0700548 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700549 print str( e )
adminbae64d82013-08-01 10:50:15 -0700550 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700551
Jon Hall714eeba2015-09-29 17:53:10 -0700552 def getDriverPath( self, driverName ):
adminbae64d82013-08-01 10:50:15 -0700553 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700554 Based on the component 'type' specified in the params , this method
555 will find the absolute path, by recursively searching the name of
556 the component.
557
558 NOTE: This function requires the linux 'find' command.
adminbae64d82013-08-01 10:50:15 -0700559 '''
560 import commands
561
Jon Hall714eeba2015-09-29 17:53:10 -0700562 cmd = "find " + drivers_path + " -name " + driverName + ".py"
563 result = commands.getoutput( cmd )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700564
Jon Hall714eeba2015-09-29 17:53:10 -0700565 result_array = str( result ).split( '\n' )
adminbae64d82013-08-01 10:50:15 -0700566 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700567
adminbae64d82013-08-01 10:50:15 -0700568 for drivers_list in result_array:
Jon Hall714eeba2015-09-29 17:53:10 -0700569 result_count = result_count + 1
570 if result_count > 1:
571 print "Found " + driverName + " " + str( result_count ) + " times:"
572 print str( result_array )
adminbae64d82013-08-01 10:50:15 -0700573 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700574
Jon Hall714eeba2015-09-29 17:53:10 -0700575 result = re.sub( "(.*)drivers", "", result )
576 result = re.sub( "\/\/", "/", result )
577 result = re.sub( "\.py", "", result )
578 result = re.sub( "\.pyc", "", result )
579 result = re.sub( "\/", ".", result )
580 result = "drivers" + result
adminbae64d82013-08-01 10:50:15 -0700581 return result
adminbae64d82013-08-01 10:50:15 -0700582
Jon Hall714eeba2015-09-29 17:53:10 -0700583 def step( self, stepDesc ):
adminbae64d82013-08-01 10:50:15 -0700584 '''
585 The step information of the test-case will append to the logs.
586 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700587 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." +\
588 str( self.stepNumber ) + ": " + str( self.stepName )
adminbae64d82013-08-01 10:50:15 -0700589 self.stepName = stepDesc
Jon Hall5a72b712015-09-28 12:20:59 -0700590 self.stepNumber += 1
591 self.stepResults[0].append( self.stepNumber )
592 self.stepResults[1].append( stepDesc )
593 self.stepResults[2].append( self.NORESULT )
594 self.stepResults[3].append( "No on fail message given" )
adminbae64d82013-08-01 10:50:15 -0700595
Jon Hall714eeba2015-09-29 17:53:10 -0700596 stepName = " " + str( self.CurrentTestCaseNumber ) + "." +\
597 str( self.stepNumber ) + ": " + str( stepDesc )
adminbae64d82013-08-01 10:50:15 -0700598 self.log.step(stepName)
599 stepHeader = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700600 line = "\n" + "-" * 45 + "\n"
601 if self.stepNumber > 1:
602 stepHeader = line + "End of Step " + previousStep + line
603 stepHeader += line + "Start of Step" + stepName + line
adminbae64d82013-08-01 10:50:15 -0700604 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700605 vars( self )[driver + 'log'].info( stepHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700606
Jon Hall714eeba2015-09-29 17:53:10 -0700607 def case( self, testCaseName ):
adminbae64d82013-08-01 10:50:15 -0700608 '''
609 Test's each test-case information will append to the logs.
610 '''
Jon Halld61331b2015-02-17 16:35:47 -0800611 self.CurrentTestCase = testCaseName
Jon Hall714eeba2015-09-29 17:53:10 -0700612 testCaseName = " " + str( testCaseName )
613 self.log.case( testCaseName )
614 caseHeader = testCaseName + "\n" + "*" * 40 + "\n"
adminbae64d82013-08-01 10:50:15 -0700615 for driver in self.componentDictionary.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700616 vars( self )[driver + 'log'].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700617
Jon Hall714eeba2015-09-29 17:53:10 -0700618 def testDesc( self, description ):
adminbae64d82013-08-01 10:50:15 -0700619 '''
620 Test description will append to the logs.
621 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700622 description = "Test Description : " + str( description )
623 self.log.info( description )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700624
Jon Hall714eeba2015-09-29 17:53:10 -0700625 def _getTest( self ):
adminbae64d82013-08-01 10:50:15 -0700626 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700627 This method will parse the test script to find required test
628 information.
adminbae64d82013-08-01 10:50:15 -0700629 '''
Jon Hall53c5e662016-04-13 16:06:56 -0700630 testFileHandler = open( main.testFile, 'r' )
adminbae64d82013-08-01 10:50:15 -0700631 testFileList = testFileHandler.readlines()
632 testFileHandler.close()
adminbae64d82013-08-01 10:50:15 -0700633 counter = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700634 for index in range( len( testFileList ) ):
635 lineMatch = re.match( '\s+def CASE(\d+)(.*):',
636 testFileList[index],
637 0 )
adminbae64d82013-08-01 10:50:15 -0700638 if lineMatch:
Jon Hall714eeba2015-09-29 17:53:10 -0700639 counter = counter + 1
640 self.TC_PLANNED = len( self.testcases_list )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700641
Jon Hall714eeba2015-09-29 17:53:10 -0700642 def response_parser( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700643 ''' It will load the default response parser '''
644 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700645 response_dict = self.response_to_dict( response, return_format )
646 return_format_string = self.dict_to_return_format( response,
647 return_format,
648 response_dict )
adminbae64d82013-08-01 10:50:15 -0700649 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700650
Jon Hall714eeba2015-09-29 17:53:10 -0700651 def response_to_dict( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700652 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700653 json_match = re.search( '^\s*{', response )
654 xml_match = re.search( '^\s*\<', response )
655 ini_match = re.search( '^\s*\[', response )
656 if json_match:
657 self.log.info( "Response is in 'JSON' format, converting to '" +
658 return_format + "' format" )
Jon Halld61331b2015-02-17 16:35:47 -0800659 # Formatting the json string
Jon Hall714eeba2015-09-29 17:53:10 -0700660 response = re.sub( r"{\s*'?(\w)", r'{"\1', response )
661 response = re.sub( r",\s*'?(\w)", r',"\1', response )
662 response = re.sub( r"(\w)'?\s*:", r'\1":', response )
663 response = re.sub( r":\s*'(\w)'\s*([,}])", r':"\1"\2', response )
664 try:
adminbae64d82013-08-01 10:50:15 -0700665 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700666 response_dict = json.loads( response )
Jon Hall1306a562015-09-04 11:21:24 -0700667 except StandardError:
Jon Hall2a5002c2015-08-21 16:49:11 -0700668 self.log.exception( "Json Parser is unable to parse the string" )
adminbae64d82013-08-01 10:50:15 -0700669 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700670 elif ini_match:
671 self.log.info( "Response is in 'INI' format, converting to '" +
672 return_format + "' format" )
adminbae64d82013-08-01 10:50:15 -0700673 from configobj import ConfigObj
Jon Hall714eeba2015-09-29 17:53:10 -0700674 response_file = open( "respnse_file.temp", 'w' )
675 response_file.write( response )
Jon Halld61331b2015-02-17 16:35:47 -0800676 response_file.close()
Jon Hall714eeba2015-09-29 17:53:10 -0700677 response_dict = ConfigObj( "respnse_file.temp" )
adminbae64d82013-08-01 10:50:15 -0700678 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700679 elif xml_match:
680 self.log.info( "Response is in 'XML' format, converting to '" +
681 return_format + "' format" )
682 try:
683 response_dict = xmldict.xml_to_dict( "<response> " +
684 str( response ) +
685 " </response>" )
Jon Hall1306a562015-09-04 11:21:24 -0700686 except StandardError:
687 self.log.exception()
adminbae64d82013-08-01 10:50:15 -0700688 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700689
Jon Hall714eeba2015-09-29 17:53:10 -0700690 def dict_to_return_format( self, response, return_format, response_dict ):
691 if return_format == 'table':
adminbae64d82013-08-01 10:50:15 -0700692 ''' Will return in table format'''
693 to_do = "Call the table output formatter"
694 global response_table
695 response_table = '\n'
Jon Hall714eeba2015-09-29 17:53:10 -0700696 response_table = response_table + '\t'.join( response_dict ) + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700697
Jon Hall714eeba2015-09-29 17:53:10 -0700698 def get_table( value_to_convert ):
699 ''' This will parse the dictionary recusrsively and print as
700 table format'''
adminbae64d82013-08-01 10:50:15 -0700701 table_data = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700702 if isinstance( value_to_convert, dict ):
703 table_data = table_data + '\t'.join( value_to_convert ) +\
704 "\n"
705 for temp_val in value_to_convert.values():
706 table_data = table_data + get_table( temp_val )
707 else:
708 table_data = table_data + str( value_to_convert ) + "\t"
Jon Halld61331b2015-02-17 16:35:47 -0800709 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700710
Jon Hall714eeba2015-09-29 17:53:10 -0700711 for value in response_dict.values():
712 response_table = response_table + get_table( value )
adminbae64d82013-08-01 10:50:15 -0700713 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700714
Jon Hall714eeba2015-09-29 17:53:10 -0700715 elif return_format == 'config':
adminbae64d82013-08-01 10:50:15 -0700716 ''' Will return in config format'''
717 to_do = 'Call dict to config coverter'
Jon Hall714eeba2015-09-29 17:53:10 -0700718 response_string = str( response_dict )
adminbae64d82013-08-01 10:50:15 -0700719 print response_string
Jon Hall714eeba2015-09-29 17:53:10 -0700720 response_config = re.sub( ",", "\n\t", response_string )
721 response_config = re.sub( "u\'", "\'", response_config )
722 response_config = re.sub( "{", "", response_config )
723 response_config = re.sub( "}", "\n", response_config )
724 response_config = re.sub( ":", " =", response_config )
725 return "[response]\n\t " + response_config
adminbae64d82013-08-01 10:50:15 -0700726 elif return_format == 'xml':
727 ''' Will return in xml format'''
Jon Hall714eeba2015-09-29 17:53:10 -0700728 response_xml = xmldict.dict_to_xml( response_dict )
729 response_xml = re.sub( ">\s*<", ">\n<", response_xml )
730 return "\n" + response_xml
adminbae64d82013-08-01 10:50:15 -0700731 elif return_format == 'json':
732 ''' Will return in json format'''
733 to_do = 'Call dict to xml coverter'
734 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700735 response_json = json.dumps( response_dict )
adminbae64d82013-08-01 10:50:15 -0700736 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700737
Jon Hall714eeba2015-09-29 17:53:10 -0700738 def get_random( self ):
adminbae64d82013-08-01 10:50:15 -0700739 self.random_order = self.random_order + 1
740 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700741
Jon Hall714eeba2015-09-29 17:53:10 -0700742 def exit( self ):
adminbae64d82013-08-01 10:50:15 -0700743 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700744 for thread in threading.enumerate():
745 if thread.isAlive():
746 try:
747 thread._Thread__stop()
748 except:
Jon Hall1306a562015-09-04 11:21:24 -0700749 # NOTE: We should catch any exceptions while trying to
750 # close the thread so that we can try to close the other
751 # threads as well
Jon Hall714eeba2015-09-29 17:53:10 -0700752 print str( thread.getName() ) +\
753 ' could not be terminated'
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700754 os.system( "stty sane" ) # fix format if necessary
adminbae64d82013-08-01 10:50:15 -0700755 sys.exit()
756
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700757
Jon Hallcd3d2a32015-10-01 11:07:28 -0700758 def stop( self, email=False ):
759 """
760 Stop the test until Ctrl-D is entered.
761 Ctrl-C will kill the test
Jon Hall25079782015-10-13 13:54:39 -0700762
763 Optional arguments:
764 email can either be a bool, or you can specify the email address
765 to send the email to
Jon Hallcd3d2a32015-10-01 11:07:28 -0700766 """
767 try:
768 if email:
Jon Hall25079782015-10-13 13:54:39 -0700769 if '@' in email:
770 main.mail = email
771 utilities.send_warning_email()
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700772 self.log.debug( "Test execution suspended. \n"
773 "- Type 'c' to resume the test.\n"
774 "- Type Ctrl-C to exit the test.\n"
775 "- Enter interactive python interpreter commands.\n"
776 "\t- ie: main.Mininet1.pingall()\n"
777 "- Type 'help' for help with pdb." )
778 pdb.set_trace()
Jon Hallcd3d2a32015-10-01 11:07:28 -0700779 except EOFError:
780 return
781 # Pass all other exceptions up to caller
782
783
Jon Hall714eeba2015-09-29 17:53:10 -0700784def verifyOptions( options ):
adminbae64d82013-08-01 10:50:15 -0700785 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700786 This will verify the command line options and set to default values,
787 if any option not given in command line.
adminbae64d82013-08-01 10:50:15 -0700788 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700789 verifyTest( options )
790 verifyExample( options )
791 verifyTestScript( options )
YPZhang1c89e762016-06-29 10:43:58 -0700792 verifyParams( options )
Jon Hall714eeba2015-09-29 17:53:10 -0700793 verifyLogdir( options )
794 verifyMail( options )
795 verifyTestCases( options )
796 verifyOnosCell( options )
adminbae64d82013-08-01 10:50:15 -0700797
Jon Hall714eeba2015-09-29 17:53:10 -0700798def verifyTest( options ):
Jon Hall44506242015-07-29 17:40:26 -0700799 try:
800 if options.testname:
801 main.TEST = options.testname
Jon Hall714eeba2015-09-29 17:53:10 -0700802 main.classPath = "tests." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700803 main.tests_path = tests_path
804 elif options.example:
805 main.TEST = options.example
Jon Hall714eeba2015-09-29 17:53:10 -0700806 main.tests_path = path + "/examples/"
807 main.classPath = "examples." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700808 except AttributeError:
adminbae64d82013-08-01 10:50:15 -0700809 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700810 main.exit()
adminbae64d82013-08-01 10:50:15 -0700811
Jon Hall714eeba2015-09-29 17:53:10 -0700812def verifyExample( options ):
adminbae64d82013-08-01 10:50:15 -0700813 if options.example:
Jon Hall714eeba2015-09-29 17:53:10 -0700814 main.testDir = path + '/examples/'
815 main.tests_path = path + "/examples/"
816 main.classPath = "examples." + main.TEST + "." + main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700817
Jon Hall714eeba2015-09-29 17:53:10 -0700818def verifyLogdir( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800819 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700820 if options.logdir:
821 main.logdir = options.logdir
Jon Hall714eeba2015-09-29 17:53:10 -0700822 else:
Jon Halld61331b2015-02-17 16:35:47 -0800823 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700824
Jon Hall714eeba2015-09-29 17:53:10 -0700825def verifyMail( options ):
Jon Hall25079782015-10-13 13:54:39 -0700826 # Mail-To: field
827 if options.mail: # Test run specific
adminbae64d82013-08-01 10:50:15 -0700828 main.mail = options.mail
Jon Hall25079782015-10-13 13:54:39 -0700829 elif main.params.get('mail'): # Test suite specific
830 main.mail = main.params.get( 'mail' )
831 else: # TestON specific
832 main.mail = main.config['config'].get( 'mail_to' )
833 # Mail-From: field
834 main.sender = main.config['config'].get( 'mail_from' )
835 # Mail smtp server
836 main.smtp = main.config['config'].get( 'mail_server' )
837 # Mail-From account password
838 main.senderPwd = main.config['config'].get( 'mail_pass' )
839
Devin Lim2df68a12017-06-30 15:39:05 -0700840def evalTestCase( tempList ):
841 tList = []
842 for tcase in tempList:
843 if isinstance( tcase, list ):
844 tList.extend( evalTestCase( tcase ) )
845 else:
846 tList.extend( [tcase] )
847 return tList
adminbae64d82013-08-01 10:50:15 -0700848
Jon Hall714eeba2015-09-29 17:53:10 -0700849def verifyTestCases( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800850 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700851 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800852 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800853 # sys.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700854 testcases_list = re.sub( "(\[|\])", "", options.testcases )
855 main.testcases_list = eval( testcases_list + "," )
856 else:
adminbae64d82013-08-01 10:50:15 -0700857 if 'testcases' in main.params.keys():
Jon Hall714eeba2015-09-29 17:53:10 -0700858 temp = eval( main.params['testcases'] + "," )
Devin Lim2df68a12017-06-30 15:39:05 -0700859 main.testcases_list = evalTestCase( list( temp ) )
Jon Hall714eeba2015-09-29 17:53:10 -0700860 else:
861 print "Testcases not specifed in params, please provide in " +\
862 "params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800863 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700864
Jon Hall714eeba2015-09-29 17:53:10 -0700865def verifyOnosCell( options ):
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700866 # Verifying onoscell option
Hari Krishna03f530e2015-07-10 17:28:27 -0700867 if options.onoscell:
868 main.onoscell = options.onoscell
Devin Lim58046fa2017-07-05 16:55:00 -0700869 main.ONOSip = []
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700870 main.mnIP = ""
Devin Lim58046fa2017-07-05 16:55:00 -0700871 cellCMD = ". ~/onos/tools/dev/bash_profile; cell " + main.onoscell
Jon Hall714eeba2015-09-29 17:53:10 -0700872 output = subprocess.check_output( ["bash", '-c', cellCMD] )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700873 splitOutput = output.splitlines()
Devin Lim58046fa2017-07-05 16:55:00 -0700874 main.apps = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700875 for i in range( len( splitOutput ) ):
876 if re.match( "OCN", splitOutput[i] ):
877 mnNode = splitOutput[i].split( "=" )
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700878 main.mnIP = mnNode[1]
Jon Hall714eeba2015-09-29 17:53:10 -0700879 # cell already sorts OC variables in bash, so no need to
880 # sort in TestON
Devin Lim58046fa2017-07-05 16:55:00 -0700881 elif re.match( "OC[1-9]", splitOutput[i] ):
Jon Hall714eeba2015-09-29 17:53:10 -0700882 onosNodes = splitOutput[i].split( "=" )
Devin Lim58046fa2017-07-05 16:55:00 -0700883 main.ONOSip.append( onosNodes[1] )
884 elif re.match( "ONOS_APPS", splitOutput[i] ):
885 main.apps = ( splitOutput[i].split( "=" ) )[1]
Jon Hall714eeba2015-09-29 17:53:10 -0700886 else:
Hari Krishna03f530e2015-07-10 17:28:27 -0700887 main.onoscell = main.FALSE
888
Jon Hall714eeba2015-09-29 17:53:10 -0700889def verifyTestScript( options ):
adminbae64d82013-08-01 10:50:15 -0700890 '''
891 Verifyies test script.
892 '''
Jon Halld61331b2015-02-17 16:35:47 -0800893 main.openspeak = openspeak.OpenSpeak()
Jon Hall53c5e662016-04-13 16:06:56 -0700894 directory = main.testDir + "/" + main.TEST
895 if os.path.exists( directory ):
896 pass
897 else:
898 directory = ""
899 for root, dirs, files in os.walk( main.testDir, topdown=True):
900 if not directory:
901 for name in dirs:
902 if name == main.TEST:
903 directory = ( os.path.join( root, name ) )
904 index = directory.find( "/tests/" ) + 1
905 main.classPath = directory[index:].replace( '/', '.' ) + "." + main.TEST
906 break
907 openspeakfile = directory + "/" + main.TEST + ".ospk"
908 main.testFile = directory + "/" + main.TEST + ".py"
Jon Hall714eeba2015-09-29 17:53:10 -0700909 if os.path.exists( openspeakfile ):
Jon Hall44506242015-07-29 17:40:26 -0700910 # Openspeak file found, compiling to python
Jon Hall714eeba2015-09-29 17:53:10 -0700911 main.openspeak.compiler( openspeakfile=openspeakfile, writetofile=1 )
Jon Hall53c5e662016-04-13 16:06:56 -0700912 elif os.path.exists( main.testFile ):
Jon Hall44506242015-07-29 17:40:26 -0700913 # No openspeak found, using python file instead
914 pass
adminbae64d82013-08-01 10:50:15 -0700915 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700916 print "\nThere is no \"" + main.TEST + "\" test script.\nPlease provide a " +\
Jon Hall44506242015-07-29 17:40:26 -0700917 "Python or OpenSpeak test script in the tests folder: " +\
Jon Hall714eeba2015-09-29 17:53:10 -0700918 main.testDir + "/" + main.TEST + "/"
adminbae64d82013-08-01 10:50:15 -0700919 __builtin__.testthread = None
920 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700921 try:
922 testModule = __import__( main.classPath,
923 globals(),
924 locals(),
925 [main.TEST],
926 -1 )
Jon Hall1306a562015-09-04 11:21:24 -0700927 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -0700928 print "There was an import error, it might mean that there is " +\
929 "no test named " + main.TEST
Jon Halld61331b2015-02-17 16:35:47 -0800930 main.exit()
adminbae64d82013-08-01 10:50:15 -0700931
Jon Hall714eeba2015-09-29 17:53:10 -0700932 testClass = getattr( testModule, main.TEST )
adminbae64d82013-08-01 10:50:15 -0700933 main.testObject = testClass()
934 load_parser()
Jon Hall714eeba2015-09-29 17:53:10 -0700935 main.params = main.parser.parseParams( main.classPath )
936 main.topology = main.parser.parseTopology( main.classPath )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700937
YPZhang1c89e762016-06-29 10:43:58 -0700938def verifyParams( options ):
Jon Hall714eeba2015-09-29 17:53:10 -0700939 try:
adminbae64d82013-08-01 10:50:15 -0700940 main.params = main.params['PARAMS']
Jon Hall1306a562015-09-04 11:21:24 -0700941 except KeyError:
Jon Hall714eeba2015-09-29 17:53:10 -0700942 print "Error with the params file: Either the file not specified " +\
943 "or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -0800944 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700945 try:
adminbae64d82013-08-01 10:50:15 -0700946 main.topology = main.topology['TOPOLOGY']
Jon Hall1306a562015-09-04 11:21:24 -0700947 except KeyError:
Jon Hall714eeba2015-09-29 17:53:10 -0700948 print "Error with the Topology file: Either the file not specified " +\
949 "or the format is not correct"
adminbae64d82013-08-01 10:50:15 -0700950 main.exit()
YPZhang1c89e762016-06-29 10:43:58 -0700951 # Overwrite existing params variables if they are specified from command line
952 if len(options.params) > 0:
953 # Some params variables are specified from command line
954 for param in options.params:
955 if not re.search( ".=.", param ):
956 print( "Error when parsing params: params should follow key=value format" )
957 continue
Jon Hall7c4f4302016-07-15 14:39:02 -0700958 # Split the param string to catch nested keys and the value
YPZhang1c89e762016-06-29 10:43:58 -0700959 [ keys, value ] = param.split( "=" )
960 # Split the nested keys according to its hierarchy
961 keyList = keys.split( "/" )
962 # Get the outermost dictionary
963 paramDict = main.params
964 # Get the innermost dictionary
965 try:
966 while len( keyList ) > 1:
967 key = keyList.pop(0)
968 assert isinstance( paramDict[ key ], dict )
969 paramDict = paramDict[ key ]
970 except KeyError:
971 print( "Error when parsing params: key \"" + key + "\" not found in main.params" )
972 main.exit()
973 except AssertionError:
974 print( "Error when parsing params: \"" + key + "\" is already the innermost level in main.params" )
975 main.exit()
976 # Change the value
977 if not paramDict.has_key( keyList[0] ):
978 print( "Error when parsing params: key \"" + keyList[0] + "\" not found in main.params" )
979 main.exit()
980 elif isinstance( paramDict[ keyList[0] ], dict ):
981 print( "Error when parsing params: more levels under key \"" + keyList[0] + "\" in main.params" )
982 main.exit()
983 else:
984 paramDict[ keyList[0] ] = value
kelvin-onlabf70fd542015-05-07 18:41:40 -0700985
Jon Hall714eeba2015-09-29 17:53:10 -0700986def load_parser():
adminbae64d82013-08-01 10:50:15 -0700987 '''
988 It facilitates the loading customised parser for topology and params file.
989 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -0700990 It also loads default xmlparser if no parser have specified in teston.cfg
991 file.
adminbae64d82013-08-01 10:50:15 -0700992
993 '''
994 confighash = main.configDict
Jon Hall714eeba2015-09-29 17:53:10 -0700995 if 'file' in confighash['config']['parser'] and\
996 'class' in confighash['config']['parser']:
Jon Hall44506242015-07-29 17:40:26 -0700997 path = confighash['config']['parser']['file']
Jon Hall714eeba2015-09-29 17:53:10 -0700998 if path is not None or\
999 confighash['config']['parser']['class'] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001000 try:
1001 module = re.sub( r".py\s*$", "", path )
adminbae64d82013-08-01 10:50:15 -07001002 moduleList = module.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -07001003 newModule = ".".join( moduleList[-2:] )
Jon Hall44506242015-07-29 17:40:26 -07001004 parsingClass = confighash['config']['parser']['class']
Jon Hall714eeba2015-09-29 17:53:10 -07001005 parsingModule = __import__( newModule,
1006 globals(),
1007 locals(),
1008 [parsingClass],
1009 -1 )
1010 parsingClass = getattr( parsingModule, parsingClass )
Jon Hall44506242015-07-29 17:40:26 -07001011 main.parser = parsingClass()
Jon Hall714eeba2015-09-29 17:53:10 -07001012 if hasattr( main.parser, "parseParams" ) and\
1013 hasattr( main.parser, "parseTopology" ) and\
1014 hasattr( main.parser, "parse" ):
Jon Hall44506242015-07-29 17:40:26 -07001015 pass
1016 else:
1017 print "Invalid parser format"
adminbae64d82013-08-01 10:50:15 -07001018 main.exit()
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 parser."
Jon Halld61331b2015-02-17 16:35:47 -08001022 load_defaultParser()
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_defaultParser()
adminbae64d82013-08-01 10:50:15 -07001026 else:
1027 load_defaultParser()
1028
1029def load_defaultParser():
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.parserPath.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -07001035 newModule = ".".join( moduleList[-2:] )
1036 try:
Jon Halld61331b2015-02-17 16:35:47 -08001037 parsingClass = main.parsingClass
Jon Hall714eeba2015-09-29 17:53:10 -07001038 parsingModule = __import__( newModule,
1039 globals(),
1040 locals(),
1041 [parsingClass],
1042 -1 )
1043 parsingClass = getattr( parsingModule, parsingClass )
adminbae64d82013-08-01 10:50:15 -07001044 main.parser = parsingClass()
Jon Hall714eeba2015-09-29 17:53:10 -07001045 if hasattr( main.parser, "parseParams" ) and\
1046 hasattr( main.parser, "parseTopology" ) and\
1047 hasattr( main.parser, "parse" ):
adminbae64d82013-08-01 10:50:15 -07001048 pass
1049 else:
1050 main.exit()
adminbae64d82013-08-01 10:50:15 -07001051 except ImportError:
1052 print sys.exc_info()[1]
1053
Jon Hall714eeba2015-09-29 17:53:10 -07001054def load_logger():
adminbae64d82013-08-01 10:50:15 -07001055 '''
1056 It facilitates the loading customised parser for topology and params file.
1057 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -07001058 It also loads default xmlparser if no parser have specified in teston.cfg
1059 file.
adminbae64d82013-08-01 10:50:15 -07001060 '''
1061 confighash = main.configDict
Jon Hall714eeba2015-09-29 17:53:10 -07001062 if 'file' in confighash['config']['logger'] and\
1063 'class' in confighash['config']['logger']:
Jon Hall44506242015-07-29 17:40:26 -07001064 path = confighash['config']['logger']['file']
Jon Hall714eeba2015-09-29 17:53:10 -07001065 if path is not None or\
1066 confighash['config']['logger']['class'] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001067 try:
1068 module = re.sub( r".py\s*$", "", path )
Jon Hall714eeba2015-09-29 17:53:10 -07001069 moduleList = module.split( "/" )
1070 newModule = ".".join( moduleList[-2:] )
Jon Hall44506242015-07-29 17:40:26 -07001071 loggerClass = confighash['config']['logger']['class']
Jon Hall714eeba2015-09-29 17:53:10 -07001072 loggerModule = __import__( newModule,
1073 globals(),
1074 locals(),
1075 [loggerClass],
1076 -1 )
1077 loggerClass = getattr( loggerModule, loggerClass )
Jon Hall44506242015-07-29 17:40:26 -07001078 main.logger = loggerClass()
Jon Hall44506242015-07-29 17:40:26 -07001079 except ImportError:
Jon Hall714eeba2015-09-29 17:53:10 -07001080 print "Could not find the file " + path +\
1081 " using default logger."
adminbae64d82013-08-01 10:50:15 -07001082 load_defaultlogger()
Jon Hall714eeba2015-09-29 17:53:10 -07001083 elif confighash['config']['parser']['file'] is None or\
1084 confighash['config']['parser']['class'] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001085 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -07001086 else:
1087 load_defaultlogger()
1088
1089def load_defaultlogger():
1090 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001091 It will load the default parser which is xml parser to parse the params and
1092 topology file.
adminbae64d82013-08-01 10:50:15 -07001093 '''
1094 moduleList = main.loggerPath.split("/")
Jon Hall714eeba2015-09-29 17:53:10 -07001095 newModule = ".".join( moduleList[-2:] )
1096 try:
Jon Halld61331b2015-02-17 16:35:47 -08001097 loggerClass = main.loggerClass
Jon Hall714eeba2015-09-29 17:53:10 -07001098 loggerModule = __import__( newModule,
1099 globals(),
1100 locals(),
1101 [loggerClass],
1102 -1 )
1103 loggerClass = getattr( loggerModule, loggerClass )
adminbae64d82013-08-01 10:50:15 -07001104 main.logger = loggerClass()
1105
1106 except ImportError:
1107 print sys.exc_info()[1]
Jon Halld61331b2015-02-17 16:35:47 -08001108 main.exit()
adminbae64d82013-08-01 10:50:15 -07001109
Jon Hall714eeba2015-09-29 17:53:10 -07001110def _echo( self ):
adminbae64d82013-08-01 10:50:15 -07001111 print "THIS IS ECHO"