blob: 5653ffe284c93aff318c309f0a36fbf3c9f525ed [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 = ""
Jon Halla8cf76a2021-10-05 14:31:47 -0700257 self.CASERESULT = self.ERROR
258 self.STEPRESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700259 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700260
261 # NOTE: number of main.step statements in the
262 # outer most level of the test case. used to
263 # execute code in smaller steps
264 self.stepCount = 0
265
266 # NOTE: This is the current number of main.step()'s executed
267 # in a case. Used for logging.
268 self.stepNumber = 0
adminbae64d82013-08-01 10:50:15 -0700269 self.EXPERIMENTAL_MODE = self.FALSE
270 self.addCaseHeader()
Devin Limec989792017-08-15 15:57:55 -0700271 self.log.debug( "Case Executed : " + str( self.executedCase ) )
272 self.log.debug( "Case to be executed : " + str( self.leftCase ) )
Jon Halle234cc42015-08-31 15:26:47 -0700273 self.testCaseNumber = str( testCaseNumber )
274 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700275 stopped = False
Jon Hall5a72b712015-09-28 12:20:59 -0700276 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700277 self.code[ self.testCaseNumber ]
Jon Halld61331b2015-02-17 16:35:47 -0800278 except KeyError:
Jon Halle234cc42015-08-31 15:26:47 -0700279 self.log.error( "There is no Test-Case " + self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800280 return self.FALSE
adminbae64d82013-08-01 10:50:15 -0700281 self.stepCount = 0
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700282 while self.stepCount < len( self.code[ self.testCaseNumber ].keys() ):
Jon Hall714eeba2015-09-29 17:53:10 -0700283 result = self.runStep( self.code, self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800284 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700285 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800286 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700287 continue
Jon Hall5a72b712015-09-28 12:20:59 -0700288 # stepResults format: ( stepNo[], stepName[], stepResult[], onFail[] )
289 stepResults = self.stepResultsList
Jon Halle234cc42015-08-31 15:26:47 -0700290 if not stopped:
291 if self.CASERESULT == self.TRUE or self.CASERESULT == self.FALSE:
Jon Hall714eeba2015-09-29 17:53:10 -0700292 # Result was already explitily set somewhere else like
293 # in skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700294 pass
Jon Hall5a72b712015-09-28 12:20:59 -0700295 elif all( self.TRUE == i for i in stepResults ):
kelvin-onlabf70fd542015-05-07 18:41:40 -0700296 # ALL PASSED
297 self.CASERESULT = self.TRUE
Jon Hall5a72b712015-09-28 12:20:59 -0700298 elif self.FALSE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700299 # AT LEAST ONE FAILED
300 self.CASERESULT = self.FALSE
Jon Hall5a72b712015-09-28 12:20:59 -0700301 elif self.TRUE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700302 # AT LEAST ONE PASSED
303 self.CASERESULT = self.TRUE
304 else:
305 self.CASERESULT = self.NORESULT
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700306 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = self.CASERESULT
Devin Limec989792017-08-15 15:57:55 -0700307 self.organizeResult( self.CurrentTestCaseNumber, self.CASERESULT )
Jon Hall714eeba2015-09-29 17:53:10 -0700308 self.logger.updateCaseResults( self )
Jon Hall783bbf92015-07-23 14:33:19 -0700309 self.log.summary( self.caseExplanation )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700310 self.log.summary( self.stepCache )
Jon Hall026bd712021-08-31 16:30:09 -0700311 self.caseResultsWiki()
312 self.caseResultsTAP()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700313 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700314 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700315
Jon Hall026bd712021-08-31 16:30:09 -0700316 def caseResultsWiki( self ):
317 """
318 Add case results to the wiki results file
319 """
320 self.log.wiki( "<p>" + self.caseExplanation + "</p>" )
321 self.log.wiki( "<ul>" )
322 subcaseMessage = False
323 for line in self.stepCache.splitlines():
324 if re.search( "[0-9]\.[0-9]", line ): # Step
325 if subcaseMessage: # End of Failure Message Printout
326 self.log.wiki( "</ul>\n" )
327 subcaseMessage = False
328 if re.search( " - PASS$", line ):
329 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
330 elif re.search( " - FAIL$", line ):
331 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
332 elif re.search( " - No Result$", line ):
333 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
334 else: # Substep
335 if not subcaseMessage: # Open Failure Message Printout
336 self.log.wiki( "<ul><li>" + line + "</li>\n" )
337 subcaseMessage = True
338 else: # Add to Failure Message Printout
339 self.log.wiki( "<li>" + line + "</li>\n" )
340 if subcaseMessage: # End of Failure Message Printout for last item
341 self.log.wiki( "</ul>\n" )
342 self.log.wiki( "</ul>" )
343
344 def caseResultsTAP( self ):
345 """
346 Add case results to the TAP results file
347 """
Jon Hall026bd712021-08-31 16:30:09 -0700348 main.log.debug( self.stepCache )
Jon Hall026bd712021-08-31 16:30:09 -0700349 steps = 0
350 stepLines = []
351 for line in self.stepCache.splitlines():
Jon Hall026bd712021-08-31 16:30:09 -0700352 if re.search( "[0-9]\.[0-9]", line ): # Step
Jon Hall026bd712021-08-31 16:30:09 -0700353 if re.search( " - PASS$", line ):
354 steps += 1
Jon Halla8cf76a2021-10-05 14:31:47 -0700355 stepLines.append( " ok - STEP %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700356 elif re.search( " - FAIL$", line ):
357 steps += 1
Jon Halla8cf76a2021-10-05 14:31:47 -0700358 stepLines.append( " not ok - STEP %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700359 elif re.search( " - No Result$", line ):
360 steps += 1
Jon Halla8cf76a2021-10-05 14:31:47 -0700361 stepLines.append( " ok - STEP %s # TODO: No assertion in test step" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700362 else: # Substep
Jon Halla8cf76a2021-10-05 14:31:47 -0700363 stepLines.append( " # %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700364 if steps > 0:
365 self.log.TAP( " 1..%s" % steps )
Jon Halla8cf76a2021-10-05 14:31:47 -0700366 for line in stepLines:
367 self.log.TAP( line )
Jon Hall026bd712021-08-31 16:30:09 -0700368
369
Devin Limec989792017-08-15 15:57:55 -0700370 def organizeResult( self, caseNum, result ):
371 """
372 Organize the result and put the current number into either
373 failed/noResult lists.
374 * caseNum - number of the case
375 * result - result of the case
376 """
377 if result == main.FALSE:
378 self.failedCase.append( caseNum )
379 elif result == self.NORESULT:
380 self.noResultCase.append( caseNum )
381
Jon Hall714eeba2015-09-29 17:53:10 -0700382 def runStep( self, code, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700383 if not cli.pause:
Jon Hall5a72b712015-09-28 12:20:59 -0700384 try:
385 step = self.stepCount
386 # stepResults format: ( stepNo, stepName, stepResult, onFail )
387 # NOTE: This is needed to catch results of main.step()'s
388 # called inside functions or loops
389 self.stepResults = ( [], [], [], [] )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700390 exec code[ testCaseNumber ][ step ] in module.__dict__
adminbae64d82013-08-01 10:50:15 -0700391 self.stepCount = self.stepCount + 1
Jon Hall96b816f2015-11-03 12:00:56 -0800392 self.parseStepResults( testCaseNumber )
Jon Hallca319892017-06-15 15:25:22 -0700393 except SkipCase: # Raised in self.skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700394 self.log.warn( "Skipping the rest of CASE" +
395 str( testCaseNumber ) )
Jon Hall96b816f2015-11-03 12:00:56 -0800396 self.parseStepResults( testCaseNumber )
Jon Hall714eeba2015-09-29 17:53:10 -0700397 self.stepResultsList.append( self.STEPRESULT )
Jon Halle234cc42015-08-31 15:26:47 -0700398 self.stepCache += "\t\t" + self.onFailMsg + "\n"
399 self.stepCount = self.stepCount + 1
400 return self.FALSE
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000401 except StandardError as e:
Jon Hallc1606352015-10-06 14:51:36 -0700402 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700403 stepNo = self.stepResults[ 0 ][ self.stepNumber - 1 ]
Jon Hallc1606352015-10-06 14:51:36 -0700404 except IndexError:
405 stepNo = "<IndexError>"
406 main.log.warn( "Error trying to get step number. " +
407 "It is likely between step " +
Jon Hall6e709752016-02-01 13:38:46 -0800408 str( self.stepNumber ) + " and step " +
Jon Hallc1606352015-10-06 14:51:36 -0700409 str( self.stepNumber + 1 ) )
410 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700411 stepName = self.stepResults[ 1 ][ self.stepNumber - 1 ]
Jon Hallc1606352015-10-06 14:51:36 -0700412 except IndexError:
413 stepName = "<IndexError>"
414 self.log.error( "\nException in the following section of" +
415 " code: " + str( testCaseNumber ) + "." +
416 str( stepNo ) + ": " + stepName )
Jeremyd9e4eb12016-04-13 12:09:06 -0700417 self.log.error( str( e.__class__ ) + str( e.message ) )
Jon Halld14a5002021-03-30 16:45:30 -0700418 self.log.exception( "" )
adminbae64d82013-08-01 10:50:15 -0700419 self.stepCount = self.stepCount + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700420 self.logger.updateCaseResults( self )
Jon Hall026bd712021-08-31 16:30:09 -0700421 self.stepResultsWiki()
422 self.stepResultsTAP()
Jon Hall714eeba2015-09-29 17:53:10 -0700423 # summary results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700424 self.log.summary( self.stepCache )
425 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700426 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700427 self.exit()
Jon Halle234cc42015-08-31 15:26:47 -0700428 return self.TRUE
adminbae64d82013-08-01 10:50:15 -0700429 if cli.stop:
430 cli.stop = False
adminbae64d82013-08-01 10:50:15 -0700431 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700432 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = "Stopped"
Jon Hall714eeba2015-09-29 17:53:10 -0700433 self.logger.updateCaseResults( self )
adminbae64d82013-08-01 10:50:15 -0700434 result = self.cleanup()
Jon Halle234cc42015-08-31 15:26:47 -0700435 return self.FALSE
436
Jon Hall026bd712021-08-31 16:30:09 -0700437 def stepResultsWiki( self ):
438 """
439 Add step results to the wiki file
440 """
441 # WIKI results
442 self.log.wiki( "<ul>" )
443 for line in self.stepCache.splitlines():
444 if re.search( " - PASS$", line ):
445 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
446 elif re.search( " - FAIL$", line ):
447 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
448 elif re.search( " - No Result$", line ):
449 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
450 else: # Should only be on fail message
451 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
452 self.log.wiki( "</ul>" )
453
454 def stepResultsTAP( self ):
455 """
456 Add step results to the TAP file
457 """
458 # TAP results
459 # TODO Do we need indetation for the steps?
460 main.log.debug( "StepResultsTAP" )
461 for line in self.stepCache.splitlines():
462 if re.search( " - PASS$", line ):
Jon Halla8cf76a2021-10-05 14:31:47 -0700463 self.log.TAP( " ok - STEP %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700464 elif re.search( " - FAIL$", line ):
Jon Halla8cf76a2021-10-05 14:31:47 -0700465 self.log.TAP( " not ok - STEP %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700466 elif re.search( " - No Result$", line ):
Jon Halla8cf76a2021-10-05 14:31:47 -0700467 self.log.TAP( " ok - STEP %s # TODO: No assertion in test step" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700468 else: # Should only be on fail message
469 self.log.TAP( " # %s" % line )
470
Jon Hall96b816f2015-11-03 12:00:56 -0800471 def parseStepResults( self, testCaseNumber ):
472 """
473 Parse throught the step results for the wiki
474 """
475 try:
476 # Iterate through each of the steps and print them
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700477 for index in range( len( self.stepResults[ 0 ] ) ):
Jon Hall96b816f2015-11-03 12:00:56 -0800478 # stepResults = ( stepNo, stepName, stepResult, onFail )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700479 stepNo = self.stepResults[ 0 ][ index ]
480 stepName = self.stepResults[ 1 ][ index ]
481 stepResult = self.stepResults[ 2 ][ index ]
482 onFail = self.stepResults[ 3 ][ index ]
Jon Hall96b816f2015-11-03 12:00:56 -0800483 self.stepCache += "\t" + str( testCaseNumber ) + "."
484 self.stepCache += str( stepNo ) + " "
485 self.stepCache += stepName + " - "
486 if stepResult == self.TRUE:
487 self.stepCache += "PASS\n"
488 elif stepResult == self.FALSE:
489 self.stepCache += "FAIL\n"
490 self.stepCache += "\t\t" + onFail + "\n"
491 else:
492 self.stepCache += "No Result\n"
493 self.stepResultsList.append( stepResult )
494 except Exception:
495 self.log.exception( "Error parsing step results" )
496
Jon Halla8cf76a2021-10-05 14:31:47 -0700497 def skipCase( self, result="NORESULT", msg=None ):
Jon Halle234cc42015-08-31 15:26:47 -0700498 """
499 Will skip the rest of the code in a test case. The case results will be
500 determined as normal based on completed assertions unless the result
501 argument is given.
502
503 Optional Arguments:
Jon Hall7c4f4302016-07-15 14:39:02 -0700504 result: Case insensitive string. Can be 'PASS' or 'FAIL' and will set
Jon Halle234cc42015-08-31 15:26:47 -0700505 the case result accordingly.
506 msg: Message to be printed when the case is skipped in the reports.
507 """
508 result = result.upper().strip()
509 if result == "PASS":
510 self.CASERESULT = self.TRUE
Jon Halla8cf76a2021-10-05 14:31:47 -0700511 elif result == "NORESULT":
512 self.CASERESULT = self.NORESULT
513 else:
Jon Halle234cc42015-08-31 15:26:47 -0700514 self.CASERESULT = self.FALSE
515 self.onFailMsg = "Skipping the rest of this case. "
516 if msg:
517 self.onFailMsg += str( msg )
Jon Hallca319892017-06-15 15:25:22 -0700518 raise SkipCase
kelvin-onlabf70fd542015-05-07 18:41:40 -0700519
Jon Hall714eeba2015-09-29 17:53:10 -0700520 def addCaseHeader( self ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700521 caseHeader = "\n" + "*" * 30 + "\n Result summary for Testcase" + \
Jon Hall714eeba2015-09-29 17:53:10 -0700522 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 30 + "\n"
523 self.log.exact( caseHeader )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700524 caseHeader = "\n" + "*" * 40 + "\nStart of Test Case" + \
Jon Hall714eeba2015-09-29 17:53:10 -0700525 str( self.CurrentTestCaseNumber ) + " : "
adminbae64d82013-08-01 10:50:15 -0700526 for driver in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700527 vars( self )[ driver + 'log' ].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700528
Jon Hall714eeba2015-09-29 17:53:10 -0700529 def addCaseFooter( self ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700530 stepNo = self.stepResults[ 0 ][ -2 ]
Jon Hall714eeba2015-09-29 17:53:10 -0700531 if stepNo > 0:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700532 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." + \
Jon Hall714eeba2015-09-29 17:53:10 -0700533 str( stepNo ) + ": " + str( self.stepName )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700534 stepHeader = "\n" + "*" * 40 + "\nEnd of Step " + previousStep + \
Jon Hall714eeba2015-09-29 17:53:10 -0700535 "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700536
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700537 caseFooter = "\n" + "*" * 40 + "\nEnd of Test case " + \
Jon Hall714eeba2015-09-29 17:53:10 -0700538 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700539
adminbae64d82013-08-01 10:50:15 -0700540 for driver in self.driversList:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700541 vars( self )[ driver ].write( stepHeader + "\n" + caseFooter )
adminbae64d82013-08-01 10:50:15 -0700542
Devin Limba37cdd2018-05-07 11:41:05 -0700543 def setCheckingPoint( self ):
544 '''
545 Using when running findPatchScript.sh. This function needs to be placed
546 on the point that has the problem.
547
548 For example, if you see unusual behavior or from the portion of the code,
549 this is where you need to put with the conditional statement.
550 If some of the latency result is much greater than usual, have if statement
551 that checks if the result is greater than some point and include this function.
552
553 This will mark the 0 to findPatchResult.txt in /tmp/ and exit the test.
554 Then from findPatchScript, it will move onto the next commit and re-run the
555 test.
556 '''
557 self.log.error( "Reached to the checking point. Will mark the result and exit the test" )
558 resultFile = open( "/tmp/findPatchResult.txt", "w" )
559 resultFile.write( "0" )
560 resultFile.close()
561 self.cleanAndExit()
562
Jon Hall714eeba2015-09-29 17:53:10 -0700563 def cleanup( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000564 '''
Jon Hall5b586732015-06-11 11:39:39 -0700565 Print a summary of the current test's results then attempt to release
566 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700567
Jon Hall5b586732015-06-11 11:39:39 -0700568 This function shouldbe threadsafe such that cleanup will only be
569 executed once per test.
570
571 This will return TRUE if all the component handles and log handles
572 closed properly, else return FALSE.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000573 '''
adminbae64d82013-08-01 10:50:15 -0700574 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700575 lock = self.cleanupLock
576 if lock.acquire( False ):
577 try:
578 if self.cleanupFlag is False: # First thread to run this
579 self.cleanupFlag = True
Jon Hall0fc0d452015-07-14 09:49:58 -0700580 if self.initiated:
Jon Hall714eeba2015-09-29 17:53:10 -0700581 self.logger.testSummary( self )
Jon Hall892818c2015-10-20 17:58:34 -0700582 components = self.componentDictionary
583 for component in sorted( components,
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700584 key=lambda item: components[ item ][ 'connect_order' ],
Jon Hall892818c2015-10-20 17:58:34 -0700585 reverse=True ):
Jon Hall714eeba2015-09-29 17:53:10 -0700586 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700587 tempObject = vars( self )[ component ]
588 print "Disconnecting from " + str( tempObject.name ) + \
589 ": " + str( tempObject.__class__ )
Jon Hall5b586732015-06-11 11:39:39 -0700590 tempObject.disconnect()
Jon Hall1306a562015-09-04 11:21:24 -0700591 except KeyboardInterrupt:
592 pass
593 except KeyError:
594 # Component not created yet
595 self.log.warn( "Could not find the component " +
596 str( component ) )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000597 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700598 self.log.exception( "Exception while disconnecting from " +
599 str( component ) )
600 result = self.FALSE
601 # Closing all the driver's session files
602 for driver in self.componentDictionary.keys():
603 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700604 vars( self )[ driver ].close_log_handles()
Jon Hall1306a562015-09-04 11:21:24 -0700605 except KeyboardInterrupt:
606 pass
607 except KeyError:
608 # Component not created yet
609 self.log.warn( "Could not find the component " +
610 str( driver ) + " while trying to" +
611 " close log file" )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000612 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700613 self.log.exception( "Exception while closing log files for " +
614 str( driver ) )
615 result = self.FALSE
616 else:
617 pass # Someone else already ran through this function
618 finally:
619 lock.release()
620 else: # Someone already has a lock
621 # NOTE: This could cause problems if we don't release the lock
622 # correctly
623 lock.acquire() # Wait for the other thread to finish
624 # NOTE: If we don't wait, exit could be called while the thread
625 # with the lock is still cleaning up
626 lock.release()
adminbae64d82013-08-01 10:50:15 -0700627 return result
Jon Halld61331b2015-02-17 16:35:47 -0800628
Jon Hall714eeba2015-09-29 17:53:10 -0700629 def pause( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000630 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700631 This function will pause the test's execution, and will continue after
632 user provide 'resume' command.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000633 '''
adminbae64d82013-08-01 10:50:15 -0700634 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700635
Jon Hall714eeba2015-09-29 17:53:10 -0700636 def onfail( self, *components ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000637 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700638 When test step failed, calling all the components onfail.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000639 '''
adminbae64d82013-08-01 10:50:15 -0700640 if not components:
Jon Hall714eeba2015-09-29 17:53:10 -0700641 try:
adminbae64d82013-08-01 10:50:15 -0700642 for component in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700643 tempObject = vars( self )[ component ]
adminbae64d82013-08-01 10:50:15 -0700644 result = tempObject.onfail()
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000645 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700646 print str( e )
adminbae64d82013-08-01 10:50:15 -0700647 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700648 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700649 try:
adminbae64d82013-08-01 10:50:15 -0700650 for component in components:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700651 tempObject = vars( self )[ component ]
adminbae64d82013-08-01 10:50:15 -0700652 result = tempObject.onfail()
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000653 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700654 print str( e )
adminbae64d82013-08-01 10:50:15 -0700655 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700656
Jon Hall714eeba2015-09-29 17:53:10 -0700657 def getDriverPath( self, driverName ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000658 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700659 Based on the component 'type' specified in the params , this method
660 will find the absolute path, by recursively searching the name of
661 the component.
662
663 NOTE: This function requires the linux 'find' command.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000664 '''
adminbae64d82013-08-01 10:50:15 -0700665 import commands
666
Jon Hall714eeba2015-09-29 17:53:10 -0700667 cmd = "find " + drivers_path + " -name " + driverName + ".py"
668 result = commands.getoutput( cmd )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700669
Jon Hall714eeba2015-09-29 17:53:10 -0700670 result_array = str( result ).split( '\n' )
adminbae64d82013-08-01 10:50:15 -0700671 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700672
adminbae64d82013-08-01 10:50:15 -0700673 for drivers_list in result_array:
Jon Hall714eeba2015-09-29 17:53:10 -0700674 result_count = result_count + 1
675 if result_count > 1:
676 print "Found " + driverName + " " + str( result_count ) + " times:"
677 print str( result_array )
adminbae64d82013-08-01 10:50:15 -0700678 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700679
Jon Hall714eeba2015-09-29 17:53:10 -0700680 result = re.sub( "(.*)drivers", "", result )
681 result = re.sub( "\/\/", "/", result )
682 result = re.sub( "\.py", "", result )
683 result = re.sub( "\.pyc", "", result )
684 result = re.sub( "\/", ".", result )
685 result = "drivers" + result
adminbae64d82013-08-01 10:50:15 -0700686 return result
adminbae64d82013-08-01 10:50:15 -0700687
Jon Hall714eeba2015-09-29 17:53:10 -0700688 def step( self, stepDesc ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000689 '''
adminbae64d82013-08-01 10:50:15 -0700690 The step information of the test-case will append to the logs.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000691 '''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700692 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." + \
Jon Hall714eeba2015-09-29 17:53:10 -0700693 str( self.stepNumber ) + ": " + str( self.stepName )
adminbae64d82013-08-01 10:50:15 -0700694 self.stepName = stepDesc
Jon Hall5a72b712015-09-28 12:20:59 -0700695 self.stepNumber += 1
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700696 self.stepResults[ 0 ].append( self.stepNumber )
697 self.stepResults[ 1 ].append( stepDesc )
698 self.stepResults[ 2 ].append( self.NORESULT )
699 self.stepResults[ 3 ].append( "No on fail message given" )
adminbae64d82013-08-01 10:50:15 -0700700
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700701 stepName = " " + str( self.CurrentTestCaseNumber ) + "." + \
Jon Hall714eeba2015-09-29 17:53:10 -0700702 str( self.stepNumber ) + ": " + str( stepDesc )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700703 self.log.step( stepName )
adminbae64d82013-08-01 10:50:15 -0700704 stepHeader = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700705 line = "\n" + "-" * 45 + "\n"
706 if self.stepNumber > 1:
707 stepHeader = line + "End of Step " + previousStep + line
708 stepHeader += line + "Start of Step" + stepName + line
adminbae64d82013-08-01 10:50:15 -0700709 for driver in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700710 vars( self )[ driver + 'log' ].info( stepHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700711
Jon Hall714eeba2015-09-29 17:53:10 -0700712 def case( self, testCaseName ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000713 '''
adminbae64d82013-08-01 10:50:15 -0700714 Test's each test-case information will append to the logs.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000715 '''
Jon Halld61331b2015-02-17 16:35:47 -0800716 self.CurrentTestCase = testCaseName
Jon Hall714eeba2015-09-29 17:53:10 -0700717 testCaseName = " " + str( testCaseName )
718 self.log.case( testCaseName )
719 caseHeader = testCaseName + "\n" + "*" * 40 + "\n"
adminbae64d82013-08-01 10:50:15 -0700720 for driver in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700721 vars( self )[ driver + 'log' ].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700722
Jon Hall714eeba2015-09-29 17:53:10 -0700723 def testDesc( self, description ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000724 '''
adminbae64d82013-08-01 10:50:15 -0700725 Test description will append to the logs.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000726 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700727 description = "Test Description : " + str( description )
728 self.log.info( description )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700729
Jon Hall714eeba2015-09-29 17:53:10 -0700730 def _getTest( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000731 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700732 This method will parse the test script to find required test
733 information.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000734 '''
Jon Hall53c5e662016-04-13 16:06:56 -0700735 testFileHandler = open( main.testFile, 'r' )
adminbae64d82013-08-01 10:50:15 -0700736 testFileList = testFileHandler.readlines()
737 testFileHandler.close()
adminbae64d82013-08-01 10:50:15 -0700738 counter = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700739 for index in range( len( testFileList ) ):
740 lineMatch = re.match( '\s+def CASE(\d+)(.*):',
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700741 testFileList[ index ],
Jon Hall714eeba2015-09-29 17:53:10 -0700742 0 )
adminbae64d82013-08-01 10:50:15 -0700743 if lineMatch:
Jon Hall714eeba2015-09-29 17:53:10 -0700744 counter = counter + 1
745 self.TC_PLANNED = len( self.testcases_list )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700746
Jon Hall714eeba2015-09-29 17:53:10 -0700747 def response_parser( self, response, return_format ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000748 ''' It will load the default response parser '''
adminbae64d82013-08-01 10:50:15 -0700749 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700750 response_dict = self.response_to_dict( response, return_format )
751 return_format_string = self.dict_to_return_format( response,
752 return_format,
753 response_dict )
adminbae64d82013-08-01 10:50:15 -0700754 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700755
Jon Hall714eeba2015-09-29 17:53:10 -0700756 def response_to_dict( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700757 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700758 json_match = re.search( '^\s*{', response )
759 xml_match = re.search( '^\s*\<', response )
760 ini_match = re.search( '^\s*\[', response )
761 if json_match:
762 self.log.info( "Response is in 'JSON' format, converting to '" +
763 return_format + "' format" )
Jon Halld61331b2015-02-17 16:35:47 -0800764 # Formatting the json string
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000765 response = re.sub( r"{\s*'?(\w)", r'{"\1', response )
Jon Hall714eeba2015-09-29 17:53:10 -0700766 response = re.sub( r",\s*'?(\w)", r',"\1', response )
767 response = re.sub( r"(\w)'?\s*:", r'\1":', response )
768 response = re.sub( r":\s*'(\w)'\s*([,}])", r':"\1"\2', response )
769 try:
adminbae64d82013-08-01 10:50:15 -0700770 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700771 response_dict = json.loads( response )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000772 except StandardError:
Jon Hall2a5002c2015-08-21 16:49:11 -0700773 self.log.exception( "Json Parser is unable to parse the string" )
adminbae64d82013-08-01 10:50:15 -0700774 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700775 elif ini_match:
776 self.log.info( "Response is in 'INI' format, converting to '" +
777 return_format + "' format" )
adminbae64d82013-08-01 10:50:15 -0700778 from configobj import ConfigObj
Jon Hall714eeba2015-09-29 17:53:10 -0700779 response_file = open( "respnse_file.temp", 'w' )
780 response_file.write( response )
Jon Halld61331b2015-02-17 16:35:47 -0800781 response_file.close()
Jon Hall714eeba2015-09-29 17:53:10 -0700782 response_dict = ConfigObj( "respnse_file.temp" )
adminbae64d82013-08-01 10:50:15 -0700783 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700784 elif xml_match:
785 self.log.info( "Response is in 'XML' format, converting to '" +
786 return_format + "' format" )
787 try:
788 response_dict = xmldict.xml_to_dict( "<response> " +
789 str( response ) +
790 " </response>" )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000791 except StandardError:
Jon Hall1306a562015-09-04 11:21:24 -0700792 self.log.exception()
adminbae64d82013-08-01 10:50:15 -0700793 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700794
Jon Hall714eeba2015-09-29 17:53:10 -0700795 def dict_to_return_format( self, response, return_format, response_dict ):
796 if return_format == 'table':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000797 ''' Will return in table format'''
adminbae64d82013-08-01 10:50:15 -0700798 to_do = "Call the table output formatter"
799 global response_table
800 response_table = '\n'
Jon Hall714eeba2015-09-29 17:53:10 -0700801 response_table = response_table + '\t'.join( response_dict ) + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700802
Jon Hall714eeba2015-09-29 17:53:10 -0700803 def get_table( value_to_convert ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000804 ''' This will parse the dictionary recusrsively and print as
805 table format'''
adminbae64d82013-08-01 10:50:15 -0700806 table_data = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700807 if isinstance( value_to_convert, dict ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700808 table_data = table_data + '\t'.join( value_to_convert ) + \
Jon Hall714eeba2015-09-29 17:53:10 -0700809 "\n"
810 for temp_val in value_to_convert.values():
811 table_data = table_data + get_table( temp_val )
812 else:
813 table_data = table_data + str( value_to_convert ) + "\t"
Jon Halld61331b2015-02-17 16:35:47 -0800814 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700815
Jon Hall714eeba2015-09-29 17:53:10 -0700816 for value in response_dict.values():
817 response_table = response_table + get_table( value )
adminbae64d82013-08-01 10:50:15 -0700818 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700819
Jon Hall714eeba2015-09-29 17:53:10 -0700820 elif return_format == 'config':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000821 ''' Will return in config format'''
adminbae64d82013-08-01 10:50:15 -0700822 to_do = 'Call dict to config coverter'
Jon Hall714eeba2015-09-29 17:53:10 -0700823 response_string = str( response_dict )
adminbae64d82013-08-01 10:50:15 -0700824 print response_string
Jon Hall714eeba2015-09-29 17:53:10 -0700825 response_config = re.sub( ",", "\n\t", response_string )
826 response_config = re.sub( "u\'", "\'", response_config )
827 response_config = re.sub( "{", "", response_config )
828 response_config = re.sub( "}", "\n", response_config )
829 response_config = re.sub( ":", " =", response_config )
830 return "[response]\n\t " + response_config
adminbae64d82013-08-01 10:50:15 -0700831 elif return_format == 'xml':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000832 ''' Will return in xml format'''
Jon Hall714eeba2015-09-29 17:53:10 -0700833 response_xml = xmldict.dict_to_xml( response_dict )
834 response_xml = re.sub( ">\s*<", ">\n<", response_xml )
835 return "\n" + response_xml
adminbae64d82013-08-01 10:50:15 -0700836 elif return_format == 'json':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000837 ''' Will return in json format'''
adminbae64d82013-08-01 10:50:15 -0700838 to_do = 'Call dict to xml coverter'
839 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700840 response_json = json.dumps( response_dict )
adminbae64d82013-08-01 10:50:15 -0700841 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700842
Jon Hall714eeba2015-09-29 17:53:10 -0700843 def get_random( self ):
adminbae64d82013-08-01 10:50:15 -0700844 self.random_order = self.random_order + 1
845 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700846
Jon Hall714eeba2015-09-29 17:53:10 -0700847 def exit( self ):
adminbae64d82013-08-01 10:50:15 -0700848 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700849 for thread in threading.enumerate():
850 if thread.isAlive():
851 try:
852 thread._Thread__stop()
853 except:
Jon Hall1306a562015-09-04 11:21:24 -0700854 # NOTE: We should catch any exceptions while trying to
855 # close the thread so that we can try to close the other
856 # threads as well
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700857 print str( thread.getName() ) + \
Jon Hall714eeba2015-09-29 17:53:10 -0700858 ' could not be terminated'
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700859 os.system( "stty sane" ) # fix format if necessary
adminbae64d82013-08-01 10:50:15 -0700860 sys.exit()
861
You Wang7880b372019-02-27 16:50:47 -0800862 def cleanAndExit( self, alarm=True, msg="" ):
Devin Lim44075962017-08-11 10:56:37 -0700863 """
864 It will set the testcase result to be FAILED and update it
865 before cleaning up and exitting the test.
You Wang7880b372019-02-27 16:50:47 -0800866 alarm: when set to True, it will write to the alarm log before
867 cleaning up and exitting; otherwise it will write to error log.
868 msg: message that will be written to the log if specified;
869 otherwise a default message will be written.
Devin Lim44075962017-08-11 10:56:37 -0700870 :return:
871 """
872 if self.CurrentTestCaseNumber:
873 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = self.FALSE
Devin Limec989792017-08-15 15:57:55 -0700874 self.organizeResult( self.CurrentTestCaseNumber, self.FALSE )
Devin Lim44075962017-08-11 10:56:37 -0700875 self.logger.updateCaseResults( self )
You Wang7880b372019-02-27 16:50:47 -0800876 if alarm:
877 if msg:
878 self.log.alarm( "Test exited unexpectedly: {}".format( msg ) )
879 else:
880 self.log.alarm( "Test exited unexpectedly" )
881 else:
882 if msg:
883 self.log.error( "Test exited unexpectedly: {}".format( msg ) )
884 else:
885 self.log.error( "Test exited unexpectedly" )
Devin Lim44075962017-08-11 10:56:37 -0700886 self.cleanup()
887 self.exit()
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700888
Jon Hallcd3d2a32015-10-01 11:07:28 -0700889 def stop( self, email=False ):
890 """
891 Stop the test until Ctrl-D is entered.
892 Ctrl-C will kill the test
Jon Hall25079782015-10-13 13:54:39 -0700893
894 Optional arguments:
895 email can either be a bool, or you can specify the email address
896 to send the email to
Jon Hallcd3d2a32015-10-01 11:07:28 -0700897 """
898 try:
899 if email:
Jon Hall25079782015-10-13 13:54:39 -0700900 if '@' in email:
901 main.mail = email
902 utilities.send_warning_email()
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700903 self.log.debug( "Test execution suspended. \n"
904 "- Type 'c' to resume the test.\n"
905 "- Type Ctrl-C to exit the test.\n"
906 "- Enter interactive python interpreter commands.\n"
907 "\t- ie: main.Mininet1.pingall()\n"
908 "- Type 'help' for help with pdb." )
909 pdb.set_trace()
Jon Hallcd3d2a32015-10-01 11:07:28 -0700910 except EOFError:
911 return
912 # Pass all other exceptions up to caller
913
914
Jon Hall714eeba2015-09-29 17:53:10 -0700915def verifyOptions( options ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000916 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700917 This will verify the command line options and set to default values,
918 if any option not given in command line.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000919 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700920 verifyTest( options )
921 verifyExample( options )
922 verifyTestScript( options )
YPZhang1c89e762016-06-29 10:43:58 -0700923 verifyParams( options )
Jon Hall714eeba2015-09-29 17:53:10 -0700924 verifyLogdir( options )
925 verifyMail( options )
926 verifyTestCases( options )
927 verifyOnosCell( options )
adminbae64d82013-08-01 10:50:15 -0700928
Jon Hall714eeba2015-09-29 17:53:10 -0700929def verifyTest( options ):
Jon Hall44506242015-07-29 17:40:26 -0700930 try:
931 if options.testname:
932 main.TEST = options.testname
Jon Hall714eeba2015-09-29 17:53:10 -0700933 main.classPath = "tests." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700934 main.tests_path = tests_path
935 elif options.example:
936 main.TEST = options.example
Jon Hall714eeba2015-09-29 17:53:10 -0700937 main.tests_path = path + "/examples/"
938 main.classPath = "examples." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700939 except AttributeError:
adminbae64d82013-08-01 10:50:15 -0700940 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700941 main.exit()
adminbae64d82013-08-01 10:50:15 -0700942
Jon Hall714eeba2015-09-29 17:53:10 -0700943def verifyExample( options ):
adminbae64d82013-08-01 10:50:15 -0700944 if options.example:
Jon Hall714eeba2015-09-29 17:53:10 -0700945 main.testDir = path + '/examples/'
946 main.tests_path = path + "/examples/"
947 main.classPath = "examples." + main.TEST + "." + main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700948
Jon Hall714eeba2015-09-29 17:53:10 -0700949def verifyLogdir( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800950 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700951 if options.logdir:
952 main.logdir = options.logdir
Jon Hall714eeba2015-09-29 17:53:10 -0700953 else:
Jon Halld61331b2015-02-17 16:35:47 -0800954 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700955
Jon Hall714eeba2015-09-29 17:53:10 -0700956def verifyMail( options ):
Jon Hall25079782015-10-13 13:54:39 -0700957 # Mail-To: field
958 if options.mail: # Test run specific
adminbae64d82013-08-01 10:50:15 -0700959 main.mail = options.mail
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700960 elif main.params.get( 'mail' ): # Test suite specific
Jon Hall25079782015-10-13 13:54:39 -0700961 main.mail = main.params.get( 'mail' )
962 else: # TestON specific
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700963 main.mail = main.config[ 'config' ].get( 'mail_to' )
Jon Hall25079782015-10-13 13:54:39 -0700964 # Mail-From: field
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700965 main.sender = main.config[ 'config' ].get( 'mail_from' )
Jon Hall25079782015-10-13 13:54:39 -0700966 # Mail smtp server
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700967 main.smtp = main.config[ 'config' ].get( 'mail_server' )
Jon Hall25079782015-10-13 13:54:39 -0700968 # Mail-From account password
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700969 main.senderPwd = main.config[ 'config' ].get( 'mail_pass' )
Jon Hall25079782015-10-13 13:54:39 -0700970
Devin Lim2df68a12017-06-30 15:39:05 -0700971def evalTestCase( tempList ):
972 tList = []
973 for tcase in tempList:
974 if isinstance( tcase, list ):
975 tList.extend( evalTestCase( tcase ) )
976 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700977 tList.extend( [ tcase ] )
Devin Lim2df68a12017-06-30 15:39:05 -0700978 return tList
adminbae64d82013-08-01 10:50:15 -0700979
Jon Hall714eeba2015-09-29 17:53:10 -0700980def verifyTestCases( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800981 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700982 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800983 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800984 # sys.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700985 testcases_list = re.sub( "(\[|\])", "", options.testcases )
986 main.testcases_list = eval( testcases_list + "," )
987 else:
adminbae64d82013-08-01 10:50:15 -0700988 if 'testcases' in main.params.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700989 temp = eval( main.params[ 'testcases' ] + "," )
Devin Lim2df68a12017-06-30 15:39:05 -0700990 main.testcases_list = evalTestCase( list( temp ) )
Jon Hall714eeba2015-09-29 17:53:10 -0700991 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700992 print "Testcases not specifed in params, please provide in " + \
Jon Hall714eeba2015-09-29 17:53:10 -0700993 "params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800994 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700995
Jon Hall714eeba2015-09-29 17:53:10 -0700996def verifyOnosCell( options ):
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700997 # Verifying onoscell option
Hari Krishna03f530e2015-07-10 17:28:27 -0700998 if options.onoscell:
999 main.onoscell = options.onoscell
Devin Lim58046fa2017-07-05 16:55:00 -07001000 main.ONOSip = []
Hari Krishnabe4b97b2015-07-15 12:19:43 -07001001 main.mnIP = ""
Devin Lim58046fa2017-07-05 16:55:00 -07001002 cellCMD = ". ~/onos/tools/dev/bash_profile; cell " + main.onoscell
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001003 output = subprocess.check_output( [ "bash", '-c', cellCMD ] )
Hari Krishnabe4b97b2015-07-15 12:19:43 -07001004 splitOutput = output.splitlines()
Devin Lim58046fa2017-07-05 16:55:00 -07001005 main.apps = ""
Jon Hall714eeba2015-09-29 17:53:10 -07001006 for i in range( len( splitOutput ) ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001007 if re.match( "OCN", splitOutput[ i ] ):
1008 mnNode = splitOutput[ i ].split( "=" )
1009 main.mnIP = mnNode[ 1 ]
Jon Hall714eeba2015-09-29 17:53:10 -07001010 # cell already sorts OC variables in bash, so no need to
1011 # sort in TestON
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001012 elif re.match( "OC[1-9]", splitOutput[ i ] ):
1013 onosNodes = splitOutput[ i ].split( "=" )
1014 main.ONOSip.append( onosNodes[ 1 ] )
1015 elif re.match( "ONOS_APPS", splitOutput[ i ] ):
1016 main.apps = ( splitOutput[ i ].split( "=" ) )[ 1 ]
Jon Hall714eeba2015-09-29 17:53:10 -07001017 else:
Hari Krishna03f530e2015-07-10 17:28:27 -07001018 main.onoscell = main.FALSE
1019
Jon Hall714eeba2015-09-29 17:53:10 -07001020def verifyTestScript( options ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001021 '''
adminbae64d82013-08-01 10:50:15 -07001022 Verifyies test script.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001023 '''
Jon Halld61331b2015-02-17 16:35:47 -08001024 main.openspeak = openspeak.OpenSpeak()
Jon Hall53c5e662016-04-13 16:06:56 -07001025 directory = main.testDir + "/" + main.TEST
1026 if os.path.exists( directory ):
1027 pass
1028 else:
1029 directory = ""
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001030 for root, dirs, files in os.walk( main.testDir, topdown=True ):
Jon Hall53c5e662016-04-13 16:06:56 -07001031 if not directory:
1032 for name in dirs:
1033 if name == main.TEST:
1034 directory = ( os.path.join( root, name ) )
1035 index = directory.find( "/tests/" ) + 1
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001036 main.classPath = directory[ index: ].replace( '/', '.' ) + "." + main.TEST
Jon Hall53c5e662016-04-13 16:06:56 -07001037 break
1038 openspeakfile = directory + "/" + main.TEST + ".ospk"
Jon Halld74d2952018-03-01 13:26:39 -08001039 main.testDir = directory
Jon Hall53c5e662016-04-13 16:06:56 -07001040 main.testFile = directory + "/" + main.TEST + ".py"
Jon Hall714eeba2015-09-29 17:53:10 -07001041 if os.path.exists( openspeakfile ):
Jon Hall44506242015-07-29 17:40:26 -07001042 # Openspeak file found, compiling to python
Jon Hall714eeba2015-09-29 17:53:10 -07001043 main.openspeak.compiler( openspeakfile=openspeakfile, writetofile=1 )
Jon Hall53c5e662016-04-13 16:06:56 -07001044 elif os.path.exists( main.testFile ):
Jon Hall44506242015-07-29 17:40:26 -07001045 # No openspeak found, using python file instead
1046 pass
adminbae64d82013-08-01 10:50:15 -07001047 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001048 print "\nThere is no \"" + main.TEST + "\" test script.\nPlease provide a " + \
1049 "Python or OpenSpeak test script in the tests folder: " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001050 main.testDir + "/" + main.TEST + "/"
adminbae64d82013-08-01 10:50:15 -07001051 __builtin__.testthread = None
1052 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -07001053 try:
1054 testModule = __import__( main.classPath,
1055 globals(),
1056 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001057 [ main.TEST ],
Jon Hall714eeba2015-09-29 17:53:10 -07001058 -1 )
Jon Hall1306a562015-09-04 11:21:24 -07001059 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001060 print "There was an import error, it might mean that there is " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001061 "no test named " + main.TEST
Jon Halld61331b2015-02-17 16:35:47 -08001062 main.exit()
adminbae64d82013-08-01 10:50:15 -07001063
Jon Hall714eeba2015-09-29 17:53:10 -07001064 testClass = getattr( testModule, main.TEST )
adminbae64d82013-08-01 10:50:15 -07001065 main.testObject = testClass()
1066 load_parser()
Jon Halld74d2952018-03-01 13:26:39 -08001067 main.paramsFile = main.TEST + ".params" if options.paramsFile is None else options.paramsFile
1068 main.topoFile = main.TEST + ".topo" if options.topoFile is None else options.topoFile
1069 main.params = main.parser.parseFile( main.testDir + "/" + main.paramsFile )
1070 main.topology = main.parser.parseFile( main.testDir + "/" + main.topoFile )
kelvin-onlabf70fd542015-05-07 18:41:40 -07001071
YPZhang1c89e762016-06-29 10:43:58 -07001072def verifyParams( options ):
Jon Hall714eeba2015-09-29 17:53:10 -07001073 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001074 main.params = main.params[ 'PARAMS' ]
Jon Hall1306a562015-09-04 11:21:24 -07001075 except KeyError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001076 print "Error with the params file: Either the file not specified " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001077 "or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -08001078 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -07001079 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001080 main.topology = main.topology[ 'TOPOLOGY' ]
Jon Hall1306a562015-09-04 11:21:24 -07001081 except KeyError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001082 print "Error with the Topology file: Either the file not specified " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001083 "or the format is not correct"
adminbae64d82013-08-01 10:50:15 -07001084 main.exit()
YPZhang1c89e762016-06-29 10:43:58 -07001085 # Overwrite existing params variables if they are specified from command line
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001086 if len( options.params ) > 0:
YPZhang1c89e762016-06-29 10:43:58 -07001087 # Some params variables are specified from command line
1088 for param in options.params:
1089 if not re.search( ".=.", param ):
1090 print( "Error when parsing params: params should follow key=value format" )
1091 continue
Jon Hall7c4f4302016-07-15 14:39:02 -07001092 # Split the param string to catch nested keys and the value
YPZhang1c89e762016-06-29 10:43:58 -07001093 [ keys, value ] = param.split( "=" )
1094 # Split the nested keys according to its hierarchy
1095 keyList = keys.split( "/" )
1096 # Get the outermost dictionary
1097 paramDict = main.params
1098 # Get the innermost dictionary
1099 try:
1100 while len( keyList ) > 1:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001101 key = keyList.pop( 0 )
YPZhang1c89e762016-06-29 10:43:58 -07001102 assert isinstance( paramDict[ key ], dict )
1103 paramDict = paramDict[ key ]
1104 except KeyError:
1105 print( "Error when parsing params: key \"" + key + "\" not found in main.params" )
1106 main.exit()
1107 except AssertionError:
1108 print( "Error when parsing params: \"" + key + "\" is already the innermost level in main.params" )
1109 main.exit()
1110 # Change the value
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001111 if keyList[ 0 ] not in paramDict:
1112 print( "Error when parsing params: key \"" + keyList[ 0 ] + "\" not found in main.params" )
YPZhang1c89e762016-06-29 10:43:58 -07001113 main.exit()
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001114 elif isinstance( paramDict[ keyList[ 0 ] ], dict ):
1115 print( "Error when parsing params: more levels under key \"" + keyList[ 0 ] + "\" in main.params" )
YPZhang1c89e762016-06-29 10:43:58 -07001116 main.exit()
1117 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001118 paramDict[ keyList[ 0 ] ] = value
kelvin-onlabf70fd542015-05-07 18:41:40 -07001119
Jon Hall714eeba2015-09-29 17:53:10 -07001120def load_parser():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001121 '''
adminbae64d82013-08-01 10:50:15 -07001122 It facilitates the loading customised parser for topology and params file.
1123 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -07001124 It also loads default xmlparser if no parser have specified in teston.cfg
1125 file.
adminbae64d82013-08-01 10:50:15 -07001126
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001127 '''
adminbae64d82013-08-01 10:50:15 -07001128 confighash = main.configDict
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001129 if 'file' in confighash[ 'config' ][ 'parser' ] and\
1130 'class' in confighash[ 'config' ][ 'parser' ]:
1131 path = confighash[ 'config' ][ 'parser' ][ 'file' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001132 if path is not None or\
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001133 confighash[ 'config' ][ 'parser' ][ 'class' ] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001134 try:
1135 module = re.sub( r".py\s*$", "", path )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001136 moduleList = module.split( "/" )
1137 newModule = ".".join( moduleList[ -2: ] )
1138 parsingClass = confighash[ 'config' ][ 'parser' ][ 'class' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001139 parsingModule = __import__( newModule,
1140 globals(),
1141 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001142 [ parsingClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001143 -1 )
1144 parsingClass = getattr( parsingModule, parsingClass )
Jon Hall44506242015-07-29 17:40:26 -07001145 main.parser = parsingClass()
Jon Halld74d2952018-03-01 13:26:39 -08001146 if hasattr( main.parser, "parseFile" ) and\
Jon Hall714eeba2015-09-29 17:53:10 -07001147 hasattr( main.parser, "parse" ):
Jon Hall44506242015-07-29 17:40:26 -07001148 pass
1149 else:
1150 print "Invalid parser format"
adminbae64d82013-08-01 10:50:15 -07001151 main.exit()
Jon Hall44506242015-07-29 17:40:26 -07001152 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001153 print "Could not find the file " + path + \
Jon Hall714eeba2015-09-29 17:53:10 -07001154 " using default parser."
Jon Halld61331b2015-02-17 16:35:47 -08001155 load_defaultParser()
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001156 elif confighash[ 'config' ][ 'parser' ][ 'file' ] is None or\
1157 confighash[ 'config' ][ 'parser' ][ 'class' ] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001158 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -07001159 else:
1160 load_defaultParser()
1161
1162def load_defaultParser():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001163 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001164 It will load the default parser which is xml parser to parse the params and
1165 topology file.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001166 '''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001167 moduleList = main.parserPath.split( "/" )
1168 newModule = ".".join( moduleList[ -2: ] )
Jon Hall714eeba2015-09-29 17:53:10 -07001169 try:
Jon Halld61331b2015-02-17 16:35:47 -08001170 parsingClass = main.parsingClass
Jon Hall714eeba2015-09-29 17:53:10 -07001171 parsingModule = __import__( newModule,
1172 globals(),
1173 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001174 [ parsingClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001175 -1 )
1176 parsingClass = getattr( parsingModule, parsingClass )
adminbae64d82013-08-01 10:50:15 -07001177 main.parser = parsingClass()
Jon Halld74d2952018-03-01 13:26:39 -08001178 if hasattr( main.parser, "parseFile" ) and\
Jon Hall714eeba2015-09-29 17:53:10 -07001179 hasattr( main.parser, "parse" ):
adminbae64d82013-08-01 10:50:15 -07001180 pass
1181 else:
1182 main.exit()
adminbae64d82013-08-01 10:50:15 -07001183 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001184 print sys.exc_info()[ 1 ]
adminbae64d82013-08-01 10:50:15 -07001185
Jon Hall714eeba2015-09-29 17:53:10 -07001186def load_logger():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001187 '''
adminbae64d82013-08-01 10:50:15 -07001188 It facilitates the loading customised parser for topology and params file.
1189 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -07001190 It also loads default xmlparser if no parser have specified in teston.cfg
1191 file.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001192 '''
adminbae64d82013-08-01 10:50:15 -07001193 confighash = main.configDict
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001194 if 'file' in confighash[ 'config' ][ 'logger' ] and\
1195 'class' in confighash[ 'config' ][ 'logger' ]:
1196 path = confighash[ 'config' ][ 'logger' ][ 'file' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001197 if path is not None or\
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001198 confighash[ 'config' ][ 'logger' ][ 'class' ] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001199 try:
1200 module = re.sub( r".py\s*$", "", path )
Jon Hall714eeba2015-09-29 17:53:10 -07001201 moduleList = module.split( "/" )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001202 newModule = ".".join( moduleList[ -2: ] )
1203 loggerClass = confighash[ 'config' ][ 'logger' ][ 'class' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001204 loggerModule = __import__( newModule,
1205 globals(),
1206 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001207 [ loggerClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001208 -1 )
1209 loggerClass = getattr( loggerModule, loggerClass )
Jon Hall44506242015-07-29 17:40:26 -07001210 main.logger = loggerClass()
Jon Hall44506242015-07-29 17:40:26 -07001211 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001212 print "Could not find the file " + path + \
Jon Hall714eeba2015-09-29 17:53:10 -07001213 " using default logger."
adminbae64d82013-08-01 10:50:15 -07001214 load_defaultlogger()
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001215 elif confighash[ 'config' ][ 'parser' ][ 'file' ] is None or\
1216 confighash[ 'config' ][ 'parser' ][ 'class' ] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001217 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -07001218 else:
1219 load_defaultlogger()
1220
1221def load_defaultlogger():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001222 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001223 It will load the default parser which is xml parser to parse the params and
1224 topology file.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001225 '''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001226 moduleList = main.loggerPath.split( "/" )
1227 newModule = ".".join( moduleList[ -2: ] )
Jon Hall714eeba2015-09-29 17:53:10 -07001228 try:
Jon Halld61331b2015-02-17 16:35:47 -08001229 loggerClass = main.loggerClass
Jon Hall714eeba2015-09-29 17:53:10 -07001230 loggerModule = __import__( newModule,
1231 globals(),
1232 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001233 [ loggerClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001234 -1 )
1235 loggerClass = getattr( loggerModule, loggerClass )
adminbae64d82013-08-01 10:50:15 -07001236 main.logger = loggerClass()
1237
1238 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001239 print sys.exc_info()[ 1 ]
Jon Halld61331b2015-02-17 16:35:47 -08001240 main.exit()
adminbae64d82013-08-01 10:50:15 -07001241
Jon Hall714eeba2015-09-29 17:53:10 -07001242def _echo( self ):
adminbae64d82013-08-01 10:50:15 -07001243 print "THIS IS ECHO"