blob: c27388ce18a5949060c330ac6d44bf574b5c1ea4 [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()
Jon Hall4c3d44b2021-10-07 11:23:27 -070077 __builtin__.SkipCase = SkipCase
adminbae64d82013-08-01 10:50:15 -070078 self.TRUE = 1
79 self.FALSE = 0
80 self.ERROR = -1
kelvin-onlabf70fd542015-05-07 18:41:40 -070081 self.NORESULT = 2
adminbae64d82013-08-01 10:50:15 -070082 self.FAIL = False
83 self.PASS = True
kelvin-onlabf70fd542015-05-07 18:41:40 -070084 self.CASERESULT = self.ERROR
85 self.STEPRESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -070086 self.init_result = self.TRUE
87 self.testResult = "Summary"
kelvin-onlabf70fd542015-05-07 18:41:40 -070088 self.stepName = ""
89 self.stepCache = ""
Jon Halld61331b2015-02-17 16:35:47 -080090 self.EXPERIMENTAL_MODE = False
adminbae64d82013-08-01 10:50:15 -070091 self.test_target = None
92 self.lastcommand = None
Jon Halld61331b2015-02-17 16:35:47 -080093 self.testDir = tests_path
Jon Halld74d2952018-03-01 13:26:39 -080094 self.testsRoot = tests_path
Jon Halld61331b2015-02-17 16:35:47 -080095 self.configFile = config_path + "teston.cfg"
adminbae64d82013-08-01 10:50:15 -070096 self.parsingClass = "xmlparser"
97 self.parserPath = core_path + "/xmlparser"
98 self.loggerPath = core_path + "/logger"
99 self.loggerClass = "Logger"
100 self.logs_path = logs_path
101 self.driver = ''
kelvin-onlabfb521662015-02-27 09:52:40 -0800102 self.Thread = Thread
Jon Hall5b586732015-06-11 11:39:39 -0700103 self.cleanupFlag = False
104 self.cleanupLock = threading.Lock()
Jon Hall0fc0d452015-07-14 09:49:58 -0700105 self.initiated = False
Devin Limec989792017-08-15 15:57:55 -0700106 self.executedCase = []
107 self.leftCase = []
108 self.failedCase = []
109 self.noResultCase = []
Jon Hall65844a32015-03-09 19:09:37 -0700110
Jon Hall25079782015-10-13 13:54:39 -0700111 self.config = self.configparser()
Jon Hall714eeba2015-09-29 17:53:10 -0700112 verifyOptions( options )
adminbae64d82013-08-01 10:50:15 -0700113 load_logger()
114 self.componentDictionary = {}
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700115 self.componentDictionary = self.topology[ 'COMPONENT' ]
Jon Hall714eeba2015-09-29 17:53:10 -0700116 self.driversList = []
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700117 if isinstance( self.componentDictionary, str ):
Jon Hall714eeba2015-09-29 17:53:10 -0700118 self.componentDictionary = dict( self.componentDictionary )
Jon Hall65844a32015-03-09 19:09:37 -0700119
Jon Hall714eeba2015-09-29 17:53:10 -0700120 for component in self.componentDictionary:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700121 self.driversList.append( self.componentDictionary[ component ][ 'type' ] )
Jon Hall65844a32015-03-09 19:09:37 -0700122
Jon Hall714eeba2015-09-29 17:53:10 -0700123 self.driversList = list( set( self.driversList ) ) # Removing duplicates.
adminbae64d82013-08-01 10:50:15 -0700124 # Checking the test_target option set for the component or not
Jon Hall714eeba2015-09-29 17:53:10 -0700125 if isinstance( self.componentDictionary, dict ):
adminbae64d82013-08-01 10:50:15 -0700126 for component in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700127 if 'test_target' in self.componentDictionary[ component ].keys():
adminbae64d82013-08-01 10:50:15 -0700128 self.test_target = component
Jon Hall65844a32015-03-09 19:09:37 -0700129
Jon Halld61331b2015-02-17 16:35:47 -0800130 # Checking for the openspeak file and test script
Jon Hall714eeba2015-09-29 17:53:10 -0700131 self.logger.initlog( self )
adminbae64d82013-08-01 10:50:15 -0700132
133 # Creating Drivers Handles
Jon Hall714eeba2015-09-29 17:53:10 -0700134 initString = "\n" + "*" * 30 + "\n CASE INIT \n" + "*" * 30 + "\n"
135 self.log.exact( initString )
adminbae64d82013-08-01 10:50:15 -0700136 self.driverObject = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700137 self.random_order = 111 # Random order id to connect the components
adminbae64d82013-08-01 10:50:15 -0700138 components_connect_order = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700139 if isinstance( self.componentDictionary, dict ):
adminbae64d82013-08-01 10:50:15 -0700140 for component in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700141 if 'connect_order' not in self.componentDictionary[ component ].keys():
142 self.componentDictionary[ component ][ 'connect_order' ] = str( self.get_random() )
143 components_connect_order[ component ] = eval( self.componentDictionary[ component ][ 'connect_order' ] )
Jon Hall714eeba2015-09-29 17:53:10 -0700144 # Ordering components based on the connect order.
145 ordered_component_list = sorted( components_connect_order,
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700146 key=lambda key: components_connect_order[ key ] )
adminbae64d82013-08-01 10:50:15 -0700147 print ordered_component_list
adminbae64d82013-08-01 10:50:15 -0700148 for component in ordered_component_list:
Jon Hall714eeba2015-09-29 17:53:10 -0700149 self.componentInit( component )
adminbae64d82013-08-01 10:50:15 -0700150
Jon Hall714eeba2015-09-29 17:53:10 -0700151 def configparser( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000152 '''
153 It will parse the config file (teston.cfg) and return as dictionary
154 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700155 matchFileName = re.match( r'(.*)\.cfg', self.configFile, re.M | re.I )
adminbae64d82013-08-01 10:50:15 -0700156 if matchFileName:
Jon Hall714eeba2015-09-29 17:53:10 -0700157 xml = open( self.configFile ).read()
158 try:
159 self.configDict = xmldict.xml_to_dict( xml )
adminbae64d82013-08-01 10:50:15 -0700160 return self.configDict
Jon Hall1306a562015-09-04 11:21:24 -0700161 except IOError:
adminbae64d82013-08-01 10:50:15 -0700162 print "There is no such file to parse " + self.configFile
Jon Hall1306a562015-09-04 11:21:24 -0700163 else:
164 print "There is no such file to parse " + self.configFile
kelvin-onlabf70fd542015-05-07 18:41:40 -0700165
Jon Hall714eeba2015-09-29 17:53:10 -0700166 def componentInit( self, component ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000167 '''
adminbae64d82013-08-01 10:50:15 -0700168 This method will initialize specified component
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000169 '''
adminbae64d82013-08-01 10:50:15 -0700170 global driver_options
Jon Hall0fc0d452015-07-14 09:49:58 -0700171 self.initiated = False
Jon Hall3a03cad2021-04-07 11:21:55 -0700172 self.log.info( "Creating component handle: " + component )
Jon Halld61331b2015-02-17 16:35:47 -0800173 driver_options = {}
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700174 if 'COMPONENTS' in self.componentDictionary[ component ].keys():
175 driver_options = dict( self.componentDictionary[ component ][ 'COMPONENTS' ] )
176 driver_options[ 'name' ] = component
177 driverName = self.componentDictionary[ component ][ 'type' ]
178 driver_options[ 'type' ] = driverName
Jon Hall06fd0df2021-01-25 15:50:06 -0800179 driver_home = self.componentDictionary[ component ].get( 'home' )
180 if driver_home:
181 driver_options[ 'home' ] = driver_home
kelvin-onlabf70fd542015-05-07 18:41:40 -0700182
Jon Hall714eeba2015-09-29 17:53:10 -0700183 classPath = self.getDriverPath( driverName.lower() )
184 driverModule = importlib.import_module( classPath )
185 driverClass = getattr( driverModule, driverName )
adminbae64d82013-08-01 10:50:15 -0700186 driverObject = driverClass()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700187
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700188 if "OCN" in self.componentDictionary[ component ][ 'host' ] and\
Jon Hall714eeba2015-09-29 17:53:10 -0700189 main.onoscell:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700190 self.componentDictionary[ component ][ 'host' ] = main.mnIP
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700191
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700192 user_name = self.componentDictionary[ component ].get( 'user', getpass.getuser() )
193 ip_address = self.componentDictionary[ component ].get( 'host', 'localhost' )
194 pwd = self.componentDictionary[ component ].get( 'password', 'changeme' )
195 port = self.componentDictionary[ component ].get( 'port' )
Jon Hall714eeba2015-09-29 17:53:10 -0700196 connect_result = driverObject.connect( user_name=user_name,
197 ip_address=ip_address,
198 pwd=pwd,
199 port=port,
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700200 options=driver_options )
cameron@onlab.us5cc6a372015-05-11 17:18:07 -0700201
adminbae64d82013-08-01 10:50:15 -0700202 if not connect_result:
Jon Hall714eeba2015-09-29 17:53:10 -0700203 self.log.error( "Exiting from the test execution because connecting to the " +
204 component + " component failed." )
Jon Halld61331b2015-02-17 16:35:47 -0800205 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700206
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700207 vars( self )[ component ] = driverObject
Jon Hall0fc0d452015-07-14 09:49:58 -0700208 self.initiated = True
Jon Hallca319892017-06-15 15:25:22 -0700209 return driverObject
kelvin-onlabf70fd542015-05-07 18:41:40 -0700210
Jon Hall714eeba2015-09-29 17:53:10 -0700211 def run( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000212 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700213 The Execution of the test script's cases listed in the Test params
214 file will be done here then update each test case result.
215 This method will return main.TRUE if it executed all the test cases
216 successfully, else will retun main.FALSE
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000217 '''
adminbae64d82013-08-01 10:50:15 -0700218 self.testCaseResult = {}
Jon Halla1185982014-09-15 14:55:10 -0700219 self.TOTAL_TC = 0
adminbae64d82013-08-01 10:50:15 -0700220 self.TOTAL_TC_RUN = 0
Jon Halld61331b2015-02-17 16:35:47 -0800221 self.TOTAL_TC_PLANNED = 0
adminbae64d82013-08-01 10:50:15 -0700222 self.TOTAL_TC_NORESULT = 0
223 self.TOTAL_TC_FAIL = 0
224 self.TOTAL_TC_PASS = 0
Jon Halla1185982014-09-15 14:55:10 -0700225 self.TEST_ITERATION = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700226
227 # NOTE: number of main.step statements in the
228 # outer most level of the test case. used to
229 # execute code in smaller steps
230 self.stepCount = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700231 self.CASERESULT = self.NORESULT
232
Jon Halld61331b2015-02-17 16:35:47 -0800233 import testparser
Jon Hall53c5e662016-04-13 16:06:56 -0700234 test = testparser.TestParser( main.testFile )
adminbae64d82013-08-01 10:50:15 -0700235 self.testscript = test.testscript
236 self.code = test.getStepCode()
Jon Hall714eeba2015-09-29 17:53:10 -0700237 repeat = int( self.params.get( 'repeat', 1 ) )
238 self.TOTAL_TC_PLANNED = len( self.testcases_list ) * repeat
Jon Hall026bd712021-08-31 16:30:09 -0700239 self.log.TAP( "1..%s" % self.TOTAL_TC_PLANNED )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700240
adminbae64d82013-08-01 10:50:15 -0700241 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700242 while repeat:
Devin Limec989792017-08-15 15:57:55 -0700243 self.leftCase.extend( self.testcases_list )
Jon Halla1185982014-09-15 14:55:10 -0700244 for self.CurrentTestCaseNumber in self.testcases_list:
Devin Limec989792017-08-15 15:57:55 -0700245 self.executedCase.append( self.leftCase.pop( 0 ) )
Jon Hall714eeba2015-09-29 17:53:10 -0700246 result = self.runCase( self.CurrentTestCaseNumber )
247 repeat -= 1
adminbae64d82013-08-01 10:50:15 -0700248 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700249
Jon Halle234cc42015-08-31 15:26:47 -0700250 def runCase( self, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700251 self.CurrentTestCaseNumber = testCaseNumber
kelvin-onlabf70fd542015-05-07 18:41:40 -0700252 self.CurrentTestCase = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700253
254 # List of step results in a case. ANDed together to get the result
255 self.stepResultsList = []
kelvin-onlabf70fd542015-05-07 18:41:40 -0700256 self.stepName = ""
Jon Hall783bbf92015-07-23 14:33:19 -0700257 self.caseExplanation = ""
Jon Halla8cf76a2021-10-05 14:31:47 -0700258 self.CASERESULT = self.ERROR
259 self.STEPRESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700260 result = self.TRUE
Jon Hall714eeba2015-09-29 17:53:10 -0700261
262 # NOTE: number of main.step statements in the
263 # outer most level of the test case. used to
264 # execute code in smaller steps
265 self.stepCount = 0
266
267 # NOTE: This is the current number of main.step()'s executed
268 # in a case. Used for logging.
269 self.stepNumber = 0
adminbae64d82013-08-01 10:50:15 -0700270 self.EXPERIMENTAL_MODE = self.FALSE
271 self.addCaseHeader()
Devin Limec989792017-08-15 15:57:55 -0700272 self.log.debug( "Case Executed : " + str( self.executedCase ) )
273 self.log.debug( "Case to be executed : " + str( self.leftCase ) )
Jon Halle234cc42015-08-31 15:26:47 -0700274 self.testCaseNumber = str( testCaseNumber )
275 self.CASERESULT = self.NORESULT
adminbae64d82013-08-01 10:50:15 -0700276 stopped = False
Jon Hall5a72b712015-09-28 12:20:59 -0700277 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700278 self.code[ self.testCaseNumber ]
Jon Halld61331b2015-02-17 16:35:47 -0800279 except KeyError:
Jon Halle234cc42015-08-31 15:26:47 -0700280 self.log.error( "There is no Test-Case " + self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800281 return self.FALSE
adminbae64d82013-08-01 10:50:15 -0700282 self.stepCount = 0
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700283 while self.stepCount < len( self.code[ self.testCaseNumber ].keys() ):
Jon Hall714eeba2015-09-29 17:53:10 -0700284 result = self.runStep( self.code, self.testCaseNumber )
Jon Hallfebb1c72015-03-05 13:30:09 -0800285 if result == self.FALSE:
adminbae64d82013-08-01 10:50:15 -0700286 break
Jon Hallfebb1c72015-03-05 13:30:09 -0800287 elif result == self.TRUE:
adminbae64d82013-08-01 10:50:15 -0700288 continue
Jon Hall5a72b712015-09-28 12:20:59 -0700289 # stepResults format: ( stepNo[], stepName[], stepResult[], onFail[] )
290 stepResults = self.stepResultsList
Jon Halle234cc42015-08-31 15:26:47 -0700291 if not stopped:
292 if self.CASERESULT == self.TRUE or self.CASERESULT == self.FALSE:
Jon Hall714eeba2015-09-29 17:53:10 -0700293 # Result was already explitily set somewhere else like
294 # in skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700295 pass
Jon Hall5a72b712015-09-28 12:20:59 -0700296 elif all( self.TRUE == i for i in stepResults ):
kelvin-onlabf70fd542015-05-07 18:41:40 -0700297 # ALL PASSED
298 self.CASERESULT = self.TRUE
Jon Hall5a72b712015-09-28 12:20:59 -0700299 elif self.FALSE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700300 # AT LEAST ONE FAILED
301 self.CASERESULT = self.FALSE
Jon Hall5a72b712015-09-28 12:20:59 -0700302 elif self.TRUE in stepResults:
kelvin-onlabf70fd542015-05-07 18:41:40 -0700303 # AT LEAST ONE PASSED
304 self.CASERESULT = self.TRUE
305 else:
306 self.CASERESULT = self.NORESULT
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700307 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = self.CASERESULT
Devin Limec989792017-08-15 15:57:55 -0700308 self.organizeResult( self.CurrentTestCaseNumber, self.CASERESULT )
Jon Hall714eeba2015-09-29 17:53:10 -0700309 self.logger.updateCaseResults( self )
Jon Hall783bbf92015-07-23 14:33:19 -0700310 self.log.summary( self.caseExplanation )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700311 self.log.summary( self.stepCache )
Jon Hall026bd712021-08-31 16:30:09 -0700312 self.caseResultsWiki()
313 self.caseResultsTAP()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700314 self.stepCache = ""
adminbae64d82013-08-01 10:50:15 -0700315 return result
kelvin-onlabf70fd542015-05-07 18:41:40 -0700316
Jon Hall026bd712021-08-31 16:30:09 -0700317 def caseResultsWiki( self ):
318 """
319 Add case results to the wiki results file
320 """
321 self.log.wiki( "<p>" + self.caseExplanation + "</p>" )
322 self.log.wiki( "<ul>" )
323 subcaseMessage = False
324 for line in self.stepCache.splitlines():
325 if re.search( "[0-9]\.[0-9]", line ): # Step
326 if subcaseMessage: # End of Failure Message Printout
327 self.log.wiki( "</ul>\n" )
328 subcaseMessage = False
329 if re.search( " - PASS$", line ):
330 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
331 elif re.search( " - FAIL$", line ):
332 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
333 elif re.search( " - No Result$", line ):
334 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
335 else: # Substep
336 if not subcaseMessage: # Open Failure Message Printout
337 self.log.wiki( "<ul><li>" + line + "</li>\n" )
338 subcaseMessage = True
339 else: # Add to Failure Message Printout
340 self.log.wiki( "<li>" + line + "</li>\n" )
341 if subcaseMessage: # End of Failure Message Printout for last item
342 self.log.wiki( "</ul>\n" )
343 self.log.wiki( "</ul>" )
344
345 def caseResultsTAP( self ):
346 """
347 Add case results to the TAP results file
348 """
Jon Hall026bd712021-08-31 16:30:09 -0700349 main.log.debug( self.stepCache )
Jon Hall026bd712021-08-31 16:30:09 -0700350 steps = 0
351 stepLines = []
352 for line in self.stepCache.splitlines():
Jon Hall026bd712021-08-31 16:30:09 -0700353 if re.search( "[0-9]\.[0-9]", line ): # Step
Jon Hall026bd712021-08-31 16:30:09 -0700354 if re.search( " - PASS$", line ):
355 steps += 1
Jon Halla8cf76a2021-10-05 14:31:47 -0700356 stepLines.append( " ok - STEP %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700357 elif re.search( " - FAIL$", line ):
358 steps += 1
Jon Halla8cf76a2021-10-05 14:31:47 -0700359 stepLines.append( " not ok - STEP %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700360 elif re.search( " - No Result$", line ):
361 steps += 1
Jon Halla8cf76a2021-10-05 14:31:47 -0700362 stepLines.append( " ok - STEP %s # TODO: No assertion in test step" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700363 else: # Substep
Jon Halla8cf76a2021-10-05 14:31:47 -0700364 stepLines.append( " # %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700365 if steps > 0:
366 self.log.TAP( " 1..%s" % steps )
Jon Halla8cf76a2021-10-05 14:31:47 -0700367 for line in stepLines:
368 self.log.TAP( line )
Jon Hall026bd712021-08-31 16:30:09 -0700369
370
Devin Limec989792017-08-15 15:57:55 -0700371 def organizeResult( self, caseNum, result ):
372 """
373 Organize the result and put the current number into either
374 failed/noResult lists.
375 * caseNum - number of the case
376 * result - result of the case
377 """
378 if result == main.FALSE:
379 self.failedCase.append( caseNum )
380 elif result == self.NORESULT:
381 self.noResultCase.append( caseNum )
382
Jon Hall714eeba2015-09-29 17:53:10 -0700383 def runStep( self, code, testCaseNumber ):
adminbae64d82013-08-01 10:50:15 -0700384 if not cli.pause:
Jon Hall5a72b712015-09-28 12:20:59 -0700385 try:
386 step = self.stepCount
387 # stepResults format: ( stepNo, stepName, stepResult, onFail )
388 # NOTE: This is needed to catch results of main.step()'s
389 # called inside functions or loops
390 self.stepResults = ( [], [], [], [] )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700391 exec code[ testCaseNumber ][ step ] in module.__dict__
adminbae64d82013-08-01 10:50:15 -0700392 self.stepCount = self.stepCount + 1
Jon Hall96b816f2015-11-03 12:00:56 -0800393 self.parseStepResults( testCaseNumber )
Jon Hallca319892017-06-15 15:25:22 -0700394 except SkipCase: # Raised in self.skipCase()
Jon Halle234cc42015-08-31 15:26:47 -0700395 self.log.warn( "Skipping the rest of CASE" +
396 str( testCaseNumber ) )
Jon Hall96b816f2015-11-03 12:00:56 -0800397 self.parseStepResults( testCaseNumber )
Jon Hall714eeba2015-09-29 17:53:10 -0700398 self.stepResultsList.append( self.STEPRESULT )
Jon Halle234cc42015-08-31 15:26:47 -0700399 self.stepCache += "\t\t" + self.onFailMsg + "\n"
400 self.stepCount = self.stepCount + 1
401 return self.FALSE
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000402 except StandardError as e:
Jon Hallc1606352015-10-06 14:51:36 -0700403 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700404 stepNo = self.stepResults[ 0 ][ self.stepNumber - 1 ]
Jon Hallc1606352015-10-06 14:51:36 -0700405 except IndexError:
406 stepNo = "<IndexError>"
407 main.log.warn( "Error trying to get step number. " +
408 "It is likely between step " +
Jon Hall6e709752016-02-01 13:38:46 -0800409 str( self.stepNumber ) + " and step " +
Jon Hallc1606352015-10-06 14:51:36 -0700410 str( self.stepNumber + 1 ) )
411 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700412 stepName = self.stepResults[ 1 ][ self.stepNumber - 1 ]
Jon Hallc1606352015-10-06 14:51:36 -0700413 except IndexError:
414 stepName = "<IndexError>"
415 self.log.error( "\nException in the following section of" +
416 " code: " + str( testCaseNumber ) + "." +
417 str( stepNo ) + ": " + stepName )
Jeremyd9e4eb12016-04-13 12:09:06 -0700418 self.log.error( str( e.__class__ ) + str( e.message ) )
Jon Halld14a5002021-03-30 16:45:30 -0700419 self.log.exception( "" )
adminbae64d82013-08-01 10:50:15 -0700420 self.stepCount = self.stepCount + 1
Jon Hall714eeba2015-09-29 17:53:10 -0700421 self.logger.updateCaseResults( self )
Jon Hall026bd712021-08-31 16:30:09 -0700422 self.stepResultsWiki()
423 self.stepResultsTAP()
Jon Hall714eeba2015-09-29 17:53:10 -0700424 # summary results
kelvin-onlabf70fd542015-05-07 18:41:40 -0700425 self.log.summary( self.stepCache )
426 self.stepCache = ""
shahshreya957feaa2015-03-23 16:08:29 -0700427 self.cleanup()
Jon Hall00539b12015-04-03 13:55:46 -0700428 self.exit()
Jon Halle234cc42015-08-31 15:26:47 -0700429 return self.TRUE
adminbae64d82013-08-01 10:50:15 -0700430 if cli.stop:
431 cli.stop = False
adminbae64d82013-08-01 10:50:15 -0700432 self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700433 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = "Stopped"
Jon Hall714eeba2015-09-29 17:53:10 -0700434 self.logger.updateCaseResults( self )
adminbae64d82013-08-01 10:50:15 -0700435 result = self.cleanup()
Jon Halle234cc42015-08-31 15:26:47 -0700436 return self.FALSE
437
Jon Hall026bd712021-08-31 16:30:09 -0700438 def stepResultsWiki( self ):
439 """
440 Add step results to the wiki file
441 """
442 # WIKI results
443 self.log.wiki( "<ul>" )
444 for line in self.stepCache.splitlines():
445 if re.search( " - PASS$", line ):
446 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"tick\" /></li>\n" )
447 elif re.search( " - FAIL$", line ):
448 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"cross\" /></li>\n" )
449 elif re.search( " - No Result$", line ):
450 self.log.wiki( "<li>" + line + " <ac:emoticon ac:name=\"warning\" /></li>\n" )
451 else: # Should only be on fail message
452 self.log.wiki( "<ul><li>" + line + "</li></ul>\n" )
453 self.log.wiki( "</ul>" )
454
455 def stepResultsTAP( self ):
456 """
457 Add step results to the TAP file
458 """
459 # TAP results
460 # TODO Do we need indetation for the steps?
461 main.log.debug( "StepResultsTAP" )
462 for line in self.stepCache.splitlines():
463 if re.search( " - PASS$", line ):
Jon Halla8cf76a2021-10-05 14:31:47 -0700464 self.log.TAP( " ok - STEP %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700465 elif re.search( " - FAIL$", line ):
Jon Halla8cf76a2021-10-05 14:31:47 -0700466 self.log.TAP( " not ok - STEP %s" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700467 elif re.search( " - No Result$", line ):
Jon Halla8cf76a2021-10-05 14:31:47 -0700468 self.log.TAP( " ok - STEP %s # TODO: No assertion in test step" % line )
Jon Hall026bd712021-08-31 16:30:09 -0700469 else: # Should only be on fail message
470 self.log.TAP( " # %s" % line )
471
Jon Hall96b816f2015-11-03 12:00:56 -0800472 def parseStepResults( self, testCaseNumber ):
473 """
474 Parse throught the step results for the wiki
475 """
476 try:
477 # Iterate through each of the steps and print them
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700478 for index in range( len( self.stepResults[ 0 ] ) ):
Jon Hall96b816f2015-11-03 12:00:56 -0800479 # stepResults = ( stepNo, stepName, stepResult, onFail )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700480 stepNo = self.stepResults[ 0 ][ index ]
481 stepName = self.stepResults[ 1 ][ index ]
482 stepResult = self.stepResults[ 2 ][ index ]
483 onFail = self.stepResults[ 3 ][ index ]
Jon Hall96b816f2015-11-03 12:00:56 -0800484 self.stepCache += "\t" + str( testCaseNumber ) + "."
485 self.stepCache += str( stepNo ) + " "
486 self.stepCache += stepName + " - "
487 if stepResult == self.TRUE:
488 self.stepCache += "PASS\n"
489 elif stepResult == self.FALSE:
490 self.stepCache += "FAIL\n"
491 self.stepCache += "\t\t" + onFail + "\n"
492 else:
493 self.stepCache += "No Result\n"
494 self.stepResultsList.append( stepResult )
495 except Exception:
496 self.log.exception( "Error parsing step results" )
497
Jon Halla8cf76a2021-10-05 14:31:47 -0700498 def skipCase( self, result="NORESULT", msg=None ):
Jon Halle234cc42015-08-31 15:26:47 -0700499 """
500 Will skip the rest of the code in a test case. The case results will be
501 determined as normal based on completed assertions unless the result
502 argument is given.
503
504 Optional Arguments:
Jon Hall7c4f4302016-07-15 14:39:02 -0700505 result: Case insensitive string. Can be 'PASS' or 'FAIL' and will set
Jon Halle234cc42015-08-31 15:26:47 -0700506 the case result accordingly.
507 msg: Message to be printed when the case is skipped in the reports.
508 """
509 result = result.upper().strip()
510 if result == "PASS":
511 self.CASERESULT = self.TRUE
Jon Halla8cf76a2021-10-05 14:31:47 -0700512 elif result == "NORESULT":
513 self.CASERESULT = self.NORESULT
514 else:
Jon Halle234cc42015-08-31 15:26:47 -0700515 self.CASERESULT = self.FALSE
516 self.onFailMsg = "Skipping the rest of this case. "
517 if msg:
518 self.onFailMsg += str( msg )
Jon Hallca319892017-06-15 15:25:22 -0700519 raise SkipCase
kelvin-onlabf70fd542015-05-07 18:41:40 -0700520
Jon Hall714eeba2015-09-29 17:53:10 -0700521 def addCaseHeader( self ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700522 caseHeader = "\n" + "*" * 30 + "\n Result summary for Testcase" + \
Jon Hall714eeba2015-09-29 17:53:10 -0700523 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 30 + "\n"
524 self.log.exact( caseHeader )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700525 caseHeader = "\n" + "*" * 40 + "\nStart of Test Case" + \
Jon Hall714eeba2015-09-29 17:53:10 -0700526 str( self.CurrentTestCaseNumber ) + " : "
adminbae64d82013-08-01 10:50:15 -0700527 for driver in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700528 vars( self )[ driver + 'log' ].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700529
Jon Hall714eeba2015-09-29 17:53:10 -0700530 def addCaseFooter( self ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700531 stepNo = self.stepResults[ 0 ][ -2 ]
Jon Hall714eeba2015-09-29 17:53:10 -0700532 if stepNo > 0:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700533 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." + \
Jon Hall714eeba2015-09-29 17:53:10 -0700534 str( stepNo ) + ": " + str( self.stepName )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700535 stepHeader = "\n" + "*" * 40 + "\nEnd of Step " + previousStep + \
Jon Hall714eeba2015-09-29 17:53:10 -0700536 "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700537
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700538 caseFooter = "\n" + "*" * 40 + "\nEnd of Test case " + \
Jon Hall714eeba2015-09-29 17:53:10 -0700539 str( self.CurrentTestCaseNumber ) + "\n" + "*" * 40 + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700540
adminbae64d82013-08-01 10:50:15 -0700541 for driver in self.driversList:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700542 vars( self )[ driver ].write( stepHeader + "\n" + caseFooter )
adminbae64d82013-08-01 10:50:15 -0700543
Devin Limba37cdd2018-05-07 11:41:05 -0700544 def setCheckingPoint( self ):
545 '''
546 Using when running findPatchScript.sh. This function needs to be placed
547 on the point that has the problem.
548
549 For example, if you see unusual behavior or from the portion of the code,
550 this is where you need to put with the conditional statement.
551 If some of the latency result is much greater than usual, have if statement
552 that checks if the result is greater than some point and include this function.
553
554 This will mark the 0 to findPatchResult.txt in /tmp/ and exit the test.
555 Then from findPatchScript, it will move onto the next commit and re-run the
556 test.
557 '''
558 self.log.error( "Reached to the checking point. Will mark the result and exit the test" )
559 resultFile = open( "/tmp/findPatchResult.txt", "w" )
560 resultFile.write( "0" )
561 resultFile.close()
562 self.cleanAndExit()
563
Jon Hall714eeba2015-09-29 17:53:10 -0700564 def cleanup( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000565 '''
Jon Hall5b586732015-06-11 11:39:39 -0700566 Print a summary of the current test's results then attempt to release
567 all the component handles and the close opened file handles.
adminbae64d82013-08-01 10:50:15 -0700568
Jon Hall5b586732015-06-11 11:39:39 -0700569 This function shouldbe threadsafe such that cleanup will only be
570 executed once per test.
571
572 This will return TRUE if all the component handles and log handles
573 closed properly, else return FALSE.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000574 '''
adminbae64d82013-08-01 10:50:15 -0700575 result = self.TRUE
Jon Hall5b586732015-06-11 11:39:39 -0700576 lock = self.cleanupLock
577 if lock.acquire( False ):
578 try:
579 if self.cleanupFlag is False: # First thread to run this
580 self.cleanupFlag = True
Jon Hall0fc0d452015-07-14 09:49:58 -0700581 if self.initiated:
Jon Hall714eeba2015-09-29 17:53:10 -0700582 self.logger.testSummary( self )
Jon Hall892818c2015-10-20 17:58:34 -0700583 components = self.componentDictionary
584 for component in sorted( components,
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700585 key=lambda item: components[ item ][ 'connect_order' ],
Jon Hall892818c2015-10-20 17:58:34 -0700586 reverse=True ):
Jon Hall714eeba2015-09-29 17:53:10 -0700587 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700588 tempObject = vars( self )[ component ]
589 print "Disconnecting from " + str( tempObject.name ) + \
590 ": " + str( tempObject.__class__ )
Jon Hall5b586732015-06-11 11:39:39 -0700591 tempObject.disconnect()
Jon Hall1306a562015-09-04 11:21:24 -0700592 except KeyboardInterrupt:
593 pass
594 except KeyError:
595 # Component not created yet
596 self.log.warn( "Could not find the component " +
597 str( component ) )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000598 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700599 self.log.exception( "Exception while disconnecting from " +
600 str( component ) )
601 result = self.FALSE
602 # Closing all the driver's session files
603 for driver in self.componentDictionary.keys():
604 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700605 vars( self )[ driver ].close_log_handles()
Jon Hall1306a562015-09-04 11:21:24 -0700606 except KeyboardInterrupt:
607 pass
608 except KeyError:
609 # Component not created yet
610 self.log.warn( "Could not find the component " +
611 str( driver ) + " while trying to" +
612 " close log file" )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000613 except StandardError:
Jon Hall5b586732015-06-11 11:39:39 -0700614 self.log.exception( "Exception while closing log files for " +
615 str( driver ) )
616 result = self.FALSE
617 else:
618 pass # Someone else already ran through this function
619 finally:
620 lock.release()
621 else: # Someone already has a lock
622 # NOTE: This could cause problems if we don't release the lock
623 # correctly
624 lock.acquire() # Wait for the other thread to finish
625 # NOTE: If we don't wait, exit could be called while the thread
626 # with the lock is still cleaning up
627 lock.release()
adminbae64d82013-08-01 10:50:15 -0700628 return result
Jon Halld61331b2015-02-17 16:35:47 -0800629
Jon Hall714eeba2015-09-29 17:53:10 -0700630 def pause( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000631 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700632 This function will pause the test's execution, and will continue after
633 user provide 'resume' command.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000634 '''
adminbae64d82013-08-01 10:50:15 -0700635 __builtin__.testthread.pause()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700636
Jon Hall714eeba2015-09-29 17:53:10 -0700637 def onfail( self, *components ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000638 '''
kelvin-onlabf70fd542015-05-07 18:41:40 -0700639 When test step failed, calling all the components onfail.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000640 '''
adminbae64d82013-08-01 10:50:15 -0700641 if not components:
Jon Hall714eeba2015-09-29 17:53:10 -0700642 try:
adminbae64d82013-08-01 10:50:15 -0700643 for component in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700644 tempObject = vars( self )[ component ]
adminbae64d82013-08-01 10:50:15 -0700645 result = tempObject.onfail()
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000646 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700647 print str( e )
adminbae64d82013-08-01 10:50:15 -0700648 result = self.FALSE
adminbae64d82013-08-01 10:50:15 -0700649 else:
Jon Hall714eeba2015-09-29 17:53:10 -0700650 try:
adminbae64d82013-08-01 10:50:15 -0700651 for component in components:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700652 tempObject = vars( self )[ component ]
adminbae64d82013-08-01 10:50:15 -0700653 result = tempObject.onfail()
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000654 except StandardError as e:
Jon Hall714eeba2015-09-29 17:53:10 -0700655 print str( e )
adminbae64d82013-08-01 10:50:15 -0700656 result = self.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700657
Jon Hall714eeba2015-09-29 17:53:10 -0700658 def getDriverPath( self, driverName ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000659 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700660 Based on the component 'type' specified in the params , this method
661 will find the absolute path, by recursively searching the name of
662 the component.
663
664 NOTE: This function requires the linux 'find' command.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000665 '''
adminbae64d82013-08-01 10:50:15 -0700666 import commands
667
Jon Hall714eeba2015-09-29 17:53:10 -0700668 cmd = "find " + drivers_path + " -name " + driverName + ".py"
669 result = commands.getoutput( cmd )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700670
Jon Hall714eeba2015-09-29 17:53:10 -0700671 result_array = str( result ).split( '\n' )
adminbae64d82013-08-01 10:50:15 -0700672 result_count = 0
kelvin-onlabf70fd542015-05-07 18:41:40 -0700673
adminbae64d82013-08-01 10:50:15 -0700674 for drivers_list in result_array:
Jon Hall714eeba2015-09-29 17:53:10 -0700675 result_count = result_count + 1
676 if result_count > 1:
677 print "Found " + driverName + " " + str( result_count ) + " times:"
678 print str( result_array )
adminbae64d82013-08-01 10:50:15 -0700679 self.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700680
Jon Hall714eeba2015-09-29 17:53:10 -0700681 result = re.sub( "(.*)drivers", "", result )
682 result = re.sub( "\/\/", "/", result )
683 result = re.sub( "\.py", "", result )
684 result = re.sub( "\.pyc", "", result )
685 result = re.sub( "\/", ".", result )
686 result = "drivers" + result
adminbae64d82013-08-01 10:50:15 -0700687 return result
adminbae64d82013-08-01 10:50:15 -0700688
Jon Hall714eeba2015-09-29 17:53:10 -0700689 def step( self, stepDesc ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000690 '''
adminbae64d82013-08-01 10:50:15 -0700691 The step information of the test-case will append to the logs.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000692 '''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700693 previousStep = " " + str( self.CurrentTestCaseNumber ) + "." + \
Jon Hall714eeba2015-09-29 17:53:10 -0700694 str( self.stepNumber ) + ": " + str( self.stepName )
adminbae64d82013-08-01 10:50:15 -0700695 self.stepName = stepDesc
Jon Hall5a72b712015-09-28 12:20:59 -0700696 self.stepNumber += 1
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700697 self.stepResults[ 0 ].append( self.stepNumber )
698 self.stepResults[ 1 ].append( stepDesc )
699 self.stepResults[ 2 ].append( self.NORESULT )
700 self.stepResults[ 3 ].append( "No on fail message given" )
adminbae64d82013-08-01 10:50:15 -0700701
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700702 stepName = " " + str( self.CurrentTestCaseNumber ) + "." + \
Jon Hall714eeba2015-09-29 17:53:10 -0700703 str( self.stepNumber ) + ": " + str( stepDesc )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700704 self.log.step( stepName )
adminbae64d82013-08-01 10:50:15 -0700705 stepHeader = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700706 line = "\n" + "-" * 45 + "\n"
707 if self.stepNumber > 1:
708 stepHeader = line + "End of Step " + previousStep + line
709 stepHeader += line + "Start of Step" + stepName + line
adminbae64d82013-08-01 10:50:15 -0700710 for driver in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700711 vars( self )[ driver + 'log' ].info( stepHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700712
Jon Hall714eeba2015-09-29 17:53:10 -0700713 def case( self, testCaseName ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000714 '''
adminbae64d82013-08-01 10:50:15 -0700715 Test's each test-case information will append to the logs.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000716 '''
Jon Halld61331b2015-02-17 16:35:47 -0800717 self.CurrentTestCase = testCaseName
Jon Hall714eeba2015-09-29 17:53:10 -0700718 testCaseName = " " + str( testCaseName )
719 self.log.case( testCaseName )
720 caseHeader = testCaseName + "\n" + "*" * 40 + "\n"
adminbae64d82013-08-01 10:50:15 -0700721 for driver in self.componentDictionary.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700722 vars( self )[ driver + 'log' ].info( caseHeader )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700723
Jon Hall714eeba2015-09-29 17:53:10 -0700724 def testDesc( self, description ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000725 '''
adminbae64d82013-08-01 10:50:15 -0700726 Test description will append to the logs.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000727 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700728 description = "Test Description : " + str( description )
729 self.log.info( description )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700730
Jon Hall714eeba2015-09-29 17:53:10 -0700731 def _getTest( self ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000732 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700733 This method will parse the test script to find required test
734 information.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000735 '''
Jon Hall53c5e662016-04-13 16:06:56 -0700736 testFileHandler = open( main.testFile, 'r' )
adminbae64d82013-08-01 10:50:15 -0700737 testFileList = testFileHandler.readlines()
738 testFileHandler.close()
adminbae64d82013-08-01 10:50:15 -0700739 counter = 0
Jon Hall714eeba2015-09-29 17:53:10 -0700740 for index in range( len( testFileList ) ):
741 lineMatch = re.match( '\s+def CASE(\d+)(.*):',
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700742 testFileList[ index ],
Jon Hall714eeba2015-09-29 17:53:10 -0700743 0 )
adminbae64d82013-08-01 10:50:15 -0700744 if lineMatch:
Jon Hall714eeba2015-09-29 17:53:10 -0700745 counter = counter + 1
746 self.TC_PLANNED = len( self.testcases_list )
kelvin-onlabf70fd542015-05-07 18:41:40 -0700747
Jon Hall714eeba2015-09-29 17:53:10 -0700748 def response_parser( self, response, return_format ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000749 ''' It will load the default response parser '''
adminbae64d82013-08-01 10:50:15 -0700750 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700751 response_dict = self.response_to_dict( response, return_format )
752 return_format_string = self.dict_to_return_format( response,
753 return_format,
754 response_dict )
adminbae64d82013-08-01 10:50:15 -0700755 return return_format_string
kelvin-onlabf70fd542015-05-07 18:41:40 -0700756
Jon Hall714eeba2015-09-29 17:53:10 -0700757 def response_to_dict( self, response, return_format ):
adminbae64d82013-08-01 10:50:15 -0700758 response_dict = {}
Jon Hall714eeba2015-09-29 17:53:10 -0700759 json_match = re.search( '^\s*{', response )
760 xml_match = re.search( '^\s*\<', response )
761 ini_match = re.search( '^\s*\[', response )
762 if json_match:
763 self.log.info( "Response is in 'JSON' format, converting to '" +
764 return_format + "' format" )
Jon Halld61331b2015-02-17 16:35:47 -0800765 # Formatting the json string
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000766 response = re.sub( r"{\s*'?(\w)", r'{"\1', response )
Jon Hall714eeba2015-09-29 17:53:10 -0700767 response = re.sub( r",\s*'?(\w)", r',"\1', response )
768 response = re.sub( r"(\w)'?\s*:", r'\1":', response )
769 response = re.sub( r":\s*'(\w)'\s*([,}])", r':"\1"\2', response )
770 try:
adminbae64d82013-08-01 10:50:15 -0700771 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700772 response_dict = json.loads( response )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000773 except StandardError:
Jon Hall2a5002c2015-08-21 16:49:11 -0700774 self.log.exception( "Json Parser is unable to parse the string" )
adminbae64d82013-08-01 10:50:15 -0700775 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700776 elif ini_match:
777 self.log.info( "Response is in 'INI' format, converting to '" +
778 return_format + "' format" )
adminbae64d82013-08-01 10:50:15 -0700779 from configobj import ConfigObj
Jon Hall714eeba2015-09-29 17:53:10 -0700780 response_file = open( "respnse_file.temp", 'w' )
781 response_file.write( response )
Jon Halld61331b2015-02-17 16:35:47 -0800782 response_file.close()
Jon Hall714eeba2015-09-29 17:53:10 -0700783 response_dict = ConfigObj( "respnse_file.temp" )
adminbae64d82013-08-01 10:50:15 -0700784 return response_dict
Jon Hall714eeba2015-09-29 17:53:10 -0700785 elif xml_match:
786 self.log.info( "Response is in 'XML' format, converting to '" +
787 return_format + "' format" )
788 try:
789 response_dict = xmldict.xml_to_dict( "<response> " +
790 str( response ) +
791 " </response>" )
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000792 except StandardError:
Jon Hall1306a562015-09-04 11:21:24 -0700793 self.log.exception()
adminbae64d82013-08-01 10:50:15 -0700794 return response_dict
kelvin-onlabf70fd542015-05-07 18:41:40 -0700795
Jon Hall714eeba2015-09-29 17:53:10 -0700796 def dict_to_return_format( self, response, return_format, response_dict ):
797 if return_format == 'table':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000798 ''' Will return in table format'''
adminbae64d82013-08-01 10:50:15 -0700799 to_do = "Call the table output formatter"
800 global response_table
801 response_table = '\n'
Jon Hall714eeba2015-09-29 17:53:10 -0700802 response_table = response_table + '\t'.join( response_dict ) + "\n"
kelvin-onlabf70fd542015-05-07 18:41:40 -0700803
Jon Hall714eeba2015-09-29 17:53:10 -0700804 def get_table( value_to_convert ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000805 ''' This will parse the dictionary recusrsively and print as
806 table format'''
adminbae64d82013-08-01 10:50:15 -0700807 table_data = ""
Jon Hall714eeba2015-09-29 17:53:10 -0700808 if isinstance( value_to_convert, dict ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700809 table_data = table_data + '\t'.join( value_to_convert ) + \
Jon Hall714eeba2015-09-29 17:53:10 -0700810 "\n"
811 for temp_val in value_to_convert.values():
812 table_data = table_data + get_table( temp_val )
813 else:
814 table_data = table_data + str( value_to_convert ) + "\t"
Jon Halld61331b2015-02-17 16:35:47 -0800815 return table_data
kelvin-onlabf70fd542015-05-07 18:41:40 -0700816
Jon Hall714eeba2015-09-29 17:53:10 -0700817 for value in response_dict.values():
818 response_table = response_table + get_table( value )
adminbae64d82013-08-01 10:50:15 -0700819 return response_table
kelvin-onlabf70fd542015-05-07 18:41:40 -0700820
Jon Hall714eeba2015-09-29 17:53:10 -0700821 elif return_format == 'config':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000822 ''' Will return in config format'''
adminbae64d82013-08-01 10:50:15 -0700823 to_do = 'Call dict to config coverter'
Jon Hall714eeba2015-09-29 17:53:10 -0700824 response_string = str( response_dict )
adminbae64d82013-08-01 10:50:15 -0700825 print response_string
Jon Hall714eeba2015-09-29 17:53:10 -0700826 response_config = re.sub( ",", "\n\t", response_string )
827 response_config = re.sub( "u\'", "\'", response_config )
828 response_config = re.sub( "{", "", response_config )
829 response_config = re.sub( "}", "\n", response_config )
830 response_config = re.sub( ":", " =", response_config )
831 return "[response]\n\t " + response_config
adminbae64d82013-08-01 10:50:15 -0700832 elif return_format == 'xml':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000833 ''' Will return in xml format'''
Jon Hall714eeba2015-09-29 17:53:10 -0700834 response_xml = xmldict.dict_to_xml( response_dict )
835 response_xml = re.sub( ">\s*<", ">\n<", response_xml )
836 return "\n" + response_xml
adminbae64d82013-08-01 10:50:15 -0700837 elif return_format == 'json':
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000838 ''' Will return in json format'''
adminbae64d82013-08-01 10:50:15 -0700839 to_do = 'Call dict to xml coverter'
840 import json
Jon Hall714eeba2015-09-29 17:53:10 -0700841 response_json = json.dumps( response_dict )
adminbae64d82013-08-01 10:50:15 -0700842 return response_json
kelvin-onlabf70fd542015-05-07 18:41:40 -0700843
Jon Hall714eeba2015-09-29 17:53:10 -0700844 def get_random( self ):
adminbae64d82013-08-01 10:50:15 -0700845 self.random_order = self.random_order + 1
846 return self.random_order
kelvin-onlabf70fd542015-05-07 18:41:40 -0700847
Jon Hall714eeba2015-09-29 17:53:10 -0700848 def exit( self ):
adminbae64d82013-08-01 10:50:15 -0700849 __builtin__.testthread = None
Jon Hall5b586732015-06-11 11:39:39 -0700850 for thread in threading.enumerate():
851 if thread.isAlive():
852 try:
853 thread._Thread__stop()
854 except:
Jon Hall1306a562015-09-04 11:21:24 -0700855 # NOTE: We should catch any exceptions while trying to
856 # close the thread so that we can try to close the other
857 # threads as well
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700858 print str( thread.getName() ) + \
Jon Hall714eeba2015-09-29 17:53:10 -0700859 ' could not be terminated'
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700860 os.system( "stty sane" ) # fix format if necessary
adminbae64d82013-08-01 10:50:15 -0700861 sys.exit()
862
You Wang7880b372019-02-27 16:50:47 -0800863 def cleanAndExit( self, alarm=True, msg="" ):
Devin Lim44075962017-08-11 10:56:37 -0700864 """
865 It will set the testcase result to be FAILED and update it
866 before cleaning up and exitting the test.
You Wang7880b372019-02-27 16:50:47 -0800867 alarm: when set to True, it will write to the alarm log before
868 cleaning up and exitting; otherwise it will write to error log.
869 msg: message that will be written to the log if specified;
870 otherwise a default message will be written.
Devin Lim44075962017-08-11 10:56:37 -0700871 :return:
872 """
873 if self.CurrentTestCaseNumber:
874 self.testCaseResult[ str( self.CurrentTestCaseNumber ) ] = self.FALSE
Devin Limec989792017-08-15 15:57:55 -0700875 self.organizeResult( self.CurrentTestCaseNumber, self.FALSE )
Devin Lim44075962017-08-11 10:56:37 -0700876 self.logger.updateCaseResults( self )
You Wang7880b372019-02-27 16:50:47 -0800877 if alarm:
878 if msg:
879 self.log.alarm( "Test exited unexpectedly: {}".format( msg ) )
880 else:
881 self.log.alarm( "Test exited unexpectedly" )
882 else:
883 if msg:
884 self.log.error( "Test exited unexpectedly: {}".format( msg ) )
885 else:
886 self.log.error( "Test exited unexpectedly" )
Devin Lim44075962017-08-11 10:56:37 -0700887 self.cleanup()
888 self.exit()
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700889
Jon Hallcd3d2a32015-10-01 11:07:28 -0700890 def stop( self, email=False ):
891 """
892 Stop the test until Ctrl-D is entered.
893 Ctrl-C will kill the test
Jon Hall25079782015-10-13 13:54:39 -0700894
895 Optional arguments:
896 email can either be a bool, or you can specify the email address
897 to send the email to
Jon Hallcd3d2a32015-10-01 11:07:28 -0700898 """
899 try:
900 if email:
Jon Hall25079782015-10-13 13:54:39 -0700901 if '@' in email:
902 main.mail = email
903 utilities.send_warning_email()
Jeremy Ronquillo15ff1072017-07-17 10:55:46 -0700904 self.log.debug( "Test execution suspended. \n"
905 "- Type 'c' to resume the test.\n"
906 "- Type Ctrl-C to exit the test.\n"
907 "- Enter interactive python interpreter commands.\n"
908 "\t- ie: main.Mininet1.pingall()\n"
909 "- Type 'help' for help with pdb." )
910 pdb.set_trace()
Jon Hallcd3d2a32015-10-01 11:07:28 -0700911 except EOFError:
912 return
913 # Pass all other exceptions up to caller
914
915
Jon Hall714eeba2015-09-29 17:53:10 -0700916def verifyOptions( options ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000917 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700918 This will verify the command line options and set to default values,
919 if any option not given in command line.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +0000920 '''
Jon Hall714eeba2015-09-29 17:53:10 -0700921 verifyTest( options )
922 verifyExample( options )
923 verifyTestScript( options )
YPZhang1c89e762016-06-29 10:43:58 -0700924 verifyParams( options )
Jon Hall714eeba2015-09-29 17:53:10 -0700925 verifyLogdir( options )
926 verifyMail( options )
927 verifyTestCases( options )
928 verifyOnosCell( options )
adminbae64d82013-08-01 10:50:15 -0700929
Jon Hall714eeba2015-09-29 17:53:10 -0700930def verifyTest( options ):
Jon Hall44506242015-07-29 17:40:26 -0700931 try:
932 if options.testname:
933 main.TEST = options.testname
Jon Hall714eeba2015-09-29 17:53:10 -0700934 main.classPath = "tests." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700935 main.tests_path = tests_path
936 elif options.example:
937 main.TEST = options.example
Jon Hall714eeba2015-09-29 17:53:10 -0700938 main.tests_path = path + "/examples/"
939 main.classPath = "examples." + main.TEST + "." + main.TEST
Jon Hall44506242015-07-29 17:40:26 -0700940 except AttributeError:
adminbae64d82013-08-01 10:50:15 -0700941 print "Test or Example not specified please specify the --test <test name > or --example <example name>"
Jon Hall5b586732015-06-11 11:39:39 -0700942 main.exit()
adminbae64d82013-08-01 10:50:15 -0700943
Jon Hall714eeba2015-09-29 17:53:10 -0700944def verifyExample( options ):
adminbae64d82013-08-01 10:50:15 -0700945 if options.example:
Jon Hall714eeba2015-09-29 17:53:10 -0700946 main.testDir = path + '/examples/'
947 main.tests_path = path + "/examples/"
948 main.classPath = "examples." + main.TEST + "." + main.TEST
kelvin-onlabf70fd542015-05-07 18:41:40 -0700949
Jon Hall714eeba2015-09-29 17:53:10 -0700950def verifyLogdir( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800951 # Verifying Log directory option
adminbae64d82013-08-01 10:50:15 -0700952 if options.logdir:
953 main.logdir = options.logdir
Jon Hall714eeba2015-09-29 17:53:10 -0700954 else:
Jon Halld61331b2015-02-17 16:35:47 -0800955 main.logdir = main.FALSE
kelvin-onlabf70fd542015-05-07 18:41:40 -0700956
Jon Hall714eeba2015-09-29 17:53:10 -0700957def verifyMail( options ):
Jon Hall25079782015-10-13 13:54:39 -0700958 # Mail-To: field
959 if options.mail: # Test run specific
adminbae64d82013-08-01 10:50:15 -0700960 main.mail = options.mail
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700961 elif main.params.get( 'mail' ): # Test suite specific
Jon Hall25079782015-10-13 13:54:39 -0700962 main.mail = main.params.get( 'mail' )
963 else: # TestON specific
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700964 main.mail = main.config[ 'config' ].get( 'mail_to' )
Jon Hall25079782015-10-13 13:54:39 -0700965 # Mail-From: field
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700966 main.sender = main.config[ 'config' ].get( 'mail_from' )
Jon Hall25079782015-10-13 13:54:39 -0700967 # Mail smtp server
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700968 main.smtp = main.config[ 'config' ].get( 'mail_server' )
Jon Hall25079782015-10-13 13:54:39 -0700969 # Mail-From account password
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700970 main.senderPwd = main.config[ 'config' ].get( 'mail_pass' )
Jon Hall25079782015-10-13 13:54:39 -0700971
Devin Lim2df68a12017-06-30 15:39:05 -0700972def evalTestCase( tempList ):
973 tList = []
974 for tcase in tempList:
975 if isinstance( tcase, list ):
976 tList.extend( evalTestCase( tcase ) )
977 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700978 tList.extend( [ tcase ] )
Devin Lim2df68a12017-06-30 15:39:05 -0700979 return tList
adminbae64d82013-08-01 10:50:15 -0700980
Jon Hall714eeba2015-09-29 17:53:10 -0700981def verifyTestCases( options ):
Jon Hall88e498c2015-03-06 09:54:35 -0800982 # Getting Test cases list
adminbae64d82013-08-01 10:50:15 -0700983 if options.testcases:
Jon Hallfebb1c72015-03-05 13:30:09 -0800984 testcases_list = options.testcases
Jon Hall88e498c2015-03-06 09:54:35 -0800985 # sys.exit()
Jon Hall714eeba2015-09-29 17:53:10 -0700986 testcases_list = re.sub( "(\[|\])", "", options.testcases )
987 main.testcases_list = eval( testcases_list + "," )
988 else:
adminbae64d82013-08-01 10:50:15 -0700989 if 'testcases' in main.params.keys():
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700990 temp = eval( main.params[ 'testcases' ] + "," )
Devin Lim2df68a12017-06-30 15:39:05 -0700991 main.testcases_list = evalTestCase( list( temp ) )
Jon Hall714eeba2015-09-29 17:53:10 -0700992 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -0700993 print "Testcases not specifed in params, please provide in " + \
Jon Hall714eeba2015-09-29 17:53:10 -0700994 "params file or 'testcases' commandline argument"
Jon Halld61331b2015-02-17 16:35:47 -0800995 sys.exit()
kelvin-onlabf70fd542015-05-07 18:41:40 -0700996
Jon Hall714eeba2015-09-29 17:53:10 -0700997def verifyOnosCell( options ):
Hari Krishnabe4b97b2015-07-15 12:19:43 -0700998 # Verifying onoscell option
Hari Krishna03f530e2015-07-10 17:28:27 -0700999 if options.onoscell:
1000 main.onoscell = options.onoscell
Devin Lim58046fa2017-07-05 16:55:00 -07001001 main.ONOSip = []
Hari Krishnabe4b97b2015-07-15 12:19:43 -07001002 main.mnIP = ""
Devin Lim58046fa2017-07-05 16:55:00 -07001003 cellCMD = ". ~/onos/tools/dev/bash_profile; cell " + main.onoscell
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001004 output = subprocess.check_output( [ "bash", '-c', cellCMD ] )
Hari Krishnabe4b97b2015-07-15 12:19:43 -07001005 splitOutput = output.splitlines()
Devin Lim58046fa2017-07-05 16:55:00 -07001006 main.apps = ""
Jon Hall714eeba2015-09-29 17:53:10 -07001007 for i in range( len( splitOutput ) ):
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001008 if re.match( "OCN", splitOutput[ i ] ):
1009 mnNode = splitOutput[ i ].split( "=" )
1010 main.mnIP = mnNode[ 1 ]
Jon Hall714eeba2015-09-29 17:53:10 -07001011 # cell already sorts OC variables in bash, so no need to
1012 # sort in TestON
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001013 elif re.match( "OC[1-9]", splitOutput[ i ] ):
1014 onosNodes = splitOutput[ i ].split( "=" )
1015 main.ONOSip.append( onosNodes[ 1 ] )
1016 elif re.match( "ONOS_APPS", splitOutput[ i ] ):
1017 main.apps = ( splitOutput[ i ].split( "=" ) )[ 1 ]
Jon Hall714eeba2015-09-29 17:53:10 -07001018 else:
Hari Krishna03f530e2015-07-10 17:28:27 -07001019 main.onoscell = main.FALSE
1020
Jon Hall714eeba2015-09-29 17:53:10 -07001021def verifyTestScript( options ):
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001022 '''
adminbae64d82013-08-01 10:50:15 -07001023 Verifyies test script.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001024 '''
Jon Halld61331b2015-02-17 16:35:47 -08001025 main.openspeak = openspeak.OpenSpeak()
Jon Hall53c5e662016-04-13 16:06:56 -07001026 directory = main.testDir + "/" + main.TEST
1027 if os.path.exists( directory ):
1028 pass
1029 else:
1030 directory = ""
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001031 for root, dirs, files in os.walk( main.testDir, topdown=True ):
Jon Hall53c5e662016-04-13 16:06:56 -07001032 if not directory:
1033 for name in dirs:
1034 if name == main.TEST:
1035 directory = ( os.path.join( root, name ) )
1036 index = directory.find( "/tests/" ) + 1
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001037 main.classPath = directory[ index: ].replace( '/', '.' ) + "." + main.TEST
Jon Hall53c5e662016-04-13 16:06:56 -07001038 break
1039 openspeakfile = directory + "/" + main.TEST + ".ospk"
Jon Halld74d2952018-03-01 13:26:39 -08001040 main.testDir = directory
Jon Hall53c5e662016-04-13 16:06:56 -07001041 main.testFile = directory + "/" + main.TEST + ".py"
Jon Hall714eeba2015-09-29 17:53:10 -07001042 if os.path.exists( openspeakfile ):
Jon Hall44506242015-07-29 17:40:26 -07001043 # Openspeak file found, compiling to python
Jon Hall714eeba2015-09-29 17:53:10 -07001044 main.openspeak.compiler( openspeakfile=openspeakfile, writetofile=1 )
Jon Hall53c5e662016-04-13 16:06:56 -07001045 elif os.path.exists( main.testFile ):
Jon Hall44506242015-07-29 17:40:26 -07001046 # No openspeak found, using python file instead
1047 pass
adminbae64d82013-08-01 10:50:15 -07001048 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001049 print "\nThere is no \"" + main.TEST + "\" test script.\nPlease provide a " + \
1050 "Python or OpenSpeak test script in the tests folder: " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001051 main.testDir + "/" + main.TEST + "/"
adminbae64d82013-08-01 10:50:15 -07001052 __builtin__.testthread = None
1053 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -07001054 try:
1055 testModule = __import__( main.classPath,
1056 globals(),
1057 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001058 [ main.TEST ],
Jon Hall714eeba2015-09-29 17:53:10 -07001059 -1 )
Jon Hall1306a562015-09-04 11:21:24 -07001060 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001061 print "There was an import error, it might mean that there is " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001062 "no test named " + main.TEST
Jon Halld61331b2015-02-17 16:35:47 -08001063 main.exit()
adminbae64d82013-08-01 10:50:15 -07001064
Jon Hall714eeba2015-09-29 17:53:10 -07001065 testClass = getattr( testModule, main.TEST )
adminbae64d82013-08-01 10:50:15 -07001066 main.testObject = testClass()
1067 load_parser()
Jon Halld74d2952018-03-01 13:26:39 -08001068 main.paramsFile = main.TEST + ".params" if options.paramsFile is None else options.paramsFile
1069 main.topoFile = main.TEST + ".topo" if options.topoFile is None else options.topoFile
1070 main.params = main.parser.parseFile( main.testDir + "/" + main.paramsFile )
1071 main.topology = main.parser.parseFile( main.testDir + "/" + main.topoFile )
kelvin-onlabf70fd542015-05-07 18:41:40 -07001072
YPZhang1c89e762016-06-29 10:43:58 -07001073def verifyParams( options ):
Jon Hall714eeba2015-09-29 17:53:10 -07001074 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001075 main.params = main.params[ 'PARAMS' ]
Jon Hall1306a562015-09-04 11:21:24 -07001076 except KeyError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001077 print "Error with the params file: Either the file not specified " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001078 "or the format is not correct"
Jon Halld61331b2015-02-17 16:35:47 -08001079 main.exit()
Jon Hall714eeba2015-09-29 17:53:10 -07001080 try:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001081 main.topology = main.topology[ 'TOPOLOGY' ]
Jon Hall1306a562015-09-04 11:21:24 -07001082 except KeyError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001083 print "Error with the Topology file: Either the file not specified " + \
Jon Hall714eeba2015-09-29 17:53:10 -07001084 "or the format is not correct"
adminbae64d82013-08-01 10:50:15 -07001085 main.exit()
YPZhang1c89e762016-06-29 10:43:58 -07001086 # Overwrite existing params variables if they are specified from command line
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001087 if len( options.params ) > 0:
YPZhang1c89e762016-06-29 10:43:58 -07001088 # Some params variables are specified from command line
1089 for param in options.params:
1090 if not re.search( ".=.", param ):
1091 print( "Error when parsing params: params should follow key=value format" )
1092 continue
Jon Hall7c4f4302016-07-15 14:39:02 -07001093 # Split the param string to catch nested keys and the value
YPZhang1c89e762016-06-29 10:43:58 -07001094 [ keys, value ] = param.split( "=" )
1095 # Split the nested keys according to its hierarchy
1096 keyList = keys.split( "/" )
1097 # Get the outermost dictionary
1098 paramDict = main.params
1099 # Get the innermost dictionary
1100 try:
1101 while len( keyList ) > 1:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001102 key = keyList.pop( 0 )
YPZhang1c89e762016-06-29 10:43:58 -07001103 assert isinstance( paramDict[ key ], dict )
1104 paramDict = paramDict[ key ]
1105 except KeyError:
1106 print( "Error when parsing params: key \"" + key + "\" not found in main.params" )
1107 main.exit()
1108 except AssertionError:
1109 print( "Error when parsing params: \"" + key + "\" is already the innermost level in main.params" )
1110 main.exit()
1111 # Change the value
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001112 if keyList[ 0 ] not in paramDict:
1113 print( "Error when parsing params: key \"" + keyList[ 0 ] + "\" not found in main.params" )
YPZhang1c89e762016-06-29 10:43:58 -07001114 main.exit()
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001115 elif isinstance( paramDict[ keyList[ 0 ] ], dict ):
1116 print( "Error when parsing params: more levels under key \"" + keyList[ 0 ] + "\" in main.params" )
YPZhang1c89e762016-06-29 10:43:58 -07001117 main.exit()
1118 else:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001119 paramDict[ keyList[ 0 ] ] = value
kelvin-onlabf70fd542015-05-07 18:41:40 -07001120
Jon Hall714eeba2015-09-29 17:53:10 -07001121def load_parser():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001122 '''
adminbae64d82013-08-01 10:50:15 -07001123 It facilitates the loading customised parser for topology and params file.
1124 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -07001125 It also loads default xmlparser if no parser have specified in teston.cfg
1126 file.
adminbae64d82013-08-01 10:50:15 -07001127
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001128 '''
adminbae64d82013-08-01 10:50:15 -07001129 confighash = main.configDict
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001130 if 'file' in confighash[ 'config' ][ 'parser' ] and\
1131 'class' in confighash[ 'config' ][ 'parser' ]:
1132 path = confighash[ 'config' ][ 'parser' ][ 'file' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001133 if path is not None or\
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001134 confighash[ 'config' ][ 'parser' ][ 'class' ] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001135 try:
1136 module = re.sub( r".py\s*$", "", path )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001137 moduleList = module.split( "/" )
1138 newModule = ".".join( moduleList[ -2: ] )
1139 parsingClass = confighash[ 'config' ][ 'parser' ][ 'class' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001140 parsingModule = __import__( newModule,
1141 globals(),
1142 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001143 [ parsingClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001144 -1 )
1145 parsingClass = getattr( parsingModule, parsingClass )
Jon Hall44506242015-07-29 17:40:26 -07001146 main.parser = parsingClass()
Jon Halld74d2952018-03-01 13:26:39 -08001147 if hasattr( main.parser, "parseFile" ) and\
Jon Hall714eeba2015-09-29 17:53:10 -07001148 hasattr( main.parser, "parse" ):
Jon Hall44506242015-07-29 17:40:26 -07001149 pass
1150 else:
1151 print "Invalid parser format"
adminbae64d82013-08-01 10:50:15 -07001152 main.exit()
Jon Hall44506242015-07-29 17:40:26 -07001153 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001154 print "Could not find the file " + path + \
Jon Hall714eeba2015-09-29 17:53:10 -07001155 " using default parser."
Jon Halld61331b2015-02-17 16:35:47 -08001156 load_defaultParser()
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001157 elif confighash[ 'config' ][ 'parser' ][ 'file' ] is None or\
1158 confighash[ 'config' ][ 'parser' ][ 'class' ] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001159 load_defaultParser()
adminbae64d82013-08-01 10:50:15 -07001160 else:
1161 load_defaultParser()
1162
1163def load_defaultParser():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001164 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001165 It will load the default parser which is xml parser to parse the params and
1166 topology file.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001167 '''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001168 moduleList = main.parserPath.split( "/" )
1169 newModule = ".".join( moduleList[ -2: ] )
Jon Hall714eeba2015-09-29 17:53:10 -07001170 try:
Jon Halld61331b2015-02-17 16:35:47 -08001171 parsingClass = main.parsingClass
Jon Hall714eeba2015-09-29 17:53:10 -07001172 parsingModule = __import__( newModule,
1173 globals(),
1174 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001175 [ parsingClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001176 -1 )
1177 parsingClass = getattr( parsingModule, parsingClass )
adminbae64d82013-08-01 10:50:15 -07001178 main.parser = parsingClass()
Jon Halld74d2952018-03-01 13:26:39 -08001179 if hasattr( main.parser, "parseFile" ) and\
Jon Hall714eeba2015-09-29 17:53:10 -07001180 hasattr( main.parser, "parse" ):
adminbae64d82013-08-01 10:50:15 -07001181 pass
1182 else:
1183 main.exit()
adminbae64d82013-08-01 10:50:15 -07001184 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001185 print sys.exc_info()[ 1 ]
adminbae64d82013-08-01 10:50:15 -07001186
Jon Hall714eeba2015-09-29 17:53:10 -07001187def load_logger():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001188 '''
adminbae64d82013-08-01 10:50:15 -07001189 It facilitates the loading customised parser for topology and params file.
1190 It loads parser mentioned in tab named parser of teston.cfg file.
Jon Hall714eeba2015-09-29 17:53:10 -07001191 It also loads default xmlparser if no parser have specified in teston.cfg
1192 file.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001193 '''
adminbae64d82013-08-01 10:50:15 -07001194 confighash = main.configDict
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001195 if 'file' in confighash[ 'config' ][ 'logger' ] and\
1196 'class' in confighash[ 'config' ][ 'logger' ]:
1197 path = confighash[ 'config' ][ 'logger' ][ 'file' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001198 if path is not None or\
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001199 confighash[ 'config' ][ 'logger' ][ 'class' ] is not None:
Jon Hall44506242015-07-29 17:40:26 -07001200 try:
1201 module = re.sub( r".py\s*$", "", path )
Jon Hall714eeba2015-09-29 17:53:10 -07001202 moduleList = module.split( "/" )
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001203 newModule = ".".join( moduleList[ -2: ] )
1204 loggerClass = confighash[ 'config' ][ 'logger' ][ 'class' ]
Jon Hall714eeba2015-09-29 17:53:10 -07001205 loggerModule = __import__( newModule,
1206 globals(),
1207 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001208 [ loggerClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001209 -1 )
1210 loggerClass = getattr( loggerModule, loggerClass )
Jon Hall44506242015-07-29 17:40:26 -07001211 main.logger = loggerClass()
Jon Hall44506242015-07-29 17:40:26 -07001212 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001213 print "Could not find the file " + path + \
Jon Hall714eeba2015-09-29 17:53:10 -07001214 " using default logger."
adminbae64d82013-08-01 10:50:15 -07001215 load_defaultlogger()
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001216 elif confighash[ 'config' ][ 'parser' ][ 'file' ] is None or\
1217 confighash[ 'config' ][ 'parser' ][ 'class' ] is None:
Jon Halld61331b2015-02-17 16:35:47 -08001218 load_defaultlogger()
adminbae64d82013-08-01 10:50:15 -07001219 else:
1220 load_defaultlogger()
1221
1222def load_defaultlogger():
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001223 '''
Jon Hall714eeba2015-09-29 17:53:10 -07001224 It will load the default parser which is xml parser to parse the params and
1225 topology file.
Jeremy Ronquillo4d5f1d02017-10-13 20:23:57 +00001226 '''
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001227 moduleList = main.loggerPath.split( "/" )
1228 newModule = ".".join( moduleList[ -2: ] )
Jon Hall714eeba2015-09-29 17:53:10 -07001229 try:
Jon Halld61331b2015-02-17 16:35:47 -08001230 loggerClass = main.loggerClass
Jon Hall714eeba2015-09-29 17:53:10 -07001231 loggerModule = __import__( newModule,
1232 globals(),
1233 locals(),
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001234 [ loggerClass ],
Jon Hall714eeba2015-09-29 17:53:10 -07001235 -1 )
1236 loggerClass = getattr( loggerModule, loggerClass )
adminbae64d82013-08-01 10:50:15 -07001237 main.logger = loggerClass()
1238
1239 except ImportError:
Jeremy Ronquillo696f4262017-10-17 10:56:26 -07001240 print sys.exc_info()[ 1 ]
Jon Halld61331b2015-02-17 16:35:47 -08001241 main.exit()
adminbae64d82013-08-01 10:50:15 -07001242
Jon Hall714eeba2015-09-29 17:53:10 -07001243def _echo( self ):
adminbae64d82013-08-01 10:50:15 -07001244 print "THIS IS ECHO"