blob: ff01b00de6d8e1234d771ba19f5304efd39f7d38 [file] [log] [blame]
adminbae64d82013-08-01 10:50:15 -07001#!/usr/bin/env python
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00002'''
adminbae64d82013-08-01 10:50:15 -07003Created on 22-Oct-2012
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00004Copyright 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
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000013 (at your option) any later version.
adminbae64d82013-08-01 10:50:15 -070014
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
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000027'''
28
adminbae64d82013-08-01 10:50:15 -070029import 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:
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000062 '''
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.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000067 '''
Jon Hall714eeba2015-09-29 17:53:10 -070068 def __init__( self, options ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000069 '''
Jon Hall714eeba2015-09-29 17:53:10 -070070 Initialise the component handles specified in the topology file of
71 the specified test.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +000072 '''
adminbae64d82013-08-01 10:50:15 -070073 # 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
Jon Halld74d2952018-03-01 13:26:39 -080093 self.testsRoot = tests_path
Jon Halld61331b2015-02-17 16:35:47 -080094 self.configFile = config_path + "teston.cfg"
adminbae64d82013-08-01 10:50:15 -070095 self.parsingClass = "xmlparser"
96 self.parserPath = core_path + "/xmlparser"
97 self.loggerPath = core_path + "/logger"
98 self.loggerClass = "Logger"
99 self.logs_path = logs_path
100 self.driver = ''
kelvin-onlabfb521662015-02-27 09:52:40 -0800101 self.Thread = Thread
Jon Hall5b586732015-06-11 11:39:39 -0700102 self.cleanupFlag = False
103 self.cleanupLock = threading.Lock()
Jon Hall0fc0d452015-07-14 09:49:58 -0700104 self.initiated = False
Devin Limec989792017-08-15 15:57:55 -0700105 self.executedCase = []
106 self.leftCase = []
107 self.failedCase = []
108 self.noResultCase = []
Jon Hall65844a32015-03-09 19:09:37 -0700109
Jon Hall25079782015-10-13 13:54:39 -0700110 self.config = self.configparser()
Jon Hall714eeba2015-09-29 17:53:10 -0700111 verifyOptions( options )
adminbae64d82013-08-01 10:50:15 -0700112 load_logger()
113 self.componentDictionary = {}
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700114 self.componentDictionary = self.topology[ 'COMPONENT' ]
Jon Hall714eeba2015-09-29 17:53:10 -0700115 self.driversList = []
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700116 if isinstance( self.componentDictionary, str ):
Jon Hall714eeba2015-09-29 17:53:10 -0700117 self.componentDictionary = dict( self.componentDictionary )
Jon Hall65844a32015-03-09 19:09:37 -0700118
Jon Hall714eeba2015-09-29 17:53:10 -0700119 for component in self.componentDictionary:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700120 self.driversList.append( self.componentDictionary[ component ][ 'type' ] )
Jon Hall65844a32015-03-09 19:09:37 -0700121
Jon Hall714eeba2015-09-29 17:53:10 -0700122 self.driversList = list( set( self.driversList ) ) # Removing duplicates.
adminbae64d82013-08-01 10:50:15 -0700123 # Checking the test_target option set for the component or not
Jon Hall714eeba2015-09-29 17:53:10 -0700124 if isinstance( self.componentDictionary, dict ):
adminbae64d82013-08-01 10:50:15 -0700125 for component in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700126 if 'test_target' in self.componentDictionary[ component ].keys():
adminbae64d82013-08-01 10:50:15 -0700127 self.test_target = component
Jon Hall65844a32015-03-09 19:09:37 -0700128
Jon Halld61331b2015-02-17 16:35:47 -0800129 # Checking for the openspeak file and test script
Jon Hall714eeba2015-09-29 17:53:10 -0700130 self.logger.initlog( self )
adminbae64d82013-08-01 10:50:15 -0700131
132 # Creating Drivers Handles
Jon Hall714eeba2015-09-29 17:53:10 -0700133 initString = "\n" + "*" * 30 + "\n CASE INIT \n" + "*" * 30 + "\n"
134 self.log.exact( initString )
adminbae64d82013-08-01 10:50:15 -0700135 self.driverObject = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700136 self.random_order = 111 # Random order id to connect the components
adminbae64d82013-08-01 10:50:15 -0700137 components_connect_order = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700138 if isinstance( self.componentDictionary, dict ):
adminbae64d82013-08-01 10:50:15 -0700139 for component in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700140 if 'connect_order' not in self.componentDictionary[ component ].keys():
141 self.componentDictionary[ component ][ 'connect_order' ] = str( self.get_random() )
142 components_connect_order[ component ] = eval( self.componentDictionary[ component ][ 'connect_order' ] )
Jon Hall714eeba2015-09-29 17:53:10 -0700143 # Ordering components based on the connect order.
144 ordered_component_list = sorted( components_connect_order,
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700145 key=lambda key: components_connect_order[ key ] )
adminbae64d82013-08-01 10:50:15 -0700146 print ordered_component_list
adminbae64d82013-08-01 10:50:15 -0700147 for component in ordered_component_list:
Jon Hall714eeba2015-09-29 17:53:10 -0700148 self.componentInit( component )
adminbae64d82013-08-01 10:50:15 -0700149
Jon Hall714eeba2015-09-29 17:53:10 -0700150 def configparser( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000151 '''
152 It will parse the config file (teston.cfg) and return as dictionary
153 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700154 matchFileName = re.match( r'(.*)\.cfg', self.configFile, re.M | re.I )
adminbae64d82013-08-01 10:50:15 -0700155 if matchFileName:
Jon Hall714eeba2015-09-29 17:53:10 -0700156 xml = open( self.configFile ).read()
157 try:
158 self.configDict = xmldict.xml_to_dict( xml )
adminbae64d82013-08-01 10:50:15 -0700159 return self.configDict
Jon Hall1306a562015-09-04 11:21:24 -0700160 except IOError:
adminbae64d82013-08-01 10:50:15 -0700161 print "There is no such file to parse " + self.configFile
Jon Hall1306a562015-09-04 11:21:24 -0700162 else:
163 print "There is no such file to parse " + self.configFile
kelvin-onlabf70fd542015-05-07 18:41:40 -0700164
Jon Hall714eeba2015-09-29 17:53:10 -0700165 def componentInit( self, component ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000166 '''
adminbae64d82013-08-01 10:50:15 -0700167 This method will initialize specified component
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000168 '''
adminbae64d82013-08-01 10:50:15 -0700169 global driver_options
Jon Hall0fc0d452015-07-14 09:49:58 -0700170 self.initiated = False
Jon Hall3a03cad2021-04-07 11:21:55 -0700171 self.log.info( "Creating component handle: " + component )
Jon Halld61331b2015-02-17 16:35:47 -0800172 driver_options = {}
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700173 if 'COMPONENTS' in self.componentDictionary[ component ].keys():
174 driver_options = dict( self.componentDictionary[ component ][ 'COMPONENTS' ] )
175 driver_options[ 'name' ] = component
176 driverName = self.componentDictionary[ component ][ 'type' ]
177 driver_options[ 'type' ] = driverName
Jon Hall06fd0df2021-01-25 15:50:06 -0800178 driver_home = self.componentDictionary[ component ].get( 'home' )
179 if driver_home:
180 driver_options[ 'home' ] = driver_home
kelvin-onlabf70fd542015-05-07 18:41:40 -0700181
Jon Hall714eeba2015-09-29 17:53:10 -0700182 classPath = self.getDriverPath( driverName.lower() )
183 driverModule = importlib.import_module( classPath )
184 driverClass = getattr( driverModule, driverName )
adminbae64d82013-08-01 10:50:15 -0700185 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700186
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700187 if "OCN" in self.componentDictionary[ component ][ 'host' ] and\
Jon Hall714eeba2015-09-29 17:53:10 -0700188 main.onoscell:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700189 self.componentDictionary[ component ][ 'host' ] = main.mnIP
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700190
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700191 user_name = self.componentDictionary[ component ].get( 'user', getpass.getuser() )
192 ip_address = self.componentDictionary[ component ].get( 'host', 'localhost' )
193 pwd = self.componentDictionary[ component ].get( 'password', 'changeme' )
194 port = self.componentDictionary[ component ].get( 'port' )
Jon Hall714eeba2015-09-29 17:53:10 -0700195 connect_result = driverObject.connect( user_name=user_name,
196 ip_address=ip_address,
197 pwd=pwd,
198 port=port,
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700199 options=driver_options )
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700200
adminbae64d82013-08-01 10:50:15 -0700201 if not connect_result:
Jon Hall714eeba2015-09-29 17:53:10 -0700202 self.log.error( "Exiting from the test execution because connecting to the " +
203 component + " component failed." )
Jon Halld61331b2015-02-17 16:35:47 -0800204 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700205
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700206 vars( self )[ component ] = driverObject
Jon Hall0fc0d452015-07-14 09:49:58 -0700207 self.initiated = True
Jon Hallca319892017-06-15 15:25:22 -0700208 return driverObject
kelvin-onlabf70fd542015-05-07 18:41:40 -0700209
Jon Hall714eeba2015-09-29 17:53:10 -0700210 def run( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000211 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700212 The Execution of the test script's cases listed in the Test params
213 file will be done here then update each test case result.
214 This method will return main.TRUE if it executed all the test cases
215 successfully, else will retun main.FALSE
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000216 '''
adminbae64d82013-08-01 10:50:15 -0700217 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700218 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700219 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800220 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700221 self.TOTAL_TC_NORESULT = 0
222 self.TOTAL_TC_FAIL = 0
223 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700224 self.TEST_ITERATION = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700225
226 # NOTE: number of main.step statements in the
227 # outer most level of the test case. used to
228 # execute code in smaller steps
229 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700230 self.CASERESULT = self.NORESULT
231
Jon Halld61331b2015-02-17 16:35:47 -0800232 import testparser
Jon Hall53c5e662016-04-13 16:06:56 -0700233 test = testparser.TestParser( main.testFile )
adminbae64d82013-08-01 10:50:15 -0700234 self.testscript = test.testscript
235 self.code = test.getStepCode()
Jon Hall714eeba2015-09-29 17:53:10 -0700236 repeat = int( self.params.get( 'repeat', 1 ) )
237 self.TOTAL_TC_PLANNED = len( self.testcases_list ) * repeat
Jon Hall026bd712021-08-31 16:30:09 -0700238 self.log.TAP( "1..%s" % self.TOTAL_TC_PLANNED )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700239
adminbae64d82013-08-01 10:50:15 -0700240 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700241 while repeat:
Devin Limec989792017-08-15 15:57:55 -0700242 self.leftCase.extend( self.testcases_list )
Jon Halla1185982014-09-15 14:55:10 -0700243 for self.CurrentTestCaseNumber in self.testcases_list:
Devin Limec989792017-08-15 15:57:55 -0700244 self.executedCase.append( self.leftCase.pop( 0 ) )
Jon Hall714eeba2015-09-29 17:53:10 -0700245 result = self.runCase( self.CurrentTestCaseNumber )
246 repeat -= 1
adminbae64d82013-08-01 10:50:15 -0700247 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700248
Jon Halle234cc42015-08-31 15:26:47 -0700249 def runCase( self, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700250 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700251 self.CurrentTestCase = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700252
253 # List of step results in a case. ANDed together to get the result
254 self.stepResultsList = []
kelvin-onlabf70fd542015-05-07 18:41:40 -0700255 self.stepName = ""
Jon Hall783bbf92015-07-23 14:33:19 -0700256 self.caseExplanation = ""
adminbae64d82013-08-01 10:50:15 -0700257 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700258
259 # NOTE: number of main.step statements in the
260 # outer most level of the test case. used to
261 # execute code in smaller steps
262 self.stepCount = 0
263
264 # NOTE: This is the current number of main.step()'s executed
265 # in a case. Used for logging.
266 self.stepNumber = 0
adminbae64d82013-08-01 10:50:15 -0700267 self.EXPERIMENTAL_MODE = self.FALSE
268 self.addCaseHeader()
Devin Limec989792017-08-15 15:57:55 -0700269 self.log.debug( "Case Executed : " + str( self.executedCase ) )
270 self.log.debug( "Case to be executed : " + str( self.leftCase ) )
Jon Halle234cc42015-08-31 15:26:47 -0700271 self.testCaseNumber = str( testCaseNumber )
272 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700273 stopped = False
Jon Hall5a72b712015-09-28 12:20:59 -0700274 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700275 self.code[ self.testCaseNumber ]
Jon Halld61331b2015-02-17 16:35:47 -0800276 except KeyError:
Jon Halle234cc42015-08-31 15:26:47 -0700277 self.log.error( "There is no Test-Case " + self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800278 return self.FALSE
adminbae64d82013-08-01 10:50:15 -0700279 self.stepCount = 0
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700280 while self.stepCount < len( self.code[ self.testCaseNumber ].keys() ):
Jon Hall714eeba2015-09-29 17:53:10 -0700281 result = self.runStep( self.code, self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800282 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700283 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800284 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700285 continue
Jon Hall5a72b712015-09-28 12:20:59 -0700286 # stepResults format: ( stepNo[], stepName[], stepResult[], onFail[] )
287 stepResults = self.stepResultsList
Jon Halle234cc42015-08-31 15:26:47 -0700288 if not stopped:
289 if self.CASERESULT == self.TRUE or self.CASERESULT == self.FALSE:
Jon Hall714eeba2015-09-29 17:53:10 -0700290 # Result was already explitily set somewhere else like
291 # in skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700292 pass
Jon Hall5a72b712015-09-28 12:20:59 -0700293 elif all( self.TRUE == i for i in stepResults ):
kelvin-onlabf70fd542015-05-07 18:41:40 -0700294 # ALL PASSED
295 self.CASERESULT = self.TRUE
Jon Hall5a72b712015-09-28 12:20:59 -0700296 elif self.FALSE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700297 # AT LEAST ONE FAILED
298 self.CASERESULT = self.FALSE
Jon Hall5a72b712015-09-28 12:20:59 -0700299 elif self.TRUE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700300 # AT LEAST ONE PASSED
301 self.CASERESULT = self.TRUE
302 else:
303 self.CASERESULT = self.NORESULT
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700304 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = self.CASERESULT
Devin Limec989792017-08-15 15:57:55 -0700305 self.organizeResult( self.CurrentTestCaseNumber, self.CASERESULT )
Jon Hall714eeba2015-09-29 17:53:10 -0700306 self.logger.updateCaseResults( self )
Jon Hall783bbf92015-07-23 14:33:19 -0700307 self.log.summary( self.caseExplanation )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700308 self.log.summary( self.stepCache )
Jon Hall026bd712021-08-31 16:30:09 -0700309 self.caseResultsWiki()
310 self.caseResultsTAP()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700311 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700312 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700313
Jon Hall026bd712021-08-31 16:30:09 -0700314 def caseResultsWiki( self ):
315 """
316 Add case results to the wiki results file
317 """
318 self.log.wiki( "<p>" + self.caseExplanation + "</p>" )
319 self.log.wiki( "<ul>" )
320 subcaseMessage = False
321 for line in self.stepCache.splitlines():
322 if re.search( "[0-9]\.[0-9]", line ): # Step
323 if subcaseMessage: # End of Failure Message Printout
324 self.log.wiki( "</ul>\n" )
325 subcaseMessage = False
326 if re.search( " - PASS$", line ):
327 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
328 elif re.search( " - FAIL$", line ):
329 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
330 elif re.search( " - No Result$", line ):
331 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
332 else: # Substep
333 if not subcaseMessage: # Open Failure Message Printout
334 self.log.wiki( "<ul><li>" + line + "</li>\n" )
335 subcaseMessage = True
336 else: # Add to Failure Message Printout
337 self.log.wiki( "<li>" + line + "</li>\n" )
338 if subcaseMessage: # End of Failure Message Printout for last item
339 self.log.wiki( "</ul>\n" )
340 self.log.wiki( "</ul>" )
341
342 def caseResultsTAP( self ):
343 """
344 Add case results to the TAP results file
345 """
346 #self.log.TAP( "<p>" + self.caseExplanation + "</p>" )
347 main.log.debug( self.stepCache )
348 subcaseMessage = False
349 steps = 0
350 stepLines = []
351 for line in self.stepCache.splitlines():
352 main.log.debug( line )
353 if re.search( "[0-9]\.[0-9]", line ): # Step
354 if subcaseMessage: # End of Failure Message Printout
355 subcaseMessage = False
356 if re.search( " - PASS$", line ):
357 steps += 1
358 stepLines.append( " ok -- STEP %s" % line )
359 elif re.search( " - FAIL$", line ):
360 steps += 1
361 stepLines.append( " not ok -- STEP %s" % line )
362 elif re.search( " - No Result$", line ):
363 steps += 1
364 stepLines.append( " ok -- STEP %s # TODO: No assertion in test step" % line )
365 else: # Substep
366 if not subcaseMessage: # Open Failure Message Printout
367 stepLines.append( " # %s" % line )
368 subcaseMessage = True
369 else: # Add to Failure Message Printout
370 self.log.TAP( " # %s" % line )
371 if steps > 0:
372 self.log.TAP( " 1..%s" % steps )
373 for line in stepLines:
374 self.log.TAP( line )
375
376
Devin Limec989792017-08-15 15:57:55 -0700377 def organizeResult( self, caseNum, result ):
378 """
379 Organize the result and put the current number into either
380 failed/noResult lists.
381 * caseNum - number of the case
382 * result - result of the case
383 """
384 if result == main.FALSE:
385 self.failedCase.append( caseNum )
386 elif result == self.NORESULT:
387 self.noResultCase.append( caseNum )
388
Jon Hall714eeba2015-09-29 17:53:10 -0700389 def runStep( self, code, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700390 if not cli.pause:
Jon Hall5a72b712015-09-28 12:20:59 -0700391 try:
392 step = self.stepCount
393 # stepResults format: ( stepNo, stepName, stepResult, onFail )
394 # NOTE: This is needed to catch results of main.step()'s
395 # called inside functions or loops
396 self.stepResults = ( [], [], [], [] )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700397 exec code[ testCaseNumber ][ step ] in module.__dict__
adminbae64d82013-08-01 10:50:15 -0700398 self.stepCount = self.stepCount + 1
Jon Hall96b816f2015-11-03 12:00:56 -0800399 self.parseStepResults( testCaseNumber )
Jon Hallca319892017-06-15 15:25:22 -0700400 except SkipCase: # Raised in self.skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700401 self.log.warn( "Skipping the rest of CASE" +
402 str( testCaseNumber ) )
Jon Hall96b816f2015-11-03 12:00:56 -0800403 self.parseStepResults( testCaseNumber )
Jon Hall714eeba2015-09-29 17:53:10 -0700404 self.stepResultsList.append( self.STEPRESULT )
Jon Halle234cc42015-08-31 15:26:47 -0700405 self.stepCache += "\t\t" + self.onFailMsg + "\n"
406 self.stepCount = self.stepCount + 1
407 return self.FALSE
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000408 except StandardError as e:
Jon Hallc1606352015-10-06 14:51:36 -0700409 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700410 stepNo = self.stepResults[ 0 ][ self.stepNumber - 1 ]
Jon Hallc1606352015-10-06 14:51:36 -0700411 except IndexError:
412 stepNo = "<IndexError>"
413 main.log.warn( "Error trying to get step number. " +
414 "It is likely between step " +
Jon Hall6e709752016-02-01 13:38:46 -0800415 str( self.stepNumber ) + " and step " +
Jon Hallc1606352015-10-06 14:51:36 -0700416 str( self.stepNumber + 1 ) )
417 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700418 stepName = self.stepResults[ 1 ][ self.stepNumber - 1 ]
Jon Hallc1606352015-10-06 14:51:36 -0700419 except IndexError:
420 stepName = "<IndexError>"
421 self.log.error( "\nException in the following section of" +
422 " code: " + str( testCaseNumber ) + "." +
423 str( stepNo ) + ": " + stepName )
Jeremyd9e4eb12016-04-13 12:09:06 -0700424 self.log.error( str( e.__class__ ) + str( e.message ) )
Jon Halld14a5002021-03-30 16:45:30 -0700425 self.log.exception( "" )
adminbae64d82013-08-01 10:50:15 -0700426 self.stepCount = self.stepCount + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700427 self.logger.updateCaseResults( self )
Jon Hall026bd712021-08-31 16:30:09 -0700428 self.stepResultsWiki()
429 self.stepResultsTAP()
Jon Hall714eeba2015-09-29 17:53:10 -0700430 # summary results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700431 self.log.summary( self.stepCache )
432 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700433 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700434 self.exit()
Jon Halle234cc42015-08-31 15:26:47 -0700435 return self.TRUE
adminbae64d82013-08-01 10:50:15 -0700436 if cli.stop:
437 cli.stop = False
adminbae64d82013-08-01 10:50:15 -0700438 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700439 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = "Stopped"
Jon Hall714eeba2015-09-29 17:53:10 -0700440 self.logger.updateCaseResults( self )
adminbae64d82013-08-01 10:50:15 -0700441 result = self.cleanup()
Jon Halle234cc42015-08-31 15:26:47 -0700442 return self.FALSE
443
Jon Hall026bd712021-08-31 16:30:09 -0700444 def stepResultsWiki( self ):
445 """
446 Add step results to the wiki file
447 """
448 # WIKI results
449 self.log.wiki( "<ul>" )
450 for line in self.stepCache.splitlines():
451 if re.search( " - PASS$", line ):
452 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
453 elif re.search( " - FAIL$", line ):
454 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
455 elif re.search( " - No Result$", line ):
456 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
457 else: # Should only be on fail message
458 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
459 self.log.wiki( "</ul>" )
460
461 def stepResultsTAP( self ):
462 """
463 Add step results to the TAP file
464 """
465 # TAP results
466 # TODO Do we need indetation for the steps?
467 main.log.debug( "StepResultsTAP" )
468 for line in self.stepCache.splitlines():
469 if re.search( " - PASS$", line ):
470 self.log.TAP( " ok -- STEP %s" % line )
471 elif re.search( " - FAIL$", line ):
472 self.log.TAP( " not ok -- STEP %s" % line )
473 elif re.search( " - No Result$", line ):
474 self.log.TAP( " ok -- STEP %s # TODO: No assertion in test step" % line )
475 else: # Should only be on fail message
476 self.log.TAP( " # %s" % line )
477
Jon Hall96b816f2015-11-03 12:00:56 -0800478 def parseStepResults( self, testCaseNumber ):
479 """
480 Parse throught the step results for the wiki
481 """
482 try:
483 # Iterate through each of the steps and print them
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700484 for index in range( len( self.stepResults[ 0 ] ) ):
Jon Hall96b816f2015-11-03 12:00:56 -0800485 # stepResults = ( stepNo, stepName, stepResult, onFail )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700486 stepNo = self.stepResults[ 0 ][ index ]
487 stepName = self.stepResults[ 1 ][ index ]
488 stepResult = self.stepResults[ 2 ][ index ]
489 onFail = self.stepResults[ 3 ][ index ]
Jon Hall96b816f2015-11-03 12:00:56 -0800490 self.stepCache += "\t" + str( testCaseNumber ) + "."
491 self.stepCache += str( stepNo ) + " "
492 self.stepCache += stepName + " - "
493 if stepResult == self.TRUE:
494 self.stepCache += "PASS\n"
495 elif stepResult == self.FALSE:
496 self.stepCache += "FAIL\n"
497 self.stepCache += "\t\t" + onFail + "\n"
498 else:
499 self.stepCache += "No Result\n"
500 self.stepResultsList.append( stepResult )
501 except Exception:
502 self.log.exception( "Error parsing step results" )
503
Jon Halle234cc42015-08-31 15:26:47 -0700504 def skipCase( self, result="DEFAULT", msg=None ):
505 """
506 Will skip the rest of the code in a test case. The case results will be
507 determined as normal based on completed assertions unless the result
508 argument is given.
509
510 Optional Arguments:
Jon Hall7c4f4302016-07-15 14:39:02 -0700511 result: Case insensitive string. Can be 'PASS' or 'FAIL' and will set
Jon Halle234cc42015-08-31 15:26:47 -0700512 the case result accordingly.
513 msg: Message to be printed when the case is skipped in the reports.
514 """
515 result = result.upper().strip()
516 if result == "PASS":
517 self.CASERESULT = self.TRUE
518 elif result == "FAIL":
519 self.CASERESULT = self.FALSE
520 self.onFailMsg = "Skipping the rest of this case. "
521 if msg:
522 self.onFailMsg += str( msg )
Jon Hallca319892017-06-15 15:25:22 -0700523 raise SkipCase
kelvin-onlabf70fd542015-05-07 18:41:40 -0700524
Jon Hall714eeba2015-09-29 17:53:10 -0700525 def addCaseHeader( self ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700526 caseHeader = "\n" + "*" * 30 + "\n Result summary for Testcase" + \
Jon Hall714eeba2015-09-29 17:53:10 -0700527 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 30 + "\n"
528 self.log.exact( caseHeader )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700529 caseHeader = "\n" + "*" * 40 + "\nStart of Test Case" + \
Jon Hall714eeba2015-09-29 17:53:10 -0700530 str( self.CurrentTestCaseNumber ) + " : "
adminbae64d82013-08-01 10:50:15 -0700531 for driver in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700532 vars( self )[ driver + 'log' ].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700533
Jon Hall714eeba2015-09-29 17:53:10 -0700534 def addCaseFooter( self ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700535 stepNo = self.stepResults[ 0 ][ -2 ]
Jon Hall714eeba2015-09-29 17:53:10 -0700536 if stepNo > 0:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700537 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." + \
Jon Hall714eeba2015-09-29 17:53:10 -0700538 str( stepNo ) + ": " + str( self.stepName )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700539 stepHeader = "\n" + "*" * 40 + "\nEnd of Step " + previousStep + \
Jon Hall714eeba2015-09-29 17:53:10 -0700540 "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700541
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700542 caseFooter = "\n" + "*" * 40 + "\nEnd of Test case " + \
Jon Hall714eeba2015-09-29 17:53:10 -0700543 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700544
adminbae64d82013-08-01 10:50:15 -0700545 for driver in self.driversList:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700546 vars( self )[ driver ].write( stepHeader + "\n" + caseFooter )
adminbae64d82013-08-01 10:50:15 -0700547
Devin Limba37cdd2018-05-07 11:41:05 -0700548 def setCheckingPoint( self ):
549 '''
550 Using when running findPatchScript.sh. This function needs to be placed
551 on the point that has the problem.
552
553 For example, if you see unusual behavior or from the portion of the code,
554 this is where you need to put with the conditional statement.
555 If some of the latency result is much greater than usual, have if statement
556 that checks if the result is greater than some point and include this function.
557
558 This will mark the 0 to findPatchResult.txt in /tmp/ and exit the test.
559 Then from findPatchScript, it will move onto the next commit and re-run the
560 test.
561 '''
562 self.log.error( "Reached to the checking point. Will mark the result and exit the test" )
563 resultFile = open( "/tmp/findPatchResult.txt", "w" )
564 resultFile.write( "0" )
565 resultFile.close()
566 self.cleanAndExit()
567
Jon Hall714eeba2015-09-29 17:53:10 -0700568 def cleanup( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000569 '''
Jon Hall5b586732015-06-11 11:39:39 -0700570 Print a summary of the current test's results then attempt to release
571 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700572
Jon Hall5b586732015-06-11 11:39:39 -0700573 This function shouldbe threadsafe such that cleanup will only be
574 executed once per test.
575
576 This will return TRUE if all the component handles and log handles
577 closed properly, else return FALSE.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000578 '''
adminbae64d82013-08-01 10:50:15 -0700579 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700580 lock = self.cleanupLock
581 if lock.acquire( False ):
582 try:
583 if self.cleanupFlag is False: # First thread to run this
584 self.cleanupFlag = True
Jon Hall0fc0d452015-07-14 09:49:58 -0700585 if self.initiated:
Jon Hall714eeba2015-09-29 17:53:10 -0700586 self.logger.testSummary( self )
Jon Hall892818c2015-10-20 17:58:34 -0700587 components = self.componentDictionary
588 for component in sorted( components,
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700589 key=lambda item: components[ item ][ 'connect_order' ],
Jon Hall892818c2015-10-20 17:58:34 -0700590 reverse=True ):
Jon Hall714eeba2015-09-29 17:53:10 -0700591 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700592 tempObject = vars( self )[ component ]
593 print "Disconnecting from " + str( tempObject.name ) + \
594 ": " + str( tempObject.__class__ )
Jon Hall5b586732015-06-11 11:39:39 -0700595 tempObject.disconnect()
Jon Hall1306a562015-09-04 11:21:24 -0700596 except KeyboardInterrupt:
597 pass
598 except KeyError:
599 # Component not created yet
600 self.log.warn( "Could not find the component " +
601 str( component ) )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000602 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700603 self.log.exception( "Exception while disconnecting from " +
604 str( component ) )
605 result = self.FALSE
606 # Closing all the driver's session files
607 for driver in self.componentDictionary.keys():
608 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700609 vars( self )[ driver ].close_log_handles()
Jon Hall1306a562015-09-04 11:21:24 -0700610 except KeyboardInterrupt:
611 pass
612 except KeyError:
613 # Component not created yet
614 self.log.warn( "Could not find the component " +
615 str( driver ) + " while trying to" +
616 " close log file" )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000617 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700618 self.log.exception( "Exception while closing log files for " +
619 str( driver ) )
620 result = self.FALSE
621 else:
622 pass # Someone else already ran through this function
623 finally:
624 lock.release()
625 else: # Someone already has a lock
626 # NOTE: This could cause problems if we don't release the lock
627 # correctly
628 lock.acquire() # Wait for the other thread to finish
629 # NOTE: If we don't wait, exit could be called while the thread
630 # with the lock is still cleaning up
631 lock.release()
adminbae64d82013-08-01 10:50:15 -0700632 return result
Jon Halld61331b2015-02-17 16:35:47 -0800633
Jon Hall714eeba2015-09-29 17:53:10 -0700634 def pause( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000635 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700636 This function will pause the test's execution, and will continue after
637 user provide 'resume' command.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000638 '''
adminbae64d82013-08-01 10:50:15 -0700639 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700640
Jon Hall714eeba2015-09-29 17:53:10 -0700641 def onfail( self, *components ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000642 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700643 When test step failed, calling all the components onfail.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000644 '''
adminbae64d82013-08-01 10:50:15 -0700645 if not components:
Jon Hall714eeba2015-09-29 17:53:10 -0700646 try:
adminbae64d82013-08-01 10:50:15 -0700647 for component in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700648 tempObject = vars( self )[ component ]
adminbae64d82013-08-01 10:50:15 -0700649 result = tempObject.onfail()
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000650 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700651 print str( e )
adminbae64d82013-08-01 10:50:15 -0700652 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700653 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700654 try:
adminbae64d82013-08-01 10:50:15 -0700655 for component in components:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700656 tempObject = vars( self )[ component ]
adminbae64d82013-08-01 10:50:15 -0700657 result = tempObject.onfail()
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000658 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700659 print str( e )
adminbae64d82013-08-01 10:50:15 -0700660 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700661
Jon Hall714eeba2015-09-29 17:53:10 -0700662 def getDriverPath( self, driverName ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000663 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700664 Based on the component 'type' specified in the params , this method
665 will find the absolute path, by recursively searching the name of
666 the component.
667
668 NOTE: This function requires the linux 'find' command.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000669 '''
adminbae64d82013-08-01 10:50:15 -0700670 import commands
671
Jon Hall714eeba2015-09-29 17:53:10 -0700672 cmd = "find " + drivers_path + " -name " + driverName + ".py"
673 result = commands.getoutput( cmd )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700674
Jon Hall714eeba2015-09-29 17:53:10 -0700675 result_array = str( result ).split( '\n' )
adminbae64d82013-08-01 10:50:15 -0700676 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700677
adminbae64d82013-08-01 10:50:15 -0700678 for drivers_list in result_array:
Jon Hall714eeba2015-09-29 17:53:10 -0700679 result_count = result_count + 1
680 if result_count > 1:
681 print "Found " + driverName + " " + str( result_count ) + " times:"
682 print str( result_array )
adminbae64d82013-08-01 10:50:15 -0700683 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700684
Jon Hall714eeba2015-09-29 17:53:10 -0700685 result = re.sub( "(.*)drivers", "", result )
686 result = re.sub( "\/\/", "/", result )
687 result = re.sub( "\.py", "", result )
688 result = re.sub( "\.pyc", "", result )
689 result = re.sub( "\/", ".", result )
690 result = "drivers" + result
adminbae64d82013-08-01 10:50:15 -0700691 return result
adminbae64d82013-08-01 10:50:15 -0700692
Jon Hall714eeba2015-09-29 17:53:10 -0700693 def step( self, stepDesc ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000694 '''
adminbae64d82013-08-01 10:50:15 -0700695 The step information of the test-case will append to the logs.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000696 '''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700697 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." + \
Jon Hall714eeba2015-09-29 17:53:10 -0700698 str( self.stepNumber ) + ": " + str( self.stepName )
adminbae64d82013-08-01 10:50:15 -0700699 self.stepName = stepDesc
Jon Hall5a72b712015-09-28 12:20:59 -0700700 self.stepNumber += 1
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700701 self.stepResults[ 0 ].append( self.stepNumber )
702 self.stepResults[ 1 ].append( stepDesc )
703 self.stepResults[ 2 ].append( self.NORESULT )
704 self.stepResults[ 3 ].append( "No on fail message given" )
adminbae64d82013-08-01 10:50:15 -0700705
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700706 stepName = " " + str( self.CurrentTestCaseNumber ) + "." + \
Jon Hall714eeba2015-09-29 17:53:10 -0700707 str( self.stepNumber ) + ": " + str( stepDesc )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700708 self.log.step( stepName )
adminbae64d82013-08-01 10:50:15 -0700709 stepHeader = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700710 line = "\n" + "-" * 45 + "\n"
711 if self.stepNumber > 1:
712 stepHeader = line + "End of Step " + previousStep + line
713 stepHeader += line + "Start of Step" + stepName + line
adminbae64d82013-08-01 10:50:15 -0700714 for driver in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700715 vars( self )[ driver + 'log' ].info( stepHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700716
Jon Hall714eeba2015-09-29 17:53:10 -0700717 def case( self, testCaseName ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000718 '''
adminbae64d82013-08-01 10:50:15 -0700719 Test's each test-case information will append to the logs.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000720 '''
Jon Halld61331b2015-02-17 16:35:47 -0800721 self.CurrentTestCase = testCaseName
Jon Hall714eeba2015-09-29 17:53:10 -0700722 testCaseName = " " + str( testCaseName )
723 self.log.case( testCaseName )
724 caseHeader = testCaseName + "\n" + "*" * 40 + "\n"
adminbae64d82013-08-01 10:50:15 -0700725 for driver in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700726 vars( self )[ driver + 'log' ].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700727
Jon Hall714eeba2015-09-29 17:53:10 -0700728 def testDesc( self, description ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000729 '''
adminbae64d82013-08-01 10:50:15 -0700730 Test description will append to the logs.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000731 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700732 description = "Test Description : " + str( description )
733 self.log.info( description )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700734
Jon Hall714eeba2015-09-29 17:53:10 -0700735 def _getTest( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000736 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700737 This method will parse the test script to find required test
738 information.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000739 '''
Jon Hall53c5e662016-04-13 16:06:56 -0700740 testFileHandler = open( main.testFile, 'r' )
adminbae64d82013-08-01 10:50:15 -0700741 testFileList = testFileHandler.readlines()
742 testFileHandler.close()
adminbae64d82013-08-01 10:50:15 -0700743 counter = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700744 for index in range( len( testFileList ) ):
745 lineMatch = re.match( '\s+def CASE(\d+)(.*):',
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700746 testFileList[ index ],
Jon Hall714eeba2015-09-29 17:53:10 -0700747 0 )
adminbae64d82013-08-01 10:50:15 -0700748 if lineMatch:
Jon Hall714eeba2015-09-29 17:53:10 -0700749 counter = counter + 1
750 self.TC_PLANNED = len( self.testcases_list )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700751
Jon Hall714eeba2015-09-29 17:53:10 -0700752 def response_parser( self, response, return_format ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000753 ''' It will load the default response parser '''
adminbae64d82013-08-01 10:50:15 -0700754 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700755 response_dict = self.response_to_dict( response, return_format )
756 return_format_string = self.dict_to_return_format( response,
757 return_format,
758 response_dict )
adminbae64d82013-08-01 10:50:15 -0700759 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700760
Jon Hall714eeba2015-09-29 17:53:10 -0700761 def response_to_dict( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700762 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700763 json_match = re.search( '^\s*{', response )
764 xml_match = re.search( '^\s*\<', response )
765 ini_match = re.search( '^\s*\[', response )
766 if json_match:
767 self.log.info( "Response is in 'JSON' format, converting to '" +
768 return_format + "' format" )
Jon Halld61331b2015-02-17 16:35:47 -0800769 # Formatting the json string
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000770 response = re.sub( r"{\s*'?(\w)", r'{"\1', response )
Jon Hall714eeba2015-09-29 17:53:10 -0700771 response = re.sub( r",\s*'?(\w)", r',"\1', response )
772 response = re.sub( r"(\w)'?\s*:", r'\1":', response )
773 response = re.sub( r":\s*'(\w)'\s*([,}])", r':"\1"\2', response )
774 try:
adminbae64d82013-08-01 10:50:15 -0700775 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700776 response_dict = json.loads( response )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000777 except StandardError:
Jon Hall2a5002c2015-08-21 16:49:11 -0700778 self.log.exception( "Json Parser is unable to parse the string" )
adminbae64d82013-08-01 10:50:15 -0700779 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700780 elif ini_match:
781 self.log.info( "Response is in 'INI' format, converting to '" +
782 return_format + "' format" )
adminbae64d82013-08-01 10:50:15 -0700783 from configobj import ConfigObj
Jon Hall714eeba2015-09-29 17:53:10 -0700784 response_file = open( "respnse_file.temp", 'w' )
785 response_file.write( response )
Jon Halld61331b2015-02-17 16:35:47 -0800786 response_file.close()
Jon Hall714eeba2015-09-29 17:53:10 -0700787 response_dict = ConfigObj( "respnse_file.temp" )
adminbae64d82013-08-01 10:50:15 -0700788 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700789 elif xml_match:
790 self.log.info( "Response is in 'XML' format, converting to '" +
791 return_format + "' format" )
792 try:
793 response_dict = xmldict.xml_to_dict( "<response> " +
794 str( response ) +
795 " </response>" )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000796 except StandardError:
Jon Hall1306a562015-09-04 11:21:24 -0700797 self.log.exception()
adminbae64d82013-08-01 10:50:15 -0700798 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700799
Jon Hall714eeba2015-09-29 17:53:10 -0700800 def dict_to_return_format( self, response, return_format, response_dict ):
801 if return_format == 'table':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000802 ''' Will return in table format'''
adminbae64d82013-08-01 10:50:15 -0700803 to_do = "Call the table output formatter"
804 global response_table
805 response_table = '\n'
Jon Hall714eeba2015-09-29 17:53:10 -0700806 response_table = response_table + '\t'.join( response_dict ) + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700807
Jon Hall714eeba2015-09-29 17:53:10 -0700808 def get_table( value_to_convert ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000809 ''' This will parse the dictionary recusrsively and print as
810 table format'''
adminbae64d82013-08-01 10:50:15 -0700811 table_data = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700812 if isinstance( value_to_convert, dict ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700813 table_data = table_data + '\t'.join( value_to_convert ) + \
Jon Hall714eeba2015-09-29 17:53:10 -0700814 "\n"
815 for temp_val in value_to_convert.values():
816 table_data = table_data + get_table( temp_val )
817 else:
818 table_data = table_data + str( value_to_convert ) + "\t"
Jon Halld61331b2015-02-17 16:35:47 -0800819 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700820
Jon Hall714eeba2015-09-29 17:53:10 -0700821 for value in response_dict.values():
822 response_table = response_table + get_table( value )
adminbae64d82013-08-01 10:50:15 -0700823 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700824
Jon Hall714eeba2015-09-29 17:53:10 -0700825 elif return_format == 'config':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000826 ''' Will return in config format'''
adminbae64d82013-08-01 10:50:15 -0700827 to_do = 'Call dict to config coverter'
Jon Hall714eeba2015-09-29 17:53:10 -0700828 response_string = str( response_dict )
adminbae64d82013-08-01 10:50:15 -0700829 print response_string
Jon Hall714eeba2015-09-29 17:53:10 -0700830 response_config = re.sub( ",", "\n\t", response_string )
831 response_config = re.sub( "u\'", "\'", response_config )
832 response_config = re.sub( "{", "", response_config )
833 response_config = re.sub( "}", "\n", response_config )
834 response_config = re.sub( ":", " =", response_config )
835 return "[response]\n\t " + response_config
adminbae64d82013-08-01 10:50:15 -0700836 elif return_format == 'xml':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000837 ''' Will return in xml format'''
Jon Hall714eeba2015-09-29 17:53:10 -0700838 response_xml = xmldict.dict_to_xml( response_dict )
839 response_xml = re.sub( ">\s*<", ">\n<", response_xml )
840 return "\n" + response_xml
adminbae64d82013-08-01 10:50:15 -0700841 elif return_format == 'json':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000842 ''' Will return in json format'''
adminbae64d82013-08-01 10:50:15 -0700843 to_do = 'Call dict to xml coverter'
844 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700845 response_json = json.dumps( response_dict )
adminbae64d82013-08-01 10:50:15 -0700846 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700847
Jon Hall714eeba2015-09-29 17:53:10 -0700848 def get_random( self ):
adminbae64d82013-08-01 10:50:15 -0700849 self.random_order = self.random_order + 1
850 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700851
Jon Hall714eeba2015-09-29 17:53:10 -0700852 def exit( self ):
adminbae64d82013-08-01 10:50:15 -0700853 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700854 for thread in threading.enumerate():
855 if thread.isAlive():
856 try:
857 thread._Thread__stop()
858 except:
Jon Hall1306a562015-09-04 11:21:24 -0700859 # NOTE: We should catch any exceptions while trying to
860 # close the thread so that we can try to close the other
861 # threads as well
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700862 print str( thread.getName() ) + \
Jon Hall714eeba2015-09-29 17:53:10 -0700863 ' could not be terminated'
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700864 os.system( "stty sane" ) # fix format if necessary
adminbae64d82013-08-01 10:50:15 -0700865 sys.exit()
866
You Wang7880b372019-02-27 16:50:47 -0800867 def cleanAndExit( self, alarm=True, msg="" ):
Devin Lim44075962017-08-11 10:56:37 -0700868 """
869 It will set the testcase result to be FAILED and update it
870 before cleaning up and exitting the test.
You Wang7880b372019-02-27 16:50:47 -0800871 alarm: when set to True, it will write to the alarm log before
872 cleaning up and exitting; otherwise it will write to error log.
873 msg: message that will be written to the log if specified;
874 otherwise a default message will be written.
Devin Lim44075962017-08-11 10:56:37 -0700875 :return:
876 """
877 if self.CurrentTestCaseNumber:
878 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = self.FALSE
Devin Limec989792017-08-15 15:57:55 -0700879 self.organizeResult( self.CurrentTestCaseNumber, self.FALSE )
Devin Lim44075962017-08-11 10:56:37 -0700880 self.logger.updateCaseResults( self )
You Wang7880b372019-02-27 16:50:47 -0800881 if alarm:
882 if msg:
883 self.log.alarm( "Test exited unexpectedly: {}".format( msg ) )
884 else:
885 self.log.alarm( "Test exited unexpectedly" )
886 else:
887 if msg:
888 self.log.error( "Test exited unexpectedly: {}".format( msg ) )
889 else:
890 self.log.error( "Test exited unexpectedly" )
Devin Lim44075962017-08-11 10:56:37 -0700891 self.cleanup()
892 self.exit()
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700893
Jon Hallcd3d2a32015-10-01 11:07:28 -0700894 def stop( self, email=False ):
895 """
896 Stop the test until Ctrl-D is entered.
897 Ctrl-C will kill the test
Jon Hall25079782015-10-13 13:54:39 -0700898
899 Optional arguments:
900 email can either be a bool, or you can specify the email address
901 to send the email to
Jon Hallcd3d2a32015-10-01 11:07:28 -0700902 """
903 try:
904 if email:
Jon Hall25079782015-10-13 13:54:39 -0700905 if '@' in email:
906 main.mail = email
907 utilities.send_warning_email()
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700908 self.log.debug( "Test execution suspended. \n"
909 "- Type 'c' to resume the test.\n"
910 "- Type Ctrl-C to exit the test.\n"
911 "- Enter interactive python interpreter commands.\n"
912 "\t- ie: main.Mininet1.pingall()\n"
913 "- Type 'help' for help with pdb." )
914 pdb.set_trace()
Jon Hallcd3d2a32015-10-01 11:07:28 -0700915 except EOFError:
916 return
917 # Pass all other exceptions up to caller
918
919
Jon Hall714eeba2015-09-29 17:53:10 -0700920def verifyOptions( options ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000921 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700922 This will verify the command line options and set to default values,
923 if any option not given in command line.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000924 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700925 verifyTest( options )
926 verifyExample( options )
927 verifyTestScript( options )
YPZhang1c89e762016-06-29 10:43:58 -0700928 verifyParams( options )
Jon Hall714eeba2015-09-29 17:53:10 -0700929 verifyLogdir( options )
930 verifyMail( options )
931 verifyTestCases( options )
932 verifyOnosCell( options )
adminbae64d82013-08-01 10:50:15 -0700933
Jon Hall714eeba2015-09-29 17:53:10 -0700934def verifyTest( options ):
Jon Hall44506242015-07-29 17:40:26 -0700935 try:
936 if options.testname:
937 main.TEST = options.testname
Jon Hall714eeba2015-09-29 17:53:10 -0700938 main.classPath = "tests." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700939 main.tests_path = tests_path
940 elif options.example:
941 main.TEST = options.example
Jon Hall714eeba2015-09-29 17:53:10 -0700942 main.tests_path = path + "/examples/"
943 main.classPath = "examples." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700944 except AttributeError:
adminbae64d82013-08-01 10:50:15 -0700945 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700946 main.exit()
adminbae64d82013-08-01 10:50:15 -0700947
Jon Hall714eeba2015-09-29 17:53:10 -0700948def verifyExample( options ):
adminbae64d82013-08-01 10:50:15 -0700949 if options.example:
Jon Hall714eeba2015-09-29 17:53:10 -0700950 main.testDir = path + '/examples/'
951 main.tests_path = path + "/examples/"
952 main.classPath = "examples." + main.TEST + "." + main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700953
Jon Hall714eeba2015-09-29 17:53:10 -0700954def verifyLogdir( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800955 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700956 if options.logdir:
957 main.logdir = options.logdir
Jon Hall714eeba2015-09-29 17:53:10 -0700958 else:
Jon Halld61331b2015-02-17 16:35:47 -0800959 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700960
Jon Hall714eeba2015-09-29 17:53:10 -0700961def verifyMail( options ):
Jon Hall25079782015-10-13 13:54:39 -0700962 # Mail-To: field
963 if options.mail: # Test run specific
adminbae64d82013-08-01 10:50:15 -0700964 main.mail = options.mail
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700965 elif main.params.get( 'mail' ): # Test suite specific
Jon Hall25079782015-10-13 13:54:39 -0700966 main.mail = main.params.get( 'mail' )
967 else: # TestON specific
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700968 main.mail = main.config[ 'config' ].get( 'mail_to' )
Jon Hall25079782015-10-13 13:54:39 -0700969 # Mail-From: field
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700970 main.sender = main.config[ 'config' ].get( 'mail_from' )
Jon Hall25079782015-10-13 13:54:39 -0700971 # Mail smtp server
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700972 main.smtp = main.config[ 'config' ].get( 'mail_server' )
Jon Hall25079782015-10-13 13:54:39 -0700973 # Mail-From account password
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700974 main.senderPwd = main.config[ 'config' ].get( 'mail_pass' )
Jon Hall25079782015-10-13 13:54:39 -0700975
Devin Lim2df68a12017-06-30 15:39:05 -0700976def evalTestCase( tempList ):
977 tList = []
978 for tcase in tempList:
979 if isinstance( tcase, list ):
980 tList.extend( evalTestCase( tcase ) )
981 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700982 tList.extend( [ tcase ] )
Devin Lim2df68a12017-06-30 15:39:05 -0700983 return tList
adminbae64d82013-08-01 10:50:15 -0700984
Jon Hall714eeba2015-09-29 17:53:10 -0700985def verifyTestCases( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800986 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700987 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800988 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800989 # sys.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700990 testcases_list = re.sub( "(\[|\])", "", options.testcases )
991 main.testcases_list = eval( testcases_list + "," )
992 else:
adminbae64d82013-08-01 10:50:15 -0700993 if 'testcases' in main.params.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700994 temp = eval( main.params[ 'testcases' ] + "," )
Devin Lim2df68a12017-06-30 15:39:05 -0700995 main.testcases_list = evalTestCase( list( temp ) )
Jon Hall714eeba2015-09-29 17:53:10 -0700996 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700997 print "Testcases not specifed in params, please provide in " + \
Jon Hall714eeba2015-09-29 17:53:10 -0700998 "params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800999 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -07001000
Jon Hall714eeba2015-09-29 17:53:10 -07001001def verifyOnosCell( options ):
Hari Krishnabe4b97b2015-07-15 12:19:43 -07001002 # Verifying onoscell option
Hari Krishna03f530e2015-07-10 17:28:27 -07001003 if options.onoscell:
1004 main.onoscell = options.onoscell
Devin Lim58046fa2017-07-05 16:55:00 -07001005 main.ONOSip = []
Hari Krishnabe4b97b2015-07-15 12:19:43 -07001006 main.mnIP = ""
Devin Lim58046fa2017-07-05 16:55:00 -07001007 cellCMD = ". ~/onos/tools/dev/bash_profile; cell " + main.onoscell
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001008 output = subprocess.check_output( [ "bash", '-c', cellCMD ] )
Hari Krishnabe4b97b2015-07-15 12:19:43 -07001009 splitOutput = output.splitlines()
Devin Lim58046fa2017-07-05 16:55:00 -07001010 main.apps = ""
Jon Hall714eeba2015-09-29 17:53:10 -07001011 for i in range( len( splitOutput ) ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001012 if re.match( "OCN", splitOutput[ i ] ):
1013 mnNode = splitOutput[ i ].split( "=" )
1014 main.mnIP = mnNode[ 1 ]
Jon Hall714eeba2015-09-29 17:53:10 -07001015 # cell already sorts OC variables in bash, so no need to
1016 # sort in TestON
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001017 elif re.match( "OC[1-9]", splitOutput[ i ] ):
1018 onosNodes = splitOutput[ i ].split( "=" )
1019 main.ONOSip.append( onosNodes[ 1 ] )
1020 elif re.match( "ONOS_APPS", splitOutput[ i ] ):
1021 main.apps = ( splitOutput[ i ].split( "=" ) )[ 1 ]
Jon Hall714eeba2015-09-29 17:53:10 -07001022 else:
Hari Krishna03f530e2015-07-10 17:28:27 -07001023 main.onoscell = main.FALSE
1024
Jon Hall714eeba2015-09-29 17:53:10 -07001025def verifyTestScript( options ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001026 '''
adminbae64d82013-08-01 10:50:15 -07001027 Verifyies test script.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001028 '''
Jon Halld61331b2015-02-17 16:35:47 -08001029 main.openspeak = openspeak.OpenSpeak()
Jon Hall53c5e662016-04-13 16:06:56 -07001030 directory = main.testDir + "/" + main.TEST
1031 if os.path.exists( directory ):
1032 pass
1033 else:
1034 directory = ""
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001035 for root, dirs, files in os.walk( main.testDir, topdown=True ):
Jon Hall53c5e662016-04-13 16:06:56 -07001036 if not directory:
1037 for name in dirs:
1038 if name == main.TEST:
1039 directory = ( os.path.join( root, name ) )
1040 index = directory.find( "/tests/" ) + 1
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001041 main.classPath = directory[ index: ].replace( '/', '.' ) + "." + main.TEST
Jon Hall53c5e662016-04-13 16:06:56 -07001042 break
1043 openspeakfile = directory + "/" + main.TEST + ".ospk"
Jon Halld74d2952018-03-01 13:26:39 -08001044 main.testDir = directory
Jon Hall53c5e662016-04-13 16:06:56 -07001045 main.testFile = directory + "/" + main.TEST + ".py"
Jon Hall714eeba2015-09-29 17:53:10 -07001046 if os.path.exists( openspeakfile ):
Jon Hall44506242015-07-29 17:40:26 -07001047 # Openspeak file found, compiling to python
Jon Hall714eeba2015-09-29 17:53:10 -07001048 main.openspeak.compiler( openspeakfile=openspeakfile, writetofile=1 )
Jon Hall53c5e662016-04-13 16:06:56 -07001049 elif os.path.exists( main.testFile ):
Jon Hall44506242015-07-29 17:40:26 -07001050 # No openspeak found, using python file instead
1051 pass
adminbae64d82013-08-01 10:50:15 -07001052 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001053 print "\nThere is no \"" + main.TEST + "\" test script.\nPlease provide a " + \
1054 "Python or OpenSpeak test script in the tests folder: " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001055 main.testDir + "/" + main.TEST + "/"
adminbae64d82013-08-01 10:50:15 -07001056 __builtin__.testthread = None
1057 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -07001058 try:
1059 testModule = __import__( main.classPath,
1060 globals(),
1061 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001062 [ main.TEST ],
Jon Hall714eeba2015-09-29 17:53:10 -07001063 -1 )
Jon Hall1306a562015-09-04 11:21:24 -07001064 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001065 print "There was an import error, it might mean that there is " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001066 "no test named " + main.TEST
Jon Halld61331b2015-02-17 16:35:47 -08001067 main.exit()
adminbae64d82013-08-01 10:50:15 -07001068
Jon Hall714eeba2015-09-29 17:53:10 -07001069 testClass = getattr( testModule, main.TEST )
adminbae64d82013-08-01 10:50:15 -07001070 main.testObject = testClass()
1071 load_parser()
Jon Halld74d2952018-03-01 13:26:39 -08001072 main.paramsFile = main.TEST + ".params" if options.paramsFile is None else options.paramsFile
1073 main.topoFile = main.TEST + ".topo" if options.topoFile is None else options.topoFile
1074 main.params = main.parser.parseFile( main.testDir + "/" + main.paramsFile )
1075 main.topology = main.parser.parseFile( main.testDir + "/" + main.topoFile )
kelvin-onlabf70fd542015-05-07 18:41:40 -07001076
YPZhang1c89e762016-06-29 10:43:58 -07001077def verifyParams( options ):
Jon Hall714eeba2015-09-29 17:53:10 -07001078 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001079 main.params = main.params[ 'PARAMS' ]
Jon Hall1306a562015-09-04 11:21:24 -07001080 except KeyError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001081 print "Error with the params file: Either the file not specified " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001082 "or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -08001083 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -07001084 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001085 main.topology = main.topology[ 'TOPOLOGY' ]
Jon Hall1306a562015-09-04 11:21:24 -07001086 except KeyError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001087 print "Error with the Topology file: Either the file not specified " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001088 "or the format is not correct"
adminbae64d82013-08-01 10:50:15 -07001089 main.exit()
YPZhang1c89e762016-06-29 10:43:58 -07001090 # Overwrite existing params variables if they are specified from command line
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001091 if len( options.params ) > 0:
YPZhang1c89e762016-06-29 10:43:58 -07001092 # Some params variables are specified from command line
1093 for param in options.params:
1094 if not re.search( ".=.", param ):
1095 print( "Error when parsing params: params should follow key=value format" )
1096 continue
Jon Hall7c4f4302016-07-15 14:39:02 -07001097 # Split the param string to catch nested keys and the value
YPZhang1c89e762016-06-29 10:43:58 -07001098 [ keys, value ] = param.split( "=" )
1099 # Split the nested keys according to its hierarchy
1100 keyList = keys.split( "/" )
1101 # Get the outermost dictionary
1102 paramDict = main.params
1103 # Get the innermost dictionary
1104 try:
1105 while len( keyList ) > 1:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001106 key = keyList.pop( 0 )
YPZhang1c89e762016-06-29 10:43:58 -07001107 assert isinstance( paramDict[ key ], dict )
1108 paramDict = paramDict[ key ]
1109 except KeyError:
1110 print( "Error when parsing params: key \"" + key + "\" not found in main.params" )
1111 main.exit()
1112 except AssertionError:
1113 print( "Error when parsing params: \"" + key + "\" is already the innermost level in main.params" )
1114 main.exit()
1115 # Change the value
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001116 if keyList[ 0 ] not in paramDict:
1117 print( "Error when parsing params: key \"" + keyList[ 0 ] + "\" not found in main.params" )
YPZhang1c89e762016-06-29 10:43:58 -07001118 main.exit()
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001119 elif isinstance( paramDict[ keyList[ 0 ] ], dict ):
1120 print( "Error when parsing params: more levels under key \"" + keyList[ 0 ] + "\" in main.params" )
YPZhang1c89e762016-06-29 10:43:58 -07001121 main.exit()
1122 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001123 paramDict[ keyList[ 0 ] ] = value
kelvin-onlabf70fd542015-05-07 18:41:40 -07001124
Jon Hall714eeba2015-09-29 17:53:10 -07001125def load_parser():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001126 '''
adminbae64d82013-08-01 10:50:15 -07001127 It facilitates the loading customised parser for topology and params file.
1128 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -07001129 It also loads default xmlparser if no parser have specified in teston.cfg
1130 file.
adminbae64d82013-08-01 10:50:15 -07001131
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001132 '''
adminbae64d82013-08-01 10:50:15 -07001133 confighash = main.configDict
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001134 if 'file' in confighash[ 'config' ][ 'parser' ] and\
1135 'class' in confighash[ 'config' ][ 'parser' ]:
1136 path = confighash[ 'config' ][ 'parser' ][ 'file' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001137 if path is not None or\
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001138 confighash[ 'config' ][ 'parser' ][ 'class' ] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001139 try:
1140 module = re.sub( r".py\s*$", "", path )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001141 moduleList = module.split( "/" )
1142 newModule = ".".join( moduleList[ -2: ] )
1143 parsingClass = confighash[ 'config' ][ 'parser' ][ 'class' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001144 parsingModule = __import__( newModule,
1145 globals(),
1146 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001147 [ parsingClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001148 -1 )
1149 parsingClass = getattr( parsingModule, parsingClass )
Jon Hall44506242015-07-29 17:40:26 -07001150 main.parser = parsingClass()
Jon Halld74d2952018-03-01 13:26:39 -08001151 if hasattr( main.parser, "parseFile" ) and\
Jon Hall714eeba2015-09-29 17:53:10 -07001152 hasattr( main.parser, "parse" ):
Jon Hall44506242015-07-29 17:40:26 -07001153 pass
1154 else:
1155 print "Invalid parser format"
adminbae64d82013-08-01 10:50:15 -07001156 main.exit()
Jon Hall44506242015-07-29 17:40:26 -07001157 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001158 print "Could not find the file " + path + \
Jon Hall714eeba2015-09-29 17:53:10 -07001159 " using default parser."
Jon Halld61331b2015-02-17 16:35:47 -08001160 load_defaultParser()
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001161 elif confighash[ 'config' ][ 'parser' ][ 'file' ] is None or\
1162 confighash[ 'config' ][ 'parser' ][ 'class' ] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001163 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -07001164 else:
1165 load_defaultParser()
1166
1167def load_defaultParser():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001168 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001169 It will load the default parser which is xml parser to parse the params and
1170 topology file.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001171 '''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001172 moduleList = main.parserPath.split( "/" )
1173 newModule = ".".join( moduleList[ -2: ] )
Jon Hall714eeba2015-09-29 17:53:10 -07001174 try:
Jon Halld61331b2015-02-17 16:35:47 -08001175 parsingClass = main.parsingClass
Jon Hall714eeba2015-09-29 17:53:10 -07001176 parsingModule = __import__( newModule,
1177 globals(),
1178 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001179 [ parsingClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001180 -1 )
1181 parsingClass = getattr( parsingModule, parsingClass )
adminbae64d82013-08-01 10:50:15 -07001182 main.parser = parsingClass()
Jon Halld74d2952018-03-01 13:26:39 -08001183 if hasattr( main.parser, "parseFile" ) and\
Jon Hall714eeba2015-09-29 17:53:10 -07001184 hasattr( main.parser, "parse" ):
adminbae64d82013-08-01 10:50:15 -07001185 pass
1186 else:
1187 main.exit()
adminbae64d82013-08-01 10:50:15 -07001188 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001189 print sys.exc_info()[ 1 ]
adminbae64d82013-08-01 10:50:15 -07001190
Jon Hall714eeba2015-09-29 17:53:10 -07001191def load_logger():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001192 '''
adminbae64d82013-08-01 10:50:15 -07001193 It facilitates the loading customised parser for topology and params file.
1194 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -07001195 It also loads default xmlparser if no parser have specified in teston.cfg
1196 file.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001197 '''
adminbae64d82013-08-01 10:50:15 -07001198 confighash = main.configDict
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001199 if 'file' in confighash[ 'config' ][ 'logger' ] and\
1200 'class' in confighash[ 'config' ][ 'logger' ]:
1201 path = confighash[ 'config' ][ 'logger' ][ 'file' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001202 if path is not None or\
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001203 confighash[ 'config' ][ 'logger' ][ 'class' ] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001204 try:
1205 module = re.sub( r".py\s*$", "", path )
Jon Hall714eeba2015-09-29 17:53:10 -07001206 moduleList = module.split( "/" )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001207 newModule = ".".join( moduleList[ -2: ] )
1208 loggerClass = confighash[ 'config' ][ 'logger' ][ 'class' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001209 loggerModule = __import__( newModule,
1210 globals(),
1211 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001212 [ loggerClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001213 -1 )
1214 loggerClass = getattr( loggerModule, loggerClass )
Jon Hall44506242015-07-29 17:40:26 -07001215 main.logger = loggerClass()
Jon Hall44506242015-07-29 17:40:26 -07001216 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001217 print "Could not find the file " + path + \
Jon Hall714eeba2015-09-29 17:53:10 -07001218 " using default logger."
adminbae64d82013-08-01 10:50:15 -07001219 load_defaultlogger()
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001220 elif confighash[ 'config' ][ 'parser' ][ 'file' ] is None or\
1221 confighash[ 'config' ][ 'parser' ][ 'class' ] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001222 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -07001223 else:
1224 load_defaultlogger()
1225
1226def load_defaultlogger():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001227 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001228 It will load the default parser which is xml parser to parse the params and
1229 topology file.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001230 '''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001231 moduleList = main.loggerPath.split( "/" )
1232 newModule = ".".join( moduleList[ -2: ] )
Jon Hall714eeba2015-09-29 17:53:10 -07001233 try:
Jon Halld61331b2015-02-17 16:35:47 -08001234 loggerClass = main.loggerClass
Jon Hall714eeba2015-09-29 17:53:10 -07001235 loggerModule = __import__( newModule,
1236 globals(),
1237 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001238 [ loggerClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001239 -1 )
1240 loggerClass = getattr( loggerModule, loggerClass )
adminbae64d82013-08-01 10:50:15 -07001241 main.logger = loggerClass()
1242
1243 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001244 print sys.exc_info()[ 1 ]
Jon Halld61331b2015-02-17 16:35:47 -08001245 main.exit()
adminbae64d82013-08-01 10:50:15 -07001246
Jon Hall714eeba2015-09-29 17:53:10 -07001247def _echo( self ):
adminbae64d82013-08-01 10:50:15 -07001248 print "THIS IS ECHO"